@directive-run/knowledge 0.2.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/LICENSE +21 -0
- package/README.md +63 -0
- package/ai/ai-adapters.md +250 -0
- package/ai/ai-agents-streaming.md +269 -0
- package/ai/ai-budget-resilience.md +235 -0
- package/ai/ai-communication.md +281 -0
- package/ai/ai-debug-observability.md +243 -0
- package/ai/ai-guardrails-memory.md +332 -0
- package/ai/ai-mcp-rag.md +288 -0
- package/ai/ai-multi-agent.md +274 -0
- package/ai/ai-orchestrator.md +227 -0
- package/ai/ai-security.md +293 -0
- package/ai/ai-tasks.md +261 -0
- package/ai/ai-testing-evals.md +378 -0
- package/api-skeleton.md +5 -0
- package/core/anti-patterns.md +382 -0
- package/core/constraints.md +263 -0
- package/core/core-patterns.md +228 -0
- package/core/error-boundaries.md +322 -0
- package/core/multi-module.md +315 -0
- package/core/naming.md +283 -0
- package/core/plugins.md +344 -0
- package/core/react-adapter.md +262 -0
- package/core/resolvers.md +357 -0
- package/core/schema-types.md +262 -0
- package/core/system-api.md +271 -0
- package/core/testing.md +257 -0
- package/core/time-travel.md +238 -0
- package/dist/index.cjs +111 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/examples/ab-testing.ts +385 -0
- package/examples/ai-checkpoint.ts +509 -0
- package/examples/ai-guardrails.ts +319 -0
- package/examples/ai-orchestrator.ts +589 -0
- package/examples/async-chains.ts +287 -0
- package/examples/auth-flow.ts +371 -0
- package/examples/batch-resolver.ts +341 -0
- package/examples/checkers.ts +589 -0
- package/examples/contact-form.ts +176 -0
- package/examples/counter.ts +393 -0
- package/examples/dashboard-loader.ts +512 -0
- package/examples/debounce-constraints.ts +105 -0
- package/examples/dynamic-modules.ts +293 -0
- package/examples/error-boundaries.ts +430 -0
- package/examples/feature-flags.ts +220 -0
- package/examples/form-wizard.ts +347 -0
- package/examples/fraud-analysis.ts +663 -0
- package/examples/goal-heist.ts +341 -0
- package/examples/multi-module.ts +57 -0
- package/examples/newsletter.ts +241 -0
- package/examples/notifications.ts +210 -0
- package/examples/optimistic-updates.ts +317 -0
- package/examples/pagination.ts +260 -0
- package/examples/permissions.ts +337 -0
- package/examples/provider-routing.ts +403 -0
- package/examples/server.ts +316 -0
- package/examples/shopping-cart.ts +422 -0
- package/examples/sudoku.ts +630 -0
- package/examples/theme-locale.ts +204 -0
- package/examples/time-machine.ts +225 -0
- package/examples/topic-guard.ts +306 -0
- package/examples/url-sync.ts +333 -0
- package/examples/websocket.ts +404 -0
- package/package.json +65 -0
package/ai/ai-mcp-rag.md
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# AI MCP and RAG
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server integration and RAG (Retrieval-Augmented Generation) enrichment for Directive AI agents.
|
|
4
|
+
|
|
5
|
+
## Decision Tree: "How do I connect external tools or knowledge?"
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
What do you need?
|
|
9
|
+
├── External tool servers (MCP) → createMCPAdapter({ servers: [...] })
|
|
10
|
+
│ ├── stdio transport → command-based MCP servers
|
|
11
|
+
│ └── SSE transport → HTTP-based MCP servers
|
|
12
|
+
│
|
|
13
|
+
├── Knowledge retrieval (RAG) → createRAGEnricher({ embedder, storage })
|
|
14
|
+
│ ├── Need embeddings → createOpenAIEmbedder() or createAnthropicEmbedder()
|
|
15
|
+
│ ├── Need vector storage → createJSONFileStore() or custom VectorStore
|
|
16
|
+
│ └── Need chunk ingestion → enricher.ingest(documents)
|
|
17
|
+
│
|
|
18
|
+
Where do I import from?
|
|
19
|
+
├── MCP adapter → import { createMCPAdapter } from '@directive-run/ai'
|
|
20
|
+
├── RAG enricher → import { createRAGEnricher } from '@directive-run/ai'
|
|
21
|
+
└── Embedders → import from '@directive-run/ai/openai' (subpath)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## MCP Server Integration
|
|
25
|
+
|
|
26
|
+
Connect to MCP servers to give agents access to external tools:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { createMCPAdapter } from "@directive-run/ai";
|
|
30
|
+
|
|
31
|
+
const mcp = createMCPAdapter({
|
|
32
|
+
servers: [
|
|
33
|
+
// stdio transport — runs a local process
|
|
34
|
+
{
|
|
35
|
+
name: "tools",
|
|
36
|
+
transport: "stdio",
|
|
37
|
+
command: "npx mcp-server-tools",
|
|
38
|
+
},
|
|
39
|
+
// SSE transport — connects to an HTTP server
|
|
40
|
+
{
|
|
41
|
+
name: "data",
|
|
42
|
+
transport: "sse",
|
|
43
|
+
url: "http://localhost:3001/sse",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
|
|
47
|
+
// Per-tool constraints
|
|
48
|
+
toolConstraints: {
|
|
49
|
+
"tools/dangerous-tool": {
|
|
50
|
+
requireApproval: true,
|
|
51
|
+
maxAttempts: 3,
|
|
52
|
+
},
|
|
53
|
+
"tools/read-only": {
|
|
54
|
+
requireApproval: false,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Connection options
|
|
59
|
+
connectionTimeout: 10000,
|
|
60
|
+
reconnect: true,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Connect to all servers
|
|
64
|
+
await mcp.connect();
|
|
65
|
+
|
|
66
|
+
// Get available tools (normalized for Directive agents)
|
|
67
|
+
const tools = mcp.getTools();
|
|
68
|
+
|
|
69
|
+
// Use tools with an agent
|
|
70
|
+
const agent = {
|
|
71
|
+
name: "researcher",
|
|
72
|
+
instructions: "Use available tools to research topics.",
|
|
73
|
+
model: "claude-sonnet-4-5",
|
|
74
|
+
tools: tools,
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Anti-Pattern #36: Importing MCP from subpath
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// WRONG — there is no /mcp subpath export
|
|
82
|
+
import { createMCPToolProvider } from "@directive-run/ai/mcp";
|
|
83
|
+
|
|
84
|
+
// CORRECT — MCP adapter is exported from the main package
|
|
85
|
+
import { createMCPAdapter } from "@directive-run/ai";
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## MCP Server Lifecycle
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// Connect to all configured servers
|
|
92
|
+
await mcp.connect();
|
|
93
|
+
|
|
94
|
+
// Check server status
|
|
95
|
+
const status = mcp.getStatus();
|
|
96
|
+
// { tools: "connected", data: "connected" }
|
|
97
|
+
|
|
98
|
+
// Disconnect a specific server
|
|
99
|
+
await mcp.disconnect("tools");
|
|
100
|
+
|
|
101
|
+
// Disconnect all servers
|
|
102
|
+
await mcp.disconnectAll();
|
|
103
|
+
|
|
104
|
+
// Reconnect after disconnect
|
|
105
|
+
await mcp.connect();
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## MCP with Orchestrator
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { createAgentOrchestrator } from "@directive-run/ai";
|
|
112
|
+
|
|
113
|
+
const mcp = createMCPAdapter({
|
|
114
|
+
servers: [
|
|
115
|
+
{ name: "tools", transport: "stdio", command: "npx mcp-server-tools" },
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await mcp.connect();
|
|
120
|
+
|
|
121
|
+
const orchestrator = createAgentOrchestrator({
|
|
122
|
+
runner,
|
|
123
|
+
hooks: {
|
|
124
|
+
onStart: async () => {
|
|
125
|
+
await mcp.connect();
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const agent = {
|
|
131
|
+
name: "worker",
|
|
132
|
+
instructions: "Complete tasks using available tools.",
|
|
133
|
+
model: "claude-sonnet-4-5",
|
|
134
|
+
tools: mcp.getTools(),
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const result = await orchestrator.run(agent, "Search for recent AI papers");
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## RAG Enrichment
|
|
143
|
+
|
|
144
|
+
Augment agent prompts with relevant context from a knowledge base:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { createRAGEnricher } from "@directive-run/ai";
|
|
148
|
+
import { createOpenAIEmbedder } from "@directive-run/ai/openai";
|
|
149
|
+
|
|
150
|
+
const enricher = createRAGEnricher({
|
|
151
|
+
// Embedder for similarity search
|
|
152
|
+
embedder: createOpenAIEmbedder({
|
|
153
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
154
|
+
}),
|
|
155
|
+
|
|
156
|
+
// Vector storage backend
|
|
157
|
+
storage: createJSONFileStore({ filePath: "./chunks.json" }),
|
|
158
|
+
|
|
159
|
+
// Retrieval settings
|
|
160
|
+
topK: 5, // Max chunks to retrieve
|
|
161
|
+
minSimilarity: 0.3, // Minimum cosine similarity threshold
|
|
162
|
+
|
|
163
|
+
// Format each retrieved chunk
|
|
164
|
+
formatChunk: (chunk, similarity) => {
|
|
165
|
+
return `[${similarity.toFixed(2)}] ${chunk.content}`;
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Ingesting Documents
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Ingest raw text with metadata
|
|
174
|
+
await enricher.ingest([
|
|
175
|
+
{
|
|
176
|
+
content: "Directive uses proxy-based facts for auto-tracking.",
|
|
177
|
+
metadata: { source: "docs", topic: "facts" },
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
content: "Derivations are auto-tracked computed values.",
|
|
181
|
+
metadata: { source: "docs", topic: "derivations" },
|
|
182
|
+
},
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
// Ingest from files (chunks automatically)
|
|
186
|
+
await enricher.ingestFile("./docs/architecture.md", {
|
|
187
|
+
chunkSize: 500,
|
|
188
|
+
chunkOverlap: 50,
|
|
189
|
+
metadata: { source: "architecture" },
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Enriching Prompts
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Basic enrichment — prepends relevant context
|
|
197
|
+
const enrichedInput = await enricher.enrich("How do facts work?", {
|
|
198
|
+
prefix: "Use this context to answer:\n",
|
|
199
|
+
});
|
|
200
|
+
// Result: "Use this context to answer:\n[0.92] Directive uses proxy-based..."
|
|
201
|
+
|
|
202
|
+
// With conversation history for better retrieval
|
|
203
|
+
const enrichedInput = await enricher.enrich("Tell me more about that", {
|
|
204
|
+
prefix: "Use this context:\n",
|
|
205
|
+
history: messages,
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## RAG with Orchestrator
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { createAgentOrchestrator } from "@directive-run/ai";
|
|
213
|
+
|
|
214
|
+
const orchestrator = createAgentOrchestrator({
|
|
215
|
+
runner,
|
|
216
|
+
hooks: {
|
|
217
|
+
onBeforeRun: async (agent, prompt) => {
|
|
218
|
+
// Enrich every prompt with relevant context
|
|
219
|
+
const enriched = await enricher.enrich(prompt, {
|
|
220
|
+
prefix: "Relevant context:\n",
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return { approved: true, modifiedPrompt: enriched };
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Custom Embedders
|
|
230
|
+
|
|
231
|
+
Implement the `Embedder` interface for any provider:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import type { Embedder } from "@directive-run/ai";
|
|
235
|
+
|
|
236
|
+
const customEmbedder: Embedder = {
|
|
237
|
+
embed: async (texts: string[]) => {
|
|
238
|
+
// Return float arrays, one per input text
|
|
239
|
+
const embeddings = await myEmbeddingAPI.embed(texts);
|
|
240
|
+
|
|
241
|
+
return embeddings.map((e) => e.vector);
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
dimensions: 1536, // Vector dimensions
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const enricher = createRAGEnricher({
|
|
248
|
+
embedder: customEmbedder,
|
|
249
|
+
storage: createJSONFileStore({ filePath: "./chunks.json" }),
|
|
250
|
+
topK: 5,
|
|
251
|
+
minSimilarity: 0.3,
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Custom Vector Storage
|
|
256
|
+
|
|
257
|
+
Implement the `VectorStore` interface for any backend:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import type { VectorStore } from "@directive-run/ai";
|
|
261
|
+
|
|
262
|
+
const pgStore: VectorStore = {
|
|
263
|
+
add: async (chunks) => {
|
|
264
|
+
await db.query("INSERT INTO chunks ...", chunks);
|
|
265
|
+
},
|
|
266
|
+
search: async (vector, topK) => {
|
|
267
|
+
const results = await db.query(
|
|
268
|
+
"SELECT * FROM chunks ORDER BY embedding <=> $1 LIMIT $2",
|
|
269
|
+
[vector, topK],
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
return results.rows;
|
|
273
|
+
},
|
|
274
|
+
clear: async () => {
|
|
275
|
+
await db.query("DELETE FROM chunks");
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Quick Reference
|
|
281
|
+
|
|
282
|
+
| API | Import Path | Purpose |
|
|
283
|
+
|---|---|---|
|
|
284
|
+
| `createMCPAdapter` | `@directive-run/ai` | Connect to MCP tool servers |
|
|
285
|
+
| `createRAGEnricher` | `@directive-run/ai` | RAG pipeline for prompt enrichment |
|
|
286
|
+
| `createOpenAIEmbedder` | `@directive-run/ai/openai` | OpenAI text embeddings |
|
|
287
|
+
| `createAnthropicEmbedder` | `@directive-run/ai/anthropic` | Anthropic text embeddings |
|
|
288
|
+
| `createJSONFileStore` | `@directive-run/ai` | File-based vector storage |
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# AI Multi-Agent Orchestrator
|
|
2
|
+
|
|
3
|
+
`createMultiAgentOrchestrator` coordinates multiple agents using 8 composition patterns. Each agent becomes a namespaced Directive module with a shared coordinator.
|
|
4
|
+
|
|
5
|
+
## Decision Tree: "Which pattern do I need?"
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
How should agents interact?
|
|
9
|
+
├── Independent, combine results → parallel()
|
|
10
|
+
├── One feeds the next → sequential()
|
|
11
|
+
├── One agent delegates → supervisor()
|
|
12
|
+
├── Complex dependency graph → dag()
|
|
13
|
+
├── Agent critiques own output → reflect()
|
|
14
|
+
├── First to finish wins → race()
|
|
15
|
+
├── Agents argue to consensus → debate()
|
|
16
|
+
└── Iterate until goal met → goal()
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Basic Setup
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import {
|
|
23
|
+
createMultiAgentOrchestrator,
|
|
24
|
+
parallel,
|
|
25
|
+
sequential,
|
|
26
|
+
supervisor,
|
|
27
|
+
dag,
|
|
28
|
+
reflect,
|
|
29
|
+
race,
|
|
30
|
+
debate,
|
|
31
|
+
goal,
|
|
32
|
+
} from "@directive-run/ai";
|
|
33
|
+
import { createAnthropicRunner } from "@directive-run/ai/anthropic";
|
|
34
|
+
|
|
35
|
+
const runner = createAnthropicRunner({
|
|
36
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const orchestrator = createMultiAgentOrchestrator({
|
|
40
|
+
agents: {
|
|
41
|
+
researcher: {
|
|
42
|
+
name: "researcher",
|
|
43
|
+
instructions: "Research the topic thoroughly.",
|
|
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
|
+
},
|
|
56
|
+
},
|
|
57
|
+
patterns: {
|
|
58
|
+
pipeline: sequential(["researcher", "writer", "editor"]),
|
|
59
|
+
brainstorm: parallel(["researcher", "writer"], mergeResults),
|
|
60
|
+
managed: supervisor("editor", ["researcher", "writer"]),
|
|
61
|
+
workflow: dag([
|
|
62
|
+
{ id: "research", handler: "researcher" },
|
|
63
|
+
{ id: "write", handler: "writer", dependencies: ["research"] },
|
|
64
|
+
{ id: "edit", handler: "editor", dependencies: ["write"] },
|
|
65
|
+
]),
|
|
66
|
+
},
|
|
67
|
+
runner,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// REQUIRED for multi-agent — must call start() before running patterns
|
|
71
|
+
orchestrator.start();
|
|
72
|
+
|
|
73
|
+
const result = await orchestrator.runPattern("pipeline", "Write about AI");
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Pattern Details
|
|
77
|
+
|
|
78
|
+
### parallel — Run agents concurrently, merge results
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const brainstorm = parallel(
|
|
82
|
+
["researcher", "writer"],
|
|
83
|
+
(results) => {
|
|
84
|
+
// results: Map<string, RunResult>
|
|
85
|
+
const combined = Array.from(results.values())
|
|
86
|
+
.map((r) => r.output)
|
|
87
|
+
.join("\n\n");
|
|
88
|
+
|
|
89
|
+
return combined;
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### sequential — Chain agents in order
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Each agent receives the previous agent's output as its prompt
|
|
98
|
+
const pipeline = sequential(["researcher", "writer", "editor"]);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### supervisor — One agent delegates to workers
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Editor decides which worker to invoke and when to stop
|
|
105
|
+
const managed = supervisor("editor", ["researcher", "writer"]);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### dag — Directed acyclic graph of dependencies
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// DagNode shape
|
|
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");
|
|
127
|
+
|
|
128
|
+
return `Based on research:\n${research}\n\nWrite about: ${input}`;
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{ id: "edit", handler: "editor", dependencies: ["write"] },
|
|
132
|
+
]);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### reflect — Agent critiques and revises its own output
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const selfImprove = reflect("writer", {
|
|
139
|
+
maxIterations: 3,
|
|
140
|
+
stopWhen: (output, iteration) => {
|
|
141
|
+
return output.includes("FINAL") || iteration >= 3;
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### race — First agent to finish wins
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const fastest = race(["researcher", "writer"], {
|
|
150
|
+
minSuccess: 1, // How many must complete (default: 1)
|
|
151
|
+
timeout: 30000, // Cancel remaining after timeout
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### debate — Agents argue to consensus
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const consensus = debate(["researcher", "writer"], {
|
|
159
|
+
maxRounds: 5,
|
|
160
|
+
judge: "editor", // Agent that decides when consensus is reached
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### goal — Iterate until a condition is met
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const iterative = goal("researcher", {
|
|
168
|
+
maxIterations: 10,
|
|
169
|
+
goalCheck: (output, facts) => {
|
|
170
|
+
return facts.confidence > 0.9;
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Fact Propagation
|
|
176
|
+
|
|
177
|
+
Each agent has its own namespaced facts. The coordinator module (`__coord`) holds shared state:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Read agent-specific facts
|
|
181
|
+
orchestrator.system.facts.researcher.status;
|
|
182
|
+
orchestrator.system.facts.writer.lastOutput;
|
|
183
|
+
|
|
184
|
+
// Read coordinator facts
|
|
185
|
+
orchestrator.system.facts.__coord.activePattern;
|
|
186
|
+
orchestrator.system.facts.__coord.completedAgents;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Checkpoint Serialization
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Save entire multi-agent state
|
|
193
|
+
const checkpoint = orchestrator.checkpoint();
|
|
194
|
+
const serialized = JSON.stringify(checkpoint);
|
|
195
|
+
|
|
196
|
+
// Restore from checkpoint
|
|
197
|
+
const restored = createMultiAgentOrchestrator({
|
|
198
|
+
agents,
|
|
199
|
+
patterns,
|
|
200
|
+
runner,
|
|
201
|
+
checkpoint: JSON.parse(serialized),
|
|
202
|
+
});
|
|
203
|
+
restored.start();
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Tasks in Multi-Agent Patterns
|
|
207
|
+
|
|
208
|
+
Tasks and agents share the DAG/sequential/parallel namespace. See `ai-tasks.md` for details.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const workflow = dag([
|
|
212
|
+
{ id: "research", handler: "researcher" },
|
|
213
|
+
{ id: "format", handler: "formatter-task" }, // task, not agent
|
|
214
|
+
{ id: "edit", handler: "editor", dependencies: ["research", "format"] },
|
|
215
|
+
]);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Anti-Patterns
|
|
219
|
+
|
|
220
|
+
### #24: Forgetting start() for multi-agent
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// WRONG — multi-agent orchestrators require explicit start()
|
|
224
|
+
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
225
|
+
const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
226
|
+
// Error: Orchestrator not started
|
|
227
|
+
|
|
228
|
+
// CORRECT
|
|
229
|
+
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
230
|
+
orchestrator.start();
|
|
231
|
+
const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### #30: race minSuccess greater than agent count
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// WRONG — minSuccess cannot exceed the number of agents
|
|
238
|
+
const broken = race(["researcher", "writer"], {
|
|
239
|
+
minSuccess: 3, // Only 2 agents, will never satisfy
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// CORRECT — minSuccess <= agents.length
|
|
243
|
+
const working = race(["researcher", "writer"], {
|
|
244
|
+
minSuccess: 1,
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Reusing agent names across patterns
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
// WRONG — agent names must match keys in the agents config
|
|
252
|
+
patterns: {
|
|
253
|
+
pipeline: sequential(["research-agent", "write-agent"]),
|
|
254
|
+
// These don't match the keys "researcher", "writer"
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// CORRECT — use the exact keys from agents config
|
|
258
|
+
patterns: {
|
|
259
|
+
pipeline: sequential(["researcher", "writer"]),
|
|
260
|
+
},
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Quick Reference
|
|
264
|
+
|
|
265
|
+
| Pattern | Use Case | Key Option |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| `parallel()` | Independent work, merge results | merge function |
|
|
268
|
+
| `sequential()` | Pipeline, each feeds next | agent order |
|
|
269
|
+
| `supervisor()` | Dynamic delegation | supervisor agent |
|
|
270
|
+
| `dag()` | Complex dependencies | DagNode[] |
|
|
271
|
+
| `reflect()` | Self-improvement loop | maxIterations, stopWhen |
|
|
272
|
+
| `race()` | Fastest wins | minSuccess, timeout |
|
|
273
|
+
| `debate()` | Consensus building | maxRounds, judge |
|
|
274
|
+
| `goal()` | Condition-driven iteration | goalCheck |
|