Skip to content

Give an agent its input

View as Markdown

This guide gives an agent its input, from a direct run or a flow step, fills its instructions with parameters, and reads what a turn returns.

An agent runs one turn at a time. Run directly, a turn's input is the user's message and a few optional fields. Run as a step of a flow, the agent gets the step's input instead.

  • A pack on a runtime such as kindgi dev, with Kindgi 0.1's CLI, and the agents and tools from Write an agent.
  • A registered model for answers worth reading. Without one, dev-echo answers.
  • For the app's half: Node 22.12 or later, Python 3.11 or later, or Java 17 or later, with Kindgi 0.1's client, and KINDGI_API_URL and KINDGI_API_TOKEN set.

A direct run gives the agent a message:

Terminal window
pnpm exec kindgi runs start --agent=acme.order-desk --input='{"userMessage":"Where is my order A-1001?"}'

--agent is the agent, and --input the turn's input, as JSON. It has these fields:

Field
userMessage The turn's message. Required.
conversationId Continue a conversation: see Hold a conversation. Without it, the turn opens a new one.
participantId Who the conversation is with, kept on the conversation the turn opens.
parameters Values for the agent's parameters, as Parameters describes: strings, numbers or booleans.

Without a userMessage, the run is refused:

Error [invalid-request]: An agent run expects input { userMessage: string, conversationId?: string, participantId?: string, parameters?: { [name]: string | number | boolean } }.

From your app, the same input goes in runs.start. Ask your coding agent: "I want my app to run an agent with a customer's message, and print its answer." For reference, the code looks like this. It runs the acme.reply-drafter agent from the next section:

scripts/drafter.ts
import { createClient } from '@kindgi/sdk/client';
const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
const run = await kindgi.runs.start({
agent: 'acme.reply-drafter',
input: {
userMessage: 'My parcel is a week late.',
parameters: { tone: 'formal', signature: 'Sam at Acme' },
},
});
const turn = run.output as { response: { content: string } };
console.log(turn.response.content);

Each prints the agent's answer. A run waits for the turn to end. To get the run back as soon as it exists, add --no-wait, or options: { wait: false } in the clients. It comes back pending, and kindgi runs get <run-id> shows it completed, with its output, once the turn ends.

Parameters are your own variables in the agent's instructions. Declare each one, and the caller supplies the values. Ask your coding agent: "I want an agent that drafts replies to customers in the tone I ask for." Kindgi's skills in your pack tell it how (How it knows Kindgi). For reference, the agent looks like this:

agents/reply-drafter/index.ts
import { defineAgent } from '@kindgi/sdk/define';
const defined = defineAgent({
id: 'acme.reply-drafter',
version: '0.1.0',
name: 'Reply drafter',
instructions: [
'You draft short replies to Acme customers, in a {{ tone }} tone.',
'Sign every reply as {{ signature }}.',
].join('\n'),
parameters: [
{ name: 'tone', type: 'string', description: 'friendly, formal, …' },
{ name: 'signature', type: 'string', default: 'The Acme team' },
],
capabilities: [{ needs: [] }],
tools: [],
retrieval: [],
guardrails: [],
});
if (defined.kind === 'err') throw new Error(defined.error.message);
export default defined.value;

A parameter is string, number, boolean or date. Give it a default to make it optional: here tone is required, and signature falls back to its default. required: false without a default isn't enough: the instructions still name the variable, and rendering fails without a value.

Run it with a tone:

Terminal window
pnpm exec kindgi runs start --agent=acme.reply-drafter --input='{"userMessage":"My parcel is a week late.","parameters":{"tone":"friendly"}}'

parameters in --input gives the parameters' values. It prints the run:

{
…
"status": "completed",
…
"output": {
…
"response": {
"role": "agent",
"content": "Hi there!\n\nI'm sorry to hear your parcel is running late – we know how frustrating that can be! … Thanks for your patience!\n\nThe Acme team",
…
},
…
}
}
Excerpt

The journal shows what the model was told, in the render-prompt step. Read it with kindgi runs journal <run-id>, where <run-id> is the run's id:

You draft short replies to Acme customers, in a friendly tone.
Sign every reply as The Acme team.

A required parameter with no value fails the turn before the model is called:

Error [model-invocation-failed]: Prompt render failed: Required parameter missing: tone

A flow runs an agent as a step: one turn, as a child run of the flow's run. The step's inputMapping builds the agent's input, and config.parameters fills its parameters. Ask your coding agent: "I want a flow that looks an order up, then has an agent write the customer an update about it." For reference, the flow looks like this. It looks the order up with acme.lookup-order, from Write an agent. Then it has an agent write the customer an update:

flows/notify-customer/index.ts
import { defineFlow } from '@kindgi/sdk/define';
const defined = defineFlow({
id: 'acme.notify-customer',
version: '0.1.0',
name: 'Notify a customer',
nodes: [
{
id: 'lookup',
kind: 'tool',
ref: 'acme.lookup-order',
inputMapping: { orderId: { path: 'runInput.orderId' } },
},
{
id: 'update',
kind: 'agent',
ref: 'acme.order-update',
inputMapping: { order: { path: 'nodeOutputs.lookup' } },
config: { parameters: { tone: 'friendly' } },
},
],
edges: [
{ id: 'e-start', from: '$start', to: 'lookup' },
{ id: 'e-update', from: 'lookup', to: 'update' },
{ id: 'e-end', from: 'update', to: '$end' },
],
output: { mapping: { update: { path: 'nodeOutputs.update.text' } } },
});
if (defined.kind === 'err') throw new Error(defined.error.message);
export default defined.value;

The agent gets the step's input two ways:

  • as {{ input }} in its instructions, so it can use the fields;
  • as its user message: the input as JSON.

For reference, the agent the flow runs looks like this:

agents/order-update/index.ts
import { defineAgent } from '@kindgi/sdk/define';
const defined = defineAgent({
id: 'acme.order-update',
version: '0.1.0',
name: 'Order update',
instructions: [
'Write a two-sentence update for the customer about order {{ input.order.orderId }}.',
'Its status is {{ input.order.status }}{% if input.order.eta %}, expected on {{ input.order.eta }}{% endif %}.',
'Use a {{ tone }} tone.',
].join('\n'),
parameters: [{ name: 'tone', type: 'string' }],
capabilities: [{ needs: [] }],
tools: [],
retrieval: [],
guardrails: [],
});
if (defined.kind === 'err') throw new Error(defined.error.message);
export default defined.value;

Run the flow:

Terminal window
pnpm exec kindgi runs start --flow=acme.notify-customer --input='{"orderId":"A-1001"}'

--flow is the flow, and --input its input. It prints the run, with the agent's update as the flow's output:

{
…
"flowId": "acme.notify-customer",
…
"status": "completed",
…
"output": {
"update": "Great news! Your order A-1001 is on its way and should arrive by October 6th, 2026. Thanks for your patience, and we can't wait for you to receive it!"
}
}
Excerpt

In the agent's turn, the instructions rendered as:

Write a two-sentence update for the customer about order A-1001.
Its status is shipped, expected on 2026-10-06.
Use a friendly tone.

Its user message was the step's input:

{
"order": {
"orderId": "A-1001",
"status": "shipped",
"eta": "2026-10-06"
}
}

The step's output, which later steps and the flow's output read as nodeOutputs.update.<field>:

{
"text": "Great news! Your order A-1001 is on its way …",
"runId": "c2cd458f-3364-4c0d-aefc-e6a7765f96d2",
"usage": { "steps": 1, "durationMs": 1212, "promptTokens": 90, "totalCostUsd": 0.00031999999999999997, "completionTokens": 46 },
"violations": [],
"conversationId": "1cf8b177-7f18-4513-b3fe-178f8aea6738"
}
Excerpt

text is the answer. An agent with a typed answer also has output, as Give an agent a typed answer shows.

A turn's result is the run's output:

Field
response.content The answer, as text.
output The typed answer, for an agent with an output schema.
conversationId, turnNumber The conversation and the turn's number in it.
usage steps, the model calls, then promptTokens, completionTokens, totalCostUsd and durationMs.
provider The provider id and model that answered.
appended The messages the turn added to the conversation: the user message, tool calls and their results, the answer.
warnings For example fallback-provider and dev-echo-not-a-model, when dev-echo answered.
violations Guardrail results.
provenance The turn's provenance record, as Trace an answer and its cost describes.

In the TypeScript client, run.output is unknown: cast it to the fields you read. In the Python client, it's a dict.