@directive-run/knowledge 0.2.0 → 0.5.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 +1 -1
- package/README.md +3 -3
- package/ai/ai-adapters.md +7 -7
- package/ai/ai-agents-streaming.md +8 -8
- package/ai/ai-budget-resilience.md +5 -5
- package/ai/ai-communication.md +1 -1
- package/ai/ai-guardrails-memory.md +7 -7
- package/ai/ai-mcp-rag.md +5 -5
- package/ai/ai-multi-agent.md +14 -14
- package/ai/ai-orchestrator.md +8 -8
- package/ai/ai-security.md +2 -2
- package/ai/ai-tasks.md +9 -9
- package/ai/ai-testing-evals.md +2 -2
- package/core/anti-patterns.md +39 -39
- package/core/constraints.md +15 -15
- package/core/core-patterns.md +9 -9
- package/core/error-boundaries.md +7 -7
- package/core/multi-module.md +16 -16
- package/core/naming.md +21 -21
- package/core/plugins.md +14 -14
- package/core/react-adapter.md +13 -13
- package/core/resolvers.md +14 -14
- package/core/schema-types.md +22 -22
- package/core/system-api.md +16 -16
- package/core/testing.md +5 -5
- package/core/time-travel.md +20 -20
- package/dist/index.cjs +6 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -97
- package/dist/index.js.map +1 -1
- package/examples/ab-testing.ts +18 -90
- package/examples/ai-checkpoint.ts +68 -87
- package/examples/ai-guardrails.ts +20 -70
- package/examples/auth-flow.ts +2 -2
- package/examples/batch-resolver.ts +19 -59
- package/examples/contact-form.ts +220 -69
- package/examples/counter.ts +77 -95
- package/examples/dashboard-loader.ts +38 -56
- package/examples/debounce-constraints.ts +0 -2
- package/examples/dynamic-modules.ts +17 -20
- package/examples/error-boundaries.ts +30 -81
- package/examples/form-wizard.ts +6 -6
- package/examples/newsletter.ts +24 -51
- package/examples/notifications.ts +24 -23
- package/examples/optimistic-updates.ts +36 -41
- package/examples/pagination.ts +2 -2
- package/examples/permissions.ts +22 -32
- package/examples/provider-routing.ts +26 -83
- package/examples/shopping-cart.ts +12 -12
- package/examples/sudoku.ts +60 -67
- package/examples/theme-locale.ts +4 -7
- package/examples/time-machine.ts +12 -90
- package/examples/topic-guard.ts +31 -39
- package/examples/url-sync.ts +8 -8
- package/examples/websocket.ts +5 -5
- package/package.json +3 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
Knowledge files, examples, and validation scripts for the [Directive](https://directive.run) runtime.
|
|
4
4
|
|
|
5
5
|
This package is the **source of truth** for all Directive coding knowledge used by:
|
|
6
|
-
- `@directive-run/cli`
|
|
7
|
-
- `@directive-run/claude-plugin`
|
|
8
|
-
- `directive.run/llms.txt`
|
|
6
|
+
- `@directive-run/cli` – generates AI rules files (`.cursorrules`, `CLAUDE.md`, etc.)
|
|
7
|
+
- `@directive-run/claude-plugin` – builds Claude Code plugin skills
|
|
8
|
+
- `directive.run/llms.txt` – website LLM reference
|
|
9
9
|
|
|
10
10
|
## Contents
|
|
11
11
|
|
package/ai/ai-adapters.md
CHANGED
|
@@ -24,7 +24,7 @@ Which LLM provider?
|
|
|
24
24
|
Every adapter MUST be imported from its subpath. The main `@directive-run/ai` entry does NOT export adapters.
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
|
-
// CORRECT
|
|
27
|
+
// CORRECT – subpath imports
|
|
28
28
|
import { createAnthropicRunner } from "@directive-run/ai/anthropic";
|
|
29
29
|
import { createOpenAIRunner } from "@directive-run/ai/openai";
|
|
30
30
|
import { createOllamaRunner } from "@directive-run/ai/ollama";
|
|
@@ -34,11 +34,11 @@ import { createGeminiRunner } from "@directive-run/ai/gemini";
|
|
|
34
34
|
### Anti-Pattern #26: Importing adapters from the main entry
|
|
35
35
|
|
|
36
36
|
```typescript
|
|
37
|
-
// WRONG
|
|
37
|
+
// WRONG – adapters are NOT exported from the main package
|
|
38
38
|
import { createOpenAIRunner } from "@directive-run/ai";
|
|
39
39
|
import { createAnthropicRunner } from "@directive-run/ai";
|
|
40
40
|
|
|
41
|
-
// CORRECT
|
|
41
|
+
// CORRECT – use subpath imports
|
|
42
42
|
import { createOpenAIRunner } from "@directive-run/ai/openai";
|
|
43
43
|
import { createAnthropicRunner } from "@directive-run/ai/anthropic";
|
|
44
44
|
```
|
|
@@ -136,12 +136,12 @@ const runner = createGeminiRunner({
|
|
|
136
136
|
### Anti-Pattern #27: Assuming provider-specific token structure
|
|
137
137
|
|
|
138
138
|
```typescript
|
|
139
|
-
// WRONG
|
|
139
|
+
// WRONG – Anthropic returns { input_tokens, output_tokens } natively
|
|
140
140
|
// but adapters normalize this
|
|
141
141
|
const result = await runner.run(agent, prompt);
|
|
142
142
|
console.log(result.tokenUsage.input_tokens); // undefined!
|
|
143
143
|
|
|
144
|
-
// CORRECT
|
|
144
|
+
// CORRECT – adapters normalize to camelCase
|
|
145
145
|
const result = await runner.run(agent, prompt);
|
|
146
146
|
console.log(result.tokenUsage.inputTokens); // number
|
|
147
147
|
console.log(result.tokenUsage.outputTokens); // number
|
|
@@ -201,7 +201,7 @@ const runner = createAnthropicRunner({
|
|
|
201
201
|
// Single-agent
|
|
202
202
|
const orchestrator = createAgentOrchestrator({ runner });
|
|
203
203
|
|
|
204
|
-
// Multi-agent
|
|
204
|
+
// Multi-agent – same runner shared across all agents
|
|
205
205
|
const multiOrchestrator = createMultiAgentOrchestrator({
|
|
206
206
|
agents: { /* ... */ },
|
|
207
207
|
runner,
|
|
@@ -219,7 +219,7 @@ const runner = createAnthropicRunner({
|
|
|
219
219
|
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
220
220
|
});
|
|
221
221
|
|
|
222
|
-
// After: OpenAI
|
|
222
|
+
// After: OpenAI – same orchestrator, different runner
|
|
223
223
|
import { createOpenAIRunner } from "@directive-run/ai/openai";
|
|
224
224
|
const runner = createOpenAIRunner({
|
|
225
225
|
apiKey: process.env.OPENAI_API_KEY,
|
|
@@ -18,11 +18,11 @@ Need the complete result?
|
|
|
18
18
|
└── Default → strategy: "buffer"
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
## AgentLike
|
|
21
|
+
## AgentLike – What the Runner Receives
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
interface AgentLike {
|
|
25
|
-
// Required
|
|
25
|
+
// Required – unique identifier
|
|
26
26
|
name: string;
|
|
27
27
|
|
|
28
28
|
// System prompt / instructions
|
|
@@ -44,7 +44,7 @@ const agent: AgentLike = {
|
|
|
44
44
|
};
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
## RunResult
|
|
47
|
+
## RunResult – What the Runner Returns
|
|
48
48
|
|
|
49
49
|
```typescript
|
|
50
50
|
interface RunResult<T = unknown> {
|
|
@@ -143,7 +143,7 @@ Control behavior when the consumer cannot keep up with token production:
|
|
|
143
143
|
|
|
144
144
|
```typescript
|
|
145
145
|
const stream = orchestrator.runStream(agent, "Generate long report", {
|
|
146
|
-
backpressure: "buffer", // default
|
|
146
|
+
backpressure: "buffer", // default – buffer all tokens in memory
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
const stream = orchestrator.runStream(agent, "Generate long report", {
|
|
@@ -228,12 +228,12 @@ eventSource.onmessage = (event) => {
|
|
|
228
228
|
### Not checking chunk.type before accessing fields
|
|
229
229
|
|
|
230
230
|
```typescript
|
|
231
|
-
// WRONG
|
|
231
|
+
// WRONG – not all chunks have .data
|
|
232
232
|
for await (const chunk of stream) {
|
|
233
233
|
console.log(chunk.data); // undefined for non-token chunks
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
// CORRECT
|
|
236
|
+
// CORRECT – switch on chunk.type
|
|
237
237
|
for await (const chunk of stream) {
|
|
238
238
|
if (chunk.type === "token") {
|
|
239
239
|
console.log(chunk.data);
|
|
@@ -244,12 +244,12 @@ for await (const chunk of stream) {
|
|
|
244
244
|
### Ignoring the stopped flag on guardrail chunks
|
|
245
245
|
|
|
246
246
|
```typescript
|
|
247
|
-
// WRONG
|
|
247
|
+
// WRONG – continuing after a stopping guardrail
|
|
248
248
|
case "guardrail_triggered":
|
|
249
249
|
console.log("Guardrail triggered, continuing...");
|
|
250
250
|
break;
|
|
251
251
|
|
|
252
|
-
// CORRECT
|
|
252
|
+
// CORRECT – check if the stream was stopped
|
|
253
253
|
case "guardrail_triggered":
|
|
254
254
|
if (chunk.stopped) {
|
|
255
255
|
console.error(`Stopped by ${chunk.guardrailName}: ${chunk.reason}`);
|
|
@@ -55,13 +55,13 @@ const budgetRunner = withBudget(baseRunner, {
|
|
|
55
55
|
### Anti-Pattern #29: budgetWarningThreshold out of range
|
|
56
56
|
|
|
57
57
|
```typescript
|
|
58
|
-
// WRONG
|
|
58
|
+
// WRONG – threshold must be a 0-1 percentage
|
|
59
59
|
const budgetRunner = withBudget(baseRunner, {
|
|
60
60
|
budgetWarningThreshold: 80, // Not a percentage!
|
|
61
61
|
budgets: [{ window: "hour", maxCost: 1.0, pricing: { inputPerMillion: 3, outputPerMillion: 15 } }],
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
// CORRECT
|
|
64
|
+
// CORRECT – use a decimal between 0 and 1
|
|
65
65
|
const budgetRunner = withBudget(baseRunner, {
|
|
66
66
|
budgetWarningThreshold: 0.8, // 80%
|
|
67
67
|
budgets: [{ window: "hour", maxCost: 1.0, pricing: { inputPerMillion: 3, outputPerMillion: 15 } }],
|
|
@@ -127,12 +127,12 @@ breaker.reset(); // Force back to closed
|
|
|
127
127
|
### Anti-Pattern #28: Sharing a CircuitBreaker across unrelated agents
|
|
128
128
|
|
|
129
129
|
```typescript
|
|
130
|
-
// WRONG
|
|
130
|
+
// WRONG – one failing agent opens the breaker for all agents
|
|
131
131
|
const sharedBreaker = createCircuitBreaker({ failureThreshold: 3, resetTimeout: 30000 });
|
|
132
132
|
const researchRunner = sharedBreaker.wrap(baseRunner);
|
|
133
133
|
const writerRunner = sharedBreaker.wrap(baseRunner); // Same breaker!
|
|
134
134
|
|
|
135
|
-
// CORRECT
|
|
135
|
+
// CORRECT – each agent gets its own breaker instance
|
|
136
136
|
const researchBreaker = createCircuitBreaker({ failureThreshold: 3, resetTimeout: 30000 });
|
|
137
137
|
const writerBreaker = createCircuitBreaker({ failureThreshold: 3, resetTimeout: 30000 });
|
|
138
138
|
|
|
@@ -207,7 +207,7 @@ const router = createConstraintRouter({
|
|
|
207
207
|
|
|
208
208
|
## Combining Wrappers
|
|
209
209
|
|
|
210
|
-
Wrappers compose
|
|
210
|
+
Wrappers compose – apply them inside-out (innermost runs first):
|
|
211
211
|
|
|
212
212
|
```typescript
|
|
213
213
|
import { withBudget, withRetry, withFallback } from "@directive-run/ai";
|
package/ai/ai-communication.md
CHANGED
|
@@ -184,7 +184,7 @@ const isReady = orchestrator.system.derive.researcher.isComplete;
|
|
|
184
184
|
The scratchpad is an ephemeral key-value store scoped to a single pattern execution. Tasks and agents in the same pattern share it:
|
|
185
185
|
|
|
186
186
|
```typescript
|
|
187
|
-
// In a task
|
|
187
|
+
// In a task – write to scratchpad
|
|
188
188
|
tasks: {
|
|
189
189
|
gather: {
|
|
190
190
|
run: async (input, context) => {
|
|
@@ -28,7 +28,7 @@ interface GuardrailResult {
|
|
|
28
28
|
// Why it failed (when passed: false)
|
|
29
29
|
reason?: string;
|
|
30
30
|
|
|
31
|
-
// Modified data
|
|
31
|
+
// Modified data – guardrail can transform the input/output
|
|
32
32
|
transformed?: unknown;
|
|
33
33
|
}
|
|
34
34
|
```
|
|
@@ -60,7 +60,7 @@ const piiGuardrail = createPIIGuardrail({
|
|
|
60
60
|
import { createModerationGuardrail } from "@directive-run/ai";
|
|
61
61
|
|
|
62
62
|
const moderationGuardrail = createModerationGuardrail({
|
|
63
|
-
// Custom check function
|
|
63
|
+
// Custom check function – return true if content is safe
|
|
64
64
|
checkFn: async (content) => {
|
|
65
65
|
const result = await moderationAPI.check(content);
|
|
66
66
|
|
|
@@ -171,7 +171,7 @@ const orchestrator = createAgentOrchestrator({
|
|
|
171
171
|
## Anti-Pattern #25: Catching Error Instead of GuardrailError
|
|
172
172
|
|
|
173
173
|
```typescript
|
|
174
|
-
// WRONG
|
|
174
|
+
// WRONG – loses guardrail-specific metadata
|
|
175
175
|
try {
|
|
176
176
|
const result = await orchestrator.run(agent, prompt);
|
|
177
177
|
} catch (error) {
|
|
@@ -180,7 +180,7 @@ try {
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
// CORRECT
|
|
183
|
+
// CORRECT – catch GuardrailError for full context
|
|
184
184
|
import { GuardrailError } from "@directive-run/ai";
|
|
185
185
|
|
|
186
186
|
try {
|
|
@@ -259,7 +259,7 @@ When messages are evicted, a summarizer condenses them:
|
|
|
259
259
|
```typescript
|
|
260
260
|
import { createTruncationSummarizer } from "@directive-run/ai";
|
|
261
261
|
|
|
262
|
-
// Simply drops old messages
|
|
262
|
+
// Simply drops old messages – no summary generated
|
|
263
263
|
const summarizer = createTruncationSummarizer();
|
|
264
264
|
```
|
|
265
265
|
|
|
@@ -299,14 +299,14 @@ const orchestrator = createAgentOrchestrator({
|
|
|
299
299
|
## Anti-Pattern #31: Async Summarizer Without autoManage: false
|
|
300
300
|
|
|
301
301
|
```typescript
|
|
302
|
-
// WRONG
|
|
302
|
+
// WRONG – LLM summarizer is async but autoManage runs synchronously
|
|
303
303
|
const memory = createAgentMemory({
|
|
304
304
|
strategy: createSlidingWindowStrategy({ maxMessages: 20 }),
|
|
305
305
|
summarizer: createLLMSummarizer(runner),
|
|
306
306
|
autoManage: true, // Will not await the summarizer properly
|
|
307
307
|
});
|
|
308
308
|
|
|
309
|
-
// CORRECT
|
|
309
|
+
// CORRECT – disable autoManage, call memory.manage() manually
|
|
310
310
|
const memory = createAgentMemory({
|
|
311
311
|
strategy: createSlidingWindowStrategy({ maxMessages: 20 }),
|
|
312
312
|
summarizer: createLLMSummarizer(runner),
|
package/ai/ai-mcp-rag.md
CHANGED
|
@@ -30,13 +30,13 @@ import { createMCPAdapter } from "@directive-run/ai";
|
|
|
30
30
|
|
|
31
31
|
const mcp = createMCPAdapter({
|
|
32
32
|
servers: [
|
|
33
|
-
// stdio transport
|
|
33
|
+
// stdio transport – runs a local process
|
|
34
34
|
{
|
|
35
35
|
name: "tools",
|
|
36
36
|
transport: "stdio",
|
|
37
37
|
command: "npx mcp-server-tools",
|
|
38
38
|
},
|
|
39
|
-
// SSE transport
|
|
39
|
+
// SSE transport – connects to an HTTP server
|
|
40
40
|
{
|
|
41
41
|
name: "data",
|
|
42
42
|
transport: "sse",
|
|
@@ -78,10 +78,10 @@ const agent = {
|
|
|
78
78
|
### Anti-Pattern #36: Importing MCP from subpath
|
|
79
79
|
|
|
80
80
|
```typescript
|
|
81
|
-
// WRONG
|
|
81
|
+
// WRONG – there is no /mcp subpath export
|
|
82
82
|
import { createMCPToolProvider } from "@directive-run/ai/mcp";
|
|
83
83
|
|
|
84
|
-
// CORRECT
|
|
84
|
+
// CORRECT – MCP adapter is exported from the main package
|
|
85
85
|
import { createMCPAdapter } from "@directive-run/ai";
|
|
86
86
|
```
|
|
87
87
|
|
|
@@ -193,7 +193,7 @@ await enricher.ingestFile("./docs/architecture.md", {
|
|
|
193
193
|
## Enriching Prompts
|
|
194
194
|
|
|
195
195
|
```typescript
|
|
196
|
-
// Basic enrichment
|
|
196
|
+
// Basic enrichment – prepends relevant context
|
|
197
197
|
const enrichedInput = await enricher.enrich("How do facts work?", {
|
|
198
198
|
prefix: "Use this context to answer:\n",
|
|
199
199
|
});
|
package/ai/ai-multi-agent.md
CHANGED
|
@@ -67,7 +67,7 @@ const orchestrator = createMultiAgentOrchestrator({
|
|
|
67
67
|
runner,
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
// REQUIRED for multi-agent
|
|
70
|
+
// REQUIRED for multi-agent – must call start() before running patterns
|
|
71
71
|
orchestrator.start();
|
|
72
72
|
|
|
73
73
|
const result = await orchestrator.runPattern("pipeline", "Write about AI");
|
|
@@ -75,7 +75,7 @@ const result = await orchestrator.runPattern("pipeline", "Write about AI");
|
|
|
75
75
|
|
|
76
76
|
## Pattern Details
|
|
77
77
|
|
|
78
|
-
### parallel
|
|
78
|
+
### parallel – Run agents concurrently, merge results
|
|
79
79
|
|
|
80
80
|
```typescript
|
|
81
81
|
const brainstorm = parallel(
|
|
@@ -91,21 +91,21 @@ const brainstorm = parallel(
|
|
|
91
91
|
);
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
### sequential
|
|
94
|
+
### sequential – Chain agents in order
|
|
95
95
|
|
|
96
96
|
```typescript
|
|
97
97
|
// Each agent receives the previous agent's output as its prompt
|
|
98
98
|
const pipeline = sequential(["researcher", "writer", "editor"]);
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
### supervisor
|
|
101
|
+
### supervisor – One agent delegates to workers
|
|
102
102
|
|
|
103
103
|
```typescript
|
|
104
104
|
// Editor decides which worker to invoke and when to stop
|
|
105
105
|
const managed = supervisor("editor", ["researcher", "writer"]);
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
### dag
|
|
108
|
+
### dag – Directed acyclic graph of dependencies
|
|
109
109
|
|
|
110
110
|
```typescript
|
|
111
111
|
// DagNode shape
|
|
@@ -132,7 +132,7 @@ const workflow = dag([
|
|
|
132
132
|
]);
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
### reflect
|
|
135
|
+
### reflect – Agent critiques and revises its own output
|
|
136
136
|
|
|
137
137
|
```typescript
|
|
138
138
|
const selfImprove = reflect("writer", {
|
|
@@ -143,7 +143,7 @@ const selfImprove = reflect("writer", {
|
|
|
143
143
|
});
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
### race
|
|
146
|
+
### race – First agent to finish wins
|
|
147
147
|
|
|
148
148
|
```typescript
|
|
149
149
|
const fastest = race(["researcher", "writer"], {
|
|
@@ -152,7 +152,7 @@ const fastest = race(["researcher", "writer"], {
|
|
|
152
152
|
});
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
### debate
|
|
155
|
+
### debate – Agents argue to consensus
|
|
156
156
|
|
|
157
157
|
```typescript
|
|
158
158
|
const consensus = debate(["researcher", "writer"], {
|
|
@@ -161,7 +161,7 @@ const consensus = debate(["researcher", "writer"], {
|
|
|
161
161
|
});
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
### goal
|
|
164
|
+
### goal – Iterate until a condition is met
|
|
165
165
|
|
|
166
166
|
```typescript
|
|
167
167
|
const iterative = goal("researcher", {
|
|
@@ -220,7 +220,7 @@ const workflow = dag([
|
|
|
220
220
|
### #24: Forgetting start() for multi-agent
|
|
221
221
|
|
|
222
222
|
```typescript
|
|
223
|
-
// WRONG
|
|
223
|
+
// WRONG – multi-agent orchestrators require explicit start()
|
|
224
224
|
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
225
225
|
const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
226
226
|
// Error: Orchestrator not started
|
|
@@ -234,12 +234,12 @@ const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
|
234
234
|
### #30: race minSuccess greater than agent count
|
|
235
235
|
|
|
236
236
|
```typescript
|
|
237
|
-
// WRONG
|
|
237
|
+
// WRONG – minSuccess cannot exceed the number of agents
|
|
238
238
|
const broken = race(["researcher", "writer"], {
|
|
239
239
|
minSuccess: 3, // Only 2 agents, will never satisfy
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
-
// CORRECT
|
|
242
|
+
// CORRECT – minSuccess <= agents.length
|
|
243
243
|
const working = race(["researcher", "writer"], {
|
|
244
244
|
minSuccess: 1,
|
|
245
245
|
});
|
|
@@ -248,13 +248,13 @@ const working = race(["researcher", "writer"], {
|
|
|
248
248
|
### Reusing agent names across patterns
|
|
249
249
|
|
|
250
250
|
```typescript
|
|
251
|
-
// WRONG
|
|
251
|
+
// WRONG – agent names must match keys in the agents config
|
|
252
252
|
patterns: {
|
|
253
253
|
pipeline: sequential(["research-agent", "write-agent"]),
|
|
254
254
|
// These don't match the keys "researcher", "writer"
|
|
255
255
|
},
|
|
256
256
|
|
|
257
|
-
// CORRECT
|
|
257
|
+
// CORRECT – use the exact keys from agents config
|
|
258
258
|
patterns: {
|
|
259
259
|
pipeline: sequential(["researcher", "writer"]),
|
|
260
260
|
},
|
package/ai/ai-orchestrator.md
CHANGED
|
@@ -156,13 +156,13 @@ const restored = createAgentOrchestrator({
|
|
|
156
156
|
### #21: TypeScript types instead of t.*() for factsSchema
|
|
157
157
|
|
|
158
158
|
```typescript
|
|
159
|
-
// WRONG
|
|
159
|
+
// WRONG – TS types are erased at runtime, no schema validation
|
|
160
160
|
const orchestrator = createAgentOrchestrator({
|
|
161
161
|
runner,
|
|
162
162
|
factsSchema: {} as { confidence: number; analysis: string },
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
// CORRECT
|
|
165
|
+
// CORRECT – use t.*() builders for runtime schema
|
|
166
166
|
const orchestrator = createAgentOrchestrator({
|
|
167
167
|
runner,
|
|
168
168
|
factsSchema: {
|
|
@@ -175,24 +175,24 @@ const orchestrator = createAgentOrchestrator({
|
|
|
175
175
|
### #22: Mutating arrays/objects in place
|
|
176
176
|
|
|
177
177
|
```typescript
|
|
178
|
-
// WRONG
|
|
178
|
+
// WRONG – proxy cannot detect in-place mutations
|
|
179
179
|
context.facts.cache.push("new-item");
|
|
180
180
|
|
|
181
|
-
// CORRECT
|
|
181
|
+
// CORRECT – replace the entire value
|
|
182
182
|
context.facts.cache = [...context.facts.cache, "new-item"];
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
### #23: Returning data from resolve
|
|
186
186
|
|
|
187
187
|
```typescript
|
|
188
|
-
// WRONG
|
|
188
|
+
// WRONG – resolvers return void, not data
|
|
189
189
|
resolve: async (req, context) => {
|
|
190
190
|
const result = await analyzeData(req.input);
|
|
191
191
|
|
|
192
192
|
return result; // Return value is ignored
|
|
193
193
|
},
|
|
194
194
|
|
|
195
|
-
// CORRECT
|
|
195
|
+
// CORRECT – mutate context.facts to store results
|
|
196
196
|
resolve: async (req, context) => {
|
|
197
197
|
const result = await analyzeData(req.input);
|
|
198
198
|
context.facts.analysis = result;
|
|
@@ -202,11 +202,11 @@ resolve: async (req, context) => {
|
|
|
202
202
|
### #24: Forgetting start() for multi-agent
|
|
203
203
|
|
|
204
204
|
```typescript
|
|
205
|
-
// WRONG
|
|
205
|
+
// WRONG – multi-agent orchestrators require explicit start()
|
|
206
206
|
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
207
207
|
const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
208
208
|
|
|
209
|
-
// CORRECT
|
|
209
|
+
// CORRECT – call start() before running patterns
|
|
210
210
|
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
211
211
|
orchestrator.start();
|
|
212
212
|
const result = await orchestrator.runPattern("pipeline", "prompt");
|
package/ai/ai-security.md
CHANGED
|
@@ -224,10 +224,10 @@ const orchestrator = createAgentOrchestrator({
|
|
|
224
224
|
### Input Validation
|
|
225
225
|
|
|
226
226
|
```typescript
|
|
227
|
-
// WRONG
|
|
227
|
+
// WRONG – passing raw user input to the agent
|
|
228
228
|
const result = await orchestrator.run(agent, userInput);
|
|
229
229
|
|
|
230
|
-
// CORRECT
|
|
230
|
+
// CORRECT – validate and sanitize input first
|
|
231
231
|
const sanitized = sanitizeInput(userInput);
|
|
232
232
|
const result = await orchestrator.run(agent, sanitized);
|
|
233
233
|
```
|
package/ai/ai-tasks.md
CHANGED
|
@@ -21,7 +21,7 @@ Does this work need an LLM?
|
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
interface TaskRegistration {
|
|
24
|
-
// The work function
|
|
24
|
+
// The work function – input is ALWAYS a string
|
|
25
25
|
run: (input: string, context: TaskContext) => Promise<string>;
|
|
26
26
|
|
|
27
27
|
// Human-readable label for debugging/logging
|
|
@@ -184,11 +184,11 @@ tasks: {
|
|
|
184
184
|
### #33: Tasks calling agents internally
|
|
185
185
|
|
|
186
186
|
```typescript
|
|
187
|
-
// WRONG
|
|
187
|
+
// WRONG – tasks cannot invoke agents
|
|
188
188
|
tasks: {
|
|
189
189
|
enhance: {
|
|
190
190
|
run: async (input, context) => {
|
|
191
|
-
// Tasks have no runner access
|
|
191
|
+
// Tasks have no runner access – this won't work
|
|
192
192
|
const result = await runner.run(someAgent, input);
|
|
193
193
|
|
|
194
194
|
return result.output;
|
|
@@ -196,7 +196,7 @@ tasks: {
|
|
|
196
196
|
},
|
|
197
197
|
},
|
|
198
198
|
|
|
199
|
-
// CORRECT
|
|
199
|
+
// CORRECT – use a pattern to compose agents and tasks
|
|
200
200
|
patterns: {
|
|
201
201
|
enhance: sequential(["enhancer-agent", "format-task"]),
|
|
202
202
|
},
|
|
@@ -205,17 +205,17 @@ patterns: {
|
|
|
205
205
|
### #34: Expecting structured input (not a string)
|
|
206
206
|
|
|
207
207
|
```typescript
|
|
208
|
-
// WRONG
|
|
208
|
+
// WRONG – task input is always a string
|
|
209
209
|
tasks: {
|
|
210
210
|
process: {
|
|
211
211
|
run: async (input, context) => {
|
|
212
|
-
// input.items is undefined
|
|
212
|
+
// input.items is undefined – input is a string
|
|
213
213
|
return input.items.map((i) => i.name).join(", ");
|
|
214
214
|
},
|
|
215
215
|
},
|
|
216
216
|
},
|
|
217
217
|
|
|
218
|
-
// CORRECT
|
|
218
|
+
// CORRECT – parse the string input
|
|
219
219
|
tasks: {
|
|
220
220
|
process: {
|
|
221
221
|
run: async (input, context) => {
|
|
@@ -230,7 +230,7 @@ tasks: {
|
|
|
230
230
|
### #35: Task and agent IDs collide
|
|
231
231
|
|
|
232
232
|
```typescript
|
|
233
|
-
// WRONG
|
|
233
|
+
// WRONG – "researcher" exists as both agent and task
|
|
234
234
|
agents: {
|
|
235
235
|
researcher: { name: "researcher", instructions: "...", model: "claude-sonnet-4-5" },
|
|
236
236
|
},
|
|
@@ -238,7 +238,7 @@ tasks: {
|
|
|
238
238
|
researcher: { run: async (input) => input }, // Name collision!
|
|
239
239
|
},
|
|
240
240
|
|
|
241
|
-
// CORRECT
|
|
241
|
+
// CORRECT – use distinct names
|
|
242
242
|
agents: {
|
|
243
243
|
researcher: { name: "researcher", instructions: "...", model: "claude-sonnet-4-5" },
|
|
244
244
|
},
|
package/ai/ai-testing-evals.md
CHANGED
|
@@ -254,7 +254,7 @@ const evaluator = createEvaluator({
|
|
|
254
254
|
### Anti-Pattern #32: Side effects in evaluator scorer
|
|
255
255
|
|
|
256
256
|
```typescript
|
|
257
|
-
// WRONG
|
|
257
|
+
// WRONG – scorers must be pure functions
|
|
258
258
|
{
|
|
259
259
|
name: "quality",
|
|
260
260
|
scorer: (input, output) => {
|
|
@@ -266,7 +266,7 @@ const evaluator = createEvaluator({
|
|
|
266
266
|
},
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
// CORRECT
|
|
269
|
+
// CORRECT – scorers are pure, return score + reason only
|
|
270
270
|
{
|
|
271
271
|
name: "quality",
|
|
272
272
|
scorer: (input, output) => {
|