@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,235 @@
1
+ # AI Budget and Resilience
2
+
3
+ Budget wrappers, retry policies, fallback chains, circuit breakers, health monitors, semantic caching, and constraint-driven provider routing for AI runners.
4
+
5
+ ## Decision Tree: "How do I protect my AI calls?"
6
+
7
+ ```
8
+ What failure mode are you guarding against?
9
+ ├── Cost overruns → withBudget(runner, { budgets: [...] })
10
+ ├── Transient errors → withRetry(runner, { maxRetries, backoff })
11
+ ├── Provider outage → withFallback(primaryRunner, fallbackRunner)
12
+ ├── Repeated failures → createCircuitBreaker({ failureThreshold })
13
+ ├── Fleet monitoring → createHealthMonitor({ agents: {...} })
14
+
15
+ Want to avoid redundant LLM calls?
16
+ ├── Yes, similar inputs → createSemanticCache({ embedder, similarity })
17
+
18
+ Need dynamic provider selection?
19
+ └── Yes → createConstraintRouter({ providers: [...], constraints: [...] })
20
+ ```
21
+
22
+ ## Budget Wrapping
23
+
24
+ Wrap any runner with cost tracking and enforcement per time window:
25
+
26
+ ```typescript
27
+ import { withBudget } from "@directive-run/ai";
28
+
29
+ const budgetRunner = withBudget(baseRunner, {
30
+ // Hard cap per single LLM call
31
+ maxCostPerCall: 0.10,
32
+
33
+ // Time-window budgets (multiple allowed)
34
+ budgets: [
35
+ {
36
+ window: "hour",
37
+ maxCost: 1.0,
38
+ pricing: { inputPerMillion: 3, outputPerMillion: 15 },
39
+ },
40
+ {
41
+ window: "day",
42
+ maxCost: 10.0,
43
+ pricing: { inputPerMillion: 3, outputPerMillion: 15 },
44
+ },
45
+ ],
46
+
47
+ // Callback when approaching limit (0-1 percentage)
48
+ budgetWarningThreshold: 0.8,
49
+ onWarning: (usage) => {
50
+ console.warn(`Budget at ${(usage.percentage * 100).toFixed(0)}%`);
51
+ },
52
+ });
53
+ ```
54
+
55
+ ### Anti-Pattern #29: budgetWarningThreshold out of range
56
+
57
+ ```typescript
58
+ // WRONG — threshold must be a 0-1 percentage
59
+ const budgetRunner = withBudget(baseRunner, {
60
+ budgetWarningThreshold: 80, // Not a percentage!
61
+ budgets: [{ window: "hour", maxCost: 1.0, pricing: { inputPerMillion: 3, outputPerMillion: 15 } }],
62
+ });
63
+
64
+ // CORRECT — use a decimal between 0 and 1
65
+ const budgetRunner = withBudget(baseRunner, {
66
+ budgetWarningThreshold: 0.8, // 80%
67
+ budgets: [{ window: "hour", maxCost: 1.0, pricing: { inputPerMillion: 3, outputPerMillion: 15 } }],
68
+ });
69
+ ```
70
+
71
+ ## Retry Policies
72
+
73
+ Wrap a runner with automatic retry on transient failures:
74
+
75
+ ```typescript
76
+ import { withRetry } from "@directive-run/ai";
77
+
78
+ const retryRunner = withRetry(baseRunner, {
79
+ maxRetries: 3,
80
+ backoff: "exponential", // "exponential" | "linear" | "none"
81
+ baseDelayMs: 100,
82
+
83
+ // Only retry specific errors
84
+ shouldRetry: (error) => {
85
+ return error.status === 429 || error.status >= 500;
86
+ },
87
+ });
88
+ ```
89
+
90
+ ## Fallback Chains
91
+
92
+ Automatically switch to a backup runner when the primary fails:
93
+
94
+ ```typescript
95
+ import { withFallback } from "@directive-run/ai";
96
+ import { createAnthropicRunner } from "@directive-run/ai/anthropic";
97
+ import { createOpenAIRunner } from "@directive-run/ai/openai";
98
+
99
+ const primary = createAnthropicRunner({ apiKey: process.env.ANTHROPIC_API_KEY });
100
+ const backup = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY });
101
+
102
+ // Falls back to backup when primary throws
103
+ const resilientRunner = withFallback(primary, backup);
104
+ ```
105
+
106
+ ## Circuit Breaker
107
+
108
+ Prevent repeated calls to a failing provider. Opens after N failures, resets after a timeout:
109
+
110
+ ```typescript
111
+ import { createCircuitBreaker } from "@directive-run/ai";
112
+
113
+ const breaker = createCircuitBreaker({
114
+ failureThreshold: 3, // Open after 3 consecutive failures
115
+ resetTimeout: 30000, // Try again after 30s (half-open state)
116
+ halfOpenMaxAttempts: 1, // Allow 1 test request in half-open
117
+ });
118
+
119
+ // Use with a runner
120
+ const protectedRunner = breaker.wrap(baseRunner);
121
+
122
+ // Check state
123
+ console.log(breaker.state); // "closed" | "open" | "half-open"
124
+ breaker.reset(); // Force back to closed
125
+ ```
126
+
127
+ ### Anti-Pattern #28: Sharing a CircuitBreaker across unrelated agents
128
+
129
+ ```typescript
130
+ // WRONG — one failing agent opens the breaker for all agents
131
+ const sharedBreaker = createCircuitBreaker({ failureThreshold: 3, resetTimeout: 30000 });
132
+ const researchRunner = sharedBreaker.wrap(baseRunner);
133
+ const writerRunner = sharedBreaker.wrap(baseRunner); // Same breaker!
134
+
135
+ // CORRECT — each agent gets its own breaker instance
136
+ const researchBreaker = createCircuitBreaker({ failureThreshold: 3, resetTimeout: 30000 });
137
+ const writerBreaker = createCircuitBreaker({ failureThreshold: 3, resetTimeout: 30000 });
138
+
139
+ const researchRunner = researchBreaker.wrap(baseRunner);
140
+ const writerRunner = writerBreaker.wrap(baseRunner);
141
+ ```
142
+
143
+ ## Health Monitor
144
+
145
+ Monitor agent health across the system, track circuit breaker states, and report status:
146
+
147
+ ```typescript
148
+ import { createHealthMonitor } from "@directive-run/ai";
149
+
150
+ const monitor = createHealthMonitor({
151
+ agents: {
152
+ researcher: { runner: researchRunner, circuitBreaker: researchBreaker },
153
+ writer: { runner: writerRunner, circuitBreaker: writerBreaker },
154
+ },
155
+ checkInterval: 60000, // Health check every 60s
156
+
157
+ onStatusChange: (agent, status) => {
158
+ console.log(`${agent}: ${status}`); // "healthy" | "degraded" | "unhealthy"
159
+ },
160
+ });
161
+
162
+ monitor.start();
163
+ const report = monitor.getReport();
164
+ monitor.stop();
165
+ ```
166
+
167
+ ## Semantic Cache
168
+
169
+ Cache LLM responses by semantic similarity to avoid redundant calls:
170
+
171
+ ```typescript
172
+ import { createSemanticCache } from "@directive-run/ai";
173
+ import { createOpenAIEmbedder } from "@directive-run/ai/openai";
174
+
175
+ const cache = createSemanticCache({
176
+ embedder: createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY }),
177
+ similarity: 0.98, // Minimum cosine similarity to count as a hit
178
+ maxSize: 1000, // Max cached entries (LRU eviction)
179
+ ttl: 3600000, // Cache entry TTL in ms (1 hour)
180
+ });
181
+
182
+ // Wrap a runner with caching
183
+ const cachedRunner = cache.wrap(baseRunner);
184
+ ```
185
+
186
+ ## Constraint-Driven Provider Routing
187
+
188
+ Route LLM calls to different providers based on runtime constraints:
189
+
190
+ ```typescript
191
+ import { createConstraintRouter } from "@directive-run/ai";
192
+
193
+ const router = createConstraintRouter({
194
+ providers: [
195
+ { name: "anthropic", runner: anthropicRunner, costPerMillion: 3 },
196
+ { name: "openai", runner: openaiRunner, costPerMillion: 5 },
197
+ { name: "ollama", runner: ollamaRunner, costPerMillion: 0 },
198
+ ],
199
+ constraints: [
200
+ // Use cheapest provider when budget is low
201
+ { when: (context) => context.budgetRemaining < 1.0, prefer: "ollama" },
202
+ // Use best provider for high-priority tasks
203
+ { when: (context) => context.priority === "high", prefer: "anthropic" },
204
+ ],
205
+ });
206
+ ```
207
+
208
+ ## Combining Wrappers
209
+
210
+ Wrappers compose — apply them inside-out (innermost runs first):
211
+
212
+ ```typescript
213
+ import { withBudget, withRetry, withFallback } from "@directive-run/ai";
214
+
215
+ // Order: retry → budget → fallback
216
+ const resilientRunner = withFallback(
217
+ withBudget(
218
+ withRetry(primaryRunner, { maxRetries: 3, backoff: "exponential", baseDelayMs: 100 }),
219
+ { budgets: [{ window: "hour", maxCost: 1.0, pricing: { inputPerMillion: 3, outputPerMillion: 15 } }] },
220
+ ),
221
+ fallbackRunner,
222
+ );
223
+ ```
224
+
225
+ ## Quick Reference
226
+
227
+ | Utility | Purpose | Key Options |
228
+ |---|---|---|
229
+ | `withBudget` | Cost caps per time window | `budgets`, `maxCostPerCall` |
230
+ | `withRetry` | Retry transient failures | `maxRetries`, `backoff`, `shouldRetry` |
231
+ | `withFallback` | Switch to backup runner | primary, fallback runners |
232
+ | `createCircuitBreaker` | Stop calling failing providers | `failureThreshold`, `resetTimeout` |
233
+ | `createHealthMonitor` | Fleet health tracking | `agents`, `checkInterval` |
234
+ | `createSemanticCache` | Avoid redundant LLM calls | `similarity`, `maxSize`, `ttl` |
235
+ | `createConstraintRouter` | Dynamic provider selection | `providers`, `constraints` |
@@ -0,0 +1,281 @@
1
+ # AI Communication
2
+
3
+ Cross-agent messaging, agent networks, shared state via derivations, scratchpad coordination, and handoff patterns.
4
+
5
+ ## Decision Tree: "How do agents communicate?"
6
+
7
+ ```
8
+ What kind of communication?
9
+ ├── Fire-and-forget notification → bus.publish({ type: "INFORM", ... })
10
+ ├── Request-response (await reply) → bus.request({ type: "REQUEST", ... })
11
+ ├── Delegate work to another agent → bus.publish({ type: "DELEGATION", ... })
12
+ ├── Subscribe to ongoing updates → bus.publish({ type: "SUBSCRIBE", ... })
13
+
14
+ How do agents share state?
15
+ ├── Read another agent's facts → orchestrator.system.facts.agentName.key
16
+ ├── Cross-agent derivations → orchestrator.derive.agentName.derivation
17
+ ├── Ephemeral key-value store → context.scratchpad
18
+
19
+ How do agents hand off work?
20
+ ├── One-time transfer → handoff pattern (DELEGATION + await DELEGATION_RESULT)
21
+ ├── Ongoing collaboration → agent network with capabilities
22
+ └── Conditional routing → reroute in supervisor pattern
23
+ ```
24
+
25
+ ## Message Bus
26
+
27
+ The message bus enables structured communication between agents:
28
+
29
+ ```typescript
30
+ import { createMessageBus } from "@directive-run/ai";
31
+
32
+ const bus = createMessageBus();
33
+ ```
34
+
35
+ ## Publishing Messages
36
+
37
+ ```typescript
38
+ // Fire-and-forget notification
39
+ bus.publish({
40
+ type: "INFORM",
41
+ from: "researcher",
42
+ to: "writer",
43
+ content: "Found 5 relevant sources",
44
+ metadata: { sourceCount: 5, topics: ["AI", "ML"] },
45
+ });
46
+
47
+ // Broadcast to all agents (omit "to")
48
+ bus.publish({
49
+ type: "INFORM",
50
+ from: "coordinator",
51
+ content: "System entering maintenance mode",
52
+ });
53
+ ```
54
+
55
+ ## Request-Response Pattern
56
+
57
+ ```typescript
58
+ // Send a request and await the response
59
+ const response = await bus.request({
60
+ type: "REQUEST",
61
+ from: "writer",
62
+ to: "researcher",
63
+ action: "verify_claim",
64
+ payload: { claim: "Transformers were invented in 2017" },
65
+ timeout: 5000, // Throws after 5s if no response
66
+ });
67
+
68
+ console.log(response.content); // "Verified: correct"
69
+ console.log(response.metadata); // { confidence: 0.95, source: "..." }
70
+ ```
71
+
72
+ ## Message Types
73
+
74
+ All 11 message types in the system:
75
+
76
+ | Type | Direction | Purpose |
77
+ |---|---|---|
78
+ | `REQUEST` | Agent-to-agent | Ask another agent to do something |
79
+ | `RESPONSE` | Agent-to-agent | Reply to a REQUEST |
80
+ | `DELEGATION` | Agent-to-agent | Hand off a task to another agent |
81
+ | `DELEGATION_RESULT` | Agent-to-agent | Return result of delegated work |
82
+ | `QUERY` | Agent-to-agent | Ask for information without side effects |
83
+ | `INFORM` | Agent-to-agent/all | Share information, no response expected |
84
+ | `SUBSCRIBE` | Agent-to-agent | Request ongoing updates on a topic |
85
+ | `UNSUBSCRIBE` | Agent-to-agent | Stop receiving updates |
86
+ | `UPDATE` | Agent-to-subscriber | Push update to a subscriber |
87
+ | `ACK` | Agent-to-agent | Acknowledge receipt |
88
+ | `NACK` | Agent-to-agent | Reject or refuse a message |
89
+
90
+ ## Subscribing to Messages
91
+
92
+ ```typescript
93
+ // Subscribe to all messages for an agent
94
+ const unsubscribe = bus.subscribe("writer", (message) => {
95
+ switch (message.type) {
96
+ case "INFORM":
97
+ console.log(`Info from ${message.from}: ${message.content}`);
98
+ break;
99
+ case "REQUEST":
100
+ // Handle and respond
101
+ bus.publish({
102
+ type: "RESPONSE",
103
+ from: "writer",
104
+ to: message.from,
105
+ correlationId: message.id,
106
+ content: "Done",
107
+ });
108
+ break;
109
+ }
110
+ });
111
+
112
+ // Clean up
113
+ unsubscribe();
114
+ ```
115
+
116
+ ## Agent Network
117
+
118
+ Higher-level abstraction for capability-based agent discovery:
119
+
120
+ ```typescript
121
+ import { createAgentNetwork } from "@directive-run/ai";
122
+
123
+ const network = createAgentNetwork({
124
+ bus,
125
+ agents: {
126
+ researcher: {
127
+ capabilities: ["search", "verify", "cite"],
128
+ },
129
+ writer: {
130
+ capabilities: ["draft", "edit", "summarize"],
131
+ },
132
+ analyst: {
133
+ capabilities: ["analyze", "chart", "report"],
134
+ },
135
+ },
136
+ });
137
+
138
+ // Find agents by capability
139
+ const writers = network.findByCapability("draft");
140
+ // ["writer"]
141
+
142
+ const verifiers = network.findByCapability("verify");
143
+ // ["researcher"]
144
+
145
+ // Route a request to the best agent for a capability
146
+ const result = await network.route("verify", {
147
+ claim: "GPT-4 has 1.8T parameters",
148
+ });
149
+ ```
150
+
151
+ ## Cross-Agent State via Derivations
152
+
153
+ Agents can read each other's facts and derivations through the shared system:
154
+
155
+ ```typescript
156
+ const orchestrator = createMultiAgentOrchestrator({
157
+ agents: {
158
+ researcher: {
159
+ name: "researcher",
160
+ instructions: "...",
161
+ model: "claude-sonnet-4-5",
162
+ },
163
+ writer: {
164
+ name: "writer",
165
+ instructions: "...",
166
+ model: "claude-sonnet-4-5",
167
+ },
168
+ },
169
+ runner,
170
+ });
171
+
172
+ orchestrator.start();
173
+
174
+ // Read another agent's facts (read-only)
175
+ const researchStatus = orchestrator.system.facts.researcher.status;
176
+ const writerOutput = orchestrator.system.facts.writer.lastOutput;
177
+
178
+ // Cross-agent derivations react to fact changes
179
+ const isReady = orchestrator.system.derive.researcher.isComplete;
180
+ ```
181
+
182
+ ## Scratchpad Coordination
183
+
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
+
186
+ ```typescript
187
+ // In a task — write to scratchpad
188
+ tasks: {
189
+ gather: {
190
+ run: async (input, context) => {
191
+ const data = JSON.parse(input);
192
+ context.scratchpad.researchData = data;
193
+ context.scratchpad.timestamp = Date.now();
194
+
195
+ return input;
196
+ },
197
+ },
198
+ format: {
199
+ run: async (input, context) => {
200
+ // Read from scratchpad set by earlier task
201
+ const data = context.scratchpad.researchData;
202
+ const ts = context.scratchpad.timestamp as number;
203
+
204
+ return JSON.stringify({ data, processedAt: ts });
205
+ },
206
+ },
207
+ },
208
+ ```
209
+
210
+ ## Handoff Patterns
211
+
212
+ ### One-Time Delegation
213
+
214
+ ```typescript
215
+ // Agent A delegates work to Agent B
216
+ bus.publish({
217
+ type: "DELEGATION",
218
+ from: "coordinator",
219
+ to: "researcher",
220
+ content: "Research the topic: quantum computing",
221
+ metadata: { priority: "high", deadline: Date.now() + 60000 },
222
+ });
223
+
224
+ // Agent B returns the result
225
+ bus.publish({
226
+ type: "DELEGATION_RESULT",
227
+ from: "researcher",
228
+ to: "coordinator",
229
+ correlationId: originalMessage.id,
230
+ content: "Research findings: ...",
231
+ metadata: { sourcesFound: 12 },
232
+ });
233
+ ```
234
+
235
+ ### Supervisor Reroute
236
+
237
+ In a supervisor pattern, the supervisor can reroute work mid-execution:
238
+
239
+ ```typescript
240
+ const managed = supervisor("editor", ["researcher", "writer"], {
241
+ onReroute: (from, to, reason) => {
242
+ console.log(`Rerouting from ${from} to ${to}: ${reason}`);
243
+ },
244
+ });
245
+ ```
246
+
247
+ ## Message Bus with Orchestrator
248
+
249
+ ```typescript
250
+ import { createMultiAgentOrchestrator, createMessageBus } from "@directive-run/ai";
251
+
252
+ const bus = createMessageBus();
253
+
254
+ const orchestrator = createMultiAgentOrchestrator({
255
+ agents: { researcher, writer },
256
+ runner,
257
+ bus, // Attach the message bus
258
+ });
259
+
260
+ orchestrator.start();
261
+
262
+ // External systems can also publish to the bus
263
+ bus.publish({
264
+ type: "INFORM",
265
+ from: "external",
266
+ to: "researcher",
267
+ content: "New data available",
268
+ });
269
+ ```
270
+
271
+ ## Quick Reference
272
+
273
+ | API | Purpose | Key Options |
274
+ |---|---|---|
275
+ | `createMessageBus()` | Agent-to-agent messaging | subscribe, publish, request |
276
+ | `createAgentNetwork()` | Capability-based discovery | agents with capabilities |
277
+ | `bus.publish()` | Fire-and-forget message | type, from, to, content |
278
+ | `bus.request()` | Request-response with timeout | action, payload, timeout |
279
+ | `bus.subscribe()` | Listen for messages | agentName, callback |
280
+ | `network.findByCapability()` | Find agents by skill | capability string |
281
+ | `network.route()` | Route work to capable agent | capability, payload |