@directive-run/knowledge 1.14.0 → 1.16.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 (43) hide show
  1. package/README.md +50 -15
  2. package/ai/ai-adapters.md +7 -0
  3. package/ai/ai-agents-streaming.md +187 -149
  4. package/ai/ai-budget-resilience.md +305 -132
  5. package/ai/ai-communication.md +220 -197
  6. package/ai/ai-debug-observability.md +259 -173
  7. package/ai/ai-guardrails-memory.md +191 -153
  8. package/ai/ai-mcp-rag.md +204 -199
  9. package/ai/ai-multi-agent.md +254 -153
  10. package/ai/ai-orchestrator.md +353 -114
  11. package/ai/ai-security.md +287 -180
  12. package/ai/ai-tasks.md +8 -1
  13. package/ai/ai-testing-evals.md +363 -256
  14. package/core/anti-patterns.md +18 -2
  15. package/core/constraints.md +13 -2
  16. package/core/core-patterns.md +12 -0
  17. package/core/error-boundaries.md +8 -0
  18. package/core/history.md +7 -0
  19. package/core/multi-module.md +15 -3
  20. package/core/naming.md +128 -90
  21. package/core/plugins.md +7 -0
  22. package/core/react-adapter.md +256 -174
  23. package/core/resolvers.md +10 -0
  24. package/core/schema-types.md +8 -0
  25. package/core/system-api.md +10 -0
  26. package/core/testing.md +257 -143
  27. package/examples/checkers.ts +15 -16
  28. package/examples/contact-form.ts +2 -2
  29. package/examples/counter-react.ts +1 -1
  30. package/examples/counter-svelte.ts +1 -1
  31. package/examples/counter-vue.ts +1 -1
  32. package/examples/counter.ts +1 -1
  33. package/examples/data-triggers.ts +4 -4
  34. package/examples/feature-flags.ts +2 -2
  35. package/examples/form-wizard.ts +2 -2
  36. package/examples/newsletter.ts +2 -2
  37. package/examples/server.ts +2 -2
  38. package/examples/shopping-cart.ts +1 -1
  39. package/examples/topic-guard.ts +1 -1
  40. package/package.json +3 -3
  41. package/sitemap.md +17 -11
  42. package/examples/debounce-constraints.ts +0 -95
  43. package/examples/multi-module.ts +0 -58
package/ai/ai-security.md CHANGED
@@ -1,293 +1,400 @@
1
- # AI Security
1
+ # AI security
2
2
 
3
- PII detection/redaction, prompt injection defense, audit trails, GDPR/CCPA compliance, and security best practices for Directive AI applications.
3
+ > Covers `@directive-run/ai` and `@directive-run/ai/guardrails` `createPIIGuardrail`, `createPromptInjectionGuardrail`, `createAuditTrail`, `createCompliance` (GDPR/CCPA).
4
4
 
5
- ## Decision Tree: "What security do I need?"
5
+ PII detection and redaction, prompt-injection defense, audit trails with non-repudiation, and GDPR/CCPA compliance — all wired in via Directive's guardrail and instance APIs. Import the audit + compliance instances from `@directive-run/ai` (NOT `@directive-run/core/plugins`); import the security guardrails from `@directive-run/ai/guardrails`.
6
+
7
+ ## Decision tree
6
8
 
7
9
  ```
8
10
  What are you protecting against?
9
- ├── PII leakage in prompts/outputs → createPIIGuardrail()
10
- ├── Prompt injection attacks createPromptInjectionGuardrail()
11
- ├── Audit/compliance requirements createAuditTrailPlugin()
12
- ├── GDPR/CCPA data handling createCompliancePlugin()
13
-
14
- Where do guardrails go?
15
- ├── Before agent receives prompt → guardrails.input
16
- ├── After agent produces output → guardrails.output
17
- └── Both directions → guardrails.input + guardrails.output
18
-
19
- Where do plugins go?
20
- └── Alwaysplugins: [createAuditTrailPlugin(), ...]
21
- (Plugins are Directive core plugins, not AI-specific)
11
+ ├── PII in input → createPIIGuardrail() or createEnhancedPIIGuardrail()
12
+ ├── PII in output createOutputPIIGuardrail()
13
+ ├── Prompt injection createPromptInjectionGuardrail()
14
+ ├── Audit / forensics createAuditTrail(config)
15
+ ├── GDPR / CCPA → createCompliance(config)
16
+ ├── Tool restriction → createToolGuardrail({ allowlist | denylist })
17
+ └── Sensitive content → createContentFilterGuardrail({ blockedPatterns })
18
+
19
+ Where do these go?
20
+ ├── Guardrails → orchestrator.guardrails.input / output / toolCall
21
+ ├── Audit → record into auditInstance from your call sites (NOT a plugins:[…] entry)
22
+ └── Complianceinstance you call directly (exportData, deleteData, consent.*)
22
23
  ```
23
24
 
24
- ## PII Detection and Redaction
25
-
26
- Enhanced PII guardrail with built-in patterns and custom regex support:
25
+ ## PII detection + redaction
27
26
 
28
- ```typescript
29
- import { createPIIGuardrail } from "@directive-run/ai";
27
+ ### Basic PII guardrail (input only)
30
28
 
31
- const piiGuardrail = createPIIGuardrail({
32
- // Redact PII instead of blocking (default: false = block)
33
- redact: true,
29
+ `createPIIGuardrail` returns a `GuardrailFn<InputGuardrailData>` — input only. For output PII protection, use `createOutputPIIGuardrail`.
34
30
 
35
- // Replacement string (default: "[REDACTED]")
36
- redactReplacement: "[REDACTED]",
31
+ ```typescript
32
+ import { createPIIGuardrail } from "@directive-run/ai/guardrails";
37
33
 
38
- // Additional custom patterns beyond built-ins
34
+ const piiInput = createPIIGuardrail({
39
35
  patterns: [
40
- /\b\d{3}-\d{2}-\d{4}\b/, // SSN
36
+ /\b\d{3}-\d{2}-\d{4}\b/, // SSN — already a default, here as a custom example
41
37
  /\b[A-Z]{2}\d{6,8}\b/, // Passport
42
- /ACCT-\d{10}/, // Internal account IDs
38
+ /ACCT-\d{10}/, // Internal account IDs
43
39
  ],
40
+ redact: true, // default: false (block instead of redact)
41
+ redactReplacement: "[REDACTED]",
44
42
  });
45
43
  ```
46
44
 
47
- Built-in patterns detect:
48
- - Email addresses
49
- - Phone numbers (US, international)
50
- - Credit card numbers (Visa, MC, Amex, Discover)
51
- - IP addresses (v4, v6)
52
- - Dates of birth (common formats)
45
+ Built-in default patterns: SSN, credit card numbers, email addresses. Custom `patterns` are added on top.
53
46
 
54
- ### Using PII Guardrail
47
+ ### Enhanced PII guardrails (input + output)
48
+
49
+ For production scenarios — context-aware detection, multi-region defaults, output coverage — use the enhanced factories:
55
50
 
56
51
  ```typescript
52
+ import { createEnhancedPIIGuardrail, createOutputPIIGuardrail } from "@directive-run/ai/guardrails";
53
+
54
+ const piiInput = createEnhancedPIIGuardrail({ /* …config… */ });
55
+ const piiOutput = createOutputPIIGuardrail({ /* …config… */ });
56
+
57
57
  const orchestrator = createAgentOrchestrator({
58
58
  runner,
59
59
  guardrails: {
60
- // Redact PII before the agent sees it
61
- input: [piiGuardrail],
60
+ input: [piiInput],
61
+ output: [piiOutput],
62
+ },
63
+ });
64
+ ```
65
+
66
+ ### Wiring it in
62
67
 
63
- // Catch any PII the agent generates
64
- output: [piiGuardrail],
68
+ ```typescript
69
+ const orchestrator = createAgentOrchestrator({
70
+ runner,
71
+ guardrails: {
72
+ input: [piiInput],
73
+ output: [piiOutput],
65
74
  },
66
75
  });
67
76
  ```
68
77
 
69
- ## Prompt Injection Detection
78
+ ## Prompt-injection defense
70
79
 
71
- Detect and block common prompt injection patterns:
80
+ `createPromptInjectionGuardrail` ships with default + strict pattern sets and a 0–100 risk score. The real options are `strictMode`, `blockThreshold`, `additionalPatterns`, `replacePatterns`, `sanitize`, `onBlocked`, `ignoreCategories`. There is no `sensitivity` field and no `allowlist`.
72
81
 
73
82
  ```typescript
74
- import { createPromptInjectionGuardrail } from "@directive-run/ai";
83
+ import { createPromptInjectionGuardrail } from "@directive-run/ai/guardrails";
75
84
 
76
- const injectionGuardrail = createPromptInjectionGuardrail({
77
- // Sensitivity: "low" | "medium" | "high" (default: "medium")
78
- sensitivity: "high",
85
+ // Basic uses default patterns + 50 block threshold
86
+ const injection = createPromptInjectionGuardrail();
79
87
 
80
- // Custom patterns to detect
81
- additionalPatterns: [
82
- /ignore previous instructions/i,
83
- /you are now/i,
84
- /system prompt/i,
85
- ],
86
-
87
- // Allow-list specific phrases that look like injections but are safe
88
- allowlist: [
89
- "you are now ready to proceed",
88
+ // Strict for high-security applications
89
+ const strictInjection = createPromptInjectionGuardrail({
90
+ strictMode: true, // use STRICT_INJECTION_PATTERNS instead of DEFAULT
91
+ blockThreshold: 25, // lower threshold — more aggressive blocking
92
+ additionalPatterns: [ // your own patterns layered on top
93
+ { name: "custom_role_override", regex: /you are now a /i, score: 70, category: "role_manipulation" },
90
94
  ],
95
+ sanitize: false, // when true, attempts to neutralize the input instead of blocking
96
+ onBlocked: (input, result) => {
97
+ metrics.increment("prompt_injection_blocked", { risk: result.riskScore });
98
+ },
91
99
  });
92
- ```
93
100
 
94
- ### Sensitivity Levels
101
+ // Roleplay app — allow role-manipulation patterns, keep everything else
102
+ const roleplayInjection = createPromptInjectionGuardrail({
103
+ ignoreCategories: ["role_manipulation"],
104
+ });
95
105
 
96
- | Level | Detects | False Positives |
97
- |---|---|---|
98
- | `"low"` | Obvious injections (role overrides, ignore instructions) | Rare |
99
- | `"medium"` | Common patterns + encoded attacks | Occasional |
100
- | `"high"` | Aggressive detection + heuristic analysis | More frequent |
106
+ // Replace all defaults
107
+ const customOnly = createPromptInjectionGuardrail({
108
+ replacePatterns: myPatternList,
109
+ });
110
+ ```
101
111
 
102
- ### Applying Injection Defense
112
+ ### Catching the block
103
113
 
104
114
  ```typescript
105
- const orchestrator = createAgentOrchestrator({
106
- runner,
107
- guardrails: {
108
- // Check user input for injection attempts
109
- input: [injectionGuardrail],
110
- },
111
- });
112
-
113
- // Handle blocked input
114
- import { GuardrailError } from "@directive-run/ai";
115
+ import { isGuardrailError } from "@directive-run/ai";
115
116
 
116
117
  try {
117
- const result = await orchestrator.run(agent, userInput);
118
+ await orchestrator.run(agent, userInput);
118
119
  } catch (error) {
119
- if (error instanceof GuardrailError) {
120
- console.log(error.guardrailName); // "prompt-injection"
121
- console.log(error.errorCode); // "GUARDRAIL_INPUT_BLOCKED"
122
- console.log(error.reason); // "Prompt injection detected: role override"
120
+ if (isGuardrailError(error)) {
121
+ console.log(error.guardrailName); // "prompt-injection"
122
+ console.log(error.code); // "INPUT_GUARDRAIL_FAILED"
123
+ console.log(error.userMessage); // safe-to-display rejection reason
124
+ // error.input and error.data are NON-enumerable (won't leak via JSON.stringify)
123
125
  }
124
126
  }
125
127
  ```
126
128
 
127
- ## Audit Trail Plugin
128
-
129
- Log all AI interactions for compliance and forensics:
130
-
131
- ```typescript
132
- import { createAuditTrailPlugin } from "@directive-run/core/plugins";
133
-
134
- const auditPlugin = createAuditTrailPlugin({
135
- // Where to store audit logs
136
- storage: "file", // "file" | "console" | custom handler
137
- filePath: "./audit.jsonl", // For file storage
129
+ `GuardrailError` does not expose `errorCode` (it's `code`) or `reason` (the rejection reason becomes the error `message` / `userMessage`). See `ai-guardrails-memory.md` for the full error shape.
138
130
 
139
- // What to log
140
- logInputs: true,
141
- logOutputs: true,
142
- logToolCalls: true,
143
- logTokenUsage: true,
131
+ ## Audit trail
144
132
 
145
- // Redact sensitive data in logs (recommended)
146
- redactPII: true,
133
+ `createAuditTrail(config)` returns an `AuditInstance` you record into from your call sites — it is NOT a plugin you put in `plugins: […]`. The factory is named `createAuditTrail`, NOT `createAuditTrailPlugin`, and it lives in `@directive-run/ai`, NOT `@directive-run/core/plugins`.
147
134
 
148
- // Custom log handler (alternative to file/console)
149
- onLog: async (entry) => {
150
- await sendToSIEM(entry);
135
+ ```typescript
136
+ import { createAuditTrail } from "@directive-run/ai";
137
+
138
+ const audit = createAuditTrail({
139
+ maxEntries: 10_000, // default 10000
140
+ retentionMs: 7 * 24 * 60 * 60 * 1000, // default: 7 days
141
+ exportInterval: 60_000, // default 60s — async exporter cadence
142
+ exporter: async (entries) => {
143
+ await sendToSIEM(entries);
144
+ },
145
+ piiMasking: {
146
+ enabled: true,
147
+ fields: ["input", "output"],
148
+ },
149
+ signing: { // optional non-repudiation chain
150
+ signFn: (hash) => signWithHSM(hash),
151
+ verifyFn: (hash, sig) => verifyWithHSM(hash, sig),
152
+ },
153
+ sessionId: currentSessionId,
154
+ actorId: currentUserId,
155
+ events: {
156
+ onEntryAdded: (entry) => log("audit:entry", entry.eventType),
157
+ onChainBroken: (result) => alertOnTamper(result),
158
+ onExportError: (err, entries) => log("audit:export:fail", err, entries.length),
151
159
  },
152
160
  });
161
+
162
+ // Query
163
+ const failed = audit.getEntries({ eventType: "guardrail_check" });
164
+ const verified = await audit.verifyChain();
165
+ const exported = await audit.export(Date.now() - 24 * 60 * 60 * 1000);
153
166
  ```
154
167
 
155
- ### Audit Log Entry Shape
168
+ Each `AuditEntry` carries a hash-chained sequence number so `verifyChain()` can prove no entries were dropped or rewritten in flight.
169
+
170
+ ### Recording entries
171
+
172
+ For most workflows the orchestrator records relevant events automatically when an audit instance is attached via your own integration code. The bare minimum from a call site:
156
173
 
157
174
  ```typescript
158
- interface AuditLogEntry {
159
- timestamp: string;
160
- eventType: "agent_run" | "tool_call" | "guardrail_check" | "error";
161
- agentName: string;
162
- input?: string; // Redacted if redactPII: true
163
- output?: string; // Redacted if redactPII: true
164
- toolCalls?: ToolCall[];
165
- tokenUsage?: { inputTokens: number; outputTokens: number };
166
- duration: number;
167
- guardrails?: { name: string; passed: boolean; reason?: string }[];
168
- error?: { message: string; code: string };
169
- }
175
+ // In your resolver / event handler / orchestrator hook
176
+ audit.record({
177
+ eventType: "agent_run",
178
+ agentName: agent.name,
179
+ input,
180
+ output: result.output,
181
+ tokenUsage: result.tokenUsage,
182
+ });
170
183
  ```
171
184
 
172
- ## GDPR/CCPA Compliance Plugin
185
+ See the API skeleton for the full `AuditEntry` shape.
186
+
187
+ ## GDPR / CCPA compliance
173
188
 
174
- Enforce data handling policies at the system level:
189
+ `createCompliance(config)` returns a `ComplianceInstance` you call directly. The factory is named `createCompliance`, NOT `createCompliancePlugin`, and lives in `@directive-run/ai`. **`storage` is required.**
175
190
 
176
191
  ```typescript
177
- import { createCompliancePlugin } from "@directive-run/core/plugins";
192
+ import { createCompliance } from "@directive-run/ai";
178
193
 
179
- const compliancePlugin = createCompliancePlugin({
180
- // Data retention policy
194
+ const compliance = createCompliance({
195
+ storage: myComplianceStorage, // REQUIRED your ComplianceStorage adapter
181
196
  retention: {
182
- maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days in ms
183
- autoDelete: true,
197
+ maxAgeMs: 30 * 24 * 60 * 60 * 1000, // 30 days
198
+ autoEnforce: true,
184
199
  },
185
-
186
- // Right to deletion
187
- onDeletionRequest: async (userId) => {
188
- await deleteUserData(userId);
189
- await deleteConversationHistory(userId);
200
+ consentPurposes: ["analytics", "personalization", "training"],
201
+ exportExpirationMs: 24 * 60 * 60 * 1000, // signed export links expire in 24h (default)
202
+ auditOperations: true, // mirror every compliance op into the audit trail
203
+ events: {
204
+ onExport: (result) => log("gdpr:export", result.subjectId),
205
+ onDelete: (result) => log("gdpr:delete", result.certificate),
206
+ onConsentChange: (record) => log("consent:change", record),
207
+ onRetentionEnforced: (category, count) => log("retention:enforced", category, count),
190
208
  },
209
+ });
191
210
 
192
- // Data export (right to portability)
193
- onExportRequest: async (userId) => {
194
- const data = await getUserData(userId);
211
+ // GDPR Article 20 — right to data portability
212
+ const exportResult = await compliance.exportData({ subjectId: "user-42", format: "json" });
195
213
 
196
- return JSON.stringify(data);
197
- },
214
+ // GDPR Article 17 — right to erasure (returns a signed deletion certificate)
215
+ const deletion = await compliance.deleteData({ subjectId: "user-42", scope: "all" });
216
+ console.log(deletion.certificate.signature);
198
217
 
199
- // Consent tracking
200
- requireConsent: true,
201
- consentCategories: ["analytics", "personalization", "training"],
202
- });
218
+ // Consent
219
+ compliance.consent.grant({ subjectId: "user-42", purpose: "analytics" });
220
+ compliance.consent.revoke({ subjectId: "user-42", purpose: "personalization" });
221
+ const consents = compliance.consent.list("user-42");
203
222
  ```
204
223
 
205
- ## Applying Security Plugins
224
+ The `storage` adapter is your responsibility — Directive provides the policy + signed-receipt machinery; you provide the database. The `ComplianceStorage` interface lives in `@directive-run/ai`.
206
225
 
207
- Plugins go on the orchestrator (they are Directive core plugins):
226
+ ## Combining the surface
208
227
 
209
228
  ```typescript
210
229
  import { createAgentOrchestrator } from "@directive-run/ai";
230
+ import { createAuditTrail, createCompliance } from "@directive-run/ai";
231
+ import {
232
+ createPIIGuardrail,
233
+ createOutputPIIGuardrail,
234
+ createPromptInjectionGuardrail,
235
+ createToolGuardrail,
236
+ } from "@directive-run/ai/guardrails";
237
+
238
+ const audit = createAuditTrail({ /* ... */ });
239
+ const compliance = createCompliance({ storage: myStorage });
211
240
 
212
241
  const orchestrator = createAgentOrchestrator({
213
242
  runner,
214
243
  guardrails: {
215
- input: [piiGuardrail, injectionGuardrail],
216
- output: [piiGuardrail],
244
+ input: [createPIIGuardrail({ redact: true }), createPromptInjectionGuardrail({ strictMode: true })],
245
+ output: [createOutputPIIGuardrail()],
246
+ toolCall: [createToolGuardrail({ allowlist: ["search", "calculator"] })],
217
247
  },
218
- plugins: [auditPlugin, compliancePlugin],
248
+ maxTokenBudget: 100_000,
249
+ budgetWarningThreshold: 0.8,
219
250
  });
251
+
252
+ // Wire audit + compliance into your orchestrator hooks
253
+ orchestrator.run = (orig => async (agent, input, opts) => {
254
+ audit.record({ eventType: "agent_run", agentName: agent.name, input });
255
+ return orig(agent, input, opts);
256
+ })(orchestrator.run);
220
257
  ```
221
258
 
222
- ## Security Best Practices
259
+ ## Security best practices
223
260
 
224
- ### Input Validation
261
+ ### Validate input before dispatch
225
262
 
226
263
  ```typescript
227
- // WRONG passing raw user input to the agent
228
- const result = await orchestrator.run(agent, userInput);
264
+ // WRONG raw user input goes straight to the agent
265
+ await orchestrator.run(agent, userInput);
229
266
 
230
- // CORRECT validate and sanitize input first
267
+ // CORRECT sanitize / shape-check first, even with guardrails
231
268
  const sanitized = sanitizeInput(userInput);
232
- const result = await orchestrator.run(agent, sanitized);
269
+ await orchestrator.run(agent, sanitized);
233
270
  ```
234
271
 
235
- ### Token Budget Limits
272
+ ### Always set a token budget
236
273
 
237
274
  ```typescript
238
- // Always set a token budget to prevent runaway costs
239
- const orchestrator = createAgentOrchestrator({
275
+ createAgentOrchestrator({
240
276
  runner,
241
- maxTokenBudget: 100000,
277
+ maxTokenBudget: 100_000,
242
278
  budgetWarningThreshold: 0.8,
243
- });
279
+ onBudgetWarning: (e) => alertOps(e),
280
+ })
244
281
  ```
245
282
 
246
- ### Tool Approval Workflows
283
+ ### Restrict tool access
247
284
 
248
285
  ```typescript
249
- import { createToolGuardrail } from "@directive-run/ai";
286
+ import { createToolGuardrail } from "@directive-run/ai/guardrails";
250
287
 
251
- // Restrict which tools the agent can call
252
- const toolGuardrail = createToolGuardrail({
253
- allowedTools: ["search", "calculator", "readFile"],
254
- // Tools not in this list are blocked
288
+ const tools = createToolGuardrail({
289
+ allowlist: ["search", "calculator", "readFile"],
255
290
  });
256
291
 
257
- // For MCP tools, use toolConstraints
258
- const mcp = createMCPAdapter({
259
- servers: [...],
260
- toolConstraints: {
261
- "tools/write-file": { requireApproval: true },
262
- "tools/delete": { requireApproval: true, maxAttempts: 1 },
263
- },
292
+ const orchestrator = createAgentOrchestrator({
293
+ runner,
294
+ guardrails: { toolCall: [tools] },
264
295
  });
265
296
  ```
266
297
 
267
- ### Output Sanitization
298
+ For MCP-mediated tools, see `ai-mcp-rag.md` for per-tool approval + risk-scoring.
299
+
300
+ ### Always validate output
268
301
 
269
302
  ```typescript
270
- // Always validate agent output before using it
271
- const orchestrator = createAgentOrchestrator({
303
+ import {
304
+ createOutputSchemaGuardrail,
305
+ createContentFilterGuardrail,
306
+ createOutputPIIGuardrail,
307
+ } from "@directive-run/ai/guardrails";
308
+
309
+ createAgentOrchestrator({
272
310
  runner,
273
311
  guardrails: {
274
312
  output: [
275
- createOutputSchemaGuardrail({ schema: expectedSchema, retries: 2 }),
276
- createContentFilterGuardrail({ patterns: [/eval\(/, /<script/i], action: "block" }),
277
- createPIIGuardrail({ redact: true }),
313
+ createOutputSchemaGuardrail({ validate: zodAdapter(expectedSchema) }),
314
+ createContentFilterGuardrail({ blockedPatterns: [/eval\(/, /<script/i] }),
315
+ createOutputPIIGuardrail(),
278
316
  ],
279
317
  },
280
318
  });
281
319
  ```
282
320
 
283
- ## Quick Reference
284
-
285
- | API | Import Path | Purpose |
286
- |---|---|---|
287
- | `createPIIGuardrail` | `@directive-run/ai` | Detect/redact PII |
288
- | `createPromptInjectionGuardrail` | `@directive-run/ai` | Block injection attacks |
289
- | `createAuditTrailPlugin` | `@directive-run/core/plugins` | Log all AI interactions |
290
- | `createCompliancePlugin` | `@directive-run/core/plugins` | GDPR/CCPA data policies |
291
- | `createToolGuardrail` | `@directive-run/ai` | Restrict tool access |
292
- | `createContentFilterGuardrail` | `@directive-run/ai` | Block unsafe content patterns |
293
- | `GuardrailError` | `@directive-run/ai` | Catch guardrail failures |
321
+ (`createOutputSchemaGuardrail` takes `validate` — not `schema` + `retries`. For automatic retry on schema failure, set `outputSchema` + `maxSchemaRetries` directly on the orchestrator.)
322
+
323
+ ## Anti-patterns
324
+
325
+ ### Importing audit/compliance from `@directive-run/core/plugins`
326
+
327
+ ```typescript
328
+ // WRONG these names + path don't exist
329
+ import { createAuditTrailPlugin, createCompliancePlugin } from "@directive-run/core/plugins";
330
+
331
+ // CORRECT createAuditTrail / createCompliance from @directive-run/ai
332
+ import { createAuditTrail, createCompliance } from "@directive-run/ai";
333
+ ```
334
+
335
+ ### Putting `createAuditTrail()` into `plugins: [...]`
336
+
337
+ ```typescript
338
+ // WRONG — createAuditTrail returns an AuditInstance, not a Directive Plugin
339
+ plugins: [createAuditTrail({ /* … */ })],
340
+
341
+ // CORRECT — keep the instance, record into it
342
+ const audit = createAuditTrail({ /* … */ });
343
+ audit.record({ /* … */ });
344
+ ```
345
+
346
+ ### `createPromptInjectionGuardrail({ sensitivity, allowlist })`
347
+
348
+ ```typescript
349
+ // WRONG — sensitivity + allowlist are hallucinated
350
+ createPromptInjectionGuardrail({ sensitivity: "high", allowlist: ["safe phrase"] })
351
+
352
+ // CORRECT — strictMode + blockThreshold + ignoreCategories + replacePatterns
353
+ createPromptInjectionGuardrail({
354
+ strictMode: true,
355
+ blockThreshold: 25,
356
+ ignoreCategories: ["role_manipulation"],
357
+ })
358
+ ```
359
+
360
+ ### Using `createPIIGuardrail` for output
361
+
362
+ ```typescript
363
+ // WRONG — createPIIGuardrail is input-only (GuardrailFn<InputGuardrailData>)
364
+ guardrails: { output: [createPIIGuardrail({ redact: true })] }
365
+
366
+ // CORRECT — createOutputPIIGuardrail for output
367
+ guardrails: { output: [createOutputPIIGuardrail()] }
368
+ ```
369
+
370
+ ### `createCompliance` without `storage`
371
+
372
+ ```typescript
373
+ // WRONG — storage is required
374
+ createCompliance({ retention: { maxAgeMs: 30 * 24 * 60 * 60 * 1000 } })
375
+
376
+ // CORRECT — pass your ComplianceStorage adapter
377
+ createCompliance({
378
+ storage: myStorage,
379
+ retention: { maxAgeMs: 30 * 24 * 60 * 60 * 1000, autoEnforce: true },
380
+ })
381
+ ```
382
+
383
+ ## Quick reference
384
+
385
+ | API | Import path | Returns | Purpose |
386
+ |---|---|---|---|
387
+ | `createPIIGuardrail` | `@directive-run/ai/guardrails` | `GuardrailFn<InputGuardrailData>` | Basic input PII detection (block or redact) |
388
+ | `createEnhancedPIIGuardrail` | `@directive-run/ai/guardrails` | guardrail | Context-aware input PII |
389
+ | `createOutputPIIGuardrail` | `@directive-run/ai/guardrails` | guardrail | Output PII coverage |
390
+ | `createPromptInjectionGuardrail` | `@directive-run/ai/guardrails` | guardrail | Risk-scored injection defense (`strictMode`, `blockThreshold`) |
391
+ | `createAuditTrail` | `@directive-run/ai` | `AuditInstance` | Hash-chained audit log w/ signing + PII masking + async export |
392
+ | `createCompliance` | `@directive-run/ai` | `ComplianceInstance` | GDPR exportData / deleteData / consent + retention enforcement |
393
+ | `createToolGuardrail` | `@directive-run/ai/guardrails` | guardrail | Tool allow/deny lists |
394
+ | `createContentFilterGuardrail` | `@directive-run/ai/guardrails` | guardrail | Block sensitive patterns (block-only — no redact) |
395
+ | `GuardrailError` / `isGuardrailError` | `@directive-run/ai` | error class + guard | Carries `code`, `guardrailName`, `userMessage` |
396
+
397
+ ## See also
398
+
399
+ - [`ai-guardrails-memory.md`](./ai-guardrails-memory.md) — the broader guardrail surface (length, schema, content filter, tool allowlist) this file's security-flavored guardrails compose with
400
+ - [`ai-mcp-rag.md`](./ai-mcp-rag.md) — `toolConstraints[…].requireApproval` is where MCP tool calls thread into the approval workflow surfaced here
package/ai/ai-tasks.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # AI Tasks
2
2
 
3
+ > Covers `@directive-run/ai` — deterministic non-LLM task registration with cancellation, retry, and scratchpad access; composes with multi-agent patterns.
4
+
3
5
  Tasks are deterministic, non-LLM work units that run alongside agents in orchestration patterns. Use tasks for data transformation, API calls, file I/O, or any work that does not need an LLM.
4
6
 
5
7
  ## Decision Tree: "Should this be an agent or a task?"
@@ -65,7 +67,7 @@ interface TaskContext {
65
67
  ## Registering Tasks
66
68
 
67
69
  ```typescript
68
- import { createMultiAgentOrchestrator } from "@directive-run/ai";
70
+ import { createMultiAgentOrchestrator } from "@directive-run/ai/multi-agent";
69
71
 
70
72
  const orchestrator = createMultiAgentOrchestrator({
71
73
  agents: {
@@ -259,3 +261,8 @@ tasks: {
259
261
  | Concurrency control | Via patterns | `maxConcurrent` |
260
262
  | Scratchpad access | No | Yes |
261
263
  | Works in all patterns | Yes | Yes |
264
+
265
+ ## See also
266
+
267
+ - [`ai-multi-agent.md`](./ai-multi-agent.md) — tasks share the `handler:` namespace with agents inside `dag` / `sequential` / `parallel` patterns
268
+ - [`ai-communication.md`](./ai-communication.md) — tasks read the scratchpad this file's `context.scratchpad` surface exposes