@directive-run/ai 0.1.1

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.
@@ -0,0 +1,4663 @@
1
+ import { Requirement, ModuleSchema, Plugin, System } from '@directive-run/core';
2
+ import { CircuitState, ObservabilityInstance, TraceSpan, AggregatedMetric, CircuitBreakerConfig, CircuitBreaker, AlertConfig } from '@directive-run/core/plugins';
3
+ export { AggregatedMetric, AlertConfig, AlertEvent, CircuitBreaker, CircuitBreakerConfig, CircuitBreakerOpenError, CircuitBreakerStats, CircuitState, DashboardData, MetricDataPoint, MetricType, OTLPExporter, OTLPExporterConfig, ObservabilityConfig, ObservabilityInstance, TraceSpan, createAgentMetrics, createCircuitBreaker, createOTLPExporter, createObservability } from '@directive-run/core/plugins';
4
+ import { M as Message$1, g as RunResult, b as AgentLike, d as GuardrailFn, O as OutputGuardrailData, I as InputGuardrailData, S as SchemaValidator, T as ToolCallGuardrailData, f as AdapterHooks, c as AgentRunner, h as ApprovalState, i as AgentState, j as OrchestratorState, k as OrchestratorConstraint, R as RunOptions, N as NamedGuardrail, l as OrchestratorResolver, A as ApprovalRequest, m as AgentRetryConfig, n as OrchestratorLifecycleHooks, o as GuardrailsConfig } from './types-BKCdgKC-.js';
5
+ export { e as GuardrailContext, p as GuardrailError, q as GuardrailErrorCode, G as GuardrailResult, r as GuardrailRetryConfig, s as OrchestratorResolverContext, t as RejectedRequest, u as SchemaValidationResult, v as TokenUsage, a as ToolCall, w as isGuardrailError } from './types-BKCdgKC-.js';
6
+
7
+ /**
8
+ * Agent Memory System
9
+ *
10
+ * Provides sliding window message management and automatic summarization
11
+ * for long-running agent conversations.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { createAgentMemory, createSlidingWindowStrategy } from '@directive-run/ai';
16
+ *
17
+ * const memory = createAgentMemory({
18
+ * strategy: createSlidingWindowStrategy({ maxMessages: 50 }),
19
+ * summarizer: async (messages) => {
20
+ * // Call LLM to summarize older messages
21
+ * return await summarizeWithLLM(messages);
22
+ * },
23
+ * });
24
+ *
25
+ * // Use with orchestrator
26
+ * const orchestrator = createAgentOrchestrator({
27
+ * memory,
28
+ * runner: run,
29
+ * });
30
+ * ```
31
+ */
32
+ /**
33
+ * Memory-compatible message type.
34
+ * Extends the standard Message type to include system messages for summaries.
35
+ */
36
+ interface MemoryMessage {
37
+ role: "user" | "assistant" | "tool" | "system";
38
+ content: string;
39
+ toolCallId?: string;
40
+ }
41
+ type Message = MemoryMessage;
42
+ /** Configuration for memory management strategies */
43
+ interface MemoryStrategyConfig {
44
+ /** Maximum number of messages to keep in active memory */
45
+ maxMessages?: number;
46
+ /** Maximum total tokens to keep in active memory */
47
+ maxTokens?: number;
48
+ /** Number of recent messages to always keep (protected from summarization) */
49
+ preserveRecentCount?: number;
50
+ /** Whether to include system messages in token count */
51
+ countSystemMessages?: boolean;
52
+ }
53
+ /** Result of a memory strategy evaluation */
54
+ interface MemoryStrategyResult {
55
+ /** Messages to keep in active memory */
56
+ keep: Message[];
57
+ /** Messages to summarize or discard */
58
+ toSummarize: Message[];
59
+ /** Estimated token count of kept messages */
60
+ estimatedTokens: number;
61
+ }
62
+ /** Memory management strategy function */
63
+ type MemoryStrategy = (messages: Message[], config: MemoryStrategyConfig) => MemoryStrategyResult;
64
+ /** Summarizer function to compress older messages */
65
+ type MessageSummarizer = (messages: Message[]) => Promise<string>;
66
+ /** Agent memory configuration */
67
+ interface AgentMemoryConfig {
68
+ /** Memory management strategy */
69
+ strategy: MemoryStrategy;
70
+ /** Optional summarizer for compressing old messages */
71
+ summarizer?: MessageSummarizer;
72
+ /** Strategy configuration */
73
+ strategyConfig?: MemoryStrategyConfig;
74
+ /** Whether to auto-manage memory after each interaction */
75
+ autoManage?: boolean;
76
+ /** Callback when memory is managed */
77
+ onMemoryManaged?: (result: MemoryManageResult) => void;
78
+ /** Callback when auto-manage encounters an error */
79
+ onManageError?: (error: Error) => void;
80
+ /** Maximum context window tokens (triggers additional summarization if exceeded) */
81
+ maxContextTokens?: number;
82
+ }
83
+ /** Result of memory management */
84
+ interface MemoryManageResult {
85
+ /** Number of messages before management */
86
+ messagesBefore: number;
87
+ /** Number of messages after management */
88
+ messagesAfter: number;
89
+ /** Number of messages summarized */
90
+ messagesSummarized: number;
91
+ /** The summary that was generated (if any) */
92
+ summary?: string;
93
+ /** Estimated tokens before */
94
+ estimatedTokensBefore: number;
95
+ /** Estimated tokens after */
96
+ estimatedTokensAfter: number;
97
+ }
98
+ /** Memory state for a conversation */
99
+ interface MemoryState {
100
+ /** Active messages in memory */
101
+ messages: Message[];
102
+ /** Summaries of older messages */
103
+ summaries: Array<{
104
+ content: string;
105
+ messagesCount: number;
106
+ createdAt: number;
107
+ }>;
108
+ /** Total messages ever processed */
109
+ totalMessagesProcessed: number;
110
+ /** Estimated current token count */
111
+ estimatedTokens: number;
112
+ }
113
+ /** Agent memory instance */
114
+ interface AgentMemory {
115
+ /** Get current memory state */
116
+ getState(): MemoryState;
117
+ /** Add a message to memory */
118
+ addMessage(message: Message): void;
119
+ /** Check if memory management is currently in progress */
120
+ isManaging(): boolean;
121
+ /** Add multiple messages to memory */
122
+ addMessages(messages: Message[]): void;
123
+ /** Get messages for context (includes summaries as system messages) */
124
+ getContextMessages(): Message[];
125
+ /** Manually trigger memory management */
126
+ manage(): Promise<MemoryManageResult>;
127
+ /** Clear all memory */
128
+ clear(): void;
129
+ /** Export memory state for persistence */
130
+ export(): MemoryState;
131
+ /** Import memory state from persistence */
132
+ import(state: MemoryState): void;
133
+ }
134
+ /**
135
+ * Create a sliding window memory strategy.
136
+ *
137
+ * Keeps the most recent N messages, moving older ones to summarization.
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const strategy = createSlidingWindowStrategy({
142
+ * maxMessages: 50,
143
+ * preserveRecentCount: 10,
144
+ * });
145
+ * ```
146
+ */
147
+ declare function createSlidingWindowStrategy(defaultConfig?: MemoryStrategyConfig): MemoryStrategy;
148
+ /**
149
+ * Create a token-based memory strategy.
150
+ *
151
+ * Keeps messages until a token limit is reached, then moves older ones to summarization.
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const strategy = createTokenBasedStrategy({
156
+ * maxTokens: 4000,
157
+ * preserveRecentCount: 5,
158
+ * });
159
+ * ```
160
+ */
161
+ declare function createTokenBasedStrategy(defaultConfig?: MemoryStrategyConfig): MemoryStrategy;
162
+ /**
163
+ * Create a hybrid strategy that combines message count and token limits.
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const strategy = createHybridStrategy({
168
+ * maxMessages: 50,
169
+ * maxTokens: 4000,
170
+ * preserveRecentCount: 5,
171
+ * });
172
+ * ```
173
+ */
174
+ declare function createHybridStrategy(defaultConfig?: MemoryStrategyConfig): MemoryStrategy;
175
+ /**
176
+ * Create an agent memory instance.
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const memory = createAgentMemory({
181
+ * strategy: createSlidingWindowStrategy({ maxMessages: 50 }),
182
+ * summarizer: async (messages) => {
183
+ * const response = await openai.chat.completions.create({
184
+ * model: 'gpt-4o-mini',
185
+ * messages: [
186
+ * { role: 'system', content: 'Summarize the following conversation concisely.' },
187
+ * ...messages.map(m => ({ role: m.role, content: m.content })),
188
+ * ],
189
+ * });
190
+ * return response.choices[0].message.content;
191
+ * },
192
+ * autoManage: true,
193
+ * });
194
+ * ```
195
+ */
196
+ declare function createAgentMemory(config: AgentMemoryConfig): AgentMemory;
197
+ /**
198
+ * Create a simple truncation "summarizer" that just returns key points.
199
+ * Useful for testing or when LLM summarization isn't needed.
200
+ */
201
+ declare function createTruncationSummarizer(maxLength?: number): MessageSummarizer;
202
+ /**
203
+ * Create a summarizer that extracts only user questions and key assistant answers.
204
+ */
205
+ declare function createKeyPointsSummarizer(): MessageSummarizer;
206
+ /**
207
+ * Create a summarizer factory for LLM-based summarization.
208
+ * You provide the LLM call function, this handles the prompt.
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * const summarizer = createLLMSummarizer(async (prompt) => {
213
+ * const response = await openai.chat.completions.create({
214
+ * model: 'gpt-4o-mini',
215
+ * messages: [{ role: 'user', content: prompt }],
216
+ * });
217
+ * return response.choices[0].message.content ?? '';
218
+ * });
219
+ * ```
220
+ */
221
+ declare function createLLMSummarizer(llmCall: (prompt: string) => Promise<string>, options?: {
222
+ maxSummaryLength?: number;
223
+ preserveKeyFacts?: boolean;
224
+ }): MessageSummarizer;
225
+
226
+ /**
227
+ * OpenAI Agents Streaming - Token-by-token streaming with backpressure support
228
+ *
229
+ * Provides async iterators for streaming agent responses with guardrail evaluation
230
+ * on partial output and configurable backpressure handling.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * import { createAgentOrchestrator } from '@directive-run/ai';
235
+ * import { createStreamingRunner } from '@directive-run/ai';
236
+ *
237
+ * const { stream, result } = orchestrator.runStream(agent, input);
238
+ *
239
+ * for await (const chunk of stream) {
240
+ * if (chunk.type === 'token') process.stdout.write(chunk.data);
241
+ * if (chunk.type === 'guardrail_triggered') handleGuardrail(chunk);
242
+ * }
243
+ *
244
+ * const finalResult = await result;
245
+ * ```
246
+ */
247
+
248
+ /** Token chunk from streaming response */
249
+ interface TokenChunk {
250
+ type: "token";
251
+ data: string;
252
+ /** Running total of tokens received */
253
+ tokenCount: number;
254
+ }
255
+ /** Tool execution started */
256
+ interface ToolStartChunk {
257
+ type: "tool_start";
258
+ tool: string;
259
+ toolCallId: string;
260
+ arguments: string;
261
+ }
262
+ /** Tool execution completed */
263
+ interface ToolEndChunk {
264
+ type: "tool_end";
265
+ tool: string;
266
+ toolCallId: string;
267
+ result: string;
268
+ }
269
+ /** Message added to conversation */
270
+ interface MessageChunk {
271
+ type: "message";
272
+ message: Message$1;
273
+ }
274
+ /** Guardrail was triggered during streaming */
275
+ interface GuardrailTriggeredChunk {
276
+ type: "guardrail_triggered";
277
+ guardrailName: string;
278
+ reason: string;
279
+ /** Partial output at the time of trigger */
280
+ partialOutput: string;
281
+ /** Whether the stream was stopped */
282
+ stopped: boolean;
283
+ }
284
+ /** Progress update for UI feedback */
285
+ interface ProgressChunk {
286
+ type: "progress";
287
+ phase: "starting" | "generating" | "tool_calling" | "finishing";
288
+ /** Percentage complete (0-100), if known */
289
+ percent?: number;
290
+ /** Human-readable status message */
291
+ message?: string;
292
+ }
293
+ /** Stream completed */
294
+ interface DoneChunk {
295
+ type: "done";
296
+ totalTokens: number;
297
+ duration: number;
298
+ /** Number of tokens dropped due to backpressure (only with 'drop' strategy) */
299
+ droppedTokens: number;
300
+ }
301
+ /** Error during streaming */
302
+ interface ErrorChunk {
303
+ type: "error";
304
+ error: Error;
305
+ /** Partial output before error */
306
+ partialOutput?: string;
307
+ }
308
+ /** Union of all stream chunk types */
309
+ type StreamChunk = TokenChunk | ToolStartChunk | ToolEndChunk | MessageChunk | GuardrailTriggeredChunk | ProgressChunk | DoneChunk | ErrorChunk;
310
+ /** Backpressure strategy when consumer is slow */
311
+ type BackpressureStrategy =
312
+ /** Drop tokens when buffer is full (lossy, fast) */
313
+ "drop"
314
+ /** Block producer when buffer is full (lossless, may slow response) */
315
+ | "block"
316
+ /** Buffer all tokens (lossless, uses memory) */
317
+ | "buffer";
318
+ /** Streaming run options */
319
+ interface StreamRunOptions {
320
+ /** Maximum turns before stopping */
321
+ maxTurns?: number;
322
+ /** Abort signal for cancellation */
323
+ signal?: AbortSignal;
324
+ /** Backpressure strategy (default: 'buffer') */
325
+ backpressure?: BackpressureStrategy;
326
+ /** Buffer size for 'drop' and 'block' strategies */
327
+ bufferSize?: number;
328
+ /** Evaluate guardrails every N tokens (default: 50) */
329
+ guardrailCheckInterval?: number;
330
+ /** Stop stream on guardrail trigger (default: true for critical) */
331
+ stopOnGuardrail?: boolean | ((chunk: GuardrailTriggeredChunk) => boolean);
332
+ }
333
+ /** Stream run function type (mirrors OpenAI Agents streaming API) */
334
+ type StreamRunner = <T = unknown>(agent: AgentLike, input: string, options?: StreamRunOptions) => StreamingRunResult<T>;
335
+ /** Result from a streaming run */
336
+ interface StreamingRunResult<T = unknown> {
337
+ /** Async iterator for streaming chunks */
338
+ stream: AsyncIterable<StreamChunk>;
339
+ /** Promise that resolves to the final result */
340
+ result: Promise<RunResult<T>>;
341
+ /** Abort the stream */
342
+ abort: () => void;
343
+ }
344
+ /** Streaming guardrail that evaluates partial output */
345
+ interface StreamingGuardrail {
346
+ /** Unique name for this guardrail */
347
+ name: string;
348
+ /** Check partial output (called every guardrailCheckInterval tokens) */
349
+ check: (partialOutput: string, tokenCount: number) => StreamingGuardrailResult | Promise<StreamingGuardrailResult>;
350
+ /** Whether to stop the stream on failure (default: true) */
351
+ stopOnFail?: boolean;
352
+ }
353
+ /** Result from a streaming guardrail check */
354
+ interface StreamingGuardrailResult {
355
+ passed: boolean;
356
+ reason?: string;
357
+ /** Severity level for UI display */
358
+ severity?: "warning" | "error" | "critical";
359
+ /** Warning message (guardrail passed but wants to emit a warning) */
360
+ warning?: string;
361
+ }
362
+ /**
363
+ * Create a streaming runner that wraps a base run function.
364
+ * This is used internally by the orchestrator but can be used standalone.
365
+ *
366
+ * @param baseRunner - The underlying non-streaming runner
367
+ * @param options - Configuration options
368
+ */
369
+ declare function createStreamingRunner(baseRunner: (agent: AgentLike, input: string, callbacks: {
370
+ onToken?: (token: string) => void;
371
+ onToolStart?: (tool: string, id: string, args: string) => void;
372
+ onToolEnd?: (tool: string, id: string, result: string) => void;
373
+ onMessage?: (message: Message$1) => void;
374
+ signal?: AbortSignal;
375
+ }) => Promise<RunResult<unknown>>, options?: {
376
+ streamingGuardrails?: StreamingGuardrail[];
377
+ }): StreamRunner;
378
+ /**
379
+ * Create a streaming guardrail that detects toxic content.
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * const toxicityGuardrail = createToxicityStreamingGuardrail({
384
+ * threshold: 0.9,
385
+ * checkFn: async (text) => myToxicityModel.score(text),
386
+ * });
387
+ * ```
388
+ */
389
+ declare function createToxicityStreamingGuardrail(options: {
390
+ /** Toxicity scoring function (returns 0-1) */
391
+ checkFn: (text: string) => number | Promise<number>;
392
+ /** Threshold above which content is flagged (default: 0.8) */
393
+ threshold?: number;
394
+ /** Stop the stream on detection (default: true) */
395
+ stopOnFail?: boolean;
396
+ }): StreamingGuardrail;
397
+ /**
398
+ * Create a streaming guardrail that limits output length.
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * const lengthGuardrail = createLengthStreamingGuardrail({
403
+ * maxTokens: 4000,
404
+ * warnAt: 3500,
405
+ * });
406
+ * ```
407
+ */
408
+ declare function createLengthStreamingGuardrail(options: {
409
+ /** Maximum tokens before stopping */
410
+ maxTokens: number;
411
+ /** Warn at this token count (optional) */
412
+ warnAt?: number;
413
+ /** Stop the stream on max (default: true) */
414
+ stopOnFail?: boolean;
415
+ }): StreamingGuardrail;
416
+ /**
417
+ * Create a streaming guardrail that detects patterns (regex-based).
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * const piiGuardrail = createPatternStreamingGuardrail({
422
+ * patterns: [
423
+ * { regex: /\b\d{3}-\d{2}-\d{4}\b/, name: 'SSN' },
424
+ * { regex: /\b\d{16}\b/, name: 'Credit Card' },
425
+ * ],
426
+ * stopOnFail: true,
427
+ * });
428
+ * ```
429
+ */
430
+ declare function createPatternStreamingGuardrail(options: {
431
+ patterns: Array<{
432
+ regex: RegExp;
433
+ name: string;
434
+ }>;
435
+ stopOnFail?: boolean;
436
+ }): StreamingGuardrail;
437
+ /**
438
+ * Combine multiple streaming guardrails into one.
439
+ *
440
+ * @example
441
+ * ```typescript
442
+ * const combined = combineStreamingGuardrails([
443
+ * createToxicityStreamingGuardrail({ ... }),
444
+ * createLengthStreamingGuardrail({ ... }),
445
+ * ]);
446
+ * ```
447
+ */
448
+ declare function combineStreamingGuardrails(guardrails: StreamingGuardrail[], options?: {
449
+ name?: string;
450
+ stopOnFirstFail?: boolean;
451
+ }): StreamingGuardrail;
452
+ /**
453
+ * Convert a regular output guardrail to a streaming guardrail.
454
+ * Useful for reusing existing guardrails in streaming context.
455
+ *
456
+ * @example
457
+ * ```typescript
458
+ * const streamingPII = adaptOutputGuardrail(
459
+ * "pii-streaming",
460
+ * createPIIGuardrail({ redact: false }),
461
+ * { checkInterval: 100 }
462
+ * );
463
+ * ```
464
+ */
465
+ declare function adaptOutputGuardrail(name: string, guardrail: GuardrailFn<OutputGuardrailData>, options?: {
466
+ /** Only run after this many tokens (optimization) */
467
+ minTokens?: number;
468
+ stopOnFail?: boolean;
469
+ }): StreamingGuardrail;
470
+ /**
471
+ * Collect all tokens from a stream into a string.
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * const { stream, result } = orchestrator.runStream(agent, input);
476
+ * const fullOutput = await collectTokens(stream);
477
+ * ```
478
+ */
479
+ declare function collectTokens(stream: AsyncIterable<StreamChunk>): Promise<string>;
480
+ /**
481
+ * Tap into a stream without consuming it.
482
+ * Useful for logging or side effects.
483
+ *
484
+ * @example
485
+ * ```typescript
486
+ * const { stream } = orchestrator.runStream(agent, input);
487
+ * const tapped = tapStream(stream, (chunk) => console.log(chunk));
488
+ * for await (const chunk of tapped) { ... }
489
+ * ```
490
+ */
491
+ declare function tapStream(stream: AsyncIterable<StreamChunk>, fn: (chunk: StreamChunk) => void | Promise<void>): AsyncIterable<StreamChunk>;
492
+ /**
493
+ * Filter stream chunks by type.
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * const tokensOnly = filterStream(stream, ['token']);
498
+ * ```
499
+ */
500
+ declare function filterStream<T extends StreamChunk["type"]>(stream: AsyncIterable<StreamChunk>, types: T[]): AsyncIterable<Extract<StreamChunk, {
501
+ type: T;
502
+ }>>;
503
+ /**
504
+ * Transform stream chunks.
505
+ *
506
+ * @example
507
+ * ```typescript
508
+ * const upperTokens = mapStream(stream, (chunk) => {
509
+ * if (chunk.type === 'token') return { ...chunk, data: chunk.data.toUpperCase() };
510
+ * return chunk;
511
+ * });
512
+ * ```
513
+ */
514
+ declare function mapStream<R>(stream: AsyncIterable<StreamChunk>, fn: (chunk: StreamChunk) => R | Promise<R>): AsyncIterable<R>;
515
+
516
+ /**
517
+ * Built-in guardrails for AI adapter — PII, moderation, rate limiting, tool allowlists, schema validation.
518
+ */
519
+
520
+ /**
521
+ * Create a PII detection guardrail.
522
+ *
523
+ * @example
524
+ * ```typescript
525
+ * const piiGuardrail = createPIIGuardrail({
526
+ * patterns: [
527
+ * /\b\d{3}-\d{2}-\d{4}\b/, // SSN
528
+ * /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i, // Email
529
+ * ],
530
+ * redact: true,
531
+ * });
532
+ * ```
533
+ */
534
+ declare function createPIIGuardrail(options: {
535
+ patterns?: RegExp[];
536
+ redact?: boolean;
537
+ redactReplacement?: string;
538
+ }): GuardrailFn<InputGuardrailData>;
539
+ /**
540
+ * Create a content moderation guardrail.
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * const moderationGuardrail = createModerationGuardrail({
545
+ * checkFn: async (text) => {
546
+ * const result = await openai.moderations.create({ input: text });
547
+ * return result.results[0].flagged;
548
+ * },
549
+ * });
550
+ * ```
551
+ */
552
+ declare function createModerationGuardrail(options: {
553
+ checkFn: (text: string) => boolean | Promise<boolean>;
554
+ message?: string;
555
+ }): GuardrailFn<InputGuardrailData | OutputGuardrailData>;
556
+ /** Rate limiter with reset capability for testing */
557
+ interface RateLimitGuardrail extends GuardrailFn<InputGuardrailData> {
558
+ reset(): void;
559
+ }
560
+ /**
561
+ * Create a rate limit guardrail based on token usage.
562
+ * Returns a guardrail function with an additional `reset()` method for testing.
563
+ */
564
+ declare function createRateLimitGuardrail(options: {
565
+ maxTokensPerMinute?: number;
566
+ maxRequestsPerMinute?: number;
567
+ }): RateLimitGuardrail;
568
+ /**
569
+ * Create a tool allowlist/denylist guardrail.
570
+ */
571
+ declare function createToolGuardrail(options: {
572
+ allowlist?: string[];
573
+ denylist?: string[];
574
+ /** @default false */
575
+ caseSensitive?: boolean;
576
+ }): GuardrailFn<ToolCallGuardrailData>;
577
+ /**
578
+ * Create an output schema validation guardrail.
579
+ */
580
+ declare function createOutputSchemaGuardrail<T = unknown>(options: {
581
+ validate: SchemaValidator<T>;
582
+ errorPrefix?: string;
583
+ }): GuardrailFn<OutputGuardrailData>;
584
+ /**
585
+ * Create a simple type check guardrail for common output types.
586
+ */
587
+ declare function createOutputTypeGuardrail(options: {
588
+ type: "string" | "number" | "boolean" | "object" | "array";
589
+ requiredFields?: string[];
590
+ minLength?: number;
591
+ maxLength?: number;
592
+ minStringLength?: number;
593
+ maxStringLength?: number;
594
+ }): GuardrailFn<OutputGuardrailData>;
595
+ /**
596
+ * Create a length guardrail that limits output size.
597
+ *
598
+ * @example
599
+ * ```typescript
600
+ * const lengthGuardrail = createLengthGuardrail({
601
+ * maxCharacters: 5000,
602
+ * });
603
+ * ```
604
+ */
605
+ declare function createLengthGuardrail(options: {
606
+ /** Maximum characters in output */
607
+ maxCharacters?: number;
608
+ /** Maximum estimated tokens in output */
609
+ maxTokens?: number;
610
+ /** Custom token estimator (default: chars / 4) */
611
+ estimateTokens?: (text: string) => number;
612
+ }): GuardrailFn<OutputGuardrailData>;
613
+ /**
614
+ * Create a content filter guardrail that blocks output matching specific patterns.
615
+ *
616
+ * @example
617
+ * ```typescript
618
+ * const contentFilter = createContentFilterGuardrail({
619
+ * blockedPatterns: [
620
+ * /\bpassword\b/i,
621
+ * /\bsecret\b/i,
622
+ * 'internal-only',
623
+ * ],
624
+ * });
625
+ * ```
626
+ */
627
+ declare function createContentFilterGuardrail(options: {
628
+ /** Patterns to block — strings or RegExp */
629
+ blockedPatterns: Array<string | RegExp>;
630
+ /** Case-sensitive matching for string patterns (default: false) */
631
+ caseSensitive?: boolean;
632
+ }): GuardrailFn<OutputGuardrailData>;
633
+
634
+ /**
635
+ * Helper functions for AI adapter — createRunner, estimateCost, state queries, validation.
636
+ */
637
+
638
+ /** Check if agent is currently running. */
639
+ declare function isAgentRunning(state: AgentState): boolean;
640
+ /** Check if there are pending approvals. */
641
+ declare function hasPendingApprovals(state: ApprovalState): boolean;
642
+ /**
643
+ * Get total cost estimate based on token usage.
644
+ *
645
+ * @param tokenUsage - Total token count
646
+ * @param ratePerMillionTokens - Cost per million tokens (required, no default to avoid stale pricing)
647
+ * @returns Estimated cost in dollars
648
+ */
649
+ declare function estimateCost(tokenUsage: number, ratePerMillionTokens: number): number;
650
+ /**
651
+ * Validate that a baseURL uses http or https.
652
+ * Throws immediately at adapter creation time (not at call time) to catch config errors early.
653
+ */
654
+ declare function validateBaseURL(baseURL: string): void;
655
+ /** Parsed response from an LLM provider */
656
+ interface ParsedResponse {
657
+ text: string;
658
+ totalTokens: number;
659
+ /** Input token count, when available from the provider */
660
+ inputTokens?: number;
661
+ /** Output token count, when available from the provider */
662
+ outputTokens?: number;
663
+ }
664
+ /** Options for creating an AgentRunner from buildRequest/parseResponse */
665
+ interface CreateRunnerOptions {
666
+ fetch?: typeof globalThis.fetch;
667
+ buildRequest: (agent: AgentLike, input: string, messages: Message$1[]) => {
668
+ url: string;
669
+ init: RequestInit;
670
+ };
671
+ parseResponse: (response: Response, messages: Message$1[]) => Promise<ParsedResponse>;
672
+ parseOutput?: <T>(text: string) => T;
673
+ /** Lifecycle hooks for tracing, logging, and metrics */
674
+ hooks?: AdapterHooks;
675
+ }
676
+ /**
677
+ * Create an AgentRunner from buildRequest/parseResponse helpers.
678
+ * Reduces ~50 lines of fetch boilerplate to ~20 lines of configuration.
679
+ *
680
+ * Supports lifecycle hooks for observability:
681
+ * - `onBeforeCall` fires before each API request
682
+ * - `onAfterCall` fires after a successful response (includes token breakdown)
683
+ * - `onError` fires when the request fails
684
+ *
685
+ * @example
686
+ * ```typescript
687
+ * const runClaude = createRunner({
688
+ * buildRequest: (agent, input) => ({
689
+ * url: "/api/claude",
690
+ * init: {
691
+ * method: "POST",
692
+ * headers: { "Content-Type": "application/json" },
693
+ * body: JSON.stringify({
694
+ * model: agent.model ?? "claude-haiku-4-5-20251001",
695
+ * system: agent.instructions ?? "",
696
+ * messages: [{ role: "user", content: input }],
697
+ * }),
698
+ * },
699
+ * }),
700
+ * parseResponse: async (res) => {
701
+ * const data = await res.json();
702
+ * const inputTokens = data.usage?.input_tokens ?? 0;
703
+ * const outputTokens = data.usage?.output_tokens ?? 0;
704
+ * return {
705
+ * text: data.content?.[0]?.text ?? "",
706
+ * totalTokens: inputTokens + outputTokens,
707
+ * inputTokens,
708
+ * outputTokens,
709
+ * };
710
+ * },
711
+ * hooks: {
712
+ * onAfterCall: ({ durationMs, tokenUsage }) => {
713
+ * console.log(`LLM call: ${durationMs}ms, ${tokenUsage.inputTokens}in/${tokenUsage.outputTokens}out`);
714
+ * },
715
+ * },
716
+ * });
717
+ * ```
718
+ */
719
+ declare function createRunner(options: CreateRunnerOptions): AgentRunner;
720
+
721
+ /**
722
+ * Constraint Helper Functions — Ergonomic builders for OrchestratorConstraint
723
+ *
724
+ * @example
725
+ * ```typescript
726
+ * import { constraint, when } from '@directive-run/ai';
727
+ *
728
+ * constraints: {
729
+ * // Builder pattern
730
+ * escalate: constraint<MyFacts>()
731
+ * .when(f => f.confidence < 0.7)
732
+ * .require({ type: 'ESCALATE' })
733
+ * .priority(50)
734
+ * .build(),
735
+ *
736
+ * // Quick shorthand
737
+ * pause: when<MyFacts>(f => f.errors > 3)
738
+ * .require({ type: 'PAUSE' }),
739
+ * }
740
+ * ```
741
+ */
742
+
743
+ interface ConstraintBuilderWithWhen<F extends Record<string, unknown>> {
744
+ require(req: Requirement | ((facts: F & OrchestratorState) => Requirement)): ConstraintBuilderWithRequire<F>;
745
+ }
746
+ interface ConstraintBuilderWithRequire<F extends Record<string, unknown>> {
747
+ priority(p: number): ConstraintBuilderWithRequire<F>;
748
+ build(): OrchestratorConstraint<F>;
749
+ }
750
+ interface ConstraintBuilder<F extends Record<string, unknown>> {
751
+ when(condition: (facts: F & OrchestratorState) => boolean | Promise<boolean>): ConstraintBuilderWithWhen<F>;
752
+ }
753
+ /**
754
+ * Fluent builder for creating orchestrator constraints.
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * const myConstraint = constraint<MyFacts>()
759
+ * .when(f => f.confidence < 0.7)
760
+ * .require({ type: 'ESCALATE' })
761
+ * .priority(50)
762
+ * .build();
763
+ * ```
764
+ */
765
+ declare function constraint<F extends Record<string, unknown> = Record<string, never>>(): ConstraintBuilder<F>;
766
+ interface WhenResult<F extends Record<string, unknown>> {
767
+ require(req: Requirement | ((facts: F & OrchestratorState) => Requirement)): WhenWithRequire<F>;
768
+ }
769
+ /**
770
+ * Result of `when().require()` — a valid `OrchestratorConstraint<F>` directly,
771
+ * or chain `.withPriority(n)` to get a constraint with priority set.
772
+ */
773
+ interface WhenWithRequire<F extends Record<string, unknown>> extends OrchestratorConstraint<F> {
774
+ /** Return a new constraint with the given priority */
775
+ withPriority(p: number): OrchestratorConstraint<F>;
776
+ }
777
+ /**
778
+ * Quick shorthand for creating simple constraints.
779
+ * The returned object is a valid `OrchestratorConstraint<F>` — use directly
780
+ * or chain `.withPriority(n)` to set priority.
781
+ *
782
+ * @example
783
+ * ```typescript
784
+ * const myConstraint = when<MyFacts>(f => f.errors > 3)
785
+ * .require({ type: 'PAUSE' });
786
+ *
787
+ * // With priority
788
+ * const urgent = when<MyFacts>(f => f.critical)
789
+ * .require({ type: 'HALT' })
790
+ * .withPriority(100);
791
+ * ```
792
+ */
793
+ declare function when<F extends Record<string, unknown> = Record<string, never>>(condition: (facts: F & OrchestratorState) => boolean | Promise<boolean>): WhenResult<F>;
794
+
795
+ /**
796
+ * Multi-Agent Orchestration Patterns
797
+ *
798
+ * Provides patterns for coordinating multiple AI agents:
799
+ * - Parallel execution with result merging
800
+ * - Sequential pipelines
801
+ * - Supervisor patterns with worker delegation
802
+ * - Constraint-driven agent selection
803
+ *
804
+ * @example
805
+ * ```typescript
806
+ * import { createMultiAgentOrchestrator } from '@directive-run/ai';
807
+ *
808
+ * const orchestrator = createMultiAgentOrchestrator({
809
+ * agents: {
810
+ * researcher: { agent: researchAgent, maxConcurrent: 3 },
811
+ * writer: { agent: writerAgent, maxConcurrent: 1 },
812
+ * reviewer: { agent: reviewerAgent, maxConcurrent: 1 },
813
+ * },
814
+ * patterns: {
815
+ * parallelResearch: {
816
+ * type: 'parallel',
817
+ * agents: ['researcher', 'researcher', 'researcher'],
818
+ * merge: (results) => combineResearch(results),
819
+ * },
820
+ * },
821
+ * });
822
+ * ```
823
+ */
824
+
825
+ /**
826
+ * Async semaphore for controlling concurrent access.
827
+ * Uses a queue-based approach instead of polling for efficiency.
828
+ *
829
+ * @example
830
+ * ```typescript
831
+ * import { Semaphore } from '@directive-run/ai';
832
+ *
833
+ * const sem = new Semaphore(3); // Allow 3 concurrent operations
834
+ *
835
+ * async function doWork() {
836
+ * const release = await sem.acquire();
837
+ * try {
838
+ * await performWork();
839
+ * } finally {
840
+ * release();
841
+ * }
842
+ * }
843
+ * ```
844
+ */
845
+ declare class Semaphore {
846
+ private count;
847
+ private readonly maxPermits;
848
+ private readonly queue;
849
+ constructor(max: number);
850
+ acquire(): Promise<() => void>;
851
+ private release;
852
+ /** Get current available permits */
853
+ get available(): number;
854
+ /** Get number of waiters in queue */
855
+ get waiting(): number;
856
+ /** Get maximum permits */
857
+ get max(): number;
858
+ /** Reject all pending waiters with an error and reset permits */
859
+ drain(): void;
860
+ }
861
+ /** Configuration for a registered agent */
862
+ interface AgentRegistration {
863
+ /** The agent instance */
864
+ agent: AgentLike;
865
+ /** Maximum concurrent runs for this agent (default: 1) */
866
+ maxConcurrent?: number;
867
+ /** Timeout for agent runs (ms) */
868
+ timeout?: number;
869
+ /** Custom run options */
870
+ runOptions?: Omit<RunOptions, "signal">;
871
+ /** Description for constraint-based selection */
872
+ description?: string;
873
+ /** Capabilities this agent has */
874
+ capabilities?: string[];
875
+ /** Per-agent output guardrails (applied in addition to stack-level guardrails) */
876
+ guardrails?: {
877
+ output?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
878
+ };
879
+ }
880
+ /** Agent registry configuration */
881
+ interface AgentRegistry {
882
+ [agentId: string]: AgentRegistration;
883
+ }
884
+ /** State of a running agent */
885
+ interface AgentRunState {
886
+ agentId: string;
887
+ runId: string;
888
+ status: "pending" | "running" | "completed" | "error" | "cancelled";
889
+ input: string;
890
+ output?: unknown;
891
+ error?: Error;
892
+ startedAt?: number;
893
+ completedAt?: number;
894
+ tokens: number;
895
+ }
896
+ /** Parallel execution pattern - run agents concurrently and merge results */
897
+ interface ParallelPattern<T = unknown> {
898
+ type: "parallel";
899
+ /** Agent IDs to run in parallel (can repeat for multiple instances) */
900
+ agents: string[];
901
+ /** Function to merge results from all agents */
902
+ merge: (results: RunResult<unknown>[]) => T | Promise<T>;
903
+ /** Minimum successful results required (default: all) */
904
+ minSuccess?: number;
905
+ /** Overall timeout (ms) */
906
+ timeout?: number;
907
+ }
908
+ /** Sequential execution pattern - pipeline of agents */
909
+ interface SequentialPattern<T = unknown> {
910
+ type: "sequential";
911
+ /** Agent IDs in execution order */
912
+ agents: string[];
913
+ /** Transform output to next input (default: stringify) */
914
+ transform?: (output: unknown, agentId: string, index: number) => string;
915
+ /** Final result extractor */
916
+ extract?: (output: unknown) => T;
917
+ /** Continue on error (default: false) */
918
+ continueOnError?: boolean;
919
+ }
920
+ /** Supervisor pattern - one agent directs others */
921
+ interface SupervisorPattern<T = unknown> {
922
+ type: "supervisor";
923
+ /** Supervisor agent ID */
924
+ supervisor: string;
925
+ /** Worker agent IDs */
926
+ workers: string[];
927
+ /** Maximum delegation rounds */
928
+ maxRounds?: number;
929
+ /** Extract final result */
930
+ extract?: (supervisorOutput: unknown, workerResults: RunResult<unknown>[]) => T;
931
+ }
932
+ /** Union of all patterns */
933
+ type ExecutionPattern<T = unknown> = ParallelPattern<T> | SequentialPattern<T> | SupervisorPattern<T>;
934
+ /** Handoff request between agents */
935
+ interface HandoffRequest {
936
+ id: string;
937
+ fromAgent: string;
938
+ toAgent: string;
939
+ input: string;
940
+ context?: Record<string, unknown>;
941
+ requestedAt: number;
942
+ }
943
+ /** Handoff result */
944
+ interface HandoffResult {
945
+ request: HandoffRequest;
946
+ result: RunResult<unknown>;
947
+ completedAt: number;
948
+ }
949
+ /** Constraint for agent selection */
950
+ interface AgentSelectionConstraint {
951
+ when: (facts: Record<string, unknown>) => boolean | Promise<boolean>;
952
+ select: string | ((facts: Record<string, unknown>) => string);
953
+ input: string | ((facts: Record<string, unknown>) => string);
954
+ priority?: number;
955
+ }
956
+ /** Run agent requirement */
957
+ interface RunAgentRequirement extends Requirement {
958
+ type: "RUN_AGENT";
959
+ agent: string;
960
+ input: string;
961
+ context?: Record<string, unknown>;
962
+ }
963
+ /** Multi-agent orchestrator options */
964
+ interface MultiAgentOrchestratorOptions {
965
+ /** Base run function */
966
+ runner: AgentRunner;
967
+ /** Registered agents */
968
+ agents: AgentRegistry;
969
+ /** Execution patterns */
970
+ patterns?: Record<string, ExecutionPattern>;
971
+ /** Handoff callbacks */
972
+ onHandoff?: (request: HandoffRequest) => void;
973
+ /** Handoff completion callbacks */
974
+ onHandoffComplete?: (result: HandoffResult) => void;
975
+ /** Maximum number of handoff results to retain (default: 1000) */
976
+ maxHandoffHistory?: number;
977
+ /** Debug mode */
978
+ debug?: boolean;
979
+ }
980
+ /** Multi-agent state in facts */
981
+ interface MultiAgentState {
982
+ /** Namespace for each agent's state */
983
+ __agents: Record<string, {
984
+ status: "idle" | "running" | "completed" | "error";
985
+ lastInput?: string;
986
+ lastOutput?: unknown;
987
+ lastError?: string;
988
+ runCount: number;
989
+ totalTokens: number;
990
+ }>;
991
+ /** Pending handoffs */
992
+ __handoffs: HandoffRequest[];
993
+ /** Completed handoffs */
994
+ __handoffResults: HandoffResult[];
995
+ }
996
+ /** Multi-agent orchestrator instance */
997
+ interface MultiAgentOrchestrator {
998
+ /** Run a single agent */
999
+ runAgent<T>(agentId: string, input: string, options?: RunOptions): Promise<RunResult<T>>;
1000
+ /** Run an execution pattern */
1001
+ runPattern<T>(patternId: string, input: string): Promise<T>;
1002
+ /** Run agents in parallel */
1003
+ runParallel<T>(agentIds: string[], inputs: string | string[], merge: (results: RunResult<unknown>[]) => T | Promise<T>): Promise<T>;
1004
+ /** Run agents sequentially */
1005
+ runSequential<T>(agentIds: string[], initialInput: string, options?: {
1006
+ transform?: (output: unknown, agentId: string, index: number) => string;
1007
+ }): Promise<RunResult<T>[]>;
1008
+ /** Request a handoff between agents */
1009
+ handoff(fromAgent: string, toAgent: string, input: string, context?: Record<string, unknown>): Promise<RunResult<unknown>>;
1010
+ /** Get agent state */
1011
+ getAgentState(agentId: string): MultiAgentState["__agents"][string] | undefined;
1012
+ /** Get all agent states */
1013
+ getAllAgentStates(): Record<string, MultiAgentState["__agents"][string]>;
1014
+ /** Get pending handoffs */
1015
+ getPendingHandoffs(): HandoffRequest[];
1016
+ /** Reset all agent states */
1017
+ reset(): void;
1018
+ /** Dispose of the orchestrator, resetting all state */
1019
+ dispose(): void;
1020
+ }
1021
+ /**
1022
+ * Create a multi-agent orchestrator.
1023
+ *
1024
+ * @example
1025
+ * ```typescript
1026
+ * const orchestrator = createMultiAgentOrchestrator({
1027
+ * runner,
1028
+ * agents: {
1029
+ * researcher: { agent: researchAgent, maxConcurrent: 3 },
1030
+ * writer: { agent: writerAgent },
1031
+ * reviewer: { agent: reviewerAgent },
1032
+ * },
1033
+ * patterns: {
1034
+ * research: {
1035
+ * type: 'parallel',
1036
+ * agents: ['researcher', 'researcher'],
1037
+ * merge: (results) => results.map(r => r.output).join('\n\n'),
1038
+ * },
1039
+ * write: {
1040
+ * type: 'sequential',
1041
+ * agents: ['writer', 'reviewer'],
1042
+ * },
1043
+ * },
1044
+ * });
1045
+ *
1046
+ * // Run pattern
1047
+ * const research = await orchestrator.runPattern('research', 'What is AI?');
1048
+ *
1049
+ * // Run parallel
1050
+ * const results = await orchestrator.runParallel(
1051
+ * ['researcher', 'researcher'],
1052
+ * ['Question 1', 'Question 2'],
1053
+ * (results) => results.map(r => r.output)
1054
+ * );
1055
+ *
1056
+ * // Handoff
1057
+ * const reviewed = await orchestrator.handoff('writer', 'reviewer', draft);
1058
+ * ```
1059
+ *
1060
+ * @throws {Error} If a pattern references an agent that is not in the registry
1061
+ */
1062
+ declare function createMultiAgentOrchestrator(options: MultiAgentOrchestratorOptions): MultiAgentOrchestrator;
1063
+ /**
1064
+ * Create a parallel pattern configuration.
1065
+ *
1066
+ * @example
1067
+ * ```typescript
1068
+ * const researchPattern = parallel(
1069
+ * ['researcher', 'researcher', 'researcher'],
1070
+ * (results) => results.map(r => r.output).join('\n')
1071
+ * );
1072
+ * ```
1073
+ */
1074
+ declare function parallel<T>(agents: string[], merge: (results: RunResult<unknown>[]) => T | Promise<T>, options?: {
1075
+ minSuccess?: number;
1076
+ timeout?: number;
1077
+ }): ParallelPattern<T>;
1078
+ /**
1079
+ * Create a sequential pattern configuration.
1080
+ *
1081
+ * @example
1082
+ * ```typescript
1083
+ * const writeReviewPattern = sequential(
1084
+ * ['writer', 'reviewer'],
1085
+ * { transform: (output) => `Review this: ${output}` }
1086
+ * );
1087
+ * ```
1088
+ */
1089
+ declare function sequential<T>(agents: string[], options?: {
1090
+ transform?: (output: unknown, agentId: string, index: number) => string;
1091
+ extract?: (output: unknown) => T;
1092
+ continueOnError?: boolean;
1093
+ }): SequentialPattern<T>;
1094
+ /**
1095
+ * Create a supervisor pattern configuration.
1096
+ *
1097
+ * @example
1098
+ * ```typescript
1099
+ * const managedPattern = supervisor(
1100
+ * 'manager',
1101
+ * ['worker1', 'worker2'],
1102
+ * { maxRounds: 3 }
1103
+ * );
1104
+ * ```
1105
+ */
1106
+ declare function supervisor<T>(supervisorAgent: string, workers: string[], options?: {
1107
+ maxRounds?: number;
1108
+ extract?: (supervisorOutput: unknown, workerResults: RunResult<unknown>[]) => T;
1109
+ }): SupervisorPattern<T>;
1110
+ /**
1111
+ * Create an agent selection constraint.
1112
+ *
1113
+ * @example
1114
+ * ```typescript
1115
+ * const constraints = {
1116
+ * routeToExpert: selectAgent(
1117
+ * (facts) => facts.complexity > 0.8,
1118
+ * 'expert',
1119
+ * (facts) => facts.query
1120
+ * ),
1121
+ * };
1122
+ * ```
1123
+ */
1124
+ declare function selectAgent(when: (facts: Record<string, unknown>) => boolean | Promise<boolean>, agent: string | ((facts: Record<string, unknown>) => string), input: string | ((facts: Record<string, unknown>) => string), priority?: number): AgentSelectionConstraint;
1125
+ /**
1126
+ * Create a RUN_AGENT requirement.
1127
+ *
1128
+ * @example
1129
+ * ```typescript
1130
+ * constraints: {
1131
+ * needsResearch: {
1132
+ * when: (facts) => facts.hasUnknowns,
1133
+ * require: runAgentRequirement('researcher', facts.query),
1134
+ * },
1135
+ * }
1136
+ * ```
1137
+ */
1138
+ declare function runAgentRequirement(agent: string, input: string, context?: Record<string, unknown>): RunAgentRequirement;
1139
+ /**
1140
+ * Merge results by concatenating outputs.
1141
+ */
1142
+ declare function concatResults(results: RunResult<unknown>[], separator?: string): string;
1143
+ /**
1144
+ * Merge results by picking the best one based on a scoring function.
1145
+ */
1146
+ declare function pickBestResult<T>(results: RunResult<T>[], score: (result: RunResult<T>) => number): RunResult<T>;
1147
+ /**
1148
+ * Merge results into an array of outputs.
1149
+ */
1150
+ declare function collectOutputs<T>(results: RunResult<T>[]): T[];
1151
+ /**
1152
+ * Aggregate token counts from results.
1153
+ */
1154
+ declare function aggregateTokens(results: RunResult<unknown>[]): number;
1155
+
1156
+ /**
1157
+ * Agent-to-Agent Communication Protocol
1158
+ *
1159
+ * Provides structured communication channels between agents for coordination,
1160
+ * delegation, and knowledge sharing without central orchestration.
1161
+ *
1162
+ * @example
1163
+ * ```typescript
1164
+ * import { createAgentNetwork, createMessageBus } from '@directive-run/ai';
1165
+ *
1166
+ * const messageBus = createMessageBus();
1167
+ *
1168
+ * const network = createAgentNetwork({
1169
+ * bus: messageBus,
1170
+ * agents: {
1171
+ * researcher: { capabilities: ['search', 'analyze'] },
1172
+ * writer: { capabilities: ['draft', 'edit'] },
1173
+ * reviewer: { capabilities: ['review', 'approve'] },
1174
+ * },
1175
+ * });
1176
+ *
1177
+ * // Agents can send messages to each other
1178
+ * await network.send('researcher', 'writer', {
1179
+ * type: 'DELEGATION',
1180
+ * task: 'Draft an article based on this research',
1181
+ * context: { findings: [...] },
1182
+ * });
1183
+ * ```
1184
+ */
1185
+ /** Base message structure */
1186
+ interface AgentMessage {
1187
+ id: string;
1188
+ type: AgentMessageType;
1189
+ from: string;
1190
+ to: string | string[] | "*";
1191
+ timestamp: number;
1192
+ correlationId?: string;
1193
+ replyTo?: string;
1194
+ priority?: "low" | "normal" | "high" | "urgent";
1195
+ ttlMs?: number;
1196
+ metadata?: Record<string, unknown>;
1197
+ }
1198
+ /** Message types for agent communication */
1199
+ type AgentMessageType = "REQUEST" | "RESPONSE" | "DELEGATION" | "DELEGATION_RESULT" | "QUERY" | "INFORM" | "SUBSCRIBE" | "UNSUBSCRIBE" | "UPDATE" | "ACK" | "NACK" | "PING" | "PONG" | "CUSTOM";
1200
+ /** Request message */
1201
+ interface RequestMessage extends AgentMessage {
1202
+ type: "REQUEST";
1203
+ action: string;
1204
+ payload: Record<string, unknown>;
1205
+ timeout?: number;
1206
+ }
1207
+ /** Response message */
1208
+ interface ResponseMessage extends AgentMessage {
1209
+ type: "RESPONSE";
1210
+ success: boolean;
1211
+ result?: unknown;
1212
+ error?: string;
1213
+ }
1214
+ /** Delegation message */
1215
+ interface DelegationMessage extends AgentMessage {
1216
+ type: "DELEGATION";
1217
+ task: string;
1218
+ context: Record<string, unknown>;
1219
+ constraints?: {
1220
+ deadline?: number;
1221
+ maxCost?: number;
1222
+ requiredCapabilities?: string[];
1223
+ };
1224
+ }
1225
+ /** Delegation result message */
1226
+ interface DelegationResultMessage extends AgentMessage {
1227
+ type: "DELEGATION_RESULT";
1228
+ success: boolean;
1229
+ result?: unknown;
1230
+ error?: string;
1231
+ metrics?: {
1232
+ durationMs: number;
1233
+ tokensUsed?: number;
1234
+ cost?: number;
1235
+ };
1236
+ }
1237
+ /** Query message */
1238
+ interface QueryMessage extends AgentMessage {
1239
+ type: "QUERY";
1240
+ question: string;
1241
+ context?: Record<string, unknown>;
1242
+ }
1243
+ /** Inform message */
1244
+ interface InformMessage extends AgentMessage {
1245
+ type: "INFORM";
1246
+ topic: string;
1247
+ content: unknown;
1248
+ }
1249
+ /** Subscribe message */
1250
+ interface SubscribeMessage extends AgentMessage {
1251
+ type: "SUBSCRIBE";
1252
+ topics: string[];
1253
+ }
1254
+ /** Update message */
1255
+ interface UpdateMessage extends AgentMessage {
1256
+ type: "UPDATE";
1257
+ topic: string;
1258
+ content: unknown;
1259
+ }
1260
+ /** Union of all message types */
1261
+ type TypedAgentMessage = RequestMessage | ResponseMessage | DelegationMessage | DelegationResultMessage | QueryMessage | InformMessage | SubscribeMessage | UpdateMessage | (AgentMessage & {
1262
+ type: "UNSUBSCRIBE" | "ACK" | "NACK" | "PING" | "PONG" | "CUSTOM";
1263
+ });
1264
+ /** Message handler function */
1265
+ type MessageHandler = (message: TypedAgentMessage) => void | Promise<void>;
1266
+ /** Subscription to messages */
1267
+ interface Subscription {
1268
+ id: string;
1269
+ agentId: string;
1270
+ handler: MessageHandler;
1271
+ filter?: MessageFilter;
1272
+ unsubscribe: () => void;
1273
+ }
1274
+ /** Message filter criteria */
1275
+ interface MessageFilter {
1276
+ types?: AgentMessageType[];
1277
+ from?: string | string[];
1278
+ topics?: string[];
1279
+ priority?: ("low" | "normal" | "high" | "urgent")[];
1280
+ custom?: (message: TypedAgentMessage) => boolean;
1281
+ }
1282
+ /** Message bus configuration */
1283
+ interface MessageBusConfig {
1284
+ /** Maximum messages to retain in history */
1285
+ maxHistory?: number;
1286
+ /** Default TTL for messages */
1287
+ defaultTtlMs?: number;
1288
+ /** Maximum pending messages per offline agent (prevents unbounded queue growth) */
1289
+ maxPendingPerAgent?: number;
1290
+ /** Enable message persistence */
1291
+ persistence?: MessagePersistence;
1292
+ /** Callback when message is delivered */
1293
+ onDelivery?: (message: TypedAgentMessage, recipients: string[]) => void;
1294
+ /** Callback when message delivery fails */
1295
+ onDeliveryError?: (message: TypedAgentMessage, error: Error) => void;
1296
+ }
1297
+ /** Message persistence interface */
1298
+ interface MessagePersistence {
1299
+ save(message: TypedAgentMessage): Promise<void>;
1300
+ load(agentId: string, since?: number): Promise<TypedAgentMessage[]>;
1301
+ delete(messageId: string): Promise<void>;
1302
+ clear(agentId?: string): Promise<void>;
1303
+ }
1304
+ /** Message bus instance */
1305
+ interface MessageBus {
1306
+ /** Publish a message */
1307
+ publish(message: Omit<TypedAgentMessage, "id" | "timestamp">): string;
1308
+ /** Subscribe to messages */
1309
+ subscribe(agentId: string, handler: MessageHandler, filter?: MessageFilter): Subscription;
1310
+ /** Get message history */
1311
+ getHistory(filter?: MessageFilter, limit?: number): TypedAgentMessage[];
1312
+ /** Get a specific message by ID */
1313
+ getMessage(id: string): TypedAgentMessage | undefined;
1314
+ /** Get pending messages for an agent */
1315
+ getPending(agentId: string): TypedAgentMessage[];
1316
+ /** Clear all messages and data */
1317
+ clear(): void;
1318
+ /** Dispose of the message bus, clearing all data and subscriptions */
1319
+ dispose(): void;
1320
+ }
1321
+ /**
1322
+ * Create a message bus for agent communication.
1323
+ *
1324
+ * @example
1325
+ * ```typescript
1326
+ * const bus = createMessageBus({ maxHistory: 1000 });
1327
+ *
1328
+ * // Subscribe to messages
1329
+ * bus.subscribe('writer', (msg) => {
1330
+ * console.log(`Writer received: ${msg.type}`);
1331
+ * });
1332
+ *
1333
+ * // Publish a message
1334
+ * bus.publish({
1335
+ * type: 'DELEGATION',
1336
+ * from: 'researcher',
1337
+ * to: 'writer',
1338
+ * task: 'Write summary',
1339
+ * context: { data: '...' },
1340
+ * });
1341
+ * ```
1342
+ */
1343
+ /**
1344
+ * Note: `publish()` is fire-and-forget -- it returns the message ID synchronously
1345
+ * before delivery completes. Use `onDelivery` / `onDeliveryError` callbacks in
1346
+ * config to track delivery status if needed.
1347
+ */
1348
+ declare function createMessageBus(config?: MessageBusConfig): MessageBus;
1349
+ /** Agent registration info */
1350
+ interface AgentInfo {
1351
+ id: string;
1352
+ capabilities: string[];
1353
+ status: "online" | "offline" | "busy";
1354
+ lastSeen: number;
1355
+ metadata?: Record<string, unknown>;
1356
+ }
1357
+ /** Agent network configuration */
1358
+ interface AgentNetworkConfig {
1359
+ /** Message bus to use */
1360
+ bus: MessageBus;
1361
+ /** Registered agents */
1362
+ agents?: Record<string, Omit<AgentInfo, "id" | "lastSeen" | "status">>;
1363
+ /** Timeout for request-response patterns */
1364
+ defaultTimeout?: number;
1365
+ /** Callback when agent comes online */
1366
+ onAgentOnline?: (agentId: string) => void;
1367
+ /** Callback when agent goes offline */
1368
+ onAgentOffline?: (agentId: string) => void;
1369
+ }
1370
+ /** Agent network instance */
1371
+ interface AgentNetwork {
1372
+ /** Register an agent */
1373
+ register(id: string, info: Omit<AgentInfo, "id" | "lastSeen" | "status">): void;
1374
+ /** Unregister an agent */
1375
+ unregister(id: string): void;
1376
+ /** Get agent info */
1377
+ getAgent(id: string): AgentInfo | undefined;
1378
+ /** Get all agents */
1379
+ getAgents(): AgentInfo[];
1380
+ /** Find agents by capability */
1381
+ findByCapability(capability: string): AgentInfo[];
1382
+ /** Send a message */
1383
+ send(from: string, to: string | string[], message: Partial<TypedAgentMessage>): string;
1384
+ /** Send a request and wait for response */
1385
+ request(from: string, to: string, action: string, payload: Record<string, unknown>, timeout?: number): Promise<ResponseMessage>;
1386
+ /** Delegate a task */
1387
+ delegate(from: string, to: string, task: string, context: Record<string, unknown>): Promise<DelegationResultMessage>;
1388
+ /** Query an agent */
1389
+ query(from: string, to: string, question: string, context?: Record<string, unknown>): Promise<ResponseMessage>;
1390
+ /** Broadcast to all agents */
1391
+ broadcast(from: string, message: Partial<TypedAgentMessage>): string;
1392
+ /** Subscribe an agent to messages */
1393
+ listen(agentId: string, handler: MessageHandler, filter?: MessageFilter): Subscription;
1394
+ /** Get the message bus */
1395
+ getBus(): MessageBus;
1396
+ /** Dispose of the network, clearing pending waiters and timers */
1397
+ dispose(): void;
1398
+ }
1399
+ /**
1400
+ * Create an agent network for coordinated communication.
1401
+ *
1402
+ * @example
1403
+ * ```typescript
1404
+ * const network = createAgentNetwork({
1405
+ * bus: createMessageBus(),
1406
+ * agents: {
1407
+ * researcher: { capabilities: ['search', 'summarize'] },
1408
+ * writer: { capabilities: ['draft', 'edit'] },
1409
+ * reviewer: { capabilities: ['review', 'approve'] },
1410
+ * },
1411
+ * });
1412
+ *
1413
+ * // Delegate a task
1414
+ * const result = await network.delegate(
1415
+ * 'researcher',
1416
+ * 'writer',
1417
+ * 'Write an article about AI safety',
1418
+ * { research: findingsData }
1419
+ * );
1420
+ *
1421
+ * // Query for information
1422
+ * const answer = await network.query(
1423
+ * 'writer',
1424
+ * 'reviewer',
1425
+ * 'Is this paragraph technically accurate?',
1426
+ * { text: '...' }
1427
+ * );
1428
+ * ```
1429
+ */
1430
+ declare function createAgentNetwork(config: AgentNetworkConfig): AgentNetwork;
1431
+ /**
1432
+ * Create a request-response helper for handling incoming requests.
1433
+ *
1434
+ * @example
1435
+ * ```typescript
1436
+ * const responder = createResponder(network, 'writer');
1437
+ *
1438
+ * responder.onRequest('draft', async (payload) => {
1439
+ * const draft = await generateDraft(payload.topic);
1440
+ * return { success: true, result: draft };
1441
+ * });
1442
+ * ```
1443
+ */
1444
+ declare function createResponder(network: AgentNetwork, agentId: string): {
1445
+ onRequest(action: string, handler: (payload: Record<string, unknown>) => Promise<{
1446
+ success: boolean;
1447
+ result?: unknown;
1448
+ error?: string;
1449
+ }>): void;
1450
+ /** Remove a request handler */
1451
+ offRequest(action: string): void;
1452
+ /** Dispose of this responder, unsubscribing from network */
1453
+ dispose(): void;
1454
+ };
1455
+ /**
1456
+ * Create a task delegator for handling incoming delegations.
1457
+ *
1458
+ * @example
1459
+ * ```typescript
1460
+ * const delegator = createDelegator(network, 'writer');
1461
+ *
1462
+ * delegator.onDelegation(async (task, context) => {
1463
+ * const result = await executeTask(task, context);
1464
+ * return {
1465
+ * success: true,
1466
+ * result,
1467
+ * metrics: { durationMs: 1500, tokensUsed: 500 },
1468
+ * };
1469
+ * });
1470
+ * ```
1471
+ */
1472
+ declare function createDelegator(network: AgentNetwork, agentId: string): {
1473
+ onDelegation(handler: (task: string, context: Record<string, unknown>) => Promise<{
1474
+ success: boolean;
1475
+ result?: unknown;
1476
+ error?: string;
1477
+ metrics?: {
1478
+ durationMs: number;
1479
+ tokensUsed?: number;
1480
+ cost?: number;
1481
+ };
1482
+ }>): void;
1483
+ /** Remove the delegation handler */
1484
+ offDelegation(): void;
1485
+ /** Dispose of this delegator, unsubscribing from network */
1486
+ dispose(): void;
1487
+ };
1488
+ /**
1489
+ * Create a pub/sub helper for topic-based communication.
1490
+ *
1491
+ * @example
1492
+ * ```typescript
1493
+ * const pubsub = createPubSub(network, 'analyst');
1494
+ *
1495
+ * // Subscribe to topics
1496
+ * pubsub.subscribe(['market-updates', 'alerts'], (topic, content) => {
1497
+ * console.log(`Received ${topic}:`, content);
1498
+ * });
1499
+ *
1500
+ * // Publish to topics
1501
+ * pubsub.publish('market-updates', { price: 100, change: 5 });
1502
+ * ```
1503
+ */
1504
+ declare function createPubSub(network: AgentNetwork, agentId: string): {
1505
+ subscribe(topics: string[], handler: (topic: string, content: unknown) => void): () => void;
1506
+ publish(topic: string, content: unknown): void;
1507
+ /** Dispose of this pub/sub, unsubscribing from network and clearing handlers */
1508
+ dispose(): void;
1509
+ };
1510
+
1511
+ /**
1512
+ * Enhanced PII Detection Guardrail
1513
+ *
1514
+ * Provides comprehensive PII detection beyond basic regex patterns:
1515
+ * - Multiple PII types (SSN, credit cards, emails, phones, addresses, names)
1516
+ * - Pluggable detection backends (regex, custom, or external services)
1517
+ * - Context-aware detection (reduces false positives)
1518
+ * - Redaction with reversible or irreversible options
1519
+ *
1520
+ * @example
1521
+ * ```typescript
1522
+ * import { createEnhancedPIIGuardrail } from '@directive-run/ai';
1523
+ *
1524
+ * const guardrail = createEnhancedPIIGuardrail({
1525
+ * types: ['ssn', 'credit_card', 'email'],
1526
+ * redact: true,
1527
+ * detector: 'regex', // or 'custom' with custom detector
1528
+ * });
1529
+ * ```
1530
+ */
1531
+
1532
+ /** Supported PII types */
1533
+ type PIIType = "ssn" | "credit_card" | "email" | "phone" | "address" | "name" | "date_of_birth" | "passport" | "driver_license" | "ip_address" | "bank_account" | "medical_id" | "national_id";
1534
+ /** Detected PII instance */
1535
+ interface DetectedPII {
1536
+ type: PIIType;
1537
+ value: string;
1538
+ position: {
1539
+ start: number;
1540
+ end: number;
1541
+ };
1542
+ confidence: number;
1543
+ context?: string;
1544
+ }
1545
+ /** PII detection result */
1546
+ interface PIIDetectionResult {
1547
+ detected: boolean;
1548
+ items: DetectedPII[];
1549
+ typeCounts: Partial<Record<PIIType, number>>;
1550
+ /** Text with PII redacted (if requested) */
1551
+ redactedText?: string;
1552
+ }
1553
+ /** Custom PII detector interface */
1554
+ interface PIIDetector {
1555
+ detect(text: string, types: PIIType[]): Promise<DetectedPII[]>;
1556
+ name: string;
1557
+ }
1558
+ /** Redaction style */
1559
+ type RedactionStyle =
1560
+ /** Replace with [REDACTED] */
1561
+ "placeholder"
1562
+ /** Replace with type-specific placeholder like [EMAIL] */
1563
+ | "typed"
1564
+ /** Replace with asterisks preserving length */
1565
+ | "masked"
1566
+ /** Replace with hash for reversible redaction */
1567
+ | "hashed";
1568
+ /** Redact detected PII from text */
1569
+ declare function redactPII(text: string, items: DetectedPII[], style?: RedactionStyle): string;
1570
+ /** Options for enhanced PII guardrail */
1571
+ interface EnhancedPIIGuardrailOptions {
1572
+ /** PII types to detect (default: all) */
1573
+ types?: PIIType[];
1574
+ /** Detection backend (default: 'regex') */
1575
+ detector?: "regex" | PIIDetector;
1576
+ /** Redact instead of blocking */
1577
+ redact?: boolean;
1578
+ /** Redaction style (default: 'typed') */
1579
+ redactionStyle?: RedactionStyle;
1580
+ /** Minimum confidence to flag (0-1, default: 0.7) */
1581
+ minConfidence?: number;
1582
+ /** Callback when PII is detected */
1583
+ onDetected?: (items: DetectedPII[]) => void;
1584
+ /** Allow specific values (whitelist) */
1585
+ allowlist?: string[];
1586
+ /** Block only if count exceeds threshold */
1587
+ minItemsToBlock?: number;
1588
+ /** Timeout for custom detector in milliseconds (default: 5000) */
1589
+ detectorTimeout?: number;
1590
+ }
1591
+ /**
1592
+ * Create an enhanced PII detection guardrail.
1593
+ *
1594
+ * @example
1595
+ * ```typescript
1596
+ * // Basic usage
1597
+ * const guardrail = createEnhancedPIIGuardrail();
1598
+ *
1599
+ * // Redact instead of blocking
1600
+ * const redactGuardrail = createEnhancedPIIGuardrail({
1601
+ * redact: true,
1602
+ * redactionStyle: 'masked',
1603
+ * });
1604
+ *
1605
+ * // Custom detection with external service
1606
+ * const customGuardrail = createEnhancedPIIGuardrail({
1607
+ * detector: myPresidioDetector,
1608
+ * types: ['ssn', 'credit_card', 'medical_id'],
1609
+ * });
1610
+ * ```
1611
+ */
1612
+ declare function createEnhancedPIIGuardrail(options?: EnhancedPIIGuardrailOptions): GuardrailFn<InputGuardrailData>;
1613
+ /**
1614
+ * Create an output PII guardrail (for checking agent responses).
1615
+ *
1616
+ * @example
1617
+ * ```typescript
1618
+ * const outputGuardrail = createOutputPIIGuardrail({
1619
+ * types: ['ssn', 'credit_card'],
1620
+ * redact: true,
1621
+ * });
1622
+ * ```
1623
+ */
1624
+ declare function createOutputPIIGuardrail(options?: EnhancedPIIGuardrailOptions): GuardrailFn<OutputGuardrailData>;
1625
+ /**
1626
+ * Detect PII in text without using as a guardrail.
1627
+ * Useful for analysis and logging.
1628
+ *
1629
+ * @example
1630
+ * ```typescript
1631
+ * const result = await detectPII('My SSN is 123-45-6789');
1632
+ * console.log(result.items); // [{ type: 'ssn', value: '123-45-6789', ... }]
1633
+ *
1634
+ * // With custom detector and timeout
1635
+ * const result = await detectPII(text, {
1636
+ * detector: myPresidioDetector,
1637
+ * timeout: 10000, // 10 seconds
1638
+ * });
1639
+ * ```
1640
+ */
1641
+ declare function detectPII(text: string, options?: {
1642
+ types?: PIIType[];
1643
+ detector?: "regex" | PIIDetector;
1644
+ minConfidence?: number;
1645
+ /** Timeout for custom detectors in milliseconds (default: 5000) */
1646
+ timeout?: number;
1647
+ }): Promise<PIIDetectionResult>;
1648
+
1649
+ /**
1650
+ * Audit Plugin - Immutable Audit Trail with Hash Chain
1651
+ *
1652
+ * Provides enterprise-grade audit logging with:
1653
+ * - Cryptographic hash chain for tamper detection
1654
+ * - Bounded storage with FIFO eviction
1655
+ * - PII masking with configurable redaction
1656
+ * - Optional signing for non-repudiation
1657
+ * - Async export to external systems
1658
+ *
1659
+ * @example
1660
+ * ```typescript
1661
+ * import { createAuditTrail } from '@directive-run/ai';
1662
+ *
1663
+ * const audit = createAuditTrail({
1664
+ * maxEntries: 10000,
1665
+ * retentionMs: 7 * 24 * 60 * 60 * 1000, // 7 days
1666
+ * piiMasking: {
1667
+ * enabled: true,
1668
+ * types: ['ssn', 'credit_card', 'email'],
1669
+ * redactionStyle: 'typed',
1670
+ * },
1671
+ * exporter: async (entries) => {
1672
+ * await sendToSIEM(entries);
1673
+ * },
1674
+ * });
1675
+ *
1676
+ * const system = createSystem({
1677
+ * module: myModule,
1678
+ * plugins: [audit.createPlugin()],
1679
+ * });
1680
+ * ```
1681
+ */
1682
+
1683
+ /** Audit event types - 17 total covering all system operations */
1684
+ type AuditEventType = "agent.run.start" | "agent.run.complete" | "agent.run.error" | "tool.call.start" | "tool.call.complete" | "tool.call.error" | "approval.requested" | "approval.granted" | "approval.denied" | "requirement.created" | "requirement.met" | "resolver.start" | "resolver.complete" | "resolver.error" | "fact.set" | "fact.batch" | "error.occurred" | "error.recovery";
1685
+ /** Single audit entry with hash chain linking */
1686
+ interface AuditEntry {
1687
+ /** Unique identifier for this entry */
1688
+ id: string;
1689
+ /** Unix timestamp in milliseconds */
1690
+ timestamp: number;
1691
+ /** Type of event */
1692
+ eventType: AuditEventType;
1693
+ /** SHA-256 hash of previous entry (empty string for genesis) */
1694
+ previousHash: string;
1695
+ /** SHA-256 hash of this entry's content */
1696
+ hash: string;
1697
+ /** Event payload data */
1698
+ payload: Record<string, unknown>;
1699
+ /** PII-redacted version of payload (if masking enabled) */
1700
+ maskedPayload?: Record<string, unknown>;
1701
+ /** Actor identifier (user, agent, or system) */
1702
+ actorId?: string;
1703
+ /** Session identifier for correlation */
1704
+ sessionId?: string;
1705
+ /** Cryptographic signature (if signing enabled) */
1706
+ signature?: string;
1707
+ }
1708
+ /** Filter options for querying audit entries */
1709
+ interface AuditEntryFilter {
1710
+ /** Filter by event types */
1711
+ eventTypes?: AuditEventType[];
1712
+ /** Filter by actor ID */
1713
+ actorId?: string;
1714
+ /** Filter by session ID */
1715
+ sessionId?: string;
1716
+ /** Start of time range */
1717
+ since?: number;
1718
+ /** End of time range */
1719
+ until?: number;
1720
+ /** Maximum entries to return */
1721
+ limit?: number;
1722
+ /** Offset for pagination */
1723
+ offset?: number;
1724
+ }
1725
+ /** Result of chain verification */
1726
+ interface AuditVerificationResult {
1727
+ /** Whether the chain is valid */
1728
+ valid: boolean;
1729
+ /** Number of entries verified */
1730
+ entriesVerified: number;
1731
+ /** First broken link (if any) */
1732
+ brokenAt?: {
1733
+ index: number;
1734
+ entryId: string;
1735
+ expectedHash: string;
1736
+ actualHash: string;
1737
+ };
1738
+ /** Verification timestamp */
1739
+ verifiedAt: number;
1740
+ }
1741
+ /** Audit statistics */
1742
+ interface AuditStats {
1743
+ /** Total entries in trail */
1744
+ totalEntries: number;
1745
+ /** Entries by event type */
1746
+ byEventType: Partial<Record<AuditEventType, number>>;
1747
+ /** Oldest entry timestamp */
1748
+ oldestEntry?: number;
1749
+ /** Newest entry timestamp */
1750
+ newestEntry?: number;
1751
+ /** Number of entries pruned */
1752
+ entriesPruned: number;
1753
+ /** Number of entries exported */
1754
+ entriesExported: number;
1755
+ /** Chain integrity (true if verified valid) */
1756
+ chainIntegrity: boolean;
1757
+ }
1758
+ /** PII masking configuration */
1759
+ interface PIIMaskingConfig {
1760
+ /** Enable PII masking */
1761
+ enabled: boolean;
1762
+ /** PII types to detect and mask */
1763
+ types: PIIType[];
1764
+ /** Redaction style */
1765
+ redactionStyle: RedactionStyle;
1766
+ /** Custom allowlist (values to skip) */
1767
+ allowlist?: string[];
1768
+ /** Minimum confidence threshold */
1769
+ minConfidence?: number;
1770
+ }
1771
+ /** Signing configuration for non-repudiation */
1772
+ interface SigningConfig {
1773
+ /** Function to sign a hash value */
1774
+ signFn: (hash: string) => Promise<string>;
1775
+ /** Function to verify a signature */
1776
+ verifyFn?: (hash: string, signature: string) => Promise<boolean>;
1777
+ }
1778
+ /** Audit plugin configuration */
1779
+ interface AuditPluginConfig {
1780
+ /** Maximum entries to retain (default: 10000) */
1781
+ maxEntries?: number;
1782
+ /** Retention period in milliseconds (default: 7 days) */
1783
+ retentionMs?: number;
1784
+ /** Export interval in milliseconds (default: 60000) */
1785
+ exportInterval?: number;
1786
+ /** Async exporter function */
1787
+ exporter?: (entries: AuditEntry[]) => Promise<void>;
1788
+ /** PII masking configuration */
1789
+ piiMasking?: PIIMaskingConfig;
1790
+ /** Signing configuration for non-repudiation */
1791
+ signing?: SigningConfig;
1792
+ /** Session ID for all entries */
1793
+ sessionId?: string;
1794
+ /** Actor ID for all entries */
1795
+ actorId?: string;
1796
+ /** Event callbacks */
1797
+ events?: {
1798
+ onEntryAdded?: (entry: AuditEntry) => void;
1799
+ onChainBroken?: (result: AuditVerificationResult) => void;
1800
+ onExportError?: (error: Error, entries: AuditEntry[]) => void;
1801
+ };
1802
+ }
1803
+ /** Audit trail instance */
1804
+ interface AuditInstance {
1805
+ /** Get entries with optional filtering */
1806
+ getEntries(filter?: AuditEntryFilter): AuditEntry[];
1807
+ /** Verify the integrity of the hash chain */
1808
+ verifyChain(): Promise<AuditVerificationResult>;
1809
+ /** Export entries since timestamp */
1810
+ export(since?: number): Promise<AuditEntry[]>;
1811
+ /** Prune old entries based on retention policy */
1812
+ prune(): number;
1813
+ /** Get audit statistics */
1814
+ getStats(): AuditStats;
1815
+ /** Dispose of the instance (clears timers, flushes exports) */
1816
+ dispose(): Promise<void>;
1817
+ /** Create a plugin for a directive system */
1818
+ createPlugin<M extends ModuleSchema>(): Plugin<M>;
1819
+ /** Add a custom audit entry */
1820
+ addEntry(eventType: AuditEventType, payload: Record<string, unknown>): Promise<AuditEntry>;
1821
+ }
1822
+ /**
1823
+ * Create an audit trail instance for enterprise-grade audit logging.
1824
+ *
1825
+ * Features:
1826
+ * - Immutable hash chain for tamper detection
1827
+ * - Bounded storage with automatic FIFO eviction
1828
+ * - PII masking with configurable redaction styles
1829
+ * - Optional cryptographic signing for non-repudiation
1830
+ * - Async export to external SIEM/logging systems
1831
+ *
1832
+ * @example
1833
+ * ```typescript
1834
+ * const audit = createAuditTrail({
1835
+ * maxEntries: 10000,
1836
+ * piiMasking: {
1837
+ * enabled: true,
1838
+ * types: ['ssn', 'credit_card'],
1839
+ * redactionStyle: 'typed',
1840
+ * },
1841
+ * exporter: async (entries) => {
1842
+ * await fetch('/api/audit', {
1843
+ * method: 'POST',
1844
+ * body: JSON.stringify(entries),
1845
+ * });
1846
+ * },
1847
+ * });
1848
+ *
1849
+ * // Use with directive system
1850
+ * const system = createSystem({
1851
+ * module: myModule,
1852
+ * plugins: [audit.createPlugin()],
1853
+ * });
1854
+ *
1855
+ * // Query audit entries
1856
+ * const recentErrors = audit.getEntries({
1857
+ * eventTypes: ['error.occurred', 'error.recovery'],
1858
+ * since: Date.now() - 3600000, // Last hour
1859
+ * });
1860
+ *
1861
+ * // Verify chain integrity
1862
+ * const verification = await audit.verifyChain();
1863
+ * if (!verification.valid) {
1864
+ * console.error('Audit chain tampered!', verification.brokenAt);
1865
+ * }
1866
+ * ```
1867
+ */
1868
+ declare function createAuditTrail(config?: AuditPluginConfig): AuditInstance;
1869
+ /**
1870
+ * Create audit event handlers for agent orchestrator integration.
1871
+ * Use this to audit agent operations when using the agent orchestrator.
1872
+ *
1873
+ * @example
1874
+ * ```typescript
1875
+ * const audit = createAuditTrail({ ... });
1876
+ * const handlers = createAgentAuditHandlers(audit);
1877
+ *
1878
+ * // Use in orchestrator callbacks
1879
+ * orchestrator.run(agent, input, {
1880
+ * onStart: handlers.onAgentStart,
1881
+ * onComplete: handlers.onAgentComplete,
1882
+ * // ...
1883
+ * });
1884
+ * ```
1885
+ */
1886
+ declare function createAgentAuditHandlers(audit: AuditInstance): {
1887
+ onAgentStart: (agentName: string, input: string) => void;
1888
+ onAgentComplete: (agentName: string, output: unknown, tokens: number, cost: number) => void;
1889
+ onAgentError: (agentName: string, error: Error) => void;
1890
+ onToolStart: (toolName: string, toolCallId: string, args: unknown) => void;
1891
+ onToolComplete: (toolName: string, toolCallId: string, result: unknown) => void;
1892
+ onToolError: (toolName: string, toolCallId: string, error: Error) => void;
1893
+ onApprovalRequested: (toolName: string, toolCallId: string, args: unknown) => void;
1894
+ onApprovalGranted: (toolName: string, toolCallId: string) => void;
1895
+ onApprovalDenied: (toolName: string, toolCallId: string, reason?: string) => void;
1896
+ };
1897
+
1898
+ /**
1899
+ * Prompt Injection Detection Guardrail
1900
+ *
1901
+ * Detects and blocks prompt injection attacks including:
1902
+ * - Direct injection attempts ("ignore previous instructions")
1903
+ * - Jailbreak patterns ("DAN mode", "pretend you can")
1904
+ * - Indirect injection via external content
1905
+ * - Encoding-based evasion attempts
1906
+ *
1907
+ * @example
1908
+ * ```typescript
1909
+ * import { createPromptInjectionGuardrail } from '@directive-run/ai';
1910
+ *
1911
+ * const guardrail = createPromptInjectionGuardrail({
1912
+ * strictMode: true,
1913
+ * onBlocked: (input, patterns) => logSecurityEvent(input, patterns),
1914
+ * });
1915
+ * ```
1916
+ */
1917
+
1918
+ /** Pattern with metadata for better debugging */
1919
+ interface InjectionPattern {
1920
+ pattern: RegExp;
1921
+ name: string;
1922
+ severity: "low" | "medium" | "high" | "critical";
1923
+ category: InjectionCategory;
1924
+ }
1925
+ /** Categories of injection attacks */
1926
+ type InjectionCategory = "instruction_override" | "jailbreak" | "role_manipulation" | "encoding_evasion" | "delimiter_injection" | "context_manipulation" | "indirect_injection";
1927
+ /** Default injection patterns - well-tested and low false-positive rate */
1928
+ declare const DEFAULT_INJECTION_PATTERNS: InjectionPattern[];
1929
+ /** Strict patterns - more aggressive, may have higher false positives */
1930
+ declare const STRICT_INJECTION_PATTERNS: InjectionPattern[];
1931
+ /** Detailed detection result */
1932
+ interface InjectionDetectionResult {
1933
+ detected: boolean;
1934
+ patterns: Array<{
1935
+ name: string;
1936
+ category: InjectionCategory;
1937
+ severity: InjectionPattern["severity"];
1938
+ match: string;
1939
+ position: number;
1940
+ }>;
1941
+ riskScore: number;
1942
+ sanitizedInput?: string;
1943
+ }
1944
+ /**
1945
+ * Detect prompt injection patterns in text.
1946
+ * Returns detailed results about what was detected.
1947
+ *
1948
+ * @throws Error if input exceeds MAX_INJECTION_INPUT_LENGTH (100KB)
1949
+ */
1950
+ declare function detectPromptInjection(text: string, patterns?: InjectionPattern[]): InjectionDetectionResult;
1951
+ /**
1952
+ * Sanitize text by removing detected injection patterns.
1953
+ * Warning: This is a best-effort sanitization, not a security guarantee.
1954
+ *
1955
+ * Uses a single-pass approach to prevent infinite loops where a replacement
1956
+ * could create a new pattern match.
1957
+ */
1958
+ declare function sanitizeInjection(text: string, patterns?: InjectionPattern[]): string;
1959
+ /** Options for prompt injection guardrail */
1960
+ interface PromptInjectionGuardrailOptions {
1961
+ /** Additional patterns to check (added to defaults) */
1962
+ additionalPatterns?: InjectionPattern[];
1963
+ /** Replace default patterns entirely */
1964
+ replacePatterns?: InjectionPattern[];
1965
+ /** Use strict mode with more aggressive detection */
1966
+ strictMode?: boolean;
1967
+ /** Minimum risk score to block (0-100, default: 50) */
1968
+ blockThreshold?: number;
1969
+ /** Attempt to sanitize instead of blocking */
1970
+ sanitize?: boolean;
1971
+ /** Callback when injection is detected */
1972
+ onBlocked?: (input: string, result: InjectionDetectionResult) => void;
1973
+ /** Categories to ignore (e.g., allow 'role_manipulation' for roleplay apps) */
1974
+ ignoreCategories?: InjectionCategory[];
1975
+ }
1976
+ /**
1977
+ * Create a prompt injection detection guardrail.
1978
+ *
1979
+ * @example
1980
+ * ```typescript
1981
+ * // Basic usage
1982
+ * const guardrail = createPromptInjectionGuardrail();
1983
+ *
1984
+ * // Strict mode for high-security applications
1985
+ * const strictGuardrail = createPromptInjectionGuardrail({
1986
+ * strictMode: true,
1987
+ * blockThreshold: 25,
1988
+ * });
1989
+ *
1990
+ * // Allow role manipulation for roleplay apps
1991
+ * const roleplayGuardrail = createPromptInjectionGuardrail({
1992
+ * ignoreCategories: ['role_manipulation'],
1993
+ * });
1994
+ * ```
1995
+ */
1996
+ declare function createPromptInjectionGuardrail(options?: PromptInjectionGuardrailOptions): GuardrailFn<InputGuardrailData>;
1997
+ /**
1998
+ * Mark content as potentially untrusted (from external sources).
1999
+ * This wraps the content with markers that injection detection will scrutinize more closely.
2000
+ *
2001
+ * @example
2002
+ * ```typescript
2003
+ * const userUpload = await readFile(path);
2004
+ * const markedContent = markUntrustedContent(userUpload, 'user-upload');
2005
+ * const prompt = `Summarize this document: ${markedContent}`;
2006
+ * ```
2007
+ */
2008
+ declare function markUntrustedContent(content: string, source: string): string;
2009
+ /**
2010
+ * Create a guardrail that applies stricter checks to marked untrusted content.
2011
+ *
2012
+ * @example
2013
+ * ```typescript
2014
+ * const guardrail = createUntrustedContentGuardrail({
2015
+ * baseGuardrail: createPromptInjectionGuardrail({ strictMode: true }),
2016
+ * });
2017
+ * ```
2018
+ */
2019
+ declare function createUntrustedContentGuardrail(options: {
2020
+ /** Guardrail to apply to untrusted sections */
2021
+ baseGuardrail?: GuardrailFn<InputGuardrailData>;
2022
+ /** Block if untrusted content contains these patterns */
2023
+ additionalPatterns?: InjectionPattern[];
2024
+ }): GuardrailFn<InputGuardrailData>;
2025
+
2026
+ /**
2027
+ * Compliance Plugin - GDPR/CCPA Data Subject Rights
2028
+ *
2029
+ * Provides enterprise-grade compliance features:
2030
+ * - Data Export (DSR) - Export all data for a subject
2031
+ * - Data Deletion - Soft/hard delete with certificates
2032
+ * - Consent Tracking - Track and enforce consent
2033
+ * - Retention Policies - Automatic data retention enforcement
2034
+ *
2035
+ * @example
2036
+ * ```typescript
2037
+ * import { createCompliance } from '@directive-run/ai';
2038
+ *
2039
+ * const compliance = createCompliance({
2040
+ * storage: myStorageAdapter,
2041
+ * retention: {
2042
+ * defaultRetentionMs: 365 * 24 * 60 * 60 * 1000, // 1 year
2043
+ * categoryRetention: {
2044
+ * audit: 7 * 365 * 24 * 60 * 60 * 1000, // 7 years for audit
2045
+ * sessions: 30 * 24 * 60 * 60 * 1000, // 30 days for sessions
2046
+ * },
2047
+ * },
2048
+ * });
2049
+ *
2050
+ * // Handle data subject request
2051
+ * const exportResult = await compliance.exportData({
2052
+ * subjectId: 'user-123',
2053
+ * format: 'json',
2054
+ * includeAudit: true,
2055
+ * });
2056
+ *
2057
+ * // Delete user data
2058
+ * const deleteResult = await compliance.deleteData({
2059
+ * subjectId: 'user-123',
2060
+ * scope: 'all',
2061
+ * });
2062
+ * ```
2063
+ */
2064
+
2065
+ /** Data export request (GDPR Article 20) */
2066
+ interface DataExportRequest {
2067
+ /** Subject identifier (user ID) */
2068
+ subjectId: string;
2069
+ /** Export format */
2070
+ format: "json" | "csv";
2071
+ /** Include audit trail entries */
2072
+ includeAudit?: boolean;
2073
+ /** Include derived data */
2074
+ includeDerived?: boolean;
2075
+ /** Specific data categories to export */
2076
+ categories?: string[];
2077
+ /** Request metadata */
2078
+ metadata?: Record<string, unknown>;
2079
+ }
2080
+ /** Result of data export */
2081
+ interface DataExportResult {
2082
+ /** Whether export was successful */
2083
+ success: boolean;
2084
+ /** Subject identifier */
2085
+ subjectId: string;
2086
+ /** Export format used */
2087
+ format: "json" | "csv";
2088
+ /** Exported data */
2089
+ data: string;
2090
+ /** Data categories included */
2091
+ categories: string[];
2092
+ /** Number of records exported */
2093
+ recordCount: number;
2094
+ /** SHA-256 checksum of exported data */
2095
+ checksum: string;
2096
+ /** Export timestamp */
2097
+ exportedAt: number;
2098
+ /** Expiration timestamp for download link (if applicable) */
2099
+ expiresAt?: number;
2100
+ /** Error message if failed */
2101
+ error?: string;
2102
+ }
2103
+ /** Data deletion scope */
2104
+ type DeletionScope = "all" | "facts" | "audit" | "specific";
2105
+ /** Data deletion request (GDPR Article 17) */
2106
+ interface DataDeletionRequest {
2107
+ /** Subject identifier (user ID) */
2108
+ subjectId: string;
2109
+ /** Scope of deletion */
2110
+ scope: DeletionScope;
2111
+ /** Anonymize instead of delete (retain structure, remove PII) */
2112
+ anonymize?: boolean;
2113
+ /** Specific data categories to delete (when scope is 'specific') */
2114
+ categories?: string[];
2115
+ /** Reason for deletion */
2116
+ reason?: string;
2117
+ /** Request metadata */
2118
+ metadata?: Record<string, unknown>;
2119
+ }
2120
+ /** Result of data deletion */
2121
+ interface DataDeletionResult {
2122
+ /** Whether deletion was successful */
2123
+ success: boolean;
2124
+ /** Subject identifier */
2125
+ subjectId: string;
2126
+ /** Scope of deletion performed */
2127
+ scope: DeletionScope;
2128
+ /** Whether data was anonymized vs deleted */
2129
+ anonymized: boolean;
2130
+ /** Number of records deleted/anonymized */
2131
+ recordsAffected: number;
2132
+ /** Data categories affected */
2133
+ categoriesAffected: string[];
2134
+ /** Deletion certificate (for compliance records) */
2135
+ certificate: DeletionCertificate;
2136
+ /** Deletion timestamp */
2137
+ deletedAt: number;
2138
+ /** Error message if failed */
2139
+ error?: string;
2140
+ }
2141
+ /** Deletion certificate for compliance records */
2142
+ interface DeletionCertificate {
2143
+ /** Certificate ID */
2144
+ id: string;
2145
+ /** Subject identifier */
2146
+ subjectId: string;
2147
+ /** Type of deletion */
2148
+ type: "soft" | "hard" | "anonymization";
2149
+ /** Scope of deletion */
2150
+ scope: DeletionScope;
2151
+ /** Categories deleted */
2152
+ categories: string[];
2153
+ /** Record count */
2154
+ recordCount: number;
2155
+ /** Deletion timestamp */
2156
+ deletedAt: number;
2157
+ /** Reason for deletion */
2158
+ reason?: string;
2159
+ /** SHA-256 hash of certificate content */
2160
+ hash: string;
2161
+ }
2162
+ /** Consent record for a subject */
2163
+ interface ConsentRecord {
2164
+ /** Subject identifier */
2165
+ subjectId: string;
2166
+ /** Consent purpose (e.g., 'marketing', 'analytics', 'personalization') */
2167
+ purpose: string;
2168
+ /** Whether consent is granted */
2169
+ granted: boolean;
2170
+ /** When consent was granted (if granted) */
2171
+ grantedAt?: number;
2172
+ /** When consent expires (if applicable) */
2173
+ expiresAt?: number;
2174
+ /** When consent was revoked (if revoked) */
2175
+ revokedAt?: number;
2176
+ /** Source of consent (e.g., 'signup_form', 'settings_page') */
2177
+ source?: string;
2178
+ /** Consent version/hash (for tracking which T&C version was accepted) */
2179
+ version?: string;
2180
+ }
2181
+ /** Consent tracker interface */
2182
+ interface ConsentTracker {
2183
+ /** Record consent grant */
2184
+ grant(subjectId: string, purpose: string, options?: {
2185
+ expiresAt?: number;
2186
+ source?: string;
2187
+ version?: string;
2188
+ }): Promise<ConsentRecord>;
2189
+ /** Revoke consent */
2190
+ revoke(subjectId: string, purpose: string): Promise<ConsentRecord | null>;
2191
+ /** Check if consent is granted */
2192
+ check(subjectId: string, purpose: string): Promise<boolean>;
2193
+ /** Get all consents for a subject */
2194
+ getForSubject(subjectId: string): Promise<ConsentRecord[]>;
2195
+ /** Get all subjects with consent for a purpose */
2196
+ getForPurpose(purpose: string): Promise<ConsentRecord[]>;
2197
+ }
2198
+ /** Retention policy */
2199
+ interface RetentionPolicy {
2200
+ /** Policy name */
2201
+ name: string;
2202
+ /** Default retention period in milliseconds */
2203
+ defaultRetentionMs: number;
2204
+ /** Category-specific retention periods */
2205
+ categoryRetention?: Record<string, number>;
2206
+ /** Callback before data is deleted */
2207
+ onBeforeDelete?: (data: {
2208
+ category: string;
2209
+ count: number;
2210
+ }) => Promise<void>;
2211
+ /** Callback after data is deleted */
2212
+ onAfterDelete?: (data: {
2213
+ category: string;
2214
+ count: number;
2215
+ }) => void;
2216
+ }
2217
+ /** Storage adapter for compliance data */
2218
+ interface ComplianceStorage {
2219
+ /** Get all data for a subject */
2220
+ getSubjectData(subjectId: string, categories?: string[]): Promise<{
2221
+ category: string;
2222
+ records: Array<{
2223
+ id: string;
2224
+ data: Record<string, unknown>;
2225
+ createdAt: number;
2226
+ }>;
2227
+ }[]>;
2228
+ /** Delete data for a subject */
2229
+ deleteSubjectData(subjectId: string, categories?: string[]): Promise<number>;
2230
+ /** Anonymize data for a subject */
2231
+ anonymizeSubjectData(subjectId: string, categories?: string[]): Promise<number>;
2232
+ /** Get audit entries for a subject */
2233
+ getAuditEntries?(subjectId: string): Promise<Array<{
2234
+ id: string;
2235
+ timestamp: number;
2236
+ eventType: string;
2237
+ payload: Record<string, unknown>;
2238
+ }>>;
2239
+ /** Get data older than timestamp by category */
2240
+ getExpiredData(category: string, olderThan: number): Promise<Array<{
2241
+ id: string;
2242
+ createdAt: number;
2243
+ }>>;
2244
+ /** Delete records by IDs */
2245
+ deleteByIds(ids: string[]): Promise<number>;
2246
+ /** Store consent record */
2247
+ storeConsent(record: ConsentRecord): Promise<void>;
2248
+ /** Get consent record */
2249
+ getConsent(subjectId: string, purpose: string): Promise<ConsentRecord | null>;
2250
+ /** Get consents by subject */
2251
+ getConsentsBySubject(subjectId: string): Promise<ConsentRecord[]>;
2252
+ /** Get consents by purpose */
2253
+ getConsentsByPurpose(purpose: string): Promise<ConsentRecord[]>;
2254
+ /** Store deletion certificate */
2255
+ storeDeletionCertificate(certificate: DeletionCertificate): Promise<void>;
2256
+ }
2257
+ /** Compliance configuration */
2258
+ interface ComplianceConfig {
2259
+ /** Storage adapter */
2260
+ storage: ComplianceStorage;
2261
+ /** Retention policy */
2262
+ retention?: RetentionPolicy;
2263
+ /** Consent purposes to track */
2264
+ consentPurposes?: string[];
2265
+ /** Export link expiration (default: 24 hours) */
2266
+ exportExpirationMs?: number;
2267
+ /** Audit all compliance operations */
2268
+ auditOperations?: boolean;
2269
+ /** Event callbacks */
2270
+ events?: {
2271
+ onExport?: (result: DataExportResult) => void;
2272
+ onDelete?: (result: DataDeletionResult) => void;
2273
+ onConsentChange?: (record: ConsentRecord) => void;
2274
+ onRetentionEnforced?: (category: string, count: number) => void;
2275
+ };
2276
+ }
2277
+ /** Compliance instance */
2278
+ interface ComplianceInstance {
2279
+ /** Export data for a subject (GDPR Article 20) */
2280
+ exportData(request: DataExportRequest): Promise<DataExportResult>;
2281
+ /** Delete data for a subject (GDPR Article 17) */
2282
+ deleteData(request: DataDeletionRequest): Promise<DataDeletionResult>;
2283
+ /** Consent tracker */
2284
+ consent: ConsentTracker;
2285
+ /** Enforce retention policy */
2286
+ enforceRetention(): Promise<number>;
2287
+ /** Create a guardrail that checks consent before processing */
2288
+ createConsentGuardrail(purpose: string): GuardrailFn<InputGuardrailData>;
2289
+ /** Get deletion certificate by ID */
2290
+ getDeletionCertificate(subjectId: string): Promise<DeletionCertificate | null>;
2291
+ }
2292
+ /** Create an in-memory compliance storage adapter */
2293
+ declare function createInMemoryComplianceStorage(): ComplianceStorage;
2294
+ /**
2295
+ * Create a compliance instance for GDPR/CCPA data subject rights.
2296
+ *
2297
+ * Features:
2298
+ * - Data Export (GDPR Article 20) - Portable data export
2299
+ * - Data Deletion (GDPR Article 17) - Right to erasure
2300
+ * - Consent Tracking - Track and verify consent
2301
+ * - Retention Policies - Automatic data retention
2302
+ *
2303
+ * @example
2304
+ * ```typescript
2305
+ * const compliance = createCompliance({
2306
+ * storage: myStorageAdapter,
2307
+ * retention: {
2308
+ * name: 'default',
2309
+ * defaultRetentionMs: 365 * 24 * 60 * 60 * 1000, // 1 year
2310
+ * categoryRetention: {
2311
+ * audit: 7 * 365 * 24 * 60 * 60 * 1000, // 7 years
2312
+ * },
2313
+ * },
2314
+ * consentPurposes: ['marketing', 'analytics', 'personalization'],
2315
+ * });
2316
+ *
2317
+ * // Export user data
2318
+ * const exportResult = await compliance.exportData({
2319
+ * subjectId: 'user-123',
2320
+ * format: 'json',
2321
+ * });
2322
+ *
2323
+ * // Check consent
2324
+ * const hasConsent = await compliance.consent.check('user-123', 'marketing');
2325
+ * ```
2326
+ */
2327
+ declare function createCompliance(config: ComplianceConfig): ComplianceInstance;
2328
+
2329
+ /**
2330
+ * Semantic Caching Guardrail
2331
+ *
2332
+ * Caches agent responses based on semantic similarity to reduce redundant LLM calls.
2333
+ * Uses vector embeddings to find semantically similar previous queries.
2334
+ *
2335
+ * @example
2336
+ * ```typescript
2337
+ * import { createSemanticCacheGuardrail } from '@directive-run/ai';
2338
+ *
2339
+ * const cacheGuardrail = createSemanticCacheGuardrail({
2340
+ * embedder: async (text) => {
2341
+ * // Use your embedding model (OpenAI, local model, etc.)
2342
+ * return await getEmbedding(text);
2343
+ * },
2344
+ * similarityThreshold: 0.95,
2345
+ * maxCacheSize: 1000,
2346
+ * ttlMs: 3600000, // 1 hour
2347
+ * });
2348
+ *
2349
+ * const orchestrator = createAgentOrchestrator({
2350
+ * guardrails: {
2351
+ * input: [cacheGuardrail],
2352
+ * },
2353
+ * runner: run,
2354
+ * });
2355
+ * ```
2356
+ */
2357
+ /** Vector embedding (array of numbers) */
2358
+ type Embedding = number[];
2359
+ /** Function to generate embeddings for text */
2360
+ type EmbedderFn = (text: string) => Promise<Embedding>;
2361
+ /** Cached response entry */
2362
+ interface CacheEntry {
2363
+ id: string;
2364
+ query: string;
2365
+ queryEmbedding: Embedding;
2366
+ response: string;
2367
+ metadata: Record<string, unknown>;
2368
+ createdAt: number;
2369
+ accessedAt: number;
2370
+ accessCount: number;
2371
+ agentName?: string;
2372
+ }
2373
+ /** Cache lookup result */
2374
+ interface CacheLookupResult {
2375
+ hit: boolean;
2376
+ entry?: CacheEntry;
2377
+ similarity?: number;
2378
+ latencyMs: number;
2379
+ }
2380
+ /** Semantic cache configuration */
2381
+ interface SemanticCacheConfig {
2382
+ /** Function to generate embeddings */
2383
+ embedder: EmbedderFn;
2384
+ /** Similarity threshold (0.0 to 1.0) for cache hits */
2385
+ similarityThreshold?: number;
2386
+ /** Maximum number of entries to cache */
2387
+ maxCacheSize?: number;
2388
+ /** Time-to-live in milliseconds for cache entries */
2389
+ ttlMs?: number;
2390
+ /** Cache namespace for multi-tenant scenarios */
2391
+ namespace?: string;
2392
+ /** Custom storage backend (defaults to in-memory) */
2393
+ storage?: SemanticCacheStorage;
2394
+ /** Callback when cache hit occurs */
2395
+ onHit?: (entry: CacheEntry, similarity: number) => void;
2396
+ /** Callback when cache miss occurs */
2397
+ onMiss?: (query: string) => void;
2398
+ /** Callback when cache lookup encounters an error */
2399
+ onError?: (error: Error) => void;
2400
+ /** Whether to include agent name in cache key */
2401
+ perAgent?: boolean;
2402
+ }
2403
+ /** Storage interface for cache backends */
2404
+ interface SemanticCacheStorage {
2405
+ /** Get all entries for a namespace */
2406
+ getEntries(namespace: string): Promise<CacheEntry[]>;
2407
+ /** Add an entry to the cache */
2408
+ addEntry(namespace: string, entry: CacheEntry): Promise<void>;
2409
+ /** Update an entry (e.g., access count) */
2410
+ updateEntry(namespace: string, id: string, updates: Partial<CacheEntry>): Promise<void>;
2411
+ /** Remove an entry */
2412
+ removeEntry(namespace: string, id: string): Promise<void>;
2413
+ /** Clear all entries in a namespace */
2414
+ clear(namespace: string): Promise<void>;
2415
+ }
2416
+ /** Semantic cache instance */
2417
+ interface SemanticCache {
2418
+ /** Look up a query in the cache */
2419
+ lookup(query: string, agentName?: string): Promise<CacheLookupResult>;
2420
+ /** Store a response in the cache */
2421
+ store(query: string, response: string, agentName?: string, metadata?: Record<string, unknown>): Promise<void>;
2422
+ /** Invalidate cache entries matching a predicate */
2423
+ invalidate(predicate: (entry: CacheEntry) => boolean): Promise<number>;
2424
+ /** Clear all cache entries */
2425
+ clear(): Promise<void>;
2426
+ /** Get cache statistics */
2427
+ getStats(): CacheStats;
2428
+ /** Export cache entries (for persistence) */
2429
+ export(): Promise<CacheEntry[]>;
2430
+ /** Import cache entries (from persistence) */
2431
+ import(entries: CacheEntry[]): Promise<void>;
2432
+ }
2433
+ /** Cache statistics */
2434
+ interface CacheStats {
2435
+ totalEntries: number;
2436
+ totalHits: number;
2437
+ totalMisses: number;
2438
+ hitRate: number;
2439
+ avgSimilarityOnHit: number;
2440
+ oldestEntry: number | null;
2441
+ newestEntry: number | null;
2442
+ }
2443
+ /**
2444
+ * Create an in-memory cache storage backend.
2445
+ */
2446
+ declare function createInMemoryStorage(): SemanticCacheStorage;
2447
+ /**
2448
+ * Create a semantic cache instance.
2449
+ *
2450
+ * @example
2451
+ * ```typescript
2452
+ * const cache = createSemanticCache({
2453
+ * embedder: async (text) => {
2454
+ * const response = await openai.embeddings.create({
2455
+ * model: 'text-embedding-3-small',
2456
+ * input: text,
2457
+ * });
2458
+ * return response.data[0].embedding;
2459
+ * },
2460
+ * similarityThreshold: 0.92,
2461
+ * maxCacheSize: 500,
2462
+ * ttlMs: 3600000, // 1 hour
2463
+ * });
2464
+ *
2465
+ * // Check cache before calling agent
2466
+ * const result = await cache.lookup(userQuery);
2467
+ * if (result.hit) {
2468
+ * return result.entry!.response;
2469
+ * }
2470
+ *
2471
+ * // Call agent and cache response
2472
+ * const response = await runAgent(userQuery);
2473
+ * await cache.store(userQuery, response);
2474
+ * ```
2475
+ */
2476
+ declare function createSemanticCache(config: SemanticCacheConfig): SemanticCache;
2477
+ /** Input guardrail data for semantic cache */
2478
+ interface SemanticCacheGuardrailData {
2479
+ input: string;
2480
+ agentName?: string;
2481
+ }
2482
+ /**
2483
+ * Result of semantic cache guardrail.
2484
+ *
2485
+ * **Important semantics:**
2486
+ * - `passed: false` + `cacheHit: true` = Short-circuit with cached response (not an error!)
2487
+ * - `passed: true` + `cacheHit: false` = No cache hit, proceed with agent call
2488
+ *
2489
+ * The `passed: false` follows guardrail convention where "not passing" stops the flow,
2490
+ * but in this case stopping is desirable (returning cached data is good).
2491
+ */
2492
+ interface SemanticCacheGuardrailResult {
2493
+ /**
2494
+ * Whether to proceed with the agent call.
2495
+ * `false` means short-circuit with cached response (this is good, not an error).
2496
+ * `true` means no cache hit, proceed with agent.
2497
+ */
2498
+ passed: boolean;
2499
+ /** Indicates whether this was a cache hit */
2500
+ cacheHit: boolean;
2501
+ /** Reason for the result */
2502
+ reason?: string;
2503
+ /** The cached response (only present on cache hit) */
2504
+ cachedResponse?: string;
2505
+ /** Similarity score (0-1) of the cache hit */
2506
+ similarity?: number;
2507
+ }
2508
+ /**
2509
+ * Create a semantic caching input guardrail.
2510
+ *
2511
+ * **How it works:**
2512
+ * - On cache HIT: Returns `{ passed: false, cacheHit: true, cachedResponse: "..." }`
2513
+ * The orchestrator should detect `cacheHit: true` and return the cached response.
2514
+ * - On cache MISS: Returns `{ passed: true, cacheHit: false }`
2515
+ * Proceed with normal agent execution.
2516
+ *
2517
+ * **Important:** `passed: false` with `cacheHit: true` is SUCCESS, not failure.
2518
+ * The guardrail "short-circuits" the flow to return cached data efficiently.
2519
+ *
2520
+ * @example
2521
+ * ```typescript
2522
+ * const cacheGuardrail = createSemanticCacheGuardrail({
2523
+ * cache: mySemanticCache,
2524
+ * });
2525
+ *
2526
+ * const orchestrator = createAgentOrchestrator({
2527
+ * guardrails: {
2528
+ * input: [
2529
+ * {
2530
+ * name: 'semantic-cache',
2531
+ * fn: cacheGuardrail,
2532
+ * },
2533
+ * ],
2534
+ * },
2535
+ * runner: run,
2536
+ * });
2537
+ *
2538
+ * // In your orchestrator wrapper, check for cache hits:
2539
+ * const guardrailResult = await cacheGuardrail({ input: userQuery });
2540
+ * if (guardrailResult.cacheHit) {
2541
+ * return guardrailResult.cachedResponse; // Fast path!
2542
+ * }
2543
+ * // Otherwise proceed with agent call...
2544
+ * ```
2545
+ */
2546
+ declare function createSemanticCacheGuardrail(config: {
2547
+ cache: SemanticCache;
2548
+ }): (data: SemanticCacheGuardrailData) => Promise<SemanticCacheGuardrailResult>;
2549
+ /**
2550
+ * Create a simple hash-based "embedder" for testing.
2551
+ * NOT suitable for production - use a real embedding model.
2552
+ */
2553
+ declare function createTestEmbedder(dimensions?: number): EmbedderFn;
2554
+ /** Batched embedder instance with dispose capability */
2555
+ interface BatchedEmbedder {
2556
+ /** Embed a single text (batched internally) */
2557
+ embed: EmbedderFn;
2558
+ /** Flush any pending batch immediately */
2559
+ flush(): Promise<void>;
2560
+ /** Dispose of the embedder, clearing timers and rejecting pending requests */
2561
+ dispose(): void;
2562
+ }
2563
+ /**
2564
+ * Create a batched embedder that groups multiple texts into single API calls.
2565
+ *
2566
+ * **BREAKING CHANGE:** Previously returned `EmbedderFn` directly. Now returns
2567
+ * a `BatchedEmbedder` object with `embed`, `flush`, and `dispose` methods.
2568
+ *
2569
+ * To migrate: `const embed = createBatchedEmbedder(...)` becomes
2570
+ * `const { embed } = createBatchedEmbedder(...)`.
2571
+ *
2572
+ * @example
2573
+ * ```typescript
2574
+ * const batchedEmbedder = createBatchedEmbedder({
2575
+ * batchSize: 20,
2576
+ * embedBatch: async (texts) => {
2577
+ * const response = await openai.embeddings.create({
2578
+ * model: 'text-embedding-3-small',
2579
+ * input: texts,
2580
+ * });
2581
+ * return response.data.map(d => d.embedding);
2582
+ * },
2583
+ * maxWaitMs: 50,
2584
+ * });
2585
+ *
2586
+ * // Use the embedder
2587
+ * const embedding = await batchedEmbedder.embed("Hello world");
2588
+ *
2589
+ * // Clean up when done
2590
+ * batchedEmbedder.dispose();
2591
+ * ```
2592
+ */
2593
+ declare function createBatchedEmbedder(config: {
2594
+ batchSize?: number;
2595
+ embedBatch: (texts: string[]) => Promise<Embedding[]>;
2596
+ maxWaitMs?: number;
2597
+ }): BatchedEmbedder;
2598
+
2599
+ /**
2600
+ * Approximate Nearest Neighbor (ANN) Index for Semantic Cache
2601
+ *
2602
+ * Provides pluggable vector search backends for efficient similarity lookups.
2603
+ * Includes a brute-force exact search and a VP-tree (Vantage Point Tree) for
2604
+ * fast approximate nearest neighbor queries.
2605
+ *
2606
+ * @example
2607
+ * ```typescript
2608
+ * import { createSemanticCache } from '@directive-run/ai';
2609
+ * import { createVPTreeIndex } from '@directive-run/ai';
2610
+ *
2611
+ * const index = createVPTreeIndex();
2612
+ *
2613
+ * const cache = createSemanticCache({
2614
+ * embedder: myEmbedder,
2615
+ * annIndex: index,
2616
+ * });
2617
+ * ```
2618
+ */
2619
+
2620
+ /** Search result from an ANN index */
2621
+ interface ANNSearchResult {
2622
+ /** ID of the matched item */
2623
+ id: number;
2624
+ /** Similarity score (0-1, higher is more similar) */
2625
+ similarity: number;
2626
+ }
2627
+ /** ANN Index interface - pluggable vector search backend */
2628
+ interface ANNIndex {
2629
+ /** Add a vector to the index */
2630
+ add(id: number, embedding: Embedding): void;
2631
+ /** Remove a vector from the index */
2632
+ remove(id: number): void;
2633
+ /** Search for the k nearest neighbors */
2634
+ search(query: Embedding, k: number, threshold?: number): ANNSearchResult[];
2635
+ /** Rebuild the index (call after batch additions) */
2636
+ rebuild(): void;
2637
+ /** Get the number of indexed vectors */
2638
+ size(): number;
2639
+ /** Clear the index */
2640
+ clear(): void;
2641
+ /** Check if the index needs to be rebuilt (e.g., after additions/removals) */
2642
+ needsRebuild(): boolean;
2643
+ }
2644
+ /**
2645
+ * Create a brute-force exact search index.
2646
+ *
2647
+ * O(n) search, O(1) add/remove. Best for small collections (< 10,000 vectors).
2648
+ *
2649
+ * @example
2650
+ * ```typescript
2651
+ * const index = createBruteForceIndex();
2652
+ * index.add(0, [0.1, 0.2, 0.3]);
2653
+ * index.add(1, [0.4, 0.5, 0.6]);
2654
+ *
2655
+ * const results = index.search([0.1, 0.2, 0.3], 1);
2656
+ * // [{ id: 0, similarity: 1.0 }]
2657
+ * ```
2658
+ */
2659
+ declare function createBruteForceIndex(): ANNIndex;
2660
+ /** VP-Tree index configuration */
2661
+ interface VPTreeIndexConfig {
2662
+ /** Optional random number generator for deterministic builds. Returns a number in [0, 1). */
2663
+ random?: () => number;
2664
+ }
2665
+ /**
2666
+ * Create a VP-Tree (Vantage Point Tree) index for efficient approximate nearest neighbor search.
2667
+ *
2668
+ * O(log n) search on average, requires rebuild after batch additions.
2669
+ * Best for medium collections (1,000 - 100,000 vectors).
2670
+ *
2671
+ * @example
2672
+ * ```typescript
2673
+ * const index = createVPTreeIndex();
2674
+ *
2675
+ * // Add vectors
2676
+ * for (let i = 0; i < embeddings.length; i++) {
2677
+ * index.add(i, embeddings[i]);
2678
+ * }
2679
+ *
2680
+ * // Build the tree
2681
+ * index.rebuild();
2682
+ *
2683
+ * // Search
2684
+ * const results = index.search(queryEmbedding, 5, 0.9);
2685
+ * ```
2686
+ */
2687
+ declare function createVPTreeIndex(vpConfig?: VPTreeIndexConfig): ANNIndex;
2688
+
2689
+ /**
2690
+ * Streaming Channel for Agent-to-Agent Communication
2691
+ *
2692
+ * Provides AsyncIterable-based streaming for large data transfers between agents.
2693
+ * Supports backpressure, buffering, and graceful termination.
2694
+ *
2695
+ * @example
2696
+ * ```typescript
2697
+ * import { createStreamChannel } from '@directive-run/ai';
2698
+ *
2699
+ * // Producer side
2700
+ * const channel = createStreamChannel<string>({ bufferSize: 100 });
2701
+ *
2702
+ * // Send data
2703
+ * await channel.send('chunk 1');
2704
+ * await channel.send('chunk 2');
2705
+ * channel.end(); // Signal completion
2706
+ *
2707
+ * // Consumer side (async iteration)
2708
+ * for await (const chunk of channel) {
2709
+ * console.log(chunk);
2710
+ * }
2711
+ * ```
2712
+ */
2713
+ /** Stream channel configuration */
2714
+ interface StreamChannelConfig {
2715
+ /** Maximum buffer size before backpressure is applied (default: 100) */
2716
+ bufferSize?: number;
2717
+ /** Channel name for debugging */
2718
+ name?: string;
2719
+ }
2720
+ /** Stream channel state */
2721
+ type StreamChannelState = "open" | "closed" | "error";
2722
+ /** Stream channel instance */
2723
+ interface StreamChannel<T> extends AsyncIterable<T> {
2724
+ /** Send a value to the channel. Resolves when consumed or buffered. */
2725
+ send(value: T): Promise<void>;
2726
+ /** Signal that no more values will be sent */
2727
+ end(): void;
2728
+ /** Signal an error and terminate the stream */
2729
+ error(err: Error): void;
2730
+ /** Get the current state */
2731
+ getState(): StreamChannelState;
2732
+ /** Get the number of buffered items */
2733
+ bufferedCount(): number;
2734
+ }
2735
+ /** Bidirectional stream between two agents */
2736
+ interface BidirectionalStream<TSend, TReceive> {
2737
+ /** Send a value to the remote end */
2738
+ send(value: TSend): Promise<void>;
2739
+ /** Iterate over received values */
2740
+ receive: AsyncIterable<TReceive>;
2741
+ /** Close both directions */
2742
+ close(): void;
2743
+ }
2744
+ /**
2745
+ * Create a stream channel for async data transfer.
2746
+ *
2747
+ * Implements proper backpressure: `send()` will pause when the buffer is full
2748
+ * and resume when the consumer catches up.
2749
+ *
2750
+ * @example
2751
+ * ```typescript
2752
+ * const channel = createStreamChannel<{ token: string }>();
2753
+ *
2754
+ * // Producer (e.g., LLM streaming response)
2755
+ * (async () => {
2756
+ * for (const token of tokens) {
2757
+ * await channel.send({ token });
2758
+ * }
2759
+ * channel.end();
2760
+ * })();
2761
+ *
2762
+ * // Consumer (e.g., downstream agent)
2763
+ * for await (const chunk of channel) {
2764
+ * process.stdout.write(chunk.token);
2765
+ * }
2766
+ * ```
2767
+ */
2768
+ declare function createStreamChannel<T>(config?: StreamChannelConfig): StreamChannel<T>;
2769
+ /**
2770
+ * Create a bidirectional stream channel for two-way communication between agents.
2771
+ *
2772
+ * @example
2773
+ * ```typescript
2774
+ * const { sideA, sideB } = createBidirectionalStream<string, string>();
2775
+ *
2776
+ * // Agent A sends and receives
2777
+ * await sideA.send('question?');
2778
+ * for await (const reply of sideA.receive) {
2779
+ * console.log('A got:', reply);
2780
+ * }
2781
+ *
2782
+ * // Agent B receives and responds
2783
+ * for await (const msg of sideB.receive) {
2784
+ * await sideB.send(`reply to: ${msg}`);
2785
+ * }
2786
+ * ```
2787
+ */
2788
+ declare function createBidirectionalStream<TA, TB>(config?: StreamChannelConfig): {
2789
+ sideA: BidirectionalStream<TA, TB>;
2790
+ sideB: BidirectionalStream<TB, TA>;
2791
+ };
2792
+ /**
2793
+ * Pipe one stream channel through a transform function into another.
2794
+ *
2795
+ * @example
2796
+ * ```typescript
2797
+ * const input = createStreamChannel<string>();
2798
+ * const output = createStreamChannel<number>();
2799
+ *
2800
+ * pipeThrough(input, output, (chunk) => chunk.length);
2801
+ * ```
2802
+ */
2803
+ declare function pipeThrough<TIn, TOut>(source: AsyncIterable<TIn>, destination: StreamChannel<TOut>, transform: (value: TIn) => TOut | Promise<TOut>): Promise<void>;
2804
+ /**
2805
+ * Merge multiple async iterables into a single stream.
2806
+ * Values are emitted as soon as they arrive from any source.
2807
+ *
2808
+ * Note: The internal buffer is capped at 10,000 items. Values exceeding this
2809
+ * limit are dropped. For high-throughput scenarios, ensure the consumer keeps up
2810
+ * or use bounded `StreamChannel` sources.
2811
+ *
2812
+ * @example
2813
+ * ```typescript
2814
+ * const merged = mergeStreams(channel1, channel2, channel3);
2815
+ * for await (const value of merged) {
2816
+ * console.log(value);
2817
+ * }
2818
+ * ```
2819
+ */
2820
+ declare function mergeStreams<T>(...sources: AsyncIterable<T>[]): AsyncIterable<T>;
2821
+
2822
+ /**
2823
+ * P2: Intelligent Retry — HTTP-status-aware retry wrapper for AgentRunner.
2824
+ *
2825
+ * Respects 429 Retry-After headers, uses exponential backoff with jitter for 503,
2826
+ * and never retries client errors (400/401/403/404/422).
2827
+ *
2828
+ * @module
2829
+ *
2830
+ * @example
2831
+ * ```typescript
2832
+ * import { withRetry, RetryExhaustedError } from '@directive-run/ai';
2833
+ *
2834
+ * const runner = withRetry(baseRunner, {
2835
+ * maxRetries: 3,
2836
+ * baseDelayMs: 1000,
2837
+ * maxDelayMs: 30000,
2838
+ * onRetry: (attempt, error, delayMs) => {
2839
+ * console.log(`Retry ${attempt} in ${delayMs}ms: ${error.message}`);
2840
+ * },
2841
+ * });
2842
+ *
2843
+ * try {
2844
+ * const result = await runner(agent, input);
2845
+ * } catch (err) {
2846
+ * if (err instanceof RetryExhaustedError) {
2847
+ * console.error(`All ${err.retryCount} retries failed:`, err.lastError);
2848
+ * }
2849
+ * }
2850
+ * ```
2851
+ */
2852
+
2853
+ /**
2854
+ * Configuration for the intelligent retry wrapper.
2855
+ *
2856
+ * @example
2857
+ * ```typescript
2858
+ * const config: RetryConfig = {
2859
+ * maxRetries: 3,
2860
+ * baseDelayMs: 1000,
2861
+ * maxDelayMs: 30000,
2862
+ * isRetryable: (error) => !error.message.includes("invalid API key"),
2863
+ * onRetry: (attempt, error, delayMs) => {
2864
+ * console.log(`Retry ${attempt} after ${delayMs}ms: ${error.message}`);
2865
+ * },
2866
+ * };
2867
+ * ```
2868
+ */
2869
+ interface RetryConfig {
2870
+ /** Maximum number of retry attempts (not counting the initial call). @default 3 */
2871
+ maxRetries?: number;
2872
+ /** Base delay in ms for exponential backoff. @default 1000 */
2873
+ baseDelayMs?: number;
2874
+ /** Maximum delay in ms (caps exponential growth). @default 30000 */
2875
+ maxDelayMs?: number;
2876
+ /** Custom predicate — return `false` to skip retry for specific errors. Called after the built-in HTTP status check. */
2877
+ isRetryable?: (error: Error) => boolean;
2878
+ /** Called before each retry wait. Useful for logging or metrics. */
2879
+ onRetry?: (attempt: number, error: Error, delayMs: number) => void;
2880
+ }
2881
+ /** Error enriched with retry metadata, thrown when all retries are exhausted. */
2882
+ declare class RetryExhaustedError extends Error {
2883
+ readonly retryCount: number;
2884
+ readonly lastError: Error;
2885
+ constructor(retryCount: number, lastError: Error);
2886
+ }
2887
+ /**
2888
+ * Extract HTTP status code from error message or error properties.
2889
+ *
2890
+ * Checks `error.status` / `error.statusCode` properties first, then falls back
2891
+ * to matching common error message patterns like "request failed: 429" or "HTTP 503".
2892
+ */
2893
+ declare function parseHttpStatus(error: Error): number | null;
2894
+ /**
2895
+ * Extract Retry-After value (in ms) from error message.
2896
+ *
2897
+ * Per HTTP spec, `Retry-After` numeric values are always in seconds.
2898
+ * Returns the value converted to milliseconds.
2899
+ */
2900
+ declare function parseRetryAfter(error: Error): number | null;
2901
+ /**
2902
+ * Wrap an AgentRunner with intelligent retry logic.
2903
+ *
2904
+ * @example
2905
+ * ```typescript
2906
+ * const runner = withRetry(baseRunner, {
2907
+ * maxRetries: 3,
2908
+ * baseDelayMs: 1000,
2909
+ * onRetry: (attempt, error, delayMs) => {
2910
+ * console.log(`Retry ${attempt} after ${delayMs}ms: ${error.message}`);
2911
+ * },
2912
+ * });
2913
+ * ```
2914
+ */
2915
+ declare function withRetry(runner: AgentRunner, config?: RetryConfig): AgentRunner;
2916
+
2917
+ /**
2918
+ * P0: Provider Fallback Chains — Automatic failover across multiple AgentRunners.
2919
+ *
2920
+ * Tries runners in order, moving to the next on failure.
2921
+ * Composes naturally with {@link withRetry} (each runner can have its own retry policy).
2922
+ *
2923
+ * @module
2924
+ *
2925
+ * @example
2926
+ * ```typescript
2927
+ * import { withFallback, withRetry, AllProvidersFailedError } from '@directive-run/ai';
2928
+ *
2929
+ * const runner = withFallback([
2930
+ * withRetry(openaiRunner, { maxRetries: 2 }),
2931
+ * withRetry(anthropicRunner, { maxRetries: 2 }),
2932
+ * ollamaRunner,
2933
+ * ], {
2934
+ * onFallback: (from, to, error) => {
2935
+ * console.log(`Provider ${from} failed, trying ${to}: ${error.message}`);
2936
+ * },
2937
+ * });
2938
+ *
2939
+ * try {
2940
+ * const result = await runner(agent, input);
2941
+ * } catch (err) {
2942
+ * if (err instanceof AllProvidersFailedError) {
2943
+ * console.error(`All ${err.errors.length} providers failed`);
2944
+ * }
2945
+ * }
2946
+ * ```
2947
+ */
2948
+
2949
+ interface FallbackConfig {
2950
+ /** Custom predicate to decide whether to fall back on a given error. Default: always fall back. */
2951
+ shouldFallback?: (error: Error) => boolean;
2952
+ /** Called when falling back from one provider to the next. */
2953
+ onFallback?: (fromIndex: number, toIndex: number, error: Error) => void;
2954
+ }
2955
+ /** Error thrown when all providers in the fallback chain have failed. */
2956
+ declare class AllProvidersFailedError extends Error {
2957
+ readonly errors: Error[];
2958
+ constructor(errors: Error[]);
2959
+ }
2960
+ /**
2961
+ * Wrap multiple AgentRunners into a fallback chain.
2962
+ *
2963
+ * @example
2964
+ * ```typescript
2965
+ * const runner = withFallback([
2966
+ * withRetry(openaiRunner, { maxRetries: 2 }),
2967
+ * withRetry(anthropicRunner, { maxRetries: 2 }),
2968
+ * ollamaRunner,
2969
+ * ], {
2970
+ * onFallback: (from, to, error) => {
2971
+ * console.log(`Falling back from provider ${from} to ${to}: ${error.message}`);
2972
+ * },
2973
+ * });
2974
+ * ```
2975
+ */
2976
+ declare function withFallback(runners: AgentRunner[], config?: FallbackConfig): AgentRunner;
2977
+
2978
+ /**
2979
+ * P1: Cost Budget Guards — Pre-call estimation + rolling budget windows.
2980
+ *
2981
+ * Prevents runaway LLM costs by estimating costs before each call
2982
+ * and tracking actual costs after each call. Supports per-call limits
2983
+ * and rolling time-window budgets (hourly, daily).
2984
+ *
2985
+ * @module
2986
+ *
2987
+ * @example
2988
+ * ```typescript
2989
+ * import { withBudget, BudgetExceededError } from '@directive-run/ai';
2990
+ * import type { BudgetRunner } from '@directive-run/ai';
2991
+ *
2992
+ * const pricing = { inputPerMillion: 3, outputPerMillion: 15 };
2993
+ *
2994
+ * const runner = withBudget(baseRunner, {
2995
+ * maxCostPerCall: 0.10,
2996
+ * pricing,
2997
+ * budgets: [
2998
+ * { window: "hour", maxCost: 5.00, pricing },
2999
+ * { window: "day", maxCost: 50.00, pricing },
3000
+ * ],
3001
+ * });
3002
+ *
3003
+ * // Check spending via escape hatch
3004
+ * const spent = (runner as BudgetRunner).getSpent("hour");
3005
+ * if (spent > 4.00) {
3006
+ * console.warn("Approaching hourly budget limit!");
3007
+ * }
3008
+ * ```
3009
+ */
3010
+
3011
+ /**
3012
+ * Token pricing for a specific model or provider.
3013
+ *
3014
+ * @example
3015
+ * ```typescript
3016
+ * // GPT-4o pricing (as of 2024)
3017
+ * const gpt4oPricing: TokenPricing = {
3018
+ * inputPerMillion: 5,
3019
+ * outputPerMillion: 15,
3020
+ * };
3021
+ * ```
3022
+ */
3023
+ interface TokenPricing {
3024
+ /** Cost per million input tokens (in dollars). */
3025
+ inputPerMillion: number;
3026
+ /** Cost per million output tokens (in dollars). */
3027
+ outputPerMillion: number;
3028
+ }
3029
+ /**
3030
+ * Rolling budget window configuration.
3031
+ *
3032
+ * Each window tracks cost independently, preventing double-counting
3033
+ * when multiple windows are configured.
3034
+ *
3035
+ * @example
3036
+ * ```typescript
3037
+ * const hourlyBudget: BudgetWindow = {
3038
+ * window: "hour",
3039
+ * maxCost: 5.00,
3040
+ * pricing: { inputPerMillion: 3, outputPerMillion: 15 },
3041
+ * };
3042
+ * ```
3043
+ */
3044
+ interface BudgetWindow {
3045
+ /** Time window for the budget. */
3046
+ window: "hour" | "day";
3047
+ /** Maximum cost in dollars for this window. */
3048
+ maxCost: number;
3049
+ /** Token pricing for cost calculation within this window. */
3050
+ pricing: TokenPricing;
3051
+ }
3052
+ interface BudgetConfig {
3053
+ /** Maximum estimated cost per individual call. */
3054
+ maxCostPerCall?: number;
3055
+ /** Rolling budget windows. */
3056
+ budgets?: BudgetWindow[];
3057
+ /** Pricing used for per-call estimation (when maxCostPerCall is set). */
3058
+ pricing?: TokenPricing;
3059
+ /** Approximate characters per token for input estimation. @default 4 */
3060
+ charsPerToken?: number;
3061
+ /**
3062
+ * Multiplier for estimated output tokens relative to input tokens.
3063
+ * For summarization tasks, use a value less than 1 (e.g., 0.3).
3064
+ * For generation tasks, use a value greater than 1 (e.g., 3.0).
3065
+ * @default 1.0
3066
+ */
3067
+ estimatedOutputMultiplier?: number;
3068
+ /** Called when a budget check fails (before throwing). */
3069
+ onBudgetExceeded?: (details: BudgetExceededDetails) => void;
3070
+ }
3071
+ interface BudgetExceededDetails {
3072
+ estimated: number;
3073
+ remaining: number;
3074
+ window: "per-call" | "hour" | "day";
3075
+ }
3076
+ /** Error thrown when a budget limit is exceeded. */
3077
+ declare class BudgetExceededError extends Error {
3078
+ readonly estimated: number;
3079
+ readonly remaining: number;
3080
+ readonly window: "per-call" | "hour" | "day";
3081
+ constructor(details: BudgetExceededDetails);
3082
+ }
3083
+ /**
3084
+ * Wrap an AgentRunner with cost budget guards.
3085
+ *
3086
+ * @example
3087
+ * ```typescript
3088
+ * const runner = withBudget(baseRunner, {
3089
+ * maxCostPerCall: 0.10,
3090
+ * pricing: { inputPerMillion: 3, outputPerMillion: 15 },
3091
+ * budgets: [
3092
+ * { window: "hour", maxCost: 5.00, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
3093
+ * { window: "day", maxCost: 50.00, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
3094
+ * ],
3095
+ * });
3096
+ * ```
3097
+ */
3098
+ declare function withBudget(runner: AgentRunner, config: BudgetConfig): BudgetRunner;
3099
+ /** Helper type for accessing budget runner's getSpent method. */
3100
+ type BudgetRunner = AgentRunner & {
3101
+ /** Get cost spent within a rolling window. */
3102
+ getSpent(window: "hour" | "day"): number;
3103
+ };
3104
+
3105
+ /**
3106
+ * P3: Smart Model Selection — Rule-based model routing for AgentRunner.
3107
+ *
3108
+ * Route simple tasks to cheaper models and complex tasks to expensive ones,
3109
+ * reducing cost without sacrificing quality where it matters.
3110
+ *
3111
+ * Rules are evaluated in order; the first match wins. If no rule matches,
3112
+ * the agent's original model is used unchanged.
3113
+ *
3114
+ * Accepts either a {@link ModelSelectionConfig} object (recommended) or
3115
+ * a bare `ModelRule[]` array for convenience.
3116
+ *
3117
+ * @module
3118
+ *
3119
+ * @example Config object (recommended)
3120
+ * ```typescript
3121
+ * import { withModelSelection, byInputLength, byAgentName, byPattern } from '@directive-run/ai';
3122
+ *
3123
+ * const runner = withModelSelection(baseRunner, {
3124
+ * rules: [
3125
+ * byInputLength(200, "gpt-4o-mini"),
3126
+ * byAgentName("summarizer", "gpt-4o-mini"),
3127
+ * byPattern(/classify|categorize/i, "gpt-4o-mini"),
3128
+ * ],
3129
+ * onModelSelected: (original, selected) => {
3130
+ * if (original !== selected) console.log(`Routed ${original} → ${selected}`);
3131
+ * },
3132
+ * });
3133
+ * ```
3134
+ *
3135
+ * @example Shorthand (rules array)
3136
+ * ```typescript
3137
+ * const runner = withModelSelection(baseRunner, [
3138
+ * byInputLength(200, "gpt-4o-mini"),
3139
+ * ]);
3140
+ * ```
3141
+ */
3142
+
3143
+ /** A single model selection rule. First match wins. */
3144
+ interface ModelRule {
3145
+ /** Predicate that determines if this rule applies. */
3146
+ match: (agent: AgentLike, input: string) => boolean;
3147
+ /** The model to use when this rule matches. */
3148
+ model: string;
3149
+ }
3150
+ /** Configuration for model selection. */
3151
+ interface ModelSelectionConfig {
3152
+ /** Rules evaluated in order. First match wins. */
3153
+ rules: ModelRule[];
3154
+ /** Called when a model is selected (even if it matches the original). */
3155
+ onModelSelected?: (originalModel: string | undefined, selectedModel: string | undefined) => void;
3156
+ }
3157
+ /**
3158
+ * Match when input character length is at most `maxLength`.
3159
+ *
3160
+ * @example
3161
+ * ```typescript
3162
+ * byInputLength(500, "gpt-4o-mini") // inputs up to 500 chars use mini
3163
+ * ```
3164
+ */
3165
+ declare function byInputLength(maxLength: number, model: string): ModelRule;
3166
+ /**
3167
+ * Match by agent name (exact string match).
3168
+ *
3169
+ * @example
3170
+ * ```typescript
3171
+ * byAgentName("classifier", "gpt-4o-mini")
3172
+ * ```
3173
+ */
3174
+ declare function byAgentName(name: string, model: string): ModelRule;
3175
+ /**
3176
+ * Match by regex pattern on the input text.
3177
+ *
3178
+ * @example
3179
+ * ```typescript
3180
+ * byPattern(/classify|categorize/i, "gpt-4o-mini") // classification prompts use mini
3181
+ * ```
3182
+ */
3183
+ declare function byPattern(pattern: RegExp, model: string): ModelRule;
3184
+ /**
3185
+ * Wrap an AgentRunner with rule-based model selection.
3186
+ *
3187
+ * Rules are evaluated in order. The first match wins and overrides `agent.model`.
3188
+ * If no rule matches, the agent's original model is used.
3189
+ *
3190
+ * Accepts either a config object or a bare `ModelRule[]` for convenience.
3191
+ *
3192
+ * @example
3193
+ * ```typescript
3194
+ * // Config object (recommended)
3195
+ * const runner = withModelSelection(baseRunner, {
3196
+ * rules: [
3197
+ * byInputLength(200, "gpt-4o-mini"),
3198
+ * byAgentName("summarizer", "gpt-4o-mini"),
3199
+ * byPattern(/classify|categorize/i, "gpt-4o-mini"),
3200
+ * ],
3201
+ * onModelSelected: (original, selected) => {
3202
+ * console.log(`Model: ${original} → ${selected}`);
3203
+ * },
3204
+ * });
3205
+ *
3206
+ * // Shorthand (rules array)
3207
+ * const runner = withModelSelection(baseRunner, [
3208
+ * byInputLength(200, "gpt-4o-mini"),
3209
+ * ]);
3210
+ * ```
3211
+ */
3212
+ declare function withModelSelection(runner: AgentRunner, configOrRules: ModelSelectionConfig | ModelRule[]): AgentRunner;
3213
+
3214
+ /**
3215
+ * P6: Structured Outputs — Schema validation with auto-retry for LLM responses.
3216
+ *
3217
+ * Turns unreliable text output into typed, validated data. Appends JSON schema
3218
+ * instructions to the system prompt and retries with error feedback on parse failure.
3219
+ *
3220
+ * Works with any Zod-compatible schema (any object with a `safeParse` method).
3221
+ *
3222
+ * @module
3223
+ *
3224
+ * @example
3225
+ * ```typescript
3226
+ * import { z } from "zod";
3227
+ * import { withStructuredOutput, StructuredOutputError } from '@directive-run/ai';
3228
+ *
3229
+ * const SentimentSchema = z.object({
3230
+ * sentiment: z.enum(["positive", "negative", "neutral"]),
3231
+ * confidence: z.number().min(0).max(1),
3232
+ * });
3233
+ *
3234
+ * const runner = withStructuredOutput(baseRunner, {
3235
+ * schema: SentimentSchema,
3236
+ * maxRetries: 2,
3237
+ * });
3238
+ *
3239
+ * const result = await runner(agent, "Analyze: I love this product!");
3240
+ * // result.output is typed as { sentiment: string; confidence: number }
3241
+ * ```
3242
+ */
3243
+
3244
+ /**
3245
+ * Zod-compatible schema duck type — any object with a `safeParse` method.
3246
+ *
3247
+ * This interface allows structured outputs to work with Zod, Valibot,
3248
+ * or any validation library that implements this pattern.
3249
+ *
3250
+ * @example
3251
+ * ```typescript
3252
+ * import { z } from "zod";
3253
+ *
3254
+ * // Zod schemas implement SafeParseable automatically
3255
+ * const schema = z.object({ name: z.string() });
3256
+ *
3257
+ * // Custom schema
3258
+ * const custom: SafeParseable<{ name: string }> = {
3259
+ * safeParse(value) {
3260
+ * if (typeof value === "object" && value && "name" in value) {
3261
+ * return { success: true, data: value as { name: string } };
3262
+ * }
3263
+ * return { success: false, error: { message: "Missing name field" } };
3264
+ * },
3265
+ * };
3266
+ * ```
3267
+ */
3268
+ interface SafeParseable<T = unknown> {
3269
+ safeParse(value: unknown): SafeParseResult<T>;
3270
+ /** Optional: schema description injected into the system prompt. */
3271
+ description?: string;
3272
+ }
3273
+ interface SafeParseResult<T> {
3274
+ success: boolean;
3275
+ data?: T;
3276
+ error?: {
3277
+ message?: string;
3278
+ issues?: Array<{
3279
+ message: string;
3280
+ }>;
3281
+ };
3282
+ }
3283
+ interface StructuredOutputConfig<T = unknown> {
3284
+ /** Zod-compatible schema with safeParse. */
3285
+ schema: SafeParseable<T>;
3286
+ /** Max retries on parse/validation failure. @default 2 */
3287
+ maxRetries?: number;
3288
+ /** Custom JSON extractor. Default: finds first `{...}` or `[...]` in output. */
3289
+ extractJson?: (output: string) => unknown;
3290
+ /** Schema description to inject into system prompt. Auto-derived from schema.description if available. */
3291
+ schemaDescription?: string;
3292
+ }
3293
+ /** Default JSON extractor — finds the first `{...}` or `[...]` in output. */
3294
+ declare function extractJsonFromOutput(output: string): unknown;
3295
+ /**
3296
+ * Wrap an AgentRunner with structured output parsing and validation.
3297
+ *
3298
+ * @example
3299
+ * ```typescript
3300
+ * import { z } from "zod";
3301
+ *
3302
+ * const SentimentSchema = z.object({
3303
+ * sentiment: z.enum(["positive", "negative", "neutral"]),
3304
+ * confidence: z.number().min(0).max(1),
3305
+ * });
3306
+ *
3307
+ * const runner = withStructuredOutput(baseRunner, {
3308
+ * schema: SentimentSchema,
3309
+ * maxRetries: 2,
3310
+ * });
3311
+ *
3312
+ * const result = await runner(agent, "Analyze: I love this product!");
3313
+ * // result.output is typed as { sentiment: string; confidence: number }
3314
+ * ```
3315
+ */
3316
+ declare function withStructuredOutput<T = unknown>(runner: AgentRunner, config: StructuredOutputConfig<T>): AgentRunner;
3317
+ /** Error thrown when structured output parsing fails after all retries. */
3318
+ declare class StructuredOutputError extends Error {
3319
+ readonly lastResult: RunResult<unknown> | undefined;
3320
+ constructor(message: string, lastResult?: RunResult<unknown>);
3321
+ }
3322
+
3323
+ /**
3324
+ * Agent Stack — Composition API for AI Adapters
3325
+ *
3326
+ * One factory that wires orchestrator, memory, circuit breaker, rate limiter,
3327
+ * streaming, multi-agent patterns, semantic cache, observability, OTLP export,
3328
+ * and communication bus with sensible defaults.
3329
+ *
3330
+ * @example Basic usage
3331
+ * ```typescript
3332
+ * import { createAgentStack, parallel } from '@directive-run/ai';
3333
+ *
3334
+ * const stack = createAgentStack({
3335
+ * runner: myAgentRunner,
3336
+ * agents: { move: { agent: moveAgent, capabilities: ["move"] } },
3337
+ * memory: { maxMessages: 30 },
3338
+ * circuitBreaker: { failureThreshold: 3 },
3339
+ * cache: { threshold: 0.98, maxSize: 200, ttlMs: 600_000 },
3340
+ * observability: { serviceName: "my-app" },
3341
+ * });
3342
+ *
3343
+ * const result = await stack.run("move", input);
3344
+ * ```
3345
+ *
3346
+ * @example Streaming
3347
+ * ```typescript
3348
+ * const stack = createAgentStack({
3349
+ * runner: myAgentRunner,
3350
+ * streaming: { runner: myStreamingAgentRunner },
3351
+ * agents: { chat: { agent: chatAgent, capabilities: ["chat"] } },
3352
+ * });
3353
+ *
3354
+ * const tokenStream = stack.stream("chat", "Hello!");
3355
+ * for await (const token of tokenStream) { process.stdout.write(token); }
3356
+ * const finalResult = await tokenStream.result;
3357
+ * ```
3358
+ */
3359
+
3360
+ /** Callback-based streaming run function (e.g. for SSE-based LLM APIs) */
3361
+ type StreamingCallbackRunner = (agent: AgentLike, input: string, callbacks: {
3362
+ onToken?: (token: string) => void;
3363
+ onToolStart?: (tool: string, id: string, args: string) => void;
3364
+ onToolEnd?: (tool: string, id: string, result: string) => void;
3365
+ onMessage?: (message: Message$1) => void;
3366
+ signal?: AbortSignal;
3367
+ }) => Promise<RunResult<unknown>>;
3368
+ interface AgentStackConfig {
3369
+ /** Required: base runner for agent execution */
3370
+ runner: AgentRunner;
3371
+ /** Enables stack.stream() when provided */
3372
+ streaming?: {
3373
+ runner: StreamingCallbackRunner;
3374
+ };
3375
+ /** Agent registry — required for multi-agent patterns */
3376
+ agents?: AgentRegistry;
3377
+ /** Named execution patterns (parallel, sequential, supervisor) */
3378
+ patterns?: Record<string, ExecutionPattern>;
3379
+ memory?: {
3380
+ maxMessages?: number;
3381
+ preserveRecentCount?: number;
3382
+ } | AgentMemory;
3383
+ circuitBreaker?: CircuitBreakerConfig | CircuitBreaker;
3384
+ rateLimit?: {
3385
+ maxPerMinute: number;
3386
+ };
3387
+ cache?: {
3388
+ threshold?: number;
3389
+ maxSize?: number;
3390
+ ttlMs?: number;
3391
+ embedder?: EmbedderFn;
3392
+ } | SemanticCache;
3393
+ observability?: {
3394
+ serviceName: string;
3395
+ alerts?: AlertConfig[];
3396
+ } | ObservabilityInstance;
3397
+ otlp?: {
3398
+ endpoint: string;
3399
+ intervalMs?: number;
3400
+ onError?: (err: Error, type: "metrics" | "traces") => void;
3401
+ };
3402
+ /** @deprecated Use `messageBus` instead */
3403
+ bus?: {
3404
+ maxHistory?: number;
3405
+ } | MessageBus;
3406
+ /** Message bus for agent communication */
3407
+ messageBus?: {
3408
+ maxHistory?: number;
3409
+ } | MessageBus;
3410
+ guardrails?: {
3411
+ input?: Array<GuardrailFn<InputGuardrailData> | NamedGuardrail<InputGuardrailData>>;
3412
+ output?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
3413
+ streaming?: StreamingGuardrail[];
3414
+ };
3415
+ maxTokenBudget?: number;
3416
+ /** Cost per million tokens for cost estimation */
3417
+ costPerMillionTokens?: number;
3418
+ /** @deprecated Use `costPerMillionTokens` */
3419
+ costRatePerMillion?: number;
3420
+ debug?: boolean;
3421
+ constraints?: Record<string, OrchestratorConstraint<Record<string, unknown>>>;
3422
+ resolvers?: Record<string, OrchestratorResolver<Record<string, unknown>, Requirement>>;
3423
+ approvals?: {
3424
+ /** @default true */
3425
+ autoApproveToolCalls?: boolean;
3426
+ onRequest?: (request: ApprovalRequest) => void;
3427
+ /** @default 300_000 */
3428
+ timeoutMs?: number;
3429
+ };
3430
+ retry?: AgentRetryConfig;
3431
+ hooks?: OrchestratorLifecycleHooks;
3432
+ /** P2: Intelligent retry config for the base runner. */
3433
+ intelligentRetry?: RetryConfig;
3434
+ /** P0: Fallback runners (tried in order on failure). */
3435
+ fallback?: {
3436
+ runners: AgentRunner[];
3437
+ config?: FallbackConfig;
3438
+ };
3439
+ /** P1: Cost budget guards. */
3440
+ budget?: BudgetConfig;
3441
+ /** P3: Model selection rules (first match wins). */
3442
+ modelSelection?: ModelRule[];
3443
+ /** P6: Structured output config (applied per-agent via agents map, or globally here). */
3444
+ structuredOutput?: StructuredOutputConfig;
3445
+ }
3446
+ interface StackRunOptions {
3447
+ /** Override output guardrails for this call */
3448
+ guardrails?: {
3449
+ output?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
3450
+ };
3451
+ /** Set to false to skip cache for this call */
3452
+ cache?: false;
3453
+ /** AbortSignal for cancellation */
3454
+ signal?: AbortSignal;
3455
+ }
3456
+ interface StackStreamOptions {
3457
+ signal?: AbortSignal;
3458
+ }
3459
+ interface TokenStream<T = string> extends AsyncIterable<string> {
3460
+ /** Resolves to the final run result after the stream completes */
3461
+ result: Promise<RunResult<T>>;
3462
+ /** Abort the stream */
3463
+ abort: () => void;
3464
+ }
3465
+ interface AgentStackState {
3466
+ totalTokens: number;
3467
+ estimatedCost: number;
3468
+ circuitState: CircuitState;
3469
+ cacheStats: CacheStats;
3470
+ memoryMessageCount: number;
3471
+ busMessageCount: number;
3472
+ rateLimitRemaining: number | null;
3473
+ }
3474
+ /** Options for runStructured() */
3475
+ interface StructuredRunOptions<_T = unknown> extends StackRunOptions {
3476
+ /** Validate the output. Return `true` or `{ valid: true }` on success. */
3477
+ validate: (value: unknown) => boolean | {
3478
+ valid: boolean;
3479
+ errors?: string[];
3480
+ };
3481
+ /** Number of retry attempts on validation failure @default 1 */
3482
+ retries?: number;
3483
+ }
3484
+ interface AgentStack {
3485
+ /** Run a single registered agent by ID */
3486
+ run<T = unknown>(agentId: string, input: string, options?: StackRunOptions): Promise<RunResult<T>>;
3487
+ /** Run and validate output against a schema, retrying on failure */
3488
+ runStructured<T>(agentId: string, input: string, options: StructuredRunOptions<T>): Promise<RunResult<T>>;
3489
+ /** Run a named execution pattern */
3490
+ runPattern<T = unknown>(patternId: string, input: string, options?: StackRunOptions): Promise<T>;
3491
+ /** Stream tokens from a single agent */
3492
+ stream<T = string>(agentId: string, input: string, options?: StackStreamOptions): TokenStream<T>;
3493
+ /** Stream full rich chunks (token, tool_start, tool_end, etc.) from a single agent */
3494
+ streamChunks<T = unknown>(agentId: string, input: string, options?: StackStreamOptions): StreamingRunResult<T>;
3495
+ /** Approve a pending approval request */
3496
+ approve(requestId: string): void;
3497
+ /** Reject a pending approval request */
3498
+ reject(requestId: string, reason?: string): void;
3499
+ /** Aggregate state across all features */
3500
+ getState(): AgentStackState;
3501
+ /** Reset all feature state */
3502
+ reset(): void;
3503
+ /** Dispose all resources */
3504
+ dispose(): Promise<void>;
3505
+ readonly orchestrator: AgentOrchestrator<Record<string, unknown>>;
3506
+ readonly observability: ObservabilityInstance | null;
3507
+ readonly messageBus: MessageBus | null;
3508
+ readonly coordinator: MultiAgentOrchestrator | null;
3509
+ readonly cache: SemanticCache | null;
3510
+ readonly memory: AgentMemory | null;
3511
+ /** Get observability timeline (spans + metrics) for debugging */
3512
+ getTimeline(limit?: number): {
3513
+ spans: readonly TraceSpan[];
3514
+ metrics: Record<string, AggregatedMetric>;
3515
+ };
3516
+ /** @deprecated Use `observability` */
3517
+ readonly obs: ObservabilityInstance | null;
3518
+ /** @deprecated Use `messageBus` */
3519
+ readonly bus: MessageBus | null;
3520
+ /** @deprecated Use `coordinator` */
3521
+ readonly multi: MultiAgentOrchestrator | null;
3522
+ }
3523
+ /**
3524
+ * Create an agent stack that composes all AI adapter features.
3525
+ *
3526
+ * Only `runner` is required. Every other feature activates when its config key
3527
+ * is present. Pass a pre-built instance to reuse existing objects, or pass
3528
+ * shorthand config to let the stack create them.
3529
+ */
3530
+ declare function createAgentStack(config: AgentStackConfig): AgentStack;
3531
+
3532
+ /**
3533
+ * AI Bridge — Syncs AI adapter state into a Directive system.
3534
+ *
3535
+ * Eliminates manual state sync boilerplate when using createAgentStack()
3536
+ * alongside createSystem().
3537
+ *
3538
+ * @example Using with AgentStack directly
3539
+ * ```typescript
3540
+ * const syncAI = createAISyncer(stack, (state) => {
3541
+ * system.events.chat.updateAIState({
3542
+ * totalTokens: state.totalTokens,
3543
+ * estimatedCost: state.estimatedCost,
3544
+ * circuitState: state.circuitState,
3545
+ * });
3546
+ * });
3547
+ * syncAI();
3548
+ * ```
3549
+ *
3550
+ * @example Using with a wrapper that has getState()
3551
+ * ```typescript
3552
+ * const syncAI = createAISyncer(myAIWrapper, (state) => {
3553
+ * system.events.chat.updateAIState({ ... });
3554
+ * });
3555
+ * syncAI();
3556
+ * ```
3557
+ */
3558
+ /**
3559
+ * Any object with a getState() method.
3560
+ * Works with AgentStack, or any wrapper that exposes getState().
3561
+ */
3562
+ interface Syncable<S> {
3563
+ getState(): S;
3564
+ }
3565
+ /**
3566
+ * Create a sync function that reads the latest state from a source and
3567
+ * passes it to a callback (typically dispatching events into a Directive system).
3568
+ *
3569
+ * Call the returned function after any AI operation to push state updates.
3570
+ */
3571
+ declare function createAISyncer<S>(source: Syncable<S>, syncFn: (state: S) => void): () => void;
3572
+
3573
+ /**
3574
+ * RAG Enricher — Composable retrieval-augmented generation pipeline.
3575
+ *
3576
+ * Embeds a query, searches a chunk store by cosine similarity, and assembles
3577
+ * an enriched input string (context + history + query) for any agent.
3578
+ *
3579
+ * @example
3580
+ * ```typescript
3581
+ * import {
3582
+ * createRAGEnricher,
3583
+ * createJSONFileStore,
3584
+ * } from '@directive-run/ai';
3585
+ *
3586
+ * const enricher = createRAGEnricher({
3587
+ * embedder: myEmbedder, // Provide your own EmbedderFn
3588
+ * storage: createJSONFileStore({ filePath: './embeddings.json' }),
3589
+ * });
3590
+ *
3591
+ * const enrichedInput = await enricher.enrich('How do constraints work?', {
3592
+ * prefix: 'User is viewing: /docs/constraints',
3593
+ * history: [{ role: 'user', content: 'Hello' }],
3594
+ * });
3595
+ * ```
3596
+ */
3597
+
3598
+ /** A document chunk with embedding and metadata */
3599
+ interface RAGChunk {
3600
+ id: string;
3601
+ content: string;
3602
+ embedding: Embedding;
3603
+ metadata: Record<string, unknown>;
3604
+ }
3605
+ /** Pluggable storage backend */
3606
+ interface RAGStorage {
3607
+ getChunks(): Promise<RAGChunk[]>;
3608
+ size(): Promise<number>;
3609
+ /** Optional: optimized vector search (bypasses full getChunks scan) */
3610
+ search?(query: Embedding, topK: number, minSimilarity: number): Promise<Array<RAGChunk & {
3611
+ similarity: number;
3612
+ }>>;
3613
+ /** Reload storage (clear cache, re-read from source) */
3614
+ reload?(): Promise<void>;
3615
+ /** Dispose of resources */
3616
+ dispose?(): void;
3617
+ }
3618
+ interface RAGEnricherConfig {
3619
+ /** Function to generate query embeddings */
3620
+ embedder: EmbedderFn;
3621
+ /** Storage backend for document chunks */
3622
+ storage: RAGStorage;
3623
+ /** Number of top results to return (default: 5) */
3624
+ topK?: number;
3625
+ /** Minimum similarity score to include, clamped to [0, 1] (default: 0.3) */
3626
+ minSimilarity?: number;
3627
+ /** Custom chunk formatter */
3628
+ formatChunk?: (chunk: RAGChunk, similarity: number) => string;
3629
+ /** Custom context block formatter */
3630
+ formatContext?: (formattedChunks: string[], query: string) => string;
3631
+ /** Error callback — embedder/storage errors are non-fatal by default */
3632
+ onError?: (error: Error) => void;
3633
+ }
3634
+ interface RAGEnrichOptions {
3635
+ /** Prefix line (e.g. "User is viewing: /docs/constraints") */
3636
+ prefix?: string;
3637
+ /** Conversation history */
3638
+ history?: Array<{
3639
+ role: string;
3640
+ content: string;
3641
+ }>;
3642
+ /** Per-call topK override */
3643
+ topK?: number;
3644
+ /** Filter chunks before ranking (e.g. by metadata tag or section) */
3645
+ filter?: (chunk: RAGChunk) => boolean;
3646
+ }
3647
+ interface RAGEnricher {
3648
+ /** Retrieve relevant chunks for a query */
3649
+ retrieve(query: string, topK?: number): Promise<Array<RAGChunk & {
3650
+ similarity: number;
3651
+ }>>;
3652
+ /** Retrieve + format into an enriched input string */
3653
+ enrich(input: string, options?: RAGEnrichOptions): Promise<string>;
3654
+ }
3655
+ /**
3656
+ * Create a RAG enricher that retrieves relevant document chunks and
3657
+ * assembles enriched input for an agent.
3658
+ */
3659
+ declare function createRAGEnricher(config: RAGEnricherConfig): RAGEnricher;
3660
+ interface JSONFileStoreOptions {
3661
+ /** Absolute or relative path to the JSON embeddings file */
3662
+ filePath: string;
3663
+ /** Optional transform from raw JSON entries to RAGChunk */
3664
+ mapEntry?: (entry: Record<string, unknown>) => RAGChunk;
3665
+ /** Cache TTL in ms. 0 = cache forever (default) */
3666
+ ttlMs?: number;
3667
+ }
3668
+ /**
3669
+ * Create a RAGStorage backed by a JSON file (lazy-loaded, cached in memory).
3670
+ * Uses dynamic `import('node:fs')` for isomorphic safety.
3671
+ */
3672
+ declare function createJSONFileStore(options: JSONFileStoreOptions): RAGStorage;
3673
+
3674
+ /**
3675
+ * SSE Transport — Wrap a Directive AgentStack token stream into an HTTP
3676
+ * Server-Sent Events response.
3677
+ *
3678
+ * Framework-agnostic: uses the WinterCG `Response` constructor (Node 18+,
3679
+ * Deno, Bun, Cloudflare Workers, Next.js).
3680
+ *
3681
+ * @example
3682
+ * ```typescript
3683
+ * import { createSSETransport, createAgentStack } from '@directive-run/ai';
3684
+ *
3685
+ * const transport = createSSETransport({
3686
+ * maxResponseChars: 10_000,
3687
+ * errorMessages: {
3688
+ * INPUT_GUARDRAIL_FAILED: 'Your message was flagged by our safety filter.',
3689
+ * },
3690
+ * });
3691
+ *
3692
+ * // Next.js route handler
3693
+ * export async function POST(req: Request) {
3694
+ * const { message } = await req.json();
3695
+ * return transport.toResponse(stack, 'docs-qa', message);
3696
+ * }
3697
+ * ```
3698
+ */
3699
+
3700
+ type SSEEvent = {
3701
+ type: "text";
3702
+ text: string;
3703
+ } | {
3704
+ type: "truncated";
3705
+ text: string;
3706
+ } | {
3707
+ type: "done";
3708
+ } | {
3709
+ type: "error";
3710
+ message: string;
3711
+ } | {
3712
+ type: "heartbeat";
3713
+ timestamp: number;
3714
+ };
3715
+ interface SSETransportConfig {
3716
+ /** Truncate response after this many characters (default: Infinity) */
3717
+ maxResponseChars?: number;
3718
+ /** Message shown when response is truncated */
3719
+ truncationMessage?: string;
3720
+ /** Heartbeat interval in ms (default: 0 = disabled) */
3721
+ heartbeatIntervalMs?: number;
3722
+ /** Map error codes/types to user-facing messages */
3723
+ errorMessages?: Record<string, string> | ((error: unknown) => string);
3724
+ /** Extra headers merged into the SSE response */
3725
+ headers?: Record<string, string>;
3726
+ }
3727
+ interface SSETransport {
3728
+ /** Create a full HTTP Response with SSE headers */
3729
+ toResponse(stack: AgentStack, agentId: string, input: string, opts?: {
3730
+ signal?: AbortSignal;
3731
+ }): Response;
3732
+ /** Return just the ReadableStream (for Express/Koa `res.write()`) */
3733
+ toStream(stack: AgentStack, agentId: string, input: string, opts?: {
3734
+ signal?: AbortSignal;
3735
+ }): ReadableStream<Uint8Array>;
3736
+ }
3737
+ /**
3738
+ * Create an SSE transport that converts a Directive AgentStack token stream
3739
+ * into Server-Sent Events.
3740
+ */
3741
+ declare function createSSETransport(config?: SSETransportConfig): SSETransport;
3742
+
3743
+ /**
3744
+ * P5: Batch Queue — Application-level batching for agent calls.
3745
+ *
3746
+ * Accumulates calls and flushes them in batches to reduce overhead.
3747
+ * Each `submit()` returns a promise that resolves when its individual call completes.
3748
+ * Batches execute calls in parallel up to a configurable concurrency limit.
3749
+ *
3750
+ * @module
3751
+ *
3752
+ * @example
3753
+ * ```typescript
3754
+ * import { createBatchQueue } from '@directive-run/ai';
3755
+ *
3756
+ * const queue = createBatchQueue(runner, {
3757
+ * maxBatchSize: 20,
3758
+ * maxWaitMs: 5000,
3759
+ * concurrency: 5,
3760
+ * });
3761
+ *
3762
+ * // Submit calls — they batch automatically
3763
+ * const [r1, r2, r3] = await Promise.all([
3764
+ * queue.submit(agent, "input 1"),
3765
+ * queue.submit(agent, "input 2"),
3766
+ * queue.submit(agent, "input 3"),
3767
+ * ]);
3768
+ *
3769
+ * // Force immediate flush
3770
+ * await queue.flush();
3771
+ *
3772
+ * // Clean up (flushes remaining calls)
3773
+ * await queue.dispose();
3774
+ * ```
3775
+ */
3776
+
3777
+ interface BatchQueueConfig {
3778
+ /** Maximum number of calls per batch. @default 20 */
3779
+ maxBatchSize?: number;
3780
+ /** Maximum time to wait before flushing (ms). @default 5000 */
3781
+ maxWaitMs?: number;
3782
+ /** Number of calls to run in parallel within a batch. @default 5 */
3783
+ concurrency?: number;
3784
+ }
3785
+ interface BatchQueue {
3786
+ /** Submit a call to the queue. Returns a promise that resolves when the call completes. */
3787
+ submit<T = unknown>(agent: AgentLike, input: string, options?: RunOptions): Promise<RunResult<T>>;
3788
+ /** Flush all pending calls immediately. */
3789
+ flush(): Promise<void>;
3790
+ /** Get the number of pending calls. */
3791
+ readonly pending: number;
3792
+ /** Dispose the queue, flushing remaining calls. */
3793
+ dispose(): Promise<void>;
3794
+ }
3795
+ /**
3796
+ * Create a batch queue for grouping agent calls.
3797
+ *
3798
+ * @example
3799
+ * ```typescript
3800
+ * const queue = createBatchQueue(runner, {
3801
+ * maxBatchSize: 20,
3802
+ * maxWaitMs: 5000,
3803
+ * concurrency: 5,
3804
+ * });
3805
+ *
3806
+ * // Submit multiple calls — they batch automatically
3807
+ * const [result1, result2, result3] = await Promise.all([
3808
+ * queue.submit(agent, "input 1"),
3809
+ * queue.submit(agent, "input 2"),
3810
+ * queue.submit(agent, "input 3"),
3811
+ * ]);
3812
+ *
3813
+ * // Clean up
3814
+ * await queue.dispose();
3815
+ * ```
3816
+ */
3817
+ declare function createBatchQueue(runner: AgentRunner, config?: BatchQueueConfig): BatchQueue;
3818
+
3819
+ /**
3820
+ * P4: Constraint-Driven Provider Routing — Directive's unique differentiator.
3821
+ *
3822
+ * Uses user-supplied constraints to select providers based on runtime state:
3823
+ * cost, latency, error rates, and compliance regions.
3824
+ *
3825
+ * Tracks per-provider stats (call count, error count, cost, latency) and
3826
+ * exposes them as {@link RoutingFacts} for constraint evaluation.
3827
+ *
3828
+ * @module
3829
+ *
3830
+ * @example
3831
+ * ```typescript
3832
+ * import { createConstraintRouter } from '@directive-run/ai';
3833
+ * import type { ConstraintRouterRunner } from '@directive-run/ai';
3834
+ *
3835
+ * const router = createConstraintRouter({
3836
+ * providers: [
3837
+ * { name: "openai", runner: openaiRunner, pricing: { inputPerMillion: 5, outputPerMillion: 15 } },
3838
+ * { name: "anthropic", runner: anthropicRunner, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
3839
+ * { name: "ollama", runner: ollamaRunner },
3840
+ * ],
3841
+ * defaultProvider: "openai",
3842
+ * constraints: [
3843
+ * { when: (facts) => facts.totalCost > 100, provider: "ollama", priority: 10 },
3844
+ * { when: (facts) => facts.providers["openai"]?.errorCount > 5, provider: "anthropic" },
3845
+ * ],
3846
+ * preferCheapest: true, // opt-in to cheapest-provider heuristic
3847
+ * onProviderSelected: (name, reason) => console.log(`Using ${name} (${reason})`),
3848
+ * });
3849
+ *
3850
+ * // Access runtime stats
3851
+ * console.log(router.facts.totalCost, router.facts.callCount);
3852
+ * ```
3853
+ */
3854
+
3855
+ /**
3856
+ * Provider definition for the constraint router.
3857
+ *
3858
+ * Each provider has its own runner, optional pricing (for cost tracking
3859
+ * and cheapest-provider heuristic), and optional region tag.
3860
+ */
3861
+ interface RoutingProvider {
3862
+ /** Unique name for this provider. */
3863
+ name: string;
3864
+ /** The runner to use for this provider. */
3865
+ runner: AgentRunner;
3866
+ /** Token pricing (cost per million tokens). */
3867
+ pricing?: {
3868
+ inputPerMillion: number;
3869
+ outputPerMillion: number;
3870
+ };
3871
+ /** Geographic region (for compliance routing). */
3872
+ region?: string;
3873
+ }
3874
+ /**
3875
+ * Runtime facts tracked by the router — exposed for user constraints.
3876
+ *
3877
+ * Access via the `facts` property on the returned {@link ConstraintRouterRunner}.
3878
+ */
3879
+ interface RoutingFacts {
3880
+ totalCost: number;
3881
+ callCount: number;
3882
+ errorCount: number;
3883
+ lastProvider: string | null;
3884
+ avgLatencyMs: number;
3885
+ /** Per-provider stats. */
3886
+ providers: Record<string, ProviderStats>;
3887
+ }
3888
+ interface ProviderStats {
3889
+ callCount: number;
3890
+ errorCount: number;
3891
+ totalCost: number;
3892
+ avgLatencyMs: number;
3893
+ lastErrorAt: number | null;
3894
+ }
3895
+ /** User-supplied routing constraint. */
3896
+ interface RoutingConstraint {
3897
+ /** When this constraint is active. */
3898
+ when: (facts: RoutingFacts) => boolean;
3899
+ /** The provider to route to. */
3900
+ provider: string;
3901
+ /** Priority — higher wins when multiple constraints match. @default 0 */
3902
+ priority?: number;
3903
+ }
3904
+ interface ConstraintRouterConfig {
3905
+ /** Available providers. */
3906
+ providers: RoutingProvider[];
3907
+ /** Default provider name. */
3908
+ defaultProvider: string;
3909
+ /** User-supplied routing constraints. */
3910
+ constraints?: RoutingConstraint[];
3911
+ /** Called when a provider is selected. */
3912
+ onProviderSelected?: (providerName: string, reason: "constraint" | "cheapest" | "default") => void;
3913
+ /** Error cooldown — skip a provider for this many ms after an error. @default 30000 */
3914
+ errorCooldownMs?: number;
3915
+ /**
3916
+ * When true, automatically prefer the cheapest available provider
3917
+ * (based on pricing) when no user constraint matches.
3918
+ * When false, the default provider is used unless a constraint overrides it.
3919
+ * @default false
3920
+ */
3921
+ preferCheapest?: boolean;
3922
+ }
3923
+ /**
3924
+ * Create a constraint-driven provider router.
3925
+ *
3926
+ * @example
3927
+ * ```typescript
3928
+ * const runner = createConstraintRouter({
3929
+ * providers: [
3930
+ * { name: "openai", runner: openaiRunner, pricing: { inputPerMillion: 5, outputPerMillion: 15 } },
3931
+ * { name: "anthropic", runner: anthropicRunner, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
3932
+ * { name: "ollama", runner: ollamaRunner },
3933
+ * ],
3934
+ * defaultProvider: "openai",
3935
+ * constraints: [
3936
+ * { when: (facts) => facts.totalCost > 100, provider: "ollama", priority: 10 },
3937
+ * { when: (facts) => facts.providers["openai"]?.errorCount > 5, provider: "anthropic" },
3938
+ * ],
3939
+ * });
3940
+ * ```
3941
+ */
3942
+ declare function createConstraintRouter(config: ConstraintRouterConfig): ConstraintRouterRunner;
3943
+ /** Helper type for accessing router facts. */
3944
+ type ConstraintRouterRunner = AgentRunner & {
3945
+ readonly facts: RoutingFacts;
3946
+ };
3947
+
3948
+ /**
3949
+ * MCP Type Definitions
3950
+ *
3951
+ * Model Context Protocol types for Directive integration.
3952
+ * These types are compatible with the MCP specification but don't require
3953
+ * the MCP SDK as a dependency.
3954
+ *
3955
+ * @see https://modelcontextprotocol.io/
3956
+ */
3957
+ /** MCP Transport type */
3958
+ type MCPTransport = "stdio" | "sse" | "websocket";
3959
+ /** MCP Server connection configuration */
3960
+ interface MCPServerConfig {
3961
+ /** Unique name for this server */
3962
+ name: string;
3963
+ /** Transport protocol */
3964
+ transport: MCPTransport;
3965
+ /** For stdio: command to run */
3966
+ command?: string;
3967
+ /** For stdio: command arguments */
3968
+ args?: string[];
3969
+ /** For stdio: environment variables */
3970
+ env?: Record<string, string>;
3971
+ /** For sse/websocket: URL to connect to */
3972
+ url?: string;
3973
+ /** Optional authentication */
3974
+ auth?: {
3975
+ type: "bearer" | "api-key" | "oauth";
3976
+ token?: string;
3977
+ apiKey?: string;
3978
+ };
3979
+ /** Connection timeout (ms) */
3980
+ timeout?: number;
3981
+ /** Retry configuration */
3982
+ retry?: {
3983
+ maxAttempts?: number;
3984
+ backoffMs?: number;
3985
+ };
3986
+ }
3987
+ /** MCP Tool definition */
3988
+ interface MCPTool {
3989
+ /** Tool name (must be unique within server) */
3990
+ name: string;
3991
+ /** Human-readable description */
3992
+ description?: string;
3993
+ /** JSON Schema for tool input */
3994
+ inputSchema: MCPJsonSchema;
3995
+ }
3996
+ /** MCP Resource definition */
3997
+ interface MCPResource {
3998
+ /** Resource URI */
3999
+ uri: string;
4000
+ /** Human-readable name */
4001
+ name: string;
4002
+ /** Resource description */
4003
+ description?: string;
4004
+ /** MIME type */
4005
+ mimeType?: string;
4006
+ }
4007
+ /** MCP Prompt definition */
4008
+ interface MCPPrompt {
4009
+ /** Prompt name */
4010
+ name: string;
4011
+ /** Prompt description */
4012
+ description?: string;
4013
+ /** Arguments the prompt accepts */
4014
+ arguments?: MCPPromptArgument[];
4015
+ }
4016
+ /** MCP Prompt argument */
4017
+ interface MCPPromptArgument {
4018
+ name: string;
4019
+ description?: string;
4020
+ required?: boolean;
4021
+ }
4022
+ /** JSON Schema type (subset used by MCP) */
4023
+ interface MCPJsonSchema {
4024
+ type?: string;
4025
+ description?: string;
4026
+ properties?: Record<string, MCPJsonSchema>;
4027
+ required?: string[];
4028
+ items?: MCPJsonSchema;
4029
+ enum?: unknown[];
4030
+ default?: unknown;
4031
+ [key: string]: unknown;
4032
+ }
4033
+ /** Result from calling an MCP tool */
4034
+ interface MCPToolResult {
4035
+ /** Tool output content */
4036
+ content: MCPContent[];
4037
+ /** Whether the tool call failed */
4038
+ isError?: boolean;
4039
+ }
4040
+ /** MCP Content types */
4041
+ type MCPContent = MCPTextContent | MCPImageContent | MCPResourceContent;
4042
+ /** Text content */
4043
+ interface MCPTextContent {
4044
+ type: "text";
4045
+ text: string;
4046
+ }
4047
+ /** Image content */
4048
+ interface MCPImageContent {
4049
+ type: "image";
4050
+ data: string;
4051
+ mimeType: string;
4052
+ }
4053
+ /** Resource reference content */
4054
+ interface MCPResourceContent {
4055
+ type: "resource";
4056
+ resource: {
4057
+ uri: string;
4058
+ mimeType?: string;
4059
+ text?: string;
4060
+ blob?: string;
4061
+ };
4062
+ }
4063
+ /** Result from reading an MCP resource */
4064
+ interface MCPResourceResult {
4065
+ contents: Array<{
4066
+ uri: string;
4067
+ mimeType?: string;
4068
+ text?: string;
4069
+ blob?: string;
4070
+ }>;
4071
+ }
4072
+ /** Result from getting an MCP prompt */
4073
+ interface MCPPromptResult {
4074
+ description?: string;
4075
+ messages: Array<{
4076
+ role: "user" | "assistant";
4077
+ content: MCPContent;
4078
+ }>;
4079
+ }
4080
+ /** MCP Client capabilities */
4081
+ interface MCPCapabilities {
4082
+ tools?: boolean;
4083
+ resources?: boolean;
4084
+ prompts?: boolean;
4085
+ sampling?: boolean;
4086
+ logging?: boolean;
4087
+ }
4088
+ /** MCP Client interface (for custom implementations) */
4089
+ interface MCPClient {
4090
+ /** Connect to the server */
4091
+ connect(): Promise<void>;
4092
+ /** Disconnect from the server */
4093
+ disconnect(): Promise<void>;
4094
+ /** Check if connected */
4095
+ isConnected(): boolean;
4096
+ /** Get server capabilities */
4097
+ getCapabilities(): MCPCapabilities;
4098
+ /** List available tools */
4099
+ listTools(): Promise<MCPTool[]>;
4100
+ /** Call a tool */
4101
+ callTool(name: string, args: Record<string, unknown>): Promise<MCPToolResult>;
4102
+ /** List available resources */
4103
+ listResources(): Promise<MCPResource[]>;
4104
+ /** Read a resource */
4105
+ readResource(uri: string): Promise<MCPResourceResult>;
4106
+ /** Subscribe to resource changes */
4107
+ subscribeResource?(uri: string, callback: (resource: MCPResource) => void): () => void;
4108
+ /** List available prompts */
4109
+ listPrompts(): Promise<MCPPrompt[]>;
4110
+ /** Get a prompt with arguments */
4111
+ getPrompt(name: string, args?: Record<string, string>): Promise<MCPPromptResult>;
4112
+ }
4113
+ /** Constraint configuration for an MCP tool */
4114
+ interface MCPToolConstraint {
4115
+ /** Require human approval before calling */
4116
+ requireApproval?: boolean;
4117
+ /** Maximum argument size (bytes) */
4118
+ maxArgSize?: number;
4119
+ /** Constraint that must be true to allow the tool */
4120
+ when?: (facts: Record<string, unknown>, args: Record<string, unknown>) => boolean | Promise<boolean>;
4121
+ /** Requirement to emit when constraint is violated */
4122
+ require?: {
4123
+ type: string;
4124
+ [key: string]: unknown;
4125
+ };
4126
+ /** Rate limit (calls per minute) */
4127
+ rateLimit?: number;
4128
+ /** Timeout for tool execution (ms) */
4129
+ timeout?: number;
4130
+ }
4131
+ /** Mapping of MCP resources to Directive facts */
4132
+ interface MCPResourceMapping {
4133
+ /** Resource URI pattern (glob or regex) */
4134
+ pattern: string | RegExp;
4135
+ /** Fact key to sync to */
4136
+ factKey: string;
4137
+ /** Transform resource content before setting fact */
4138
+ transform?: (content: string) => unknown;
4139
+ /** Sync mode */
4140
+ mode: "poll" | "subscribe" | "manual";
4141
+ /** Poll interval (ms) for 'poll' mode */
4142
+ pollInterval?: number;
4143
+ }
4144
+ /** MCP Approval request */
4145
+ interface MCPApprovalRequest {
4146
+ id: string;
4147
+ server: string;
4148
+ tool: string;
4149
+ args: Record<string, unknown>;
4150
+ requestedAt: number;
4151
+ }
4152
+ /** MCP Adapter events */
4153
+ interface MCPAdapterEvents {
4154
+ /** Server connected */
4155
+ onConnect?: (server: string) => void;
4156
+ /** Server disconnected */
4157
+ onDisconnect?: (server: string, reason?: string) => void;
4158
+ /** Tool called */
4159
+ onToolCall?: (server: string, tool: string, args: Record<string, unknown>) => void;
4160
+ /** Tool result received */
4161
+ onToolResult?: (server: string, tool: string, result: MCPToolResult) => void;
4162
+ /** Resource updated */
4163
+ onResourceUpdate?: (server: string, uri: string, content: MCPResourceResult) => void;
4164
+ /** Error occurred */
4165
+ onError?: (server: string, error: Error) => void;
4166
+ /** Approval required for tool call */
4167
+ onApprovalRequest?: (request: MCPApprovalRequest) => void;
4168
+ /** Approval resolved */
4169
+ onApprovalResolved?: (requestId: string, approved: boolean) => void;
4170
+ }
4171
+ /** MCP Adapter configuration */
4172
+ interface MCPAdapterConfig {
4173
+ /** MCP servers to connect to */
4174
+ servers: MCPServerConfig[];
4175
+ /** Tool-specific constraints */
4176
+ toolConstraints?: Record<string, MCPToolConstraint>;
4177
+ /** Resource to fact mappings */
4178
+ resourceMappings?: MCPResourceMapping[];
4179
+ /** Event handlers */
4180
+ events?: MCPAdapterEvents;
4181
+ /** Auto-connect on adapter creation */
4182
+ autoConnect?: boolean;
4183
+ /** Reconnect on disconnect */
4184
+ autoReconnect?: boolean;
4185
+ /** Custom MCP client factory (for testing or custom implementations) */
4186
+ clientFactory?: (config: MCPServerConfig) => MCPClient;
4187
+ /** Enable debug logging for stub client (default: false) */
4188
+ debug?: boolean;
4189
+ /** Approval timeout in milliseconds (default: 300000 = 5 minutes) */
4190
+ approvalTimeoutMs?: number;
4191
+ }
4192
+ /** Requirement to call an MCP tool */
4193
+ interface MCPCallToolRequirement {
4194
+ type: "MCP_CALL_TOOL";
4195
+ server: string;
4196
+ tool: string;
4197
+ args: Record<string, unknown>;
4198
+ [key: string]: unknown;
4199
+ }
4200
+ /** Requirement to read an MCP resource */
4201
+ interface MCPReadResourceRequirement {
4202
+ type: "MCP_READ_RESOURCE";
4203
+ server: string;
4204
+ uri: string;
4205
+ [key: string]: unknown;
4206
+ }
4207
+ /** Requirement to get an MCP prompt */
4208
+ interface MCPGetPromptRequirement {
4209
+ type: "MCP_GET_PROMPT";
4210
+ server: string;
4211
+ prompt: string;
4212
+ args?: Record<string, string>;
4213
+ [key: string]: unknown;
4214
+ }
4215
+ /** Requirement to sync MCP resources */
4216
+ interface MCPSyncResourcesRequirement {
4217
+ type: "MCP_SYNC_RESOURCES";
4218
+ server?: string;
4219
+ pattern?: string | RegExp;
4220
+ [key: string]: unknown;
4221
+ }
4222
+ /** Union of all MCP requirements */
4223
+ type MCPRequirement = MCPCallToolRequirement | MCPReadResourceRequirement | MCPGetPromptRequirement | MCPSyncResourcesRequirement;
4224
+
4225
+ /**
4226
+ * MCP Adapter - Model Context Protocol Integration for Directive
4227
+ *
4228
+ * Provides seamless integration between Directive's constraint system and MCP servers:
4229
+ * - MCP tools become Directive resolvers with constraint-driven access control
4230
+ * - MCP resources sync to Directive facts
4231
+ * - MCP prompts available through requirements
4232
+ *
4233
+ * @example
4234
+ * ```typescript
4235
+ * import { createMCPAdapter } from '@directive-run/ai';
4236
+ *
4237
+ * const mcpAdapter = createMCPAdapter({
4238
+ * servers: [
4239
+ * { name: 'filesystem', transport: 'stdio', command: 'mcp-server-filesystem' },
4240
+ * { name: 'github', transport: 'sse', url: 'https://mcp.github.com' }
4241
+ * ],
4242
+ * toolConstraints: {
4243
+ * 'filesystem.write': { requireApproval: true },
4244
+ * 'github.create_pr': { when: (facts) => facts.reviewComplete }
4245
+ * }
4246
+ * });
4247
+ *
4248
+ * const system = createSystem({
4249
+ * module: myModule,
4250
+ * plugins: [mcpAdapter.plugin]
4251
+ * });
4252
+ * ```
4253
+ */
4254
+
4255
+ /** State of an MCP server connection */
4256
+ interface MCPServerState {
4257
+ config: MCPServerConfig;
4258
+ client: MCPClient | null;
4259
+ tools: MCPTool[];
4260
+ resources: MCPResource[];
4261
+ status: "disconnected" | "connecting" | "connected" | "error";
4262
+ error?: Error;
4263
+ lastSync?: number;
4264
+ }
4265
+ /** MCP Adapter instance */
4266
+ interface MCPAdapter {
4267
+ /** Plugin to add to Directive system */
4268
+ plugin: Plugin;
4269
+ /** Connect to all configured servers */
4270
+ connect(): Promise<void>;
4271
+ /** Connect to a specific server */
4272
+ connectServer(name: string): Promise<void>;
4273
+ /** Disconnect from all servers */
4274
+ disconnect(): Promise<void>;
4275
+ /** Disconnect from a specific server */
4276
+ disconnectServer(name: string): Promise<void>;
4277
+ /** Get all available tools across all servers */
4278
+ getTools(): Map<string, MCPTool[]>;
4279
+ /** Get all available resources across all servers */
4280
+ getResources(): Map<string, MCPResource[]>;
4281
+ /**
4282
+ * Call a tool with constraint checking (recommended).
4283
+ * Applies rate limits, argument size limits, approval workflow, and custom constraints.
4284
+ * @param server - Server name
4285
+ * @param tool - Tool name
4286
+ * @param args - Tool arguments
4287
+ * @param facts - Current facts for constraint evaluation
4288
+ */
4289
+ callTool(server: string, tool: string, args: Record<string, unknown>, facts: Record<string, unknown>): Promise<MCPToolResult>;
4290
+ /**
4291
+ * Call a tool directly, bypassing all constraints (rate limits, approvals, etc.).
4292
+ * Use only for trusted internal calls where constraint checking is not needed.
4293
+ */
4294
+ callToolDirect(server: string, tool: string, args: Record<string, unknown>): Promise<MCPToolResult>;
4295
+ /** Read a resource directly */
4296
+ readResource(server: string, uri: string): Promise<MCPResourceResult>;
4297
+ /** Sync resources to facts */
4298
+ syncResources(facts: Record<string, unknown>): Promise<void>;
4299
+ /** Get server status */
4300
+ getServerStatus(name: string): MCPServerState | undefined;
4301
+ /** Get all server statuses */
4302
+ getAllServerStatuses(): Map<string, MCPServerState>;
4303
+ /** Approve a pending tool call request */
4304
+ approve(requestId: string): void;
4305
+ /** Reject a pending tool call request */
4306
+ reject(requestId: string, reason?: string): void;
4307
+ /** Get pending approval requests */
4308
+ getPendingApprovals(): MCPApprovalRequest[];
4309
+ /** Get the rejection reason for a request (if available) */
4310
+ getRejectionReason(requestId: string): string | undefined;
4311
+ }
4312
+ /**
4313
+ * Create an MCP adapter for Directive integration.
4314
+ *
4315
+ * @example
4316
+ * ```typescript
4317
+ * const adapter = createMCPAdapter({
4318
+ * servers: [
4319
+ * { name: 'fs', transport: 'stdio', command: 'mcp-server-filesystem' },
4320
+ * ],
4321
+ * toolConstraints: {
4322
+ * 'fs.write_file': {
4323
+ * requireApproval: true,
4324
+ * maxArgSize: 10000,
4325
+ * timeout: 30000,
4326
+ * },
4327
+ * },
4328
+ * resourceMappings: [
4329
+ * {
4330
+ * pattern: 'file://*.json',
4331
+ * factKey: 'jsonFiles',
4332
+ * mode: 'poll',
4333
+ * pollInterval: 5000,
4334
+ * },
4335
+ * ],
4336
+ * });
4337
+ *
4338
+ * // Add to system
4339
+ * const system = createSystem({
4340
+ * module: myModule,
4341
+ * plugins: [adapter.plugin],
4342
+ * });
4343
+ *
4344
+ * // Connect to servers
4345
+ * await adapter.connect();
4346
+ * ```
4347
+ */
4348
+ declare function createMCPAdapter(config: MCPAdapterConfig): MCPAdapter;
4349
+ /**
4350
+ * Convert MCP tools to a format suitable for LLM tool calling.
4351
+ *
4352
+ * @example
4353
+ * ```typescript
4354
+ * const adapter = createMCPAdapter({ servers: [...] });
4355
+ * await adapter.connect();
4356
+ *
4357
+ * const tools = adapter.getTools();
4358
+ * const llmTools = convertToolsForLLM(tools);
4359
+ * // Use with OpenAI/Anthropic/etc.
4360
+ * ```
4361
+ */
4362
+ declare function convertToolsForLLM(tools: Map<string, MCPTool[]>): Array<{
4363
+ type: "function";
4364
+ function: {
4365
+ name: string;
4366
+ description: string;
4367
+ parameters: Record<string, unknown>;
4368
+ };
4369
+ }>;
4370
+ /**
4371
+ * Create a requirement to call an MCP tool.
4372
+ *
4373
+ * @example
4374
+ * ```typescript
4375
+ * const req = mcpCallTool('filesystem', 'read_file', { path: '/etc/hosts' });
4376
+ * // { type: 'MCP_CALL_TOOL', server: 'filesystem', tool: 'read_file', args: { path: '/etc/hosts' } }
4377
+ * ```
4378
+ */
4379
+ declare function mcpCallTool(server: string, tool: string, args: Record<string, unknown>): MCPCallToolRequirement;
4380
+ /**
4381
+ * Create a requirement to read an MCP resource.
4382
+ */
4383
+ declare function mcpReadResource(server: string, uri: string): MCPReadResourceRequirement;
4384
+ /**
4385
+ * Create a requirement to get an MCP prompt.
4386
+ */
4387
+ declare function mcpGetPrompt(server: string, prompt: string, args?: Record<string, string>): MCPGetPromptRequirement;
4388
+ /**
4389
+ * Create a requirement to sync MCP resources.
4390
+ */
4391
+ declare function mcpSyncResources(server?: string, pattern?: string | RegExp): MCPSyncResourcesRequirement;
4392
+
4393
+ /**
4394
+ * AI Adapter – Constraint-driven agent orchestration with guardrails
4395
+ *
4396
+ * Philosophy: "Use Directive WITH any LLM agent framework"
4397
+ * - Your framework handles LLM tool execution
4398
+ * - Directive adds safety guardrails, approval workflows, state persistence
4399
+ *
4400
+ * Also available:
4401
+ * - `@directive-run/ai/testing` – Mock runners, test orchestrators, assertion helpers
4402
+ * - `@directive-run/ai/anthropic` – Anthropic Claude adapter
4403
+ * - `@directive-run/ai/openai` – OpenAI / Azure / Together adapter
4404
+ * - `@directive-run/ai/ollama` – Local Ollama inference adapter
4405
+ *
4406
+ * @example
4407
+ * ```typescript
4408
+ * import { createAgentOrchestrator } from '@directive-run/ai'
4409
+ *
4410
+ * const orchestrator = createAgentOrchestrator({
4411
+ * runner: myAgentRunner,
4412
+ * constraints: {
4413
+ * needsExpertReview: {
4414
+ * when: (facts) => facts.decision.confidence < 0.7,
4415
+ * require: { type: 'EXPERT_AGENT', query: facts.userQuery }
4416
+ * },
4417
+ * budgetLimit: {
4418
+ * when: (facts) => facts.tokenUsage > 10000,
4419
+ * require: { type: 'PAUSE_AGENTS' }
4420
+ * }
4421
+ * },
4422
+ * guardrails: {
4423
+ * input: [(data) => validatePII(data.input)],
4424
+ * output: [(data) => checkToxicity(data.output)]
4425
+ * }
4426
+ * })
4427
+ * ```
4428
+ */
4429
+
4430
+ /** Orchestrator options */
4431
+ interface OrchestratorOptions<F extends Record<string, unknown>> {
4432
+ /** Function to run an agent */
4433
+ runner: AgentRunner;
4434
+ /** Additional facts schema */
4435
+ factsSchema?: Record<string, {
4436
+ _type: unknown;
4437
+ _validators: [];
4438
+ }>;
4439
+ /** Initialize additional facts */
4440
+ init?: (facts: F & OrchestratorState) => void;
4441
+ /** Constraints for orchestration */
4442
+ constraints?: Record<string, OrchestratorConstraint<F>>;
4443
+ /** Resolvers for orchestration */
4444
+ resolvers?: Record<string, OrchestratorResolver<F, Requirement>>;
4445
+ /** Guardrails */
4446
+ guardrails?: GuardrailsConfig;
4447
+ /** Callback for approval requests */
4448
+ onApprovalRequest?: (request: ApprovalRequest) => void;
4449
+ /**
4450
+ * Auto-approve tool calls
4451
+ * @default true
4452
+ */
4453
+ autoApproveToolCalls?: boolean;
4454
+ /**
4455
+ * Maximum token budget across all agent runs.
4456
+ *
4457
+ * When exceeded, agents are automatically paused with status "paused".
4458
+ * Check `facts.agent.tokenUsage` to see current usage.
4459
+ *
4460
+ * For more sophisticated cost management (per-user budgets, tiered pricing,
4461
+ * cost alerts), see the Cost Management section in the documentation.
4462
+ *
4463
+ * @example
4464
+ * ```typescript
4465
+ * const orchestrator = createAgentOrchestrator({
4466
+ * maxTokenBudget: 10000, // Pause after 10K tokens
4467
+ * });
4468
+ *
4469
+ * // Check if paused due to budget
4470
+ * if (orchestrator.facts.agent.status === 'paused') {
4471
+ * console.log('Budget exceeded:', orchestrator.facts.agent.tokenUsage);
4472
+ * }
4473
+ * ```
4474
+ */
4475
+ maxTokenBudget?: number;
4476
+ /** Plugins */
4477
+ plugins?: Plugin[];
4478
+ /**
4479
+ * Enable debugging
4480
+ * @default false
4481
+ */
4482
+ debug?: boolean;
4483
+ /**
4484
+ * Approval timeout in milliseconds
4485
+ * @default 300000 (5 minutes)
4486
+ */
4487
+ approvalTimeoutMs?: number;
4488
+ /** Retry configuration for agent runs (no retries if not specified) */
4489
+ agentRetry?: AgentRetryConfig;
4490
+ /** Lifecycle hooks for observability */
4491
+ hooks?: OrchestratorLifecycleHooks;
4492
+ /**
4493
+ * Optional memory instance. When provided, context messages are auto-injected
4494
+ * into agent instructions before each run, and result messages are auto-stored.
4495
+ */
4496
+ memory?: AgentMemory;
4497
+ /**
4498
+ * Optional circuit breaker. Wraps every run() call.
4499
+ * When OPEN, throws CircuitBreakerOpenError instead of calling the agent.
4500
+ */
4501
+ circuitBreaker?: CircuitBreaker;
4502
+ }
4503
+ /** Streaming run result from orchestrator */
4504
+ interface OrchestratorStreamResult<T = unknown> {
4505
+ /** Async iterator for streaming chunks */
4506
+ stream: AsyncIterable<OrchestratorStreamChunk>;
4507
+ /** Promise that resolves to the final result */
4508
+ result: Promise<RunResult<T>>;
4509
+ /** Abort the stream */
4510
+ abort: () => void;
4511
+ }
4512
+ /** Stream chunk types for orchestrator — extends StreamChunk with approval events */
4513
+ type OrchestratorStreamChunk = StreamChunk | {
4514
+ type: "approval_required";
4515
+ requestId: string;
4516
+ toolName: string;
4517
+ } | {
4518
+ type: "approval_resolved";
4519
+ requestId: string;
4520
+ approved: boolean;
4521
+ };
4522
+ /** Per-call options for run() */
4523
+ interface RunCallOptions {
4524
+ /** Override output guardrails for this call only. Set to [] to skip. */
4525
+ outputGuardrails?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
4526
+ /** Override input guardrails for this call only. Set to [] to skip. */
4527
+ inputGuardrails?: Array<GuardrailFn<InputGuardrailData> | NamedGuardrail<InputGuardrailData>>;
4528
+ /** Signal for abort */
4529
+ signal?: AbortSignal;
4530
+ }
4531
+ /** Orchestrator instance */
4532
+ interface AgentOrchestrator<F extends Record<string, unknown>> {
4533
+ system: System<any>;
4534
+ facts: F & OrchestratorState;
4535
+ /** Run an agent with guardrails. Pass options to override guardrails per-call. */
4536
+ run<T>(agent: AgentLike, input: string, options?: RunCallOptions): Promise<RunResult<T>>;
4537
+ /**
4538
+ * Run an agent with streaming support.
4539
+ * Returns an async iterator for chunks and a promise for the final result.
4540
+ *
4541
+ * @example
4542
+ * ```typescript
4543
+ * const { stream, result, abort } = orchestrator.runStream(agent, input);
4544
+ *
4545
+ * for await (const chunk of stream) {
4546
+ * if (chunk.type === 'token') process.stdout.write(chunk.data);
4547
+ * if (chunk.type === 'approval_required') showApprovalDialog(chunk);
4548
+ * if (chunk.type === 'guardrail_triggered') handleGuardrail(chunk);
4549
+ * }
4550
+ *
4551
+ * const finalResult = await result;
4552
+ * ```
4553
+ */
4554
+ runStream<T>(agent: AgentLike, input: string, options?: {
4555
+ signal?: AbortSignal;
4556
+ }): OrchestratorStreamResult<T>;
4557
+ /** Approve a pending request */
4558
+ approve(requestId: string): void;
4559
+ /** Reject a pending request */
4560
+ reject(requestId: string, reason?: string): void;
4561
+ /** Pause all agents */
4562
+ pause(): void;
4563
+ /** Resume agents */
4564
+ resume(): void;
4565
+ /** Reset conversation state */
4566
+ reset(): void;
4567
+ /** Dispose of the orchestrator */
4568
+ dispose(): void;
4569
+ }
4570
+ /**
4571
+ * Create an orchestrator for OpenAI agents with Directive constraints.
4572
+ *
4573
+ * @example
4574
+ * ```typescript
4575
+ * import { run as runner } from '@openai/agents'
4576
+ *
4577
+ * const orchestrator = createAgentOrchestrator({
4578
+ * runner,
4579
+ * constraints: {
4580
+ * escalateToExpert: {
4581
+ * when: (facts) => facts.agent.output?.confidence < 0.7,
4582
+ * require: (facts) => ({
4583
+ * type: 'RUN_EXPERT_AGENT',
4584
+ * query: facts.agent.input,
4585
+ * }),
4586
+ * },
4587
+ * budgetExceeded: {
4588
+ * when: (facts) => facts.agent.tokenUsage > 10000,
4589
+ * require: { type: 'PAUSE_AGENTS' },
4590
+ * },
4591
+ * },
4592
+ * guardrails: {
4593
+ * input: [
4594
+ * async (data) => {
4595
+ * const hasPII = await detectPII(data.input);
4596
+ * return { passed: !hasPII, reason: hasPII ? 'Contains PII' : undefined };
4597
+ * },
4598
+ * ],
4599
+ * output: [
4600
+ * async (data) => {
4601
+ * const isToxic = await checkToxicity(data.output);
4602
+ * return { passed: !isToxic, reason: isToxic ? 'Toxic content' : undefined };
4603
+ * },
4604
+ * ],
4605
+ * },
4606
+ * });
4607
+ *
4608
+ * // Run with guardrails and constraint-driven orchestration
4609
+ * const result = await orchestrator.run(myAgent, 'Hello, can you help me?');
4610
+ * ```
4611
+ *
4612
+ * @throws {Error} If autoApproveToolCalls is false but no onApprovalRequest callback is provided
4613
+ */
4614
+ declare function createAgentOrchestrator<F extends Record<string, unknown> = Record<string, never>>(options: OrchestratorOptions<F>): AgentOrchestrator<F>;
4615
+ /** Builder for type-safe orchestrator configuration */
4616
+ interface OrchestratorBuilder<F extends Record<string, unknown>> {
4617
+ /** Add a constraint */
4618
+ withConstraint<K extends string>(id: K, constraint: OrchestratorConstraint<F>): OrchestratorBuilder<F>;
4619
+ /** Add a resolver */
4620
+ withResolver<R extends Requirement>(id: string, resolver: OrchestratorResolver<F, R>): OrchestratorBuilder<F>;
4621
+ /** Add an input guardrail */
4622
+ withInputGuardrail(nameOrGuardrail: string | NamedGuardrail<InputGuardrailData>, fn?: GuardrailFn<InputGuardrailData>): OrchestratorBuilder<F>;
4623
+ /** Add an output guardrail */
4624
+ withOutputGuardrail(nameOrGuardrail: string | NamedGuardrail<OutputGuardrailData>, fn?: GuardrailFn<OutputGuardrailData>): OrchestratorBuilder<F>;
4625
+ /** Add a tool call guardrail */
4626
+ withToolCallGuardrail(nameOrGuardrail: string | NamedGuardrail<ToolCallGuardrailData>, fn?: GuardrailFn<ToolCallGuardrailData>): OrchestratorBuilder<F>;
4627
+ /** Add a plugin */
4628
+ withPlugin(plugin: Plugin): OrchestratorBuilder<F>;
4629
+ /** Set memory instance for auto context injection and message storage */
4630
+ withMemory(memory: AgentMemory): OrchestratorBuilder<F>;
4631
+ /** Set circuit breaker to wrap all run() calls */
4632
+ withCircuitBreaker(cb: CircuitBreaker): OrchestratorBuilder<F>;
4633
+ /** Set max token budget */
4634
+ withBudget(maxTokens: number): OrchestratorBuilder<F>;
4635
+ /** Enable debug mode */
4636
+ withDebug(enabled?: boolean): OrchestratorBuilder<F>;
4637
+ /** Build the orchestrator */
4638
+ build(options: {
4639
+ runner: AgentRunner;
4640
+ autoApproveToolCalls?: boolean;
4641
+ onApprovalRequest?: (request: ApprovalRequest) => void;
4642
+ }): AgentOrchestrator<F>;
4643
+ }
4644
+ /**
4645
+ * Create a type-safe orchestrator builder.
4646
+ *
4647
+ * @example
4648
+ * ```typescript
4649
+ * const orchestrator = createOrchestratorBuilder<MyFacts>()
4650
+ * .withConstraint('budget', {
4651
+ * when: (facts) => facts.cost > 100,
4652
+ * require: { type: 'PAUSE' },
4653
+ * })
4654
+ * .withInputGuardrail('pii', createPIIGuardrail())
4655
+ * .withOutputGuardrail('toxicity', createModerationGuardrail({ ... }))
4656
+ * .withBudget(10000)
4657
+ * .withDebug()
4658
+ * .build({ runner });
4659
+ * ```
4660
+ */
4661
+ declare function createOrchestratorBuilder<F extends Record<string, unknown> = Record<string, never>>(): OrchestratorBuilder<F>;
4662
+
4663
+ export { type ANNIndex, type ANNSearchResult, AdapterHooks, type AgentInfo, AgentLike, type AgentMemory, type AgentMemoryConfig, type AgentMessage, type AgentMessageType, type AgentNetwork, type AgentNetworkConfig, type AgentOrchestrator, type AgentRegistration, type AgentRegistry, AgentRetryConfig, type AgentRunState, AgentRunner, type AgentSelectionConstraint, type AgentStack, type AgentStackConfig, type AgentStackState, AgentState, AllProvidersFailedError, ApprovalRequest, ApprovalState, type AuditInstance, type AuditPluginConfig, type BackpressureStrategy, type BatchQueue, type BatchQueueConfig, type BatchedEmbedder, type BidirectionalStream, type BudgetConfig, type BudgetExceededDetails, BudgetExceededError, type BudgetRunner, type BudgetWindow, type CacheEntry, type CacheLookupResult, type CacheStats, type ComplianceConfig, type ComplianceInstance, type ComplianceStorage, type ConstraintBuilder, type ConstraintRouterConfig, type ConstraintRouterRunner, type CreateRunnerOptions, DEFAULT_INJECTION_PATTERNS, type DelegationMessage, type DelegationResultMessage, type DoneChunk, type EmbedderFn, type Embedding, type EnhancedPIIGuardrailOptions, type ErrorChunk, type ExecutionPattern, type FallbackConfig, GuardrailFn, type GuardrailTriggeredChunk, GuardrailsConfig, type HandoffRequest, type HandoffResult, type InformMessage, InputGuardrailData, type JSONFileStoreOptions, type MCPAdapter, type MCPAdapterConfig, type MCPApprovalRequest, type MCPCallToolRequirement, type MCPGetPromptRequirement, type MCPReadResourceRequirement, type MCPRequirement, type MCPResource, type MCPServerConfig, type MCPSyncResourcesRequirement, type MCPTool, type MCPToolConstraint, type MCPToolResult, type MemoryManageResult, type MemoryState, type MemoryStrategy, type MemoryStrategyConfig, type MemoryStrategyResult, Message$1 as Message, type MessageBus, type MessageBusConfig, type MessageChunk, type MessageFilter, type MessageHandler, type MessageSummarizer, type ModelRule, type ModelSelectionConfig, type MultiAgentOrchestrator, type MultiAgentOrchestratorOptions, type MultiAgentState, NamedGuardrail, type OrchestratorBuilder, OrchestratorConstraint, OrchestratorLifecycleHooks, type OrchestratorOptions, OrchestratorResolver, OrchestratorState, type OrchestratorStreamChunk, type OrchestratorStreamResult, OutputGuardrailData, type ParallelPattern, type ParsedResponse, type ProgressChunk, type PromptInjectionGuardrailOptions, type ProviderStats, type QueryMessage, type RAGChunk, type RAGEnrichOptions, type RAGEnricher, type RAGEnricherConfig, type RAGStorage, type RateLimitGuardrail, type RequestMessage, type ResponseMessage, type RetryConfig, RetryExhaustedError, type RoutingConstraint, type RoutingFacts, type RoutingProvider, type RunAgentRequirement, type RunCallOptions, RunOptions, RunResult, type SSEEvent, type SSETransport, type SSETransportConfig, STRICT_INJECTION_PATTERNS, type SafeParseResult, type SafeParseable, SchemaValidator, type SemanticCache, type SemanticCacheConfig, type SemanticCacheStorage, Semaphore, type SequentialPattern, type StackRunOptions, type StackStreamOptions, type StreamChannel, type StreamChannelConfig, type StreamChannelState, type StreamChunk, type StreamRunOptions, type StreamRunner, type StreamingCallbackRunner, type StreamingGuardrail, type StreamingGuardrailResult, type StreamingRunResult, type StructuredOutputConfig, StructuredOutputError, type StructuredRunOptions, type Subscription, type SupervisorPattern, type TokenChunk, type TokenPricing, type TokenStream, ToolCallGuardrailData, type ToolEndChunk, type ToolStartChunk, type TypedAgentMessage, type UpdateMessage, type VPTreeIndexConfig, type WhenWithRequire, adaptOutputGuardrail, aggregateTokens, byAgentName, byInputLength, byPattern, collectOutputs, collectTokens, combineStreamingGuardrails, concatResults, constraint, convertToolsForLLM, createAISyncer, createAgentAuditHandlers, createAgentMemory, createAgentNetwork, createAgentOrchestrator, createAgentStack, createAuditTrail, createBatchQueue, createBatchedEmbedder, createBidirectionalStream, createBruteForceIndex, createCompliance, createConstraintRouter, createContentFilterGuardrail, createDelegator, createEnhancedPIIGuardrail, createHybridStrategy, createInMemoryComplianceStorage, createInMemoryStorage, createJSONFileStore, createKeyPointsSummarizer, createLLMSummarizer, createLengthGuardrail, createLengthStreamingGuardrail, createMCPAdapter, createMessageBus, createModerationGuardrail, createMultiAgentOrchestrator, createOrchestratorBuilder, createOutputPIIGuardrail, createOutputSchemaGuardrail, createOutputTypeGuardrail, createPIIGuardrail, createPatternStreamingGuardrail, createPromptInjectionGuardrail, createPubSub, createRAGEnricher, createRateLimitGuardrail, createResponder, createRunner, createSSETransport, createSemanticCache, createSemanticCacheGuardrail, createSlidingWindowStrategy, createStreamChannel, createStreamingRunner, createTestEmbedder, createTokenBasedStrategy, createToolGuardrail, createToxicityStreamingGuardrail, createTruncationSummarizer, createUntrustedContentGuardrail, createVPTreeIndex, detectPII, detectPromptInjection, estimateCost, extractJsonFromOutput, filterStream, hasPendingApprovals, isAgentRunning, mapStream, markUntrustedContent, mcpCallTool, mcpGetPrompt, mcpReadResource, mcpSyncResources, mergeStreams, parallel, parseHttpStatus, parseRetryAfter, pickBestResult, pipeThrough, redactPII, runAgentRequirement, sanitizeInjection, selectAgent, sequential, supervisor, tapStream, validateBaseURL, when, withBudget, withFallback, withModelSelection, withRetry, withStructuredOutput };