@directive-run/knowledge 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/ai/ai-adapters.md +250 -0
- package/ai/ai-agents-streaming.md +269 -0
- package/ai/ai-budget-resilience.md +235 -0
- package/ai/ai-communication.md +281 -0
- package/ai/ai-debug-observability.md +243 -0
- package/ai/ai-guardrails-memory.md +332 -0
- package/ai/ai-mcp-rag.md +288 -0
- package/ai/ai-multi-agent.md +274 -0
- package/ai/ai-orchestrator.md +227 -0
- package/ai/ai-security.md +293 -0
- package/ai/ai-tasks.md +261 -0
- package/ai/ai-testing-evals.md +378 -0
- package/api-skeleton.md +5 -0
- package/core/anti-patterns.md +382 -0
- package/core/constraints.md +263 -0
- package/core/core-patterns.md +228 -0
- package/core/error-boundaries.md +322 -0
- package/core/multi-module.md +315 -0
- package/core/naming.md +283 -0
- package/core/plugins.md +344 -0
- package/core/react-adapter.md +262 -0
- package/core/resolvers.md +357 -0
- package/core/schema-types.md +262 -0
- package/core/system-api.md +271 -0
- package/core/testing.md +257 -0
- package/core/time-travel.md +238 -0
- package/dist/index.cjs +111 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/examples/ab-testing.ts +385 -0
- package/examples/ai-checkpoint.ts +509 -0
- package/examples/ai-guardrails.ts +319 -0
- package/examples/ai-orchestrator.ts +589 -0
- package/examples/async-chains.ts +287 -0
- package/examples/auth-flow.ts +371 -0
- package/examples/batch-resolver.ts +341 -0
- package/examples/checkers.ts +589 -0
- package/examples/contact-form.ts +176 -0
- package/examples/counter.ts +393 -0
- package/examples/dashboard-loader.ts +512 -0
- package/examples/debounce-constraints.ts +105 -0
- package/examples/dynamic-modules.ts +293 -0
- package/examples/error-boundaries.ts +430 -0
- package/examples/feature-flags.ts +220 -0
- package/examples/form-wizard.ts +347 -0
- package/examples/fraud-analysis.ts +663 -0
- package/examples/goal-heist.ts +341 -0
- package/examples/multi-module.ts +57 -0
- package/examples/newsletter.ts +241 -0
- package/examples/notifications.ts +210 -0
- package/examples/optimistic-updates.ts +317 -0
- package/examples/pagination.ts +260 -0
- package/examples/permissions.ts +337 -0
- package/examples/provider-routing.ts +403 -0
- package/examples/server.ts +316 -0
- package/examples/shopping-cart.ts +422 -0
- package/examples/sudoku.ts +630 -0
- package/examples/theme-locale.ts +204 -0
- package/examples/time-machine.ts +225 -0
- package/examples/topic-guard.ts +306 -0
- package/examples/url-sync.ts +333 -0
- package/examples/websocket.ts +404 -0
- package/package.json +65 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# AI Orchestrator (Single-Agent)
|
|
2
|
+
|
|
3
|
+
The `createAgentOrchestrator` configures a Directive-backed runtime for a single AI agent with constraints, resolvers, guardrails, memory, budgets, and hooks.
|
|
4
|
+
|
|
5
|
+
## Decision Tree: "How do I set up an orchestrator?"
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Need to run an AI agent?
|
|
9
|
+
├── Single agent → createAgentOrchestrator (this file)
|
|
10
|
+
├── Multiple agents → createMultiAgentOrchestrator (see ai-multi-agent.md)
|
|
11
|
+
│
|
|
12
|
+
Setting up createAgentOrchestrator...
|
|
13
|
+
├── Need schema? → factsSchema with t.*() builders (NOT TS types)
|
|
14
|
+
├── Need guardrails? → guardrails: { input: [...], output: [...] }
|
|
15
|
+
├── Need memory? → memory: createAgentMemory({ strategy, summarizer })
|
|
16
|
+
├── Need budget control? → maxTokenBudget + budgetWarningThreshold
|
|
17
|
+
├── Need streaming? → orchestrator.runStream(agent, prompt)
|
|
18
|
+
└── Need approval workflow? → hooks.onBeforeRun returns { approved: boolean }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Basic Setup
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { createAgentOrchestrator, t } from "@directive-run/ai";
|
|
25
|
+
import { createAnthropicRunner } from "@directive-run/ai/anthropic";
|
|
26
|
+
|
|
27
|
+
const runner = createAnthropicRunner({
|
|
28
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const orchestrator = createAgentOrchestrator({
|
|
32
|
+
runner,
|
|
33
|
+
factsSchema: {
|
|
34
|
+
confidence: t.number(),
|
|
35
|
+
analysis: t.string(),
|
|
36
|
+
cache: t.array<string>(),
|
|
37
|
+
},
|
|
38
|
+
init: (facts) => {
|
|
39
|
+
facts.confidence = 0;
|
|
40
|
+
facts.analysis = "";
|
|
41
|
+
facts.cache = [];
|
|
42
|
+
},
|
|
43
|
+
constraints: {
|
|
44
|
+
lowConfidence: {
|
|
45
|
+
when: (facts) => facts.confidence < 0.5,
|
|
46
|
+
require: { type: "RE_ANALYZE" },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
resolvers: {
|
|
50
|
+
reAnalyze: {
|
|
51
|
+
requirement: "RE_ANALYZE",
|
|
52
|
+
resolve: async (req, context) => {
|
|
53
|
+
context.facts.confidence = 0;
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
guardrails: {
|
|
58
|
+
input: [createPIIGuardrail({ redact: true })],
|
|
59
|
+
output: [createLengthGuardrail({ maxChars: 5000 })],
|
|
60
|
+
},
|
|
61
|
+
maxTokenBudget: 100000,
|
|
62
|
+
budgetWarningThreshold: 0.8,
|
|
63
|
+
memory: createAgentMemory({
|
|
64
|
+
strategy: createSlidingWindowStrategy({ maxMessages: 50 }),
|
|
65
|
+
summarizer: createKeyPointsSummarizer(),
|
|
66
|
+
}),
|
|
67
|
+
debug: true,
|
|
68
|
+
hooks: {
|
|
69
|
+
onStart: () => console.log("Orchestrator started"),
|
|
70
|
+
onBeforeRun: (agent, prompt) => ({ approved: true }),
|
|
71
|
+
onAfterRun: (agent, result) => console.log("Done", result.totalTokens),
|
|
72
|
+
onError: (error) => console.error(error),
|
|
73
|
+
onBudgetWarning: (usage) => console.warn("Budget:", usage),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Running the Agent
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const agent = {
|
|
82
|
+
name: "analyst",
|
|
83
|
+
instructions: "You are a data analyst.",
|
|
84
|
+
model: "claude-sonnet-4-5",
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Standard run
|
|
88
|
+
const result = await orchestrator.run(agent, "Analyze this dataset");
|
|
89
|
+
console.log(result.output);
|
|
90
|
+
|
|
91
|
+
// Streaming run
|
|
92
|
+
const stream = orchestrator.runStream(agent, "Summarize findings");
|
|
93
|
+
for await (const chunk of stream) {
|
|
94
|
+
if (chunk.type === "token") {
|
|
95
|
+
process.stdout.write(chunk.data);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Wait for all constraints/resolvers to settle
|
|
100
|
+
await orchestrator.system.settle();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## OrchestratorState Fields
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// Access via orchestrator.system.facts
|
|
107
|
+
orchestrator.system.facts.status; // "idle" | "running" | "paused" | "error"
|
|
108
|
+
orchestrator.system.facts.tokenUsage; // { inputTokens, outputTokens, total }
|
|
109
|
+
orchestrator.system.facts.runCount; // number of completed runs
|
|
110
|
+
orchestrator.system.facts.lastError; // Error | null
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Approval Workflow
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const orchestrator = createAgentOrchestrator({
|
|
117
|
+
runner,
|
|
118
|
+
hooks: {
|
|
119
|
+
onBeforeRun: async (agent, prompt) => {
|
|
120
|
+
const decision = await reviewPrompt(prompt);
|
|
121
|
+
|
|
122
|
+
return { approved: decision.ok, reason: decision.reason };
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// If not approved, run() throws ApprovalDeniedError
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Pause / Resume
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
orchestrator.pause();
|
|
134
|
+
// Agent work suspends; in-flight requests complete but new ones queue
|
|
135
|
+
|
|
136
|
+
orchestrator.resume();
|
|
137
|
+
// Queued work begins executing
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Checkpoints
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// Save state
|
|
144
|
+
const checkpoint = orchestrator.checkpoint();
|
|
145
|
+
const serialized = JSON.stringify(checkpoint);
|
|
146
|
+
|
|
147
|
+
// Restore state
|
|
148
|
+
const restored = createAgentOrchestrator({
|
|
149
|
+
runner,
|
|
150
|
+
checkpoint: JSON.parse(serialized),
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Anti-Patterns
|
|
155
|
+
|
|
156
|
+
### #21: TypeScript types instead of t.*() for factsSchema
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// WRONG — TS types are erased at runtime, no schema validation
|
|
160
|
+
const orchestrator = createAgentOrchestrator({
|
|
161
|
+
runner,
|
|
162
|
+
factsSchema: {} as { confidence: number; analysis: string },
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// CORRECT — use t.*() builders for runtime schema
|
|
166
|
+
const orchestrator = createAgentOrchestrator({
|
|
167
|
+
runner,
|
|
168
|
+
factsSchema: {
|
|
169
|
+
confidence: t.number(),
|
|
170
|
+
analysis: t.string(),
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### #22: Mutating arrays/objects in place
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// WRONG — proxy cannot detect in-place mutations
|
|
179
|
+
context.facts.cache.push("new-item");
|
|
180
|
+
|
|
181
|
+
// CORRECT — replace the entire value
|
|
182
|
+
context.facts.cache = [...context.facts.cache, "new-item"];
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### #23: Returning data from resolve
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// WRONG — resolvers return void, not data
|
|
189
|
+
resolve: async (req, context) => {
|
|
190
|
+
const result = await analyzeData(req.input);
|
|
191
|
+
|
|
192
|
+
return result; // Return value is ignored
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
// CORRECT — mutate context.facts to store results
|
|
196
|
+
resolve: async (req, context) => {
|
|
197
|
+
const result = await analyzeData(req.input);
|
|
198
|
+
context.facts.analysis = result;
|
|
199
|
+
},
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### #24: Forgetting start() for multi-agent
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// WRONG — multi-agent orchestrators require explicit start()
|
|
206
|
+
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
207
|
+
const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
208
|
+
|
|
209
|
+
// CORRECT — call start() before running patterns
|
|
210
|
+
const orchestrator = createMultiAgentOrchestrator({ agents, runner });
|
|
211
|
+
orchestrator.start();
|
|
212
|
+
const result = await orchestrator.runPattern("pipeline", "prompt");
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Note: Single-agent `createAgentOrchestrator` does NOT require `start()`. Only `createMultiAgentOrchestrator` does.
|
|
216
|
+
|
|
217
|
+
## Quick Reference
|
|
218
|
+
|
|
219
|
+
| Method | Purpose |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `orchestrator.run(agent, prompt)` | Run agent, return RunResult |
|
|
222
|
+
| `orchestrator.runStream(agent, prompt)` | Run agent, return AsyncIterable<StreamChunk> |
|
|
223
|
+
| `orchestrator.pause()` | Suspend new work |
|
|
224
|
+
| `orchestrator.resume()` | Resume suspended work |
|
|
225
|
+
| `orchestrator.checkpoint()` | Serialize current state |
|
|
226
|
+
| `orchestrator.system.settle()` | Wait for all resolvers |
|
|
227
|
+
| `orchestrator.system.facts` | Read orchestrator state |
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# AI Security
|
|
2
|
+
|
|
3
|
+
PII detection/redaction, prompt injection defense, audit trails, GDPR/CCPA compliance, and security best practices for Directive AI applications.
|
|
4
|
+
|
|
5
|
+
## Decision Tree: "What security do I need?"
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
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
|
+
└── Always → plugins: [createAuditTrailPlugin(), ...]
|
|
21
|
+
(Plugins are Directive core plugins, not AI-specific)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## PII Detection and Redaction
|
|
25
|
+
|
|
26
|
+
Enhanced PII guardrail with built-in patterns and custom regex support:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { createPIIGuardrail } from "@directive-run/ai";
|
|
30
|
+
|
|
31
|
+
const piiGuardrail = createPIIGuardrail({
|
|
32
|
+
// Redact PII instead of blocking (default: false = block)
|
|
33
|
+
redact: true,
|
|
34
|
+
|
|
35
|
+
// Replacement string (default: "[REDACTED]")
|
|
36
|
+
redactReplacement: "[REDACTED]",
|
|
37
|
+
|
|
38
|
+
// Additional custom patterns beyond built-ins
|
|
39
|
+
patterns: [
|
|
40
|
+
/\b\d{3}-\d{2}-\d{4}\b/, // SSN
|
|
41
|
+
/\b[A-Z]{2}\d{6,8}\b/, // Passport
|
|
42
|
+
/ACCT-\d{10}/, // Internal account IDs
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
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)
|
|
53
|
+
|
|
54
|
+
### Using PII Guardrail
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const orchestrator = createAgentOrchestrator({
|
|
58
|
+
runner,
|
|
59
|
+
guardrails: {
|
|
60
|
+
// Redact PII before the agent sees it
|
|
61
|
+
input: [piiGuardrail],
|
|
62
|
+
|
|
63
|
+
// Catch any PII the agent generates
|
|
64
|
+
output: [piiGuardrail],
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Prompt Injection Detection
|
|
70
|
+
|
|
71
|
+
Detect and block common prompt injection patterns:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { createPromptInjectionGuardrail } from "@directive-run/ai";
|
|
75
|
+
|
|
76
|
+
const injectionGuardrail = createPromptInjectionGuardrail({
|
|
77
|
+
// Sensitivity: "low" | "medium" | "high" (default: "medium")
|
|
78
|
+
sensitivity: "high",
|
|
79
|
+
|
|
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",
|
|
90
|
+
],
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Sensitivity Levels
|
|
95
|
+
|
|
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 |
|
|
101
|
+
|
|
102
|
+
### Applying Injection Defense
|
|
103
|
+
|
|
104
|
+
```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
|
+
|
|
116
|
+
try {
|
|
117
|
+
const result = await orchestrator.run(agent, userInput);
|
|
118
|
+
} 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"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
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
|
|
138
|
+
|
|
139
|
+
// What to log
|
|
140
|
+
logInputs: true,
|
|
141
|
+
logOutputs: true,
|
|
142
|
+
logToolCalls: true,
|
|
143
|
+
logTokenUsage: true,
|
|
144
|
+
|
|
145
|
+
// Redact sensitive data in logs (recommended)
|
|
146
|
+
redactPII: true,
|
|
147
|
+
|
|
148
|
+
// Custom log handler (alternative to file/console)
|
|
149
|
+
onLog: async (entry) => {
|
|
150
|
+
await sendToSIEM(entry);
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Audit Log Entry Shape
|
|
156
|
+
|
|
157
|
+
```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
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## GDPR/CCPA Compliance Plugin
|
|
173
|
+
|
|
174
|
+
Enforce data handling policies at the system level:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { createCompliancePlugin } from "@directive-run/core/plugins";
|
|
178
|
+
|
|
179
|
+
const compliancePlugin = createCompliancePlugin({
|
|
180
|
+
// Data retention policy
|
|
181
|
+
retention: {
|
|
182
|
+
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days in ms
|
|
183
|
+
autoDelete: true,
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// Right to deletion
|
|
187
|
+
onDeletionRequest: async (userId) => {
|
|
188
|
+
await deleteUserData(userId);
|
|
189
|
+
await deleteConversationHistory(userId);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
// Data export (right to portability)
|
|
193
|
+
onExportRequest: async (userId) => {
|
|
194
|
+
const data = await getUserData(userId);
|
|
195
|
+
|
|
196
|
+
return JSON.stringify(data);
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// Consent tracking
|
|
200
|
+
requireConsent: true,
|
|
201
|
+
consentCategories: ["analytics", "personalization", "training"],
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Applying Security Plugins
|
|
206
|
+
|
|
207
|
+
Plugins go on the orchestrator (they are Directive core plugins):
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { createAgentOrchestrator } from "@directive-run/ai";
|
|
211
|
+
|
|
212
|
+
const orchestrator = createAgentOrchestrator({
|
|
213
|
+
runner,
|
|
214
|
+
guardrails: {
|
|
215
|
+
input: [piiGuardrail, injectionGuardrail],
|
|
216
|
+
output: [piiGuardrail],
|
|
217
|
+
},
|
|
218
|
+
plugins: [auditPlugin, compliancePlugin],
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Security Best Practices
|
|
223
|
+
|
|
224
|
+
### Input Validation
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// WRONG — passing raw user input to the agent
|
|
228
|
+
const result = await orchestrator.run(agent, userInput);
|
|
229
|
+
|
|
230
|
+
// CORRECT — validate and sanitize input first
|
|
231
|
+
const sanitized = sanitizeInput(userInput);
|
|
232
|
+
const result = await orchestrator.run(agent, sanitized);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Token Budget Limits
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// Always set a token budget to prevent runaway costs
|
|
239
|
+
const orchestrator = createAgentOrchestrator({
|
|
240
|
+
runner,
|
|
241
|
+
maxTokenBudget: 100000,
|
|
242
|
+
budgetWarningThreshold: 0.8,
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Tool Approval Workflows
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { createToolGuardrail } from "@directive-run/ai";
|
|
250
|
+
|
|
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
|
|
255
|
+
});
|
|
256
|
+
|
|
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
|
+
},
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Output Sanitization
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Always validate agent output before using it
|
|
271
|
+
const orchestrator = createAgentOrchestrator({
|
|
272
|
+
runner,
|
|
273
|
+
guardrails: {
|
|
274
|
+
output: [
|
|
275
|
+
createOutputSchemaGuardrail({ schema: expectedSchema, retries: 2 }),
|
|
276
|
+
createContentFilterGuardrail({ patterns: [/eval\(/, /<script/i], action: "block" }),
|
|
277
|
+
createPIIGuardrail({ redact: true }),
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
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 |
|