@doclo/core 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,933 @@
1
+ /**
2
+ * SDK Observability Hooks
3
+ *
4
+ * Comprehensive observability system for the doclo-sdk SDK.
5
+ * All hooks are optional and async-capable. Hooks never crash execution.
6
+ *
7
+ * @module @doclo/core/observability
8
+ */
9
+ /**
10
+ * Hook Execution Order Guarantees:
11
+ *
12
+ * 1. onFlowStart - Called BEFORE any steps execute
13
+ * 2. onStepStart - Called BEFORE step execution
14
+ * 3. onStepEnd/onStepError - Called AFTER step completes (mutually exclusive)
15
+ * 4. onConsensusStart - Called BEFORE first consensus run
16
+ * 5. onConsensusRunRetry - Called when a consensus run will be retried (before retry)
17
+ * 6. onConsensusRunComplete - Called after EACH consensus run completes (after all retries)
18
+ * 7. onConsensusComplete - Called AFTER all consensus runs and agreement reached
19
+ * 8. onFlowEnd/onFlowError - Called AFTER all steps complete (mutually exclusive)
20
+ *
21
+ * Async Behavior:
22
+ * - SDK WILL wait for async hooks to complete before continuing
23
+ * - Exception: Logs (onLog) are fire-and-forget, no waiting
24
+ * - Hooks run serially, not in parallel
25
+ * - If hook exceeds timeout, SDK logs warning and continues
26
+ *
27
+ * State Isolation:
28
+ * - Hooks cannot modify execution state (read-only by default)
29
+ * - Each hook receives immutable context snapshot
30
+ * - Hooks cannot access other hooks' execution
31
+ */
32
+ interface ObservabilityConfig {
33
+ /** Called when flow execution begins */
34
+ onFlowStart?: (context: FlowStartContext) => void | Promise<void>;
35
+ /** Called when flow completes successfully */
36
+ onFlowEnd?: (context: FlowEndContext) => void | Promise<void>;
37
+ /** Called when flow fails or is cancelled */
38
+ onFlowError?: (context: FlowErrorContext) => void | Promise<void>;
39
+ /** Called before each step executes */
40
+ onStepStart?: (context: StepStartContext) => void | Promise<void>;
41
+ /** Called after step completes successfully */
42
+ onStepEnd?: (context: StepEndContext) => void | Promise<void>;
43
+ /** Called when step fails */
44
+ onStepError?: (context: StepErrorContext) => void | Promise<void>;
45
+ /** Called when consensus decision begins */
46
+ onConsensusStart?: (context: ConsensusStartContext) => void | Promise<void>;
47
+ /** Called when a consensus run will be retried (empty result or error) */
48
+ onConsensusRunRetry?: (context: ConsensusRunRetryContext) => void | Promise<void>;
49
+ /** Called after each individual consensus run (after all retries for that run) */
50
+ onConsensusRunComplete?: (context: ConsensusRunContext) => void | Promise<void>;
51
+ /** Called when consensus decision is reached */
52
+ onConsensusComplete?: (context: ConsensusCompleteContext) => void | Promise<void>;
53
+ /** Called when batch processing begins */
54
+ onBatchStart?: (context: BatchStartContext) => void | Promise<void>;
55
+ /** Called before each batch item is processed */
56
+ onBatchItemStart?: (context: BatchItemContext) => void | Promise<void>;
57
+ /** Called after each batch item completes */
58
+ onBatchItemEnd?: (context: BatchItemEndContext) => void | Promise<void>;
59
+ /** Called when batch processing completes */
60
+ onBatchEnd?: (context: BatchEndContext) => void | Promise<void>;
61
+ /** Called before making a provider request */
62
+ onProviderRequest?: (context: ProviderRequestContext) => void | Promise<void>;
63
+ /** Called after successful provider response */
64
+ onProviderResponse?: (context: ProviderResponseContext) => void | Promise<void>;
65
+ /** Called when provider call will be retried */
66
+ onProviderRetry?: (context: ProviderRetryContext) => void | Promise<void>;
67
+ /** Called when circuit breaker opens for a provider */
68
+ onCircuitBreakerTriggered?: (context: CircuitBreakerContext) => void | Promise<void>;
69
+ /** Called for internal SDK log events (fire-and-forget) */
70
+ onLog?: (context: LogContext) => void | Promise<void>;
71
+ /** Called when a hook itself throws an error */
72
+ onHookError?: (error: HookError) => void;
73
+ /** If true, hook errors will crash execution. Default: false (hooks never crash) */
74
+ failOnHookError?: boolean;
75
+ /** Max milliseconds to wait for async hooks. Default: 5000 */
76
+ hookTimeout?: number;
77
+ /** Enable/disable all hooks. Default: true */
78
+ enabled?: boolean;
79
+ /** Sampling rate 0.0 to 1.0. Default: 1.0 (100%) */
80
+ samplingRate?: number;
81
+ /** Sampling strategy. Default: 'random' */
82
+ samplingStrategy?: 'random' | 'custom';
83
+ /** Custom sampler function (only used if samplingStrategy is 'custom') */
84
+ customSampler?: (context: FlowStartContext) => boolean;
85
+ /** Wait for async hooks to complete. Default: true */
86
+ asyncHooks?: boolean;
87
+ /** Don't wait for hooks (fire-and-forget). Default: false */
88
+ fireAndForget?: boolean;
89
+ /** Custom trace ID generator. Default: crypto-secure random */
90
+ generateTraceId?: () => string;
91
+ /** Custom span ID generator. Default: crypto-secure random */
92
+ generateSpanId?: () => string;
93
+ /** Custom execution ID generator. Default: crypto-secure random */
94
+ generateExecutionId?: () => string;
95
+ /** Propagate existing trace context (for distributed tracing) */
96
+ traceContext?: TraceContextInput;
97
+ /** Observability contract version. Default: "1.0.0" */
98
+ observabilityVersion?: string;
99
+ }
100
+ interface FlowStartContext {
101
+ flowId: string;
102
+ flowVersion: string;
103
+ executionId: string;
104
+ timestamp: number;
105
+ input: unknown;
106
+ config: Record<string, unknown>;
107
+ metadata?: Record<string, unknown>;
108
+ sdkVersion: string;
109
+ observabilityVersion: string;
110
+ traceContext: TraceContext;
111
+ }
112
+ interface FlowEndContext {
113
+ flowId: string;
114
+ executionId: string;
115
+ timestamp: number;
116
+ startTime: number;
117
+ duration: number;
118
+ output: unknown;
119
+ stats: FlowStats;
120
+ metadata?: Record<string, unknown>;
121
+ traceContext: TraceContext;
122
+ }
123
+ interface FlowErrorContext {
124
+ flowId: string;
125
+ executionId: string;
126
+ timestamp: number;
127
+ startTime: number;
128
+ duration: number;
129
+ error: Error;
130
+ errorCode?: string;
131
+ failedAtStepIndex?: number;
132
+ partialStats: FlowStats;
133
+ metadata?: Record<string, unknown>;
134
+ traceContext: TraceContext;
135
+ }
136
+ interface FlowStats {
137
+ stepsTotal: number;
138
+ stepsCompleted: number;
139
+ stepsFailed: number;
140
+ totalTokens: number;
141
+ totalCost: number;
142
+ pagesProcessed?: number;
143
+ documentsProcessed?: number;
144
+ }
145
+ interface StepStartContext {
146
+ flowId: string;
147
+ executionId: string;
148
+ stepId: string;
149
+ stepIndex: number;
150
+ stepType: string;
151
+ stepName: string;
152
+ timestamp: number;
153
+ provider?: string;
154
+ model?: string;
155
+ config: {
156
+ maxTokens?: number;
157
+ temperature?: number;
158
+ topP?: number;
159
+ topK?: number;
160
+ };
161
+ input: unknown;
162
+ isConsensusEnabled: boolean;
163
+ consensusConfig?: {
164
+ runs: number;
165
+ strategy: 'majority' | 'unanimous';
166
+ };
167
+ isRetry: boolean;
168
+ retryAttempt?: number;
169
+ maxRetries?: number;
170
+ metadata?: Record<string, unknown>;
171
+ traceContext: TraceContext;
172
+ spanId: string;
173
+ }
174
+ interface StepEndContext {
175
+ flowId: string;
176
+ executionId: string;
177
+ stepId: string;
178
+ stepIndex: number;
179
+ timestamp: number;
180
+ startTime: number;
181
+ /**
182
+ * Duration of THIS step's own work only (not rolled-up from children).
183
+ * - For 'leaf' steps: The actual API call duration
184
+ * - For 'wrapper' steps: The step's own API call if any, or ~0ms for pure wrappers
185
+ * - For 'prep' steps: The preparation time (usually minimal)
186
+ */
187
+ duration: number;
188
+ output: unknown;
189
+ /**
190
+ * Token usage for THIS step's own API call only (not rolled-up from children).
191
+ * - For 'leaf' steps: The actual token usage
192
+ * - For 'wrapper' steps: Tokens from step's own call (e.g., categorize), or 0 for pure wrappers
193
+ * - For 'prep' steps: Always 0
194
+ */
195
+ usage: {
196
+ inputTokens: number;
197
+ outputTokens: number;
198
+ totalTokens: number;
199
+ cacheCreationInputTokens?: number;
200
+ cacheReadInputTokens?: number;
201
+ };
202
+ /**
203
+ * Cost of THIS step's own API call only (not rolled-up from children).
204
+ * - For 'leaf' steps: The actual cost
205
+ * - For 'wrapper' steps: Cost from step's own call (e.g., categorize), or $0 for pure wrappers
206
+ * - For 'prep' steps: Always $0
207
+ */
208
+ cost: number;
209
+ /**
210
+ * Type of step for metrics interpretation:
211
+ * - 'leaf': Actual LLM/API call (parse, extract, categorize single call)
212
+ * - 'wrapper': Orchestration step with children (conditional, consensus parent, forEach)
213
+ * - 'prep': Utility step with no API call (output node, data transformation)
214
+ */
215
+ metricKind: 'leaf' | 'wrapper' | 'prep';
216
+ responseId?: string;
217
+ finishReason?: string;
218
+ modelUsed?: string;
219
+ httpStatusCode?: number;
220
+ httpMethod?: string;
221
+ httpUrl?: string;
222
+ otelAttributes: Record<string, string | number | boolean>;
223
+ metadata?: Record<string, unknown>;
224
+ traceContext: TraceContext;
225
+ spanId: string;
226
+ }
227
+ interface StepErrorContext {
228
+ flowId: string;
229
+ executionId: string;
230
+ stepId: string;
231
+ stepIndex: number;
232
+ timestamp: number;
233
+ startTime: number;
234
+ duration: number;
235
+ error: Error;
236
+ errorCode?: string;
237
+ partialUsage?: {
238
+ inputTokens?: number;
239
+ outputTokens?: number;
240
+ cacheCreationInputTokens?: number;
241
+ cacheReadInputTokens?: number;
242
+ };
243
+ partialCost?: number;
244
+ willRetry: boolean;
245
+ retryAttempt?: number;
246
+ nextRetryDelay?: number;
247
+ metadata?: Record<string, unknown>;
248
+ traceContext: TraceContext;
249
+ spanId: string;
250
+ }
251
+ interface ConsensusStartContext {
252
+ flowId: string;
253
+ executionId: string;
254
+ stepId: string;
255
+ timestamp: number;
256
+ runsPlanned: number;
257
+ strategy: 'majority' | 'unanimous';
258
+ metadata?: Record<string, unknown>;
259
+ traceContext: TraceContext;
260
+ }
261
+ interface ConsensusRunContext {
262
+ flowId: string;
263
+ executionId: string;
264
+ parentStepId: string;
265
+ consensusRunId: string;
266
+ runIndex: number;
267
+ timestamp: number;
268
+ startTime: number;
269
+ duration: number;
270
+ output: unknown;
271
+ usage: {
272
+ inputTokens: number;
273
+ outputTokens: number;
274
+ totalTokens: number;
275
+ cacheCreationInputTokens?: number;
276
+ cacheReadInputTokens?: number;
277
+ };
278
+ cost: number;
279
+ status: 'success' | 'failed';
280
+ error?: Error;
281
+ totalAttempts: number;
282
+ wasRetried: boolean;
283
+ metadata?: Record<string, unknown>;
284
+ traceContext: TraceContext;
285
+ }
286
+ interface ConsensusCompleteContext {
287
+ flowId: string;
288
+ executionId: string;
289
+ stepId: string;
290
+ timestamp: number;
291
+ totalRuns: number;
292
+ successfulRuns: number;
293
+ failedRuns: number;
294
+ agreement: number;
295
+ agreedOutput: unknown;
296
+ totalUsage: {
297
+ inputTokens: number;
298
+ outputTokens: number;
299
+ totalTokens: number;
300
+ cacheCreationInputTokens?: number;
301
+ cacheReadInputTokens?: number;
302
+ };
303
+ totalCost: number;
304
+ totalRetries: number;
305
+ runsWithRetries: number;
306
+ metadata?: Record<string, unknown>;
307
+ traceContext: TraceContext;
308
+ }
309
+ /**
310
+ * Context for consensus run retry events.
311
+ * Fires immediately when a retry is about to occur (before the retry attempt).
312
+ */
313
+ interface ConsensusRunRetryContext {
314
+ flowId: string;
315
+ executionId: string;
316
+ parentStepId: string;
317
+ consensusRunId: string;
318
+ runIndex: number;
319
+ timestamp: number;
320
+ attemptNumber: number;
321
+ maxAttempts: number;
322
+ reason: 'empty_result' | 'error';
323
+ error?: Error;
324
+ partialUsage?: {
325
+ inputTokens?: number;
326
+ outputTokens?: number;
327
+ };
328
+ partialCost?: number;
329
+ metadata?: Record<string, unknown>;
330
+ traceContext: TraceContext;
331
+ }
332
+ interface BatchStartContext {
333
+ flowId: string;
334
+ executionId: string;
335
+ batchId: string;
336
+ stepId: string;
337
+ totalItems: number;
338
+ timestamp: number;
339
+ metadata?: Record<string, unknown>;
340
+ traceContext: TraceContext;
341
+ }
342
+ interface BatchItemContext {
343
+ flowId: string;
344
+ executionId: string;
345
+ batchId: string;
346
+ stepId: string;
347
+ itemIndex: number;
348
+ totalItems: number;
349
+ item: unknown;
350
+ timestamp: number;
351
+ metadata?: Record<string, unknown>;
352
+ traceContext: TraceContext;
353
+ }
354
+ interface BatchItemEndContext extends BatchItemContext {
355
+ result: unknown;
356
+ duration: number;
357
+ error?: Error;
358
+ status: 'success' | 'failed';
359
+ }
360
+ interface BatchEndContext {
361
+ flowId: string;
362
+ executionId: string;
363
+ batchId: string;
364
+ stepId: string;
365
+ timestamp: number;
366
+ startTime: number;
367
+ duration: number;
368
+ totalItems: number;
369
+ successfulItems: number;
370
+ failedItems: number;
371
+ results: unknown[];
372
+ metadata?: Record<string, unknown>;
373
+ traceContext: TraceContext;
374
+ }
375
+ interface ProviderRequestContext {
376
+ flowId: string;
377
+ executionId: string;
378
+ stepId?: string;
379
+ timestamp: number;
380
+ provider: string;
381
+ model: string;
382
+ input: unknown;
383
+ schema?: unknown;
384
+ httpMethod?: string;
385
+ httpUrl?: string;
386
+ attemptNumber: number;
387
+ maxAttempts?: number;
388
+ metadata?: Record<string, unknown>;
389
+ traceContext: TraceContext;
390
+ }
391
+ interface ProviderResponseContext {
392
+ flowId: string;
393
+ executionId: string;
394
+ stepId?: string;
395
+ timestamp: number;
396
+ startTime: number;
397
+ duration: number;
398
+ provider: string;
399
+ model: string;
400
+ modelUsed?: string;
401
+ output: unknown;
402
+ usage: {
403
+ inputTokens: number;
404
+ outputTokens: number;
405
+ totalTokens: number;
406
+ cacheCreationInputTokens?: number;
407
+ cacheReadInputTokens?: number;
408
+ };
409
+ cost?: number;
410
+ httpStatusCode?: number;
411
+ httpMethod?: string;
412
+ httpUrl?: string;
413
+ responseId?: string;
414
+ finishReason?: string;
415
+ attemptNumber: number;
416
+ metadata?: Record<string, unknown>;
417
+ traceContext: TraceContext;
418
+ }
419
+ interface ProviderRetryContext {
420
+ flowId: string;
421
+ executionId: string;
422
+ stepId?: string;
423
+ timestamp: number;
424
+ provider: string;
425
+ model: string;
426
+ error: Error;
427
+ errorCode?: string;
428
+ attemptNumber: number;
429
+ maxAttempts: number;
430
+ nextRetryDelay: number;
431
+ partialUsage?: {
432
+ inputTokens?: number;
433
+ outputTokens?: number;
434
+ };
435
+ metadata?: Record<string, unknown>;
436
+ traceContext: TraceContext;
437
+ }
438
+ interface CircuitBreakerContext {
439
+ flowId: string;
440
+ executionId: string;
441
+ timestamp: number;
442
+ provider: string;
443
+ model?: string;
444
+ failureCount: number;
445
+ threshold: number;
446
+ cooldownMs: number;
447
+ lastError?: Error;
448
+ metadata?: Record<string, unknown>;
449
+ traceContext: TraceContext;
450
+ }
451
+ interface LogContext {
452
+ flowId: string;
453
+ executionId: string;
454
+ stepId?: string;
455
+ timestamp: number;
456
+ level: 'debug' | 'info' | 'warn' | 'error';
457
+ message: string;
458
+ metadata?: Record<string, unknown>;
459
+ traceContext: TraceContext;
460
+ }
461
+ /**
462
+ * Union of all possible hook context types.
463
+ * Used for generic hook handling where the specific type is unknown.
464
+ */
465
+ type HookContext = FlowStartContext | FlowEndContext | FlowErrorContext | StepStartContext | StepEndContext | StepErrorContext | ConsensusStartContext | ConsensusRunContext | ConsensusCompleteContext | ConsensusRunRetryContext | BatchStartContext | BatchItemContext | BatchItemEndContext | BatchEndContext | ProviderRequestContext | ProviderResponseContext | ProviderRetryContext | CircuitBreakerContext | LogContext;
466
+ interface HookError {
467
+ hookName: string;
468
+ error: Error;
469
+ context: HookContext;
470
+ timestamp: number;
471
+ }
472
+ interface TraceContext {
473
+ traceId: string;
474
+ spanId: string;
475
+ parentSpanId?: string;
476
+ traceFlags: number;
477
+ traceState?: string;
478
+ }
479
+ interface TraceContextInput {
480
+ traceId: string;
481
+ parentSpanId: string;
482
+ traceFlags?: number;
483
+ traceState?: string;
484
+ }
485
+ interface ExecutionContext {
486
+ flowId: string;
487
+ executionId: string;
488
+ currentStepId?: string;
489
+ currentStepIndex?: number;
490
+ startTime: number;
491
+ status: 'running' | 'completed' | 'failed';
492
+ customAttributes: Record<string, unknown>;
493
+ customMetrics: CustomMetric[];
494
+ }
495
+ interface CustomMetric {
496
+ name: string;
497
+ value: number;
498
+ unit?: string;
499
+ timestamp: number;
500
+ }
501
+
502
+ /**
503
+ * Hook Executor
504
+ *
505
+ * Executes observability hooks with timeout protection and error isolation.
506
+ * Ensures hooks never crash flow execution.
507
+ *
508
+ * @module @doclo/core/observability/hook-executor
509
+ */
510
+
511
+ /**
512
+ * Generic hook function type.
513
+ * The context parameter accepts any hook context type since this executor
514
+ * handles all observability hooks (onFlowStart, onStepEnd, onLog, etc.).
515
+ * Each specific hook in ObservabilityConfig has its own typed signature.
516
+ */
517
+ type GenericHookFunction = (context: any) => void | Promise<void>;
518
+ /**
519
+ * Hook execution options
520
+ */
521
+ interface HookExecutionOptions {
522
+ /** Hook name for error reporting */
523
+ hookName: string;
524
+ /** Observability configuration */
525
+ config: ObservabilityConfig;
526
+ /** Context passed to hook - specific type depends on which hook is being called */
527
+ context: HookContext;
528
+ /** Whether this is a fire-and-forget hook (e.g., onLog) */
529
+ fireAndForget?: boolean;
530
+ }
531
+ /**
532
+ * Execute a hook with timeout protection and error isolation
533
+ *
534
+ * @param hook - The hook function to execute
535
+ * @param options - Execution options
536
+ * @returns Promise that resolves when hook completes (or times out)
537
+ */
538
+ declare function executeHook(hook: GenericHookFunction | undefined, options: HookExecutionOptions): Promise<void>;
539
+ /**
540
+ * Execute multiple hooks serially with timeout protection
541
+ *
542
+ * This ensures hooks run one at a time in the order they're provided.
543
+ *
544
+ * @param hooks - Array of hook execution configs
545
+ */
546
+ declare function executeHooksSerial(hooks: Array<{
547
+ hook: GenericHookFunction | undefined;
548
+ options: HookExecutionOptions;
549
+ }>): Promise<void>;
550
+ /**
551
+ * Check if observability is enabled for this execution
552
+ *
553
+ * Takes sampling into account.
554
+ */
555
+ declare function isObservabilityEnabled(config: ObservabilityConfig): boolean;
556
+
557
+ /**
558
+ * Trace Context Generator
559
+ *
560
+ * Implements W3C Trace Context standard for distributed tracing.
561
+ * Generates crypto-secure trace IDs, span IDs, and execution IDs.
562
+ *
563
+ * @see https://www.w3.org/TR/trace-context/
564
+ * @module @doclo/core/observability/trace-context
565
+ */
566
+
567
+ /**
568
+ * Trace flags for sampled traces
569
+ */
570
+ declare const TRACE_FLAGS_SAMPLED = 1;
571
+ /**
572
+ * Trace flags for non-sampled traces
573
+ */
574
+ declare const TRACE_FLAGS_NOT_SAMPLED = 0;
575
+ /**
576
+ * Generate a crypto-secure trace ID (32 lowercase hex characters)
577
+ *
578
+ * Format: 32 hex digits (16 bytes)
579
+ * Example: "4bf92f3577b34da6a3ce929d0e0e4736"
580
+ */
581
+ declare function generateTraceId(): string;
582
+ /**
583
+ * Generate a crypto-secure span ID (16 lowercase hex characters)
584
+ *
585
+ * Format: 16 hex digits (8 bytes)
586
+ * Example: "00f067aa0ba902b7"
587
+ */
588
+ declare function generateSpanId(): string;
589
+ /**
590
+ * Generate a unique execution ID
591
+ *
592
+ * Uses crypto-secure random bytes for uniqueness.
593
+ * Format: UUID v4 style (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
594
+ */
595
+ declare function generateExecutionId(): string;
596
+ /**
597
+ * Create a new trace context for flow execution
598
+ *
599
+ * @param config - Observability configuration
600
+ * @param sampled - Whether this execution is sampled
601
+ * @returns Complete trace context
602
+ */
603
+ declare function createTraceContext(config: ObservabilityConfig, sampled: boolean): TraceContext;
604
+ /**
605
+ * Create a child span context from a parent trace context
606
+ *
607
+ * @param parent - Parent trace context
608
+ * @param config - Observability configuration (for custom span ID generator)
609
+ * @returns New trace context with same traceId but new spanId
610
+ */
611
+ declare function createChildSpanContext(parent: TraceContext, config?: ObservabilityConfig): TraceContext;
612
+ /**
613
+ * Format trace context as W3C traceparent header value
614
+ *
615
+ * Format: "00-{traceId}-{spanId}-{flags}"
616
+ * Example: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
617
+ *
618
+ * @see https://www.w3.org/TR/trace-context/#traceparent-header
619
+ */
620
+ declare function formatTraceparent(context: TraceContext): string;
621
+ /**
622
+ * Parse W3C traceparent header value
623
+ *
624
+ * @param traceparent - Traceparent header value
625
+ * @returns Parsed trace context input or null if invalid
626
+ */
627
+ declare function parseTraceparent(traceparent: string): TraceContextInput | null;
628
+ /**
629
+ * Format trace context as W3C tracestate header value
630
+ *
631
+ * @see https://www.w3.org/TR/trace-context/#tracestate-header
632
+ */
633
+ declare function formatTracestate(context: TraceContext): string | undefined;
634
+ /**
635
+ * Check if trace context is sampled
636
+ */
637
+ declare function isTraceSampled(context: TraceContext): boolean;
638
+ /**
639
+ * Validate trace ID format
640
+ *
641
+ * Must be 32 lowercase hex characters, not all zeros
642
+ */
643
+ declare function isValidTraceId(traceId: string): boolean;
644
+ /**
645
+ * Validate span ID format
646
+ *
647
+ * Must be 16 lowercase hex characters, not all zeros
648
+ */
649
+ declare function isValidSpanId(spanId: string): boolean;
650
+ /**
651
+ * Trace Context Manager
652
+ *
653
+ * Manages trace context for the current execution.
654
+ */
655
+ declare class TraceContextManager {
656
+ private traceContext;
657
+ private config;
658
+ constructor(config: ObservabilityConfig);
659
+ /**
660
+ * Initialize trace context for new execution
661
+ */
662
+ initialize(sampled: boolean): TraceContext;
663
+ /**
664
+ * Get current trace context
665
+ */
666
+ getTraceContext(): TraceContext | null;
667
+ /**
668
+ * Create child span context
669
+ */
670
+ createChildSpan(): TraceContext;
671
+ /**
672
+ * Get traceparent header value
673
+ */
674
+ getTraceparent(): string | null;
675
+ /**
676
+ * Reset trace context (for testing)
677
+ */
678
+ reset(): void;
679
+ }
680
+
681
+ /**
682
+ * OpenTelemetry Semantic Conventions for Gen AI
683
+ *
684
+ * Implements Gen AI semantic conventions (v1.29.0) for observability.
685
+ * Maps SDK data to standard OpenTelemetry attributes.
686
+ *
687
+ * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/
688
+ * @module @doclo/core/observability/otel-attributes
689
+ */
690
+ /**
691
+ * Build OpenTelemetry attributes for LLM operations
692
+ *
693
+ * @param data - Step execution data
694
+ * @returns OpenTelemetry attributes object
695
+ */
696
+ declare function buildOtelAttributes(data: {
697
+ provider?: string;
698
+ model?: string;
699
+ modelUsed?: string;
700
+ stepType?: string;
701
+ inputTokens?: number;
702
+ outputTokens?: number;
703
+ finishReason?: string;
704
+ temperature?: number;
705
+ maxTokens?: number;
706
+ topP?: number;
707
+ topK?: number;
708
+ }): Record<string, string | number | boolean>;
709
+ /**
710
+ * Build OpenTelemetry attributes for provider requests
711
+ *
712
+ * Used for onProviderRequest hooks
713
+ */
714
+ declare function buildProviderRequestAttributes(data: {
715
+ provider: string;
716
+ model: string;
717
+ config?: {
718
+ temperature?: number;
719
+ maxTokens?: number;
720
+ topP?: number;
721
+ topK?: number;
722
+ };
723
+ }): Record<string, string | number | boolean>;
724
+ /**
725
+ * Build OpenTelemetry attributes for provider responses
726
+ *
727
+ * Used for onProviderResponse hooks
728
+ */
729
+ declare function buildProviderResponseAttributes(data: {
730
+ provider: string;
731
+ model: string;
732
+ modelUsed?: string;
733
+ inputTokens: number;
734
+ outputTokens: number;
735
+ finishReason?: string;
736
+ }): Record<string, string | number | boolean>;
737
+ /**
738
+ * Build OpenTelemetry attributes for step execution
739
+ *
740
+ * Used for onStepEnd hooks
741
+ */
742
+ declare function buildStepAttributes(data: {
743
+ stepType: string;
744
+ provider?: string;
745
+ model?: string;
746
+ modelUsed?: string;
747
+ inputTokens?: number;
748
+ outputTokens?: number;
749
+ finishReason?: string;
750
+ config?: {
751
+ temperature?: number;
752
+ maxTokens?: number;
753
+ topP?: number;
754
+ topK?: number;
755
+ };
756
+ }): Record<string, string | number | boolean>;
757
+ /**
758
+ * Standard finish reason mappings
759
+ *
760
+ * Maps provider-specific finish reasons to standard values
761
+ */
762
+ declare const FINISH_REASON_MAPPING: Record<string, string>;
763
+ /**
764
+ * Normalize finish reason to standard value
765
+ */
766
+ declare function normalizeFinishReason(reason: string | undefined): string | undefined;
767
+ /**
768
+ * Add standard OpenTelemetry span attributes
769
+ *
770
+ * These are generic attributes that apply to all spans
771
+ */
772
+ declare function addStandardSpanAttributes(attributes: Record<string, string | number | boolean>, data: {
773
+ spanKind?: 'client' | 'server' | 'internal';
774
+ serviceName?: string;
775
+ serviceVersion?: string;
776
+ }): void;
777
+ /**
778
+ * Build full OpenTelemetry context for export
779
+ *
780
+ * Combines Gen AI attributes with standard span attributes
781
+ */
782
+ declare function buildFullOtelContext(data: {
783
+ stepType?: string;
784
+ provider?: string;
785
+ model?: string;
786
+ modelUsed?: string;
787
+ inputTokens?: number;
788
+ outputTokens?: number;
789
+ finishReason?: string;
790
+ config?: {
791
+ temperature?: number;
792
+ maxTokens?: number;
793
+ topP?: number;
794
+ topK?: number;
795
+ };
796
+ spanKind?: 'client' | 'server' | 'internal';
797
+ serviceName?: string;
798
+ serviceVersion?: string;
799
+ }): Record<string, string | number | boolean>;
800
+
801
+ /**
802
+ * Observability Configuration Defaults
803
+ *
804
+ * Provides default configuration values and config merging utilities.
805
+ *
806
+ * @module @doclo/core/observability/defaults
807
+ */
808
+
809
+ /**
810
+ * Default observability configuration
811
+ */
812
+ declare const DEFAULT_OBSERVABILITY_CONFIG: Required<Omit<ObservabilityConfig, 'onFlowStart' | 'onFlowEnd' | 'onFlowError' | 'onStepStart' | 'onStepEnd' | 'onStepError' | 'onConsensusStart' | 'onConsensusRunRetry' | 'onConsensusRunComplete' | 'onConsensusComplete' | 'onBatchStart' | 'onBatchItemStart' | 'onBatchItemEnd' | 'onBatchEnd' | 'onProviderRequest' | 'onProviderResponse' | 'onProviderRetry' | 'onCircuitBreakerTriggered' | 'onLog' | 'onHookError' | 'customSampler' | 'generateTraceId' | 'generateSpanId' | 'generateExecutionId' | 'traceContext' | 'observabilityVersion'>>;
813
+ /**
814
+ * Merge user config with defaults
815
+ *
816
+ * User config takes precedence over defaults.
817
+ */
818
+ declare function mergeConfig(userConfig?: ObservabilityConfig): ObservabilityConfig;
819
+ /**
820
+ * Determine if execution should be sampled
821
+ *
822
+ * Uses sampling strategy from config.
823
+ */
824
+ declare function shouldSample(config: ObservabilityConfig): boolean;
825
+ /**
826
+ * Validate observability configuration
827
+ *
828
+ * Checks for invalid values and warns about issues.
829
+ */
830
+ declare function validateConfig(config: ObservabilityConfig): {
831
+ valid: boolean;
832
+ warnings: string[];
833
+ errors: string[];
834
+ };
835
+ /**
836
+ * Get observability version
837
+ *
838
+ * Returns the version of the observability contract.
839
+ */
840
+ declare function getObservabilityVersion(config?: ObservabilityConfig): string;
841
+ /**
842
+ * Check if observability is effectively disabled
843
+ *
844
+ * Returns true if observability is explicitly disabled or sampling rate is 0.
845
+ */
846
+ declare function isObservabilityDisabled(config: ObservabilityConfig): boolean;
847
+ /**
848
+ * Check if any hooks are configured
849
+ *
850
+ * Returns true if at least one hook is defined.
851
+ */
852
+ declare function hasAnyHooks(config: ObservabilityConfig): boolean;
853
+ /**
854
+ * Create minimal config for testing
855
+ *
856
+ * Useful for unit tests that don't need full observability.
857
+ */
858
+ declare function createMinimalConfig(overrides?: Partial<ObservabilityConfig>): ObservabilityConfig;
859
+
860
+ /**
861
+ * Logging Utility for Observability
862
+ *
863
+ * Provides a logger that integrates with the observability system.
864
+ * Logs are sent to the onLog hook with fire-and-forget execution.
865
+ *
866
+ * @module @doclo/core/observability/logger
867
+ */
868
+
869
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
870
+ interface LoggerOptions {
871
+ observability?: ObservabilityConfig;
872
+ flowId?: string;
873
+ executionId?: string;
874
+ stepId?: string;
875
+ traceContext?: TraceContext;
876
+ metadata?: Record<string, unknown>;
877
+ }
878
+ /**
879
+ * Logger class that integrates with observability hooks
880
+ */
881
+ declare class Logger {
882
+ private options;
883
+ constructor(options?: LoggerOptions);
884
+ /**
885
+ * Log a debug message
886
+ */
887
+ debug(message: string, data?: unknown): void;
888
+ /**
889
+ * Log an info message
890
+ */
891
+ info(message: string, data?: unknown): void;
892
+ /**
893
+ * Log a warning message
894
+ */
895
+ warn(message: string, data?: unknown): void;
896
+ /**
897
+ * Log an error message
898
+ */
899
+ error(message: string, error?: Error | unknown, data?: unknown): void;
900
+ /**
901
+ * Internal log method that sends to onLog hook
902
+ */
903
+ private log;
904
+ }
905
+ /**
906
+ * Create a logger instance with observability integration
907
+ */
908
+ declare function createLogger(options?: LoggerOptions): Logger;
909
+
910
+ /**
911
+ * Observability Module
912
+ *
913
+ * Comprehensive observability system for the doclo-sdk SDK.
914
+ * Provides hooks, tracing, and monitoring capabilities.
915
+ *
916
+ * @module @doclo/core/observability
917
+ * @example
918
+ * ```typescript
919
+ * import { ObservabilityConfig } from '@doclo/core/observability';
920
+ *
921
+ * const config: ObservabilityConfig = {
922
+ * onFlowStart: (ctx) => console.log('Flow started:', ctx.flowId),
923
+ * onStepEnd: (ctx) => console.log('Step completed:', ctx.stepId, ctx.duration),
924
+ * };
925
+ * ```
926
+ */
927
+
928
+ /**
929
+ * Observability module version
930
+ */
931
+ declare const OBSERVABILITY_VERSION = "1.0.0";
932
+
933
+ export { type BatchEndContext, type BatchItemContext, type BatchItemEndContext, type BatchStartContext, type CircuitBreakerContext, type ConsensusCompleteContext, type ConsensusRunContext, type ConsensusRunRetryContext, type ConsensusStartContext, type CustomMetric, DEFAULT_OBSERVABILITY_CONFIG, type ExecutionContext, FINISH_REASON_MAPPING, type FlowEndContext, type FlowErrorContext, type FlowStartContext, type FlowStats, type HookError, type LogContext, type LogLevel, Logger, type LoggerOptions, OBSERVABILITY_VERSION, type ObservabilityConfig, type ProviderRequestContext, type ProviderResponseContext, type ProviderRetryContext, type StepEndContext, type StepErrorContext, type StepStartContext, TRACE_FLAGS_NOT_SAMPLED, TRACE_FLAGS_SAMPLED, type TraceContext, type TraceContextInput, TraceContextManager, addStandardSpanAttributes, buildFullOtelContext, buildOtelAttributes, buildProviderRequestAttributes, buildProviderResponseAttributes, buildStepAttributes, createChildSpanContext, createLogger, createMinimalConfig, createTraceContext, executeHook, executeHooksSerial, formatTraceparent, formatTracestate, generateExecutionId, generateSpanId, generateTraceId, getObservabilityVersion, hasAnyHooks, isObservabilityDisabled, isObservabilityEnabled, isTraceSampled, isValidSpanId, isValidTraceId, mergeConfig, normalizeFinishReason, parseTraceparent, shouldSample, validateConfig };