@directive-run/ai 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -31
- package/dist/anthropic.cjs +1 -1
- package/dist/anthropic.cjs.map +1 -1
- package/dist/anthropic.d.cts +5 -9
- package/dist/anthropic.d.ts +5 -9
- package/dist/anthropic.js +1 -1
- package/dist/anthropic.js.map +1 -1
- package/dist/gemini.cjs +3 -0
- package/dist/gemini.cjs.map +1 -0
- package/dist/gemini.d.cts +93 -0
- package/dist/gemini.d.ts +93 -0
- package/dist/gemini.js +3 -0
- package/dist/gemini.js.map +1 -0
- package/dist/index.cjs +117 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1376 -2106
- package/dist/index.d.ts +1376 -2106
- package/dist/index.js +117 -45
- package/dist/index.js.map +1 -1
- package/dist/multi-agent-orchestrator-CxL8ycw_.d.cts +2290 -0
- package/dist/multi-agent-orchestrator-uMp8bLfV.d.ts +2290 -0
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts +3 -2
- package/dist/ollama.d.ts +3 -2
- package/dist/ollama.js.map +1 -1
- package/dist/openai.cjs +2 -2
- package/dist/openai.cjs.map +1 -1
- package/dist/openai.d.cts +4 -8
- package/dist/openai.d.ts +4 -8
- package/dist/openai.js +2 -2
- package/dist/openai.js.map +1 -1
- package/dist/semantic-cache-F0psCRuz.d.cts +271 -0
- package/dist/semantic-cache-F0psCRuz.d.ts +271 -0
- package/dist/testing.cjs +42 -7
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +365 -5
- package/dist/testing.d.ts +365 -5
- package/dist/testing.js +42 -7
- package/dist/testing.js.map +1 -1
- package/dist/types-Co4BzMiH.d.cts +1373 -0
- package/dist/types-Co4BzMiH.d.ts +1373 -0
- package/package.json +7 -2
- package/dist/types-Bbar7yKz.d.cts +0 -304
- package/dist/types-Bbar7yKz.d.ts +0 -304
package/dist/index.d.cts
CHANGED
|
@@ -1,517 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { G as GuardrailFn, I as InputGuardrailData, O as OutputGuardrailData, S as SchemaValidator, T as ToolCallGuardrailData, A as AgentLike, M as Message, a as AdapterHooks, b as AgentRunner, c as ApprovalState, d as AgentState, R as RunOptions, e as RunResult, D as DebugEvent, B as BreakpointState, f as GoalResult } from './types-Co4BzMiH.cjs';
|
|
2
|
+
export { g as AgentCircuitBreakerConfig, h as AgentCompleteEvent, i as AgentErrorEvent, j as AgentHealthState, k as AgentRetryConfig, l as AgentRetryEvent, m as AgentSelectionStrategy, n as AgentStartEvent, o as ApprovalRequest, p as ApprovalRequestEvent, q as ApprovalResponseEvent, r as BreakpointConfig, s as BreakpointContext, t as BreakpointHitEvent, u as BreakpointModifications, v as BreakpointRequest, w as BreakpointResumedEvent, x as BreakpointState, y as BreakpointType, C as Checkpoint, z as CheckpointContext, E as CheckpointDiff, F as CheckpointLocalState, H as CheckpointProgress, J as CheckpointRestoreEvent, K as CheckpointSaveEvent, L as CheckpointStore, N as ConstraintEvaluateEvent, P as CrossAgentDerivationFn, Q as CrossAgentSnapshot, U as DagCheckpointState, V as DagExecutionContext, W as DagNode, X as DagNodeStatus, Y as DagNodeUpdateEvent, Z as DagPattern, _ as DebateCheckpointState, $ as DebateRoundEvent, a0 as DebugEventBase, a1 as DebugEventType, a2 as DerivationUpdateEvent, a3 as GoalCheckpointConfig, a4 as GoalCheckpointState, a5 as GoalMetrics, a6 as GoalNode, a7 as GoalPattern, a8 as GoalStepMetrics, a9 as GuardrailCheckEvent, aa as GuardrailContext, ab as GuardrailError, ac as GuardrailErrorCode, ad as GuardrailResult, ae as GuardrailRetryConfig, af as GuardrailsConfig, ag as HandoffCompleteEvent, ah as HandoffStartEvent, ai as HealthMonitorConfig, aj as InMemoryCheckpointStore, ak as InMemoryCheckpointStoreOptions, al as MAX_BREAKPOINT_HISTORY, am as MultiAgentBreakpointType, an as MultiAgentCheckpointLocalState, ao as MultiAgentLifecycleHooks, ap as MultiAgentSelfHealingConfig, aq as NamedGuardrail, ar as OrchestratorConstraint, as as OrchestratorDebugConfig, at as OrchestratorLifecycleHooks, au as OrchestratorResolver, av as OrchestratorResolverContext, aw as OrchestratorState, ax as PatternCheckpointBase, ay as PatternCheckpointConfig, az as PatternCheckpointState, aA as PatternCompleteEvent, aB as PatternStartEvent, aC as RaceCancelledEvent, aD as RaceStartEvent, aE as RaceWinnerEvent, aF as ReflectCheckpointState, aG as ReflectionIterationEvent, aH as RejectedRequest, aI as RelaxationContext, aJ as RelaxationRecord, aK as RelaxationStrategy, aL as RelaxationTier, aM as RerouteDebugEvent, aN as RerouteEvent, aO as ResolverCompleteEvent, aP as ResolverErrorEvent, aQ as ResolverStartEvent, aR as SchemaValidationResult, aS as Scratchpad, aT as ScratchpadUpdateEvent, aU as SelfHealingConfig, aV as SequentialCheckpointState, aW as SingleAgentCheckpointLocalState, aX as StreamingCallbackRunner, aY as SupervisorCheckpointState, aZ as TokenUsage, a_ as ToolCall, a$ as createBreakpointId, b0 as createCheckpointId, b1 as createInitialBreakpointState, b2 as isGuardrailError, b3 as matchBreakpoint, b4 as validateCheckpoint } from './types-Co4BzMiH.cjs';
|
|
3
|
+
import { E as ExecutionPattern, S as SerializedPattern, A as AgentHealthMetrics, D as DebugTimeline, H as HealthMonitor } from './multi-agent-orchestrator-CxL8ycw_.cjs';
|
|
4
|
+
export { a as AgentMemory, b as AgentMemoryConfig, c as AgentOrchestrator, d as AgentRegistration, e as AgentRegistry, B as BackpressureStrategy, f as DebateConfig, g as DebatePattern, h as DebateResult, i as DebugTimelineListener, j as DebugTimelineOptions, k as DoneChunk, l as ErrorChunk, G as GuardrailTriggeredChunk, m as HandoffRequest, n as HandoffResult, o as HealthCircuitState, M as MemoryManageResult, p as MemoryState, q as MemoryStrategy, r as MemoryStrategyConfig, s as MemoryStrategyResult, t as MergedTaggedStreamResult, u as MessageChunk, v as MessageSummarizer, w as MultiAgentOrchestrator, x as MultiAgentOrchestratorOptions, y as MultiAgentRunCallOptions, z as MultiAgentState, C as MultiplexedStreamChunk, F as MultiplexedStreamResult, O as OrchestratorOptions, I as OrchestratorStreamChunk, J as OrchestratorStreamResult, P as ParallelPattern, K as ProgressChunk, R as RacePattern, L as RaceResult, N as RaceSuccessEntry, Q as ReflectIterationRecord, T as ReflectPattern, U as ReflectionConfig, V as ReflectionContext, W as ReflectionEvaluation, X as ReflectionEvaluator, Y as ReflectionExhaustedError, Z as RunAgentRequirement, _ as RunCallOptions, $ as SafeParseResult, a0 as SafeParseable, a1 as Semaphore, a2 as SequentialPattern, a3 as SerializedDagNode, a4 as SerializedGoalNode, a5 as SpawnOnConditionOptions, a6 as SpawnPoolConfig, a7 as StreamChunk, a8 as StreamRunOptions, a9 as StreamRunner, aa as StreamingGuardrail, ab as StreamingGuardrailResult, ac as StreamingRunResult, ad as StructuredOutputConfig, ae as StructuredOutputError, af as SupervisorPattern, ag as TokenChunk, ah as ToolEndChunk, ai as ToolStartChunk, aj as adaptOutputGuardrail, ak as aggregateTokens, al as allReadyStrategy, am as capabilityRoute, an as collectOutputs, ao as collectTokens, ap as combineStreamingGuardrails, aq as composePatterns, ar as concatResults, as as costEfficientStrategy, at as createAgentMemory, au as createAgentOrchestrator, av as createDebugTimeline, aw as createDebugTimelinePlugin, ax as createHealthMonitor, ay as createHybridStrategy, az as createKeyPointsSummarizer, aA as createLLMSummarizer, aB as createLengthStreamingGuardrail, aC as createMultiAgentOrchestrator, aD as createPatternStreamingGuardrail, aE as createSlidingWindowStrategy, aF as createStreamingRunner, aG as createTokenBasedStrategy, aH as createToxicityStreamingGuardrail, aI as createTruncationSummarizer, aJ as dag, aK as debate, aL as derivedConstraint, aM as diffCheckpoints, aN as extractJsonFromOutput, aO as filterStream, aP as findAgentsByCapability, aQ as forkFromCheckpoint, aR as getCheckpointProgress, aS as getPatternStep, aT as goal, aU as highestImpactStrategy, aV as mapStream, aW as mergeTaggedStreams, aX as parallel, aY as patternFromJSON, aZ as patternToJSON, a_ as pickBestResult, a$ as race, b0 as reflect, b1 as runAgentRequirement, b2 as runDebate, b3 as selectAgent, b4 as sequential, b5 as spawnOnCondition, b6 as spawnPool, b7 as supervisor, b8 as tapStream, b9 as withReflection, ba as withStructuredOutput } from './multi-agent-orchestrator-CxL8ycw_.cjs';
|
|
3
5
|
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 {
|
|
5
|
-
|
|
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>;
|
|
6
|
+
import { ModuleSchema, Plugin } from '@directive-run/core';
|
|
7
|
+
import { E as Embedding, a as EmbedderFn } from './semantic-cache-F0psCRuz.cjs';
|
|
8
|
+
export { B as BatchedEmbedder, C as CacheEntry, b as CacheLookupResult, c as CacheStats, S as SemanticCache, d as SemanticCacheConfig, e as SemanticCacheStorage, f as createBatchedEmbedder, g as createInMemoryStorage, h as createSemanticCache, i as createSemanticCacheGuardrail, j as createTestEmbedder } from './semantic-cache-F0psCRuz.cjs';
|
|
515
9
|
|
|
516
10
|
/**
|
|
517
11
|
* Built-in guardrails for AI adapter — PII, moderation, rate limiting, tool allowlists, schema validation.
|
|
@@ -632,7 +126,7 @@ declare function createContentFilterGuardrail(options: {
|
|
|
632
126
|
}): GuardrailFn<OutputGuardrailData>;
|
|
633
127
|
|
|
634
128
|
/**
|
|
635
|
-
*
|
|
129
|
+
* Agent utilities — createRunner, estimateCost, state queries, URL validation.
|
|
636
130
|
*/
|
|
637
131
|
|
|
638
132
|
/** Check if agent is currently running. */
|
|
@@ -664,11 +158,11 @@ interface ParsedResponse {
|
|
|
664
158
|
/** Options for creating an AgentRunner from buildRequest/parseResponse */
|
|
665
159
|
interface CreateRunnerOptions {
|
|
666
160
|
fetch?: typeof globalThis.fetch;
|
|
667
|
-
buildRequest: (agent: AgentLike, input: string, messages: Message
|
|
161
|
+
buildRequest: (agent: AgentLike, input: string, messages: Message[]) => {
|
|
668
162
|
url: string;
|
|
669
163
|
init: RequestInit;
|
|
670
164
|
};
|
|
671
|
-
parseResponse: (response: Response, messages: Message
|
|
165
|
+
parseResponse: (response: Response, messages: Message[]) => Promise<ParsedResponse>;
|
|
672
166
|
parseOutput?: <T>(text: string) => T;
|
|
673
167
|
/** Lifecycle hooks for tracing, logging, and metrics */
|
|
674
168
|
hooks?: AdapterHooks;
|
|
@@ -719,490 +213,124 @@ interface CreateRunnerOptions {
|
|
|
719
213
|
declare function createRunner(options: CreateRunnerOptions): AgentRunner;
|
|
720
214
|
|
|
721
215
|
/**
|
|
722
|
-
*
|
|
216
|
+
* Middleware composition utility — left-to-right pipeline for AgentRunner wrappers.
|
|
217
|
+
*
|
|
218
|
+
* Each middleware is a function that takes an `AgentRunner` and returns a new
|
|
219
|
+
* `AgentRunner`. `pipe` applies them left to right, so the first middleware
|
|
220
|
+
* in the list wraps the runner first (innermost), and the last wraps last
|
|
221
|
+
* (outermost).
|
|
222
|
+
*
|
|
223
|
+
* @module
|
|
723
224
|
*
|
|
724
225
|
* @example
|
|
725
226
|
* ```typescript
|
|
726
|
-
* import {
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
* .build(),
|
|
735
|
-
*
|
|
736
|
-
* // Quick shorthand
|
|
737
|
-
* pause: when<MyFacts>(f => f.errors > 3)
|
|
738
|
-
* .require({ type: 'PAUSE' }),
|
|
739
|
-
* }
|
|
227
|
+
* import { pipe, withRetry, withFallback, withBudget } from '@directive-run/ai';
|
|
228
|
+
*
|
|
229
|
+
* const runner = pipe(
|
|
230
|
+
* baseRunner,
|
|
231
|
+
* withFallback([anthropicRunner, openaiRunner]),
|
|
232
|
+
* withRetry({ maxRetries: 3 }),
|
|
233
|
+
* withBudget({ budgets: [{ window: 'hour', maxCost: 5, pricing }] }),
|
|
234
|
+
* );
|
|
740
235
|
* ```
|
|
741
236
|
*/
|
|
742
237
|
|
|
743
|
-
|
|
744
|
-
|
|
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
|
-
}
|
|
238
|
+
/** A function that wraps an AgentRunner, returning a new AgentRunner. */
|
|
239
|
+
type RunnerMiddleware = (runner: AgentRunner) => AgentRunner;
|
|
753
240
|
/**
|
|
754
|
-
*
|
|
241
|
+
* Compose middleware left-to-right onto a base runner.
|
|
755
242
|
*
|
|
756
|
-
* @
|
|
757
|
-
*
|
|
758
|
-
*
|
|
759
|
-
* .when(f => f.confidence < 0.7)
|
|
760
|
-
* .require({ type: 'ESCALATE' })
|
|
761
|
-
* .priority(50)
|
|
762
|
-
* .build();
|
|
763
|
-
* ```
|
|
243
|
+
* @param runner - The base `AgentRunner` to wrap.
|
|
244
|
+
* @param middlewares - One or more middleware functions to apply in order.
|
|
245
|
+
* @returns A new `AgentRunner` with all middleware applied.
|
|
764
246
|
*/
|
|
765
|
-
declare function
|
|
766
|
-
|
|
767
|
-
|
|
247
|
+
declare function pipe(runner: AgentRunner, ...middlewares: RunnerMiddleware[]): AgentRunner;
|
|
248
|
+
|
|
249
|
+
type MermaidDirection = "LR" | "TD" | "TB" | "RL" | "BT";
|
|
250
|
+
interface MermaidNodeShapes {
|
|
251
|
+
/** Shape for agent nodes. @default "square" */
|
|
252
|
+
agent?: "square" | "round" | "stadium" | "hexagon";
|
|
253
|
+
/** Shape for virtual nodes (Input, Output, Merge). @default "circle" */
|
|
254
|
+
virtual?: "circle" | "square" | "round" | "stadium";
|
|
768
255
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
*/
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
|
|
256
|
+
interface MermaidOptions {
|
|
257
|
+
/** Graph flow direction. @default "LR" */
|
|
258
|
+
direction?: MermaidDirection;
|
|
259
|
+
/** Emits %%{init}%% preamble when set. */
|
|
260
|
+
theme?: "default" | "dark" | "forest" | "neutral";
|
|
261
|
+
/** Node shape overrides. */
|
|
262
|
+
shapes?: MermaidNodeShapes;
|
|
776
263
|
}
|
|
777
264
|
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
265
|
+
* Convert an execution pattern to a Mermaid diagram string.
|
|
266
|
+
*
|
|
267
|
+
* Accepts both runtime `ExecutionPattern` (with function callbacks) and
|
|
268
|
+
* pre-serialized `SerializedPattern`. Normalizes internally via `patternToJSON()`
|
|
269
|
+
* when it detects function-valued fields.
|
|
781
270
|
*
|
|
782
271
|
* @example
|
|
783
272
|
* ```typescript
|
|
784
|
-
* const
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
* //
|
|
788
|
-
*
|
|
789
|
-
* .require({ type: 'HALT' })
|
|
790
|
-
* .withPriority(100);
|
|
273
|
+
* const p = dag({ fetch: { agent: "fetcher" }, report: { agent: "reporter", deps: ["fetch"] } });
|
|
274
|
+
* console.log(patternToMermaid(p, { direction: "TD" }));
|
|
275
|
+
* // graph TD
|
|
276
|
+
* // fetch[fetcher]
|
|
277
|
+
* // fetch[fetcher] --> report[reporter]
|
|
791
278
|
* ```
|
|
279
|
+
*
|
|
280
|
+
* @throws {Error} If pattern type is not one of the 8 known types.
|
|
792
281
|
*/
|
|
793
|
-
declare function
|
|
282
|
+
declare function patternToMermaid(pattern: ExecutionPattern<unknown> | SerializedPattern, options?: MermaidOptions): string;
|
|
794
283
|
|
|
795
284
|
/**
|
|
796
|
-
*
|
|
285
|
+
* Agent-to-Agent Communication Protocol
|
|
797
286
|
*
|
|
798
|
-
* Provides
|
|
799
|
-
*
|
|
800
|
-
* - Sequential pipelines
|
|
801
|
-
* - Supervisor patterns with worker delegation
|
|
802
|
-
* - Constraint-driven agent selection
|
|
287
|
+
* Provides structured communication channels between agents for coordination,
|
|
288
|
+
* delegation, and knowledge sharing without central orchestration.
|
|
803
289
|
*
|
|
804
290
|
* @example
|
|
805
291
|
* ```typescript
|
|
806
|
-
* import {
|
|
292
|
+
* import { createAgentNetwork, createMessageBus } from '@directive-run/ai';
|
|
807
293
|
*
|
|
808
|
-
* const
|
|
294
|
+
* const messageBus = createMessageBus();
|
|
295
|
+
*
|
|
296
|
+
* const network = createAgentNetwork({
|
|
297
|
+
* bus: messageBus,
|
|
809
298
|
* agents: {
|
|
810
|
-
* researcher: {
|
|
811
|
-
* writer: {
|
|
812
|
-
* reviewer: {
|
|
813
|
-
* },
|
|
814
|
-
* patterns: {
|
|
815
|
-
* parallelResearch: {
|
|
816
|
-
* type: 'parallel',
|
|
817
|
-
* agents: ['researcher', 'researcher', 'researcher'],
|
|
818
|
-
* merge: (results) => combineResearch(results),
|
|
819
|
-
* },
|
|
299
|
+
* researcher: { capabilities: ['search', 'analyze'] },
|
|
300
|
+
* writer: { capabilities: ['draft', 'edit'] },
|
|
301
|
+
* reviewer: { capabilities: ['review', 'approve'] },
|
|
820
302
|
* },
|
|
821
303
|
* });
|
|
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
304
|
*
|
|
833
|
-
*
|
|
834
|
-
*
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
* } finally {
|
|
840
|
-
* release();
|
|
841
|
-
* }
|
|
842
|
-
* }
|
|
305
|
+
* // Agents can send messages to each other
|
|
306
|
+
* await network.send('researcher', 'writer', {
|
|
307
|
+
* type: 'DELEGATION',
|
|
308
|
+
* task: 'Draft an article based on this research',
|
|
309
|
+
* context: { findings: [...] },
|
|
310
|
+
* });
|
|
843
311
|
* ```
|
|
844
312
|
*/
|
|
845
|
-
|
|
846
|
-
|
|
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 {
|
|
313
|
+
/** Base message structure */
|
|
314
|
+
interface AgentMessage {
|
|
936
315
|
id: string;
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
316
|
+
type: AgentMessageType;
|
|
317
|
+
from: string;
|
|
318
|
+
to: string | string[] | "*";
|
|
319
|
+
timestamp: number;
|
|
320
|
+
correlationId?: string;
|
|
321
|
+
replyTo?: string;
|
|
322
|
+
priority?: "low" | "normal" | "high" | "urgent";
|
|
323
|
+
ttlMs?: number;
|
|
324
|
+
metadata?: Record<string, unknown>;
|
|
942
325
|
}
|
|
943
|
-
/**
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
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;
|
|
326
|
+
/** Message types for agent communication */
|
|
327
|
+
type AgentMessageType = "REQUEST" | "RESPONSE" | "DELEGATION" | "DELEGATION_RESULT" | "QUERY" | "INFORM" | "SUBSCRIBE" | "UNSUBSCRIBE" | "UPDATE" | "ACK" | "NACK" | "PING" | "PONG" | "CUSTOM";
|
|
328
|
+
/** Request message */
|
|
329
|
+
interface RequestMessage extends AgentMessage {
|
|
330
|
+
type: "REQUEST";
|
|
331
|
+
action: string;
|
|
332
|
+
payload: Record<string, unknown>;
|
|
333
|
+
timeout?: number;
|
|
1206
334
|
}
|
|
1207
335
|
/** Response message */
|
|
1208
336
|
interface ResponseMessage extends AgentMessage {
|
|
@@ -1681,7 +809,7 @@ declare function detectPII(text: string, options?: {
|
|
|
1681
809
|
*/
|
|
1682
810
|
|
|
1683
811
|
/** 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";
|
|
812
|
+
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" | "checkpoint.save" | "checkpoint.restore" | "checkpoint.fork" | "checkpoint.replay";
|
|
1685
813
|
/** Single audit entry with hash chain linking */
|
|
1686
814
|
interface AuditEntry {
|
|
1687
815
|
/** Unique identifier for this entry */
|
|
@@ -2326,276 +1454,6 @@ declare function createInMemoryComplianceStorage(): ComplianceStorage;
|
|
|
2326
1454
|
*/
|
|
2327
1455
|
declare function createCompliance(config: ComplianceConfig): ComplianceInstance;
|
|
2328
1456
|
|
|
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
1457
|
/**
|
|
2600
1458
|
* Approximate Nearest Neighbor (ANN) Index for Semantic Cache
|
|
2601
1459
|
*
|
|
@@ -2820,44 +1678,227 @@ declare function pipeThrough<TIn, TOut>(source: AsyncIterable<TIn>, destination:
|
|
|
2820
1678
|
declare function mergeStreams<T>(...sources: AsyncIterable<T>[]): AsyncIterable<T>;
|
|
2821
1679
|
|
|
2822
1680
|
/**
|
|
2823
|
-
*
|
|
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).
|
|
1681
|
+
* RAG Enricher — Composable retrieval-augmented generation pipeline.
|
|
2827
1682
|
*
|
|
2828
|
-
*
|
|
1683
|
+
* Embeds a query, searches a chunk store by cosine similarity, and assembles
|
|
1684
|
+
* an enriched input string (context + history + query) for any agent.
|
|
2829
1685
|
*
|
|
2830
1686
|
* @example
|
|
2831
1687
|
* ```typescript
|
|
2832
|
-
* import {
|
|
1688
|
+
* import {
|
|
1689
|
+
* createRAGEnricher,
|
|
1690
|
+
* createJSONFileStore,
|
|
1691
|
+
* } from '@directive-run/ai';
|
|
2833
1692
|
*
|
|
2834
|
-
* const
|
|
2835
|
-
*
|
|
2836
|
-
*
|
|
2837
|
-
* maxDelayMs: 30000,
|
|
2838
|
-
* onRetry: (attempt, error, delayMs) => {
|
|
2839
|
-
* console.log(`Retry ${attempt} in ${delayMs}ms: ${error.message}`);
|
|
2840
|
-
* },
|
|
1693
|
+
* const enricher = createRAGEnricher({
|
|
1694
|
+
* embedder: myEmbedder, // Provide your own EmbedderFn
|
|
1695
|
+
* storage: createJSONFileStore({ filePath: './embeddings.json' }),
|
|
2841
1696
|
* });
|
|
2842
1697
|
*
|
|
2843
|
-
*
|
|
2844
|
-
*
|
|
2845
|
-
*
|
|
2846
|
-
*
|
|
2847
|
-
* console.error(`All ${err.retryCount} retries failed:`, err.lastError);
|
|
2848
|
-
* }
|
|
2849
|
-
* }
|
|
1698
|
+
* const enrichedInput = await enricher.enrich('How do constraints work?', {
|
|
1699
|
+
* prefix: 'User is viewing: /docs/constraints',
|
|
1700
|
+
* history: [{ role: 'user', content: 'Hello' }],
|
|
1701
|
+
* });
|
|
2850
1702
|
* ```
|
|
2851
1703
|
*/
|
|
2852
1704
|
|
|
2853
|
-
/**
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
1705
|
+
/** A document chunk with embedding and metadata */
|
|
1706
|
+
interface RAGChunk {
|
|
1707
|
+
id: string;
|
|
1708
|
+
content: string;
|
|
1709
|
+
embedding: Embedding;
|
|
1710
|
+
metadata: Record<string, unknown>;
|
|
1711
|
+
}
|
|
1712
|
+
/** Pluggable storage backend */
|
|
1713
|
+
interface RAGStorage {
|
|
1714
|
+
getChunks(): Promise<RAGChunk[]>;
|
|
1715
|
+
size(): Promise<number>;
|
|
1716
|
+
/** Optional: optimized vector search (bypasses full getChunks scan) */
|
|
1717
|
+
search?(query: Embedding, topK: number, minSimilarity: number): Promise<Array<RAGChunk & {
|
|
1718
|
+
similarity: number;
|
|
1719
|
+
}>>;
|
|
1720
|
+
/** Reload storage (clear cache, re-read from source) */
|
|
1721
|
+
reload?(): Promise<void>;
|
|
1722
|
+
/** Dispose of resources */
|
|
1723
|
+
dispose?(): void;
|
|
1724
|
+
}
|
|
1725
|
+
interface RAGEnricherConfig {
|
|
1726
|
+
/** Function to generate query embeddings */
|
|
1727
|
+
embedder: EmbedderFn;
|
|
1728
|
+
/** Storage backend for document chunks */
|
|
1729
|
+
storage: RAGStorage;
|
|
1730
|
+
/** Number of top results to return (default: 5) */
|
|
1731
|
+
topK?: number;
|
|
1732
|
+
/** Minimum similarity score to include, clamped to [0, 1] (default: 0.3) */
|
|
1733
|
+
minSimilarity?: number;
|
|
1734
|
+
/** Custom chunk formatter */
|
|
1735
|
+
formatChunk?: (chunk: RAGChunk, similarity: number) => string;
|
|
1736
|
+
/** Custom context block formatter */
|
|
1737
|
+
formatContext?: (formattedChunks: string[], query: string) => string;
|
|
1738
|
+
/** Error callback — embedder/storage errors are non-fatal by default */
|
|
1739
|
+
onError?: (error: Error) => void;
|
|
1740
|
+
}
|
|
1741
|
+
interface RAGEnrichOptions {
|
|
1742
|
+
/** Prefix line (e.g. "User is viewing: /docs/constraints") */
|
|
1743
|
+
prefix?: string;
|
|
1744
|
+
/** Conversation history */
|
|
1745
|
+
history?: Array<{
|
|
1746
|
+
role: string;
|
|
1747
|
+
content: string;
|
|
1748
|
+
}>;
|
|
1749
|
+
/** Per-call topK override */
|
|
1750
|
+
topK?: number;
|
|
1751
|
+
/** Filter chunks before ranking (e.g. by metadata tag or section) */
|
|
1752
|
+
filter?: (chunk: RAGChunk) => boolean;
|
|
1753
|
+
}
|
|
1754
|
+
interface RAGEnricher {
|
|
1755
|
+
/** Retrieve relevant chunks for a query */
|
|
1756
|
+
retrieve(query: string, topK?: number): Promise<Array<RAGChunk & {
|
|
1757
|
+
similarity: number;
|
|
1758
|
+
}>>;
|
|
1759
|
+
/** Retrieve + format into an enriched input string */
|
|
1760
|
+
enrich(input: string, options?: RAGEnrichOptions): Promise<string>;
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Create a RAG enricher that retrieves relevant document chunks and
|
|
1764
|
+
* assembles enriched input for an agent.
|
|
1765
|
+
*/
|
|
1766
|
+
declare function createRAGEnricher(config: RAGEnricherConfig): RAGEnricher;
|
|
1767
|
+
interface JSONFileStoreOptions {
|
|
1768
|
+
/** Absolute or relative path to the JSON embeddings file */
|
|
1769
|
+
filePath: string;
|
|
1770
|
+
/** Optional transform from raw JSON entries to RAGChunk */
|
|
1771
|
+
mapEntry?: (entry: Record<string, unknown>) => RAGChunk;
|
|
1772
|
+
/** Cache TTL in ms. 0 = cache forever (default) */
|
|
1773
|
+
ttlMs?: number;
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Create a RAGStorage backed by a JSON file (lazy-loaded, cached in memory).
|
|
1777
|
+
* Uses dynamic `import('node:fs')` for isomorphic safety.
|
|
1778
|
+
*/
|
|
1779
|
+
declare function createJSONFileStore(options: JSONFileStoreOptions): RAGStorage;
|
|
1780
|
+
|
|
1781
|
+
/**
|
|
1782
|
+
* SSE Transport — Wrap a streamable source into an HTTP Server-Sent Events
|
|
1783
|
+
* response.
|
|
1784
|
+
*
|
|
1785
|
+
* Framework-agnostic: uses the WinterCG `Response` constructor (Node 18+,
|
|
1786
|
+
* Deno, Bun, Cloudflare Workers, Next.js).
|
|
1787
|
+
*
|
|
1788
|
+
* @example
|
|
1789
|
+
* ```typescript
|
|
1790
|
+
* import {
|
|
1791
|
+
* createSSETransport,
|
|
1792
|
+
* createAgentOrchestrator,
|
|
1793
|
+
* createStreamingRunner,
|
|
1794
|
+
* } from '@directive-run/ai';
|
|
1795
|
+
*
|
|
1796
|
+
* const transport = createSSETransport({
|
|
1797
|
+
* maxResponseChars: 10_000,
|
|
1798
|
+
* errorMessages: {
|
|
1799
|
+
* INPUT_GUARDRAIL_FAILED: 'Your message was flagged by our safety filter.',
|
|
1800
|
+
* },
|
|
1801
|
+
* });
|
|
1802
|
+
*
|
|
1803
|
+
* // Next.js route handler
|
|
1804
|
+
* export async function POST(req: Request) {
|
|
1805
|
+
* const { message } = await req.json();
|
|
1806
|
+
* return transport.toResponse(streamable, 'docs-qa', message);
|
|
1807
|
+
* }
|
|
1808
|
+
* ```
|
|
1809
|
+
*/
|
|
1810
|
+
/** Async iterable of string tokens with result promise and abort */
|
|
1811
|
+
interface SSETokenStream extends AsyncIterable<string> {
|
|
1812
|
+
result: Promise<unknown>;
|
|
1813
|
+
abort(): void;
|
|
1814
|
+
}
|
|
1815
|
+
/** Any object with a .stream() method compatible with SSE transport */
|
|
1816
|
+
interface SSEStreamable {
|
|
1817
|
+
stream(agentId: string, input: string, opts?: {
|
|
1818
|
+
signal?: AbortSignal;
|
|
1819
|
+
}): SSETokenStream;
|
|
1820
|
+
}
|
|
1821
|
+
type SSEEvent = {
|
|
1822
|
+
type: "text";
|
|
1823
|
+
text: string;
|
|
1824
|
+
} | {
|
|
1825
|
+
type: "truncated";
|
|
1826
|
+
text: string;
|
|
1827
|
+
} | {
|
|
1828
|
+
type: "done";
|
|
1829
|
+
} | {
|
|
1830
|
+
type: "error";
|
|
1831
|
+
message: string;
|
|
1832
|
+
} | {
|
|
1833
|
+
type: "heartbeat";
|
|
1834
|
+
timestamp: number;
|
|
1835
|
+
};
|
|
1836
|
+
interface SSETransportConfig {
|
|
1837
|
+
/** Truncate response after this many characters (default: Infinity) */
|
|
1838
|
+
maxResponseChars?: number;
|
|
1839
|
+
/** Message shown when response is truncated */
|
|
1840
|
+
truncationMessage?: string;
|
|
1841
|
+
/** Heartbeat interval in ms (default: 0 = disabled) */
|
|
1842
|
+
heartbeatIntervalMs?: number;
|
|
1843
|
+
/** Map error codes/types to user-facing messages */
|
|
1844
|
+
errorMessages?: Record<string, string> | ((error: unknown) => string);
|
|
1845
|
+
/** Extra headers merged into the SSE response */
|
|
1846
|
+
headers?: Record<string, string>;
|
|
1847
|
+
}
|
|
1848
|
+
interface SSETransport {
|
|
1849
|
+
/** Create a full HTTP Response with SSE headers */
|
|
1850
|
+
toResponse(source: SSEStreamable, agentId: string, input: string, opts?: {
|
|
1851
|
+
signal?: AbortSignal;
|
|
1852
|
+
}): Response;
|
|
1853
|
+
/** Return just the ReadableStream (for Express/Koa `res.write()`) */
|
|
1854
|
+
toStream(source: SSEStreamable, agentId: string, input: string, opts?: {
|
|
1855
|
+
signal?: AbortSignal;
|
|
1856
|
+
}): ReadableStream<Uint8Array>;
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* Create an SSE transport that converts a token stream into Server-Sent Events.
|
|
1860
|
+
*/
|
|
1861
|
+
declare function createSSETransport(config?: SSETransportConfig): SSETransport;
|
|
1862
|
+
|
|
1863
|
+
/**
|
|
1864
|
+
* P2: Intelligent Retry — HTTP-status-aware retry wrapper for AgentRunner.
|
|
1865
|
+
*
|
|
1866
|
+
* Respects 429 Retry-After headers, uses exponential backoff with jitter for 503,
|
|
1867
|
+
* and never retries client errors (400/401/403/404/422).
|
|
1868
|
+
*
|
|
1869
|
+
* @module
|
|
1870
|
+
*
|
|
1871
|
+
* @example
|
|
1872
|
+
* ```typescript
|
|
1873
|
+
* import { withRetry, RetryExhaustedError } from '@directive-run/ai';
|
|
1874
|
+
*
|
|
1875
|
+
* const runner = withRetry(baseRunner, {
|
|
1876
|
+
* maxRetries: 3,
|
|
1877
|
+
* baseDelayMs: 1000,
|
|
1878
|
+
* maxDelayMs: 30000,
|
|
1879
|
+
* onRetry: (attempt, error, delayMs) => {
|
|
1880
|
+
* console.log(`Retry ${attempt} in ${delayMs}ms: ${error.message}`);
|
|
1881
|
+
* },
|
|
1882
|
+
* });
|
|
1883
|
+
*
|
|
1884
|
+
* try {
|
|
1885
|
+
* const result = await runner(agent, input);
|
|
1886
|
+
* } catch (err) {
|
|
1887
|
+
* if (err instanceof RetryExhaustedError) {
|
|
1888
|
+
* console.error(`All ${err.retryCount} retries failed:`, err.lastError);
|
|
1889
|
+
* }
|
|
1890
|
+
* }
|
|
1891
|
+
* ```
|
|
1892
|
+
*/
|
|
1893
|
+
|
|
1894
|
+
/**
|
|
1895
|
+
* Configuration for the intelligent retry wrapper.
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* ```typescript
|
|
1899
|
+
* const config: RetryConfig = {
|
|
1900
|
+
* maxRetries: 3,
|
|
1901
|
+
* baseDelayMs: 1000,
|
|
2861
1902
|
* maxDelayMs: 30000,
|
|
2862
1903
|
* isRetryable: (error) => !error.message.includes("invalid API key"),
|
|
2863
1904
|
* onRetry: (attempt, error, delayMs) => {
|
|
@@ -3212,726 +2253,756 @@ declare function byPattern(pattern: RegExp, model: string): ModelRule;
|
|
|
3212
2253
|
declare function withModelSelection(runner: AgentRunner, configOrRules: ModelSelectionConfig | ModelRule[]): AgentRunner;
|
|
3213
2254
|
|
|
3214
2255
|
/**
|
|
3215
|
-
*
|
|
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.
|
|
2256
|
+
* P5: Batch Queue — Application-level batching for agent calls.
|
|
3219
2257
|
*
|
|
3220
|
-
*
|
|
2258
|
+
* Accumulates calls and flushes them in batches to reduce overhead.
|
|
2259
|
+
* Each `submit()` returns a promise that resolves when its individual call completes.
|
|
2260
|
+
* Batches execute calls in parallel up to a configurable concurrency limit.
|
|
3221
2261
|
*
|
|
3222
2262
|
* @module
|
|
3223
2263
|
*
|
|
3224
2264
|
* @example
|
|
3225
2265
|
* ```typescript
|
|
3226
|
-
* import {
|
|
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
|
-
* });
|
|
2266
|
+
* import { createBatchQueue } from '@directive-run/ai';
|
|
3233
2267
|
*
|
|
3234
|
-
* const
|
|
3235
|
-
*
|
|
3236
|
-
*
|
|
2268
|
+
* const queue = createBatchQueue(runner, {
|
|
2269
|
+
* maxBatchSize: 20,
|
|
2270
|
+
* maxWaitMs: 5000,
|
|
2271
|
+
* concurrency: 5,
|
|
3237
2272
|
* });
|
|
3238
2273
|
*
|
|
3239
|
-
*
|
|
3240
|
-
*
|
|
3241
|
-
*
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
* Zod-compatible schema duck type — any object with a `safeParse` method.
|
|
2274
|
+
* // Submit calls — they batch automatically
|
|
2275
|
+
* const [r1, r2, r3] = await Promise.all([
|
|
2276
|
+
* queue.submit(agent, "input 1"),
|
|
2277
|
+
* queue.submit(agent, "input 2"),
|
|
2278
|
+
* queue.submit(agent, "input 3"),
|
|
2279
|
+
* ]);
|
|
3246
2280
|
*
|
|
3247
|
-
*
|
|
3248
|
-
*
|
|
2281
|
+
* // Force immediate flush
|
|
2282
|
+
* await queue.flush();
|
|
3249
2283
|
*
|
|
3250
|
-
*
|
|
3251
|
-
*
|
|
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
|
-
* };
|
|
2284
|
+
* // Clean up (flushes remaining calls)
|
|
2285
|
+
* await queue.dispose();
|
|
3266
2286
|
* ```
|
|
3267
2287
|
*/
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
/**
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
error?: {
|
|
3277
|
-
message?: string;
|
|
3278
|
-
issues?: Array<{
|
|
3279
|
-
message: string;
|
|
3280
|
-
}>;
|
|
3281
|
-
};
|
|
2288
|
+
|
|
2289
|
+
interface BatchQueueConfig {
|
|
2290
|
+
/** Maximum number of calls per batch. @default 20 */
|
|
2291
|
+
maxBatchSize?: number;
|
|
2292
|
+
/** Maximum time to wait before flushing (ms). @default 5000 */
|
|
2293
|
+
maxWaitMs?: number;
|
|
2294
|
+
/** Number of calls to run in parallel within a batch. @default 5 */
|
|
2295
|
+
concurrency?: number;
|
|
3282
2296
|
}
|
|
3283
|
-
interface
|
|
3284
|
-
/**
|
|
3285
|
-
|
|
3286
|
-
/**
|
|
3287
|
-
|
|
3288
|
-
/**
|
|
3289
|
-
|
|
3290
|
-
/**
|
|
3291
|
-
|
|
2297
|
+
interface BatchQueue {
|
|
2298
|
+
/** Submit a call to the queue. Returns a promise that resolves when the call completes. */
|
|
2299
|
+
submit<T = unknown>(agent: AgentLike, input: string, options?: RunOptions): Promise<RunResult<T>>;
|
|
2300
|
+
/** Flush all pending calls immediately. */
|
|
2301
|
+
flush(): Promise<void>;
|
|
2302
|
+
/** Get the number of pending calls. */
|
|
2303
|
+
readonly pending: number;
|
|
2304
|
+
/** Dispose the queue, flushing remaining calls. */
|
|
2305
|
+
dispose(): Promise<void>;
|
|
3292
2306
|
}
|
|
3293
|
-
/** Default JSON extractor — finds the first `{...}` or `[...]` in output. */
|
|
3294
|
-
declare function extractJsonFromOutput(output: string): unknown;
|
|
3295
2307
|
/**
|
|
3296
|
-
*
|
|
2308
|
+
* Create a batch queue for grouping agent calls.
|
|
3297
2309
|
*
|
|
3298
2310
|
* @example
|
|
3299
2311
|
* ```typescript
|
|
3300
|
-
*
|
|
3301
|
-
*
|
|
3302
|
-
*
|
|
3303
|
-
*
|
|
3304
|
-
* confidence: z.number().min(0).max(1),
|
|
2312
|
+
* const queue = createBatchQueue(runner, {
|
|
2313
|
+
* maxBatchSize: 20,
|
|
2314
|
+
* maxWaitMs: 5000,
|
|
2315
|
+
* concurrency: 5,
|
|
3305
2316
|
* });
|
|
3306
2317
|
*
|
|
3307
|
-
*
|
|
3308
|
-
*
|
|
3309
|
-
*
|
|
3310
|
-
*
|
|
2318
|
+
* // Submit multiple calls — they batch automatically
|
|
2319
|
+
* const [result1, result2, result3] = await Promise.all([
|
|
2320
|
+
* queue.submit(agent, "input 1"),
|
|
2321
|
+
* queue.submit(agent, "input 2"),
|
|
2322
|
+
* queue.submit(agent, "input 3"),
|
|
2323
|
+
* ]);
|
|
3311
2324
|
*
|
|
3312
|
-
*
|
|
3313
|
-
*
|
|
2325
|
+
* // Clean up
|
|
2326
|
+
* await queue.dispose();
|
|
3314
2327
|
* ```
|
|
3315
2328
|
*/
|
|
3316
|
-
declare function
|
|
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
|
-
}
|
|
2329
|
+
declare function createBatchQueue(runner: AgentRunner, config?: BatchQueueConfig): BatchQueue;
|
|
3322
2330
|
|
|
3323
2331
|
/**
|
|
3324
|
-
*
|
|
2332
|
+
* P4: Constraint-Driven Provider Routing — Directive's unique differentiator.
|
|
3325
2333
|
*
|
|
3326
|
-
*
|
|
3327
|
-
*
|
|
3328
|
-
* and communication bus with sensible defaults.
|
|
2334
|
+
* Uses user-supplied constraints to select providers based on runtime state:
|
|
2335
|
+
* cost, latency, error rates, and compliance regions.
|
|
3329
2336
|
*
|
|
3330
|
-
*
|
|
3331
|
-
*
|
|
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
|
-
* });
|
|
2337
|
+
* Tracks per-provider stats (call count, error count, cost, latency) and
|
|
2338
|
+
* exposes them as {@link RoutingFacts} for constraint evaluation.
|
|
3342
2339
|
*
|
|
3343
|
-
*
|
|
3344
|
-
* ```
|
|
2340
|
+
* @module
|
|
3345
2341
|
*
|
|
3346
|
-
* @example
|
|
2342
|
+
* @example
|
|
3347
2343
|
* ```typescript
|
|
3348
|
-
*
|
|
3349
|
-
*
|
|
3350
|
-
*
|
|
3351
|
-
*
|
|
2344
|
+
* import { createConstraintRouter } from '@directive-run/ai';
|
|
2345
|
+
* import type { ConstraintRouterRunner } from '@directive-run/ai';
|
|
2346
|
+
*
|
|
2347
|
+
* const router = createConstraintRouter({
|
|
2348
|
+
* providers: [
|
|
2349
|
+
* { name: "openai", runner: openaiRunner, pricing: { inputPerMillion: 5, outputPerMillion: 15 } },
|
|
2350
|
+
* { name: "anthropic", runner: anthropicRunner, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
|
|
2351
|
+
* { name: "ollama", runner: ollamaRunner },
|
|
2352
|
+
* ],
|
|
2353
|
+
* defaultProvider: "openai",
|
|
2354
|
+
* constraints: [
|
|
2355
|
+
* { when: (facts) => facts.totalCost > 100, provider: "ollama", priority: 10 },
|
|
2356
|
+
* { when: (facts) => facts.providers["openai"]?.errorCount > 5, provider: "anthropic" },
|
|
2357
|
+
* ],
|
|
2358
|
+
* preferCheapest: true, // opt-in to cheapest-provider heuristic
|
|
2359
|
+
* onProviderSelected: (name, reason) => console.log(`Using ${name} (${reason})`),
|
|
3352
2360
|
* });
|
|
3353
2361
|
*
|
|
3354
|
-
*
|
|
3355
|
-
*
|
|
3356
|
-
* const finalResult = await tokenStream.result;
|
|
2362
|
+
* // Access runtime stats
|
|
2363
|
+
* console.log(router.facts.totalCost, router.facts.callCount);
|
|
3357
2364
|
* ```
|
|
3358
2365
|
*/
|
|
3359
2366
|
|
|
3360
|
-
/**
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
/**
|
|
2367
|
+
/**
|
|
2368
|
+
* Provider definition for the constraint router.
|
|
2369
|
+
*
|
|
2370
|
+
* Each provider has its own runner, optional pricing (for cost tracking
|
|
2371
|
+
* and cheapest-provider heuristic), and optional region tag.
|
|
2372
|
+
*/
|
|
2373
|
+
interface RoutingProvider {
|
|
2374
|
+
/** Unique name for this provider. */
|
|
2375
|
+
name: string;
|
|
2376
|
+
/** The runner to use for this provider. */
|
|
3370
2377
|
runner: AgentRunner;
|
|
3371
|
-
/**
|
|
3372
|
-
|
|
3373
|
-
|
|
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
|
-
/** Message bus for agent communication */
|
|
3403
|
-
messageBus?: {
|
|
3404
|
-
maxHistory?: number;
|
|
3405
|
-
} | MessageBus;
|
|
3406
|
-
guardrails?: {
|
|
3407
|
-
input?: Array<GuardrailFn<InputGuardrailData> | NamedGuardrail<InputGuardrailData>>;
|
|
3408
|
-
output?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
|
|
3409
|
-
streaming?: StreamingGuardrail[];
|
|
3410
|
-
};
|
|
3411
|
-
maxTokenBudget?: number;
|
|
3412
|
-
/** Cost per million tokens for cost estimation */
|
|
3413
|
-
costPerMillionTokens?: number;
|
|
3414
|
-
debug?: boolean;
|
|
3415
|
-
constraints?: Record<string, OrchestratorConstraint<Record<string, unknown>>>;
|
|
3416
|
-
resolvers?: Record<string, OrchestratorResolver<Record<string, unknown>, Requirement>>;
|
|
3417
|
-
approvals?: {
|
|
3418
|
-
/** @default true */
|
|
3419
|
-
autoApproveToolCalls?: boolean;
|
|
3420
|
-
onRequest?: (request: ApprovalRequest) => void;
|
|
3421
|
-
/** @default 300_000 */
|
|
3422
|
-
timeoutMs?: number;
|
|
3423
|
-
};
|
|
3424
|
-
retry?: AgentRetryConfig;
|
|
3425
|
-
hooks?: OrchestratorLifecycleHooks;
|
|
3426
|
-
/** P2: Intelligent retry config for the base runner. */
|
|
3427
|
-
intelligentRetry?: RetryConfig;
|
|
3428
|
-
/** P0: Fallback runners (tried in order on failure). */
|
|
3429
|
-
fallback?: {
|
|
3430
|
-
runners: AgentRunner[];
|
|
3431
|
-
config?: FallbackConfig;
|
|
3432
|
-
};
|
|
3433
|
-
/** P1: Cost budget guards. */
|
|
3434
|
-
budget?: BudgetConfig;
|
|
3435
|
-
/** P3: Model selection rules (first match wins). */
|
|
3436
|
-
modelSelection?: ModelRule[];
|
|
3437
|
-
/** P6: Structured output config (applied per-agent via agents map, or globally here). */
|
|
3438
|
-
structuredOutput?: StructuredOutputConfig;
|
|
3439
|
-
}
|
|
3440
|
-
interface StackRunOptions {
|
|
3441
|
-
/** Override output guardrails for this call */
|
|
3442
|
-
guardrails?: {
|
|
3443
|
-
output?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
|
|
3444
|
-
};
|
|
3445
|
-
/** Set to false to skip cache for this call */
|
|
3446
|
-
cache?: false;
|
|
3447
|
-
/** AbortSignal for cancellation */
|
|
3448
|
-
signal?: AbortSignal;
|
|
3449
|
-
}
|
|
3450
|
-
interface StackStreamOptions {
|
|
3451
|
-
signal?: AbortSignal;
|
|
3452
|
-
}
|
|
3453
|
-
interface TokenStream<T = string> extends AsyncIterable<string> {
|
|
3454
|
-
/** Resolves to the final run result after the stream completes */
|
|
3455
|
-
result: Promise<RunResult<T>>;
|
|
3456
|
-
/** Abort the stream */
|
|
3457
|
-
abort: () => void;
|
|
3458
|
-
}
|
|
3459
|
-
interface AgentStackState {
|
|
3460
|
-
totalTokens: number;
|
|
3461
|
-
estimatedCost: number;
|
|
3462
|
-
circuitState: CircuitState;
|
|
3463
|
-
cacheStats: CacheStats;
|
|
3464
|
-
memoryMessageCount: number;
|
|
3465
|
-
busMessageCount: number;
|
|
3466
|
-
rateLimitRemaining: number | null;
|
|
3467
|
-
}
|
|
3468
|
-
/** Options for runStructured() */
|
|
3469
|
-
interface StructuredRunOptions<_T = unknown> extends StackRunOptions {
|
|
3470
|
-
/** Validate the output. Return `true` or `{ valid: true }` on success. */
|
|
3471
|
-
validate: (value: unknown) => boolean | {
|
|
3472
|
-
valid: boolean;
|
|
3473
|
-
errors?: string[];
|
|
3474
|
-
};
|
|
3475
|
-
/** Number of retry attempts on validation failure @default 1 */
|
|
3476
|
-
retries?: number;
|
|
3477
|
-
}
|
|
3478
|
-
interface AgentStack {
|
|
3479
|
-
/** Run a single registered agent by ID */
|
|
3480
|
-
run<T = unknown>(agentId: string, input: string, options?: StackRunOptions): Promise<RunResult<T>>;
|
|
3481
|
-
/** Run and validate output against a schema, retrying on failure */
|
|
3482
|
-
runStructured<T>(agentId: string, input: string, options: StructuredRunOptions<T>): Promise<RunResult<T>>;
|
|
3483
|
-
/** Run a named execution pattern */
|
|
3484
|
-
runPattern<T = unknown>(patternId: string, input: string, options?: StackRunOptions): Promise<T>;
|
|
3485
|
-
/** Stream tokens from a single agent */
|
|
3486
|
-
stream<T = string>(agentId: string, input: string, options?: StackStreamOptions): TokenStream<T>;
|
|
3487
|
-
/** Stream full rich chunks (token, tool_start, tool_end, etc.) from a single agent */
|
|
3488
|
-
streamChunks<T = unknown>(agentId: string, input: string, options?: StackStreamOptions): StreamingRunResult<T>;
|
|
3489
|
-
/** Approve a pending approval request */
|
|
3490
|
-
approve(requestId: string): void;
|
|
3491
|
-
/** Reject a pending approval request */
|
|
3492
|
-
reject(requestId: string, reason?: string): void;
|
|
3493
|
-
/** Aggregate state across all features */
|
|
3494
|
-
getState(): AgentStackState;
|
|
3495
|
-
/** Reset all feature state */
|
|
3496
|
-
reset(): void;
|
|
3497
|
-
/** Dispose all resources */
|
|
3498
|
-
dispose(): Promise<void>;
|
|
3499
|
-
readonly orchestrator: AgentOrchestrator<Record<string, unknown>>;
|
|
3500
|
-
readonly observability: ObservabilityInstance | null;
|
|
3501
|
-
readonly messageBus: MessageBus | null;
|
|
3502
|
-
readonly coordinator: MultiAgentOrchestrator | null;
|
|
3503
|
-
readonly cache: SemanticCache | null;
|
|
3504
|
-
readonly memory: AgentMemory | null;
|
|
3505
|
-
/** Get observability timeline (spans + metrics) for debugging */
|
|
3506
|
-
getTimeline(limit?: number): {
|
|
3507
|
-
spans: readonly TraceSpan[];
|
|
3508
|
-
metrics: Record<string, AggregatedMetric>;
|
|
2378
|
+
/** Token pricing (cost per million tokens). */
|
|
2379
|
+
pricing?: {
|
|
2380
|
+
inputPerMillion: number;
|
|
2381
|
+
outputPerMillion: number;
|
|
3509
2382
|
};
|
|
2383
|
+
/** Geographic region (for compliance routing). */
|
|
2384
|
+
region?: string;
|
|
3510
2385
|
}
|
|
3511
2386
|
/**
|
|
3512
|
-
*
|
|
2387
|
+
* Runtime facts tracked by the router — exposed for user constraints.
|
|
3513
2388
|
*
|
|
3514
|
-
*
|
|
3515
|
-
* is present. Pass a pre-built instance to reuse existing objects, or pass
|
|
3516
|
-
* shorthand config to let the stack create them.
|
|
2389
|
+
* Access via the `facts` property on the returned {@link ConstraintRouterRunner}.
|
|
3517
2390
|
*/
|
|
3518
|
-
|
|
3519
|
-
|
|
2391
|
+
interface RoutingFacts {
|
|
2392
|
+
totalCost: number;
|
|
2393
|
+
callCount: number;
|
|
2394
|
+
errorCount: number;
|
|
2395
|
+
lastProvider: string | null;
|
|
2396
|
+
avgLatencyMs: number;
|
|
2397
|
+
/** Per-provider stats. */
|
|
2398
|
+
providers: Record<string, ProviderStats>;
|
|
2399
|
+
}
|
|
2400
|
+
interface ProviderStats {
|
|
2401
|
+
callCount: number;
|
|
2402
|
+
errorCount: number;
|
|
2403
|
+
totalCost: number;
|
|
2404
|
+
avgLatencyMs: number;
|
|
2405
|
+
lastErrorAt: number | null;
|
|
2406
|
+
}
|
|
2407
|
+
/** User-supplied routing constraint. */
|
|
2408
|
+
interface RoutingConstraint {
|
|
2409
|
+
/** When this constraint is active. */
|
|
2410
|
+
when: (facts: RoutingFacts) => boolean;
|
|
2411
|
+
/** The provider to route to. */
|
|
2412
|
+
provider: string;
|
|
2413
|
+
/** Priority — higher wins when multiple constraints match. @default 0 */
|
|
2414
|
+
priority?: number;
|
|
2415
|
+
}
|
|
2416
|
+
interface ConstraintRouterConfig {
|
|
2417
|
+
/** Available providers. */
|
|
2418
|
+
providers: RoutingProvider[];
|
|
2419
|
+
/** Default provider name. */
|
|
2420
|
+
defaultProvider: string;
|
|
2421
|
+
/** User-supplied routing constraints. */
|
|
2422
|
+
constraints?: RoutingConstraint[];
|
|
2423
|
+
/** Called when a provider is selected. */
|
|
2424
|
+
onProviderSelected?: (providerName: string, reason: "constraint" | "cheapest" | "default") => void;
|
|
2425
|
+
/** Error cooldown — skip a provider for this many ms after an error. @default 30000 */
|
|
2426
|
+
errorCooldownMs?: number;
|
|
2427
|
+
/**
|
|
2428
|
+
* When true, automatically prefer the cheapest available provider
|
|
2429
|
+
* (based on pricing) when no user constraint matches.
|
|
2430
|
+
* When false, the default provider is used unless a constraint overrides it.
|
|
2431
|
+
* @default false
|
|
2432
|
+
*/
|
|
2433
|
+
preferCheapest?: boolean;
|
|
2434
|
+
}
|
|
3520
2435
|
/**
|
|
3521
|
-
*
|
|
3522
|
-
*
|
|
3523
|
-
* Eliminates manual state sync boilerplate when using createAgentStack()
|
|
3524
|
-
* alongside createSystem().
|
|
3525
|
-
*
|
|
3526
|
-
* @example Using with AgentStack directly
|
|
3527
|
-
* ```typescript
|
|
3528
|
-
* const syncAI = createAISyncer(stack, (state) => {
|
|
3529
|
-
* system.events.chat.updateAIState({
|
|
3530
|
-
* totalTokens: state.totalTokens,
|
|
3531
|
-
* estimatedCost: state.estimatedCost,
|
|
3532
|
-
* circuitState: state.circuitState,
|
|
3533
|
-
* });
|
|
3534
|
-
* });
|
|
3535
|
-
* syncAI();
|
|
3536
|
-
* ```
|
|
2436
|
+
* Create a constraint-driven provider router.
|
|
3537
2437
|
*
|
|
3538
|
-
* @example
|
|
2438
|
+
* @example
|
|
3539
2439
|
* ```typescript
|
|
3540
|
-
* const
|
|
3541
|
-
*
|
|
2440
|
+
* const runner = createConstraintRouter({
|
|
2441
|
+
* providers: [
|
|
2442
|
+
* { name: "openai", runner: openaiRunner, pricing: { inputPerMillion: 5, outputPerMillion: 15 } },
|
|
2443
|
+
* { name: "anthropic", runner: anthropicRunner, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
|
|
2444
|
+
* { name: "ollama", runner: ollamaRunner },
|
|
2445
|
+
* ],
|
|
2446
|
+
* defaultProvider: "openai",
|
|
2447
|
+
* constraints: [
|
|
2448
|
+
* { when: (facts) => facts.totalCost > 100, provider: "ollama", priority: 10 },
|
|
2449
|
+
* { when: (facts) => facts.providers["openai"]?.errorCount > 5, provider: "anthropic" },
|
|
2450
|
+
* ],
|
|
3542
2451
|
* });
|
|
3543
|
-
* syncAI();
|
|
3544
2452
|
* ```
|
|
3545
2453
|
*/
|
|
2454
|
+
declare function createConstraintRouter(config: ConstraintRouterConfig): ConstraintRouterRunner;
|
|
2455
|
+
/** Helper type for accessing router facts. */
|
|
2456
|
+
type ConstraintRouterRunner = AgentRunner & {
|
|
2457
|
+
readonly facts: RoutingFacts;
|
|
2458
|
+
};
|
|
2459
|
+
|
|
3546
2460
|
/**
|
|
3547
|
-
*
|
|
3548
|
-
*
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
}
|
|
3553
|
-
/**
|
|
3554
|
-
* Create a sync function that reads the latest state from a source and
|
|
3555
|
-
* passes it to a callback (typically dispatching events into a Directive system).
|
|
2461
|
+
* DevTools Server — WebSocket-based bridge between orchestrators and DevTools UI.
|
|
2462
|
+
*
|
|
2463
|
+
* Streams debug timeline events, health metrics, breakpoint state, and system
|
|
2464
|
+
* snapshots in real-time to connected DevTools clients. Accepts commands from
|
|
2465
|
+
* clients to resume/cancel breakpoints and request snapshots.
|
|
3556
2466
|
*
|
|
3557
|
-
*
|
|
2467
|
+
* Transport-agnostic: works with any WebSocket implementation (ws, Bun, Deno)
|
|
2468
|
+
* via the {@link DevToolsTransport} interface.
|
|
2469
|
+
*
|
|
2470
|
+
* @module
|
|
3558
2471
|
*/
|
|
3559
|
-
declare function createAISyncer<S>(source: Syncable<S>, syncFn: (state: S) => void): () => void;
|
|
3560
2472
|
|
|
2473
|
+
/** A connected DevTools client */
|
|
2474
|
+
interface DevToolsClient {
|
|
2475
|
+
/** Send a JSON-serializable message to this client */
|
|
2476
|
+
send(data: string): void;
|
|
2477
|
+
/** Close the connection */
|
|
2478
|
+
close(): void;
|
|
2479
|
+
}
|
|
3561
2480
|
/**
|
|
3562
|
-
*
|
|
2481
|
+
* Transport layer for the DevTools server.
|
|
3563
2482
|
*
|
|
3564
|
-
*
|
|
3565
|
-
* an enriched input string (context + history + query) for any agent.
|
|
2483
|
+
* Implement this interface to bridge any WebSocket library (ws, Bun.serve, Deno.serve).
|
|
3566
2484
|
*
|
|
3567
|
-
* @example
|
|
2485
|
+
* @example Node.js with `ws`:
|
|
3568
2486
|
* ```typescript
|
|
3569
|
-
* import {
|
|
3570
|
-
* createRAGEnricher,
|
|
3571
|
-
* createJSONFileStore,
|
|
3572
|
-
* } from '@directive-run/ai';
|
|
2487
|
+
* import { WebSocketServer } from "ws";
|
|
3573
2488
|
*
|
|
3574
|
-
*
|
|
3575
|
-
*
|
|
3576
|
-
*
|
|
3577
|
-
* });
|
|
2489
|
+
* function createWsTransport(port: number): DevToolsTransport {
|
|
2490
|
+
* const wss = new WebSocketServer({ port });
|
|
2491
|
+
* let onConnect: ((client: DevToolsClient) => void) | null = null;
|
|
3578
2492
|
*
|
|
3579
|
-
*
|
|
3580
|
-
*
|
|
3581
|
-
*
|
|
3582
|
-
*
|
|
2493
|
+
* wss.on("connection", (ws) => {
|
|
2494
|
+
* const client: DevToolsClient = {
|
|
2495
|
+
* send: (data) => { if (ws.readyState === ws.OPEN) ws.send(data); },
|
|
2496
|
+
* close: () => ws.close(),
|
|
2497
|
+
* };
|
|
2498
|
+
* ws.on("message", (raw) => {
|
|
2499
|
+
* if (client._onMessage) client._onMessage(raw.toString());
|
|
2500
|
+
* });
|
|
2501
|
+
* ws.on("close", () => {
|
|
2502
|
+
* if (client._onClose) client._onClose();
|
|
2503
|
+
* });
|
|
2504
|
+
* onConnect?.(client);
|
|
2505
|
+
* });
|
|
2506
|
+
*
|
|
2507
|
+
* return {
|
|
2508
|
+
* onConnection(handler) { onConnect = handler; },
|
|
2509
|
+
* close() { wss.close(); },
|
|
2510
|
+
* };
|
|
2511
|
+
* }
|
|
3583
2512
|
* ```
|
|
3584
2513
|
*/
|
|
3585
|
-
|
|
3586
|
-
/**
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
embedding: Embedding;
|
|
3591
|
-
metadata: Record<string, unknown>;
|
|
3592
|
-
}
|
|
3593
|
-
/** Pluggable storage backend */
|
|
3594
|
-
interface RAGStorage {
|
|
3595
|
-
getChunks(): Promise<RAGChunk[]>;
|
|
3596
|
-
size(): Promise<number>;
|
|
3597
|
-
/** Optional: optimized vector search (bypasses full getChunks scan) */
|
|
3598
|
-
search?(query: Embedding, topK: number, minSimilarity: number): Promise<Array<RAGChunk & {
|
|
3599
|
-
similarity: number;
|
|
3600
|
-
}>>;
|
|
3601
|
-
/** Reload storage (clear cache, re-read from source) */
|
|
3602
|
-
reload?(): Promise<void>;
|
|
3603
|
-
/** Dispose of resources */
|
|
3604
|
-
dispose?(): void;
|
|
3605
|
-
}
|
|
3606
|
-
interface RAGEnricherConfig {
|
|
3607
|
-
/** Function to generate query embeddings */
|
|
3608
|
-
embedder: EmbedderFn;
|
|
3609
|
-
/** Storage backend for document chunks */
|
|
3610
|
-
storage: RAGStorage;
|
|
3611
|
-
/** Number of top results to return (default: 5) */
|
|
3612
|
-
topK?: number;
|
|
3613
|
-
/** Minimum similarity score to include, clamped to [0, 1] (default: 0.3) */
|
|
3614
|
-
minSimilarity?: number;
|
|
3615
|
-
/** Custom chunk formatter */
|
|
3616
|
-
formatChunk?: (chunk: RAGChunk, similarity: number) => string;
|
|
3617
|
-
/** Custom context block formatter */
|
|
3618
|
-
formatContext?: (formattedChunks: string[], query: string) => string;
|
|
3619
|
-
/** Error callback — embedder/storage errors are non-fatal by default */
|
|
3620
|
-
onError?: (error: Error) => void;
|
|
2514
|
+
interface DevToolsTransport {
|
|
2515
|
+
/** Register a handler for new client connections */
|
|
2516
|
+
onConnection(handler: (client: DevToolsClient, onMessage: (handler: (data: string) => void) => void, onClose: (handler: () => void) => void) => void): void;
|
|
2517
|
+
/** Shut down the transport */
|
|
2518
|
+
close(): void;
|
|
3621
2519
|
}
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
2520
|
+
/** Messages sent FROM the server TO clients */
|
|
2521
|
+
type DevToolsServerMessage = {
|
|
2522
|
+
type: "welcome";
|
|
2523
|
+
version: number;
|
|
2524
|
+
sessionId: string;
|
|
2525
|
+
timestamp: number;
|
|
2526
|
+
} | {
|
|
2527
|
+
type: "event";
|
|
2528
|
+
event: DebugEvent;
|
|
2529
|
+
} | {
|
|
2530
|
+
type: "event_batch";
|
|
2531
|
+
events: DebugEvent[];
|
|
2532
|
+
} | {
|
|
2533
|
+
type: "snapshot";
|
|
2534
|
+
data: DevToolsSnapshot;
|
|
2535
|
+
} | {
|
|
2536
|
+
type: "health";
|
|
2537
|
+
metrics: Record<string, AgentHealthMetrics>;
|
|
2538
|
+
} | {
|
|
2539
|
+
type: "breakpoints";
|
|
2540
|
+
state: BreakpointState;
|
|
2541
|
+
} | {
|
|
2542
|
+
type: "pong";
|
|
2543
|
+
timestamp: number;
|
|
2544
|
+
} | {
|
|
2545
|
+
type: "scratchpad_state";
|
|
2546
|
+
data: Record<string, unknown>;
|
|
2547
|
+
} | {
|
|
2548
|
+
type: "scratchpad_update";
|
|
2549
|
+
key: string;
|
|
2550
|
+
value: unknown;
|
|
2551
|
+
} | {
|
|
2552
|
+
type: "derived_state";
|
|
2553
|
+
data: Record<string, unknown>;
|
|
2554
|
+
} | {
|
|
2555
|
+
type: "derived_update";
|
|
2556
|
+
id: string;
|
|
2557
|
+
value: unknown;
|
|
2558
|
+
} | {
|
|
2559
|
+
type: "fork_complete";
|
|
2560
|
+
eventId: number;
|
|
2561
|
+
newEventCount: number;
|
|
2562
|
+
} | {
|
|
2563
|
+
type: "token_stream";
|
|
2564
|
+
agentId: string;
|
|
2565
|
+
tokens: string;
|
|
2566
|
+
tokenCount: number;
|
|
2567
|
+
} | {
|
|
2568
|
+
type: "stream_done";
|
|
2569
|
+
agentId: string;
|
|
2570
|
+
totalTokens: number;
|
|
2571
|
+
} | {
|
|
2572
|
+
type: "error";
|
|
2573
|
+
code: string;
|
|
2574
|
+
message: string;
|
|
2575
|
+
};
|
|
2576
|
+
/** Messages sent FROM clients TO the server */
|
|
2577
|
+
type DevToolsClientMessage = {
|
|
2578
|
+
type: "request_snapshot";
|
|
2579
|
+
} | {
|
|
2580
|
+
type: "request_health";
|
|
2581
|
+
} | {
|
|
2582
|
+
type: "request_events";
|
|
2583
|
+
since?: number;
|
|
2584
|
+
} | {
|
|
2585
|
+
type: "request_breakpoints";
|
|
2586
|
+
} | {
|
|
2587
|
+
type: "resume_breakpoint";
|
|
2588
|
+
breakpointId: string;
|
|
2589
|
+
modifications?: {
|
|
2590
|
+
input?: string;
|
|
2591
|
+
skip?: boolean;
|
|
2592
|
+
};
|
|
2593
|
+
} | {
|
|
2594
|
+
type: "cancel_breakpoint";
|
|
2595
|
+
breakpointId: string;
|
|
2596
|
+
reason?: string;
|
|
2597
|
+
} | {
|
|
2598
|
+
type: "export_session";
|
|
2599
|
+
} | {
|
|
2600
|
+
type: "import_session";
|
|
2601
|
+
data: string;
|
|
2602
|
+
} | {
|
|
2603
|
+
type: "request_scratchpad";
|
|
2604
|
+
} | {
|
|
2605
|
+
type: "request_derived";
|
|
2606
|
+
} | {
|
|
2607
|
+
type: "fork_from_snapshot";
|
|
2608
|
+
eventId: number;
|
|
2609
|
+
} | {
|
|
2610
|
+
type: "ping";
|
|
2611
|
+
};
|
|
2612
|
+
/** System snapshot sent to clients on demand */
|
|
2613
|
+
interface DevToolsSnapshot {
|
|
2614
|
+
timestamp: number;
|
|
2615
|
+
agents: Record<string, {
|
|
2616
|
+
status: string;
|
|
2617
|
+
lastInput?: string;
|
|
2618
|
+
lastOutput?: unknown;
|
|
2619
|
+
totalTokens: number;
|
|
2620
|
+
runCount: number;
|
|
3629
2621
|
}>;
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
2622
|
+
coordinator?: {
|
|
2623
|
+
globalTokens: number;
|
|
2624
|
+
status: string;
|
|
2625
|
+
};
|
|
2626
|
+
derived?: Record<string, unknown>;
|
|
2627
|
+
eventCount: number;
|
|
2628
|
+
}
|
|
2629
|
+
/** Configuration for the DevTools server */
|
|
2630
|
+
interface DevToolsServerConfig {
|
|
2631
|
+
/** Transport to use for WebSocket connections */
|
|
2632
|
+
transport: DevToolsTransport;
|
|
2633
|
+
/** Debug timeline to subscribe to */
|
|
2634
|
+
timeline: DebugTimeline;
|
|
2635
|
+
/** Health monitor for metrics (optional) */
|
|
2636
|
+
healthMonitor?: HealthMonitor | null;
|
|
2637
|
+
/** Callback to get current agent states for snapshots */
|
|
2638
|
+
getSnapshot?: () => DevToolsSnapshot;
|
|
2639
|
+
/** Callback to get current breakpoint state */
|
|
2640
|
+
getBreakpointState?: () => BreakpointState;
|
|
2641
|
+
/** Callback to resume a breakpoint */
|
|
2642
|
+
onResumeBreakpoint?: (id: string, modifications?: {
|
|
2643
|
+
input?: string;
|
|
2644
|
+
skip?: boolean;
|
|
2645
|
+
}) => void;
|
|
2646
|
+
/** Callback to cancel a breakpoint */
|
|
2647
|
+
onCancelBreakpoint?: (id: string, reason?: string) => void;
|
|
2648
|
+
/** Callback to get current scratchpad state */
|
|
2649
|
+
getScratchpadState?: () => Record<string, unknown>;
|
|
2650
|
+
/** Callback to get current derived state */
|
|
2651
|
+
getDerivedState?: () => Record<string, unknown>;
|
|
2652
|
+
/** Callback to fork from a snapshot event */
|
|
2653
|
+
onForkFromSnapshot?: (eventId: number) => {
|
|
2654
|
+
newEventCount: number;
|
|
2655
|
+
};
|
|
2656
|
+
/** Maximum events to batch before flushing. Default: 1 (no batching) */
|
|
2657
|
+
batchSize?: number;
|
|
2658
|
+
/** Flush interval for batched events (ms). Default: 50 */
|
|
2659
|
+
batchIntervalMs?: number;
|
|
2660
|
+
/** Health metrics push interval (ms). 0 = no auto-push. Default: 0 */
|
|
2661
|
+
healthPushIntervalMs?: number;
|
|
2662
|
+
/** Maximum connected clients. Default: 50 */
|
|
2663
|
+
maxClients?: number;
|
|
2664
|
+
}
|
|
2665
|
+
/** DevTools server instance */
|
|
2666
|
+
interface DevToolsServer {
|
|
2667
|
+
/** Number of connected clients */
|
|
2668
|
+
readonly clientCount: number;
|
|
2669
|
+
/** Broadcast a message to all connected clients */
|
|
2670
|
+
broadcast(message: DevToolsServerMessage): void;
|
|
2671
|
+
/** Push current health metrics to all clients */
|
|
2672
|
+
pushHealth(): void;
|
|
2673
|
+
/** Push current breakpoint state to all clients */
|
|
2674
|
+
pushBreakpoints(): void;
|
|
2675
|
+
/** Push a scratchpad key update to all clients */
|
|
2676
|
+
pushScratchpadUpdate(key: string, value: unknown): void;
|
|
2677
|
+
/** Push a derived value update to all clients */
|
|
2678
|
+
pushDerivedUpdate(id: string, value: unknown): void;
|
|
2679
|
+
/** Push streaming tokens to all clients */
|
|
2680
|
+
pushTokenStream(agentId: string, tokens: string, tokenCount: number): void;
|
|
2681
|
+
/** Signal stream completion to all clients */
|
|
2682
|
+
pushStreamDone(agentId: string, totalTokens: number): void;
|
|
2683
|
+
/** Shut down the server and disconnect all clients */
|
|
2684
|
+
close(): void;
|
|
3642
2685
|
}
|
|
3643
2686
|
/**
|
|
3644
|
-
* Create a
|
|
3645
|
-
*
|
|
2687
|
+
* Create a DevTools server that bridges orchestrator state to DevTools UI clients.
|
|
2688
|
+
*
|
|
2689
|
+
* @example
|
|
2690
|
+
* ```typescript
|
|
2691
|
+
* const server = createDevToolsServer({
|
|
2692
|
+
* transport: createWsTransport(4040),
|
|
2693
|
+
* timeline: orchestrator.timeline!,
|
|
2694
|
+
* healthMonitor: orchestrator.healthMonitor,
|
|
2695
|
+
* getSnapshot: () => buildSnapshot(orchestrator),
|
|
2696
|
+
* getBreakpointState: () => orchestrator.getBreakpointState(),
|
|
2697
|
+
* onResumeBreakpoint: (id, mods) => orchestrator.resumeBreakpoint(id, mods),
|
|
2698
|
+
* onCancelBreakpoint: (id, reason) => orchestrator.cancelBreakpoint(id, reason),
|
|
2699
|
+
* });
|
|
2700
|
+
* ```
|
|
3646
2701
|
*/
|
|
3647
|
-
declare function
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
2702
|
+
declare function createDevToolsServer(config: DevToolsServerConfig): DevToolsServer;
|
|
2703
|
+
/** Options for connecting DevTools to an orchestrator */
|
|
2704
|
+
interface ConnectDevToolsOptions {
|
|
2705
|
+
/** Port for the WebSocket server. Default: 4040 */
|
|
2706
|
+
port?: number;
|
|
2707
|
+
/** Host to bind to. Default: "localhost" */
|
|
2708
|
+
host?: string;
|
|
2709
|
+
/** Health metrics push interval (ms). Default: 5000 */
|
|
2710
|
+
healthPushIntervalMs?: number;
|
|
2711
|
+
/** Event batching size. Default: 1 (no batching) */
|
|
2712
|
+
batchSize?: number;
|
|
2713
|
+
}
|
|
2714
|
+
/** Minimal orchestrator interface for DevTools connection */
|
|
2715
|
+
interface DevToolsCompatibleOrchestrator {
|
|
2716
|
+
timeline: {
|
|
2717
|
+
subscribe: (listener: (event: DebugEvent) => void) => () => void;
|
|
2718
|
+
getEvents: () => DebugEvent[];
|
|
2719
|
+
import: (json: string) => void;
|
|
2720
|
+
export: () => string;
|
|
2721
|
+
forkFrom?: (eventId: number) => void;
|
|
2722
|
+
} | null;
|
|
2723
|
+
healthMonitor?: {
|
|
2724
|
+
getAllMetrics: () => Record<string, AgentHealthMetrics>;
|
|
2725
|
+
} | null;
|
|
2726
|
+
getPendingBreakpoints?: () => Array<{
|
|
2727
|
+
id: string;
|
|
2728
|
+
type: string;
|
|
2729
|
+
agentId: string;
|
|
2730
|
+
input: string;
|
|
2731
|
+
label?: string;
|
|
2732
|
+
requestedAt: number;
|
|
2733
|
+
}>;
|
|
2734
|
+
resumeBreakpoint?: (id: string, modifications?: {
|
|
2735
|
+
input?: string;
|
|
2736
|
+
skip?: boolean;
|
|
2737
|
+
}) => void;
|
|
2738
|
+
cancelBreakpoint?: (id: string, reason?: string) => void;
|
|
2739
|
+
getAllAgentStates?: () => Record<string, {
|
|
2740
|
+
status: string;
|
|
2741
|
+
lastInput?: string;
|
|
2742
|
+
lastOutput?: unknown;
|
|
2743
|
+
totalTokens: number;
|
|
2744
|
+
runCount: number;
|
|
2745
|
+
}>;
|
|
2746
|
+
/** Get current scratchpad state (multi-agent only) */
|
|
2747
|
+
getScratchpadState?: () => Record<string, unknown>;
|
|
2748
|
+
/** Get current derived values (multi-agent only) */
|
|
2749
|
+
getDerivedState?: () => Record<string, unknown>;
|
|
3655
2750
|
}
|
|
3656
2751
|
/**
|
|
3657
|
-
*
|
|
3658
|
-
* Uses dynamic `import('node:fs')` for isomorphic safety.
|
|
3659
|
-
*/
|
|
3660
|
-
declare function createJSONFileStore(options: JSONFileStoreOptions): RAGStorage;
|
|
3661
|
-
|
|
3662
|
-
/**
|
|
3663
|
-
* SSE Transport — Wrap a Directive AgentStack token stream into an HTTP
|
|
3664
|
-
* Server-Sent Events response.
|
|
2752
|
+
* Connect DevTools to an orchestrator instance.
|
|
3665
2753
|
*
|
|
3666
|
-
*
|
|
3667
|
-
*
|
|
2754
|
+
* Convenience function that creates a WebSocket transport and DevTools server,
|
|
2755
|
+
* automatically wiring up the orchestrator's timeline, health monitor, and breakpoint system.
|
|
2756
|
+
*
|
|
2757
|
+
* Requires the `ws` package: `npm install ws`
|
|
2758
|
+
*
|
|
2759
|
+
* **Security:** Binding to `0.0.0.0` exposes the server to all network interfaces.
|
|
2760
|
+
* Only do this behind a firewall or with proper authentication.
|
|
3668
2761
|
*
|
|
3669
2762
|
* @example
|
|
3670
2763
|
* ```typescript
|
|
3671
|
-
*
|
|
2764
|
+
* const orchestrator = createMultiAgentOrchestrator({ debug: true, ... });
|
|
2765
|
+
* const devtools = await connectDevTools(orchestrator, { port: 4040 });
|
|
3672
2766
|
*
|
|
3673
|
-
*
|
|
3674
|
-
*
|
|
3675
|
-
* errorMessages: {
|
|
3676
|
-
* INPUT_GUARDRAIL_FAILED: 'Your message was flagged by our safety filter.',
|
|
3677
|
-
* },
|
|
3678
|
-
* });
|
|
3679
|
-
*
|
|
3680
|
-
* // Next.js route handler
|
|
3681
|
-
* export async function POST(req: Request) {
|
|
3682
|
-
* const { message } = await req.json();
|
|
3683
|
-
* return transport.toResponse(stack, 'docs-qa', message);
|
|
3684
|
-
* }
|
|
2767
|
+
* // Later, clean up:
|
|
2768
|
+
* devtools.close();
|
|
3685
2769
|
* ```
|
|
3686
2770
|
*/
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
message:
|
|
3699
|
-
|
|
3700
|
-
type: "heartbeat";
|
|
3701
|
-
timestamp: number;
|
|
3702
|
-
};
|
|
3703
|
-
interface SSETransportConfig {
|
|
3704
|
-
/** Truncate response after this many characters (default: Infinity) */
|
|
3705
|
-
maxResponseChars?: number;
|
|
3706
|
-
/** Message shown when response is truncated */
|
|
3707
|
-
truncationMessage?: string;
|
|
3708
|
-
/** Heartbeat interval in ms (default: 0 = disabled) */
|
|
3709
|
-
heartbeatIntervalMs?: number;
|
|
3710
|
-
/** Map error codes/types to user-facing messages */
|
|
3711
|
-
errorMessages?: Record<string, string> | ((error: unknown) => string);
|
|
3712
|
-
/** Extra headers merged into the SSE response */
|
|
3713
|
-
headers?: Record<string, string>;
|
|
3714
|
-
}
|
|
3715
|
-
interface SSETransport {
|
|
3716
|
-
/** Create a full HTTP Response with SSE headers */
|
|
3717
|
-
toResponse(stack: AgentStack, agentId: string, input: string, opts?: {
|
|
3718
|
-
signal?: AbortSignal;
|
|
3719
|
-
}): Response;
|
|
3720
|
-
/** Return just the ReadableStream (for Express/Koa `res.write()`) */
|
|
3721
|
-
toStream(stack: AgentStack, agentId: string, input: string, opts?: {
|
|
3722
|
-
signal?: AbortSignal;
|
|
3723
|
-
}): ReadableStream<Uint8Array>;
|
|
2771
|
+
declare function connectDevTools(orchestrator: DevToolsCompatibleOrchestrator, options?: ConnectDevToolsOptions): Promise<DevToolsServer>;
|
|
2772
|
+
/**
|
|
2773
|
+
* Configuration for the built-in Node.js `ws` transport.
|
|
2774
|
+
*
|
|
2775
|
+
* Requires the `ws` package to be installed: `npm install ws`
|
|
2776
|
+
*/
|
|
2777
|
+
interface WsTransportConfig {
|
|
2778
|
+
/** Port to listen on. Default: 4040 */
|
|
2779
|
+
port?: number;
|
|
2780
|
+
/** Host to bind to. Default: "localhost" */
|
|
2781
|
+
host?: string;
|
|
2782
|
+
/** Maximum incoming message size in bytes. Default: 1048576 (1MB) */
|
|
2783
|
+
maxPayloadBytes?: number;
|
|
3724
2784
|
}
|
|
3725
2785
|
/**
|
|
3726
|
-
* Create
|
|
3727
|
-
*
|
|
2786
|
+
* Create a DevTools transport using the Node.js `ws` WebSocket library.
|
|
2787
|
+
*
|
|
2788
|
+
* This is a convenience helper — you can implement {@link DevToolsTransport}
|
|
2789
|
+
* with any WebSocket library.
|
|
2790
|
+
*
|
|
2791
|
+
* @example
|
|
2792
|
+
* ```typescript
|
|
2793
|
+
* const transport = await createWsTransport({ port: 4040 });
|
|
2794
|
+
* const server = createDevToolsServer({ transport, timeline });
|
|
2795
|
+
* ```
|
|
3728
2796
|
*/
|
|
3729
|
-
declare function
|
|
2797
|
+
declare function createWsTransport(config?: WsTransportConfig): Promise<DevToolsTransport>;
|
|
3730
2798
|
|
|
3731
2799
|
/**
|
|
3732
|
-
*
|
|
2800
|
+
* Standalone utilities for goal planning and validation.
|
|
3733
2801
|
*
|
|
3734
|
-
*
|
|
3735
|
-
*
|
|
3736
|
-
*
|
|
3737
|
-
*
|
|
3738
|
-
* @module
|
|
2802
|
+
* These functions work with the same `produces` / `requires` agent
|
|
2803
|
+
* declarations used by the goal pattern, without requiring an
|
|
2804
|
+
* orchestrator instance.
|
|
3739
2805
|
*
|
|
3740
2806
|
* @example
|
|
3741
2807
|
* ```typescript
|
|
3742
|
-
* import {
|
|
2808
|
+
* import { validateGoal, planGoal, getDependencyGraph } from '@directive-run/ai';
|
|
3743
2809
|
*
|
|
3744
|
-
* const
|
|
3745
|
-
*
|
|
3746
|
-
*
|
|
3747
|
-
*
|
|
3748
|
-
* }
|
|
2810
|
+
* const agents = {
|
|
2811
|
+
* fetcher: { produces: ['data'], requires: [] },
|
|
2812
|
+
* analyzer: { produces: ['analysis'], requires: ['data'] },
|
|
2813
|
+
* reporter: { produces: ['report'], requires: ['analysis'] },
|
|
2814
|
+
* };
|
|
3749
2815
|
*
|
|
3750
|
-
* //
|
|
3751
|
-
* const
|
|
3752
|
-
* queue.submit(agent, "input 1"),
|
|
3753
|
-
* queue.submit(agent, "input 2"),
|
|
3754
|
-
* queue.submit(agent, "input 3"),
|
|
3755
|
-
* ]);
|
|
2816
|
+
* // Validate — cycle detection, missing deps, warnings
|
|
2817
|
+
* const validation = validateGoal(agents);
|
|
3756
2818
|
*
|
|
3757
|
-
* //
|
|
3758
|
-
*
|
|
2819
|
+
* // Plan — dry-run without executing agents
|
|
2820
|
+
* const plan = planGoal(agents, ['query']);
|
|
3759
2821
|
*
|
|
3760
|
-
* //
|
|
3761
|
-
*
|
|
2822
|
+
* // Graph — topological order, roots, leaves, edges
|
|
2823
|
+
* const graph = getDependencyGraph(agents);
|
|
3762
2824
|
* ```
|
|
2825
|
+
*
|
|
2826
|
+
* @module
|
|
3763
2827
|
*/
|
|
3764
2828
|
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
2829
|
+
/** Minimal agent declaration for goal utilities (subset of GoalNode) */
|
|
2830
|
+
interface GoalAgentDeclaration {
|
|
2831
|
+
/** Fact keys this agent writes as output */
|
|
2832
|
+
produces: string[];
|
|
2833
|
+
/** Fact keys this agent reads as input */
|
|
2834
|
+
requires?: string[];
|
|
2835
|
+
}
|
|
2836
|
+
/** Edge in the inferred dependency graph */
|
|
2837
|
+
interface GoalDependencyEdge {
|
|
2838
|
+
from: string;
|
|
2839
|
+
to: string;
|
|
2840
|
+
/** Fact key that creates this dependency */
|
|
2841
|
+
factKey: string;
|
|
3772
2842
|
}
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
2843
|
+
/** Inferred dependency graph from produces/requires analysis */
|
|
2844
|
+
interface GoalDependencyGraph {
|
|
2845
|
+
/** Agent IDs in topological order (roots first) */
|
|
2846
|
+
order: string[];
|
|
2847
|
+
/** Edges between agents */
|
|
2848
|
+
edges: GoalDependencyEdge[];
|
|
2849
|
+
/** Root agents (no unfulfilled requires from other agents) */
|
|
2850
|
+
roots: string[];
|
|
2851
|
+
/** Leaf agents (nothing depends on their produces) */
|
|
2852
|
+
leaves: string[];
|
|
2853
|
+
/** Map of fact key to agent ID that produces it */
|
|
2854
|
+
producers: Map<string, string>;
|
|
2855
|
+
}
|
|
2856
|
+
/** Validation result */
|
|
2857
|
+
interface GoalValidationResult {
|
|
2858
|
+
valid: boolean;
|
|
2859
|
+
errors: string[];
|
|
2860
|
+
warnings: string[];
|
|
2861
|
+
}
|
|
2862
|
+
/** A single step in an execution plan */
|
|
2863
|
+
interface GoalPlanStep {
|
|
2864
|
+
/** Step number (1-based) */
|
|
2865
|
+
step: number;
|
|
2866
|
+
/** Agent IDs that would run in this step (parallel) */
|
|
2867
|
+
agents: string[];
|
|
2868
|
+
/** Fact keys available at the start of this step */
|
|
2869
|
+
availableFacts: string[];
|
|
2870
|
+
/** Fact keys produced after this step completes */
|
|
2871
|
+
producedFacts: string[];
|
|
2872
|
+
}
|
|
2873
|
+
/** Result of a planGoal() dry-run */
|
|
2874
|
+
interface GoalExecutionPlan {
|
|
2875
|
+
/** Ordered steps showing which agents run when */
|
|
2876
|
+
steps: GoalPlanStep[];
|
|
2877
|
+
/** Agents that can never run (requires never satisfiable) */
|
|
2878
|
+
unreachableAgents: string[];
|
|
2879
|
+
/** Required fact keys that no agent produces (must be in initial facts) */
|
|
2880
|
+
externalDeps: string[];
|
|
2881
|
+
/** Whether the plan can potentially reach all agents */
|
|
2882
|
+
feasible: boolean;
|
|
3782
2883
|
}
|
|
3783
2884
|
/**
|
|
3784
|
-
*
|
|
2885
|
+
* Get the dependency graph for a set of agent declarations.
|
|
2886
|
+
*
|
|
2887
|
+
* Uses Kahn's algorithm (topological sort) to compute execution order
|
|
2888
|
+
* and detect circular dependencies.
|
|
2889
|
+
*
|
|
2890
|
+
* @throws If agents form a circular dependency or a fact key has multiple producers.
|
|
3785
2891
|
*
|
|
3786
2892
|
* @example
|
|
3787
2893
|
* ```typescript
|
|
3788
|
-
* const
|
|
3789
|
-
*
|
|
3790
|
-
*
|
|
3791
|
-
* concurrency: 5,
|
|
2894
|
+
* const graph = getDependencyGraph({
|
|
2895
|
+
* fetcher: { produces: ['data'], requires: [] },
|
|
2896
|
+
* analyzer: { produces: ['analysis'], requires: ['data'] },
|
|
3792
2897
|
* });
|
|
3793
2898
|
*
|
|
3794
|
-
* //
|
|
3795
|
-
*
|
|
3796
|
-
*
|
|
3797
|
-
* queue.submit(agent, "input 2"),
|
|
3798
|
-
* queue.submit(agent, "input 3"),
|
|
3799
|
-
* ]);
|
|
3800
|
-
*
|
|
3801
|
-
* // Clean up
|
|
3802
|
-
* await queue.dispose();
|
|
2899
|
+
* console.log(graph.order); // ['fetcher', 'analyzer']
|
|
2900
|
+
* console.log(graph.roots); // ['fetcher']
|
|
2901
|
+
* console.log(graph.leaves); // ['analyzer']
|
|
3803
2902
|
* ```
|
|
3804
2903
|
*/
|
|
3805
|
-
declare function
|
|
3806
|
-
|
|
2904
|
+
declare function getDependencyGraph(agents: Record<string, GoalAgentDeclaration>): GoalDependencyGraph;
|
|
3807
2905
|
/**
|
|
3808
|
-
*
|
|
2906
|
+
* Validate a set of agent declarations for goal execution.
|
|
3809
2907
|
*
|
|
3810
|
-
*
|
|
3811
|
-
*
|
|
3812
|
-
*
|
|
3813
|
-
*
|
|
3814
|
-
*
|
|
3815
|
-
*
|
|
3816
|
-
* @module
|
|
2908
|
+
* Checks for:
|
|
2909
|
+
* - Circular dependencies
|
|
2910
|
+
* - Duplicate producers (same fact key produced by multiple agents)
|
|
2911
|
+
* - Agents with no `produces` (will never contribute)
|
|
2912
|
+
* - Required fact keys that no agent produces (must be in initial facts)
|
|
3817
2913
|
*
|
|
3818
2914
|
* @example
|
|
3819
2915
|
* ```typescript
|
|
3820
|
-
*
|
|
3821
|
-
*
|
|
3822
|
-
*
|
|
3823
|
-
* const router = createConstraintRouter({
|
|
3824
|
-
* providers: [
|
|
3825
|
-
* { name: "openai", runner: openaiRunner, pricing: { inputPerMillion: 5, outputPerMillion: 15 } },
|
|
3826
|
-
* { name: "anthropic", runner: anthropicRunner, pricing: { inputPerMillion: 3, outputPerMillion: 15 } },
|
|
3827
|
-
* { name: "ollama", runner: ollamaRunner },
|
|
3828
|
-
* ],
|
|
3829
|
-
* defaultProvider: "openai",
|
|
3830
|
-
* constraints: [
|
|
3831
|
-
* { when: (facts) => facts.totalCost > 100, provider: "ollama", priority: 10 },
|
|
3832
|
-
* { when: (facts) => facts.providers["openai"]?.errorCount > 5, provider: "anthropic" },
|
|
3833
|
-
* ],
|
|
3834
|
-
* preferCheapest: true, // opt-in to cheapest-provider heuristic
|
|
3835
|
-
* onProviderSelected: (name, reason) => console.log(`Using ${name} (${reason})`),
|
|
2916
|
+
* const result = validateGoal({
|
|
2917
|
+
* fetcher: { produces: ['data'] },
|
|
2918
|
+
* analyzer: { produces: ['analysis'], requires: ['data'] },
|
|
3836
2919
|
* });
|
|
3837
2920
|
*
|
|
3838
|
-
*
|
|
3839
|
-
*
|
|
2921
|
+
* if (!result.valid) {
|
|
2922
|
+
* console.error(result.errors);
|
|
2923
|
+
* }
|
|
3840
2924
|
* ```
|
|
3841
2925
|
*/
|
|
3842
|
-
|
|
2926
|
+
declare function validateGoal(agents: Record<string, GoalAgentDeclaration>): GoalValidationResult;
|
|
3843
2927
|
/**
|
|
3844
|
-
*
|
|
2928
|
+
* Dry-run goal execution to preview the plan without running agents.
|
|
3845
2929
|
*
|
|
3846
|
-
*
|
|
3847
|
-
* and
|
|
3848
|
-
*/
|
|
3849
|
-
interface RoutingProvider {
|
|
3850
|
-
/** Unique name for this provider. */
|
|
3851
|
-
name: string;
|
|
3852
|
-
/** The runner to use for this provider. */
|
|
3853
|
-
runner: AgentRunner;
|
|
3854
|
-
/** Token pricing (cost per million tokens). */
|
|
3855
|
-
pricing?: {
|
|
3856
|
-
inputPerMillion: number;
|
|
3857
|
-
outputPerMillion: number;
|
|
3858
|
-
};
|
|
3859
|
-
/** Geographic region (for compliance routing). */
|
|
3860
|
-
region?: string;
|
|
3861
|
-
}
|
|
3862
|
-
/**
|
|
3863
|
-
* Runtime facts tracked by the router — exposed for user constraints.
|
|
2930
|
+
* Shows which agents would run in each step, which facts would be produced,
|
|
2931
|
+
* and whether any agents are unreachable.
|
|
3864
2932
|
*
|
|
3865
|
-
*
|
|
2933
|
+
* @param agents - Agent declarations with produces/requires
|
|
2934
|
+
* @param initialFactKeys - Fact keys available at the start (not values, just keys)
|
|
2935
|
+
* @param maxSteps - Maximum steps to simulate (default: 50)
|
|
2936
|
+
*
|
|
2937
|
+
* @example
|
|
2938
|
+
* ```typescript
|
|
2939
|
+
* const plan = planGoal(
|
|
2940
|
+
* {
|
|
2941
|
+
* fetcher: { produces: ['data'] },
|
|
2942
|
+
* analyzer: { produces: ['analysis'], requires: ['data'] },
|
|
2943
|
+
* reporter: { produces: ['report'], requires: ['analysis'] },
|
|
2944
|
+
* },
|
|
2945
|
+
* ['query'],
|
|
2946
|
+
* );
|
|
2947
|
+
*
|
|
2948
|
+
* console.log(plan.feasible); // true
|
|
2949
|
+
* console.log(plan.steps); // 3 steps: fetcher → analyzer → reporter
|
|
2950
|
+
* ```
|
|
3866
2951
|
*/
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
/**
|
|
3896
|
-
|
|
3897
|
-
/**
|
|
3898
|
-
|
|
3899
|
-
/** Called when a provider is selected. */
|
|
3900
|
-
onProviderSelected?: (providerName: string, reason: "constraint" | "cheapest" | "default") => void;
|
|
3901
|
-
/** Error cooldown — skip a provider for this many ms after an error. @default 30000 */
|
|
3902
|
-
errorCooldownMs?: number;
|
|
3903
|
-
/**
|
|
3904
|
-
* When true, automatically prefer the cheapest available provider
|
|
3905
|
-
* (based on pricing) when no user constraint matches.
|
|
3906
|
-
* When false, the default provider is used unless a constraint overrides it.
|
|
3907
|
-
* @default false
|
|
3908
|
-
*/
|
|
3909
|
-
preferCheapest?: boolean;
|
|
2952
|
+
declare function planGoal(agents: Record<string, GoalAgentDeclaration>, initialFactKeys?: string[], maxSteps?: number): GoalExecutionPlan;
|
|
2953
|
+
/** A single line in a goal execution explanation */
|
|
2954
|
+
interface GoalExplanationStep {
|
|
2955
|
+
step: number;
|
|
2956
|
+
agents: string[];
|
|
2957
|
+
factsProduced: string[];
|
|
2958
|
+
satisfaction: number;
|
|
2959
|
+
satisfactionDelta: number;
|
|
2960
|
+
durationMs: number;
|
|
2961
|
+
tokensConsumed: number;
|
|
2962
|
+
/** Human-readable description of what happened */
|
|
2963
|
+
description: string;
|
|
2964
|
+
}
|
|
2965
|
+
/** Structured explanation of a goal execution */
|
|
2966
|
+
interface GoalExplanation {
|
|
2967
|
+
/** Whether the goal was achieved */
|
|
2968
|
+
achieved: boolean;
|
|
2969
|
+
/** Human-readable summary */
|
|
2970
|
+
summary: string;
|
|
2971
|
+
/** Per-step explanations */
|
|
2972
|
+
steps: GoalExplanationStep[];
|
|
2973
|
+
/** Relaxation events with descriptions */
|
|
2974
|
+
relaxations: Array<{
|
|
2975
|
+
step: number;
|
|
2976
|
+
label: string;
|
|
2977
|
+
strategy: string;
|
|
2978
|
+
description: string;
|
|
2979
|
+
}>;
|
|
2980
|
+
/** Total tokens consumed */
|
|
2981
|
+
totalTokens: number;
|
|
2982
|
+
/** Total duration (ms) */
|
|
2983
|
+
durationMs: number;
|
|
3910
2984
|
}
|
|
3911
2985
|
/**
|
|
3912
|
-
*
|
|
2986
|
+
* Generate a human-readable explanation of a goal execution result.
|
|
2987
|
+
*
|
|
2988
|
+
* Takes a `GoalResult` and returns a structured explanation of why each
|
|
2989
|
+
* agent ran, how satisfaction progressed, and what relaxations were applied.
|
|
3913
2990
|
*
|
|
3914
2991
|
* @example
|
|
3915
2992
|
* ```typescript
|
|
3916
|
-
* const
|
|
3917
|
-
*
|
|
3918
|
-
*
|
|
3919
|
-
*
|
|
3920
|
-
*
|
|
3921
|
-
*
|
|
3922
|
-
*
|
|
3923
|
-
*
|
|
3924
|
-
*
|
|
3925
|
-
*
|
|
3926
|
-
* ],
|
|
3927
|
-
* });
|
|
2993
|
+
* const result = await orchestrator.runGoal(nodes, input, when, options);
|
|
2994
|
+
* const explanation = explainGoal(result);
|
|
2995
|
+
*
|
|
2996
|
+
* console.log(explanation.summary);
|
|
2997
|
+
* // "Goal achieved in 3 steps (1,247 tokens, 892ms). Satisfaction: 0 → 1."
|
|
2998
|
+
*
|
|
2999
|
+
* for (const step of explanation.steps) {
|
|
3000
|
+
* console.log(step.description);
|
|
3001
|
+
* // "Step 1: Ran fetcher. Produced: data. Satisfaction: 0 → 0.3 (+0.3)."
|
|
3002
|
+
* }
|
|
3928
3003
|
* ```
|
|
3929
3004
|
*/
|
|
3930
|
-
declare function
|
|
3931
|
-
/** Helper type for accessing router facts. */
|
|
3932
|
-
type ConstraintRouterRunner = AgentRunner & {
|
|
3933
|
-
readonly facts: RoutingFacts;
|
|
3934
|
-
};
|
|
3005
|
+
declare function explainGoal<T = unknown>(result: GoalResult<T>): GoalExplanation;
|
|
3935
3006
|
|
|
3936
3007
|
/**
|
|
3937
3008
|
* MCP Type Definitions
|
|
@@ -4379,273 +3450,472 @@ declare function mcpGetPrompt(server: string, prompt: string, args?: Record<stri
|
|
|
4379
3450
|
declare function mcpSyncResources(server?: string, pattern?: string | RegExp): MCPSyncResourcesRequirement;
|
|
4380
3451
|
|
|
4381
3452
|
/**
|
|
4382
|
-
*
|
|
3453
|
+
* Evaluation Framework — Constraint-driven agent evaluation.
|
|
4383
3454
|
*
|
|
4384
|
-
*
|
|
4385
|
-
*
|
|
4386
|
-
*
|
|
4387
|
-
*
|
|
4388
|
-
* Also available:
|
|
4389
|
-
* - `@directive-run/ai/testing` – Mock runners, test orchestrators, assertion helpers
|
|
4390
|
-
* - `@directive-run/ai/anthropic` – Anthropic Claude adapter
|
|
4391
|
-
* - `@directive-run/ai/openai` – OpenAI / Azure / Together adapter
|
|
4392
|
-
* - `@directive-run/ai/ollama` – Local Ollama inference adapter
|
|
3455
|
+
* Define eval criteria as composable functions. Run agents against datasets
|
|
3456
|
+
* and score their outputs across multiple dimensions. Results integrate with
|
|
3457
|
+
* the debug timeline for DevTools visualization.
|
|
4393
3458
|
*
|
|
4394
3459
|
* @example
|
|
4395
3460
|
* ```typescript
|
|
4396
|
-
*
|
|
4397
|
-
*
|
|
4398
|
-
*
|
|
4399
|
-
*
|
|
4400
|
-
*
|
|
4401
|
-
* needsExpertReview: {
|
|
4402
|
-
* when: (facts) => facts.decision.confidence < 0.7,
|
|
4403
|
-
* require: { type: 'EXPERT_AGENT', query: facts.userQuery }
|
|
4404
|
-
* },
|
|
4405
|
-
* budgetLimit: {
|
|
4406
|
-
* when: (facts) => facts.tokenUsage > 10000,
|
|
4407
|
-
* require: { type: 'PAUSE_AGENTS' }
|
|
4408
|
-
* }
|
|
3461
|
+
* const suite = createEvalSuite({
|
|
3462
|
+
* criteria: {
|
|
3463
|
+
* safe: evalSafety({ categories: ["pii"] }),
|
|
3464
|
+
* costEfficient: evalCost({ maxTokensPerRun: 5000 }),
|
|
3465
|
+
* fast: evalLatency({ maxMs: 3000 }),
|
|
4409
3466
|
* },
|
|
4410
|
-
*
|
|
4411
|
-
*
|
|
4412
|
-
*
|
|
4413
|
-
*
|
|
4414
|
-
*
|
|
3467
|
+
* agents: [researchAgent, writerAgent],
|
|
3468
|
+
* runner: myRunner,
|
|
3469
|
+
* dataset: [
|
|
3470
|
+
* { id: "case-1", input: "What is AI?", expected: "explanation about AI" },
|
|
3471
|
+
* ],
|
|
3472
|
+
* });
|
|
3473
|
+
*
|
|
3474
|
+
* const results = await suite.run();
|
|
3475
|
+
* // results.summary — pass/fail per criterion per agent
|
|
3476
|
+
* // results.details — per-case breakdown
|
|
4415
3477
|
* ```
|
|
3478
|
+
*
|
|
3479
|
+
* @module
|
|
4416
3480
|
*/
|
|
4417
3481
|
|
|
4418
|
-
/**
|
|
4419
|
-
interface
|
|
4420
|
-
/**
|
|
3482
|
+
/** Single test case in the eval dataset */
|
|
3483
|
+
interface EvalCase {
|
|
3484
|
+
/** Unique identifier for tracking across runs */
|
|
3485
|
+
id?: string;
|
|
3486
|
+
/** Input to feed the agent */
|
|
3487
|
+
input: string;
|
|
3488
|
+
/** Expected output or reference answer (for comparison-based criteria) */
|
|
3489
|
+
expected?: string;
|
|
3490
|
+
/** Reference context for faithfulness evaluation */
|
|
3491
|
+
context?: string;
|
|
3492
|
+
/** Tags for filtering and grouping results */
|
|
3493
|
+
tags?: string[];
|
|
3494
|
+
/** Additional context passed to criteria */
|
|
3495
|
+
metadata?: Record<string, unknown>;
|
|
3496
|
+
}
|
|
3497
|
+
/** Result of evaluating a single criterion on a single case */
|
|
3498
|
+
interface EvalScore {
|
|
3499
|
+
/** Score from 0.0 to 1.0 */
|
|
3500
|
+
score: number;
|
|
3501
|
+
/** Whether this score passes the criterion threshold */
|
|
3502
|
+
passed: boolean;
|
|
3503
|
+
/** Reason for the score */
|
|
3504
|
+
reason?: string;
|
|
3505
|
+
/** Duration of evaluation (ms) */
|
|
3506
|
+
durationMs: number;
|
|
3507
|
+
}
|
|
3508
|
+
/** Context passed to eval criterion functions */
|
|
3509
|
+
interface EvalContext {
|
|
3510
|
+
/** The agent being evaluated */
|
|
3511
|
+
agent: AgentLike;
|
|
3512
|
+
/** The test case */
|
|
3513
|
+
testCase: EvalCase;
|
|
3514
|
+
/** The agent's run result */
|
|
3515
|
+
result: RunResult<unknown>;
|
|
3516
|
+
/** Duration of the agent run (ms) */
|
|
3517
|
+
runDurationMs: number;
|
|
3518
|
+
}
|
|
3519
|
+
/** Eval criterion function — scores an agent's output */
|
|
3520
|
+
type EvalCriterionFn = (context: EvalContext) => EvalScore | Promise<EvalScore>;
|
|
3521
|
+
/** Named eval criterion */
|
|
3522
|
+
interface EvalCriterion {
|
|
3523
|
+
name: string;
|
|
3524
|
+
fn: EvalCriterionFn;
|
|
3525
|
+
/** Score threshold for passing. Default: 0.5 */
|
|
3526
|
+
threshold?: number;
|
|
3527
|
+
/** Weight for aggregation. Default: 1.0 */
|
|
3528
|
+
weight?: number;
|
|
3529
|
+
}
|
|
3530
|
+
/** Per-case detail result */
|
|
3531
|
+
interface EvalCaseResult {
|
|
3532
|
+
/** Test case that was evaluated */
|
|
3533
|
+
testCase: EvalCase;
|
|
3534
|
+
/** Agent that was evaluated */
|
|
3535
|
+
agentName: string;
|
|
3536
|
+
/** Agent run result */
|
|
3537
|
+
runResult: RunResult<unknown>;
|
|
3538
|
+
/** Score per criterion */
|
|
3539
|
+
scores: Record<string, EvalScore>;
|
|
3540
|
+
/** Overall weighted score (0.0-1.0) */
|
|
3541
|
+
overallScore: number;
|
|
3542
|
+
/** Whether all criteria passed */
|
|
3543
|
+
allPassed: boolean;
|
|
3544
|
+
/** Agent run duration (ms) */
|
|
3545
|
+
runDurationMs: number;
|
|
3546
|
+
}
|
|
3547
|
+
/** Per-agent summary */
|
|
3548
|
+
interface EvalAgentSummary {
|
|
3549
|
+
agentName: string;
|
|
3550
|
+
/** Average score per criterion */
|
|
3551
|
+
criterionAverages: Record<string, number>;
|
|
3552
|
+
/** Pass rate per criterion (0.0-1.0) */
|
|
3553
|
+
criterionPassRates: Record<string, number>;
|
|
3554
|
+
/** Overall weighted average score */
|
|
3555
|
+
overallScore: number;
|
|
3556
|
+
/** Overall pass rate */
|
|
3557
|
+
passRate: number;
|
|
3558
|
+
/** Total tokens consumed */
|
|
3559
|
+
totalTokens: number;
|
|
3560
|
+
/** Average latency per run (ms) */
|
|
3561
|
+
avgLatencyMs: number;
|
|
3562
|
+
/** Total cases evaluated */
|
|
3563
|
+
totalCases: number;
|
|
3564
|
+
/** Cases that passed all criteria */
|
|
3565
|
+
passedCases: number;
|
|
3566
|
+
}
|
|
3567
|
+
/** Complete eval suite results */
|
|
3568
|
+
interface EvalResults {
|
|
3569
|
+
/** Summary per agent */
|
|
3570
|
+
summary: Record<string, EvalAgentSummary>;
|
|
3571
|
+
/** Detailed per-case results */
|
|
3572
|
+
details: EvalCaseResult[];
|
|
3573
|
+
/** Total duration (ms) */
|
|
3574
|
+
durationMs: number;
|
|
3575
|
+
/** Total tokens consumed across all agents and cases */
|
|
3576
|
+
totalTokens: number;
|
|
3577
|
+
/** Timestamp when the eval started */
|
|
3578
|
+
startedAt: number;
|
|
3579
|
+
/** Timestamp when the eval completed */
|
|
3580
|
+
completedAt: number;
|
|
3581
|
+
}
|
|
3582
|
+
/** Configuration for createEvalSuite */
|
|
3583
|
+
interface EvalSuiteConfig {
|
|
3584
|
+
/** Named criteria to evaluate */
|
|
3585
|
+
criteria: Record<string, EvalCriterionFn | EvalCriterion>;
|
|
3586
|
+
/** Agents to evaluate */
|
|
3587
|
+
agents: AgentLike[];
|
|
3588
|
+
/** Agent runner function */
|
|
4421
3589
|
runner: AgentRunner;
|
|
4422
|
-
/**
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
/** Callback for approval requests */
|
|
4436
|
-
onApprovalRequest?: (request: ApprovalRequest) => void;
|
|
4437
|
-
/**
|
|
4438
|
-
* Auto-approve tool calls
|
|
4439
|
-
* @default true
|
|
4440
|
-
*/
|
|
4441
|
-
autoApproveToolCalls?: boolean;
|
|
4442
|
-
/**
|
|
4443
|
-
* Maximum token budget across all agent runs.
|
|
4444
|
-
*
|
|
4445
|
-
* When exceeded, agents are automatically paused with status "paused".
|
|
4446
|
-
* Check `facts.agent.tokenUsage` to see current usage.
|
|
4447
|
-
*
|
|
4448
|
-
* For more sophisticated cost management (per-user budgets, tiered pricing,
|
|
4449
|
-
* cost alerts), see the Cost Management section in the documentation.
|
|
4450
|
-
*
|
|
4451
|
-
* @example
|
|
4452
|
-
* ```typescript
|
|
4453
|
-
* const orchestrator = createAgentOrchestrator({
|
|
4454
|
-
* maxTokenBudget: 10000, // Pause after 10K tokens
|
|
4455
|
-
* });
|
|
4456
|
-
*
|
|
4457
|
-
* // Check if paused due to budget
|
|
4458
|
-
* if (orchestrator.facts.agent.status === 'paused') {
|
|
4459
|
-
* console.log('Budget exceeded:', orchestrator.facts.agent.tokenUsage);
|
|
4460
|
-
* }
|
|
4461
|
-
* ```
|
|
4462
|
-
*/
|
|
4463
|
-
maxTokenBudget?: number;
|
|
4464
|
-
/** Plugins */
|
|
4465
|
-
plugins?: Plugin[];
|
|
4466
|
-
/**
|
|
4467
|
-
* Enable debugging
|
|
4468
|
-
* @default false
|
|
4469
|
-
*/
|
|
4470
|
-
debug?: boolean;
|
|
4471
|
-
/**
|
|
4472
|
-
* Approval timeout in milliseconds
|
|
4473
|
-
* @default 300000 (5 minutes)
|
|
4474
|
-
*/
|
|
4475
|
-
approvalTimeoutMs?: number;
|
|
4476
|
-
/** Retry configuration for agent runs (no retries if not specified) */
|
|
4477
|
-
agentRetry?: AgentRetryConfig;
|
|
4478
|
-
/** Lifecycle hooks for observability */
|
|
4479
|
-
hooks?: OrchestratorLifecycleHooks;
|
|
4480
|
-
/**
|
|
4481
|
-
* Optional memory instance. When provided, context messages are auto-injected
|
|
4482
|
-
* into agent instructions before each run, and result messages are auto-stored.
|
|
4483
|
-
*/
|
|
4484
|
-
memory?: AgentMemory;
|
|
4485
|
-
/**
|
|
4486
|
-
* Optional circuit breaker. Wraps every run() call.
|
|
4487
|
-
* When OPEN, throws CircuitBreakerOpenError instead of calling the agent.
|
|
4488
|
-
*/
|
|
4489
|
-
circuitBreaker?: CircuitBreaker;
|
|
4490
|
-
}
|
|
4491
|
-
/** Streaming run result from orchestrator */
|
|
4492
|
-
interface OrchestratorStreamResult<T = unknown> {
|
|
4493
|
-
/** Async iterator for streaming chunks */
|
|
4494
|
-
stream: AsyncIterable<OrchestratorStreamChunk>;
|
|
4495
|
-
/** Promise that resolves to the final result */
|
|
4496
|
-
result: Promise<RunResult<T>>;
|
|
4497
|
-
/** Abort the stream */
|
|
4498
|
-
abort: () => void;
|
|
4499
|
-
}
|
|
4500
|
-
/** Stream chunk types for orchestrator — extends StreamChunk with approval events */
|
|
4501
|
-
type OrchestratorStreamChunk = StreamChunk | {
|
|
4502
|
-
type: "approval_required";
|
|
4503
|
-
requestId: string;
|
|
4504
|
-
toolName: string;
|
|
4505
|
-
} | {
|
|
4506
|
-
type: "approval_resolved";
|
|
4507
|
-
requestId: string;
|
|
4508
|
-
approved: boolean;
|
|
4509
|
-
};
|
|
4510
|
-
/** Per-call options for run() */
|
|
4511
|
-
interface RunCallOptions {
|
|
4512
|
-
/** Override output guardrails for this call only. Set to [] to skip. */
|
|
4513
|
-
outputGuardrails?: Array<GuardrailFn<OutputGuardrailData> | NamedGuardrail<OutputGuardrailData>>;
|
|
4514
|
-
/** Override input guardrails for this call only. Set to [] to skip. */
|
|
4515
|
-
inputGuardrails?: Array<GuardrailFn<InputGuardrailData> | NamedGuardrail<InputGuardrailData>>;
|
|
4516
|
-
/** Signal for abort */
|
|
3590
|
+
/** Dataset of test cases */
|
|
3591
|
+
dataset: EvalCase[];
|
|
3592
|
+
/** Run options passed to the runner */
|
|
3593
|
+
runOptions?: Omit<RunOptions, "signal">;
|
|
3594
|
+
/** Maximum concurrent agent runs. Default: 5 */
|
|
3595
|
+
concurrency?: number;
|
|
3596
|
+
/** Optional debug timeline for recording eval events */
|
|
3597
|
+
timeline?: DebugTimeline;
|
|
3598
|
+
/** Callback fired on each case completion */
|
|
3599
|
+
onCaseComplete?: (result: EvalCaseResult) => void;
|
|
3600
|
+
/** Callback fired on each agent completion */
|
|
3601
|
+
onAgentComplete?: (summary: EvalAgentSummary) => void;
|
|
3602
|
+
/** Abort signal */
|
|
4517
3603
|
signal?: AbortSignal;
|
|
4518
3604
|
}
|
|
4519
|
-
/**
|
|
4520
|
-
interface
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
/** Run
|
|
4524
|
-
|
|
4525
|
-
/**
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
/**
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
3605
|
+
/** Eval suite instance */
|
|
3606
|
+
interface EvalSuite {
|
|
3607
|
+
/** Run the full evaluation */
|
|
3608
|
+
run(): Promise<EvalResults>;
|
|
3609
|
+
/** Run evaluation for a specific agent only */
|
|
3610
|
+
runAgent(agentName: string): Promise<EvalAgentSummary>;
|
|
3611
|
+
/** Get the list of agents being evaluated */
|
|
3612
|
+
getAgents(): AgentLike[];
|
|
3613
|
+
/** Get the list of criteria */
|
|
3614
|
+
getCriteria(): string[];
|
|
3615
|
+
/** Get the dataset */
|
|
3616
|
+
getDataset(): EvalCase[];
|
|
3617
|
+
}
|
|
3618
|
+
/** Options for cost evaluation */
|
|
3619
|
+
interface EvalCostOptions {
|
|
3620
|
+
/** Maximum tokens per run */
|
|
3621
|
+
maxTokensPerRun: number;
|
|
3622
|
+
}
|
|
3623
|
+
/**
|
|
3624
|
+
* Evaluate cost efficiency — scores based on token usage relative to a budget.
|
|
3625
|
+
*
|
|
3626
|
+
* Score = 1.0 when tokens <= maxTokensPerRun * 0.5
|
|
3627
|
+
* Score = 0.0 when tokens >= maxTokensPerRun * 2
|
|
3628
|
+
* Linear interpolation between.
|
|
3629
|
+
*/
|
|
3630
|
+
declare function evalCost(options: EvalCostOptions): EvalCriterion;
|
|
3631
|
+
/** Options for latency evaluation */
|
|
3632
|
+
interface EvalLatencyOptions {
|
|
3633
|
+
/** Maximum acceptable latency (ms) */
|
|
3634
|
+
maxMs: number;
|
|
3635
|
+
}
|
|
3636
|
+
/**
|
|
3637
|
+
* Evaluate latency — scores based on agent run duration.
|
|
3638
|
+
*
|
|
3639
|
+
* Score = 1.0 when duration <= maxMs * 0.5
|
|
3640
|
+
* Score = 0.0 when duration >= maxMs * 2
|
|
3641
|
+
* Linear interpolation between.
|
|
3642
|
+
*/
|
|
3643
|
+
declare function evalLatency(options: EvalLatencyOptions): EvalCriterion;
|
|
3644
|
+
/** Options for output length evaluation */
|
|
3645
|
+
interface EvalOutputLengthOptions {
|
|
3646
|
+
/** Minimum output length (chars) */
|
|
3647
|
+
minLength?: number;
|
|
3648
|
+
/** Maximum output length (chars) */
|
|
3649
|
+
maxLength?: number;
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Evaluate output length — ensures output is within an acceptable range.
|
|
3653
|
+
*/
|
|
3654
|
+
declare function evalOutputLength(options: EvalOutputLengthOptions): EvalCriterion;
|
|
3655
|
+
/** Options for safety evaluation */
|
|
3656
|
+
interface EvalSafetyOptions {
|
|
3657
|
+
/** Patterns to check for in output (overrides categories) */
|
|
3658
|
+
blockedPatterns?: RegExp[];
|
|
3659
|
+
/** Categories of content to check: "pii", "violence", "self_harm", "illegal" */
|
|
3660
|
+
categories?: Array<"pii" | "violence" | "self_harm" | "illegal">;
|
|
3661
|
+
}
|
|
3662
|
+
/**
|
|
3663
|
+
* Evaluate safety — checks output for blocked patterns or category-based content.
|
|
3664
|
+
*
|
|
3665
|
+
* When `categories` is provided, uses built-in pattern sets for each category.
|
|
3666
|
+
* When `blockedPatterns` is provided, uses those directly (overrides categories).
|
|
3667
|
+
* When neither is provided, defaults to all safety categories.
|
|
3668
|
+
*
|
|
3669
|
+
* Score = 1.0 when no blocked patterns found.
|
|
3670
|
+
* Score = 0.0 when any blocked pattern matches.
|
|
3671
|
+
*/
|
|
3672
|
+
declare function evalSafety(options?: EvalSafetyOptions): EvalCriterion;
|
|
3673
|
+
/** Options for output structure evaluation */
|
|
3674
|
+
interface EvalStructureOptions {
|
|
3675
|
+
/** Expected output type */
|
|
3676
|
+
type?: "json" | "string";
|
|
3677
|
+
/** Required keys if type is "json" */
|
|
3678
|
+
requiredKeys?: string[];
|
|
3679
|
+
}
|
|
3680
|
+
/**
|
|
3681
|
+
* Evaluate output structure — checks that output matches an expected format.
|
|
3682
|
+
*/
|
|
3683
|
+
declare function evalStructure(options: EvalStructureOptions): EvalCriterion;
|
|
3684
|
+
/**
|
|
3685
|
+
* Evaluate with a custom LLM judge — uses a runner to grade the output.
|
|
3686
|
+
*
|
|
3687
|
+
* The judge agent receives the input, output, and expected answer, and
|
|
3688
|
+
* returns a JSON score.
|
|
3689
|
+
*/
|
|
3690
|
+
interface EvalJudgeOptions {
|
|
3691
|
+
/** Runner to use for the judge */
|
|
3692
|
+
runner: AgentRunner;
|
|
3693
|
+
/** Judge agent */
|
|
3694
|
+
judge: AgentLike;
|
|
3695
|
+
/** Custom grading prompt template. {{input}}, {{output}}, {{expected}} are replaced. */
|
|
3696
|
+
promptTemplate?: string;
|
|
3697
|
+
/** Optional abort signal */
|
|
3698
|
+
signal?: AbortSignal;
|
|
3699
|
+
/** Timeout for the judge call in ms. Default: 30_000 */
|
|
3700
|
+
timeoutMs?: number;
|
|
3701
|
+
}
|
|
3702
|
+
declare function evalJudge(options: EvalJudgeOptions): EvalCriterion;
|
|
3703
|
+
/**
|
|
3704
|
+
* Evaluate exact or substring match against expected output.
|
|
3705
|
+
*/
|
|
3706
|
+
interface EvalMatchOptions {
|
|
3707
|
+
/** Match mode. Default: "contains" */
|
|
3708
|
+
mode?: "exact" | "contains" | "regex";
|
|
3709
|
+
/** Case-insensitive matching. Default: true */
|
|
3710
|
+
caseInsensitive?: boolean;
|
|
3711
|
+
}
|
|
3712
|
+
declare function evalMatch(options?: EvalMatchOptions): EvalCriterion;
|
|
3713
|
+
/** Options for LLM-based semantic evaluation criteria */
|
|
3714
|
+
interface EvalSemanticOptions {
|
|
3715
|
+
/** Runner to use for the judge LLM */
|
|
3716
|
+
runner: AgentRunner;
|
|
3717
|
+
/** Judge agent (model to use for evaluation) */
|
|
3718
|
+
judge: AgentLike;
|
|
3719
|
+
/** Optional abort signal */
|
|
3720
|
+
signal?: AbortSignal;
|
|
3721
|
+
/** Timeout for the judge call in ms. Default: 30_000 */
|
|
3722
|
+
timeoutMs?: number;
|
|
3723
|
+
}
|
|
3724
|
+
/**
|
|
3725
|
+
* Evaluate faithfulness — whether the output is grounded in the provided context.
|
|
3726
|
+
*
|
|
3727
|
+
* Requires `context` field on the EvalCase. Uses an LLM judge internally
|
|
3728
|
+
* to extract and verify claims against the reference context.
|
|
3729
|
+
*/
|
|
3730
|
+
declare function evalFaithfulness(options: EvalSemanticOptions): EvalCriterion;
|
|
3731
|
+
/**
|
|
3732
|
+
* Evaluate relevance — whether the output directly addresses the input question.
|
|
3733
|
+
*
|
|
3734
|
+
* Uses an LLM judge to assess how well the agent's output answers
|
|
3735
|
+
* the original question.
|
|
3736
|
+
*/
|
|
3737
|
+
declare function evalRelevance(options: EvalSemanticOptions): EvalCriterion;
|
|
3738
|
+
/**
|
|
3739
|
+
* Evaluate coherence — whether the output is logically consistent and well-structured.
|
|
3740
|
+
*
|
|
3741
|
+
* Uses an LLM judge to assess the internal coherence, logical flow,
|
|
3742
|
+
* and consistency of the output.
|
|
3743
|
+
*/
|
|
3744
|
+
declare function evalCoherence(options: EvalSemanticOptions): EvalCriterion;
|
|
3745
|
+
/**
|
|
3746
|
+
* Create an evaluation suite for testing agents against a dataset.
|
|
3747
|
+
*
|
|
3748
|
+
* @example
|
|
3749
|
+
* ```typescript
|
|
3750
|
+
* const suite = createEvalSuite({
|
|
3751
|
+
* criteria: {
|
|
3752
|
+
* fast: evalLatency({ maxMs: 3000 }),
|
|
3753
|
+
* cheap: evalCost({ maxTokensPerRun: 5000 }),
|
|
3754
|
+
* },
|
|
3755
|
+
* agents: [researchAgent, writerAgent],
|
|
3756
|
+
* runner: myRunner,
|
|
3757
|
+
* dataset: [{ input: "What is AI?" }],
|
|
3758
|
+
* });
|
|
3759
|
+
*
|
|
3760
|
+
* const results = await suite.run();
|
|
3761
|
+
* ```
|
|
3762
|
+
*/
|
|
3763
|
+
declare function createEvalSuite(config: EvalSuiteConfig): EvalSuite;
|
|
3764
|
+
/** Options for eval assertions in CI */
|
|
3765
|
+
interface EvalAssertOptions {
|
|
3766
|
+
/** Minimum weighted overall score required (0.0-1.0) */
|
|
3767
|
+
minScore?: number;
|
|
3768
|
+
/** Minimum pass rate required (0.0-1.0) */
|
|
3769
|
+
minPassRate?: number;
|
|
3770
|
+
/** Criteria that must achieve 100% pass rate */
|
|
3771
|
+
failOn?: string[];
|
|
4557
3772
|
}
|
|
4558
3773
|
/**
|
|
4559
|
-
*
|
|
3774
|
+
* Assert eval results meet requirements — designed for CI pipelines.
|
|
3775
|
+
*
|
|
3776
|
+
* Throws an error with details if any assertion fails.
|
|
3777
|
+
*
|
|
3778
|
+
* @example
|
|
3779
|
+
* ```typescript
|
|
3780
|
+
* const results = await suite.run();
|
|
3781
|
+
* evalAssert(results, {
|
|
3782
|
+
* minScore: 0.8,
|
|
3783
|
+
* minPassRate: 0.9,
|
|
3784
|
+
* failOn: ["safety"],
|
|
3785
|
+
* });
|
|
3786
|
+
* ```
|
|
3787
|
+
*/
|
|
3788
|
+
declare function evalAssert(results: EvalResults, options: EvalAssertOptions): void;
|
|
3789
|
+
|
|
3790
|
+
/**
|
|
3791
|
+
* OpenTelemetry Integration — AI-specific observability spans.
|
|
3792
|
+
*
|
|
3793
|
+
* Auto-instruments agent orchestrators with OpenTelemetry spans for
|
|
3794
|
+
* agent runs, guardrail checks, constraint evaluations, and DAG execution.
|
|
3795
|
+
* Works with any OTEL-compatible collector (Jaeger, Zipkin, Honeycomb, etc.).
|
|
3796
|
+
*
|
|
3797
|
+
* Uses OpenTelemetry GenAI semantic conventions (`gen_ai.*`) for
|
|
3798
|
+
* AI-specific attributes alongside Directive-specific attributes.
|
|
4560
3799
|
*
|
|
4561
3800
|
* @example
|
|
4562
3801
|
* ```typescript
|
|
4563
|
-
* import {
|
|
3802
|
+
* import { createOtelPlugin } from "@directive-run/ai";
|
|
4564
3803
|
*
|
|
4565
3804
|
* const orchestrator = createAgentOrchestrator({
|
|
4566
3805
|
* runner,
|
|
4567
|
-
*
|
|
4568
|
-
* escalateToExpert: {
|
|
4569
|
-
* when: (facts) => facts.agent.output?.confidence < 0.7,
|
|
4570
|
-
* require: (facts) => ({
|
|
4571
|
-
* type: 'RUN_EXPERT_AGENT',
|
|
4572
|
-
* query: facts.agent.input,
|
|
4573
|
-
* }),
|
|
4574
|
-
* },
|
|
4575
|
-
* budgetExceeded: {
|
|
4576
|
-
* when: (facts) => facts.agent.tokenUsage > 10000,
|
|
4577
|
-
* require: { type: 'PAUSE_AGENTS' },
|
|
4578
|
-
* },
|
|
4579
|
-
* },
|
|
4580
|
-
* guardrails: {
|
|
4581
|
-
* input: [
|
|
4582
|
-
* async (data) => {
|
|
4583
|
-
* const hasPII = await detectPII(data.input);
|
|
4584
|
-
* return { passed: !hasPII, reason: hasPII ? 'Contains PII' : undefined };
|
|
4585
|
-
* },
|
|
4586
|
-
* ],
|
|
4587
|
-
* output: [
|
|
4588
|
-
* async (data) => {
|
|
4589
|
-
* const isToxic = await checkToxicity(data.output);
|
|
4590
|
-
* return { passed: !isToxic, reason: isToxic ? 'Toxic content' : undefined };
|
|
4591
|
-
* },
|
|
4592
|
-
* ],
|
|
4593
|
-
* },
|
|
3806
|
+
* plugins: [createOtelPlugin({ serviceName: "my-ai-app" })],
|
|
4594
3807
|
* });
|
|
4595
|
-
*
|
|
4596
|
-
* // Run with guardrails and constraint-driven orchestration
|
|
4597
|
-
* const result = await orchestrator.run(myAgent, 'Hello, can you help me?');
|
|
3808
|
+
* // Every run() creates spans with: agent name, model, tokens, cost, duration
|
|
4598
3809
|
* ```
|
|
4599
3810
|
*
|
|
4600
|
-
* @
|
|
3811
|
+
* @module
|
|
4601
3812
|
*/
|
|
4602
|
-
|
|
4603
|
-
/**
|
|
4604
|
-
interface
|
|
4605
|
-
/**
|
|
4606
|
-
|
|
4607
|
-
/** Add
|
|
4608
|
-
|
|
4609
|
-
/**
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
3813
|
+
|
|
3814
|
+
/** Minimal span interface compatible with OpenTelemetry API */
|
|
3815
|
+
interface OtelSpan {
|
|
3816
|
+
/** Set an attribute on the span */
|
|
3817
|
+
setAttribute(key: string, value: string | number | boolean): void;
|
|
3818
|
+
/** Add an event to the span */
|
|
3819
|
+
addEvent(name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
3820
|
+
/** Set the span status */
|
|
3821
|
+
setStatus(status: {
|
|
3822
|
+
code: number;
|
|
3823
|
+
message?: string;
|
|
3824
|
+
}): void;
|
|
3825
|
+
/** End the span */
|
|
3826
|
+
end(): void;
|
|
3827
|
+
}
|
|
3828
|
+
/** OTEL status codes as a const object (no enum overhead) */
|
|
3829
|
+
declare const OtelStatusCode: {
|
|
3830
|
+
readonly UNSET: 0;
|
|
3831
|
+
readonly OK: 1;
|
|
3832
|
+
readonly ERROR: 2;
|
|
3833
|
+
};
|
|
3834
|
+
type OtelStatusCode = (typeof OtelStatusCode)[keyof typeof OtelStatusCode];
|
|
3835
|
+
/** Tracer interface compatible with OpenTelemetry API */
|
|
3836
|
+
interface OtelTracer {
|
|
3837
|
+
/** Start a new span */
|
|
3838
|
+
startSpan(name: string, options?: {
|
|
3839
|
+
attributes?: Record<string, string | number | boolean>;
|
|
3840
|
+
}): OtelSpan;
|
|
3841
|
+
}
|
|
3842
|
+
/** Configuration for the OTEL plugin */
|
|
3843
|
+
interface OtelPluginConfig {
|
|
3844
|
+
/** Service name for span attribution */
|
|
3845
|
+
serviceName: string;
|
|
3846
|
+
/** Custom tracer instance. If not provided, uses a no-op tracer for standalone span collection. */
|
|
3847
|
+
tracer?: OtelTracer;
|
|
3848
|
+
/** Span prefix. Default: "directive.ai" */
|
|
3849
|
+
spanPrefix?: string;
|
|
3850
|
+
/** Span processor callback — called for every completed span. Useful for custom exporters. */
|
|
3851
|
+
onSpanEnd?: (spanData: SpanData) => void;
|
|
3852
|
+
/** Event types to instrument. Default: all */
|
|
3853
|
+
instrumentEvents?: Set<string>;
|
|
3854
|
+
/** TTL for active spans in ms. Spans older than this are cleaned up. Default: 300000 (5 min) */
|
|
3855
|
+
spanTtlMs?: number;
|
|
3856
|
+
}
|
|
3857
|
+
/** Serializable span data for export */
|
|
3858
|
+
interface SpanData {
|
|
3859
|
+
name: string;
|
|
3860
|
+
traceId: string;
|
|
3861
|
+
spanId: string;
|
|
3862
|
+
parentSpanId?: string;
|
|
3863
|
+
attributes: Record<string, string | number | boolean>;
|
|
3864
|
+
events: Array<{
|
|
3865
|
+
name: string;
|
|
3866
|
+
attributes?: Record<string, string | number | boolean>;
|
|
3867
|
+
timestamp: number;
|
|
3868
|
+
}>;
|
|
3869
|
+
status: {
|
|
3870
|
+
code: OtelStatusCode;
|
|
3871
|
+
message?: string;
|
|
3872
|
+
};
|
|
3873
|
+
startTime: number;
|
|
3874
|
+
endTime: number;
|
|
3875
|
+
durationMs: number;
|
|
3876
|
+
}
|
|
3877
|
+
/** OTEL Plugin instance */
|
|
3878
|
+
interface OtelPlugin {
|
|
3879
|
+
/** Attach to a debug timeline to auto-instrument */
|
|
3880
|
+
attach(timeline: DebugTimeline): () => void;
|
|
3881
|
+
/** Get all collected spans (when using built-in collector) */
|
|
3882
|
+
getSpans(): SpanData[];
|
|
3883
|
+
/** Clear collected spans */
|
|
3884
|
+
clearSpans(): void;
|
|
3885
|
+
/** Get the underlying tracer */
|
|
3886
|
+
getTracer(): OtelTracer;
|
|
3887
|
+
/** Get count of currently active (in-flight) spans */
|
|
3888
|
+
getActiveSpanCount(): number;
|
|
4631
3889
|
}
|
|
4632
3890
|
/**
|
|
4633
|
-
* Create
|
|
3891
|
+
* Create an OpenTelemetry plugin for AI observability.
|
|
3892
|
+
*
|
|
3893
|
+
* Subscribes to a DebugTimeline and creates spans for agent runs,
|
|
3894
|
+
* guardrail checks, constraint evaluations, resolver executions,
|
|
3895
|
+
* and execution patterns (DAG, parallel, sequential, etc.).
|
|
3896
|
+
*
|
|
3897
|
+
* Parent-child relationships:
|
|
3898
|
+
* - Pattern spans are roots
|
|
3899
|
+
* - Agent spans are children of the active pattern span (if any)
|
|
3900
|
+
* - Guardrail/resolver spans within an agent run are children of the agent span
|
|
3901
|
+
* - Constraint evaluations within an agent run are recorded as span events
|
|
4634
3902
|
*
|
|
4635
3903
|
* @example
|
|
4636
3904
|
* ```typescript
|
|
4637
|
-
*
|
|
4638
|
-
*
|
|
4639
|
-
*
|
|
4640
|
-
*
|
|
4641
|
-
*
|
|
4642
|
-
*
|
|
4643
|
-
*
|
|
4644
|
-
*
|
|
4645
|
-
*
|
|
4646
|
-
*
|
|
3905
|
+
* // With built-in span collection:
|
|
3906
|
+
* const otel = createOtelPlugin({ serviceName: "my-app" });
|
|
3907
|
+
* const unsub = otel.attach(orchestrator.timeline);
|
|
3908
|
+
* await orchestrator.run(agent, input);
|
|
3909
|
+
* console.log(otel.getSpans()); // All spans from the run
|
|
3910
|
+
*
|
|
3911
|
+
* // With custom OTEL tracer:
|
|
3912
|
+
* import { trace } from "@opentelemetry/api";
|
|
3913
|
+
* const otel = createOtelPlugin({
|
|
3914
|
+
* serviceName: "my-app",
|
|
3915
|
+
* tracer: trace.getTracer("directive-ai"),
|
|
3916
|
+
* });
|
|
4647
3917
|
* ```
|
|
4648
3918
|
*/
|
|
4649
|
-
declare function
|
|
3919
|
+
declare function createOtelPlugin(config: OtelPluginConfig): OtelPlugin;
|
|
4650
3920
|
|
|
4651
|
-
export { type ANNIndex, type ANNSearchResult, AdapterHooks, type AgentInfo, AgentLike, type
|
|
3921
|
+
export { type ANNIndex, type ANNSearchResult, AdapterHooks, AgentHealthMetrics, type AgentInfo, AgentLike, type AgentMessage, type AgentMessageType, type AgentNetwork, type AgentNetworkConfig, AgentRunner, AgentState, AllProvidersFailedError, ApprovalState, type AuditEventType, type AuditInstance, type AuditPluginConfig, type BatchQueue, type BatchQueueConfig, type BidirectionalStream, type BudgetConfig, type BudgetExceededDetails, BudgetExceededError, type BudgetRunner, type BudgetWindow, type ComplianceConfig, type ComplianceInstance, type ComplianceStorage, type ConnectDevToolsOptions, type ConstraintRouterConfig, type ConstraintRouterRunner, type CreateRunnerOptions, DEFAULT_INJECTION_PATTERNS, DebugEvent, DebugTimeline, type DelegationMessage, type DelegationResultMessage, type DevToolsClient, type DevToolsClientMessage, type DevToolsCompatibleOrchestrator, type DevToolsServer, type DevToolsServerConfig, type DevToolsServerMessage, type DevToolsSnapshot, type DevToolsTransport, EmbedderFn, Embedding, type EnhancedPIIGuardrailOptions, type EvalAgentSummary, type EvalAssertOptions, type EvalCase, type EvalCaseResult, type EvalContext, type EvalCostOptions, type EvalCriterion, type EvalCriterionFn, type EvalJudgeOptions, type EvalLatencyOptions, type EvalMatchOptions, type EvalOutputLengthOptions, type EvalResults, type EvalSafetyOptions, type EvalScore, type EvalSemanticOptions, type EvalStructureOptions, type EvalSuite, type EvalSuiteConfig, ExecutionPattern, type FallbackConfig, type GoalAgentDeclaration, type GoalDependencyEdge, type GoalDependencyGraph, type GoalExecutionPlan, type GoalExplanation, type GoalExplanationStep, type GoalPlanStep, GoalResult, type GoalValidationResult, GuardrailFn, HealthMonitor, 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 MermaidDirection, type MermaidNodeShapes, type MermaidOptions, Message, type MessageBus, type MessageBusConfig, type MessageFilter, type MessageHandler, type ModelRule, type ModelSelectionConfig, type OtelPlugin, type OtelPluginConfig, type OtelSpan, OtelStatusCode, type OtelTracer, OutputGuardrailData, type ParsedResponse, 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, RunOptions, RunResult, type RunnerMiddleware, type SSEEvent, type SSETransport, type SSETransportConfig, STRICT_INJECTION_PATTERNS, SchemaValidator, SerializedPattern, type SpanData, type StreamChannel, type StreamChannelConfig, type StreamChannelState, type Subscription, type TokenPricing, ToolCallGuardrailData, type TypedAgentMessage, type UpdateMessage, type VPTreeIndexConfig, type WsTransportConfig, byAgentName, byInputLength, byPattern, connectDevTools, convertToolsForLLM, createAgentAuditHandlers, createAgentNetwork, createAuditTrail, createBatchQueue, createBidirectionalStream, createBruteForceIndex, createCompliance, createConstraintRouter, createContentFilterGuardrail, createDelegator, createDevToolsServer, createEnhancedPIIGuardrail, createEvalSuite, createInMemoryComplianceStorage, createJSONFileStore, createLengthGuardrail, createMCPAdapter, createMessageBus, createModerationGuardrail, createOtelPlugin, createOutputPIIGuardrail, createOutputSchemaGuardrail, createOutputTypeGuardrail, createPIIGuardrail, createPromptInjectionGuardrail, createPubSub, createRAGEnricher, createRateLimitGuardrail, createResponder, createRunner, createSSETransport, createStreamChannel, createToolGuardrail, createUntrustedContentGuardrail, createVPTreeIndex, createWsTransport, detectPII, detectPromptInjection, estimateCost, evalAssert, evalCoherence, evalCost, evalFaithfulness, evalJudge, evalLatency, evalMatch, evalOutputLength, evalRelevance, evalSafety, evalStructure, explainGoal, getDependencyGraph, hasPendingApprovals, isAgentRunning, markUntrustedContent, mcpCallTool, mcpGetPrompt, mcpReadResource, mcpSyncResources, mergeStreams, parseHttpStatus, parseRetryAfter, patternToMermaid, pipe, pipeThrough, planGoal, redactPII, sanitizeInjection, validateBaseURL, validateGoal, withBudget, withFallback, withModelSelection, withRetry };
|