Skip to content
Closed
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
4aa6eb2
feat(ai-orchestration): scaffold package
AlemTuzlak May 10, 2026
06e4f54
feat(ai-orchestration): add core public types
AlemTuzlak May 10, 2026
826920c
feat(ai-orchestration): add in-memory RunStore
AlemTuzlak May 10, 2026
8b39b2f
fix(ai-orchestration): align with repo lint conventions
AlemTuzlak May 10, 2026
03f95d8
feat(ai-orchestration): add approve, bindAgents, and retry primitives
AlemTuzlak May 10, 2026
fbb1114
feat(ai-orchestration): add state snapshot/diff and AG-UI event emit …
AlemTuzlak May 10, 2026
24702c6
feat(ai-orchestration): agent invocation with three return shapes
AlemTuzlak May 10, 2026
f2fcaaa
feat(ai-orchestration): workflow engine drive loop
AlemTuzlak May 10, 2026
916055a
fix(ai-orchestration): persist resumed state, share pendingEvents que…
AlemTuzlak May 10, 2026
2592f84
feat(ai-orchestration): public API helpers, SSE response, and index e…
AlemTuzlak May 10, 2026
8b3423a
feat(ai-client): WorkflowClient
AlemTuzlak May 10, 2026
018763d
feat(ai-react): useWorkflow + useOrchestration
AlemTuzlak May 10, 2026
c1334db
feat(ts-react-chat): article workflow demo
AlemTuzlak May 10, 2026
f8ce39d
feat(ts-react-chat): feature orchestrator demo
AlemTuzlak May 10, 2026
87d7129
feat(ts-react-chat): workflow & orchestration API routes
AlemTuzlak May 10, 2026
cf11d43
feat(ts-react-chat): workflow + orchestration demo pages
AlemTuzlak May 10, 2026
7b07432
test(ai-orchestration): engine smoke tests
AlemTuzlak May 10, 2026
de7f442
refactor(ai-orchestration): collapse runWorkflow/resumeWorkflow into …
AlemTuzlak May 10, 2026
2d273ac
refactor(ai-orchestration): drop toWorkflowSSEResponse wrapper
AlemTuzlak May 10, 2026
802548d
fix(ai-orchestration): make StepGenerator TNext=any so heterogeneous …
AlemTuzlak May 10, 2026
0c30b69
feat(ai-orchestration): pass agents map to orchestrator router for ty…
AlemTuzlak May 10, 2026
32a1987
refactor(ts-react-chat): simplify orchestrator router to be cast-free
AlemTuzlak May 10, 2026
a7bac73
chore(ts-react-chat): use toServerSentEventsResponse directly
AlemTuzlak May 10, 2026
5c2c310
feat(ai-orchestration): ok/fail result helpers
AlemTuzlak May 10, 2026
400dc3d
refactor(ai-orchestration): rename ok to succeed
AlemTuzlak May 10, 2026
58be487
feat(ai-orchestration): add defineRouter helper for extracted routers
AlemTuzlak May 10, 2026
aad5d98
refactor(ts-react-chat): drop redundant initialize and use defineRouter
AlemTuzlak May 10, 2026
95f095f
feat(ai-client): add endpoint shortcut for useWorkflow
AlemTuzlak May 10, 2026
247712b
refactor(ts-react-chat): use endpoint shortcut in demo pages
AlemTuzlak May 10, 2026
dd4bb66
feat(ai-orchestration): add handleWorkflowRequest server helper
AlemTuzlak May 10, 2026
5594a91
refactor(ts-react-chat): use handleWorkflowRequest in API routes
AlemTuzlak May 10, 2026
1473ace
refactor(ai-client): drop endpoint shortcut from WorkflowClient
AlemTuzlak May 10, 2026
474b73f
feat(ai-client): add fetchWorkflowEvents adapter helper
AlemTuzlak May 10, 2026
2e743ac
feat(ai-react): re-export fetchWorkflowEvents and FetchWorkflowEvents…
AlemTuzlak May 10, 2026
878dcfe
refactor(ai-orchestration): replace handleWorkflowRequest with parseW…
AlemTuzlak May 10, 2026
6253eee
refactor(ts-react-chat): use fetchWorkflowEvents + parseWorkflowRequest
AlemTuzlak May 10, 2026
9bbbc83
fix(ai-orchestration): default-import fast-json-patch for ESM/CJS int…
AlemTuzlak May 10, 2026
b7e7843
refactor(ai-orchestration): hand-roll JSON Patch differ, drop fast-js…
AlemTuzlak May 10, 2026
cefd387
fix(ai-react): stabilize useWorkflow client identity (mirror useChat …
AlemTuzlak May 10, 2026
6256f20
fix(ai-orchestration): share dispatch loop so resume handles full des…
AlemTuzlak May 10, 2026
37e31f3
feat(ts-react-chat): editorial-brutalist redesign of workflow + orche…
AlemTuzlak May 10, 2026
85224f3
feat(ai-orchestration,ai-client): stream workflow output through RUN_…
AlemTuzlak May 10, 2026
c0202ef
feat(ai-orchestration,ai-react): support free-text feedback on approv…
AlemTuzlak May 10, 2026
6db5d96
feat(ts-react-chat): article revision loop with editor feedback and 3…
AlemTuzlak May 10, 2026
f87140b
feat(ts-react-chat): live DraftPreview in workflow right column
AlemTuzlak May 10, 2026
9880c45
feat: finalize approval step on resume + modal preview of published a…
AlemTuzlak May 10, 2026
16354b7
ci: apply automated fixes
autofix-ci[bot] May 10, 2026
1db8896
Merge remote-tracking branch 'origin/main' into worktree-cryptic-sing…
AlemTuzlak May 15, 2026
af87834
feat(ai-orchestration): accept streaming structured output, surface l…
AlemTuzlak May 15, 2026
efe80c1
feat(ts-react-chat): streaming structured output demos + terminal orc…
AlemTuzlak May 15, 2026
f6c67ea
ci: apply automated fixes
autofix-ci[bot] May 15, 2026
40bb4ad
Merge remote-tracking branch 'origin/main' into worktree-cryptic-sing…
AlemTuzlak May 20, 2026
af0d484
chore: satisfy stricter lint + knip after merging main
AlemTuzlak May 20, 2026
a19e83d
docs(ai-orchestration): add Workflows & Orchestration section + agent…
AlemTuzlak May 20, 2026
0f66212
ci: apply automated fixes
autofix-ci[bot] May 20, 2026
5486c02
Feat/durable workflows (#589)
AlemTuzlak May 20, 2026
7322d91
chore(ai-orchestration): satisfy strict lint + override after #589
AlemTuzlak May 20, 2026
62bb9d6
test(ai-orchestration): apply test-hygiene to the engine tests
AlemTuzlak May 20, 2026
5c8d49c
chore: regenerate routeTree.gen.ts
AlemTuzlak May 20, 2026
73adcc1
chore(cr-loop): fix docs/packaging/configs/tests bucket (a) findings
AlemTuzlak May 20, 2026
b9d3fcd
fix(ts-react-chat): example-app bucket (a) findings from cr-loop
AlemTuzlak May 20, 2026
5abad6c
ci: apply automated fixes
autofix-ci[bot] May 20, 2026
ecc1431
chore(ai-orchestration): two low-risk engine fixes from cr-loop
AlemTuzlak May 20, 2026
e86b405
fix(ai-orchestration): land remaining bucket (a) engine + client fixe…
AlemTuzlak May 20, 2026
b6f1836
ci: apply automated fixes
autofix-ci[bot] May 20, 2026
04dcab8
fix(orchestration): address CodeRabbit review feedback
AlemTuzlak May 20, 2026
3288d6a
Merge branch 'main' into worktree-cryptic-singing-wadler
AlemTuzlak May 20, 2026
3a51d7b
ci: apply automated fixes
autofix-ci[bot] May 20, 2026
0849ab6
refactor(ai-orchestration): delegate workflows to workflow-core
AlemTuzlak May 23, 2026
53532dc
Merge branch 'main' into worktree-cryptic-singing-wadler
AlemTuzlak May 23, 2026
17cbfc1
fix(ai-orchestration): uniquify repeated workflow step ids
AlemTuzlak May 23, 2026
1ef0f5d
fix(example): revise articles from skeptic feedback
AlemTuzlak May 23, 2026
b3725cf
Merge branch 'main' into worktree-cryptic-singing-wadler
AlemTuzlak May 26, 2026
6c80cb8
chore(ai-orchestration): upgrade @tanstack/workflow-core to 0.0.2
AlemTuzlak May 26, 2026
7489015
ci: apply automated fixes
autofix-ci[bot] May 26, 2026
d3098e8
Merge branch 'main' into worktree-cryptic-singing-wadler
AlemTuzlak May 26, 2026
c28f61f
Merge branch 'main' into worktree-cryptic-singing-wadler
AlemTuzlak May 26, 2026
edca758
docs(ai-orchestration): align workflow docs and hook schema inference
AlemTuzlak May 28, 2026
fd3d49a
Merge branch 'main' into worktree-cryptic-singing-wadler
AlemTuzlak May 28, 2026
1d2e36f
chore: refresh pnpm lockfile
AlemTuzlak May 28, 2026
95b4c3e
merge main into orchestration PR
AlemTuzlak May 28, 2026
9de8cfa
ci: apply automated fixes
autofix-ci[bot] May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .agent/self-learning/coupling.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
"packages/typescript/ai/skills/ai-core/ag-ui-protocol/SKILL.md",
"packages/typescript/ai/skills/ai-core/debug-logging/SKILL.md",
"packages/typescript/ai/skills/ai-core/custom-backend-integration/SKILL.md",
"packages/typescript/ai-code-mode/skills/ai-code-mode/SKILL.md"
"packages/typescript/ai-code-mode/skills/ai-code-mode/SKILL.md",
"packages/typescript/ai-orchestration/skills/ai-orchestration/SKILL.md"
],
"kind": "change-required",
"why": "Agent skills are a contract with downstream coding agents. When the source surface they cover changes (new public API, changed type, new pattern, removed pattern, deprecation), the skill must be updated in the same PR — otherwise agents reading the skill keep generating obsolete or wrong code targeting a surface that no longer exists. Use this list to decide which skill(s) cover the file you're touching: `activities/chat/**` → chat-experience / structured-outputs / tool-calling; `activities/generateImage|generateAudio|generateVideo|generateSpeech|generateTranscription|summarize/**` → media-generation; `middleware/**` → middleware; `protocol/**` → ag-ui-protocol; `adapters/**` or anything that affects the adapter contract → adapter-configuration. Skip only for pure refactors / perf / internal-only changes that don't surface a new pattern or change observable behavior."
"why": "Agent skills are a contract with downstream coding agents. When the source surface they cover changes (new public API, changed type, new pattern, removed pattern, deprecation), the skill must be updated in the same PR — otherwise agents reading the skill keep generating obsolete or wrong code targeting a surface that no longer exists. Use this list to decide which skill(s) cover the file you're touching: `activities/chat/**` → chat-experience / structured-outputs / tool-calling; `activities/generateImage|generateAudio|generateVideo|generateSpeech|generateTranscription|summarize/**` → media-generation; `middleware/**` → middleware; `protocol/**` → ag-ui-protocol; `adapters/**` or anything that affects the adapter contract → adapter-configuration; `packages/typescript/ai-orchestration/src/**` → ai-orchestration. Skip only for pure refactors / perf / internal-only changes that don't surface a new pattern or change observable behavior."
}
]
},
Expand All @@ -39,7 +40,8 @@
"docs/protocol/**/*.md",
"docs/media/**/*.md",
"docs/code-mode/**/*.md",
"docs/migration/**/*.md"
"docs/migration/**/*.md",
"docs/orchestration/**/*.md"
],
"kind": "change-required",
"why": "Public docs are the canonical source for users. When the source surface they describe changes — new capability, behavior change, deprecation — the docs must be updated in the same PR. Cases to watch for: (1) the new behavior contradicts existing doc advice (e.g. removing a hack the doc still recommends); (2) the new capability opens a use case no existing page covers (consider whether a new page is needed, plus nav config and cross-links); (3) a public type / function gains or loses generic parameters, optional fields, etc. Run `pnpm test:docs` after editing to catch cross-link rot. Skip only for pure refactors / perf / internal-only changes."
Expand Down
342 changes: 342 additions & 0 deletions docs/api/ai-orchestration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
---
title: "@tanstack/ai-orchestration"
id: tanstack-ai-orchestration-api
order: 8
description: "API reference for @tanstack/ai-orchestration — defineAgent, defineWorkflow, defineOrchestrator, approve(), retry(), runWorkflow, inMemoryRunStore, and the workflow run types."
keywords:
- tanstack ai
- "@tanstack/ai-orchestration"
- defineAgent
- defineWorkflow
- defineOrchestrator
- approve
- retry
- runWorkflow
- RunStore
- api reference
---

Generator-based workflows and orchestrators for TanStack AI. Compose typed agents with `yield*`, route dynamically with a router generator, pause for approvals, and stream every step as AG-UI events.

For guided journeys see the [Workflows & Orchestration](../orchestration/overview) section.

## Installation

```bash
npm install @tanstack/ai-orchestration
```

Peer dependency: `@tanstack/ai`.

## `defineAgent(config)`

Wrap a function or `chat()` call as a typed agent.

```typescript
import { defineAgent } from "@tanstack/ai-orchestration";
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { z } from "zod";

const translate = defineAgent({
name: "translate",
input: z.object({ text: z.string(), target: z.string() }),
output: z.object({ translated: z.string() }),
run: ({ input }) =>
chat({
adapter: openaiText("gpt-5.2"),
outputSchema: z.object({ translated: z.string() }),
stream: true,
messages: [
{ role: "user", content: `Translate to ${input.target}: ${input.text}` },
],
}),
});
```

### Config

| Field | Type | Description |
|---|---|---|
| `name` | `string` | Unique step name used in events |
| `description` | `string?` | Optional, surfaced in observability |
| `input` | `StandardSchemaV1?` | Validated before `run` is called. `SchemaValidationError` thrown on failure. |
| `output` | `StandardSchemaV1?` | Validated after `run` produces a value. `SchemaValidationError` thrown on failure. |
| `run` | `(args) => AgentRunResult<TOutput>` | The agent body. See return shapes below. |

### `run` argument

`{ input, emit, signal }` — `input` is the typed, validated input. `emit(name, value)` pushes a `CUSTOM` event to the client. `signal` is an `AbortSignal` you can pass to anything that accepts one natively (e.g. `fetch`). For forwarding into `chat()`, bridge to an `AbortController` — see [Retries & Errors](../orchestration/retries-and-errors#3-honor-abort-signals).

### `run` return shapes

| Shape | When |
|---|---|
| `Promise<TOutput>` | Non-LLM agents (DB fetch, computation). |
| `StructuredOutputStream<TOutput>` | `chat({ outputSchema, stream: true })`. The runtime drains and parses. |
| `AsyncIterable<StreamChunk>` | A raw `chat()` stream (no `outputSchema`). Final output parsed from accumulated text. |
| `{ stream, output }` | Manual split — your own stream and a separately-resolved typed value. |

## `defineWorkflow(config)`

Compose agents into a linear generator-based workflow.

```typescript
import { defineWorkflow } from "@tanstack/ai-orchestration";
import { z } from "zod";

const pipeline = defineWorkflow({
name: "pipeline",
input: z.object({ text: z.string() }),
output: z.object({ summary: z.string() }),
agents: { translate, summarize },
run: async function* ({ input, agents }) {
const t = yield* agents.translate({ text: input.text, target: "english" });
const s = yield* agents.summarize({ text: t.translated });
return { summary: s.summary };
},
});
```

### Config

| Field | Type | Description |
|---|---|---|
| `name` | `string` | |
| `description` | `string?` | |
| `input` | `StandardSchemaV1?` | |
| `output` | `StandardSchemaV1?` | |
| `state` | `StandardSchemaV1?` | Shape of mutable state available to the generator. |
| `agents` | `AgentMap` | Record of `defineAgent(...)` or `defineWorkflow(...)` instances. |
| `initialize` | `(args) => Partial<TState>?` | Seed initial state from input. |
| `run` | `(args) => AsyncGenerator<StepDescriptor, TOutput, unknown>` | Generator body. `yield*` agents to compose. |

`run` argument: `{ input, state, agents, emit, signal }`. `state` is mutable. `agents` is the typed bound map — call `agents.someAgent({...})` and `yield*` the result.

## `defineOrchestrator(config)`

A workflow whose `run` body is a routing loop. You write a `router` generator that picks the next agent each turn.

```typescript
import { defineOrchestrator } from "@tanstack/ai-orchestration";

const orchestrator = defineOrchestrator({
...sharedConfig,
name: "feature-orchestrator",
maxTurns: 20,
router: function* ({ agents, state, lastResult }) {
const triage = yield* agents.triage({ /* ... */ });
if (triage.next === "done") return { done: true, output: { /* ... */ } };
return { agent: triage.next, input: { /* ... */ } };
},
});
```

### Config

Inherits all fields from `defineWorkflow`, plus:

| Field | Type | Description |
|---|---|---|
| `router` | `(args) => StepGenerator<RouterDecision>` | Routing generator. |
| `maxTurns` | `number?` | Max router iterations before throwing. Default `12`. |

### `router` argument

`{ input, state, agents, turn, lastResult }`. `turn` is the 0-indexed iteration count. `lastResult` is the typed output of the agent dispatched on the previous turn (`undefined` on turn 0).

### `RouterDecision`

```typescript
type RouterDecision =
| { done: true; output: TOutput }
| { done?: false; agent: keyof TAgents; input: unknown };
```

## `defineRouter(config, router)`

Phantom-config helper for pulling the router out of the `defineOrchestrator` call while preserving inference.

```typescript
const config = { agents, input, output, state };
const myRouter = defineRouter(config, function* ({ agents, state }) {
// `agents` and `state` are typed here.
return { done: true, output: { /* ... */ } };
});
defineOrchestrator({ ...config, name: "...", router: myRouter });
```

The first argument is ignored at runtime — it exists only so TypeScript can infer the router's `agents` / `input` / `output` / `state` types.

## `approve(options)`

Yieldable approval primitive. Pauses the run, emits `approval-requested`, closes the SSE, resumes on the next client request.

```typescript
const decision = yield* approve({
title: "Implement?",
description: "5 files to patch",
});
if (!decision.approved) throw new Error(decision.feedback ?? "Declined");
```

| Option | Type | |
|---|---|---|
| `title` | `string` | Required. Shown by the client. |
| `description` | `string?` | Optional detail. |

Returns `ApprovalResult`:

```typescript
interface ApprovalResult {
approved: boolean;
approvalId: string;
feedback?: string;
}
```

## `retry(fn, options)`

Retry a yieldable step on failure.

```typescript
const draft = yield* retry(
() => agents.writer({ topic }),
{ attempts: 3, backoff: "exponential", baseDelayMs: 200 },
);
```

| Option | Default | |
|---|---|---|
| `attempts` | — | Total attempts. Required. |
| `backoff` | `'none'` | `'none' \| 'linear' \| 'exponential'` |
| `baseDelayMs` | `100` | Base delay. |
| `maxDelayMs` | `5000` | Max delay cap. |
| `retryOn` | retry any | `(err, attempt) => boolean`. Return `false` to surface the error. |

## `runWorkflow(options)`

Server-side: run a workflow (or orchestrator) and stream AG-UI events.

```typescript
import { toServerSentEventsResponse } from "@tanstack/ai";
import {
inMemoryRunStore,
parseWorkflowRequest,
runWorkflow,
} from "@tanstack/ai-orchestration";

const runStore = inMemoryRunStore({ ttl: 60 * 60 * 1000 });

export async function POST(request: Request) {
const params = await parseWorkflowRequest(request);
if (params.abort && params.runId) {
runStore.getLive(params.runId)?.abortController.abort();
return new Response(null, { status: 204 });
}
const stream = runWorkflow({ workflow, runStore, ...params });
return toServerSentEventsResponse(stream);
}
```

| Option | Type | |
|---|---|---|
| `workflow` | `WorkflowDefinition` | Required. The workflow or orchestrator. |
| `runStore` | `InMemoryRunStore` | Required. |
| `input` | `unknown?` | Provide on the *first* call to start a run. |
| `runId` | `string?` | Provide alongside `approval` to resume a paused run. |
| `approval` | `ApprovalResult?` | Provide alongside `runId` to resume. |
| `signal` | `AbortSignal?` | Optional external abort. |
| `threadId` | `string?` | Optional correlation ID surfaced in events. |
| `outputSink` | `(output) => void?` | Called with the final output before the store entry is deleted. |

Returns `AsyncIterable<StreamChunk>` — pipe directly to `toServerSentEventsResponse`.

## `parseWorkflowRequest(request)`

Parse a POST body into `runWorkflow` params.

```typescript
const params = await parseWorkflowRequest(request);
// { input?, runId?, approval?, abort? }
```

## `inMemoryRunStore(options)`

Single-process run store. Holds `RunState` plus the live generator handle so the engine can resume in-process.

```typescript
const runStore = inMemoryRunStore({ ttl: 60 * 60 * 1000 });
```

| Option | Default | |
|---|---|---|
| `ttl` | `60 * 60 * 1000` | TTL in ms. Resets on every `set()`. |

Returns `InMemoryRunStore` which extends `RunStore` with `setLive` / `getLive` for the engine-internal live generator handle.

For durable persistence options see [Run Persistence](../orchestration/run-persistence).

## `fail(...)` / `succeed(...)`

Result helpers exported for use in agent / workflow bodies that prefer a Result-typed return over throw/return.

```typescript
import { fail, succeed } from "@tanstack/ai-orchestration";

return succeed({ patches });
// or
return fail("Spec didn't validate");
```

## `SchemaValidationError`

Thrown when input or output validation fails inside an agent.

```typescript
import { SchemaValidationError } from "@tanstack/ai-orchestration";

try {
// ...
} catch (err) {
if (err instanceof SchemaValidationError) {
console.error(err.message, err.issues);
}
}
```

`issues` is a `ReadonlyArray<unknown>` containing the Standard Schema validation issues.

## Types

| Type | Description |
|---|---|
| `AgentDefinition` | The return type of `defineAgent`. |
| `WorkflowDefinition` | The return type of `defineWorkflow` and `defineOrchestrator`. |
| `AgentMap` | `Record<string, AgentDefinition \| WorkflowDefinition>` |
| `AgentRunArgs<TInput>` | `{ input, emit, signal }` |
| `AgentRunResult<TOutput>` | Union of the four allowable agent return shapes |
| `WorkflowRunArgs<TInput, TState, TAgents>` | `{ input, state, agents, emit, signal }` |
| `BoundAgents<TAgents>` | Typed callable map injected into workflow / router bodies |
| `StepDescriptor` | What the engine sees on `yield`. Tagged `'agent' \| 'nested-workflow' \| 'approval'`. |
| `StepGenerator<T>` | `Generator<StepDescriptor, T, any>` — what `agents.*(...)` returns. |
| `ApprovalResult` | `{ approved, approvalId, feedback? }` |
| `RouterDecision` | `{ done: true, output } \| { agent, input }` |
| `RunState` | Serializable snapshot of a run. |
| `RunStatus` | `'running' \| 'paused' \| 'finished' \| 'error' \| 'aborted'` |
| `RunStore` | Persistence interface: `get` / `set` / `delete`. |
| `InMemoryRunStore` | Extends `RunStore` with `setLive` / `getLive`. |
| `DeleteReason` | `'finished' \| 'error' \| 'aborted'` |
| `EmitFn` | `(name, value) => void` |
| `LiveRun` | Engine-internal live handle (live generator, abort controller, etc). |

## Client-side hooks

The companion client hooks live in framework packages:

- `useWorkflow` — `@tanstack/ai-react`, `@tanstack/ai-solid`, `@tanstack/ai-vue`, `@tanstack/ai-svelte`, `@tanstack/ai-preact`
- `useOrchestration` — same hook, re-exported under a routing-friendly name
- `WorkflowClient` — `@tanstack/ai-client` for vanilla / non-React clients
- `fetchWorkflowEvents(url, options?)` — connection adapter, exported from every framework package and `@tanstack/ai-client`

See the framework-specific [`@tanstack/ai-react` reference](./ai-react) for hook signatures.
2 changes: 2 additions & 0 deletions docs/chat/agentic-cycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ The agentic cycle is the pattern where the LLM repeatedly calls tools, receives

> **Tip:** Code Mode can reduce agent loop iterations by letting the LLM write a program that calls multiple tools in a single execution. See [Code Mode](../code-mode/code-mode).

> **Note:** The agent loop's routing is implicit — the model picks the next tool inside one `chat()` call. If you need the routing to be **explicit** (e.g. a triage agent decides between distinct LLM steps, each with its own typed input/output) and the steps must surface to the client as separate events, reach for an [Orchestrator](../orchestration/orchestrators) instead.

```mermaid
graph TD
A[User sends message] --> B[LLM analyzes request]
Expand Down
Loading
Loading