# Give an agent its input

> What a turn's input is, how parameters fill an agent's instructions, what an agent gets as a flow step, and what a turn returns.

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.

## Before you start

- **A pack on a runtime such as `kindgi dev`,** with Kindgi 0.1's CLI, and the agents and tools from [Write an agent](https://docs.kindgi.com/v0.1.10/guides/agents/write-an-agent.md).
- **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

A direct run gives the agent a message:

- **TypeScript**

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

- **Python**

  ```sh
  uv run kindgi runs start --agent=acme.order-desk --input='{"userMessage":"Where is my order A-1001?"}'
  ```

- **Java**

  ```sh
  ./kindgiw runs start --agent=acme.order-desk --input='{"userMessage":"Where is my order A-1001?"}'
  ```

- **Scala**

  ```sh
  ./kindgiw 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](https://docs.kindgi.com/v0.1.10/guides/agents/conversations.md). 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](https://docs.kindgi.com/v0.1.10/guides/agents/give-an-agent-input.md#parameters) describes: strings, numbers or booleans. |

Without a `userMessage`, the run is refused:

```text
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:

- **TypeScript**

  `scripts/drafter.ts`

  ```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);
  ```

- **Python**

  `scripts/drafter.py`

  ```python
  from kindgi.client import Kindgi

  kindgi = Kindgi()  # KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
  run = kindgi.runs.start(
      agent="acme.reply-drafter",
      input={
          "userMessage": "My parcel is a week late.",
          "parameters": {"tone": "formal", "signature": "Sam at Acme"},
      },
  )
  if run.output is None:  # a run that didn't complete has no output
      raise SystemExit(f"Run {run.id} ended {run.status}: {run.failure_message}")
  print(run.output["response"]["content"])
  ```

- **Java**

  `src/main/java/com/acme/app/Drafter.java`

  ```java
  package com.acme.app;

  import com.kindgi.client.Kindgi;
  import com.kindgi.client.models.Run;
  import com.kindgi.client.models.StartRunBody;
  import java.util.Map;

  public final class Drafter {
    public static void main(String[] args) {
      Kindgi kindgi = Kindgi.create(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev

      Run run = kindgi.runs().start(StartRunBody.WithAgent.builder()
          .agent("acme.reply-drafter")
          .input(Map.of(
              "userMessage", "My parcel is a week late.",
              "parameters", Map.of("tone", "formal", "signature", "Sam at Acme")))
          .build());
      if (!(run.output() instanceof Map<?, ?> output)) { // a run that didn't complete has no output
        throw new IllegalStateException("Run " + run.id() + " ended " + run.status() + ": " + run.failureMessage());
      }
      System.out.println(((Map<?, ?>) output.get("response")).get("content"));
    }
  }
  ```

- **Scala**

  `src/main/scala/acme/app/Drafter.scala`

  ```scala
  package acme.app

  import com.kindgi.client.Kindgi
  import com.kindgi.client.models.StartRunBody
  import scala.jdk.CollectionConverters._

  object Drafter {
    def main(args: Array[String]): Unit = {
      val kindgi = Kindgi.create() // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev

      val run = kindgi.runs().start(StartRunBody.WithAgent.builder()
        .agent("acme.reply-drafter")
        .input(Map[String, AnyRef](
          "userMessage" -> "My parcel is a week late.",
          "parameters" -> Map("tone" -> "formal", "signature" -> "Sam at Acme").asJava).asJava)
        .build())
      run.output match {
        case output: java.util.Map[_, _] =>
          val response = output.get("response").asInstanceOf[java.util.Map[_, _]]
          println(response.get("content"))
        case _ => // a run that didn't complete has no output
          throw new IllegalStateException(s"Run ${run.id} ended ${run.status}: ${run.failureMessage}")
      }
    }
  }
  ```

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

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](https://docs.kindgi.com/v0.1.10/start/coding-agents.md)). For reference, the agent looks like this:

- **TypeScript**

  `agents/reply-drafter/index.ts`

  ```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;
  ```

- **Python**

  `agents/reply_drafter.py`

  ```python
  from kindgi import Agent

  reply_drafter = Agent(
      id="acme.reply-drafter",
      version="0.1.0",
      name="Reply drafter",
      instructions="\n".join([
          "You draft short replies to Acme customers, in a {{ tone }} tone.",
          "Sign every reply as {{ signature }}.",
      ]),
      parameters=[
          {"name": "tone", "type": "string", "description": "friendly, formal, …"},
          {"name": "signature", "type": "string", "default": "The Acme team"},
      ],
      capabilities=[{"needs": []}],
  )
  ```

- **Java**

  `src/main/java/acme/agents/ReplyDrafter.java`

  ```java
  package acme.agents;

  import com.kindgi.pack.Agent;
  import java.util.List;
  import java.util.Map;

  public final class ReplyDrafter {
    public static final Agent AGENT = Agent.define("acme.reply-drafter")
        .version("0.1.0")
        .name("Reply drafter")
        .instructions(String.join("\n",
            "You draft short replies to Acme customers, in a {{ tone }} tone.",
            "Sign every reply as {{ signature }}."))
        .set("parameters", List.of(
            Map.of("name", "tone", "type", "string", "description", "friendly, formal, …"),
            Map.of("name", "signature", "type", "string", "default", "The Acme team")))
        .capability(Map.of("needs", List.of()))
        .build();

    private ReplyDrafter() {}
  }
  ```

- **Scala**

  `src/main/scala/acme/agents/ReplyDrafter.scala`

  ```scala
  package acme.agents

  import com.kindgi.pack.scaladsl._

  object ReplyDrafter {
    val agent: Agent = Agent("acme.reply-drafter")
      .version("0.1.0")
      .name("Reply drafter")
      .instructions(Seq(
        "You draft short replies to Acme customers, in a {{ tone }} tone.",
        "Sign every reply as {{ signature }}.").mkString("\n"))
      .set("parameters", Seq(
        Map("name" -> "tone", "type" -> "string", "description" -> "friendly, formal, …"),
        Map("name" -> "signature", "type" -> "string", "default" -> "The Acme team")))
      .capability(Map("needs" -> Seq()))
      .build()
  }
  ```

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`:

- **TypeScript**

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

- **Python**

  ```sh
  uv run kindgi runs start --agent=acme.reply-drafter --input='{"userMessage":"My parcel is a week late.","parameters":{"tone":"friendly"}}'
  ```

- **Java**

  ```sh
  ./kindgiw runs start --agent=acme.reply-drafter --input='{"userMessage":"My parcel is a week late.","parameters":{"tone":"friendly"}}'
  ```

- **Scala**

  ```sh
  ./kindgiw 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:

```json excerpt
{
  …
  "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",
      …
    },
    …
  }
}
```

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:

```text
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:

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

## In a flow step

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](https://docs.kindgi.com/v0.1.10/guides/agents/write-an-agent.md#the-tool-it-calls). Then it has an agent write the customer an update:

- **TypeScript**

  `flows/notify-customer/index.ts`

  ```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;
  ```

- **Python**

  `flows/notify_customer.py`

  ```python
  from kindgi import Flow

  from ..agents.order_update import order_update

  notify_customer = Flow(
      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": 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"}}},
  )
  ```

- **Java**

  `src/main/java/acme/flows/NotifyCustomer.java`

  ```java
  package acme.flows;

  import acme.agents.OrderUpdate;
  import acme.tools.LookupOrder;
  import com.kindgi.pack.Flow;
  import java.util.Map;

  public final class NotifyCustomer {
    public static final Flow FLOW = Flow.define("acme.notify-customer")
        .version("0.1.0")
        .set("name", "Notify a customer")
        .node(Map.of(
            "id", "lookup",
            "kind", "tool",
            "ref", LookupOrder.TOOL,
            "inputMapping", Map.of("orderId", Map.of("path", "runInput.orderId"))))
        .node(Map.of(
            "id", "update",
            "kind", "agent",
            "ref", OrderUpdate.AGENT,
            "inputMapping", Map.of("order", Map.of("path", "nodeOutputs.lookup")),
            "config", Map.of("parameters", Map.of("tone", "friendly"))))
        .edge("e-start", "$start", "lookup")
        .edge("e-update", "lookup", "update")
        .edge("e-end", "update", "$end")
        .set("output", Map.of("mapping", Map.of("update", Map.of("path", "nodeOutputs.update.text"))))
        .build();

    private NotifyCustomer() {}
  }
  ```

- **Scala**

  `src/main/scala/acme/flows/NotifyCustomer.scala`

  ```scala
  package acme.flows

  import acme.agents.OrderUpdate
  import acme.tools.LookupOrder
  import com.kindgi.pack.scaladsl._

  object NotifyCustomer {
    val flow: Flow = Flow("acme.notify-customer")
      .version("0.1.0")
      .set("name", "Notify a customer")
      .node(Map(
        "id" -> "lookup",
        "kind" -> "tool",
        "ref" -> LookupOrder.tool,
        "inputMapping" -> Map("orderId" -> Map("path" -> "runInput.orderId"))))
      .node(Map(
        "id" -> "update",
        "kind" -> "agent",
        "ref" -> OrderUpdate.agent,
        "inputMapping" -> Map("order" -> Map("path" -> "nodeOutputs.lookup")),
        "config" -> Map("parameters" -> Map("tone" -> "friendly"))))
      .edge("e-start", "$start", "lookup")
      .edge("e-update", "lookup", "update")
      .edge("e-end", "update", "$end")
      .set("output", Map("mapping" -> Map("update" -> Map("path" -> "nodeOutputs.update.text"))))
      .build()
  }
  ```

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:

- **TypeScript**

  `agents/order-update/index.ts`

  ```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;
  ```

- **Python**

  `agents/order_update.py`

  ```python
  from kindgi import Agent

  order_update = Agent(
      id="acme.order-update",
      version="0.1.0",
      name="Order update",
      instructions="\n".join([
          "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.",
      ]),
      parameters=[{"name": "tone", "type": "string"}],
      capabilities=[{"needs": []}],
  )
  ```

- **Java**

  `src/main/java/acme/agents/OrderUpdate.java`

  ```java
  package acme.agents;

  import com.kindgi.pack.Agent;
  import java.util.List;
  import java.util.Map;

  public final class OrderUpdate {
    public static final Agent AGENT = Agent.define("acme.order-update")
        .version("0.1.0")
        .name("Order update")
        .instructions(String.join("\n",
            "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."))
        .set("parameters", List.of(Map.of("name", "tone", "type", "string")))
        .capability(Map.of("needs", List.of()))
        .build();

    private OrderUpdate() {}
  }
  ```

- **Scala**

  `src/main/scala/acme/agents/OrderUpdate.scala`

  ```scala
  package acme.agents

  import com.kindgi.pack.scaladsl._

  object OrderUpdate {
    val agent: Agent = Agent("acme.order-update")
      .version("0.1.0")
      .name("Order update")
      .instructions(Seq(
        "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.").mkString("\n"))
      .set("parameters", Seq(Map("name" -> "tone", "type" -> "string")))
      .capability(Map("needs" -> Seq()))
      .build()
  }
  ```

Run the flow:

- **TypeScript**

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

- **Python**

  ```sh
  uv run kindgi runs start --flow=acme.notify-customer --input='{"orderId":"A-1001"}'
  ```

- **Java**

  ```sh
  ./kindgiw runs start --flow=acme.notify-customer --input='{"orderId":"A-1001"}'
  ```

- **Scala**

  ```sh
  ./kindgiw 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:

```json excerpt
{
  …
  "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!"
  }
}
```

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

```text
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:

```json
{
  "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>`:

```json excerpt
{
  "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"
}
```

`text` is the answer. An agent with a typed answer also has `output`, as [Give an agent a typed answer](https://docs.kindgi.com/v0.1.10/guides/agents/typed-answer.md#in-a-flow) shows.

> **Caution: input exists only in a flow step**
>
> A direct run has no `{{ input }}`, so an agent whose instructions read it fails when run directly:
>
> ```text
> Error [model-invocation-failed]: Prompt render failed: Template references an unresolved variable: input
> ```

## What a turn returns

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](https://docs.kindgi.com/v0.1.10/guides/observability/trace-an-answer.md) describes. |

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

## Next

- [Give an agent a typed answer](https://docs.kindgi.com/v0.1.10/guides/agents/typed-answer.md)
- [Hold a conversation](https://docs.kindgi.com/v0.1.10/guides/agents/conversations.md)
- [Pass data between steps](https://docs.kindgi.com/v0.1.10/guides/flows/pass-data-between-steps.md)
