> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# The Run

```text {13} theme={null}
support-agent/
├── agent.json
├── instructions.md
└── .telnyx/                        written by deploy
    ├── index.ts
    ├── telnyx.toml
    ├── telnyx-env.d.ts
    └── package.json

@telnyx/acp/                      the package
├── managed/
│   ├── index.ts
│   ├── agent.ts                                       ◀
│   ├── model.ts
│   ├── memory.ts
│   ├── tools.ts
│   ├── mcp.ts
│   ├── voice.ts
│   ├── direct-turn.ts
│   └── filler.ts
├── channels/
│   ├── index.ts
│   ├── phone.ts
│   ├── email.ts
│   ├── web.ts
│   └── wire.ts
├── synth/
│   ├── index.ts
│   ├── code-entry.ts
│   └── vendor.ts
└── spec/
    ├── schema.ts
    ├── model.ts
    ├── phone.ts
    ├── project.ts
    └── io.ts
```

The run executes as a task on the instance. The harness's tasks arrive at `onTask` in `managed/agent.ts`, which hands them to the harness:

```ts theme={null}
// managed/agent.ts
async onTask(name, payload, info) {
  if (name === DELIVERY_TASK) { await this.retryDelivery(payload); return; }   // a reply's next try; see Delivery
  if (!name.startsWith(HARNESS_TASK_PREFIX)) { await super.onTask(name, payload, info); return; }
  const harness = await this.ready();
  const before = (await this.messages.last())?.seq ?? 0;   // runs are dispatched one at a time, so what the log gains is this run's
  this.modelError = undefined;
  const run = await harness.dispatch({ name, payload });
  await this.noteRun(run, before);
}
```

`onTask(name, payload, info)` overrides the runtime SDK's [`onTask()`](/docs/agent-sdk/interface/onTask), the fallback for a task whose name is not a method of the class.

* The harness's task names start with `HARNESS_TASK_PREFIX`, `__telnyx_agent_harness_`, and name no method of the class, so the tasks arrive here.
* `DELIVERY_TASK`, `__telnyx_acp_deliver`, is the next try at a reply the channel refused; [Delivery](/docs/agent-sdk/inside/turn-taking/delivery) has the window.
* Any other task goes to `super.onTask`, the runtime's default, which treats it as delivered.

`this.messages.last()` is [`last()`](/docs/agent-sdk/interface/messages#last) on the message log. Runs are dispatched one at a time, so every message past the `seq` it returns is this run's.

`harness.dispatch({ name, payload })` is [`dispatch()`](/docs/agent-sdk/harness-sdk/harness/dispatch).

* `name` and `payload` are the task as the harness queued it.
* It executes the run's turn and returns the run's [`HarnessRun`](/docs/agent-sdk/harness-sdk/harness/get#harnessrun) as the turn left it.

Inside `dispatch`, three things happen.

* The model is called with the instructions and the conversation's message log.
* Tools run, subject to their approvals.
* Each assistant message is appended to the log as it lands.

When `dispatch` returns, `noteRun` writes the outcome to state, through the runtime SDK:

```ts theme={null}
// managed/agent.ts
async noteRun(run, before) {
  if (!run) return;
  const state = await this.getState();
  const last = await this.messages.last();
  const reply = last && last.seq > before && last.role === "assistant" && last.content.trim() !== "" ? last.content : undefined;
  // …
  const at = this.now();
  const patch = {};
  // …the outcome's fields, as in the table below
  if (Object.keys(patch).length) await this.setState(patch);
  // …delivery, then the memory push
}
```

* [`getState()`](/docs/agent-sdk/interface/getState) returns the runs already noted, so a redelivered task does not note a run twice.
* [`last()`](/docs/agent-sdk/interface/messages#last) returns the newest message. It is the reply only when its `seq` is past `before`, its role is `assistant` and it has text.
* [`now()`](/docs/agent-sdk/interface/now) is the time a completed or failed outcome records as `at`.
* [`setState()`](/docs/agent-sdk/interface/setState) merges the patch. A `null` in it deletes a key, as it deletes `awaitingApprovalRunId` once that run ends.

The outcome decides the keys written.

| Outcome | State |
| - | - |
| Completed with a reply | `lastReply`, `lastRunId`, and an entry in `pendingDeliveries` under the run id when the message came in through a channel |
| Completed with nothing to say | `lastRunId`, `failedRunId`, `lastError: "EMPTY_REPLY"` |
| Failed | `lastRunId`, `failedRunId`, `lastError` with the model's own message when it threw |
| Paused on an `ask` | `awaitingApprovalRunId` |

The state stream carries each of these, which is how `invoke` ends with a reply, or with a line that says why there is none. With memory on, a completed run's exchange is pushed to Agent Memory under the run's id. [Delivery](/docs/agent-sdk/inside/turn-taking/delivery) is the last step.
