@directive-run/knowledge 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -15
- package/ai/ai-adapters.md +7 -0
- package/ai/ai-agents-streaming.md +187 -149
- package/ai/ai-budget-resilience.md +305 -132
- package/ai/ai-communication.md +220 -197
- package/ai/ai-debug-observability.md +259 -173
- package/ai/ai-guardrails-memory.md +191 -153
- package/ai/ai-mcp-rag.md +204 -199
- package/ai/ai-multi-agent.md +254 -153
- package/ai/ai-orchestrator.md +353 -114
- package/ai/ai-security.md +287 -180
- package/ai/ai-tasks.md +8 -1
- package/ai/ai-testing-evals.md +363 -256
- package/core/anti-patterns.md +18 -2
- package/core/constraints.md +13 -2
- package/core/core-patterns.md +12 -0
- package/core/error-boundaries.md +8 -0
- package/core/history.md +7 -0
- package/core/multi-module.md +15 -3
- package/core/naming.md +128 -90
- package/core/plugins.md +7 -0
- package/core/react-adapter.md +256 -174
- package/core/resolvers.md +10 -0
- package/core/schema-types.md +8 -0
- package/core/system-api.md +10 -0
- package/core/testing.md +257 -143
- package/examples/checkers.ts +15 -16
- package/examples/contact-form.ts +2 -2
- package/examples/counter-react.ts +1 -1
- package/examples/counter-svelte.ts +1 -1
- package/examples/counter-vue.ts +1 -1
- package/examples/counter.ts +1 -1
- package/examples/data-triggers.ts +4 -4
- package/examples/feature-flags.ts +2 -2
- package/examples/form-wizard.ts +2 -2
- package/examples/newsletter.ts +2 -2
- package/examples/server.ts +2 -2
- package/examples/shopping-cart.ts +1 -1
- package/examples/topic-guard.ts +1 -1
- package/package.json +3 -3
- package/sitemap.md +17 -11
- package/examples/debounce-constraints.ts +0 -95
- package/examples/multi-module.ts +0 -58
package/ai/ai-orchestrator.md
CHANGED
|
@@ -1,31 +1,38 @@
|
|
|
1
|
-
# AI Orchestrator (
|
|
1
|
+
# AI Orchestrator (single-agent)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Covers `@directive-run/ai` — `createAgentOrchestrator` for single-agent runs with constraints, resolvers, guardrails, memory, budgets, approval, breakpoints, retry, structured output, circuit breakers, checkpoints.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`createAgentOrchestrator` builds a Directive-backed runtime for ONE AI agent with constraints, resolvers, guardrails, memory, budgets, approval, breakpoints, retry, structured output, circuit breakers, checkpoints, and observability hooks.
|
|
6
|
+
|
|
7
|
+
For multiple agents (pipelines, debates, DAGs), see `ai-multi-agent.md`.
|
|
8
|
+
|
|
9
|
+
## Decision tree
|
|
6
10
|
|
|
7
11
|
```
|
|
8
|
-
|
|
9
|
-
├──
|
|
10
|
-
├──
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
├── Need
|
|
14
|
-
├── Need
|
|
15
|
-
├── Need
|
|
16
|
-
├── Need
|
|
17
|
-
├── Need
|
|
18
|
-
|
|
12
|
+
Setting up createAgentOrchestrator…
|
|
13
|
+
├── Custom orchestrator state? → factsSchema with t.*() builders (NOT TS types)
|
|
14
|
+
├── Need input/output guardrails? → guardrails: { input: [...], output: [...] }
|
|
15
|
+
├── Need conversation memory? → memory: createAgentMemory({ strategy })
|
|
16
|
+
├── Need token budget? → maxTokenBudget + onBudgetWarning (TOP-LEVEL — not in hooks)
|
|
17
|
+
├── Need streaming? → orchestrator.runStream(agent, input) returns { stream, result, abort }
|
|
18
|
+
├── Need approval before tool calls? → onApprovalRequest + orchestrator.approve()/reject()
|
|
19
|
+
├── Need human-in-the-loop pauses? → breakpoints: [...] + onBreakpoint callback
|
|
20
|
+
├── Need observability? → hooks.onAgentStart / onAgentComplete / onAgentError / onAgentRetry / onGuardrailCheck
|
|
21
|
+
├── Need automatic retry on failure? → agentRetry: { maxRetries, baseDelayMs }
|
|
22
|
+
├── Need structured output? → outputSchema: zodSchema (with maxSchemaRetries)
|
|
23
|
+
├── Need failure isolation? → circuitBreaker: createCircuitBreaker(...)
|
|
24
|
+
└── Need save/restore? → checkpointStore + orchestrator.checkpoint()/restore()
|
|
19
25
|
```
|
|
20
26
|
|
|
21
|
-
## Basic
|
|
27
|
+
## Basic setup
|
|
22
28
|
|
|
23
29
|
```typescript
|
|
24
|
-
import { createAgentOrchestrator
|
|
30
|
+
import { createAgentOrchestrator } from "@directive-run/ai";
|
|
25
31
|
import { createAnthropicRunner } from "@directive-run/ai/anthropic";
|
|
32
|
+
import { t } from "@directive-run/core";
|
|
26
33
|
|
|
27
34
|
const runner = createAnthropicRunner({
|
|
28
|
-
apiKey: process.env.ANTHROPIC_API_KEY
|
|
35
|
+
apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
29
36
|
});
|
|
30
37
|
|
|
31
38
|
const orchestrator = createAgentOrchestrator({
|
|
@@ -33,12 +40,10 @@ const orchestrator = createAgentOrchestrator({
|
|
|
33
40
|
factsSchema: {
|
|
34
41
|
confidence: t.number(),
|
|
35
42
|
analysis: t.string(),
|
|
36
|
-
cache: t.array<string>(),
|
|
37
43
|
},
|
|
38
44
|
init: (facts) => {
|
|
39
45
|
facts.confidence = 0;
|
|
40
46
|
facts.analysis = "";
|
|
41
|
-
facts.cache = [];
|
|
42
47
|
},
|
|
43
48
|
constraints: {
|
|
44
49
|
lowConfidence: {
|
|
@@ -48,180 +53,414 @@ const orchestrator = createAgentOrchestrator({
|
|
|
48
53
|
},
|
|
49
54
|
resolvers: {
|
|
50
55
|
reAnalyze: {
|
|
51
|
-
requirement: "RE_ANALYZE",
|
|
56
|
+
requirement: (req): req is { type: "RE_ANALYZE" } => req.type === "RE_ANALYZE",
|
|
52
57
|
resolve: async (req, context) => {
|
|
53
|
-
context.facts.confidence =
|
|
58
|
+
context.facts.confidence = 1;
|
|
54
59
|
},
|
|
55
60
|
},
|
|
56
61
|
},
|
|
57
|
-
guardrails: {
|
|
58
|
-
input: [createPIIGuardrail({ redact: true })],
|
|
59
|
-
output: [createLengthGuardrail({ maxChars: 5000 })],
|
|
60
|
-
},
|
|
61
|
-
maxTokenBudget: 100000,
|
|
62
|
-
budgetWarningThreshold: 0.8,
|
|
63
|
-
memory: createAgentMemory({
|
|
64
|
-
strategy: createSlidingWindowStrategy({ maxMessages: 50 }),
|
|
65
|
-
summarizer: createKeyPointsSummarizer(),
|
|
66
|
-
}),
|
|
67
|
-
debug: true,
|
|
68
|
-
hooks: {
|
|
69
|
-
onStart: () => console.log("Orchestrator started"),
|
|
70
|
-
onBeforeRun: (agent, prompt) => ({ approved: true }),
|
|
71
|
-
onAfterRun: (agent, result) => console.log("Done", result.totalTokens),
|
|
72
|
-
onError: (error) => console.error(error),
|
|
73
|
-
onBudgetWarning: (usage) => console.warn("Budget:", usage),
|
|
74
|
-
},
|
|
75
62
|
});
|
|
63
|
+
|
|
64
|
+
const result = await orchestrator.run(
|
|
65
|
+
{ name: "analyst", instructions: "You are a data analyst.", model: "claude-sonnet-4-5" },
|
|
66
|
+
"Analyze this dataset",
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
console.log(result.output, result.tokenUsage);
|
|
76
70
|
```
|
|
77
71
|
|
|
78
|
-
## Running
|
|
72
|
+
## Running an agent
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
name: "analyst",
|
|
83
|
-
instructions: "You are a data analyst.",
|
|
84
|
-
model: "claude-sonnet-4-5",
|
|
85
|
-
};
|
|
74
|
+
`run(agent, input, options?)` resolves to `RunResult<T>`.
|
|
75
|
+
`runStream(agent, input, options?)` returns `{ stream, result, abort }` — `stream` is the async iterator, `result` is a promise for the final result, `abort` cancels the in-flight run.
|
|
86
76
|
|
|
77
|
+
```typescript
|
|
87
78
|
// Standard run
|
|
88
79
|
const result = await orchestrator.run(agent, "Analyze this dataset");
|
|
89
|
-
console.log(result.output);
|
|
80
|
+
console.log(result.output, result.tokenUsage);
|
|
81
|
+
|
|
82
|
+
// Streaming run — destructure the three handles
|
|
83
|
+
const { stream, result, abort } = orchestrator.runStream(agent, "Summarize findings");
|
|
90
84
|
|
|
91
|
-
// Streaming run
|
|
92
|
-
const stream = orchestrator.runStream(agent, "Summarize findings");
|
|
93
85
|
for await (const chunk of stream) {
|
|
94
86
|
if (chunk.type === "token") {
|
|
95
87
|
process.stdout.write(chunk.data);
|
|
96
88
|
}
|
|
89
|
+
if (chunk.type === "approval_required") {
|
|
90
|
+
// Show your approval UI; resolve with orchestrator.approve(chunk.requestId)
|
|
91
|
+
}
|
|
92
|
+
if (chunk.type === "guardrail_triggered") {
|
|
93
|
+
console.warn("guardrail:", chunk.guardrail);
|
|
94
|
+
}
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
const final = await result;
|
|
98
|
+
|
|
99
|
+
// Wait for any in-flight resolvers to drain
|
|
100
|
+
await orchestrator.waitForIdle();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Reading orchestrator state
|
|
104
|
+
|
|
105
|
+
State lives on `orchestrator.facts.agent` — the `AgentState` is nested under `agent` because the orchestrator's facts shape is `OrchestratorState & F` (your custom facts merged with the orchestrator's built-ins).
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Built-in agent state
|
|
109
|
+
orchestrator.facts.agent.status; // "idle" | "running" | "paused" | "completed" | "error"
|
|
110
|
+
orchestrator.facts.agent.currentAgent; // string | null — the agent name when running
|
|
111
|
+
orchestrator.facts.agent.input; // string | null — current prompt
|
|
112
|
+
orchestrator.facts.agent.output; // unknown | null — last output
|
|
113
|
+
orchestrator.facts.agent.error; // string | null — last error message
|
|
114
|
+
orchestrator.facts.agent.tokenUsage; // number — cumulative tokens used
|
|
115
|
+
orchestrator.facts.agent.turnCount; // number — completed turns
|
|
116
|
+
orchestrator.facts.agent.startedAt; // number | null — ms timestamp
|
|
117
|
+
orchestrator.facts.agent.completedAt; // number | null
|
|
118
|
+
|
|
119
|
+
// Cumulative tokens (also exposed at the top of the orchestrator)
|
|
120
|
+
orchestrator.totalTokens;
|
|
121
|
+
|
|
122
|
+
// Approval queue (when autoApproveToolCalls: false)
|
|
123
|
+
orchestrator.facts.approval.pending; // ApprovalRequest[]
|
|
124
|
+
orchestrator.facts.approval.approved; // string[]
|
|
125
|
+
orchestrator.facts.approval.rejected; // RejectedRequest[]
|
|
126
|
+
|
|
127
|
+
// Conversation + tool call history
|
|
128
|
+
orchestrator.facts.conversation; // Message[]
|
|
129
|
+
orchestrator.facts.toolCalls; // ToolCall[]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Token budget
|
|
133
|
+
|
|
134
|
+
`maxTokenBudget` is the cap. When usage crosses it the orchestrator pauses (sets `facts.agent.status = "paused"`). `budgetWarningThreshold` (0–1, default 0.8) fires `onBudgetWarning` BEFORE the cap. **Both options are top-level — NOT inside `hooks:`**.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const orchestrator = createAgentOrchestrator({
|
|
138
|
+
runner,
|
|
139
|
+
maxTokenBudget: 100_000,
|
|
140
|
+
budgetWarningThreshold: 0.8,
|
|
141
|
+
onBudgetWarning: ({ currentTokens, maxBudget, percentage }) => {
|
|
142
|
+
console.warn(`Token usage at ${Math.round(percentage * 100)}% (${currentTokens}/${maxBudget})`);
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Memory
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { createAgentMemory, createSlidingWindowStrategy, createKeyPointsSummarizer } from "@directive-run/ai";
|
|
151
|
+
|
|
152
|
+
const orchestrator = createAgentOrchestrator({
|
|
153
|
+
runner,
|
|
154
|
+
memory: createAgentMemory({
|
|
155
|
+
strategy: createSlidingWindowStrategy({ maxMessages: 50 }),
|
|
156
|
+
summarizer: createKeyPointsSummarizer(),
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
101
159
|
```
|
|
102
160
|
|
|
103
|
-
|
|
161
|
+
When `memory` is configured, prior conversation context is auto-injected into each agent run, and the agent's response is auto-stored. See `ai-guardrails-memory.md` for memory strategies in depth.
|
|
162
|
+
|
|
163
|
+
## Guardrails
|
|
104
164
|
|
|
105
165
|
```typescript
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
166
|
+
import {
|
|
167
|
+
createPIIGuardrail,
|
|
168
|
+
createLengthGuardrail,
|
|
169
|
+
createPromptInjectionGuardrail,
|
|
170
|
+
} from "@directive-run/ai/guardrails";
|
|
171
|
+
|
|
172
|
+
const orchestrator = createAgentOrchestrator({
|
|
173
|
+
runner,
|
|
174
|
+
guardrails: {
|
|
175
|
+
input: [
|
|
176
|
+
createPIIGuardrail({ redact: true }),
|
|
177
|
+
createPromptInjectionGuardrail({ strictMode: true }),
|
|
178
|
+
],
|
|
179
|
+
output: [
|
|
180
|
+
createLengthGuardrail({ maxCharacters: 5000 }),
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
});
|
|
111
184
|
```
|
|
112
185
|
|
|
113
|
-
|
|
186
|
+
See `ai-guardrails-memory.md` for the full list of guardrail factories and their actual option shapes.
|
|
187
|
+
|
|
188
|
+
## Lifecycle hooks (observability)
|
|
189
|
+
|
|
190
|
+
These hooks fire purely for observability — they cannot block, deny, or modify runs. To block a run before it executes, use `breakpoints` (next section) or guardrails.
|
|
114
191
|
|
|
115
192
|
```typescript
|
|
116
193
|
const orchestrator = createAgentOrchestrator({
|
|
117
194
|
runner,
|
|
118
195
|
hooks: {
|
|
119
|
-
|
|
120
|
-
|
|
196
|
+
onAgentStart: (e) => console.log(`▶ ${e.agentName} @ ${e.timestamp}`),
|
|
197
|
+
onAgentComplete: (e) => console.log(`✓ ${e.agentName} — ${e.tokenUsage} tokens in ${e.durationMs}ms`),
|
|
198
|
+
onAgentError: (e) => console.error(`✗ ${e.agentName}:`, e.error),
|
|
199
|
+
onAgentRetry: (e) => console.warn(`↻ ${e.agentName} attempt ${e.attempt}`),
|
|
200
|
+
onGuardrailCheck: (e) => console.log(`${e.passed ? "✓" : "✗"} ${e.guardrailName}`),
|
|
201
|
+
onBreakpoint: (req) => console.log(`⏸ breakpoint ${req.id}`),
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
```
|
|
121
205
|
|
|
122
|
-
|
|
123
|
-
|
|
206
|
+
The full event payload shapes live in `@directive-run/ai`'s `OrchestratorLifecycleHooks` interface.
|
|
207
|
+
|
|
208
|
+
## Human-in-the-loop: breakpoints + approval
|
|
209
|
+
|
|
210
|
+
For approval workflows (pause before a sensitive tool call), Directive offers two layered mechanisms:
|
|
211
|
+
|
|
212
|
+
### Tool-call approval (`autoApproveToolCalls: false`)
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const orchestrator = createAgentOrchestrator({
|
|
216
|
+
runner,
|
|
217
|
+
autoApproveToolCalls: false,
|
|
218
|
+
onApprovalRequest: (request) => {
|
|
219
|
+
showApprovalDialog(request); // your UI
|
|
124
220
|
},
|
|
221
|
+
approvalTimeoutMs: 5 * 60 * 1000,
|
|
125
222
|
});
|
|
126
223
|
|
|
127
|
-
//
|
|
224
|
+
// In your UI handler:
|
|
225
|
+
orchestrator.approve(request.id);
|
|
226
|
+
// or
|
|
227
|
+
orchestrator.reject(request.id, "policy violation");
|
|
128
228
|
```
|
|
129
229
|
|
|
130
|
-
|
|
230
|
+
### Breakpoints (arbitrary pause points)
|
|
131
231
|
|
|
132
232
|
```typescript
|
|
133
|
-
|
|
134
|
-
|
|
233
|
+
import type { BreakpointConfig } from "@directive-run/ai";
|
|
234
|
+
|
|
235
|
+
const orchestrator = createAgentOrchestrator({
|
|
236
|
+
runner,
|
|
237
|
+
breakpoints: [
|
|
238
|
+
{ id: "review-prompt", before: "agent_start" },
|
|
239
|
+
{ id: "review-output", after: "agent_complete" },
|
|
240
|
+
],
|
|
241
|
+
onBreakpoint: (request) => {
|
|
242
|
+
showReviewUI(request);
|
|
243
|
+
},
|
|
244
|
+
breakpointTimeoutMs: 5 * 60 * 1000,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Resume (optionally with input modifications)
|
|
248
|
+
orchestrator.resumeBreakpoint("review-prompt");
|
|
135
249
|
|
|
136
|
-
|
|
137
|
-
|
|
250
|
+
// Or cancel
|
|
251
|
+
orchestrator.cancelBreakpoint("review-prompt", "user aborted");
|
|
138
252
|
```
|
|
139
253
|
|
|
140
|
-
##
|
|
254
|
+
## Retry + circuit breaker + self-healing
|
|
141
255
|
|
|
142
256
|
```typescript
|
|
143
|
-
|
|
144
|
-
const checkpoint = orchestrator.checkpoint();
|
|
145
|
-
const serialized = JSON.stringify(checkpoint);
|
|
257
|
+
import { createCircuitBreaker } from "@directive-run/ai";
|
|
146
258
|
|
|
147
|
-
|
|
148
|
-
const restored = createAgentOrchestrator({
|
|
259
|
+
const orchestrator = createAgentOrchestrator({
|
|
149
260
|
runner,
|
|
150
|
-
|
|
261
|
+
agentRetry: {
|
|
262
|
+
maxRetries: 3,
|
|
263
|
+
baseDelayMs: 500,
|
|
264
|
+
maxDelayMs: 5000,
|
|
265
|
+
isRetryable: (err) => err.message.includes("rate_limit"),
|
|
266
|
+
onRetry: ({ attempt, error, delayMs }) => console.warn(`retry ${attempt} in ${delayMs}ms:`, error.message),
|
|
267
|
+
},
|
|
268
|
+
circuitBreaker: createCircuitBreaker({
|
|
269
|
+
failureThreshold: 5,
|
|
270
|
+
recoveryTimeMs: 60_000,
|
|
271
|
+
halfOpenMaxRequests: 1,
|
|
272
|
+
}),
|
|
151
273
|
});
|
|
152
274
|
```
|
|
153
275
|
|
|
154
|
-
|
|
276
|
+
See `ai-budget-resilience.md` for the resilience surface in depth (retry, fallback, circuit breaker, health monitor, self-healing).
|
|
155
277
|
|
|
156
|
-
|
|
278
|
+
## Structured output
|
|
157
279
|
|
|
158
280
|
```typescript
|
|
159
|
-
|
|
281
|
+
import { z } from "zod";
|
|
282
|
+
|
|
160
283
|
const orchestrator = createAgentOrchestrator({
|
|
161
284
|
runner,
|
|
162
|
-
|
|
285
|
+
outputSchema: z.object({
|
|
286
|
+
summary: z.string(),
|
|
287
|
+
confidence: z.number().min(0).max(1),
|
|
288
|
+
}),
|
|
289
|
+
maxSchemaRetries: 2,
|
|
163
290
|
});
|
|
164
291
|
|
|
165
|
-
|
|
292
|
+
const result = await orchestrator.run(agent, "Summarize this article");
|
|
293
|
+
// result.output is typed and parsed by the Zod schema; up to 2 retries on validation failure
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`outputSchema` accepts anything with a `safeParse(value)` method — Zod, Valibot, or your own validator.
|
|
297
|
+
|
|
298
|
+
## Pause / resume
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
orchestrator.pause(); // in-flight runs complete; new ones queue
|
|
302
|
+
orchestrator.resume(); // queued work begins executing
|
|
303
|
+
orchestrator.reset(); // clears conversation, approval, and tool-call state
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Checkpoints (save / restore)
|
|
307
|
+
|
|
308
|
+
`checkpoint()` is **async** — it returns a Promise. Restore on an EXISTING orchestrator instance with `restore()`; there is no constructor option that takes a checkpoint.
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { createInMemoryCheckpointStore } from "@directive-run/ai";
|
|
312
|
+
|
|
166
313
|
const orchestrator = createAgentOrchestrator({
|
|
167
314
|
runner,
|
|
168
|
-
|
|
169
|
-
confidence: t.number(),
|
|
170
|
-
analysis: t.string(),
|
|
171
|
-
},
|
|
315
|
+
checkpointStore: createInMemoryCheckpointStore(),
|
|
172
316
|
});
|
|
317
|
+
|
|
318
|
+
// Save
|
|
319
|
+
const cp = await orchestrator.checkpoint({ label: "after-analysis" });
|
|
320
|
+
const serialized = JSON.stringify(cp);
|
|
321
|
+
|
|
322
|
+
// Restore — on the same instance, or a fresh one with the same config shape
|
|
323
|
+
const newOrchestrator = createAgentOrchestrator({ runner, /* same options */ });
|
|
324
|
+
newOrchestrator.restore(JSON.parse(serialized));
|
|
173
325
|
```
|
|
174
326
|
|
|
175
|
-
|
|
327
|
+
## Anti-patterns
|
|
328
|
+
|
|
329
|
+
### TS types instead of `t.*()` for `factsSchema`
|
|
176
330
|
|
|
177
331
|
```typescript
|
|
178
|
-
// WRONG
|
|
332
|
+
// WRONG — TS types are erased at runtime; no schema validation, no defaults
|
|
333
|
+
factsSchema: {} as { confidence: number; analysis: string }
|
|
334
|
+
|
|
335
|
+
// CORRECT — t.*() builders provide runtime shape + types
|
|
336
|
+
factsSchema: { confidence: t.number(), analysis: t.string() }
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### In-place array/object mutation
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// WRONG — the proxy can't detect in-place mutations
|
|
179
343
|
context.facts.cache.push("new-item");
|
|
180
344
|
|
|
181
|
-
// CORRECT
|
|
345
|
+
// CORRECT — replace the value
|
|
182
346
|
context.facts.cache = [...context.facts.cache, "new-item"];
|
|
183
347
|
```
|
|
184
348
|
|
|
185
|
-
###
|
|
349
|
+
### Returning data from `resolve`
|
|
186
350
|
|
|
187
351
|
```typescript
|
|
188
|
-
// WRONG
|
|
352
|
+
// WRONG — resolvers return void; return value is ignored
|
|
189
353
|
resolve: async (req, context) => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return result; // Return value is ignored
|
|
193
|
-
},
|
|
354
|
+
return await analyzeData(req.input);
|
|
355
|
+
}
|
|
194
356
|
|
|
195
|
-
// CORRECT
|
|
357
|
+
// CORRECT — mutate facts to store results
|
|
196
358
|
resolve: async (req, context) => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
359
|
+
context.facts.analysis = await analyzeData(req.input);
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Confusing single-agent with multi-agent lifecycle
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
// Single-agent orchestrator — NO start() needed
|
|
367
|
+
const orch = createAgentOrchestrator({ runner });
|
|
368
|
+
await orch.run(agent, "prompt"); // ✓ ready
|
|
369
|
+
|
|
370
|
+
// Multi-agent orchestrator — start() IS required before runPattern
|
|
371
|
+
const multi = createMultiAgentOrchestrator({ agents, runner });
|
|
372
|
+
multi.start();
|
|
373
|
+
await multi.runPattern("pipeline", "prompt");
|
|
200
374
|
```
|
|
201
375
|
|
|
202
|
-
###
|
|
376
|
+
### Hook names from a guess instead of the type
|
|
203
377
|
|
|
204
378
|
```typescript
|
|
205
|
-
// WRONG
|
|
206
|
-
|
|
207
|
-
|
|
379
|
+
// WRONG — onStart / onBeforeRun / onAfterRun / onError do not exist on OrchestratorLifecycleHooks
|
|
380
|
+
hooks: {
|
|
381
|
+
onStart: () => {},
|
|
382
|
+
onBeforeRun: () => ({ approved: true }),
|
|
383
|
+
onAfterRun: () => {},
|
|
384
|
+
onError: () => {},
|
|
385
|
+
}
|
|
208
386
|
|
|
209
|
-
// CORRECT
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
387
|
+
// CORRECT — actual names are onAgent*
|
|
388
|
+
hooks: {
|
|
389
|
+
onAgentStart: (e) => {},
|
|
390
|
+
onAgentComplete: (e) => {},
|
|
391
|
+
onAgentError: (e) => {},
|
|
392
|
+
onAgentRetry: (e) => {},
|
|
393
|
+
onGuardrailCheck: (e) => {},
|
|
394
|
+
}
|
|
213
395
|
```
|
|
214
396
|
|
|
215
|
-
|
|
397
|
+
### Putting `onBudgetWarning` inside `hooks`
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
// WRONG — onBudgetWarning is a TOP-LEVEL option
|
|
401
|
+
{ hooks: { onBudgetWarning: () => {} } }
|
|
402
|
+
|
|
403
|
+
// CORRECT
|
|
404
|
+
{ onBudgetWarning: (event) => {}, maxTokenBudget: 100_000 }
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Treating `checkpoint()` as sync
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// WRONG — checkpoint() returns a Promise
|
|
411
|
+
const cp = orchestrator.checkpoint();
|
|
412
|
+
const json = JSON.stringify(cp); // serializes "[object Promise]"
|
|
413
|
+
|
|
414
|
+
// CORRECT — await it
|
|
415
|
+
const cp = await orchestrator.checkpoint({ label: "snapshot-1" });
|
|
416
|
+
const json = JSON.stringify(cp);
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Restoring via constructor option
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// WRONG — there is no `checkpoint` option on createAgentOrchestrator
|
|
423
|
+
const orch = createAgentOrchestrator({ runner, checkpoint: savedCheckpoint });
|
|
424
|
+
|
|
425
|
+
// CORRECT — restore on an existing instance
|
|
426
|
+
const orch = createAgentOrchestrator({ runner });
|
|
427
|
+
orch.restore(savedCheckpoint);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Iterating `runStream`'s return value directly
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
// WRONG — runStream returns { stream, result, abort }, not an AsyncIterable
|
|
434
|
+
const stream = orchestrator.runStream(agent, "prompt");
|
|
435
|
+
for await (const chunk of stream) { /* never iterates the right thing */ }
|
|
436
|
+
|
|
437
|
+
// CORRECT — destructure
|
|
438
|
+
const { stream, result, abort } = orchestrator.runStream(agent, "prompt");
|
|
439
|
+
for await (const chunk of stream) { /* … */ }
|
|
440
|
+
const final = await result;
|
|
441
|
+
```
|
|
216
442
|
|
|
217
|
-
## Quick
|
|
443
|
+
## Quick reference
|
|
218
444
|
|
|
219
445
|
| Method | Purpose |
|
|
220
446
|
|---|---|
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
223
|
-
| `
|
|
224
|
-
| `
|
|
225
|
-
| `
|
|
226
|
-
| `
|
|
227
|
-
| `
|
|
447
|
+
| `orch.run(agent, input, opts?)` | Run agent → `Promise<RunResult<T>>` |
|
|
448
|
+
| `orch.runStream(agent, input, opts?)` | Run agent → `{ stream, result, abort }` |
|
|
449
|
+
| `orch.approve(id)` / `orch.reject(id, reason?)` | Resolve a pending approval request |
|
|
450
|
+
| `orch.pause()` / `orch.resume()` / `orch.reset()` | Lifecycle control |
|
|
451
|
+
| `orch.waitForIdle(timeoutMs?)` | Resolves when orchestrator is back at idle |
|
|
452
|
+
| `orch.checkpoint(opts?)` | Async — `Promise<Checkpoint>` |
|
|
453
|
+
| `orch.restore(cp, opts?)` | Restore state on an existing instance |
|
|
454
|
+
| `orch.resumeBreakpoint(id, mods?)` / `orch.cancelBreakpoint(id, reason?)` | Resume/cancel a paused breakpoint |
|
|
455
|
+
| `orch.facts.agent.*` | Read built-in agent state |
|
|
456
|
+
| `orch.totalTokens` | Cumulative token count |
|
|
457
|
+
| `orch.timeline` | DebugTimeline (when `debug: true`); `null` otherwise |
|
|
458
|
+
|
|
459
|
+
## See also
|
|
460
|
+
|
|
461
|
+
- [`ai-multi-agent.md`](./ai-multi-agent.md) — the multi-agent flavor; 8 composition patterns and pattern factories
|
|
462
|
+
- [`ai-adapters.md`](./ai-adapters.md) — provider runners that produce the `runner` this orchestrator wraps
|
|
463
|
+
- [`ai-guardrails-memory.md`](./ai-guardrails-memory.md) — full surface of the `guardrails:` and `memory:` options on this orchestrator
|
|
464
|
+
- [`ai-budget-resilience.md`](./ai-budget-resilience.md) — full surface of the `circuitBreaker:`, `selfHealing:`, `agentRetry:`, `maxTokenBudget:` options
|
|
465
|
+
- [`ai-debug-observability.md`](./ai-debug-observability.md) — full surface of the `debug:`, `breakpoints:`, `onBreakpoint:` options + `orchestrator.timeline`
|
|
466
|
+
- [`ai-testing-evals.md`](./ai-testing-evals.md) — `createTestOrchestrator` for unit testing this surface
|