@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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/dist/adapter-utils.cjs +2 -0
  4. package/dist/adapter-utils.cjs.map +1 -0
  5. package/dist/adapter-utils.d.cts +230 -0
  6. package/dist/adapter-utils.d.ts +230 -0
  7. package/dist/adapter-utils.js +2 -0
  8. package/dist/adapter-utils.js.map +1 -0
  9. package/dist/index.cjs +35 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +2016 -0
  12. package/dist/index.d.ts +2016 -0
  13. package/dist/index.js +35 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/migration.cjs +25 -0
  16. package/dist/migration.cjs.map +1 -0
  17. package/dist/migration.d.cts +109 -0
  18. package/dist/migration.d.ts +109 -0
  19. package/dist/migration.js +25 -0
  20. package/dist/migration.js.map +1 -0
  21. package/dist/plugins/index.cjs +3 -0
  22. package/dist/plugins/index.cjs.map +1 -0
  23. package/dist/plugins/index.d.cts +697 -0
  24. package/dist/plugins/index.d.ts +697 -0
  25. package/dist/plugins/index.js +3 -0
  26. package/dist/plugins/index.js.map +1 -0
  27. package/dist/plugins-CcwEXXMS.d.cts +1876 -0
  28. package/dist/plugins-CcwEXXMS.d.ts +1876 -0
  29. package/dist/testing.cjs +12 -0
  30. package/dist/testing.cjs.map +1 -0
  31. package/dist/testing.d.cts +235 -0
  32. package/dist/testing.d.ts +235 -0
  33. package/dist/testing.js +12 -0
  34. package/dist/testing.js.map +1 -0
  35. package/dist/utils-4JrY5fk9.d.cts +198 -0
  36. package/dist/utils-4JrY5fk9.d.ts +198 -0
  37. package/dist/worker.cjs +12 -0
  38. package/dist/worker.cjs.map +1 -0
  39. package/dist/worker.d.cts +241 -0
  40. package/dist/worker.d.ts +241 -0
  41. package/dist/worker.js +12 -0
  42. package/dist/worker.js.map +1 -0
  43. 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 };