@directive-run/knowledge 1.14.0 → 1.15.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 +2 -0
- package/ai/ai-agents-streaming.md +182 -149
- package/ai/ai-budget-resilience.md +299 -132
- package/ai/ai-communication.md +215 -197
- package/ai/ai-debug-observability.md +253 -173
- package/ai/ai-guardrails-memory.md +185 -153
- package/ai/ai-mcp-rag.md +199 -199
- package/ai/ai-multi-agent.md +247 -153
- package/ai/ai-orchestrator.md +344 -114
- package/ai/ai-security.md +282 -180
- package/ai/ai-tasks.md +3 -1
- package/ai/ai-testing-evals.md +357 -256
- package/core/anti-patterns.md +9 -2
- package/core/constraints.md +6 -2
- package/core/core-patterns.md +2 -0
- package/core/error-boundaries.md +2 -0
- package/core/history.md +2 -0
- package/core/multi-module.md +8 -3
- package/core/naming.md +15 -6
- package/core/plugins.md +2 -0
- package/core/react-adapter.md +250 -174
- package/core/resolvers.md +2 -0
- package/core/schema-types.md +2 -0
- package/core/system-api.md +2 -0
- package/core/testing.md +251 -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-multi-agent.md
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
# AI
|
|
1
|
+
# AI multi-agent orchestrator
|
|
2
2
|
|
|
3
|
-
`createMultiAgentOrchestrator`
|
|
3
|
+
> Covers `@directive-run/ai/multi-agent` — `createMultiAgentOrchestrator` + 8 composition patterns (parallel / sequential / supervisor / dag / reflect / race / debate / goal).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`createMultiAgentOrchestrator` coordinates multiple agents using 8 composition patterns. Each agent becomes a namespaced Directive module with a shared coordinator. Patterns are pure config objects you assemble with factory functions and pass via the `patterns:` option.
|
|
6
|
+
|
|
7
|
+
For a single agent, see `ai-orchestrator.md`.
|
|
8
|
+
|
|
9
|
+
## Decision tree
|
|
6
10
|
|
|
7
11
|
```
|
|
8
12
|
How should agents interact?
|
|
9
13
|
├── Independent, combine results → parallel()
|
|
10
|
-
├── One feeds the next
|
|
11
|
-
├── One agent delegates
|
|
14
|
+
├── One feeds the next → sequential()
|
|
15
|
+
├── One agent delegates work → supervisor()
|
|
12
16
|
├── Complex dependency graph → dag()
|
|
13
|
-
├──
|
|
14
|
-
├── First to finish wins
|
|
15
|
-
├──
|
|
16
|
-
└── Iterate until goal met
|
|
17
|
+
├── Producer + evaluator loop → reflect()
|
|
18
|
+
├── First to finish wins → race()
|
|
19
|
+
├── Multiple positions debated → debate()
|
|
20
|
+
└── Iterate until goal met → goal()
|
|
17
21
|
```
|
|
18
22
|
|
|
19
|
-
## Basic
|
|
23
|
+
## Basic setup
|
|
24
|
+
|
|
25
|
+
Import from the subpath barrel — the main `@directive-run/ai` barrel re-exports these with `@deprecated` notices for v2 removal.
|
|
20
26
|
|
|
21
27
|
```typescript
|
|
22
28
|
import {
|
|
@@ -29,246 +35,334 @@ import {
|
|
|
29
35
|
race,
|
|
30
36
|
debate,
|
|
31
37
|
goal,
|
|
32
|
-
} from "@directive-run/ai";
|
|
38
|
+
} from "@directive-run/ai/multi-agent";
|
|
33
39
|
import { createAnthropicRunner } from "@directive-run/ai/anthropic";
|
|
34
40
|
|
|
35
41
|
const runner = createAnthropicRunner({
|
|
36
|
-
apiKey: process.env.ANTHROPIC_API_KEY
|
|
42
|
+
apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
37
43
|
});
|
|
38
44
|
|
|
39
45
|
const orchestrator = createMultiAgentOrchestrator({
|
|
40
46
|
agents: {
|
|
41
|
-
researcher: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
model: "claude-sonnet-4-5",
|
|
45
|
-
},
|
|
46
|
-
writer: {
|
|
47
|
-
name: "writer",
|
|
48
|
-
instructions: "Write clear, engaging content.",
|
|
49
|
-
model: "claude-sonnet-4-5",
|
|
50
|
-
},
|
|
51
|
-
editor: {
|
|
52
|
-
name: "editor",
|
|
53
|
-
instructions: "Edit for clarity and correctness.",
|
|
54
|
-
model: "claude-haiku-3-5",
|
|
55
|
-
},
|
|
47
|
+
researcher: { name: "researcher", instructions: "Research the topic thoroughly.", model: "claude-sonnet-4-5" },
|
|
48
|
+
writer: { name: "writer", instructions: "Write clear, engaging content.", model: "claude-sonnet-4-5" },
|
|
49
|
+
editor: { name: "editor", instructions: "Edit for clarity and correctness.", model: "claude-haiku-4-5" },
|
|
56
50
|
},
|
|
57
51
|
patterns: {
|
|
58
|
-
pipeline:
|
|
59
|
-
brainstorm: parallel(["researcher", "writer"],
|
|
60
|
-
managed:
|
|
61
|
-
workflow:
|
|
62
|
-
{
|
|
63
|
-
{
|
|
64
|
-
{
|
|
65
|
-
|
|
52
|
+
pipeline: sequential(["researcher", "writer", "editor"]),
|
|
53
|
+
brainstorm: parallel(["researcher", "writer"], (results) => results.map((r) => String(r.output)).join("\n\n")),
|
|
54
|
+
managed: supervisor("editor", ["researcher", "writer"]),
|
|
55
|
+
workflow: dag({
|
|
56
|
+
research: { handler: "researcher" },
|
|
57
|
+
write: { handler: "writer", deps: ["research"] },
|
|
58
|
+
edit: { handler: "editor", deps: ["write"] },
|
|
59
|
+
}),
|
|
66
60
|
},
|
|
67
61
|
runner,
|
|
68
62
|
});
|
|
69
63
|
|
|
70
|
-
// REQUIRED
|
|
64
|
+
// REQUIRED — call start() before runPattern. Single-agent createAgentOrchestrator does NOT need this.
|
|
71
65
|
orchestrator.start();
|
|
72
66
|
|
|
73
67
|
const result = await orchestrator.runPattern("pipeline", "Write about AI");
|
|
74
68
|
```
|
|
75
69
|
|
|
76
|
-
##
|
|
70
|
+
## Patterns in depth
|
|
71
|
+
|
|
72
|
+
### `parallel(handlers, merge, options?)`
|
|
77
73
|
|
|
78
|
-
|
|
74
|
+
Runs handlers concurrently and combines their results. **`merge` is REQUIRED as positional argument 2** — without it the call fails at registration. `options?` accepts `minSuccess` and `timeout`.
|
|
79
75
|
|
|
80
76
|
```typescript
|
|
81
77
|
const brainstorm = parallel(
|
|
82
78
|
["researcher", "writer"],
|
|
83
|
-
(results) =>
|
|
84
|
-
|
|
85
|
-
const combined = Array.from(results.values())
|
|
86
|
-
.map((r) => r.output)
|
|
87
|
-
.join("\n\n");
|
|
88
|
-
|
|
89
|
-
return combined;
|
|
90
|
-
},
|
|
79
|
+
(results) => results.map((r) => String(r.output)).join("\n\n"),
|
|
80
|
+
{ minSuccess: 1, timeout: 30_000 },
|
|
91
81
|
);
|
|
92
82
|
```
|
|
93
83
|
|
|
94
|
-
|
|
84
|
+
The `results` arg is `RunResult<unknown>[]` — array, in handler order.
|
|
85
|
+
|
|
86
|
+
### `sequential(handlers, options?)`
|
|
87
|
+
|
|
88
|
+
Each handler's output feeds as input to the next. `options.transform(output, handlerId, index)` adapts the hand-off; `options.extract(finalOutput)` shapes the return.
|
|
95
89
|
|
|
96
90
|
```typescript
|
|
97
|
-
// Each agent receives the previous agent's output as its prompt
|
|
98
91
|
const pipeline = sequential(["researcher", "writer", "editor"]);
|
|
92
|
+
|
|
93
|
+
const writeReview = sequential(["writer", "reviewer"], {
|
|
94
|
+
transform: (output) => `Review this draft:\n${output}`,
|
|
95
|
+
});
|
|
99
96
|
```
|
|
100
97
|
|
|
101
|
-
### supervisor
|
|
98
|
+
### `supervisor(supervisorAgent, workers, options?)`
|
|
99
|
+
|
|
100
|
+
The supervisor runs first and delegates to workers based on its output. Repeats up to `maxRounds` until the supervisor signals completion.
|
|
102
101
|
|
|
103
102
|
```typescript
|
|
104
|
-
|
|
105
|
-
const managed = supervisor("editor", ["researcher", "writer"]);
|
|
103
|
+
const managed = supervisor("manager", ["worker1", "worker2"], { maxRounds: 3 });
|
|
106
104
|
```
|
|
107
105
|
|
|
108
|
-
### dag
|
|
106
|
+
### `dag(nodes, merge?, options?)`
|
|
107
|
+
|
|
108
|
+
**Nodes are a `Record<string, DagNode>`, NOT an array.** Each node's edges are listed in `deps` (not `dependencies`). The runtime validates the graph is acyclic and that all `deps` refer to declared nodes.
|
|
109
109
|
|
|
110
110
|
```typescript
|
|
111
|
-
|
|
112
|
-
interface DagNode {
|
|
113
|
-
id: string;
|
|
114
|
-
handler: string; // agent name
|
|
115
|
-
dependencies?: string[]; // node IDs this depends on
|
|
116
|
-
transform?: (input: string, depResults: Map<string, string>) => string;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const workflow = dag([
|
|
120
|
-
{ id: "research", handler: "researcher" },
|
|
121
|
-
{
|
|
122
|
-
id: "write",
|
|
123
|
-
handler: "writer",
|
|
124
|
-
dependencies: ["research"],
|
|
125
|
-
transform: (input, deps) => {
|
|
126
|
-
const research = deps.get("research");
|
|
111
|
+
import type { DagNode, DagExecutionContext } from "@directive-run/ai/multi-agent";
|
|
127
112
|
|
|
128
|
-
|
|
129
|
-
|
|
113
|
+
const workflow = dag(
|
|
114
|
+
{
|
|
115
|
+
research: { handler: "researcher" },
|
|
116
|
+
analyze: { handler: "analyzer", deps: ["research"] },
|
|
117
|
+
summarize: { handler: "summarizer", deps: ["analyze"] },
|
|
118
|
+
},
|
|
119
|
+
// optional merge — receives the execution context with .outputs Record
|
|
120
|
+
(context: DagExecutionContext) => context.outputs.summarize,
|
|
121
|
+
// optional config
|
|
122
|
+
{
|
|
123
|
+
timeout: 60_000,
|
|
124
|
+
maxConcurrent: 4,
|
|
125
|
+
onNodeError: "skip-downstream", // "fail" (default) | "skip-downstream" | "continue"
|
|
130
126
|
},
|
|
131
|
-
|
|
132
|
-
]);
|
|
127
|
+
);
|
|
133
128
|
```
|
|
134
129
|
|
|
135
|
-
### reflect
|
|
130
|
+
### `reflect(handler, evaluator, options?)`
|
|
131
|
+
|
|
132
|
+
Producer + evaluator loop. The producer generates output, the evaluator scores it; if the score is below `threshold` the producer retries with feedback, up to `maxIterations`. **`evaluator` is REQUIRED as positional argument 2.**
|
|
136
133
|
|
|
137
134
|
```typescript
|
|
138
|
-
const selfImprove = reflect("writer", {
|
|
135
|
+
const selfImprove = reflect("writer", "reviewer", {
|
|
139
136
|
maxIterations: 3,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
},
|
|
137
|
+
threshold: 0.8,
|
|
138
|
+
onExhausted: "accept-best", // "accept-last" | "accept-best" | "throw"
|
|
139
|
+
onIteration: (record) => console.log(`iter ${record.iteration}: ${record.score}`),
|
|
143
140
|
});
|
|
144
141
|
```
|
|
145
142
|
|
|
146
|
-
### race
|
|
143
|
+
### `race(handlers, options?)`
|
|
144
|
+
|
|
145
|
+
All handlers start simultaneously; the first to complete successfully wins. Use `minSuccess` to wait for N before picking.
|
|
147
146
|
|
|
148
147
|
```typescript
|
|
149
|
-
const fastest = race(["
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
const fastest = race(["fast-model", "smart-model"], {
|
|
149
|
+
timeout: 5000,
|
|
150
|
+
minSuccess: 1, // must be ≤ handlers.length
|
|
152
151
|
});
|
|
153
152
|
```
|
|
154
153
|
|
|
155
|
-
### debate
|
|
154
|
+
### `debate(config)`
|
|
155
|
+
|
|
156
|
+
**Takes a single `DebateConfig` object.** The discriminator agents argue from different positions; the `evaluator` agent judges. There is no `judge` field — it's `evaluator`.
|
|
156
157
|
|
|
157
158
|
```typescript
|
|
158
|
-
const consensus = debate(
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
const consensus = debate({
|
|
160
|
+
handlers: ["optimist", "pessimist"],
|
|
161
|
+
evaluator: "judge",
|
|
162
|
+
maxRounds: 2,
|
|
161
163
|
});
|
|
162
164
|
```
|
|
163
165
|
|
|
164
|
-
### goal
|
|
166
|
+
### `goal(nodes, when, options?)`
|
|
167
|
+
|
|
168
|
+
Goal-driven execution. Each node declares what it `produces` and `requires`; the runtime infers the execution graph and runs agents until `when(facts)` returns true. There is no single-agent string form.
|
|
165
169
|
|
|
166
170
|
```typescript
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
+
import type { GoalNode } from "@directive-run/ai/multi-agent";
|
|
172
|
+
|
|
173
|
+
const pipeline = goal(
|
|
174
|
+
{
|
|
175
|
+
researcher: {
|
|
176
|
+
handler: "researcher",
|
|
177
|
+
produces: ["research.findings"],
|
|
178
|
+
requires: ["research.topic"],
|
|
179
|
+
extractOutput: (r) => ({ "research.findings": r.output }),
|
|
180
|
+
},
|
|
181
|
+
writer: {
|
|
182
|
+
handler: "writer",
|
|
183
|
+
produces: ["article.draft"],
|
|
184
|
+
requires: ["research.findings"],
|
|
185
|
+
extractOutput: (r) => ({ "article.draft": r.output }),
|
|
186
|
+
},
|
|
171
187
|
},
|
|
172
|
-
|
|
188
|
+
(facts) => facts["article.draft"] != null,
|
|
189
|
+
{
|
|
190
|
+
maxSteps: 10,
|
|
191
|
+
extract: (facts) => facts["article.draft"],
|
|
192
|
+
satisfaction: (facts) => (facts["article.draft"] ? 1.0 : 0.0),
|
|
193
|
+
},
|
|
194
|
+
);
|
|
173
195
|
```
|
|
174
196
|
|
|
175
|
-
## Fact
|
|
197
|
+
## Fact propagation
|
|
176
198
|
|
|
177
|
-
Each agent has its own namespaced facts.
|
|
199
|
+
Each agent has its own namespaced facts module. A coordinator module (`__coord`) tracks shared orchestration state.
|
|
178
200
|
|
|
179
201
|
```typescript
|
|
180
|
-
//
|
|
202
|
+
// Per-agent state — module is named after the agent's key in `agents:`
|
|
181
203
|
orchestrator.system.facts.researcher.status;
|
|
182
|
-
orchestrator.system.facts.writer.
|
|
204
|
+
orchestrator.system.facts.writer.output;
|
|
183
205
|
|
|
184
|
-
//
|
|
206
|
+
// Coordinator state
|
|
185
207
|
orchestrator.system.facts.__coord.activePattern;
|
|
186
208
|
orchestrator.system.facts.__coord.completedAgents;
|
|
187
209
|
```
|
|
188
210
|
|
|
189
|
-
##
|
|
211
|
+
## Checkpoints
|
|
212
|
+
|
|
213
|
+
Multi-agent uses the same checkpoint shape as single-agent. **`checkpoint()` is async** — returns a `Promise<Checkpoint>`. Restore on an existing instance via `orch.restore(cp)`. There is no `createMultiAgentOrchestrator({ checkpoint })` constructor option.
|
|
190
214
|
|
|
191
215
|
```typescript
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
agents,
|
|
199
|
-
patterns,
|
|
200
|
-
runner,
|
|
201
|
-
checkpoint: JSON.parse(serialized),
|
|
202
|
-
});
|
|
216
|
+
const cp = await orchestrator.checkpoint({ label: "after-pipeline" });
|
|
217
|
+
const serialized = JSON.stringify(cp);
|
|
218
|
+
|
|
219
|
+
// On a fresh orchestrator with the same agents/patterns/runner:
|
|
220
|
+
const restored = createMultiAgentOrchestrator({ agents, patterns, runner });
|
|
221
|
+
restored.restore(JSON.parse(serialized));
|
|
203
222
|
restored.start();
|
|
204
223
|
```
|
|
205
224
|
|
|
206
|
-
## Tasks
|
|
225
|
+
## Tasks alongside agents
|
|
207
226
|
|
|
208
|
-
Tasks
|
|
227
|
+
Tasks (registered via `tasks:`) share the handler namespace with agents — a `dag` or `sequential` can refer to either by ID. See `ai-tasks.md` for the full task surface.
|
|
209
228
|
|
|
210
229
|
```typescript
|
|
211
|
-
const workflow = dag(
|
|
212
|
-
{
|
|
213
|
-
{
|
|
214
|
-
{
|
|
215
|
-
|
|
230
|
+
const workflow = dag({
|
|
231
|
+
research: { handler: "researcher" },
|
|
232
|
+
format: { handler: "formatter-task" }, // a task, not an agent
|
|
233
|
+
edit: { handler: "editor", deps: ["research", "format"] },
|
|
234
|
+
});
|
|
216
235
|
```
|
|
217
236
|
|
|
218
|
-
## Anti-
|
|
237
|
+
## Anti-patterns
|
|
219
238
|
|
|
220
|
-
###
|
|
239
|
+
### Forgetting `start()` on multi-agent
|
|
221
240
|
|
|
222
241
|
```typescript
|
|
223
|
-
// WRONG
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
// Error: Orchestrator not started
|
|
242
|
+
// WRONG — multi-agent orchestrators require explicit start()
|
|
243
|
+
const orch = createMultiAgentOrchestrator({ agents, patterns, runner });
|
|
244
|
+
await orch.runPattern("pipeline", "prompt"); // throws — not started
|
|
227
245
|
|
|
228
246
|
// CORRECT
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
247
|
+
const orch = createMultiAgentOrchestrator({ agents, patterns, runner });
|
|
248
|
+
orch.start();
|
|
249
|
+
await orch.runPattern("pipeline", "prompt");
|
|
232
250
|
```
|
|
233
251
|
|
|
234
|
-
|
|
252
|
+
Single-agent `createAgentOrchestrator` does NOT require `start()`. Only multi-agent does.
|
|
253
|
+
|
|
254
|
+
### Array-form `dag` and `dependencies` key
|
|
235
255
|
|
|
236
256
|
```typescript
|
|
237
|
-
// WRONG
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
257
|
+
// WRONG — dag takes Record<string, DagNode>, not an array; and the edge key is `deps`
|
|
258
|
+
dag([
|
|
259
|
+
{ id: "research", handler: "researcher" },
|
|
260
|
+
{ id: "write", handler: "writer", dependencies: ["research"] },
|
|
261
|
+
])
|
|
262
|
+
|
|
263
|
+
// CORRECT
|
|
264
|
+
dag({
|
|
265
|
+
research: { handler: "researcher" },
|
|
266
|
+
write: { handler: "writer", deps: ["research"] },
|
|
267
|
+
})
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### `parallel` without the merge arg
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// WRONG — merge is a REQUIRED positional argument, not in options
|
|
274
|
+
parallel(["researcher", "writer"], { minSuccess: 1 })
|
|
275
|
+
|
|
276
|
+
// CORRECT — merge first, options second
|
|
277
|
+
parallel(
|
|
278
|
+
["researcher", "writer"],
|
|
279
|
+
(results) => results.map((r) => String(r.output)).join("\n"),
|
|
280
|
+
{ minSuccess: 1 },
|
|
281
|
+
)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### `reflect` with a single agent
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// WRONG — reflect needs a SEPARATE evaluator handler; stopWhen is not an option
|
|
288
|
+
reflect("writer", { maxIterations: 3, stopWhen: (out) => out.includes("FINAL") })
|
|
289
|
+
|
|
290
|
+
// CORRECT — handler + evaluator + threshold (the evaluator decides when to stop)
|
|
291
|
+
reflect("writer", "reviewer", { maxIterations: 3, threshold: 0.8 })
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### `debate` with `judge:` option
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// WRONG — debate uses `evaluator`, not `judge`; and it's a single config arg
|
|
298
|
+
debate(["researcher", "writer"], { maxRounds: 5, judge: "editor" })
|
|
241
299
|
|
|
242
|
-
// CORRECT
|
|
243
|
-
|
|
244
|
-
|
|
300
|
+
// CORRECT — single config object, evaluator key
|
|
301
|
+
debate({ handlers: ["researcher", "writer"], evaluator: "editor", maxRounds: 5 })
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### `goal` with a single agent string
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// WRONG — goal does not take a single agent + goalCheck; it takes a node map + when()
|
|
308
|
+
goal("researcher", { maxIterations: 10, goalCheck: (out, facts) => facts.confidence > 0.9 })
|
|
309
|
+
|
|
310
|
+
// CORRECT — declarative node map + a when() predicate
|
|
311
|
+
goal(
|
|
312
|
+
{
|
|
313
|
+
researcher: {
|
|
314
|
+
handler: "researcher",
|
|
315
|
+
produces: ["confidence"],
|
|
316
|
+
requires: ["topic"],
|
|
317
|
+
extractOutput: (r) => ({ confidence: (r.output as { confidence: number }).confidence }),
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
(facts) => (facts.confidence as number) > 0.9,
|
|
321
|
+
{ maxSteps: 10 },
|
|
322
|
+
)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Handler IDs that don't match `agents:` keys
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// WRONG — handler refs must match the keys in agents/tasks
|
|
329
|
+
createMultiAgentOrchestrator({
|
|
330
|
+
agents: { researcher: {...}, writer: {...} },
|
|
331
|
+
patterns: { pipeline: sequential(["research-agent", "write-agent"]) }, // wrong names
|
|
245
332
|
});
|
|
333
|
+
|
|
334
|
+
// CORRECT
|
|
335
|
+
patterns: { pipeline: sequential(["researcher", "writer"]) }
|
|
246
336
|
```
|
|
247
337
|
|
|
248
|
-
###
|
|
338
|
+
### `race` with `minSuccess` greater than the handler count
|
|
249
339
|
|
|
250
340
|
```typescript
|
|
251
|
-
// WRONG
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
341
|
+
// WRONG — minSuccess can never exceed handlers.length
|
|
342
|
+
race(["researcher", "writer"], { minSuccess: 3 }) // 2 handlers, impossible
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Restoring via a constructor option
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// WRONG — there is no `checkpoint` option on createMultiAgentOrchestrator
|
|
349
|
+
createMultiAgentOrchestrator({ agents, patterns, runner, checkpoint: cp })
|
|
350
|
+
|
|
351
|
+
// CORRECT — restore on an existing instance, then start()
|
|
352
|
+
const orch = createMultiAgentOrchestrator({ agents, patterns, runner });
|
|
353
|
+
orch.restore(cp);
|
|
354
|
+
orch.start();
|
|
261
355
|
```
|
|
262
356
|
|
|
263
|
-
## Quick
|
|
357
|
+
## Quick reference
|
|
264
358
|
|
|
265
|
-
| Pattern |
|
|
359
|
+
| Pattern | Signature | Required arg 2 |
|
|
266
360
|
|---|---|---|
|
|
267
|
-
| `parallel()` |
|
|
268
|
-
| `sequential()` |
|
|
269
|
-
| `supervisor()` |
|
|
270
|
-
| `dag()` |
|
|
271
|
-
| `reflect()` |
|
|
272
|
-
| `race()` |
|
|
273
|
-
| `debate()` |
|
|
274
|
-
| `goal()` |
|
|
361
|
+
| `parallel(handlers, merge, options?)` | `string[], (results) => T, { minSuccess?, timeout? }` | merge |
|
|
362
|
+
| `sequential(handlers, options?)` | `string[], { transform?, extract?, continueOnError? }` | — |
|
|
363
|
+
| `supervisor(supervisorAgent, workers, options?)` | `string, string[], { maxRounds?, extract? }` | workers |
|
|
364
|
+
| `dag(nodes, merge?, options?)` | `Record<string, DagNode>, (ctx) => T, { timeout?, maxConcurrent?, onNodeError? }` | — |
|
|
365
|
+
| `reflect(handler, evaluator, options?)` | `string, string, { maxIterations?, threshold?, onExhausted?, onIteration? }` | evaluator |
|
|
366
|
+
| `race(handlers, options?)` | `string[], { timeout?, minSuccess?, extract? }` | — |
|
|
367
|
+
| `debate(config)` | `{ handlers, evaluator, maxRounds?, extract?, parseJudgement? }` | — (single arg) |
|
|
368
|
+
| `goal(nodes, when, options?)` | `Record<string, GoalNode>, (facts) => boolean, { maxSteps?, extract?, satisfaction? }` | when |
|