> ## Documentation Index
> Fetch the complete documentation index at: https://opensandbox-feat-monid-managed-catalog.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Inputs

> Read text, structured payloads, and input sources with useInput

`useInput()` reads the input that caused the current agent render. Use it to
include the current request in the instructions or change behavior based on
where the request came from.

```tsx theme={null}
import { useInput } from "@opencomputer/agent";

export default function Agent() {
  const input = useInput();
  return input.text
    ? `Help the user with this request: ${input.text}`
    : "Help the user with their request.";
}
```

`useCurrentInput()` is an alias for `useInput()`.

## Input shape

```ts theme={null}
interface AgentInput {
  readonly source: InputSource;
  readonly text?: string;
  readonly payload?: DataValue;
  readonly answer?: QuestionAnswer;
  readonly steering?: readonly HeldInput[];
}
```

| Field | Meaning |
| - | - |
| `source` | How the work entered the session: `user`, `channel`, `schedule`, `webhook`, `subagent`, `system` or `event` |
| `text` | Optional human-readable message |
| `payload` | Optional structured JSON value supplied by the source |
| `answer` | Present only when this input answers the question an earlier turn asked; see [Answers and steering](#answers-and-steering) |
| `steering` | Inputs written while that question was open that did not answer it, in order |

`DataValue` means any JSON-compatible value: `null`, a boolean, number,
string, array, or object. Both `text` and `payload` are optional, so check them
before use.

A payload comes from whatever started the turn. An application sends one on
the [turns route](/agents/api#turns) next to the text, and the agent reads it
with `source: "user"`; a [webhook](/agents/webhooks) delivers its body as the
payload; a [schedule](/agents/schedules) dispatches the payload it was
configured with. The agent reads all of them the same way.

A message from a connected [Slack app](/agents/slack) arrives with
`source: "channel"` and a `channel` object naming the `provider` (`slack`),
the `connectionId`, and the Slack `workspaceId`, `conversationId` and `userId`
when Slack supplies them. An agent serving one workspace can ignore all of
this; an agent behind a shared Slack app uses it to decide whose records to
read.

A message from a [Linear connection](/agents/linear) also arrives with
`source: "channel"`, with `channel.provider` set to `linear`,
`channel.workspaceId` the Linear workspace, `channel.conversationId` the
Linear agent session and `channel.userId` the person who wrote the message
(on the first message, the session's creator; absent when automation started
it).
Its `payload` is a `LinearInputPayload`: the issue, the session, the thread's
comments, your workspace's guidance for agents, and `origin`, which says
whether the issue had a parent and whether this agent's own app created it.
`origin` is read when the session starts and does not change afterwards. The
fields are listed on [Linear connections](/agents/linear#what-it-receives).

```tsx theme={null}
import { useInput, type LinearInputPayload } from "@opencomputer/agent";

export default function Agent() {
  const input = useInput();
  if (input.source === "channel" && input.channel.provider === "linear") {
    const linear = input.payload as unknown as LinearInputPayload;
    return linear.origin.createdByAgent && linear.origin.parent
      ? `Implement ${linear.issue.identifier}, part of ${linear.origin.parent.identifier}.`
      : `Investigate ${linear.issue.identifier} and propose an approach.`;
  }
  return `Help with: ${input.text ?? "the current request"}`;
}
```

## Adapt to the source

The current direct and delegated flows can share one agent definition:

```tsx theme={null}
import { useInput } from "@opencomputer/agent";

export default function Agent() {
  const input = useInput();

  return input.source === "subagent"
    ? "Complete the delegated task and return a concise result."
    : `Help with: ${input.text ?? "the current request"}`;
}
```

## Read structured payloads

Narrow or validate a payload before reading application-specific fields:

```tsx theme={null}
import { useInput } from "@opencomputer/agent";

type ResearchRequest = {
  topic?: string;
  depth?: "brief" | "deep";
};

export default function Agent() {
  const input = useInput();
  const request = (input.payload ?? {}) as ResearchRequest;

  if (request.topic) {
    return `Research ${request.topic} at ${request.depth ?? "brief"} depth.`;
  }

  return "Ask for a research topic before starting.";
}
```

Validate untrusted payloads in a tool before performing side effects.

## Event input

When an [event subscription](/agents/api#event-subscriptions) delivers
another session's turn outcome to this one, the turn's input has
`source: "event"` and an `event`:

```tsx theme={null}
import { useInput } from "@opencomputer/agent";

export default function Agent() {
  const input = useInput();
  if (input.source === "event") {
    const { event } = input;
    if (event.type === "turn.completed") {
      return `Worker ${event.agentId} finished turn ${event.turnId}. Its final message: ${event.result?.text ?? "(none)"}. Decide what happens next.`;
    }
    return `Worker ${event.agentId}'s turn ${event.type === "turn.failed" ? "failed" : "was cancelled"} (${event.reason ?? "no reason"}). ${event.error ?? ""}`;
  }
  return `Help with: ${input.text ?? "the current request"}`;
}
```

| Field | Meaning |
| - | - |
| `event.id` | The source session's event id for its terminal `turn.*` event |
| `event.type` | `turn.completed`, `turn.failed` or `turn.cancelled` |
| `event.sessionId`, `event.turnId`, `event.agentId` | Whose outcome this is |
| `event.occurredAt` | When the source turn settled |
| `event.reason` | Why it failed or was cancelled, when recorded |
| `event.error` | The failure message, bounded, when it failed |
| `event.result` | `{ text, truncated }`: the final assistant message of a completed turn, bounded to 16 KB |

An event input carries no `text`; read `event`. The turn's recorded input in
the [event log](/agents/events) is a text description of the same outcome.
The platform attests where the input came from through `source`; the
included message is another agent's output and is data to reason about, not
instructions to follow.

## Answers and steering

A turn can end with a question: the agent selects the
[`ask`](/agents/tools#ask-a-question) tool and the model calls it. The
reply is the next input, from any source, with `answer` set:

| Field | Meaning |
| - | - |
| `answer.questionId` | The question this input answers |
| `answer.text` | What the person wrote or selected |
| `answer.value` | The chosen option's `value`, when the text matched an option by value or label |

Input that arrives while the question is open without answering it does not
run a turn of its own. It is held and delivered with the answer as
`steering`, in the order it arrived; past a bounded number of items or 64 KiB,
the rest run as ordinary turns after the answer. In Linear, `steering` is
usually empty; see [Ask before acting](/agents/linear#ask-before-acting).

| Field | Meaning |
| - | - |
| `text`, `payload`, `channel` | The held input, as it would have arrived on its own |
| `receivedAt` | When OpenComputer received it |
| `providerTime` | When the provider says it was written, when it says |

Read `steering` before acting on the answer. A constraint written while the
question was open can change what a "go" means, and the agent should revise
its proposal rather than act on an answer the steering has overtaken.

```tsx theme={null}
import { useInput, useTool } from "@opencomputer/agent";

export default function Agent() {
  const input = useInput();
  if (input.answer) {
    const held = (input.steering ?? []).map((item) => `- ${item.text ?? ""}`).join("\n");
    return `The person answered: ${input.answer.value ?? input.answer.text}.${
      held ? `\nWritten meanwhile, read before acting:\n${held}` : ""
    }`;
  }
  useTool("ask");
  return "Read the request, propose a plan, and ask before making changes.";
}
```

`answer` and `steering` sit beside `payload`, not inside it, so they read the
same from every source and never collide with an application's payload.

## Input is not a prompt UI

`useInput()` only reads admitted input. It does not itself pause the session
to ask a person a question; a turn asks with the [`ask`](/agents/tools#ask-a-question)
tool, and the answer arrives as a later input. The durable conversation and
later messages are managed by the [session](/agents/sessions).

Input payload also differs from [session data](/agents/session-data): a payload
belongs to the current input, while session data can persist across renders.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.