@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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/ai/ai-adapters.md +250 -0
  4. package/ai/ai-agents-streaming.md +269 -0
  5. package/ai/ai-budget-resilience.md +235 -0
  6. package/ai/ai-communication.md +281 -0
  7. package/ai/ai-debug-observability.md +243 -0
  8. package/ai/ai-guardrails-memory.md +332 -0
  9. package/ai/ai-mcp-rag.md +288 -0
  10. package/ai/ai-multi-agent.md +274 -0
  11. package/ai/ai-orchestrator.md +227 -0
  12. package/ai/ai-security.md +293 -0
  13. package/ai/ai-tasks.md +261 -0
  14. package/ai/ai-testing-evals.md +378 -0
  15. package/api-skeleton.md +5 -0
  16. package/core/anti-patterns.md +382 -0
  17. package/core/constraints.md +263 -0
  18. package/core/core-patterns.md +228 -0
  19. package/core/error-boundaries.md +322 -0
  20. package/core/multi-module.md +315 -0
  21. package/core/naming.md +283 -0
  22. package/core/plugins.md +344 -0
  23. package/core/react-adapter.md +262 -0
  24. package/core/resolvers.md +357 -0
  25. package/core/schema-types.md +262 -0
  26. package/core/system-api.md +271 -0
  27. package/core/testing.md +257 -0
  28. package/core/time-travel.md +238 -0
  29. package/dist/index.cjs +111 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.cts +10 -0
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.js +102 -0
  34. package/dist/index.js.map +1 -0
  35. package/examples/ab-testing.ts +385 -0
  36. package/examples/ai-checkpoint.ts +509 -0
  37. package/examples/ai-guardrails.ts +319 -0
  38. package/examples/ai-orchestrator.ts +589 -0
  39. package/examples/async-chains.ts +287 -0
  40. package/examples/auth-flow.ts +371 -0
  41. package/examples/batch-resolver.ts +341 -0
  42. package/examples/checkers.ts +589 -0
  43. package/examples/contact-form.ts +176 -0
  44. package/examples/counter.ts +393 -0
  45. package/examples/dashboard-loader.ts +512 -0
  46. package/examples/debounce-constraints.ts +105 -0
  47. package/examples/dynamic-modules.ts +293 -0
  48. package/examples/error-boundaries.ts +430 -0
  49. package/examples/feature-flags.ts +220 -0
  50. package/examples/form-wizard.ts +347 -0
  51. package/examples/fraud-analysis.ts +663 -0
  52. package/examples/goal-heist.ts +341 -0
  53. package/examples/multi-module.ts +57 -0
  54. package/examples/newsletter.ts +241 -0
  55. package/examples/notifications.ts +210 -0
  56. package/examples/optimistic-updates.ts +317 -0
  57. package/examples/pagination.ts +260 -0
  58. package/examples/permissions.ts +337 -0
  59. package/examples/provider-routing.ts +403 -0
  60. package/examples/server.ts +316 -0
  61. package/examples/shopping-cart.ts +422 -0
  62. package/examples/sudoku.ts +630 -0
  63. package/examples/theme-locale.ts +204 -0
  64. package/examples/time-machine.ts +225 -0
  65. package/examples/topic-guard.ts +306 -0
  66. package/examples/url-sync.ts +333 -0
  67. package/examples/websocket.ts +404 -0
  68. package/package.json +65 -0
@@ -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 |