@directive-run/core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/adapter-utils.cjs +2 -0
- package/dist/adapter-utils.cjs.map +1 -0
- package/dist/adapter-utils.d.cts +230 -0
- package/dist/adapter-utils.d.ts +230 -0
- package/dist/adapter-utils.js +2 -0
- package/dist/adapter-utils.js.map +1 -0
- package/dist/index.cjs +35 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2016 -0
- package/dist/index.d.ts +2016 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/migration.cjs +25 -0
- package/dist/migration.cjs.map +1 -0
- package/dist/migration.d.cts +109 -0
- package/dist/migration.d.ts +109 -0
- package/dist/migration.js +25 -0
- package/dist/migration.js.map +1 -0
- package/dist/plugins/index.cjs +3 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.cts +697 -0
- package/dist/plugins/index.d.ts +697 -0
- package/dist/plugins/index.js +3 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins-CcwEXXMS.d.cts +1876 -0
- package/dist/plugins-CcwEXXMS.d.ts +1876 -0
- package/dist/testing.cjs +12 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +235 -0
- package/dist/testing.d.ts +235 -0
- package/dist/testing.js +12 -0
- package/dist/testing.js.map +1 -0
- package/dist/utils-4JrY5fk9.d.cts +198 -0
- package/dist/utils-4JrY5fk9.d.ts +198 -0
- package/dist/worker.cjs +12 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +241 -0
- package/dist/worker.d.ts +241 -0
- package/dist/worker.js +12 -0
- package/dist/worker.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
import { M as ModuleSchema, P as Plugin, J as System } from '../plugins-CcwEXXMS.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logging Plugin - Console logging for Directive events
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface LoggingPluginOptions {
|
|
8
|
+
/** Log level */
|
|
9
|
+
level?: "debug" | "info" | "warn" | "error";
|
|
10
|
+
/** Filter function to include/exclude events */
|
|
11
|
+
filter?: (event: string) => boolean;
|
|
12
|
+
/** Custom logger (defaults to console) */
|
|
13
|
+
logger?: Pick<Console, "debug" | "info" | "warn" | "error" | "group" | "groupEnd">;
|
|
14
|
+
/** Prefix for log messages */
|
|
15
|
+
prefix?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a logging plugin.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const system = createSystem({
|
|
23
|
+
* modules: [myModule],
|
|
24
|
+
* plugins: [loggingPlugin({ level: "debug" })],
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare function loggingPlugin<M extends ModuleSchema = ModuleSchema>(options?: LoggingPluginOptions): Plugin<M>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Devtools Plugin - Browser devtools integration
|
|
32
|
+
*
|
|
33
|
+
* Exposes the system to browser devtools via window.__DIRECTIVE__
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
interface DevtoolsPluginOptions {
|
|
37
|
+
/** Name for this system in devtools */
|
|
38
|
+
name?: string;
|
|
39
|
+
/** Enable trace logging */
|
|
40
|
+
trace?: boolean;
|
|
41
|
+
}
|
|
42
|
+
interface DevtoolsState<M extends ModuleSchema> {
|
|
43
|
+
system: System<M> | null;
|
|
44
|
+
events: Array<{
|
|
45
|
+
timestamp: number;
|
|
46
|
+
type: string;
|
|
47
|
+
data: unknown;
|
|
48
|
+
}>;
|
|
49
|
+
maxEvents: number;
|
|
50
|
+
}
|
|
51
|
+
declare global {
|
|
52
|
+
interface Window {
|
|
53
|
+
__DIRECTIVE__?: {
|
|
54
|
+
systems: Map<string, DevtoolsState<ModuleSchema>>;
|
|
55
|
+
getSystem(name?: string): System<ModuleSchema> | null;
|
|
56
|
+
getSystems(): string[];
|
|
57
|
+
inspect(name?: string): unknown;
|
|
58
|
+
getEvents(name?: string): Array<{
|
|
59
|
+
timestamp: number;
|
|
60
|
+
type: string;
|
|
61
|
+
data: unknown;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a devtools plugin.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const system = createSystem({
|
|
72
|
+
* modules: [myModule],
|
|
73
|
+
* plugins: [devtoolsPlugin({ name: "my-app" })],
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* // In browser console:
|
|
77
|
+
* // __DIRECTIVE__.inspect()
|
|
78
|
+
* // __DIRECTIVE__.getEvents()
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function devtoolsPlugin<M extends ModuleSchema = ModuleSchema>(options?: DevtoolsPluginOptions): Plugin<M>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Persistence Plugin - Save/restore facts to storage
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
interface PersistencePluginOptions {
|
|
88
|
+
/** Storage backend (localStorage, sessionStorage, or custom) */
|
|
89
|
+
storage: Storage;
|
|
90
|
+
/** Key to use in storage */
|
|
91
|
+
key: string;
|
|
92
|
+
/** Only persist these fact keys (default: all) */
|
|
93
|
+
include?: string[];
|
|
94
|
+
/** Exclude these fact keys from persistence */
|
|
95
|
+
exclude?: string[];
|
|
96
|
+
/** Debounce saves by this many ms (default: 100) */
|
|
97
|
+
debounce?: number;
|
|
98
|
+
/** Called when state is restored */
|
|
99
|
+
onRestore?: (data: Record<string, unknown>) => void;
|
|
100
|
+
/** Called when state is saved */
|
|
101
|
+
onSave?: (data: Record<string, unknown>) => void;
|
|
102
|
+
/** Called on error */
|
|
103
|
+
onError?: (error: Error) => void;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a persistence plugin.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const system = createSystem({
|
|
111
|
+
* modules: [myModule],
|
|
112
|
+
* plugins: [
|
|
113
|
+
* persistencePlugin({
|
|
114
|
+
* storage: localStorage,
|
|
115
|
+
* key: "my-app-state",
|
|
116
|
+
* include: ["user", "preferences"],
|
|
117
|
+
* }),
|
|
118
|
+
* ],
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
declare function persistencePlugin<M extends ModuleSchema = ModuleSchema>(options: PersistencePluginOptions): Plugin<M>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Performance Plugin - Track constraint, resolver, and reconciliation metrics
|
|
126
|
+
*
|
|
127
|
+
* Uses existing plugin hooks to measure performance without modifying core runtime.
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/** Metrics for a single constraint */
|
|
131
|
+
interface ConstraintMetrics {
|
|
132
|
+
evaluations: number;
|
|
133
|
+
totalDurationMs: number;
|
|
134
|
+
avgDurationMs: number;
|
|
135
|
+
maxDurationMs: number;
|
|
136
|
+
lastEvaluatedAt: number;
|
|
137
|
+
}
|
|
138
|
+
/** Metrics for a single resolver */
|
|
139
|
+
interface ResolverMetrics {
|
|
140
|
+
starts: number;
|
|
141
|
+
completions: number;
|
|
142
|
+
errors: number;
|
|
143
|
+
retries: number;
|
|
144
|
+
cancellations: number;
|
|
145
|
+
totalDurationMs: number;
|
|
146
|
+
avgDurationMs: number;
|
|
147
|
+
maxDurationMs: number;
|
|
148
|
+
lastCompletedAt: number;
|
|
149
|
+
}
|
|
150
|
+
/** Metrics for the reconciliation loop */
|
|
151
|
+
interface ReconcileMetrics {
|
|
152
|
+
runs: number;
|
|
153
|
+
totalDurationMs: number;
|
|
154
|
+
avgDurationMs: number;
|
|
155
|
+
maxDurationMs: number;
|
|
156
|
+
}
|
|
157
|
+
/** Metrics for effects */
|
|
158
|
+
interface EffectMetrics {
|
|
159
|
+
runs: number;
|
|
160
|
+
errors: number;
|
|
161
|
+
lastRunAt: number;
|
|
162
|
+
}
|
|
163
|
+
/** Full performance snapshot */
|
|
164
|
+
interface PerformanceSnapshot {
|
|
165
|
+
constraints: Record<string, ConstraintMetrics>;
|
|
166
|
+
resolvers: Record<string, ResolverMetrics>;
|
|
167
|
+
effects: Record<string, EffectMetrics>;
|
|
168
|
+
reconcile: ReconcileMetrics;
|
|
169
|
+
uptime: number;
|
|
170
|
+
}
|
|
171
|
+
/** Options for the performance plugin */
|
|
172
|
+
interface PerformancePluginOptions {
|
|
173
|
+
/** Callback when a slow constraint is detected (default threshold: 16ms) */
|
|
174
|
+
onSlowConstraint?: (id: string, durationMs: number) => void;
|
|
175
|
+
/** Callback when a slow resolver is detected (default threshold: 1000ms) */
|
|
176
|
+
onSlowResolver?: (id: string, durationMs: number) => void;
|
|
177
|
+
/** Threshold in ms for slow constraint warning (default: 16) */
|
|
178
|
+
slowConstraintThresholdMs?: number;
|
|
179
|
+
/** Threshold in ms for slow resolver warning (default: 1000) */
|
|
180
|
+
slowResolverThresholdMs?: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Create a performance monitoring plugin.
|
|
184
|
+
*
|
|
185
|
+
* Tracks constraint evaluation time, resolver latency, reconciliation cost,
|
|
186
|
+
* and effect runs using existing plugin hooks.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* const perf = performancePlugin({
|
|
191
|
+
* onSlowResolver: (id, ms) => console.warn(`Slow resolver ${id}: ${ms}ms`),
|
|
192
|
+
* });
|
|
193
|
+
*
|
|
194
|
+
* const system = createSystem({
|
|
195
|
+
* module: myModule,
|
|
196
|
+
* plugins: [perf],
|
|
197
|
+
* });
|
|
198
|
+
*
|
|
199
|
+
* // Later: get a performance snapshot
|
|
200
|
+
* const snapshot = perf.getSnapshot();
|
|
201
|
+
* console.log(snapshot.resolvers);
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
declare function performancePlugin<M extends ModuleSchema = ModuleSchema>(options?: PerformancePluginOptions): Plugin<M> & {
|
|
205
|
+
getSnapshot(): PerformanceSnapshot;
|
|
206
|
+
reset(): void;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Observability Dashboard Plugin
|
|
211
|
+
*
|
|
212
|
+
* Provides comprehensive monitoring, metrics collection, and dashboard integration
|
|
213
|
+
* for AI agent operations.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* import { createObservability, createAgentMetrics } from '@directive-run/ai';
|
|
218
|
+
*
|
|
219
|
+
* const observability = createObservability({
|
|
220
|
+
* metrics: {
|
|
221
|
+
* enabled: true,
|
|
222
|
+
* exportInterval: 10000, // Export every 10 seconds
|
|
223
|
+
* },
|
|
224
|
+
* tracing: {
|
|
225
|
+
* enabled: true,
|
|
226
|
+
* sampleRate: 1.0, // 100% sampling for dev
|
|
227
|
+
* },
|
|
228
|
+
* alerts: [
|
|
229
|
+
* { metric: 'agent.errors', threshold: 10, action: 'warn' },
|
|
230
|
+
* { metric: 'agent.latency', threshold: 5000, action: 'alert' },
|
|
231
|
+
* ],
|
|
232
|
+
* });
|
|
233
|
+
*
|
|
234
|
+
* // Use createAgentMetrics for standard metric names (required for getDashboard() summary)
|
|
235
|
+
* const agentMetrics = createAgentMetrics(observability);
|
|
236
|
+
*
|
|
237
|
+
* // Access dashboard data
|
|
238
|
+
* const dashboard = observability.getDashboard();
|
|
239
|
+
*
|
|
240
|
+
* // Clean up when done
|
|
241
|
+
* await observability.dispose();
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
/** Metric types that can be collected */
|
|
245
|
+
type MetricType = "counter" | "gauge" | "histogram" | "summary";
|
|
246
|
+
/** A single metric data point */
|
|
247
|
+
interface MetricDataPoint {
|
|
248
|
+
name: string;
|
|
249
|
+
type: MetricType;
|
|
250
|
+
value: number;
|
|
251
|
+
labels: Record<string, string>;
|
|
252
|
+
timestamp: number;
|
|
253
|
+
}
|
|
254
|
+
/** Histogram bucket for latency/size distributions */
|
|
255
|
+
interface HistogramBucket {
|
|
256
|
+
le: number;
|
|
257
|
+
count: number;
|
|
258
|
+
}
|
|
259
|
+
/** Aggregated metric for dashboard display */
|
|
260
|
+
interface AggregatedMetric {
|
|
261
|
+
name: string;
|
|
262
|
+
type: MetricType;
|
|
263
|
+
count: number;
|
|
264
|
+
sum: number;
|
|
265
|
+
min: number;
|
|
266
|
+
max: number;
|
|
267
|
+
avg: number;
|
|
268
|
+
p50?: number;
|
|
269
|
+
p90?: number;
|
|
270
|
+
p99?: number;
|
|
271
|
+
lastValue: number;
|
|
272
|
+
lastUpdated: number;
|
|
273
|
+
}
|
|
274
|
+
/** Trace span for distributed tracing */
|
|
275
|
+
interface TraceSpan {
|
|
276
|
+
traceId: string;
|
|
277
|
+
spanId: string;
|
|
278
|
+
parentSpanId?: string;
|
|
279
|
+
operationName: string;
|
|
280
|
+
serviceName: string;
|
|
281
|
+
startTime: number;
|
|
282
|
+
endTime?: number;
|
|
283
|
+
duration?: number;
|
|
284
|
+
status: "ok" | "error" | "timeout";
|
|
285
|
+
tags: Record<string, string | number | boolean>;
|
|
286
|
+
logs: Array<{
|
|
287
|
+
timestamp: number;
|
|
288
|
+
message: string;
|
|
289
|
+
level: "debug" | "info" | "warn" | "error";
|
|
290
|
+
}>;
|
|
291
|
+
}
|
|
292
|
+
/** Alert configuration */
|
|
293
|
+
interface AlertConfig {
|
|
294
|
+
metric: string;
|
|
295
|
+
threshold: number;
|
|
296
|
+
operator?: ">" | "<" | ">=" | "<=" | "==";
|
|
297
|
+
action: "log" | "warn" | "alert" | "callback";
|
|
298
|
+
callback?: (metric: AggregatedMetric, threshold: number) => void;
|
|
299
|
+
cooldownMs?: number;
|
|
300
|
+
}
|
|
301
|
+
/** Alert event when threshold is crossed */
|
|
302
|
+
interface AlertEvent {
|
|
303
|
+
alertId: string;
|
|
304
|
+
metric: string;
|
|
305
|
+
currentValue: number;
|
|
306
|
+
threshold: number;
|
|
307
|
+
operator: string;
|
|
308
|
+
action: string;
|
|
309
|
+
timestamp: number;
|
|
310
|
+
message: string;
|
|
311
|
+
}
|
|
312
|
+
/** Observability configuration */
|
|
313
|
+
interface ObservabilityConfig {
|
|
314
|
+
/** Service name for tracing */
|
|
315
|
+
serviceName?: string;
|
|
316
|
+
/** Metrics configuration */
|
|
317
|
+
metrics?: {
|
|
318
|
+
enabled?: boolean;
|
|
319
|
+
/** Export interval in milliseconds */
|
|
320
|
+
exportInterval?: number;
|
|
321
|
+
/** Custom exporter function */
|
|
322
|
+
exporter?: (metrics: AggregatedMetric[]) => Promise<void>;
|
|
323
|
+
/** Maximum data points to retain per metric */
|
|
324
|
+
maxDataPoints?: number;
|
|
325
|
+
};
|
|
326
|
+
/** Tracing configuration */
|
|
327
|
+
tracing?: {
|
|
328
|
+
enabled?: boolean;
|
|
329
|
+
/** Sample rate (0.0 to 1.0) */
|
|
330
|
+
sampleRate?: number;
|
|
331
|
+
/** Maximum spans to retain */
|
|
332
|
+
maxSpans?: number;
|
|
333
|
+
/** Custom trace exporter */
|
|
334
|
+
exporter?: (spans: TraceSpan[]) => Promise<void>;
|
|
335
|
+
};
|
|
336
|
+
/** Alert configurations */
|
|
337
|
+
alerts?: AlertConfig[];
|
|
338
|
+
/**
|
|
339
|
+
* Metric names used by `getDashboard().summary` and `getHealthStatus()`.
|
|
340
|
+
* Defaults to `agent.requests`, `agent.errors`, `agent.latency`, `agent.tokens`, `agent.cost`.
|
|
341
|
+
* Must match the metric names you record via `incrementCounter` / `observeHistogram`,
|
|
342
|
+
* or use `createAgentMetrics()` which records with these default names.
|
|
343
|
+
*/
|
|
344
|
+
summaryMetrics?: {
|
|
345
|
+
requests?: string;
|
|
346
|
+
errors?: string;
|
|
347
|
+
latency?: string;
|
|
348
|
+
tokens?: string;
|
|
349
|
+
cost?: string;
|
|
350
|
+
};
|
|
351
|
+
/** Event callbacks */
|
|
352
|
+
events?: {
|
|
353
|
+
onMetricRecorded?: (metric: MetricDataPoint) => void;
|
|
354
|
+
onSpanStart?: (span: TraceSpan) => void;
|
|
355
|
+
onSpanEnd?: (span: TraceSpan) => void;
|
|
356
|
+
onAlert?: (alert: AlertEvent) => void;
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
/** Dashboard data for UI display */
|
|
360
|
+
interface DashboardData {
|
|
361
|
+
/** Service info */
|
|
362
|
+
service: {
|
|
363
|
+
name: string;
|
|
364
|
+
uptime: number;
|
|
365
|
+
startTime: number;
|
|
366
|
+
};
|
|
367
|
+
/** Aggregated metrics */
|
|
368
|
+
metrics: Record<string, AggregatedMetric>;
|
|
369
|
+
/** Recent traces */
|
|
370
|
+
traces: TraceSpan[];
|
|
371
|
+
/** Active alerts */
|
|
372
|
+
alerts: AlertEvent[];
|
|
373
|
+
/** Summary stats */
|
|
374
|
+
summary: {
|
|
375
|
+
totalRequests: number;
|
|
376
|
+
totalErrors: number;
|
|
377
|
+
errorRate: number;
|
|
378
|
+
avgLatency: number;
|
|
379
|
+
p99Latency: number;
|
|
380
|
+
activeSpans: number;
|
|
381
|
+
totalTokens: number;
|
|
382
|
+
totalCost: number;
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/** Observability instance */
|
|
386
|
+
interface ObservabilityInstance {
|
|
387
|
+
/** Record a counter metric */
|
|
388
|
+
incrementCounter(name: string, labels?: Record<string, string>, value?: number): void;
|
|
389
|
+
/** Record a gauge metric */
|
|
390
|
+
setGauge(name: string, value: number, labels?: Record<string, string>): void;
|
|
391
|
+
/** Record a histogram observation */
|
|
392
|
+
observeHistogram(name: string, value: number, labels?: Record<string, string>): void;
|
|
393
|
+
/** Start a trace span */
|
|
394
|
+
startSpan(operationName: string, parentSpanId?: string): TraceSpan;
|
|
395
|
+
/** End a trace span */
|
|
396
|
+
endSpan(spanId: string, status?: "ok" | "error" | "timeout"): void;
|
|
397
|
+
/** Add log to a span */
|
|
398
|
+
addSpanLog(spanId: string, message: string, level?: "debug" | "info" | "warn" | "error"): void;
|
|
399
|
+
/** Add tag to a span */
|
|
400
|
+
addSpanTag(spanId: string, key: string, value: string | number | boolean): void;
|
|
401
|
+
/** Get dashboard data */
|
|
402
|
+
getDashboard(): DashboardData;
|
|
403
|
+
/** Get a specific metric */
|
|
404
|
+
getMetric(name: string): AggregatedMetric | undefined;
|
|
405
|
+
/** Get recent traces */
|
|
406
|
+
getTraces(limit?: number): TraceSpan[];
|
|
407
|
+
/** Get active alerts */
|
|
408
|
+
getAlerts(): AlertEvent[];
|
|
409
|
+
/** Export all data */
|
|
410
|
+
export(): {
|
|
411
|
+
metrics: AggregatedMetric[];
|
|
412
|
+
traces: TraceSpan[];
|
|
413
|
+
alerts: AlertEvent[];
|
|
414
|
+
};
|
|
415
|
+
/** Clear all data and reset statistics */
|
|
416
|
+
clear(): void;
|
|
417
|
+
/** Dispose of the instance, clearing timers and flushing data */
|
|
418
|
+
dispose(): Promise<void>;
|
|
419
|
+
/** Get health status for status pages */
|
|
420
|
+
getHealthStatus(): {
|
|
421
|
+
healthy: boolean;
|
|
422
|
+
uptime: number;
|
|
423
|
+
errorRate: number;
|
|
424
|
+
activeAlerts: number;
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Create an observability instance for monitoring AI agents.
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```typescript
|
|
432
|
+
* const obs = createObservability({
|
|
433
|
+
* serviceName: 'my-agent-service',
|
|
434
|
+
* metrics: { enabled: true },
|
|
435
|
+
* tracing: { enabled: true, sampleRate: 0.1 },
|
|
436
|
+
* alerts: [
|
|
437
|
+
* { metric: 'agent.errors', threshold: 10, action: 'alert' },
|
|
438
|
+
* ],
|
|
439
|
+
* });
|
|
440
|
+
*
|
|
441
|
+
* // Track agent operations
|
|
442
|
+
* const span = obs.startSpan('agent.run');
|
|
443
|
+
* obs.incrementCounter('agent.requests', { agent: 'support' });
|
|
444
|
+
*
|
|
445
|
+
* try {
|
|
446
|
+
* await runAgent();
|
|
447
|
+
* obs.observeHistogram('agent.latency', Date.now() - start);
|
|
448
|
+
* obs.endSpan(span.spanId, 'ok');
|
|
449
|
+
* } catch (e) {
|
|
450
|
+
* obs.incrementCounter('agent.errors');
|
|
451
|
+
* obs.endSpan(span.spanId, 'error');
|
|
452
|
+
* }
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
declare function createObservability(config?: ObservabilityConfig): ObservabilityInstance;
|
|
456
|
+
/**
|
|
457
|
+
* Create standard agent metrics for an observability instance.
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* ```typescript
|
|
461
|
+
* const obs = createObservability({ serviceName: 'my-service' });
|
|
462
|
+
* const agentMetrics = createAgentMetrics(obs);
|
|
463
|
+
*
|
|
464
|
+
* // Track an agent run
|
|
465
|
+
* agentMetrics.trackRun('support-agent', {
|
|
466
|
+
* success: true,
|
|
467
|
+
* latencyMs: 1500,
|
|
468
|
+
* inputTokens: 100,
|
|
469
|
+
* outputTokens: 500,
|
|
470
|
+
* cost: 0.05,
|
|
471
|
+
* });
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
declare function createAgentMetrics(obs: ObservabilityInstance): {
|
|
475
|
+
trackRun(agentName: string, result: {
|
|
476
|
+
success: boolean;
|
|
477
|
+
latencyMs: number;
|
|
478
|
+
inputTokens?: number;
|
|
479
|
+
outputTokens?: number;
|
|
480
|
+
cost?: number;
|
|
481
|
+
toolCalls?: number;
|
|
482
|
+
}): void;
|
|
483
|
+
trackGuardrail(guardrailName: string, result: {
|
|
484
|
+
passed: boolean;
|
|
485
|
+
latencyMs: number;
|
|
486
|
+
blocked?: boolean;
|
|
487
|
+
}): void;
|
|
488
|
+
trackApproval(toolName: string, result: {
|
|
489
|
+
approved: boolean;
|
|
490
|
+
waitTimeMs: number;
|
|
491
|
+
timedOut?: boolean;
|
|
492
|
+
}): void;
|
|
493
|
+
trackHandoff(fromAgent: string, toAgent: string, latencyMs: number): void;
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* OTLP (OpenTelemetry Protocol) Exporter
|
|
498
|
+
*
|
|
499
|
+
* Converts Directive observability data to OTLP JSON format for export to
|
|
500
|
+
* Grafana, Datadog, Jaeger, and other OpenTelemetry-compatible backends.
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* ```typescript
|
|
504
|
+
* import { createObservability } from '@directive-run/ai';
|
|
505
|
+
* import { createOTLPExporter } from '@directive-run/ai';
|
|
506
|
+
*
|
|
507
|
+
* const exporter = createOTLPExporter({
|
|
508
|
+
* endpoint: 'http://localhost:4318',
|
|
509
|
+
* headers: { 'Authorization': 'Bearer token' },
|
|
510
|
+
* serviceName: 'my-agent-service',
|
|
511
|
+
* });
|
|
512
|
+
*
|
|
513
|
+
* const obs = createObservability({
|
|
514
|
+
* metrics: { exporter: exporter.exportMetrics, exportInterval: 10000 },
|
|
515
|
+
* tracing: { exporter: exporter.exportTraces },
|
|
516
|
+
* });
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
|
|
520
|
+
/** OTLP exporter configuration */
|
|
521
|
+
interface OTLPExporterConfig {
|
|
522
|
+
/** OTLP endpoint base URL (e.g., http://localhost:4318) */
|
|
523
|
+
endpoint: string;
|
|
524
|
+
/** Optional headers (e.g., auth tokens) */
|
|
525
|
+
headers?: Record<string, string>;
|
|
526
|
+
/** Service name for resource identification */
|
|
527
|
+
serviceName?: string;
|
|
528
|
+
/** Service version */
|
|
529
|
+
serviceVersion?: string;
|
|
530
|
+
/** Custom resource attributes */
|
|
531
|
+
resourceAttributes?: Record<string, string>;
|
|
532
|
+
/** Instrumentation scope version (default: "0.1.0") */
|
|
533
|
+
scopeVersion?: string;
|
|
534
|
+
/** Request timeout in ms (default: 10000) */
|
|
535
|
+
timeoutMs?: number;
|
|
536
|
+
/** Custom fetch function (for testing or custom HTTP clients) */
|
|
537
|
+
fetch?: typeof globalThis.fetch;
|
|
538
|
+
/** Callback on export error */
|
|
539
|
+
onError?: (error: Error, type: "metrics" | "traces") => void;
|
|
540
|
+
}
|
|
541
|
+
/** OTLP exporter instance */
|
|
542
|
+
interface OTLPExporter {
|
|
543
|
+
/** Export metrics in OTLP format (compatible with ObservabilityConfig.metrics.exporter) */
|
|
544
|
+
exportMetrics: (metrics: AggregatedMetric[]) => Promise<void>;
|
|
545
|
+
/** Export traces in OTLP format (compatible with ObservabilityConfig.tracing.exporter) */
|
|
546
|
+
exportTraces: (traces: TraceSpan[]) => Promise<void>;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Create an OTLP exporter for sending metrics and traces to OpenTelemetry-compatible backends.
|
|
550
|
+
*
|
|
551
|
+
* Supports:
|
|
552
|
+
* - Grafana (via OTLP endpoint)
|
|
553
|
+
* - Datadog (via OTLP ingest)
|
|
554
|
+
* - Jaeger (via OTLP collector)
|
|
555
|
+
* - Any OpenTelemetry Collector
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```typescript
|
|
559
|
+
* const exporter = createOTLPExporter({
|
|
560
|
+
* endpoint: 'http://localhost:4318',
|
|
561
|
+
* serviceName: 'my-agent-service',
|
|
562
|
+
* });
|
|
563
|
+
*
|
|
564
|
+
* // Wire into observability
|
|
565
|
+
* const obs = createObservability({
|
|
566
|
+
* metrics: { exporter: exporter.exportMetrics, exportInterval: 10000 },
|
|
567
|
+
* tracing: { exporter: exporter.exportTraces },
|
|
568
|
+
* });
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
571
|
+
declare function createOTLPExporter(config: OTLPExporterConfig): OTLPExporter;
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Circuit Breaker for AI Agent Operations
|
|
575
|
+
*
|
|
576
|
+
* Implements the circuit breaker pattern to prevent cascading failures when
|
|
577
|
+
* downstream services (MCP servers, LLM APIs) are degraded. Integrates with
|
|
578
|
+
* the observability plugin to wire error rates into constraint decisions.
|
|
579
|
+
*
|
|
580
|
+
* States:
|
|
581
|
+
* - CLOSED: Normal operation, requests pass through
|
|
582
|
+
* - OPEN: Failures exceeded threshold, requests are rejected immediately
|
|
583
|
+
* - HALF_OPEN: After recovery timeout, a limited number of requests are allowed through
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```typescript
|
|
587
|
+
* import { createCircuitBreaker } from '@directive-run/ai';
|
|
588
|
+
*
|
|
589
|
+
* const breaker = createCircuitBreaker({
|
|
590
|
+
* failureThreshold: 5,
|
|
591
|
+
* recoveryTimeMs: 30000,
|
|
592
|
+
* halfOpenMaxRequests: 3,
|
|
593
|
+
* });
|
|
594
|
+
*
|
|
595
|
+
* // Use with MCP or any async operation
|
|
596
|
+
* const result = await breaker.execute(async () => {
|
|
597
|
+
* return await callExternalAPI();
|
|
598
|
+
* });
|
|
599
|
+
*
|
|
600
|
+
* // Wire into Directive constraints
|
|
601
|
+
* constraints: {
|
|
602
|
+
* apiDown: {
|
|
603
|
+
* when: () => breaker.getState() === 'OPEN',
|
|
604
|
+
* require: { type: 'FALLBACK_RESPONSE' },
|
|
605
|
+
* },
|
|
606
|
+
* }
|
|
607
|
+
* ```
|
|
608
|
+
*/
|
|
609
|
+
|
|
610
|
+
/** Circuit breaker states */
|
|
611
|
+
type CircuitState = "CLOSED" | "OPEN" | "HALF_OPEN";
|
|
612
|
+
/** Circuit breaker configuration */
|
|
613
|
+
interface CircuitBreakerConfig {
|
|
614
|
+
/** Number of failures before opening the circuit (default: 5) */
|
|
615
|
+
failureThreshold?: number;
|
|
616
|
+
/** Time in ms before transitioning from OPEN to HALF_OPEN (default: 30000) */
|
|
617
|
+
recoveryTimeMs?: number;
|
|
618
|
+
/** Number of requests allowed in HALF_OPEN state (default: 3) */
|
|
619
|
+
halfOpenMaxRequests?: number;
|
|
620
|
+
/** Time window in ms for counting failures (default: 60000). Failures outside this window are forgotten. */
|
|
621
|
+
failureWindowMs?: number;
|
|
622
|
+
/** Optional observability instance for automatic metric tracking */
|
|
623
|
+
observability?: ObservabilityInstance;
|
|
624
|
+
/** Metric name prefix for observability (default: "circuit_breaker") */
|
|
625
|
+
metricPrefix?: string;
|
|
626
|
+
/** Name for this circuit breaker (used in metrics and errors) */
|
|
627
|
+
name?: string;
|
|
628
|
+
/** Custom error classifier. Return true if the error should count as a failure. Default: all errors count. */
|
|
629
|
+
isFailure?: (error: Error) => boolean;
|
|
630
|
+
/** Callback when state changes */
|
|
631
|
+
onStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
632
|
+
}
|
|
633
|
+
/** Circuit breaker statistics */
|
|
634
|
+
interface CircuitBreakerStats {
|
|
635
|
+
state: CircuitState;
|
|
636
|
+
totalRequests: number;
|
|
637
|
+
totalFailures: number;
|
|
638
|
+
totalSuccesses: number;
|
|
639
|
+
totalRejected: number;
|
|
640
|
+
recentFailures: number;
|
|
641
|
+
lastFailureTime: number | null;
|
|
642
|
+
lastSuccessTime: number | null;
|
|
643
|
+
lastStateChange: number;
|
|
644
|
+
}
|
|
645
|
+
/** Circuit breaker instance */
|
|
646
|
+
interface CircuitBreaker {
|
|
647
|
+
/** Execute an operation through the circuit breaker */
|
|
648
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
649
|
+
/** Get the current state */
|
|
650
|
+
getState(): CircuitState;
|
|
651
|
+
/** Get statistics */
|
|
652
|
+
getStats(): CircuitBreakerStats;
|
|
653
|
+
/** Force the circuit to a specific state (useful for testing) */
|
|
654
|
+
forceState(state: CircuitState): void;
|
|
655
|
+
/** Reset the circuit breaker to CLOSED with cleared stats */
|
|
656
|
+
reset(): void;
|
|
657
|
+
/** Check if a request would be allowed (without executing) */
|
|
658
|
+
isAllowed(): boolean;
|
|
659
|
+
}
|
|
660
|
+
/** Error thrown when a request is rejected because the circuit is open */
|
|
661
|
+
declare class CircuitBreakerOpenError extends Error {
|
|
662
|
+
readonly code: "CIRCUIT_OPEN";
|
|
663
|
+
readonly retryAfterMs: number;
|
|
664
|
+
readonly state: "OPEN" | "HALF_OPEN";
|
|
665
|
+
constructor(name: string, retryAfterMs: number, state?: "OPEN" | "HALF_OPEN", detail?: string);
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Create a circuit breaker for protecting against cascading failures.
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* ```typescript
|
|
672
|
+
* const breaker = createCircuitBreaker({
|
|
673
|
+
* name: 'openai-api',
|
|
674
|
+
* failureThreshold: 5,
|
|
675
|
+
* recoveryTimeMs: 30000,
|
|
676
|
+
* observability: obs, // Optional: auto-track metrics
|
|
677
|
+
* });
|
|
678
|
+
*
|
|
679
|
+
* try {
|
|
680
|
+
* const result = await breaker.execute(async () => {
|
|
681
|
+
* return await openai.chat.completions.create({ ... });
|
|
682
|
+
* });
|
|
683
|
+
* } catch (error) {
|
|
684
|
+
* if (error.message.includes('Circuit breaker')) {
|
|
685
|
+
* // Circuit is open, use fallback
|
|
686
|
+
* }
|
|
687
|
+
* }
|
|
688
|
+
* ```
|
|
689
|
+
*
|
|
690
|
+
* @throws {Error} If failureThreshold is less than 1 or not a finite number
|
|
691
|
+
* @throws {Error} If recoveryTimeMs is not positive or not a finite number
|
|
692
|
+
* @throws {Error} If halfOpenMaxRequests is less than 1 or not a finite number
|
|
693
|
+
* @throws {Error} If failureWindowMs is not positive or not a finite number
|
|
694
|
+
*/
|
|
695
|
+
declare function createCircuitBreaker(config?: CircuitBreakerConfig): CircuitBreaker;
|
|
696
|
+
|
|
697
|
+
export { type AggregatedMetric, type AlertConfig, type AlertEvent, type CircuitBreaker, type CircuitBreakerConfig, CircuitBreakerOpenError, type CircuitBreakerStats, type CircuitState, type ConstraintMetrics, type DashboardData, type DevtoolsPluginOptions, type EffectMetrics, type HistogramBucket, type LoggingPluginOptions, type MetricDataPoint, type MetricType, type OTLPExporter, type OTLPExporterConfig, type ObservabilityConfig, type ObservabilityInstance, type PerformancePluginOptions, type PerformanceSnapshot, type PersistencePluginOptions, type ReconcileMetrics, type ResolverMetrics, type TraceSpan, createAgentMetrics, createCircuitBreaker, createOTLPExporter, createObservability, devtoolsPlugin, loggingPlugin, performancePlugin, persistencePlugin };
|