@tangle-network/sdk-telemetry 0.60.78-develop.20261025204905.3c2273e → 0.60.78-develop.20261026082550.33d103d

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/dist/index.d.mts CHANGED
@@ -487,31 +487,6 @@ declare class HttpTelemetrySink implements TelemetrySink {
487
487
  flush(): Promise<void>;
488
488
  close(): Promise<void>;
489
489
  }
490
- declare class ConsoleTelemetrySink implements TelemetrySink {
491
- readonly name = "console";
492
- private readonly prefix;
493
- private readonly logLevel;
494
- private readonly formatJson;
495
- constructor(config?: {
496
- prefix?: string;
497
- logLevel?: "log" | "debug" | "info";
498
- formatJson?: boolean;
499
- });
500
- send(events: TelemetryEvent[]): Promise<void>;
501
- flush(): Promise<void>;
502
- close(): Promise<void>;
503
- }
504
- declare class TestTelemetrySink implements TelemetrySink {
505
- readonly name = "test";
506
- readonly events: TelemetryEvent[];
507
- send(events: TelemetryEvent[]): Promise<void>;
508
- flush(): Promise<void>;
509
- close(): Promise<void>;
510
- clear(): void;
511
- getEvents(): TelemetryEvent[];
512
- getEventsByType(type: string): TelemetryEvent[];
513
- getEventsByName(name: string): TelemetryEvent[];
514
- }
515
490
  declare class MultiTelemetrySink implements TelemetrySink {
516
491
  readonly name = "multi";
517
492
  private readonly sinks;
@@ -526,11 +501,6 @@ declare function createHttpSink(config: {
526
501
  fetch?: typeof fetch;
527
502
  timeout?: number;
528
503
  }): HttpTelemetrySink;
529
- declare function createConsoleSink(config?: {
530
- prefix?: string;
531
- logLevel?: "log" | "debug" | "info";
532
- }): ConsoleTelemetrySink;
533
- declare function createTestSink(): TestTelemetrySink;
534
504
  //#endregion
535
505
  //#region src/sse-parser.d.ts
536
506
  declare const parseSSEData: typeof parseSSEData$1;
@@ -618,5 +588,5 @@ declare class TraceCollector {
618
588
  }
619
589
  declare function createTraceCollector(config: TraceCollectorConfig): TraceCollector;
620
590
  //#endregion
621
- export { type AgentErrorEvent, type AgentEvent, type BuildResultEvent, ConsoleTelemetrySink, type CustomEvent, type Diagnostic, type DiagnosticEvent, type DiagnosticSeverity, type DiagnosticSummary, type EnrichmentContext, type EnvironmentEvent, type EnvironmentType, type ErrorEvent, type ExecutionTrace, type FileChangeEvent, type FilePart, GEN_AI_CONVERSATION_ID, GEN_AI_INPUT_TOKEN_KEYS, GEN_AI_MODEL_KEYS, GEN_AI_OPERATION_NAME, GEN_AI_OUTPUT_TOKEN_KEYS, GEN_AI_REQUEST_MODEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, type GenAiUsage, HttpTelemetrySink, type InitOtelProviderResult, LangfuseSink, type LangfuseSinkConfig, type LifecycleOp, type MessagePartUpdatedEvent, type MessagePartUpdatedEventWithTimestamp, type MessageUpdatedEvent, type MetadataBlob, type MetadataBlobFormat, MultiTelemetrySink, ORCHESTRATOR_HOP_ID_HEADER, type OtelSinkConfig, OtelTelemetrySink, type Outcome, PROVISION_TRACE_ID_HEADER, PTID_PREFIX, type ParsedSSEEvent, type Part, type ProductType, type ReasoningPart, type RecordOptions, type ResultEvent, SSEChunkParser, type SSEEventData, type SSEParserOptions, type ServerTimingEntry, type Signal, type SignalEvent, type SpanComponent, SpanRecorder, type SpanStatus, type StageSpan, type StageSpanInput, type StatusEvent, type StreamTokenUsage, type StreamUsageAccumulator, StreamUsageExtractor, type SubscriptionTier, TOKEN_USAGE_COST_KEYS, TOKEN_USAGE_INPUT_KEYS, TOKEN_USAGE_OUTPUT_KEYS, type TelemetryEvent, type TelemetryEventType, type TelemetrySink, type TestResultEvent, TestTelemetrySink, type TextPart, type TokenUsageCounts, type ToolPart, type ToolState, TraceCollector, type TraceCollectorConfig, type TraceContext, type TraceEvent, type TraceEventType, type TraceScope, addTokenUsage, consumeSSEStream, createConsoleSink, createEmptyContext, createHttpSink, createLangfuseSinkFromEnv, createOtelSink, createOtelSinkFromEnv, createStreamUsageExtractor, createTestSink, createTraceCollector, createUsageCallback, firstTokenCount, firstUsageCostUsd, genAiUsageAttributes, initOtelProvider, isAdoptablePtid, isBuildResultEvent, isCompletionEvent, isCustomEvent, isDiagnosticEvent, isEnvironmentEvent, isErrorEvent, isFileChangeEvent, isFilePart, isMessagePartUpdatedEvent, isMessageUpdatedEvent, isReasoningPart, isTestResultEvent, isTextPart, isToolPart, mintPtid, monotonicNs, parseMetadataBlob, parseSSEData, parseSSEStream, parseServerTiming, readOrMintPtid, readTokenCostUsd, readTokenUsage, shutdownOtelProvider, spanDurationMs, sseToSignal, sseToTraceEvent, tokenCount, tokenUsageSource };
591
+ export { type AgentErrorEvent, type AgentEvent, type BuildResultEvent, type CustomEvent, type Diagnostic, type DiagnosticEvent, type DiagnosticSeverity, type DiagnosticSummary, type EnrichmentContext, type EnvironmentEvent, type EnvironmentType, type ErrorEvent, type ExecutionTrace, type FileChangeEvent, type FilePart, GEN_AI_CONVERSATION_ID, GEN_AI_INPUT_TOKEN_KEYS, GEN_AI_MODEL_KEYS, GEN_AI_OPERATION_NAME, GEN_AI_OUTPUT_TOKEN_KEYS, GEN_AI_REQUEST_MODEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, type GenAiUsage, HttpTelemetrySink, type InitOtelProviderResult, LangfuseSink, type LangfuseSinkConfig, type LifecycleOp, type MessagePartUpdatedEvent, type MessagePartUpdatedEventWithTimestamp, type MessageUpdatedEvent, type MetadataBlob, type MetadataBlobFormat, MultiTelemetrySink, ORCHESTRATOR_HOP_ID_HEADER, type OtelSinkConfig, OtelTelemetrySink, type Outcome, PROVISION_TRACE_ID_HEADER, PTID_PREFIX, type ParsedSSEEvent, type Part, type ProductType, type ReasoningPart, type RecordOptions, type ResultEvent, SSEChunkParser, type SSEEventData, type SSEParserOptions, type ServerTimingEntry, type Signal, type SignalEvent, type SpanComponent, SpanRecorder, type SpanStatus, type StageSpan, type StageSpanInput, type StatusEvent, type StreamTokenUsage, type StreamUsageAccumulator, StreamUsageExtractor, type SubscriptionTier, TOKEN_USAGE_COST_KEYS, TOKEN_USAGE_INPUT_KEYS, TOKEN_USAGE_OUTPUT_KEYS, type TelemetryEvent, type TelemetryEventType, type TelemetrySink, type TestResultEvent, type TextPart, type TokenUsageCounts, type ToolPart, type ToolState, TraceCollector, type TraceCollectorConfig, type TraceContext, type TraceEvent, type TraceEventType, type TraceScope, addTokenUsage, consumeSSEStream, createEmptyContext, createHttpSink, createLangfuseSinkFromEnv, createOtelSink, createOtelSinkFromEnv, createStreamUsageExtractor, createTraceCollector, createUsageCallback, firstTokenCount, firstUsageCostUsd, genAiUsageAttributes, initOtelProvider, isAdoptablePtid, isBuildResultEvent, isCompletionEvent, isCustomEvent, isDiagnosticEvent, isEnvironmentEvent, isErrorEvent, isFileChangeEvent, isFilePart, isMessagePartUpdatedEvent, isMessageUpdatedEvent, isReasoningPart, isTestResultEvent, isTextPart, isToolPart, mintPtid, monotonicNs, parseMetadataBlob, parseSSEData, parseSSEStream, parseServerTiming, readOrMintPtid, readTokenCostUsd, readTokenUsage, shutdownOtelProvider, spanDurationMs, sseToSignal, sseToTraceEvent, tokenCount, tokenUsageSource };
622
592
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/enrichment/types.ts","../src/enrichment/parse.ts","../src/trace-types.ts","../src/langfuse-sink.ts","../src/otel-provider.ts","../src/types.ts","../src/otel-sink.ts","../src/sinks.ts","../src/sse-parser.ts","../src/trace-collector.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/enrichment/types.ts","../src/enrichment/parse.ts","../src/trace-types.ts","../src/langfuse-sink.ts","../src/otel-provider.ts","../src/types.ts","../src/otel-sink.ts","../src/sinks.ts","../src/sse-parser.ts","../src/trace-collector.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -877,46 +877,6 @@ var HttpTelemetrySink = class {
877
877
  await this.flush();
878
878
  }
879
879
  };
880
- var ConsoleTelemetrySink = class {
881
- name = "console";
882
- prefix;
883
- logLevel;
884
- formatJson;
885
- constructor(config) {
886
- this.prefix = config?.prefix ?? "[telemetry]";
887
- this.logLevel = config?.logLevel ?? "debug";
888
- this.formatJson = config?.formatJson ?? true;
889
- }
890
- async send(events) {
891
- for (const event of events) {
892
- const message = this.formatJson ? JSON.stringify(event, null, 2) : `${event.type}:${event.name} ${JSON.stringify(event.data)}`;
893
- console[this.logLevel](`${this.prefix} ${message}`);
894
- }
895
- }
896
- async flush() {}
897
- async close() {}
898
- };
899
- var TestTelemetrySink = class {
900
- name = "test";
901
- events = [];
902
- async send(events) {
903
- this.events.push(...events);
904
- }
905
- async flush() {}
906
- async close() {}
907
- clear() {
908
- this.events.length = 0;
909
- }
910
- getEvents() {
911
- return [...this.events];
912
- }
913
- getEventsByType(type) {
914
- return this.events.filter((e) => e.type === type);
915
- }
916
- getEventsByName(name) {
917
- return this.events.filter((e) => e.name === name);
918
- }
919
- };
920
880
  var MultiTelemetrySink = class {
921
881
  name = "multi";
922
882
  sinks;
@@ -936,12 +896,6 @@ var MultiTelemetrySink = class {
936
896
  function createHttpSink(config) {
937
897
  return new HttpTelemetrySink(config);
938
898
  }
939
- function createConsoleSink(config) {
940
- return new ConsoleTelemetrySink(config);
941
- }
942
- function createTestSink() {
943
- return new TestTelemetrySink();
944
- }
945
899
  //#endregion
946
900
  //#region src/sse-parser.ts
947
901
  /**
@@ -1395,6 +1349,6 @@ function createTraceCollector(config) {
1395
1349
  return new TraceCollector(config);
1396
1350
  }
1397
1351
  //#endregion
1398
- export { ConsoleTelemetrySink, GEN_AI_CONVERSATION_ID, GEN_AI_INPUT_TOKEN_KEYS, GEN_AI_MODEL_KEYS, GEN_AI_OPERATION_NAME, GEN_AI_OUTPUT_TOKEN_KEYS, GEN_AI_REQUEST_MODEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, HttpTelemetrySink, LangfuseSink, MultiTelemetrySink, ORCHESTRATOR_HOP_ID_HEADER, OtelTelemetrySink, PROVISION_TRACE_ID_HEADER, PTID_PREFIX, SSEChunkParser, SpanRecorder, StreamUsageExtractor, TOKEN_USAGE_COST_KEYS, TOKEN_USAGE_INPUT_KEYS, TOKEN_USAGE_OUTPUT_KEYS, TestTelemetrySink, TraceCollector, addTokenUsage, consumeSSEStream, createConsoleSink, createEmptyContext, createHttpSink, createLangfuseSinkFromEnv, createOtelSink, createOtelSinkFromEnv, createStreamUsageExtractor, createTestSink, createTraceCollector, createUsageCallback, firstTokenCount, firstUsageCostUsd, genAiUsageAttributes, initOtelProvider, isAdoptablePtid, isBuildResultEvent, isCompletionEvent, isCustomEvent, isDiagnosticEvent, isEnvironmentEvent, isErrorEvent, isFileChangeEvent, isFilePart, isMessagePartUpdatedEvent, isMessageUpdatedEvent, isReasoningPart, isTestResultEvent, isTextPart, isToolPart, mintPtid, monotonicNs, parseMetadataBlob, parseSSEData, parseSSEStream, parseServerTiming, readOrMintPtid, readTokenCostUsd, readTokenUsage, shutdownOtelProvider, spanDurationMs, sseToSignal, sseToTraceEvent, tokenCount, tokenUsageSource };
1352
+ export { GEN_AI_CONVERSATION_ID, GEN_AI_INPUT_TOKEN_KEYS, GEN_AI_MODEL_KEYS, GEN_AI_OPERATION_NAME, GEN_AI_OUTPUT_TOKEN_KEYS, GEN_AI_REQUEST_MODEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, HttpTelemetrySink, LangfuseSink, MultiTelemetrySink, ORCHESTRATOR_HOP_ID_HEADER, OtelTelemetrySink, PROVISION_TRACE_ID_HEADER, PTID_PREFIX, SSEChunkParser, SpanRecorder, StreamUsageExtractor, TOKEN_USAGE_COST_KEYS, TOKEN_USAGE_INPUT_KEYS, TOKEN_USAGE_OUTPUT_KEYS, TraceCollector, addTokenUsage, consumeSSEStream, createEmptyContext, createHttpSink, createLangfuseSinkFromEnv, createOtelSink, createOtelSinkFromEnv, createStreamUsageExtractor, createTraceCollector, createUsageCallback, firstTokenCount, firstUsageCostUsd, genAiUsageAttributes, initOtelProvider, isAdoptablePtid, isBuildResultEvent, isCompletionEvent, isCustomEvent, isDiagnosticEvent, isEnvironmentEvent, isErrorEvent, isFileChangeEvent, isFilePart, isMessagePartUpdatedEvent, isMessageUpdatedEvent, isReasoningPart, isTestResultEvent, isTextPart, isToolPart, mintPtid, monotonicNs, parseMetadataBlob, parseSSEData, parseSSEStream, parseServerTiming, readOrMintPtid, readTokenCostUsd, readTokenUsage, shutdownOtelProvider, spanDurationMs, sseToSignal, sseToTraceEvent, tokenCount, tokenUsageSource };
1399
1353
 
1400
1354
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["GEN_AI_REQUEST_MODEL","GEN_AI_RESPONSE_MODEL","GEN_AI_USAGE_INPUT_TOKENS","GEN_AI_USAGE_OUTPUT_TOKENS","GEN_AI_OPERATION_NAME","GEN_AI_CONVERSATION_ID","coreParseSSEData"],"sources":["../src/enrichment/parse.ts","../src/enrichment/types.ts","../src/trace-types.ts","../src/langfuse-sink.ts","../src/otel-provider.ts","../src/otel-sink.ts","../src/sinks.ts","../src/sse-parser.ts","../src/trace-collector.ts"],"sourcesContent":["/**\n * Metadata blob parsing: JSON blobs map partner fields onto an enrichment\n * context; any other format, or JSON that fails to parse, yields only the raw blob.\n */\n\nimport type {\n EnrichmentContext,\n EnvironmentType,\n MetadataBlob,\n ProductType,\n SubscriptionTier,\n} from \"./types.js\";\n\n/** Expected JSON structure for partner metadata */\ninterface JsonMetadataPayload {\n partner_id?: string;\n partnerId?: string;\n subscription_tier?: string;\n subscriptionTier?: string;\n user_id?: string;\n userId?: string;\n end_user_id?: string;\n endUserId?: string;\n product?: string;\n environment?: string;\n env?: string;\n custom?: Record<string, string>;\n labels?: Record<string, string>;\n [key: string]: unknown;\n}\n\nconst VALID_PRODUCTS: ProductType[] = [\n \"vibe_coding\",\n \"simulation\",\n \"background_agent\",\n];\nconst VALID_ENVIRONMENTS: EnvironmentType[] = [\n \"development\",\n \"staging\",\n \"production\",\n];\nconst VALID_TIERS: SubscriptionTier[] = [\"free\", \"pro\", \"enterprise\"];\n\nfunction normalizeProduct(value: unknown): ProductType | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.toLowerCase().replace(/-/g, \"_\");\n return VALID_PRODUCTS.includes(normalized as ProductType)\n ? (normalized as ProductType)\n : undefined;\n}\n\nfunction normalizeEnvironment(value: unknown): EnvironmentType | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.toLowerCase();\n // Map common aliases\n if (normalized === \"dev\") return \"development\";\n if (normalized === \"prod\") return \"production\";\n return VALID_ENVIRONMENTS.includes(normalized as EnvironmentType)\n ? (normalized as EnvironmentType)\n : undefined;\n}\n\nfunction normalizeTier(value: unknown): SubscriptionTier | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.toLowerCase();\n return VALID_TIERS.includes(normalized as SubscriptionTier)\n ? (normalized as SubscriptionTier)\n : undefined;\n}\n\n/** Parse a metadata blob into an enrichment context that keeps the raw blob. */\nexport function parseMetadataBlob(blob: MetadataBlob): EnrichmentContext {\n if (blob.format !== \"json\") return { customLabels: {}, rawBlob: blob };\n try {\n return parseJsonBlob(blob);\n } catch {\n return { customLabels: {}, rawBlob: blob };\n }\n}\n\nfunction parseJsonBlob(blob: MetadataBlob): EnrichmentContext {\n const dataStr =\n typeof blob.data === \"string\" ? blob.data : blob.data.toString(\"utf-8\");\n\n const payload = JSON.parse(dataStr) as JsonMetadataPayload;\n const context: EnrichmentContext = { customLabels: {}, rawBlob: blob };\n\n // Partner ID (snake_case or camelCase)\n const partnerId = payload.partner_id || payload.partnerId;\n if (typeof partnerId === \"string\" && partnerId.length > 0) {\n context.partnerId = partnerId;\n }\n\n // Subscription tier\n const tier = payload.subscription_tier || payload.subscriptionTier;\n context.subscriptionTier = normalizeTier(tier);\n\n // End user ID (multiple possible field names)\n const userId =\n payload.end_user_id ||\n payload.endUserId ||\n payload.user_id ||\n payload.userId;\n if (typeof userId === \"string\" && userId.length > 0) {\n context.endUserId = userId;\n }\n\n // Product type\n context.product = normalizeProduct(payload.product);\n\n // Environment\n context.environment = normalizeEnvironment(\n payload.environment || payload.env,\n );\n\n // Custom labels (merge custom and labels fields)\n const customLabels: Record<string, string> = {};\n const addLabels = (obj: unknown) => {\n if (obj && typeof obj === \"object\" && !Array.isArray(obj)) {\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === \"string\") {\n customLabels[key] = value;\n } else if (typeof value === \"number\" || typeof value === \"boolean\") {\n customLabels[key] = String(value);\n }\n }\n }\n };\n addLabels(payload.custom);\n addLabels(payload.labels);\n\n if (Object.keys(customLabels).length > 0) {\n context.customLabels = customLabels;\n }\n\n return context;\n}\n","/**\n * Enrichment Types\n *\n * Types for client-forwarded metadata blobs and parsed enrichment context.\n * Partners send metadata that parseMetadataBlob turns into an enrichment\n * context attached to traces for analytics and tenant isolation.\n */\n\n/** Supported blob formats for metadata transmission */\nexport type MetadataBlobFormat = \"json\" | \"msgpack\" | \"protobuf\";\n\n/** Client-forwarded metadata blob */\nexport interface MetadataBlob {\n /** Serialization format of the data */\n format: MetadataBlobFormat;\n /** Serialized data (base64 for binary formats) */\n data: string | Buffer;\n /** Optional schema identifier for validation */\n schema?: string;\n}\n\n/** Product context for trace classification */\nexport type ProductType = \"vibe_coding\" | \"simulation\" | \"background_agent\";\n\n/** Environment context */\nexport type EnvironmentType = \"development\" | \"staging\" | \"production\";\n\n/** Subscription tier for rate limiting and feature gating */\nexport type SubscriptionTier = \"free\" | \"pro\" | \"enterprise\";\n\n/**\n * Parsed enrichment context attached to traces.\n * Built from partner metadata blobs by parseMetadataBlob.\n */\nexport interface EnrichmentContext {\n /** Partner identifier for tenant isolation */\n partnerId?: string;\n /** Subscription tier for rate limiting */\n subscriptionTier?: SubscriptionTier;\n /** End user identifier within partner's system */\n endUserId?: string;\n /** Product context */\n product?: ProductType;\n /** Deployment environment */\n environment?: EnvironmentType;\n /** Custom key-value labels for filtering */\n customLabels: Record<string, string>;\n /** Original blob for audit/replay */\n rawBlob?: MetadataBlob;\n}\n\n/** Create an empty enrichment context with defaults */\nexport function createEmptyContext(): EnrichmentContext {\n return {\n customLabels: {},\n };\n}\n","/**\n * Trace Event Types\n *\n * Strongly typed discriminated union for execution trace events.\n * Used to capture detailed agent execution data for analysis and training.\n *\n * SSE events from OpenCode (MessagePartUpdatedEvent, StatusEvent, etc.) are\n * imported from sdk-core and passed through without transformation.\n * Trace-specific events (DiagnosticEvent, BuildResultEvent, etc.) are\n * collected by other means and defined here.\n */\n\n// Re-export canonical SSE event types from sdk-core (which re-exports from agent-interface)\nexport type {\n AgentEvent,\n ErrorEvent as AgentErrorEvent,\n FilePart,\n MessagePartUpdatedEvent,\n Part,\n PartBase,\n ReasoningPart,\n ResultEvent,\n StatusEvent,\n TextPart,\n ToolPart,\n ToolState,\n ToolStateCompleted,\n} from \"@tangle-network/agent-core\";\n\nexport {\n isFilePart,\n isReasoningPart,\n isTextPart,\n isToolPart,\n} from \"@tangle-network/agent-core\";\n\nimport type { MessagePartUpdatedEvent } from \"@tangle-network/agent-core\";\n\n/**\n * MessagePartUpdatedEvent with timestamp for trace collection.\n * This is the canonical event type from OpenCode - pass through without transformation.\n */\nexport interface MessagePartUpdatedEventWithTimestamp\n extends MessagePartUpdatedEvent {\n /** Timestamp when event was recorded */\n timestamp: Date;\n}\n\n/** Type guard for MessagePartUpdatedEvent */\nexport function isMessagePartUpdatedEvent(\n event: TraceEvent,\n): event is MessagePartUpdatedEventWithTimestamp {\n return event.type === \"message.part.updated\";\n}\n\n/** Execution scope for trace association */\nexport interface TraceScope {\n projectRef?: string;\n sessionId?: string;\n /** Links sub-agent sessions to their parent session */\n parentSessionId?: string;\n userId?: string;\n /**\n * Tangle Intelligence resource attributes for this scope — the `tangle.*`\n * dimensions a partner filters on (partner / project / domain / pseudonymous\n * end-user). Built host-side and threaded per session; stamped onto every\n * exported span by the OTEL sink. Kept as an open bag so new dimensions flow\n * through without a schema change.\n */\n resourceAttributes?: Record<string, string>;\n}\n\n/** Success/failure signals captured during execution */\nexport type Signal =\n | \"build_passed\"\n | \"build_failed\"\n | \"tests_passed\"\n | \"tests_failed\"\n | \"lint_passed\"\n | \"lint_failed\"\n | \"user_approved\"\n | \"user_rejected\"\n | \"task_completed\"\n | \"task_abandoned\"\n | \"runtime_error\"\n | \"timeout\";\n\nexport interface SignalEvent {\n signal: Signal;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Trace Events - Strongly Typed Discriminated Union\n// =============================================================================\n\n/** Base fields shared by all trace events */\ninterface TraceEventBase {\n timestamp: Date;\n}\n\n/** Message updated event (final model text and result metadata) */\nexport interface MessageUpdatedEvent extends TraceEventBase {\n type: \"message.updated\";\n /** Final text content */\n text?: string;\n /** Legacy alias for text */\n finalText?: string;\n /** Token usage details */\n tokenUsage?: Record<string, unknown>;\n /** Timing details */\n timing?: Record<string, unknown>;\n /** Tool invocations captured during execution */\n toolInvocations?: unknown[];\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/** Error event */\nexport interface ErrorEvent extends TraceEventBase {\n type: \"error\";\n /** Error category */\n category: \"runtime\" | \"syntax\" | \"type\" | \"network\" | \"timeout\" | \"unknown\";\n /** Error message */\n message: string;\n /** Stack trace if available */\n stack?: string;\n /** Error code if available */\n code?: string;\n /** Source of error (tool name, file, etc.) */\n source?: string;\n}\n\n/** Diagnostic severity levels */\nexport type DiagnosticSeverity = \"error\" | \"warning\" | \"info\" | \"hint\";\n\n/** Individual diagnostic message */\nexport interface Diagnostic {\n /** Severity level */\n severity: DiagnosticSeverity;\n /** Diagnostic message */\n message: string;\n /** Diagnostic code (e.g., \"TS2304\", \"E0001\") */\n code?: string | number;\n /** Source (e.g., \"typescript\", \"eslint\") */\n source?: string;\n /** Start line (0-indexed) */\n startLine: number;\n /** Start column (0-indexed) */\n startColumn: number;\n /** End line (0-indexed) */\n endLine: number;\n /** End column (0-indexed) */\n endColumn: number;\n}\n\n/** Summary of diagnostics for a file */\nexport interface DiagnosticSummary {\n errors: number;\n warnings: number;\n infos: number;\n hints: number;\n}\n\n/** Diagnostic change event - captured after file edits */\nexport interface DiagnosticEvent extends TraceEventBase {\n type: \"diagnostic\";\n /** File path */\n file: string;\n /** Language server ID */\n serverId?: string;\n /** Language (e.g., \"typescript\", \"python\") */\n language?: string;\n /** Diagnostics before the change */\n before?: Diagnostic[];\n /** Diagnostics after the change */\n after: Diagnostic[];\n /** Summary counts before */\n beforeSummary?: DiagnosticSummary;\n /** Summary counts after */\n afterSummary: DiagnosticSummary;\n /** Net change in error count (negative = improvement) */\n errorDelta: number;\n /** Diagnostics that were resolved */\n resolved?: Diagnostic[];\n /** Diagnostics that were introduced */\n introduced?: Diagnostic[];\n}\n\n/** File change event */\nexport interface FileChangeEvent extends TraceEventBase {\n type: \"file_change\";\n /** File path */\n file: string;\n /** Change type */\n changeType: \"created\" | \"modified\" | \"deleted\";\n /** Lines added */\n linesAdded?: number;\n /** Lines removed */\n linesRemoved?: number;\n}\n\n/** Build result event */\nexport interface BuildResultEvent extends TraceEventBase {\n type: \"build_result\";\n /** Build command */\n command?: string;\n /** Whether build succeeded */\n success: boolean;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error count */\n errorCount?: number;\n /** Warning count */\n warningCount?: number;\n}\n\n/** Test result event */\nexport interface TestResultEvent extends TraceEventBase {\n type: \"test_result\";\n /** Test command */\n command?: string;\n /** Whether all tests passed */\n success: boolean;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Number of tests passed */\n passed?: number;\n /** Number of tests failed */\n failed?: number;\n /** Number of tests skipped */\n skipped?: number;\n}\n\n/** Environment snapshot at trace start */\nexport interface EnvironmentEvent extends TraceEventBase {\n type: \"environment\";\n /** Runtime versions */\n versions?: Record<string, string>;\n /** Working directory */\n workingDir?: string;\n /** Platform info */\n platform?: string;\n}\n\n/** Generic event for extensibility (use sparingly) */\nexport interface CustomEvent extends TraceEventBase {\n type: \"custom\";\n /** Custom event name */\n name: string;\n /** Custom event data */\n data: Record<string, unknown>;\n}\n\n// =============================================================================\n// Batch Execution Events\n// =============================================================================\n\n/** Batch execution started event */\nexport interface BatchStartedEvent extends TraceEventBase {\n type: \"batch_started\";\n /** Unique batch execution ID */\n batchId: string;\n /** Number of tasks in the batch */\n taskCount: number;\n /** Number of backends being tested */\n backendCount: number;\n /** Total executions (tasks × backends) */\n totalExecutions: number;\n /** Scaling mode used */\n scalingMode?: \"fastest\" | \"balanced\" | \"cheapest\";\n}\n\n/** Batch execution completed event */\nexport interface BatchCompletedEvent extends TraceEventBase {\n type: \"batch_completed\";\n /** Unique batch execution ID */\n batchId: string;\n /** Number of successful task executions */\n successCount: number;\n /** Number of failed task executions */\n failureCount: number;\n /** Success rate as percentage (0-100) */\n successRate: number;\n /** Total duration in milliseconds */\n durationMs: number;\n /** Total tokens used across all executions */\n totalTokensUsed?: number;\n}\n\n/** Individual task within a batch completed */\nexport interface BatchTaskCompletedEvent extends TraceEventBase {\n type: \"batch_task_completed\";\n /** Parent batch ID */\n batchId: string;\n /** Task ID within the batch */\n taskId: string;\n /** Backend used for this execution */\n backend: string;\n /** Whether the task succeeded */\n success: boolean;\n /** Duration in milliseconds */\n durationMs: number;\n /** Attempt number (1 = first try) */\n attempt: number;\n /** Number of retries before success/failure */\n retries: number;\n /** Tokens used for this task */\n tokensUsed?: number;\n /** Error message if failed */\n error?: string;\n}\n\n/** Union of all trace event types */\nexport type TraceEvent =\n // Canonical SSE event from OpenCode (preferred)\n | MessagePartUpdatedEventWithTimestamp\n | MessageUpdatedEvent\n | ErrorEvent\n // Trace-specific events (not from SSE)\n | DiagnosticEvent\n | FileChangeEvent\n | BuildResultEvent\n | TestResultEvent\n | EnvironmentEvent\n | CustomEvent\n | BatchStartedEvent\n | BatchCompletedEvent\n | BatchTaskCompletedEvent;\n\n/** Event type discriminator */\nexport type TraceEventType = TraceEvent[\"type\"];\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isMessageUpdatedEvent(\n event: TraceEvent,\n): event is MessageUpdatedEvent {\n return event.type === \"message.updated\";\n}\n\nexport function isErrorEvent(event: TraceEvent): event is ErrorEvent {\n return event.type === \"error\";\n}\n\nexport function isDiagnosticEvent(event: TraceEvent): event is DiagnosticEvent {\n return event.type === \"diagnostic\";\n}\n\nexport function isFileChangeEvent(event: TraceEvent): event is FileChangeEvent {\n return event.type === \"file_change\";\n}\n\nexport function isBuildResultEvent(\n event: TraceEvent,\n): event is BuildResultEvent {\n return event.type === \"build_result\";\n}\n\nexport function isTestResultEvent(event: TraceEvent): event is TestResultEvent {\n return event.type === \"test_result\";\n}\n\nexport function isEnvironmentEvent(\n event: TraceEvent,\n): event is EnvironmentEvent {\n return event.type === \"environment\";\n}\n\nexport function isCustomEvent(event: TraceEvent): event is CustomEvent {\n return event.type === \"custom\";\n}\n\n// =============================================================================\n// Execution Trace\n// =============================================================================\n\n/** Execution outcome derived from signals */\nexport type Outcome = \"success\" | \"partial\" | \"failure\" | \"unknown\";\n\n/** Execution trace - complete record of an agent task */\nexport interface ExecutionTrace {\n id: string;\n scope: TraceScope;\n task: string;\n events: TraceEvent[];\n signals: SignalEvent[];\n outcome: Outcome;\n startedAt: Date;\n completedAt?: Date;\n metadata?: Record<string, unknown>;\n}\n","/**\n * Langfuse Sink\n *\n * Native Langfuse SDK integration for trace export.\n * Uses the langfuse-node SDK directly instead of going through OTEL,\n * which provides better compatibility and richer trace visualization.\n */\n\nimport type {\n ExecutionTrace,\n MessagePartUpdatedEventWithTimestamp,\n ToolPart,\n TraceEvent,\n} from \"./trace-types.js\";\nimport {\n isFilePart,\n isReasoningPart,\n isTextPart,\n isToolPart,\n} from \"./trace-types.js\";\n\n/** Langfuse sink configuration */\nexport interface LangfuseSinkConfig {\n /** Langfuse public key */\n publicKey: string;\n /** Langfuse secret key */\n secretKey: string;\n /** Langfuse host (default: https://cloud.langfuse.com) */\n baseUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n /**\n * Redaction applied to the whole trace before any of it is turned into\n * Langfuse objects (HIPAA deployments: pass a PHI deep redactor). The\n * hook is injected rather than imported so this package stays free of\n * Node-only redaction dependencies and Worker-safe.\n */\n redactTrace?: (trace: ExecutionTrace) => ExecutionTrace;\n}\n\n// Lazy-loaded Langfuse client\nlet langfuseClient: import(\"langfuse-node\").Langfuse | null = null;\nlet langfuseConfig: LangfuseSinkConfig | null = null;\n\n/**\n * Get or create the Langfuse client\n */\nasync function getLangfuseClient(\n config: LangfuseSinkConfig,\n): Promise<import(\"langfuse-node\").Langfuse | null> {\n if (langfuseClient && langfuseConfig === config) {\n return langfuseClient;\n }\n\n try {\n const { Langfuse } = await import(\"langfuse-node\");\n langfuseClient = new Langfuse({\n publicKey: config.publicKey,\n secretKey: config.secretKey,\n baseUrl: config.baseUrl || \"https://cloud.langfuse.com\",\n });\n langfuseConfig = config;\n return langfuseClient;\n } catch (err) {\n console.warn(\"[langfuse-sink] Failed to initialize Langfuse:\", err);\n return null;\n }\n}\n\ntype LangfuseTrace = ReturnType<import(\"langfuse-node\").Langfuse[\"trace\"]>;\n\nfunction exportBuildResultSpan(\n trace: LangfuseTrace,\n event: Extract<TraceEvent, { type: \"build_result\" }>,\n): void {\n trace.span({\n name: `build.${event.success ? \"success\" : \"failure\"}`,\n startTime: event.timestamp,\n endTime: event.durationMs\n ? new Date(event.timestamp.getTime() + event.durationMs)\n : undefined,\n output: event.success ? \"success\" : \"failed\",\n metadata: {\n command: event.command,\n errorCount: event.errorCount,\n warningCount: event.warningCount,\n },\n level: event.success ? undefined : \"ERROR\",\n });\n}\n\nfunction exportTestResultSpan(\n trace: LangfuseTrace,\n event: Extract<TraceEvent, { type: \"test_result\" }>,\n): void {\n trace.span({\n name: `test.${event.success ? \"success\" : \"failure\"}`,\n startTime: event.timestamp,\n endTime: event.durationMs\n ? new Date(event.timestamp.getTime() + event.durationMs)\n : undefined,\n output: event.success ? \"success\" : \"failed\",\n metadata: {\n command: event.command,\n passed: event.passed,\n failed: event.failed,\n skipped: event.skipped,\n },\n level: event.success ? undefined : \"ERROR\",\n });\n}\n\n/** Measured startup and HTTP phases become timed spans; other custom events stay events. */\nfunction exportCustomEvent(\n trace: LangfuseTrace,\n event: Extract<TraceEvent, { type: \"custom\" }>,\n): void {\n if (event.name === \"startup.phase\" || event.name === \"http.phase\") {\n const durationMs =\n typeof event.data.durationMs === \"number\" ? event.data.durationMs : 0;\n const phase =\n typeof event.data.phase === \"string\" ? event.data.phase : \"unknown\";\n trace.span({\n name: `${event.name === \"http.phase\" ? \"http\" : \"startup\"}.${phase}`,\n startTime: new Date(event.timestamp.getTime() - durationMs),\n endTime: event.timestamp,\n metadata: event.data,\n level: event.data.status === \"error\" ? \"ERROR\" : undefined,\n statusMessage:\n typeof event.data.error === \"string\" ? event.data.error : undefined,\n });\n } else {\n trace.event({\n name: `custom.${event.name}`,\n startTime: event.timestamp,\n metadata: event.data,\n });\n }\n}\n\n/**\n * Langfuse trace exporter using the native SDK.\n *\n * Creates proper Langfuse traces with spans and generations\n * for rich observability in the Langfuse dashboard.\n *\n * Note: This is a trace-level exporter (ExecutionTrace), not a\n * TelemetrySink (TelemetryEvent). Use for exporting complete traces.\n */\nexport class LangfuseSink {\n readonly name = \"langfuse\";\n private readonly config: LangfuseSinkConfig;\n\n constructor(config: LangfuseSinkConfig) {\n this.config = config;\n }\n\n /**\n * Export an execution trace to Langfuse.\n */\n async exportTrace(trace: ExecutionTrace): Promise<void> {\n const client = await getLangfuseClient(this.config);\n if (!client) return;\n\n // Redaction runs on the trace BEFORE any Langfuse object is built, so\n // no code path below can forget a content field.\n const effectiveTrace = this.config.redactTrace\n ? this.config.redactTrace(trace)\n : trace;\n\n try {\n // Create the main trace\n const langfuseTrace = client.trace({\n id: effectiveTrace.id,\n name: effectiveTrace.task,\n sessionId: effectiveTrace.scope.sessionId,\n userId: effectiveTrace.scope.userId,\n metadata: {\n outcome: effectiveTrace.outcome,\n projectRef: effectiveTrace.scope.projectRef,\n ...effectiveTrace.metadata,\n },\n tags: effectiveTrace.outcome === \"failure\" ? [\"failed\"] : undefined,\n });\n\n // Export events as spans/generations\n for (const event of effectiveTrace.events) {\n if (!event) continue;\n this.exportTraceEvent(langfuseTrace, event);\n }\n\n // Add signals as trace events\n for (const signal of effectiveTrace.signals) {\n langfuseTrace.event({\n name: `signal.${signal.signal}`,\n startTime: signal.timestamp,\n metadata: signal.metadata,\n });\n }\n\n // Update trace with completion info\n langfuseTrace.update({\n output: effectiveTrace.outcome,\n });\n\n // Flush to ensure delivery\n await client.flushAsync();\n } catch (err) {\n console.warn(\"[langfuse-sink] Failed to export trace:\", err);\n }\n }\n\n /**\n * Export a trace event as a Langfuse span or generation.\n */ private exportTraceEvent(\n trace: ReturnType<import(\"langfuse-node\").Langfuse[\"trace\"]>,\n event: TraceEvent,\n ): void {\n switch (event.type) {\n // Canonical SSE event from OpenCode - interpret based on part type\n case \"message.part.updated\": {\n const partEvent = event as MessagePartUpdatedEventWithTimestamp;\n const part = partEvent.part;\n\n if (isToolPart(part)) {\n this.exportToolPart(trace, partEvent, part);\n } else if (isTextPart(part) || isReasoningPart(part)) {\n // Text/reasoning parts become generations\n trace.generation({\n name: part.type === \"reasoning\" ? \"reasoning\" : \"text\",\n startTime: partEvent.timestamp,\n output: part.text,\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n delta: partEvent.delta,\n },\n });\n } else if (isFilePart(part)) {\n trace.event({\n name: `file.${part.mediaType || \"unknown\"}`,\n startTime: partEvent.timestamp,\n metadata: {\n partId: part.id,\n filename: part.filename,\n mediaType: part.mediaType,\n url: part.url,\n },\n });\n }\n break;\n }\n\n case \"message.updated\":\n trace.event({\n name: \"message.updated\",\n startTime: event.timestamp,\n metadata: {\n text: event.text ?? event.finalText,\n finalText: event.finalText,\n tokenUsage: event.tokenUsage,\n timing: event.timing,\n toolInvocations: event.toolInvocations,\n metadata: event.metadata,\n },\n });\n break;\n\n case \"error\":\n trace.event({\n name: `error.${event.category}`,\n startTime: event.timestamp,\n level: \"ERROR\",\n metadata: {\n message: event.message,\n code: event.code,\n source: event.source,\n },\n });\n break;\n\n case \"file_change\":\n trace.event({\n name: `file.${event.changeType}`,\n startTime: event.timestamp,\n metadata: {\n file: event.file,\n linesAdded: event.linesAdded,\n linesRemoved: event.linesRemoved,\n },\n });\n break;\n\n case \"build_result\":\n exportBuildResultSpan(trace, event);\n break;\n\n case \"test_result\":\n exportTestResultSpan(trace, event);\n break;\n\n case \"diagnostic\":\n trace.event({\n name: `diagnostic.${event.language || \"unknown\"}`,\n startTime: event.timestamp,\n metadata: {\n file: event.file,\n errorDelta: event.errorDelta,\n errorsAfter: event.afterSummary.errors,\n warningsAfter: event.afterSummary.warnings,\n },\n });\n break;\n\n case \"environment\":\n trace.event({\n name: \"environment.snapshot\",\n startTime: event.timestamp,\n metadata: {\n workingDir: event.workingDir,\n platform: event.platform,\n },\n });\n break;\n\n case \"custom\":\n exportCustomEvent(trace, event);\n break;\n }\n }\n\n /**\n * Export a tool part from message.part.updated event.\n * Tool parts have state progression: pending → running → completed/error\n */\n private exportToolPart(\n trace: ReturnType<import(\"langfuse-node\").Langfuse[\"trace\"]>,\n event: MessagePartUpdatedEventWithTimestamp,\n part: ToolPart,\n ): void {\n const status = part.state.status;\n const toolName = part.tool;\n\n if (status === \"running\") {\n // Tool started - create span with input\n trace.span({\n name: `tool.${toolName}`,\n startTime: event.timestamp,\n input: part.state.input ?? { callID: part.callID },\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n status,\n },\n });\n } else if (status === \"completed\") {\n // Tool finished - create span with output\n const endTime = part.state.time?.end\n ? new Date(part.state.time.end)\n : event.timestamp;\n const startTime = part.state.time?.start\n ? new Date(part.state.time.start)\n : event.timestamp;\n\n trace.span({\n name: `tool.${toolName}.result`,\n startTime,\n endTime,\n input: part.state.input,\n output: part.state.output ?? \"success\",\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n callID: part.callID,\n success: true,\n },\n });\n } else if (status === \"failed\" || status === \"error\") {\n const endTime = part.state.time?.end\n ? new Date(part.state.time.end)\n : event.timestamp;\n const startTime = part.state.time?.start\n ? new Date(part.state.time.start)\n : event.timestamp;\n\n trace.span({\n name: `tool.${toolName}.result`,\n startTime,\n endTime,\n input: part.state.input,\n output: part.state.output ?? part.state.error,\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n callID: part.callID,\n success: false,\n },\n level: \"ERROR\",\n statusMessage: part.state.error,\n });\n }\n }\n\n async flush(): Promise<void> {\n const client = await getLangfuseClient(this.config);\n if (client) {\n await client.flushAsync();\n }\n }\n\n async close(): Promise<void> {\n const client = await getLangfuseClient(this.config);\n if (client) {\n await client.shutdownAsync();\n langfuseClient = null;\n }\n }\n}\n\n/**\n * Create a Langfuse sink from environment variables.\n */\nexport function createLangfuseSinkFromEnv(\n options?: Pick<LangfuseSinkConfig, \"redactTrace\">,\n): LangfuseSink | null {\n const publicKey = process.env.LANGFUSE_PUBLIC_KEY;\n const secretKey = process.env.LANGFUSE_SECRET_KEY;\n\n if (!publicKey || !secretKey) {\n return null;\n }\n\n return new LangfuseSink({\n publicKey,\n secretKey,\n baseUrl: process.env.LANGFUSE_HOST || \"https://cloud.langfuse.com\",\n debug: process.env.LANGFUSE_DEBUG === \"true\",\n ...(options?.redactTrace ? { redactTrace: options.redactTrace } : {}),\n });\n}\n","/**\n * Global OpenTelemetry tracer provider for the in-container agent loop.\n *\n * Registers a Node TracerProvider + batching OTLP/HTTP exporter so the GLOBAL\n * tracer (`@opentelemetry/api` `trace.getTracer`, used by the OTel sink) ships\n * spans to the configured collector (Tangle Intelligence) instead of being a\n * no-op. Endpoint + headers come from the standard OTEL env the host threads in\n * (`OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS`); per-session\n * partner/project/user resource attributes are stamped on spans by the sink,\n * not here.\n *\n * Opt-in + best-effort:\n * - a no-op unless `TELEMETRY_ENABLED=true` AND an endpoint is set;\n * - any SDK import / construction failure degrades to disabled, never crashes\n * the sidecar (telemetry must never take down the agent);\n * - idempotent — a second `initOtelProvider` returns the already-active result.\n */\n\nexport interface InitOtelProviderResult {\n active: boolean;\n reason?: string;\n}\n\ninterface Shutdownable {\n forceFlush(): Promise<void>;\n shutdown(): Promise<void>;\n}\n\nlet provider: Shutdownable | null = null;\n\n/** Parse `OTEL_EXPORTER_OTLP_HEADERS` (\"k=v,k2=v2\") into a header map. */\nfunction parseHeaders(raw: string | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!raw) return out;\n for (const pair of raw.split(\",\")) {\n const eq = pair.indexOf(\"=\");\n if (eq <= 0) continue;\n const key = pair.slice(0, eq).trim();\n const value = pair.slice(eq + 1).trim();\n if (key) out[key] = value;\n }\n return out;\n}\n\nexport async function initOtelProvider(\n serviceName: string,\n): Promise<InitOtelProviderResult> {\n if (provider) return { active: true };\n\n if (process.env.TELEMETRY_ENABLED !== \"true\") {\n return { active: false, reason: \"TELEMETRY_ENABLED!=true\" };\n }\n const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n if (!endpoint) {\n return { active: false, reason: \"OTEL_EXPORTER_OTLP_ENDPOINT unset\" };\n }\n\n try {\n const [\n { NodeTracerProvider, BatchSpanProcessor },\n { OTLPTraceExporter },\n { resourceFromAttributes },\n { ATTR_SERVICE_NAME },\n ] = await Promise.all([\n import(\"@opentelemetry/sdk-trace-node\"),\n import(\"@opentelemetry/exporter-trace-otlp-http\"),\n import(\"@opentelemetry/resources\"),\n import(\"@opentelemetry/semantic-conventions\"),\n ]);\n\n const exporter = new OTLPTraceExporter({\n url: endpoint,\n headers: parseHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS),\n });\n\n const tracerProvider = new NodeTracerProvider({\n resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: serviceName }),\n spanProcessors: [new BatchSpanProcessor(exporter)],\n });\n // Registers as the global provider so `api.trace.getTracer(...)` (the sink)\n // returns real tracers instead of the default no-op.\n tracerProvider.register();\n provider = tracerProvider;\n\n return { active: true };\n } catch (error) {\n return {\n active: false,\n reason: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport async function shutdownOtelProvider(): Promise<void> {\n if (!provider) return;\n const current = provider;\n provider = null;\n try {\n await current.forceFlush();\n } catch {\n // best-effort flush\n }\n await current.shutdown();\n}\n","/**\n * OpenTelemetry Sink\n *\n * Exports telemetry data to OpenTelemetry-compatible backends including\n * Langfuse, Jaeger, Honeycomb, and other OTLP collectors.\n *\n * IMPORTANT: This sink uses the GLOBAL tracer from @opentelemetry/api.\n * The OTEL SDK must be initialized separately (e.g., via NodeSDK with\n * LangfuseSpanProcessor or OTLPTraceExporter) before using this sink.\n *\n * This sink converts ExecutionTrace data into OTEL spans using the\n * global tracer, which ensures spans flow through whatever processor\n * was configured at SDK initialization.\n */\n\nimport {\n GEN_AI_CONVERSATION_ID,\n GEN_AI_OPERATION_NAME,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n} from \"@tangle-network/agent-core\";\nimport {\n type ExecutionTrace,\n isFilePart,\n isReasoningPart,\n isTextPart,\n isToolPart,\n type TraceEvent,\n} from \"./trace-types.js\";\nimport type { TelemetryEvent, TelemetrySink } from \"./types.js\";\n\n/** OTEL span attribute value. */\ntype SpanAttrValue = string | number | boolean;\n\n/**\n * GenAI semantic-convention keys promoted from a `message.updated` event's\n * metadata bag to DISCRETE span attributes. The intelligence ingest derives\n * model/token/cost and conversation linkage by reading these exact keys off the\n * flat span attribute bag (`parseGenAiAttribution` / `parseConversationLinkage`\n * in the intelligence API); leaving them inside the serialized `message.metadata`\n * blob would attribute every auto-instrumented LLM call as model/tokens/cost\n * unknown. Promotion is unconditional (not gated on `includePayloads`): these\n * are attribution signal, not prompt/completion content. `genAiUsageAttributes`\n * already guarantees the writer never emits a fabricated zero, so a key absent\n * here stays absent on the span — \"cost not computed\", never \"free\".\n */\nconst GEN_AI_PROMOTED_KEYS: readonly string[] = Object.freeze([\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_OPERATION_NAME,\n GEN_AI_CONVERSATION_ID,\n]);\n\n/**\n * Build the parent-span attributes for a trace, with a deliberate precedence:\n * partner-supplied `resourceAttributes` are the LOWEST layer, so the trusted\n * identity attributes (agent.trace.id, session.id, user.id) and metadata always\n * override a colliding key. A partner cannot spoof span identity by passing a\n * `resourceAttributes` key like `session.id`.\n */\nexport function buildTraceSpanAttributes(\n trace: ExecutionTrace,\n flattenedMetadata?: Record<string, SpanAttrValue>,\n): Record<string, SpanAttrValue> {\n return {\n // Lowest precedence: partner/project/domain tags (tangle.*). Filtered by\n // being spread first — everything below wins on a key collision.\n ...((trace.scope.resourceAttributes ?? {}) as Record<\n string,\n SpanAttrValue\n >),\n \"agent.trace.id\": trace.id,\n \"agent.task\": trace.task,\n \"agent.outcome\": trace.outcome,\n // Langfuse-specific attributes for proper mapping\n \"langfuse.trace.id\": trace.id,\n \"langfuse.trace.name\": trace.task,\n ...(trace.scope.projectRef && {\n \"langfuse.project\": trace.scope.projectRef,\n }),\n ...(trace.scope.sessionId && {\n \"langfuse.session.id\": trace.scope.sessionId,\n \"session.id\": trace.scope.sessionId,\n }),\n ...(trace.scope.userId && {\n \"langfuse.user.id\": trace.scope.userId,\n \"user.id\": trace.scope.userId,\n }),\n ...(flattenedMetadata ?? {}),\n };\n}\n\n/** Configuration for the OTEL sink */\nexport interface OtelSinkConfig {\n /** Service name for the tracer */\n serviceName?: string;\n /** Include raw input/output in span attributes (may contain sensitive data) */\n includePayloads?: boolean;\n}\n\n// Lazy-loaded OTEL API types\nlet otelApi: typeof import(\"@opentelemetry/api\") | null = null;\n\n/**\n * Load the OTEL API dynamically\n */\nasync function getOtelApi() {\n if (!otelApi) {\n try {\n otelApi = await import(\"@opentelemetry/api\");\n } catch {\n return null;\n }\n }\n return otelApi;\n}\n\n/**\n * OpenTelemetry sink — exports via whatever OTEL SDK config was set at\n * application startup (Langfuse, Jaeger, any OTLP backend).\n */\ntype OtelEventAttributes = Record<\n string,\n string | number | boolean | undefined\n>;\n\nfunction addPartUpdateAttributes(\n attrs: OtelEventAttributes,\n event: Extract<TraceEvent, { type: \"message.part.updated\" }>,\n includePayloads: boolean | undefined,\n): void {\n attrs[\"message.part.id\"] = event.part.id;\n attrs[\"message.part.type\"] = event.part.type;\n\n if (isToolPart(event.part)) {\n attrs[\"tool.name\"] = event.part.tool;\n const status = event.part.state.status;\n attrs[\"tool.status\"] = status;\n if (includePayloads && event.part.state.input) {\n attrs[\"tool.input\"] = JSON.stringify(event.part.state.input).slice(\n 0,\n 4096,\n );\n }\n if (\n includePayloads &&\n status === \"completed\" &&\n event.part.state.output !== undefined\n ) {\n attrs[\"tool.output\"] = JSON.stringify(event.part.state.output).slice(\n 0,\n 4096,\n );\n }\n if (\n includePayloads &&\n (status === \"error\" || status === \"failed\") &&\n typeof event.part.state.error === \"string\"\n ) {\n attrs[\"tool.error\"] = event.part.state.error.slice(0, 4096);\n }\n } else if (isTextPart(event.part) || isReasoningPart(event.part)) {\n attrs[\"message.part.text_length\"] = event.part.text.length;\n if (includePayloads) {\n attrs[\"message.part.text\"] = event.part.text.slice(0, 4096);\n }\n } else if (isFilePart(event.part)) {\n attrs[\"file.name\"] = event.part.filename;\n if (event.part.mediaType) attrs[\"file.media_type\"] = event.part.mediaType;\n } else {\n attrs[\"subtask.id\"] = event.part.id;\n attrs[\"subtask.session_id\"] = event.part.sessionID;\n }\n}\n\nfunction addMessageUpdateAttributes(\n attrs: OtelEventAttributes,\n event: Extract<TraceEvent, { type: \"message.updated\" }>,\n includePayloads: boolean | undefined,\n): void {\n const text = event.text ?? event.finalText;\n if (typeof text === \"string\") {\n attrs[\"message.text_length\"] = text.length;\n if (includePayloads) {\n attrs[\"message.text\"] = text.slice(0, 4096);\n }\n }\n if (includePayloads && event.tokenUsage !== undefined) {\n attrs[\"message.token_usage\"] = JSON.stringify(event.tokenUsage).slice(\n 0,\n 4096,\n );\n }\n if (includePayloads && event.timing !== undefined) {\n attrs[\"message.timing\"] = JSON.stringify(event.timing).slice(0, 4096);\n }\n if (includePayloads && event.toolInvocations !== undefined) {\n attrs[\"message.tool_invocations\"] = JSON.stringify(\n event.toolInvocations,\n ).slice(0, 4096);\n }\n if (event.metadata) {\n for (const key of GEN_AI_PROMOTED_KEYS) {\n const value = event.metadata[key];\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n attrs[key] = value;\n }\n }\n }\n if (includePayloads && event.metadata !== undefined) {\n attrs[\"message.metadata\"] = JSON.stringify(event.metadata).slice(0, 4096);\n }\n}\n\nfunction addCustomEventAttributes(\n attrs: OtelEventAttributes,\n event: Extract<TraceEvent, { type: \"custom\" }>,\n): void {\n attrs[\"custom.name\"] = event.name;\n if (event.name === \"startup.phase\") {\n attrs[\"startup.id\"] =\n typeof event.data.startupId === \"string\"\n ? event.data.startupId\n : undefined;\n attrs[\"startup.phase\"] =\n typeof event.data.phase === \"string\" ? event.data.phase : undefined;\n attrs[\"startup.service\"] =\n typeof event.data.service === \"string\" ? event.data.service : undefined;\n attrs[\"startup.status\"] =\n typeof event.data.status === \"string\" ? event.data.status : undefined;\n }\n for (const [key, value] of Object.entries(event.data)) {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n attrs[`custom.data.${key}`] = value;\n }\n }\n}\n\nexport class OtelTelemetrySink implements TelemetrySink {\n readonly name = \"otel\";\n private readonly config: OtelSinkConfig;\n\n constructor(config: OtelSinkConfig = {}) {\n this.config = {\n serviceName: config.serviceName ?? \"agent-sdk\",\n includePayloads: config.includePayloads ?? false,\n };\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n const api = await getOtelApi();\n if (!api) return;\n\n // biome-ignore lint/style/noNonNullAssertion: serviceName is required in OtelSinkConfig\n const tracer = api.trace.getTracer(this.config.serviceName!, \"1.0.0\");\n\n for (const event of events) {\n // `agent_execution` events carry the full ExecutionTrace under\n // `data.trace` (see TraceCollector.flush). Export it as a proper span\n // tree rather than a single flat telemetry span — this is the path that\n // ships tagged agent traces (partner/project/user) to the OTLP backend.\n if (\n event.type === \"agent_execution\" &&\n this.isExecutionTrace(event.data.trace)\n ) {\n await this.exportTrace(event.data.trace);\n continue;\n }\n\n const span = tracer.startSpan(`telemetry.${event.type}.${event.name}`, {\n attributes: {\n \"telemetry.event.type\": event.type,\n \"telemetry.event.name\": event.name,\n },\n startTime: event.timestamp,\n });\n\n // Add event data as attributes\n if (event.data && typeof event.data === \"object\") {\n for (const [key, value] of Object.entries(event.data)) {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n span.setAttribute(`telemetry.data.${key}`, value);\n }\n }\n }\n\n span.setStatus({ code: api.SpanStatusCode.OK });\n span.end();\n }\n }\n\n /**\n * Export an execution trace as OTEL spans.\n *\n * Creates a parent span for the trace and child spans for each event.\n * Uses the global tracer, so spans flow through the configured processor.\n */\n async exportTrace(trace: ExecutionTrace): Promise<void> {\n const api = await getOtelApi();\n if (!api) return;\n\n // biome-ignore lint/style/noNonNullAssertion: serviceName is required in OtelSinkConfig\n const tracer = api.trace.getTracer(this.config.serviceName!, \"1.0.0\");\n\n // Create parent span for the entire trace\n const traceSpan = tracer.startSpan(\"agent.task\", {\n attributes: buildTraceSpanAttributes(\n trace,\n trace.metadata ? this.flattenMetadata(trace.metadata) : undefined,\n ),\n startTime: trace.startedAt,\n });\n\n // Export each trace event as child spans using the parent context\n const parentContext = api.trace.setSpan(api.context.active(), traceSpan);\n\n for (const event of trace.events) {\n if (!event?.type) continue;\n api.context.with(parentContext, () => {\n this.exportTraceEvent(tracer, api, event);\n });\n }\n\n // Export signals as events on the parent span\n for (const signal of trace.signals) {\n traceSpan.addEvent(`signal.${signal.signal}`, {}, signal.timestamp);\n }\n\n // Set final status based on outcome\n if (trace.outcome === \"failure\") {\n traceSpan.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: \"Task failed\",\n });\n } else {\n traceSpan.setStatus({ code: api.SpanStatusCode.OK });\n }\n\n traceSpan.end(trace.completedAt || new Date());\n }\n\n /**\n * Export a single trace event as an OTEL span.\n */\n private exportTraceEvent(\n tracer: ReturnType<typeof import(\"@opentelemetry/api\").trace.getTracer>,\n api: typeof import(\"@opentelemetry/api\"),\n event: TraceEvent,\n ): void {\n const spanName = this.getSpanName(event);\n const attributes = this.getEventAttributes(event);\n const startTime = this.getEventStartTime(event);\n const endTime = this.getEventEndTime(event);\n\n const span = tracer.startSpan(spanName, {\n attributes,\n startTime,\n });\n\n // Handle errors\n if (event.type === \"error\") {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: event.message,\n });\n span.recordException(new Error(event.message));\n } else if (\n event.type === \"message.part.updated\" &&\n isToolPart(event.part)\n ) {\n const status = event.part.state.status;\n if (status === \"failed\" || status === \"error\") {\n const err =\n typeof event.part.state.error === \"string\"\n ? event.part.state.error\n : \"Tool execution failed\";\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: err,\n });\n span.recordException(new Error(err));\n } else {\n span.setStatus({ code: api.SpanStatusCode.OK });\n }\n } else if (event.type === \"build_result\" && !event.success) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: \"Build failed\",\n });\n } else if (event.type === \"test_result\" && !event.success) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: \"Tests failed\",\n });\n } else if (\n event.type === \"custom\" &&\n event.name === \"startup.phase\" &&\n event.data.status === \"error\"\n ) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message:\n typeof event.data.error === \"string\"\n ? event.data.error\n : \"Startup phase failed\",\n });\n } else {\n span.setStatus({ code: api.SpanStatusCode.OK });\n }\n\n span.end(endTime);\n }\n\n private getEventStartTime(event: TraceEvent): Date {\n if (event.type === \"custom\" && event.name === \"startup.phase\") {\n const durationMs = this.getStartupPhaseDurationMs(event);\n if (typeof durationMs === \"number\") {\n return new Date(event.timestamp.getTime() - durationMs);\n }\n }\n\n return event.timestamp;\n }\n\n private getEventEndTime(event: TraceEvent): Date {\n if (event.type === \"custom\" && event.name === \"startup.phase\") {\n return event.timestamp;\n }\n\n if (\"durationMs\" in event && typeof event.durationMs === \"number\") {\n return new Date(event.timestamp.getTime() + event.durationMs);\n }\n\n return event.timestamp;\n }\n\n private getStartupPhaseDurationMs(\n event: Extract<TraceEvent, { type: \"custom\" }>,\n ): number | undefined {\n return typeof event.data.durationMs === \"number\"\n ? event.data.durationMs\n : undefined;\n }\n\n /**\n * Get span name for a trace event.\n */\n private getSpanName(event: TraceEvent): string {\n switch (event.type) {\n case \"message.part.updated\":\n if (isToolPart(event.part)) {\n return `tool.${event.part.tool}.${event.part.state.status}`;\n }\n if (isReasoningPart(event.part)) return \"llm.reasoning\";\n if (isTextPart(event.part)) return \"llm.text\";\n return \"message.file\";\n case \"message.updated\":\n return \"message.updated\";\n case \"error\":\n return `error.${event.category}`;\n case \"diagnostic\":\n return `diagnostic.${event.language || \"unknown\"}`;\n case \"file_change\":\n return `file.${event.changeType}`;\n case \"build_result\":\n return `build.${event.success ? \"success\" : \"failure\"}`;\n case \"test_result\":\n return `test.${event.success ? \"success\" : \"failure\"}`;\n case \"environment\":\n return \"environment.snapshot\";\n case \"custom\":\n if (event.name === \"startup.phase\") {\n const phase =\n typeof event.data.phase === \"string\" ? event.data.phase : \"unknown\";\n return `startup.${phase}`;\n }\n return `custom.${event.name}`;\n default:\n return \"unknown\";\n }\n }\n\n /**\n * Get OTEL attributes for a trace event.\n */\n private getEventAttributes(\n event: TraceEvent,\n ): Record<string, string | number | boolean | undefined> {\n const attrs: Record<string, string | number | boolean | undefined> = {\n \"event.type\": event.type,\n };\n\n switch (event.type) {\n case \"message.part.updated\":\n addPartUpdateAttributes(attrs, event, this.config.includePayloads);\n break;\n\n case \"message.updated\":\n addMessageUpdateAttributes(attrs, event, this.config.includePayloads);\n break;\n\n case \"error\":\n attrs[\"error.category\"] = event.category;\n attrs[\"error.message\"] = event.message;\n if (event.code) attrs[\"error.code\"] = event.code;\n if (event.source) attrs[\"error.source\"] = event.source;\n break;\n\n case \"diagnostic\":\n attrs[\"diagnostic.file\"] = event.file;\n if (event.language) attrs[\"diagnostic.language\"] = event.language;\n attrs[\"diagnostic.error_delta\"] = event.errorDelta;\n attrs[\"diagnostic.errors_after\"] = event.afterSummary.errors;\n attrs[\"diagnostic.warnings_after\"] = event.afterSummary.warnings;\n break;\n\n case \"file_change\":\n attrs[\"file.path\"] = event.file;\n attrs[\"file.change_type\"] = event.changeType;\n if (event.linesAdded) attrs[\"file.lines_added\"] = event.linesAdded;\n if (event.linesRemoved)\n attrs[\"file.lines_removed\"] = event.linesRemoved;\n break;\n\n case \"build_result\":\n attrs[\"build.success\"] = event.success;\n if (event.command) attrs[\"build.command\"] = event.command;\n if (event.durationMs) attrs[\"build.duration_ms\"] = event.durationMs;\n if (event.errorCount) attrs[\"build.error_count\"] = event.errorCount;\n if (event.warningCount)\n attrs[\"build.warning_count\"] = event.warningCount;\n break;\n\n case \"test_result\":\n attrs[\"test.success\"] = event.success;\n if (event.command) attrs[\"test.command\"] = event.command;\n if (event.durationMs) attrs[\"test.duration_ms\"] = event.durationMs;\n if (event.passed) attrs[\"test.passed\"] = event.passed;\n if (event.failed) attrs[\"test.failed\"] = event.failed;\n if (event.skipped) attrs[\"test.skipped\"] = event.skipped;\n break;\n\n case \"environment\":\n if (event.workingDir) attrs[\"env.working_dir\"] = event.workingDir;\n if (event.platform) attrs[\"env.platform\"] = event.platform;\n break;\n\n case \"custom\":\n attrs[\"custom.name\"] = event.name;\n addCustomEventAttributes(attrs, event);\n break;\n }\n\n return attrs;\n }\n\n /**\n * Flatten metadata object into span attributes\n */\n private flattenMetadata(\n metadata: Record<string, unknown>,\n prefix = \"metadata\",\n ): Record<string, string | number | boolean> {\n const attrs: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n attrs[`${prefix}.${key}`] = value;\n }\n }\n return attrs;\n }\n\n /** Narrow an opaque telemetry `data.trace` to an ExecutionTrace. */\n private isExecutionTrace(value: unknown): value is ExecutionTrace {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"scope\" in value &&\n \"events\" in value &&\n Array.isArray((value as { events: unknown }).events)\n );\n }\n\n async flush(): Promise<void> {\n // Global tracer handles flushing via the SDK\n }\n\n async close(): Promise<void> {\n // Global tracer handles shutdown via the SDK\n }\n}\n\n/**\n * Create an OTEL sink that uses the global tracer.\n *\n * The OTEL SDK must be initialized separately before using this sink.\n */\nexport function createOtelSink(config?: OtelSinkConfig): OtelTelemetrySink {\n return new OtelTelemetrySink(config);\n}\n\n/**\n * Create an OTEL sink from environment variables.\n *\n * Returns a sink that uses the global tracer (which should be initialized\n * separately via NodeSDK with LangfuseSpanProcessor or OTLPTraceExporter).\n */\nexport function createOtelSinkFromEnv(): OtelTelemetrySink | null {\n const enabled = process.env.TELEMETRY_ENABLED === \"true\";\n const hasLangfuse =\n process.env.LANGFUSE_PUBLIC_KEY && process.env.LANGFUSE_SECRET_KEY;\n const hasOtlp = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n\n if (!enabled || (!hasLangfuse && !hasOtlp)) {\n return null;\n }\n\n return new OtelTelemetrySink({\n serviceName: process.env.OTEL_SERVICE_NAME || \"orchestrator\",\n includePayloads: process.env.OTEL_INCLUDE_PAYLOADS === \"true\",\n });\n}\n","/**\n * Telemetry Sinks\n *\n * Output destinations for telemetry data including\n * HTTP endpoints, console, and custom handlers.\n */\n\nimport type { TelemetryEvent, TelemetrySink } from \"./types.js\";\n\n// HTTP sink for sending telemetry to a remote endpoint\nexport class HttpTelemetrySink implements TelemetrySink {\n readonly name = \"http\";\n private readonly endpoint: string;\n private readonly headers: Record<string, string>;\n private readonly fetchFn: typeof fetch;\n private readonly timeout: number;\n private pendingRequests: Promise<void>[] = [];\n\n constructor(config: {\n endpoint: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n timeout?: number;\n }) {\n this.endpoint = config.endpoint;\n this.headers = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n this.timeout = config.timeout ?? 30000;\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n const request = this.fetchFn(this.endpoint, {\n method: \"POST\",\n headers: this.headers,\n body: JSON.stringify({ events }),\n signal: AbortSignal.timeout(this.timeout),\n }).then((res) => {\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}: ${res.statusText}`);\n }\n });\n\n this.pendingRequests.push(request);\n\n try {\n await request;\n } finally {\n this.pendingRequests = this.pendingRequests.filter((r) => r !== request);\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(this.pendingRequests);\n }\n\n async close(): Promise<void> {\n await this.flush();\n }\n}\n\n// Console sink for development/debugging\nexport class ConsoleTelemetrySink implements TelemetrySink {\n readonly name = \"console\";\n private readonly prefix: string;\n private readonly logLevel: \"log\" | \"debug\" | \"info\";\n private readonly formatJson: boolean;\n\n constructor(config?: {\n prefix?: string;\n logLevel?: \"log\" | \"debug\" | \"info\";\n formatJson?: boolean;\n }) {\n this.prefix = config?.prefix ?? \"[telemetry]\";\n this.logLevel = config?.logLevel ?? \"debug\";\n this.formatJson = config?.formatJson ?? true;\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n for (const event of events) {\n const message = this.formatJson\n ? JSON.stringify(event, null, 2)\n : `${event.type}:${event.name} ${JSON.stringify(event.data)}`;\n\n console[this.logLevel](`${this.prefix} ${message}`);\n }\n }\n\n async flush(): Promise<void> {\n // No-op for console\n }\n\n async close(): Promise<void> {\n // No-op for console\n }\n}\n\n// Test sink for capturing events in tests (in-memory array, not connected to memory system)\nexport class TestTelemetrySink implements TelemetrySink {\n readonly name = \"test\";\n readonly events: TelemetryEvent[] = [];\n\n async send(events: TelemetryEvent[]): Promise<void> {\n this.events.push(...events);\n }\n\n async flush(): Promise<void> {\n // No-op\n }\n\n async close(): Promise<void> {\n // No-op\n }\n\n clear(): void {\n this.events.length = 0;\n }\n\n getEvents(): TelemetryEvent[] {\n return [...this.events];\n }\n\n getEventsByType(type: string): TelemetryEvent[] {\n return this.events.filter((e) => e.type === type);\n }\n\n getEventsByName(name: string): TelemetryEvent[] {\n return this.events.filter((e) => e.name === name);\n }\n}\n\n// Multi-sink that sends to multiple destinations\nexport class MultiTelemetrySink implements TelemetrySink {\n readonly name = \"multi\";\n private readonly sinks: TelemetrySink[];\n\n constructor(sinks: TelemetrySink[]) {\n this.sinks = sinks;\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n await Promise.all(this.sinks.map((sink) => sink.send(events)));\n }\n\n async flush(): Promise<void> {\n await Promise.all(this.sinks.map((sink) => sink.flush()));\n }\n\n async close(): Promise<void> {\n await Promise.all(this.sinks.map((sink) => sink.close()));\n }\n}\n\n// Factory functions\nexport function createHttpSink(config: {\n endpoint: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n timeout?: number;\n}): HttpTelemetrySink {\n return new HttpTelemetrySink(config);\n}\n\nexport function createConsoleSink(config?: {\n prefix?: string;\n logLevel?: \"log\" | \"debug\" | \"info\";\n}): ConsoleTelemetrySink {\n return new ConsoleTelemetrySink(config);\n}\n\nexport function createTestSink(): TestTelemetrySink {\n return new TestTelemetrySink();\n}\n","/**\n * SSE Event Parser\n *\n * Converts SSE stream events to typed TraceEvents.\n * Used by both orchestrator and simulation to ensure consistent event capture.\n *\n * message.part.updated events are passed through directly without transformation.\n * This preserves full fidelity to what OpenCode outputs.\n */\n\nimport {\n parseSSEData as coreParseSSEData,\n type Part,\n type SSEEventData,\n} from \"@tangle-network/agent-core\";\nimport type {\n CustomEvent,\n ErrorEvent,\n MessagePartUpdatedEventWithTimestamp,\n MessageUpdatedEvent,\n Signal,\n SignalEvent,\n ToolPart,\n ToolState,\n TraceEvent,\n} from \"./trace-types.js\";\n\n// Re-export from sdk-core for backwards compatibility\nexport type { SSEEventData } from \"@tangle-network/agent-core\";\nexport const parseSSEData = coreParseSSEData;\n\n/** Valid signals from SSE status events */\nconst VALID_SIGNALS: Signal[] = [\n \"build_passed\",\n \"build_failed\",\n \"tests_passed\",\n \"tests_failed\",\n \"lint_passed\",\n \"lint_failed\",\n \"user_approved\",\n \"user_rejected\",\n \"task_completed\",\n \"task_abandoned\",\n \"runtime_error\",\n \"timeout\",\n];\n\n/**\n * Provider event shapes that carry a tool-invocation payload either at\n * the top level or under one of the well-known wrappers. Recognized here\n * (and not in the consumer) so trace events look identical regardless of\n * which provider emitted the call.\n */\nconst TOOL_INVOCATION_TYPES = new Set([\n \"tool-invocation\",\n `tool_${\"call\"}`,\n \"computer-use\",\n \"computer_call\",\n]);\n\n/**\n * The ToolState a raw invocation reports. OpenCode-shaped payloads nest it\n * under `state`; flat provider shapes put its fields at the top level.\n */\nfunction rawToolInvocationState(source: Record<string, unknown>): ToolState {\n const stateObj =\n (source.state as Record<string, unknown> | undefined) ?? undefined;\n const input = (source.args ??\n source.arguments ??\n source.input ??\n stateObj?.input ??\n {}) as Record<string, unknown> | undefined;\n // OpenCode-shaped state nests `output` under `state`; flat provider\n // shapes put it at the top level. Check both.\n const output = (source.result ?? source.output ?? stateObj?.output) as\n | unknown\n | undefined;\n const errorMsg =\n typeof source.error === \"string\"\n ? (source.error as string)\n : typeof stateObj?.error === \"string\"\n ? (stateObj.error as string)\n : undefined;\n const stateStatus =\n typeof stateObj?.status === \"string\"\n ? (stateObj.status as string)\n : undefined;\n const explicitStatus =\n typeof source.status === \"string\" ? (source.status as string) : undefined;\n const status =\n stateStatus ??\n explicitStatus ??\n (output !== undefined ? \"completed\" : \"running\");\n\n let toolState: ToolState;\n switch (status) {\n case \"completed\":\n toolState = {\n status: \"completed\",\n input: (input ?? {}) as Record<string, unknown>,\n // ToolStateCompleted.output is `unknown` (required, not optional).\n // Some providers emit `state: {status: \"completed\"}` for side-\n // effect-only tool calls (writes, notifications) without a\n // return value. Coerce undefined → null so the field is always\n // present on the wire (JSON.stringify drops `undefined` keys\n // entirely), and so consumers can rely on `state.output` being\n // defined whenever `state.status === \"completed\"`.\n output: output ?? null,\n };\n break;\n case \"queued\":\n // Some providers report \"queued\" before \"pending\"; treat both\n // as pending in our ToolState (which doesn't have a separate\n // queued variant). The call-site filter then drops both.\n case \"pending\":\n toolState = {\n status: \"pending\",\n input: (input ?? {}) as Record<string, unknown>,\n };\n break;\n case \"running\":\n case \"in_progress\":\n toolState = {\n status: \"running\",\n input: (input ?? {}) as Record<string, unknown>,\n };\n break;\n case \"error\":\n case \"failed\":\n toolState = {\n status,\n input: (input ?? {}) as Record<string, unknown>,\n output,\n error: errorMsg,\n };\n break;\n default:\n // Unknown status — surface as running so the consumer at least\n // gets the call shape; downstream UIs can rely on\n // running/completed parts arriving for the same callId.\n toolState = {\n status: \"running\",\n input: (input ?? {}) as Record<string, unknown>,\n };\n }\n return toolState;\n}\n\n/**\n * Best-effort: lift a raw tool-invocation event into a canonical\n * `message.part.updated` event with a `ToolPart`. Returns null for\n * payloads we cannot recognize, which lets the caller fall through to\n * a `custom` trace event rather than silently misclassifying.\n *\n * Wire contract — what shapes are expected here:\n *\n * This normalizer runs at the trace-event boundary, AFTER provider\n * adapters have done their own normalization. Adapters\n * (sdk-provider-opencode, sdk-provider-amp, sdk-provider-claude-code,\n * etc.) translate provider-native events into our internal\n * AgentStreamEvent shape — typically wrapping tool invocations\n * under `toolInvocation`/`tool_invocation`/`computerUse`/\n * `computer_use`, with `type` set to one of `TOOL_INVOCATION_TYPES`.\n *\n * Provider-native shapes that adapters are expected to unwrap:\n *\n * OpenAI Responses / Chat Completions:\n * `{id, type: \"function\", function: {name, arguments}}` →\n * adapter wraps into an internal tool-invocation event with `toolInvocation: {\n * toolCallId: id, toolName: function.name, args: function.arguments}}`\n *\n * Anthropic tool_use blocks:\n * `{type: \"tool_use\", id, name, input}` →\n * adapter wraps into an internal tool-invocation event with `toolInvocation`.\n *\n * The flat-with-`id` fallback (`source.id` in the callId chain) is\n * a defensive safety net for cases where an adapter forwards the\n * provider's flat shape verbatim. It is NOT a substitute for\n * adapter-side normalization — the literal OpenAI\n * `{type: \"function\", function: {...}}` wrapper is NOT recognized\n * here because `\"function\"` is intentionally not in\n * TOOL_INVOCATION_TYPES (the word collides with too many\n * non-tool-call uses of `function` as a top-level key).\n */\nfunction normalizeRawToolInvocation(\n event: SSEEventData,\n timestamp: Date,\n): MessagePartUpdatedEventWithTimestamp | null {\n const top = event as Record<string, unknown>;\n const wrapped = (top.toolInvocation ??\n top.tool_invocation ??\n top.computerUse ??\n top.computer_use) as Record<string, unknown> | undefined;\n const innerType = typeof top.type === \"string\" ? top.type : undefined;\n const sourceType =\n typeof top.event === \"object\" && top.event !== null\n ? ((top.event as Record<string, unknown>).type as string | undefined)\n : undefined;\n const isToolType =\n (innerType && TOOL_INVOCATION_TYPES.has(innerType)) ||\n (sourceType && TOOL_INVOCATION_TYPES.has(sourceType));\n if (!wrapped && !isToolType) {\n return null;\n }\n const source = (wrapped ?? top) as Record<string, unknown>;\n const isComputerUse =\n innerType === \"computer-use\" ||\n innerType === \"computer_call\" ||\n sourceType === \"computer-use\" ||\n sourceType === \"computer_call\";\n\n const callId = String(\n source.toolCallId ??\n source.tool_call_id ??\n source.callId ??\n source.callID ??\n source.id ??\n \"\",\n );\n const baseName = String(\n source.toolName ?? source.tool_name ?? source.name ?? \"\",\n );\n const toolName = isComputerUse\n ? `computer-use:${\n ((source.action as { type?: string } | undefined)?.type as string) ||\n \"action\"\n }`\n : baseName;\n if (!callId || !toolName) {\n return null;\n }\n\n const toolState = rawToolInvocationState(source);\n\n // PartBase contract on a SYNTHESIZED ToolPart:\n //\n // - `id` = `callId`. The tool call is uniquely identified by\n // its callID, so reusing it here lets a consumer\n // group/lookup-by-id without risk of collision across\n // provider tool calls.\n // - `sessionID` and `messageID` = \"\" (empty string). The\n // originating SSE payload does NOT carry these; they\n // are an OpenCode-shape concept that doesn't exist\n // for raw provider events. Empty string is the honest\n // \"we don't know\" — using a sentinel like\n // \"__synthesized__\" was considered but would force\n // every consumer of `ToolPart.sessionID` to special-\n // case the string, whereas standard \"is this empty?\"\n // checks already work consistently with `\"\"`.\n //\n // Consumers that group parts by `sessionID` should treat empty-\n // string as \"unsynthesized origin\" and not mix it with real\n // session traffic — the trace event itself is a record of the\n // call shape, not of session membership.\n const part: ToolPart = {\n id: callId,\n sessionID: \"\",\n messageID: \"\",\n type: \"tool\",\n callID: callId,\n tool: toolName,\n state: toolState,\n };\n\n return {\n type: \"message.part.updated\",\n part,\n timestamp,\n } satisfies MessagePartUpdatedEventWithTimestamp;\n}\n\n/**\n * Convert SSE event data to a typed TraceEvent.\n * Returns null for events that should be skipped (heartbeats, status-only, etc.)\n *\n * message.part.updated events are passed through directly - no transformation.\n * This preserves full fidelity to what OpenCode outputs.\n *\n * `raw` events that carry a recognized tool-invocation payload are\n * normalized into the same `message.part.updated` shape (with a\n * `ToolPart`) so consumers don't need to reach into provider-specific\n * raw shapes to render tool calls. Unrecognized raw events fall\n * through to a `custom` trace event.\n */\nexport function sseToTraceEvent(event: SSEEventData): TraceEvent | null {\n const timestamp = new Date();\n\n // Recognize tool-invocation payloads regardless of whether the\n // outer wrapper survived as `raw` (orchestrator path), came through\n // as the inner provider type (direct sandbox SDK path), or was\n // emitted with a top-level inner-type marker.\n if (\n event.type === \"raw\" ||\n (typeof event.type === \"string\" && TOOL_INVOCATION_TYPES.has(event.type))\n ) {\n const normalized = normalizeRawToolInvocation(event, timestamp);\n if (normalized) {\n // Apply the same filter that the `message.part.updated`\n // branch below applies — the contract for `message.part.updated`\n // trace events is \"no pending tool states\", and a normalized\n // raw event lands in the same shape, so it must obey the same\n // filter. Without this, a consumer that processes both kinds\n // of events would see pending tool calls from raw\n // normalization but not from direct message.part.updated, an\n // inconsistency in the trace contract. (\"queued\" raw events\n // are mapped to \"pending\" inside the normalizer so this single\n // check covers both source statuses.)\n const status = (normalized.part as { state?: { status?: string } }).state\n ?.status;\n if (status === \"pending\") {\n return null;\n }\n return normalized;\n }\n // Unrecognized shape → custom event so observability still\n // captures the payload but doesn't pretend it's a tool call.\n // Preserve the original event type as the custom event's `name`\n // so trace consumers filtering by `name` can find e.g. a\n // malformed legacy tool invocation under its original name instead of\n // every unrecognized variant collapsing to `name: \"raw\"`.\n //\n // Match the `data` shape produced by the `default:` arm in the\n // switch below (`{eventType, ...event}`) so consumers that\n // inspect `data.eventType` on custom events get a uniform shape\n // regardless of whether the unrecognized event came in as a raw\n // tool-invocation type or as an unknown plain type.\n const customName = typeof event.type === \"string\" ? event.type : \"raw\";\n return {\n type: \"custom\",\n timestamp,\n name: customName,\n data: { eventType: customName, ...event } as Record<string, unknown>,\n } satisfies CustomEvent;\n }\n\n switch (event.type) {\n case \"message.part.updated\": {\n // Pass through message.part.updated events directly - no transformation\n // This preserves full fidelity to what OpenCode outputs\n const part = (event as { part?: Part }).part;\n if (!part) {\n return null;\n }\n\n // Skip pending/queued tool states - they don't contain meaningful data yet\n if (part.type === \"tool\") {\n const status = (part as { state?: { status?: string } }).state?.status;\n if (status === \"pending\" || status === \"queued\") {\n return null;\n }\n }\n\n return {\n type: \"message.part.updated\",\n part,\n timestamp,\n delta: (event as { delta?: string }).delta,\n _meta: (event as { _meta?: unknown })._meta as\n | MessagePartUpdatedEventWithTimestamp[\"_meta\"]\n | undefined,\n } satisfies MessagePartUpdatedEventWithTimestamp;\n }\n\n case \"error\":\n return {\n type: \"error\",\n timestamp,\n category: \"runtime\",\n message: String(event.message || event.error || \"Unknown error\"),\n code: typeof event.code === \"string\" ? event.code : undefined,\n } satisfies ErrorEvent;\n\n case \"status\":\n // Status events don't become trace events, they become signals\n return null;\n\n case \"result\": {\n const finalText =\n typeof (event as { finalText?: unknown }).finalText === \"string\"\n ? (event as { finalText?: string }).finalText\n : typeof (event as { text?: unknown }).text === \"string\"\n ? (event as { text?: string }).text\n : undefined;\n\n return {\n type: \"message.updated\",\n timestamp,\n text: finalText,\n finalText,\n tokenUsage: (event as { tokenUsage?: unknown }).tokenUsage as\n | Record<string, unknown>\n | undefined,\n timing: (event as { timing?: unknown }).timing as\n | Record<string, unknown>\n | undefined,\n toolInvocations: (event as { toolInvocations?: unknown })\n .toolInvocations as unknown[] | undefined,\n metadata: (event as { metadata?: unknown }).metadata as\n | Record<string, unknown>\n | undefined,\n } satisfies MessageUpdatedEvent;\n }\n case \"done\":\n // Terminal events - skip as trace events\n return null;\n\n default:\n // Capture unknown events as custom type for extensibility\n if (event.type && event.type !== \"heartbeat\") {\n return {\n type: \"custom\",\n timestamp,\n name: event.type,\n data: { eventType: event.type, ...event },\n } satisfies CustomEvent;\n }\n return null;\n }\n}\n\n/**\n * Extract a signal from an SSE event if present.\n */\nexport function sseToSignal(event: SSEEventData): SignalEvent | null {\n if (event.type === \"status\" && typeof event.status === \"string\") {\n if (VALID_SIGNALS.includes(event.status as Signal)) {\n return {\n signal: event.status as Signal,\n timestamp: new Date(),\n };\n }\n }\n return null;\n}\n\n/**\n * Check if an SSE event indicates completion (success or failure).\n */\nexport function isCompletionEvent(event: SSEEventData): {\n complete: boolean;\n success: boolean;\n} {\n if (event.type === \"done\" || event.type === \"result\") {\n const success = !(\"success\" in event && event.success === false);\n return { complete: true, success };\n }\n if (event.type === \"error\") {\n return { complete: true, success: false };\n }\n return { complete: false, success: false };\n}\n","/**\n * Trace Collector\n *\n * Collects execution traces and exports them to telemetry sinks.\n * Designed for cross-user data aggregation and analysis.\n */\n\nimport type {\n ExecutionTrace,\n Outcome,\n Signal,\n TraceEvent,\n TraceScope,\n} from \"./trace-types.js\";\nimport type { TelemetrySink } from \"./types.js\";\n\n// Web Crypto instead of a static `node:crypto` import keeps this module's barrel\n// (`@tangle-network/sdk-telemetry`) browser-safe — hub-sdk re-exports the barrel\n// and platform-web ships it to the browser, where a `node:crypto` import is\n// externalized and blanks the page. `globalThis.crypto` is present in Node 20+\n// and secure browser contexts (HTTPS / localhost) but ABSENT over plain HTTP, so\n// fall back to a Math.random v4 there — a trace id needs uniqueness, not\n// cryptographic strength.\nconst randomUUID = (): string => {\n const webCrypto = globalThis.crypto;\n if (webCrypto?.randomUUID) return webCrypto.randomUUID();\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n return (ch === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n};\n\nexport interface TraceCollectorConfig {\n /** Sink to export traces to */\n sink: TelemetrySink;\n /** Max traces to buffer before auto-flush */\n maxBufferSize?: number;\n /** Auto-flush interval in ms (0 = manual only) */\n flushIntervalMs?: number;\n /** Default scope for new traces */\n defaultScope?: TraceScope;\n}\n\n/** Active trace context for tracking a single execution */\nexport interface TraceContext {\n traceId: string;\n startedAt: Date;\n /** Add a typed event to the trace */\n addEvent<T extends TraceEvent>(event: Omit<T, \"timestamp\">): void;\n /** Add a signal (success/failure indicator) */\n addSignal(signal: Signal, metadata?: Record<string, unknown>): void;\n /** Complete the trace successfully */\n complete(metadata?: Record<string, unknown>): ExecutionTrace;\n /** Complete the trace with failure */\n fail(\n error: string | Error,\n metadata?: Record<string, unknown>,\n ): ExecutionTrace;\n /** Abandon the trace */\n abandon(): ExecutionTrace;\n}\n\ninterface ActiveTrace {\n id: string;\n scope: TraceScope;\n task: string;\n events: TraceEvent[];\n signals: Array<{\n signal: Signal;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n }>;\n startedAt: Date;\n metadata?: Record<string, unknown>;\n}\n\nexport class TraceCollector {\n private sink: TelemetrySink;\n private config: Required<\n Omit<TraceCollectorConfig, \"sink\" | \"defaultScope\">\n > & { defaultScope?: TraceScope };\n private activeTraces = new Map<string, ActiveTrace>();\n private completedTraces: ExecutionTrace[] = [];\n private flushTimer?: ReturnType<typeof setInterval>;\n private flushing?: Promise<void>;\n private sequence = 0;\n\n constructor(config: TraceCollectorConfig) {\n this.sink = config.sink;\n this.config = {\n maxBufferSize: config.maxBufferSize ?? 100,\n flushIntervalMs: config.flushIntervalMs ?? 0,\n defaultScope: config.defaultScope,\n };\n\n if (this.config.flushIntervalMs > 0) {\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.config.flushIntervalMs);\n }\n }\n\n /** Start tracking a new execution */\n startTrace(\n task: string,\n scope?: TraceScope,\n metadata?: Record<string, unknown>,\n ): TraceContext {\n const traceId = `trace_${randomUUID()}`;\n const startedAt = new Date();\n const traceScope = scope ?? this.config.defaultScope ?? {};\n\n const activeTrace: ActiveTrace = {\n id: traceId,\n scope: traceScope,\n task,\n events: [],\n signals: [],\n startedAt,\n metadata,\n };\n\n this.activeTraces.set(traceId, activeTrace);\n\n return {\n traceId,\n startedAt,\n\n addEvent: <T extends TraceEvent>(event: Omit<T, \"timestamp\">) => {\n const trace = this.activeTraces.get(traceId);\n if (trace) {\n trace.events.push({ ...event, timestamp: new Date() } as T);\n }\n },\n\n addSignal: (signal, signalMeta) => {\n const trace = this.activeTraces.get(traceId);\n if (trace) {\n trace.signals.push({\n signal,\n timestamp: new Date(),\n metadata: signalMeta,\n });\n }\n },\n\n complete: (completeMeta) => {\n return this.completeTrace(traceId, \"success\", completeMeta);\n },\n\n fail: (error, failMeta) => {\n const trace = this.activeTraces.get(traceId);\n if (trace) {\n const errorMsg = error instanceof Error ? error.message : error;\n trace.events.push({\n type: \"error\",\n timestamp: new Date(),\n category: \"runtime\",\n message: errorMsg,\n stack: error instanceof Error ? error.stack : undefined,\n });\n trace.signals.push({\n signal: \"runtime_error\",\n timestamp: new Date(),\n });\n }\n return this.completeTrace(traceId, \"failure\", failMeta);\n },\n\n abandon: () => {\n return this.completeTrace(traceId, \"unknown\", { abandoned: true });\n },\n };\n }\n\n /** Convenience: track a complete execution with a wrapper function */\n async track<T>(\n task: string,\n fn: (ctx: TraceContext) => Promise<T>,\n options?: { scope?: TraceScope; metadata?: Record<string, unknown> },\n ): Promise<{ result: T; trace: ExecutionTrace }> {\n const ctx = this.startTrace(task, options?.scope, options?.metadata);\n try {\n const result = await fn(ctx);\n const trace = ctx.complete();\n return { result, trace };\n } catch (error) {\n ctx.fail(error instanceof Error ? error : String(error));\n throw error;\n }\n }\n\n /** Flush completed traces to sink, including traces completed during delivery. */\n flush(): Promise<void> {\n if (this.flushing) return this.flushing;\n if (this.completedTraces.length === 0) return Promise.resolve();\n\n // Publish ownership before invoking a sink, including synchronous callbacks.\n this.flushing = Promise.resolve().then(async () => {\n try {\n while (this.completedTraces.length > 0) {\n const count = this.completedTraces.length;\n const events = this.completedTraces.map((trace) => ({\n id: `evt_${randomUUID()}`,\n type: \"agent_execution\" as const,\n name: \"execution_trace\",\n projectRef: trace.scope.projectRef,\n sessionId: trace.scope.sessionId,\n userId: trace.scope.userId,\n data: {\n traceId: trace.id,\n task: trace.task,\n outcome: trace.outcome,\n eventCount: trace.events.length,\n signalCount: trace.signals.length,\n durationMs: trace.completedAt\n ? trace.completedAt.getTime() - trace.startedAt.getTime()\n : undefined,\n // Full trace data for detailed analysis\n trace,\n },\n timestamp: trace.completedAt ?? new Date(),\n sequence: this.sequence++,\n }));\n\n await this.sink.send(events);\n // Only acknowledge this batch; newer completions still need delivery.\n this.completedTraces.splice(0, count);\n }\n } finally {\n this.flushing = undefined;\n }\n });\n return this.flushing;\n }\n\n /** Get count of pending traces */\n getPendingCount(): number {\n return this.completedTraces.length;\n }\n\n /** Get active trace count */\n getActiveCount(): number {\n return this.activeTraces.size;\n }\n\n /** Shutdown collector */\n async shutdown(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n await this.flush();\n await this.sink.flush();\n await this.sink.close();\n }\n\n private completeTrace(\n traceId: string,\n outcome: Outcome,\n metadata?: Record<string, unknown>,\n ): ExecutionTrace {\n const active = this.activeTraces.get(traceId);\n if (!active) {\n throw new Error(`Trace not found: ${traceId}`);\n }\n\n this.activeTraces.delete(traceId);\n\n const completedTrace: ExecutionTrace = {\n id: active.id,\n scope: active.scope,\n task: active.task,\n events: active.events,\n signals: active.signals,\n outcome: this.classifyOutcome(active.signals, outcome),\n startedAt: active.startedAt,\n completedAt: new Date(),\n metadata: { ...active.metadata, ...metadata },\n };\n\n this.completedTraces.push(completedTrace);\n\n if (this.completedTraces.length >= this.config.maxBufferSize) {\n this.flush().catch(() => {});\n }\n\n return completedTrace;\n }\n\n private classifyOutcome(\n signals: Array<{ signal: Signal }>,\n defaultOutcome: Outcome,\n ): Outcome {\n const signalSet = new Set(signals.map((s) => s.signal));\n\n if (signalSet.has(\"task_completed\")) {\n if (\n signalSet.has(\"tests_passed\") ||\n signalSet.has(\"build_passed\") ||\n signalSet.has(\"user_approved\")\n ) {\n return \"success\";\n }\n return \"partial\";\n }\n\n if (\n signalSet.has(\"runtime_error\") ||\n signalSet.has(\"timeout\") ||\n signalSet.has(\"tests_failed\") ||\n signalSet.has(\"build_failed\") ||\n signalSet.has(\"user_rejected\")\n ) {\n return \"failure\";\n }\n\n if (signalSet.has(\"task_abandoned\")) {\n return \"unknown\";\n }\n\n return defaultOutcome;\n }\n}\n\nexport function createTraceCollector(\n config: TraceCollectorConfig,\n): TraceCollector {\n return new TraceCollector(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["GEN_AI_REQUEST_MODEL","GEN_AI_RESPONSE_MODEL","GEN_AI_USAGE_INPUT_TOKENS","GEN_AI_USAGE_OUTPUT_TOKENS","GEN_AI_OPERATION_NAME","GEN_AI_CONVERSATION_ID","coreParseSSEData"],"sources":["../src/enrichment/parse.ts","../src/enrichment/types.ts","../src/trace-types.ts","../src/langfuse-sink.ts","../src/otel-provider.ts","../src/otel-sink.ts","../src/sinks.ts","../src/sse-parser.ts","../src/trace-collector.ts"],"sourcesContent":["/**\n * Metadata blob parsing: JSON blobs map partner fields onto an enrichment\n * context; any other format, or JSON that fails to parse, yields only the raw blob.\n */\n\nimport type {\n EnrichmentContext,\n EnvironmentType,\n MetadataBlob,\n ProductType,\n SubscriptionTier,\n} from \"./types.js\";\n\n/** Expected JSON structure for partner metadata */\ninterface JsonMetadataPayload {\n partner_id?: string;\n partnerId?: string;\n subscription_tier?: string;\n subscriptionTier?: string;\n user_id?: string;\n userId?: string;\n end_user_id?: string;\n endUserId?: string;\n product?: string;\n environment?: string;\n env?: string;\n custom?: Record<string, string>;\n labels?: Record<string, string>;\n [key: string]: unknown;\n}\n\nconst VALID_PRODUCTS: ProductType[] = [\n \"vibe_coding\",\n \"simulation\",\n \"background_agent\",\n];\nconst VALID_ENVIRONMENTS: EnvironmentType[] = [\n \"development\",\n \"staging\",\n \"production\",\n];\nconst VALID_TIERS: SubscriptionTier[] = [\"free\", \"pro\", \"enterprise\"];\n\nfunction normalizeProduct(value: unknown): ProductType | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.toLowerCase().replace(/-/g, \"_\");\n return VALID_PRODUCTS.includes(normalized as ProductType)\n ? (normalized as ProductType)\n : undefined;\n}\n\nfunction normalizeEnvironment(value: unknown): EnvironmentType | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.toLowerCase();\n // Map common aliases\n if (normalized === \"dev\") return \"development\";\n if (normalized === \"prod\") return \"production\";\n return VALID_ENVIRONMENTS.includes(normalized as EnvironmentType)\n ? (normalized as EnvironmentType)\n : undefined;\n}\n\nfunction normalizeTier(value: unknown): SubscriptionTier | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.toLowerCase();\n return VALID_TIERS.includes(normalized as SubscriptionTier)\n ? (normalized as SubscriptionTier)\n : undefined;\n}\n\n/** Parse a metadata blob into an enrichment context that keeps the raw blob. */\nexport function parseMetadataBlob(blob: MetadataBlob): EnrichmentContext {\n if (blob.format !== \"json\") return { customLabels: {}, rawBlob: blob };\n try {\n return parseJsonBlob(blob);\n } catch {\n return { customLabels: {}, rawBlob: blob };\n }\n}\n\nfunction parseJsonBlob(blob: MetadataBlob): EnrichmentContext {\n const dataStr =\n typeof blob.data === \"string\" ? blob.data : blob.data.toString(\"utf-8\");\n\n const payload = JSON.parse(dataStr) as JsonMetadataPayload;\n const context: EnrichmentContext = { customLabels: {}, rawBlob: blob };\n\n // Partner ID (snake_case or camelCase)\n const partnerId = payload.partner_id || payload.partnerId;\n if (typeof partnerId === \"string\" && partnerId.length > 0) {\n context.partnerId = partnerId;\n }\n\n // Subscription tier\n const tier = payload.subscription_tier || payload.subscriptionTier;\n context.subscriptionTier = normalizeTier(tier);\n\n // End user ID (multiple possible field names)\n const userId =\n payload.end_user_id ||\n payload.endUserId ||\n payload.user_id ||\n payload.userId;\n if (typeof userId === \"string\" && userId.length > 0) {\n context.endUserId = userId;\n }\n\n // Product type\n context.product = normalizeProduct(payload.product);\n\n // Environment\n context.environment = normalizeEnvironment(\n payload.environment || payload.env,\n );\n\n // Custom labels (merge custom and labels fields)\n const customLabels: Record<string, string> = {};\n const addLabels = (obj: unknown) => {\n if (obj && typeof obj === \"object\" && !Array.isArray(obj)) {\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === \"string\") {\n customLabels[key] = value;\n } else if (typeof value === \"number\" || typeof value === \"boolean\") {\n customLabels[key] = String(value);\n }\n }\n }\n };\n addLabels(payload.custom);\n addLabels(payload.labels);\n\n if (Object.keys(customLabels).length > 0) {\n context.customLabels = customLabels;\n }\n\n return context;\n}\n","/**\n * Enrichment Types\n *\n * Types for client-forwarded metadata blobs and parsed enrichment context.\n * Partners send metadata that parseMetadataBlob turns into an enrichment\n * context attached to traces for analytics and tenant isolation.\n */\n\n/** Supported blob formats for metadata transmission */\nexport type MetadataBlobFormat = \"json\" | \"msgpack\" | \"protobuf\";\n\n/** Client-forwarded metadata blob */\nexport interface MetadataBlob {\n /** Serialization format of the data */\n format: MetadataBlobFormat;\n /** Serialized data (base64 for binary formats) */\n data: string | Buffer;\n /** Optional schema identifier for validation */\n schema?: string;\n}\n\n/** Product context for trace classification */\nexport type ProductType = \"vibe_coding\" | \"simulation\" | \"background_agent\";\n\n/** Environment context */\nexport type EnvironmentType = \"development\" | \"staging\" | \"production\";\n\n/** Subscription tier for rate limiting and feature gating */\nexport type SubscriptionTier = \"free\" | \"pro\" | \"enterprise\";\n\n/**\n * Parsed enrichment context attached to traces.\n * Built from partner metadata blobs by parseMetadataBlob.\n */\nexport interface EnrichmentContext {\n /** Partner identifier for tenant isolation */\n partnerId?: string;\n /** Subscription tier for rate limiting */\n subscriptionTier?: SubscriptionTier;\n /** End user identifier within partner's system */\n endUserId?: string;\n /** Product context */\n product?: ProductType;\n /** Deployment environment */\n environment?: EnvironmentType;\n /** Custom key-value labels for filtering */\n customLabels: Record<string, string>;\n /** Original blob for audit/replay */\n rawBlob?: MetadataBlob;\n}\n\n/** Create an empty enrichment context with defaults */\nexport function createEmptyContext(): EnrichmentContext {\n return {\n customLabels: {},\n };\n}\n","/**\n * Trace Event Types\n *\n * Strongly typed discriminated union for execution trace events.\n * Used to capture detailed agent execution data for analysis and training.\n *\n * SSE events from OpenCode (MessagePartUpdatedEvent, StatusEvent, etc.) are\n * imported from sdk-core and passed through without transformation.\n * Trace-specific events (DiagnosticEvent, BuildResultEvent, etc.) are\n * collected by other means and defined here.\n */\n\n// Re-export canonical SSE event types from sdk-core (which re-exports from agent-interface)\nexport type {\n AgentEvent,\n ErrorEvent as AgentErrorEvent,\n FilePart,\n MessagePartUpdatedEvent,\n Part,\n PartBase,\n ReasoningPart,\n ResultEvent,\n StatusEvent,\n TextPart,\n ToolPart,\n ToolState,\n ToolStateCompleted,\n} from \"@tangle-network/agent-core\";\n\nexport {\n isFilePart,\n isReasoningPart,\n isTextPart,\n isToolPart,\n} from \"@tangle-network/agent-core\";\n\nimport type { MessagePartUpdatedEvent } from \"@tangle-network/agent-core\";\n\n/**\n * MessagePartUpdatedEvent with timestamp for trace collection.\n * This is the canonical event type from OpenCode - pass through without transformation.\n */\nexport interface MessagePartUpdatedEventWithTimestamp\n extends MessagePartUpdatedEvent {\n /** Timestamp when event was recorded */\n timestamp: Date;\n}\n\n/** Type guard for MessagePartUpdatedEvent */\nexport function isMessagePartUpdatedEvent(\n event: TraceEvent,\n): event is MessagePartUpdatedEventWithTimestamp {\n return event.type === \"message.part.updated\";\n}\n\n/** Execution scope for trace association */\nexport interface TraceScope {\n projectRef?: string;\n sessionId?: string;\n /** Links sub-agent sessions to their parent session */\n parentSessionId?: string;\n userId?: string;\n /**\n * Tangle Intelligence resource attributes for this scope — the `tangle.*`\n * dimensions a partner filters on (partner / project / domain / pseudonymous\n * end-user). Built host-side and threaded per session; stamped onto every\n * exported span by the OTEL sink. Kept as an open bag so new dimensions flow\n * through without a schema change.\n */\n resourceAttributes?: Record<string, string>;\n}\n\n/** Success/failure signals captured during execution */\nexport type Signal =\n | \"build_passed\"\n | \"build_failed\"\n | \"tests_passed\"\n | \"tests_failed\"\n | \"lint_passed\"\n | \"lint_failed\"\n | \"user_approved\"\n | \"user_rejected\"\n | \"task_completed\"\n | \"task_abandoned\"\n | \"runtime_error\"\n | \"timeout\";\n\nexport interface SignalEvent {\n signal: Signal;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Trace Events - Strongly Typed Discriminated Union\n// =============================================================================\n\n/** Base fields shared by all trace events */\ninterface TraceEventBase {\n timestamp: Date;\n}\n\n/** Message updated event (final model text and result metadata) */\nexport interface MessageUpdatedEvent extends TraceEventBase {\n type: \"message.updated\";\n /** Final text content */\n text?: string;\n /** Legacy alias for text */\n finalText?: string;\n /** Token usage details */\n tokenUsage?: Record<string, unknown>;\n /** Timing details */\n timing?: Record<string, unknown>;\n /** Tool invocations captured during execution */\n toolInvocations?: unknown[];\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/** Error event */\nexport interface ErrorEvent extends TraceEventBase {\n type: \"error\";\n /** Error category */\n category: \"runtime\" | \"syntax\" | \"type\" | \"network\" | \"timeout\" | \"unknown\";\n /** Error message */\n message: string;\n /** Stack trace if available */\n stack?: string;\n /** Error code if available */\n code?: string;\n /** Source of error (tool name, file, etc.) */\n source?: string;\n}\n\n/** Diagnostic severity levels */\nexport type DiagnosticSeverity = \"error\" | \"warning\" | \"info\" | \"hint\";\n\n/** Individual diagnostic message */\nexport interface Diagnostic {\n /** Severity level */\n severity: DiagnosticSeverity;\n /** Diagnostic message */\n message: string;\n /** Diagnostic code (e.g., \"TS2304\", \"E0001\") */\n code?: string | number;\n /** Source (e.g., \"typescript\", \"eslint\") */\n source?: string;\n /** Start line (0-indexed) */\n startLine: number;\n /** Start column (0-indexed) */\n startColumn: number;\n /** End line (0-indexed) */\n endLine: number;\n /** End column (0-indexed) */\n endColumn: number;\n}\n\n/** Summary of diagnostics for a file */\nexport interface DiagnosticSummary {\n errors: number;\n warnings: number;\n infos: number;\n hints: number;\n}\n\n/** Diagnostic change event - captured after file edits */\nexport interface DiagnosticEvent extends TraceEventBase {\n type: \"diagnostic\";\n /** File path */\n file: string;\n /** Language server ID */\n serverId?: string;\n /** Language (e.g., \"typescript\", \"python\") */\n language?: string;\n /** Diagnostics before the change */\n before?: Diagnostic[];\n /** Diagnostics after the change */\n after: Diagnostic[];\n /** Summary counts before */\n beforeSummary?: DiagnosticSummary;\n /** Summary counts after */\n afterSummary: DiagnosticSummary;\n /** Net change in error count (negative = improvement) */\n errorDelta: number;\n /** Diagnostics that were resolved */\n resolved?: Diagnostic[];\n /** Diagnostics that were introduced */\n introduced?: Diagnostic[];\n}\n\n/** File change event */\nexport interface FileChangeEvent extends TraceEventBase {\n type: \"file_change\";\n /** File path */\n file: string;\n /** Change type */\n changeType: \"created\" | \"modified\" | \"deleted\";\n /** Lines added */\n linesAdded?: number;\n /** Lines removed */\n linesRemoved?: number;\n}\n\n/** Build result event */\nexport interface BuildResultEvent extends TraceEventBase {\n type: \"build_result\";\n /** Build command */\n command?: string;\n /** Whether build succeeded */\n success: boolean;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error count */\n errorCount?: number;\n /** Warning count */\n warningCount?: number;\n}\n\n/** Test result event */\nexport interface TestResultEvent extends TraceEventBase {\n type: \"test_result\";\n /** Test command */\n command?: string;\n /** Whether all tests passed */\n success: boolean;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Number of tests passed */\n passed?: number;\n /** Number of tests failed */\n failed?: number;\n /** Number of tests skipped */\n skipped?: number;\n}\n\n/** Environment snapshot at trace start */\nexport interface EnvironmentEvent extends TraceEventBase {\n type: \"environment\";\n /** Runtime versions */\n versions?: Record<string, string>;\n /** Working directory */\n workingDir?: string;\n /** Platform info */\n platform?: string;\n}\n\n/** Generic event for extensibility (use sparingly) */\nexport interface CustomEvent extends TraceEventBase {\n type: \"custom\";\n /** Custom event name */\n name: string;\n /** Custom event data */\n data: Record<string, unknown>;\n}\n\n// =============================================================================\n// Batch Execution Events\n// =============================================================================\n\n/** Batch execution started event */\nexport interface BatchStartedEvent extends TraceEventBase {\n type: \"batch_started\";\n /** Unique batch execution ID */\n batchId: string;\n /** Number of tasks in the batch */\n taskCount: number;\n /** Number of backends being tested */\n backendCount: number;\n /** Total executions (tasks × backends) */\n totalExecutions: number;\n /** Scaling mode used */\n scalingMode?: \"fastest\" | \"balanced\" | \"cheapest\";\n}\n\n/** Batch execution completed event */\nexport interface BatchCompletedEvent extends TraceEventBase {\n type: \"batch_completed\";\n /** Unique batch execution ID */\n batchId: string;\n /** Number of successful task executions */\n successCount: number;\n /** Number of failed task executions */\n failureCount: number;\n /** Success rate as percentage (0-100) */\n successRate: number;\n /** Total duration in milliseconds */\n durationMs: number;\n /** Total tokens used across all executions */\n totalTokensUsed?: number;\n}\n\n/** Individual task within a batch completed */\nexport interface BatchTaskCompletedEvent extends TraceEventBase {\n type: \"batch_task_completed\";\n /** Parent batch ID */\n batchId: string;\n /** Task ID within the batch */\n taskId: string;\n /** Backend used for this execution */\n backend: string;\n /** Whether the task succeeded */\n success: boolean;\n /** Duration in milliseconds */\n durationMs: number;\n /** Attempt number (1 = first try) */\n attempt: number;\n /** Number of retries before success/failure */\n retries: number;\n /** Tokens used for this task */\n tokensUsed?: number;\n /** Error message if failed */\n error?: string;\n}\n\n/** Union of all trace event types */\nexport type TraceEvent =\n // Canonical SSE event from OpenCode (preferred)\n | MessagePartUpdatedEventWithTimestamp\n | MessageUpdatedEvent\n | ErrorEvent\n // Trace-specific events (not from SSE)\n | DiagnosticEvent\n | FileChangeEvent\n | BuildResultEvent\n | TestResultEvent\n | EnvironmentEvent\n | CustomEvent\n | BatchStartedEvent\n | BatchCompletedEvent\n | BatchTaskCompletedEvent;\n\n/** Event type discriminator */\nexport type TraceEventType = TraceEvent[\"type\"];\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isMessageUpdatedEvent(\n event: TraceEvent,\n): event is MessageUpdatedEvent {\n return event.type === \"message.updated\";\n}\n\nexport function isErrorEvent(event: TraceEvent): event is ErrorEvent {\n return event.type === \"error\";\n}\n\nexport function isDiagnosticEvent(event: TraceEvent): event is DiagnosticEvent {\n return event.type === \"diagnostic\";\n}\n\nexport function isFileChangeEvent(event: TraceEvent): event is FileChangeEvent {\n return event.type === \"file_change\";\n}\n\nexport function isBuildResultEvent(\n event: TraceEvent,\n): event is BuildResultEvent {\n return event.type === \"build_result\";\n}\n\nexport function isTestResultEvent(event: TraceEvent): event is TestResultEvent {\n return event.type === \"test_result\";\n}\n\nexport function isEnvironmentEvent(\n event: TraceEvent,\n): event is EnvironmentEvent {\n return event.type === \"environment\";\n}\n\nexport function isCustomEvent(event: TraceEvent): event is CustomEvent {\n return event.type === \"custom\";\n}\n\n// =============================================================================\n// Execution Trace\n// =============================================================================\n\n/** Execution outcome derived from signals */\nexport type Outcome = \"success\" | \"partial\" | \"failure\" | \"unknown\";\n\n/** Execution trace - complete record of an agent task */\nexport interface ExecutionTrace {\n id: string;\n scope: TraceScope;\n task: string;\n events: TraceEvent[];\n signals: SignalEvent[];\n outcome: Outcome;\n startedAt: Date;\n completedAt?: Date;\n metadata?: Record<string, unknown>;\n}\n","/**\n * Langfuse Sink\n *\n * Native Langfuse SDK integration for trace export.\n * Uses the langfuse-node SDK directly instead of going through OTEL,\n * which provides better compatibility and richer trace visualization.\n */\n\nimport type {\n ExecutionTrace,\n MessagePartUpdatedEventWithTimestamp,\n ToolPart,\n TraceEvent,\n} from \"./trace-types.js\";\nimport {\n isFilePart,\n isReasoningPart,\n isTextPart,\n isToolPart,\n} from \"./trace-types.js\";\n\n/** Langfuse sink configuration */\nexport interface LangfuseSinkConfig {\n /** Langfuse public key */\n publicKey: string;\n /** Langfuse secret key */\n secretKey: string;\n /** Langfuse host (default: https://cloud.langfuse.com) */\n baseUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n /**\n * Redaction applied to the whole trace before any of it is turned into\n * Langfuse objects (HIPAA deployments: pass a PHI deep redactor). The\n * hook is injected rather than imported so this package stays free of\n * Node-only redaction dependencies and Worker-safe.\n */\n redactTrace?: (trace: ExecutionTrace) => ExecutionTrace;\n}\n\n// Lazy-loaded Langfuse client\nlet langfuseClient: import(\"langfuse-node\").Langfuse | null = null;\nlet langfuseConfig: LangfuseSinkConfig | null = null;\n\n/**\n * Get or create the Langfuse client\n */\nasync function getLangfuseClient(\n config: LangfuseSinkConfig,\n): Promise<import(\"langfuse-node\").Langfuse | null> {\n if (langfuseClient && langfuseConfig === config) {\n return langfuseClient;\n }\n\n try {\n const { Langfuse } = await import(\"langfuse-node\");\n langfuseClient = new Langfuse({\n publicKey: config.publicKey,\n secretKey: config.secretKey,\n baseUrl: config.baseUrl || \"https://cloud.langfuse.com\",\n });\n langfuseConfig = config;\n return langfuseClient;\n } catch (err) {\n console.warn(\"[langfuse-sink] Failed to initialize Langfuse:\", err);\n return null;\n }\n}\n\ntype LangfuseTrace = ReturnType<import(\"langfuse-node\").Langfuse[\"trace\"]>;\n\nfunction exportBuildResultSpan(\n trace: LangfuseTrace,\n event: Extract<TraceEvent, { type: \"build_result\" }>,\n): void {\n trace.span({\n name: `build.${event.success ? \"success\" : \"failure\"}`,\n startTime: event.timestamp,\n endTime: event.durationMs\n ? new Date(event.timestamp.getTime() + event.durationMs)\n : undefined,\n output: event.success ? \"success\" : \"failed\",\n metadata: {\n command: event.command,\n errorCount: event.errorCount,\n warningCount: event.warningCount,\n },\n level: event.success ? undefined : \"ERROR\",\n });\n}\n\nfunction exportTestResultSpan(\n trace: LangfuseTrace,\n event: Extract<TraceEvent, { type: \"test_result\" }>,\n): void {\n trace.span({\n name: `test.${event.success ? \"success\" : \"failure\"}`,\n startTime: event.timestamp,\n endTime: event.durationMs\n ? new Date(event.timestamp.getTime() + event.durationMs)\n : undefined,\n output: event.success ? \"success\" : \"failed\",\n metadata: {\n command: event.command,\n passed: event.passed,\n failed: event.failed,\n skipped: event.skipped,\n },\n level: event.success ? undefined : \"ERROR\",\n });\n}\n\n/** Measured startup and HTTP phases become timed spans; other custom events stay events. */\nfunction exportCustomEvent(\n trace: LangfuseTrace,\n event: Extract<TraceEvent, { type: \"custom\" }>,\n): void {\n if (event.name === \"startup.phase\" || event.name === \"http.phase\") {\n const durationMs =\n typeof event.data.durationMs === \"number\" ? event.data.durationMs : 0;\n const phase =\n typeof event.data.phase === \"string\" ? event.data.phase : \"unknown\";\n trace.span({\n name: `${event.name === \"http.phase\" ? \"http\" : \"startup\"}.${phase}`,\n startTime: new Date(event.timestamp.getTime() - durationMs),\n endTime: event.timestamp,\n metadata: event.data,\n level: event.data.status === \"error\" ? \"ERROR\" : undefined,\n statusMessage:\n typeof event.data.error === \"string\" ? event.data.error : undefined,\n });\n } else {\n trace.event({\n name: `custom.${event.name}`,\n startTime: event.timestamp,\n metadata: event.data,\n });\n }\n}\n\n/**\n * Langfuse trace exporter using the native SDK.\n *\n * Creates proper Langfuse traces with spans and generations\n * for rich observability in the Langfuse dashboard.\n *\n * Note: This is a trace-level exporter (ExecutionTrace), not a\n * TelemetrySink (TelemetryEvent). Use for exporting complete traces.\n */\nexport class LangfuseSink {\n readonly name = \"langfuse\";\n private readonly config: LangfuseSinkConfig;\n\n constructor(config: LangfuseSinkConfig) {\n this.config = config;\n }\n\n /**\n * Export an execution trace to Langfuse.\n */\n async exportTrace(trace: ExecutionTrace): Promise<void> {\n const client = await getLangfuseClient(this.config);\n if (!client) return;\n\n // Redaction runs on the trace BEFORE any Langfuse object is built, so\n // no code path below can forget a content field.\n const effectiveTrace = this.config.redactTrace\n ? this.config.redactTrace(trace)\n : trace;\n\n try {\n // Create the main trace\n const langfuseTrace = client.trace({\n id: effectiveTrace.id,\n name: effectiveTrace.task,\n sessionId: effectiveTrace.scope.sessionId,\n userId: effectiveTrace.scope.userId,\n metadata: {\n outcome: effectiveTrace.outcome,\n projectRef: effectiveTrace.scope.projectRef,\n ...effectiveTrace.metadata,\n },\n tags: effectiveTrace.outcome === \"failure\" ? [\"failed\"] : undefined,\n });\n\n // Export events as spans/generations\n for (const event of effectiveTrace.events) {\n if (!event) continue;\n this.exportTraceEvent(langfuseTrace, event);\n }\n\n // Add signals as trace events\n for (const signal of effectiveTrace.signals) {\n langfuseTrace.event({\n name: `signal.${signal.signal}`,\n startTime: signal.timestamp,\n metadata: signal.metadata,\n });\n }\n\n // Update trace with completion info\n langfuseTrace.update({\n output: effectiveTrace.outcome,\n });\n\n // Flush to ensure delivery\n await client.flushAsync();\n } catch (err) {\n console.warn(\"[langfuse-sink] Failed to export trace:\", err);\n }\n }\n\n /**\n * Export a trace event as a Langfuse span or generation.\n */ private exportTraceEvent(\n trace: ReturnType<import(\"langfuse-node\").Langfuse[\"trace\"]>,\n event: TraceEvent,\n ): void {\n switch (event.type) {\n // Canonical SSE event from OpenCode - interpret based on part type\n case \"message.part.updated\": {\n const partEvent = event as MessagePartUpdatedEventWithTimestamp;\n const part = partEvent.part;\n\n if (isToolPart(part)) {\n this.exportToolPart(trace, partEvent, part);\n } else if (isTextPart(part) || isReasoningPart(part)) {\n // Text/reasoning parts become generations\n trace.generation({\n name: part.type === \"reasoning\" ? \"reasoning\" : \"text\",\n startTime: partEvent.timestamp,\n output: part.text,\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n delta: partEvent.delta,\n },\n });\n } else if (isFilePart(part)) {\n trace.event({\n name: `file.${part.mediaType || \"unknown\"}`,\n startTime: partEvent.timestamp,\n metadata: {\n partId: part.id,\n filename: part.filename,\n mediaType: part.mediaType,\n url: part.url,\n },\n });\n }\n break;\n }\n\n case \"message.updated\":\n trace.event({\n name: \"message.updated\",\n startTime: event.timestamp,\n metadata: {\n text: event.text ?? event.finalText,\n finalText: event.finalText,\n tokenUsage: event.tokenUsage,\n timing: event.timing,\n toolInvocations: event.toolInvocations,\n metadata: event.metadata,\n },\n });\n break;\n\n case \"error\":\n trace.event({\n name: `error.${event.category}`,\n startTime: event.timestamp,\n level: \"ERROR\",\n metadata: {\n message: event.message,\n code: event.code,\n source: event.source,\n },\n });\n break;\n\n case \"file_change\":\n trace.event({\n name: `file.${event.changeType}`,\n startTime: event.timestamp,\n metadata: {\n file: event.file,\n linesAdded: event.linesAdded,\n linesRemoved: event.linesRemoved,\n },\n });\n break;\n\n case \"build_result\":\n exportBuildResultSpan(trace, event);\n break;\n\n case \"test_result\":\n exportTestResultSpan(trace, event);\n break;\n\n case \"diagnostic\":\n trace.event({\n name: `diagnostic.${event.language || \"unknown\"}`,\n startTime: event.timestamp,\n metadata: {\n file: event.file,\n errorDelta: event.errorDelta,\n errorsAfter: event.afterSummary.errors,\n warningsAfter: event.afterSummary.warnings,\n },\n });\n break;\n\n case \"environment\":\n trace.event({\n name: \"environment.snapshot\",\n startTime: event.timestamp,\n metadata: {\n workingDir: event.workingDir,\n platform: event.platform,\n },\n });\n break;\n\n case \"custom\":\n exportCustomEvent(trace, event);\n break;\n }\n }\n\n /**\n * Export a tool part from message.part.updated event.\n * Tool parts have state progression: pending → running → completed/error\n */\n private exportToolPart(\n trace: ReturnType<import(\"langfuse-node\").Langfuse[\"trace\"]>,\n event: MessagePartUpdatedEventWithTimestamp,\n part: ToolPart,\n ): void {\n const status = part.state.status;\n const toolName = part.tool;\n\n if (status === \"running\") {\n // Tool started - create span with input\n trace.span({\n name: `tool.${toolName}`,\n startTime: event.timestamp,\n input: part.state.input ?? { callID: part.callID },\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n status,\n },\n });\n } else if (status === \"completed\") {\n // Tool finished - create span with output\n const endTime = part.state.time?.end\n ? new Date(part.state.time.end)\n : event.timestamp;\n const startTime = part.state.time?.start\n ? new Date(part.state.time.start)\n : event.timestamp;\n\n trace.span({\n name: `tool.${toolName}.result`,\n startTime,\n endTime,\n input: part.state.input,\n output: part.state.output ?? \"success\",\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n callID: part.callID,\n success: true,\n },\n });\n } else if (status === \"failed\" || status === \"error\") {\n const endTime = part.state.time?.end\n ? new Date(part.state.time.end)\n : event.timestamp;\n const startTime = part.state.time?.start\n ? new Date(part.state.time.start)\n : event.timestamp;\n\n trace.span({\n name: `tool.${toolName}.result`,\n startTime,\n endTime,\n input: part.state.input,\n output: part.state.output ?? part.state.error,\n metadata: {\n partId: part.id,\n sessionID: part.sessionID,\n messageID: part.messageID,\n callID: part.callID,\n success: false,\n },\n level: \"ERROR\",\n statusMessage: part.state.error,\n });\n }\n }\n\n async flush(): Promise<void> {\n const client = await getLangfuseClient(this.config);\n if (client) {\n await client.flushAsync();\n }\n }\n\n async close(): Promise<void> {\n const client = await getLangfuseClient(this.config);\n if (client) {\n await client.shutdownAsync();\n langfuseClient = null;\n }\n }\n}\n\n/**\n * Create a Langfuse sink from environment variables.\n */\nexport function createLangfuseSinkFromEnv(\n options?: Pick<LangfuseSinkConfig, \"redactTrace\">,\n): LangfuseSink | null {\n const publicKey = process.env.LANGFUSE_PUBLIC_KEY;\n const secretKey = process.env.LANGFUSE_SECRET_KEY;\n\n if (!publicKey || !secretKey) {\n return null;\n }\n\n return new LangfuseSink({\n publicKey,\n secretKey,\n baseUrl: process.env.LANGFUSE_HOST || \"https://cloud.langfuse.com\",\n debug: process.env.LANGFUSE_DEBUG === \"true\",\n ...(options?.redactTrace ? { redactTrace: options.redactTrace } : {}),\n });\n}\n","/**\n * Global OpenTelemetry tracer provider for the in-container agent loop.\n *\n * Registers a Node TracerProvider + batching OTLP/HTTP exporter so the GLOBAL\n * tracer (`@opentelemetry/api` `trace.getTracer`, used by the OTel sink) ships\n * spans to the configured collector (Tangle Intelligence) instead of being a\n * no-op. Endpoint + headers come from the standard OTEL env the host threads in\n * (`OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS`); per-session\n * partner/project/user resource attributes are stamped on spans by the sink,\n * not here.\n *\n * Opt-in + best-effort:\n * - a no-op unless `TELEMETRY_ENABLED=true` AND an endpoint is set;\n * - any SDK import / construction failure degrades to disabled, never crashes\n * the sidecar (telemetry must never take down the agent);\n * - idempotent — a second `initOtelProvider` returns the already-active result.\n */\n\nexport interface InitOtelProviderResult {\n active: boolean;\n reason?: string;\n}\n\ninterface Shutdownable {\n forceFlush(): Promise<void>;\n shutdown(): Promise<void>;\n}\n\nlet provider: Shutdownable | null = null;\n\n/** Parse `OTEL_EXPORTER_OTLP_HEADERS` (\"k=v,k2=v2\") into a header map. */\nfunction parseHeaders(raw: string | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!raw) return out;\n for (const pair of raw.split(\",\")) {\n const eq = pair.indexOf(\"=\");\n if (eq <= 0) continue;\n const key = pair.slice(0, eq).trim();\n const value = pair.slice(eq + 1).trim();\n if (key) out[key] = value;\n }\n return out;\n}\n\nexport async function initOtelProvider(\n serviceName: string,\n): Promise<InitOtelProviderResult> {\n if (provider) return { active: true };\n\n if (process.env.TELEMETRY_ENABLED !== \"true\") {\n return { active: false, reason: \"TELEMETRY_ENABLED!=true\" };\n }\n const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n if (!endpoint) {\n return { active: false, reason: \"OTEL_EXPORTER_OTLP_ENDPOINT unset\" };\n }\n\n try {\n const [\n { NodeTracerProvider, BatchSpanProcessor },\n { OTLPTraceExporter },\n { resourceFromAttributes },\n { ATTR_SERVICE_NAME },\n ] = await Promise.all([\n import(\"@opentelemetry/sdk-trace-node\"),\n import(\"@opentelemetry/exporter-trace-otlp-http\"),\n import(\"@opentelemetry/resources\"),\n import(\"@opentelemetry/semantic-conventions\"),\n ]);\n\n const exporter = new OTLPTraceExporter({\n url: endpoint,\n headers: parseHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS),\n });\n\n const tracerProvider = new NodeTracerProvider({\n resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: serviceName }),\n spanProcessors: [new BatchSpanProcessor(exporter)],\n });\n // Registers as the global provider so `api.trace.getTracer(...)` (the sink)\n // returns real tracers instead of the default no-op.\n tracerProvider.register();\n provider = tracerProvider;\n\n return { active: true };\n } catch (error) {\n return {\n active: false,\n reason: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport async function shutdownOtelProvider(): Promise<void> {\n if (!provider) return;\n const current = provider;\n provider = null;\n try {\n await current.forceFlush();\n } catch {\n // best-effort flush\n }\n await current.shutdown();\n}\n","/**\n * OpenTelemetry Sink\n *\n * Exports telemetry data to OpenTelemetry-compatible backends including\n * Langfuse, Jaeger, Honeycomb, and other OTLP collectors.\n *\n * IMPORTANT: This sink uses the GLOBAL tracer from @opentelemetry/api.\n * The OTEL SDK must be initialized separately (e.g., via NodeSDK with\n * LangfuseSpanProcessor or OTLPTraceExporter) before using this sink.\n *\n * This sink converts ExecutionTrace data into OTEL spans using the\n * global tracer, which ensures spans flow through whatever processor\n * was configured at SDK initialization.\n */\n\nimport {\n GEN_AI_CONVERSATION_ID,\n GEN_AI_OPERATION_NAME,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n} from \"@tangle-network/agent-core\";\nimport {\n type ExecutionTrace,\n isFilePart,\n isReasoningPart,\n isTextPart,\n isToolPart,\n type TraceEvent,\n} from \"./trace-types.js\";\nimport type { TelemetryEvent, TelemetrySink } from \"./types.js\";\n\n/** OTEL span attribute value. */\ntype SpanAttrValue = string | number | boolean;\n\n/**\n * GenAI semantic-convention keys promoted from a `message.updated` event's\n * metadata bag to DISCRETE span attributes. The intelligence ingest derives\n * model/token/cost and conversation linkage by reading these exact keys off the\n * flat span attribute bag (`parseGenAiAttribution` / `parseConversationLinkage`\n * in the intelligence API); leaving them inside the serialized `message.metadata`\n * blob would attribute every auto-instrumented LLM call as model/tokens/cost\n * unknown. Promotion is unconditional (not gated on `includePayloads`): these\n * are attribution signal, not prompt/completion content. `genAiUsageAttributes`\n * already guarantees the writer never emits a fabricated zero, so a key absent\n * here stays absent on the span — \"cost not computed\", never \"free\".\n */\nconst GEN_AI_PROMOTED_KEYS: readonly string[] = Object.freeze([\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_OPERATION_NAME,\n GEN_AI_CONVERSATION_ID,\n]);\n\n/**\n * Build the parent-span attributes for a trace, with a deliberate precedence:\n * partner-supplied `resourceAttributes` are the LOWEST layer, so the trusted\n * identity attributes (agent.trace.id, session.id, user.id) and metadata always\n * override a colliding key. A partner cannot spoof span identity by passing a\n * `resourceAttributes` key like `session.id`.\n */\nexport function buildTraceSpanAttributes(\n trace: ExecutionTrace,\n flattenedMetadata?: Record<string, SpanAttrValue>,\n): Record<string, SpanAttrValue> {\n return {\n // Lowest precedence: partner/project/domain tags (tangle.*). Filtered by\n // being spread first — everything below wins on a key collision.\n ...((trace.scope.resourceAttributes ?? {}) as Record<\n string,\n SpanAttrValue\n >),\n \"agent.trace.id\": trace.id,\n \"agent.task\": trace.task,\n \"agent.outcome\": trace.outcome,\n // Langfuse-specific attributes for proper mapping\n \"langfuse.trace.id\": trace.id,\n \"langfuse.trace.name\": trace.task,\n ...(trace.scope.projectRef && {\n \"langfuse.project\": trace.scope.projectRef,\n }),\n ...(trace.scope.sessionId && {\n \"langfuse.session.id\": trace.scope.sessionId,\n \"session.id\": trace.scope.sessionId,\n }),\n ...(trace.scope.userId && {\n \"langfuse.user.id\": trace.scope.userId,\n \"user.id\": trace.scope.userId,\n }),\n ...(flattenedMetadata ?? {}),\n };\n}\n\n/** Configuration for the OTEL sink */\nexport interface OtelSinkConfig {\n /** Service name for the tracer */\n serviceName?: string;\n /** Include raw input/output in span attributes (may contain sensitive data) */\n includePayloads?: boolean;\n}\n\n// Lazy-loaded OTEL API types\nlet otelApi: typeof import(\"@opentelemetry/api\") | null = null;\n\n/**\n * Load the OTEL API dynamically\n */\nasync function getOtelApi() {\n if (!otelApi) {\n try {\n otelApi = await import(\"@opentelemetry/api\");\n } catch {\n return null;\n }\n }\n return otelApi;\n}\n\n/**\n * OpenTelemetry sink — exports via whatever OTEL SDK config was set at\n * application startup (Langfuse, Jaeger, any OTLP backend).\n */\ntype OtelEventAttributes = Record<\n string,\n string | number | boolean | undefined\n>;\n\nfunction addPartUpdateAttributes(\n attrs: OtelEventAttributes,\n event: Extract<TraceEvent, { type: \"message.part.updated\" }>,\n includePayloads: boolean | undefined,\n): void {\n attrs[\"message.part.id\"] = event.part.id;\n attrs[\"message.part.type\"] = event.part.type;\n\n if (isToolPart(event.part)) {\n attrs[\"tool.name\"] = event.part.tool;\n const status = event.part.state.status;\n attrs[\"tool.status\"] = status;\n if (includePayloads && event.part.state.input) {\n attrs[\"tool.input\"] = JSON.stringify(event.part.state.input).slice(\n 0,\n 4096,\n );\n }\n if (\n includePayloads &&\n status === \"completed\" &&\n event.part.state.output !== undefined\n ) {\n attrs[\"tool.output\"] = JSON.stringify(event.part.state.output).slice(\n 0,\n 4096,\n );\n }\n if (\n includePayloads &&\n (status === \"error\" || status === \"failed\") &&\n typeof event.part.state.error === \"string\"\n ) {\n attrs[\"tool.error\"] = event.part.state.error.slice(0, 4096);\n }\n } else if (isTextPart(event.part) || isReasoningPart(event.part)) {\n attrs[\"message.part.text_length\"] = event.part.text.length;\n if (includePayloads) {\n attrs[\"message.part.text\"] = event.part.text.slice(0, 4096);\n }\n } else if (isFilePart(event.part)) {\n attrs[\"file.name\"] = event.part.filename;\n if (event.part.mediaType) attrs[\"file.media_type\"] = event.part.mediaType;\n } else {\n attrs[\"subtask.id\"] = event.part.id;\n attrs[\"subtask.session_id\"] = event.part.sessionID;\n }\n}\n\nfunction addMessageUpdateAttributes(\n attrs: OtelEventAttributes,\n event: Extract<TraceEvent, { type: \"message.updated\" }>,\n includePayloads: boolean | undefined,\n): void {\n const text = event.text ?? event.finalText;\n if (typeof text === \"string\") {\n attrs[\"message.text_length\"] = text.length;\n if (includePayloads) {\n attrs[\"message.text\"] = text.slice(0, 4096);\n }\n }\n if (includePayloads && event.tokenUsage !== undefined) {\n attrs[\"message.token_usage\"] = JSON.stringify(event.tokenUsage).slice(\n 0,\n 4096,\n );\n }\n if (includePayloads && event.timing !== undefined) {\n attrs[\"message.timing\"] = JSON.stringify(event.timing).slice(0, 4096);\n }\n if (includePayloads && event.toolInvocations !== undefined) {\n attrs[\"message.tool_invocations\"] = JSON.stringify(\n event.toolInvocations,\n ).slice(0, 4096);\n }\n if (event.metadata) {\n for (const key of GEN_AI_PROMOTED_KEYS) {\n const value = event.metadata[key];\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n attrs[key] = value;\n }\n }\n }\n if (includePayloads && event.metadata !== undefined) {\n attrs[\"message.metadata\"] = JSON.stringify(event.metadata).slice(0, 4096);\n }\n}\n\nfunction addCustomEventAttributes(\n attrs: OtelEventAttributes,\n event: Extract<TraceEvent, { type: \"custom\" }>,\n): void {\n attrs[\"custom.name\"] = event.name;\n if (event.name === \"startup.phase\") {\n attrs[\"startup.id\"] =\n typeof event.data.startupId === \"string\"\n ? event.data.startupId\n : undefined;\n attrs[\"startup.phase\"] =\n typeof event.data.phase === \"string\" ? event.data.phase : undefined;\n attrs[\"startup.service\"] =\n typeof event.data.service === \"string\" ? event.data.service : undefined;\n attrs[\"startup.status\"] =\n typeof event.data.status === \"string\" ? event.data.status : undefined;\n }\n for (const [key, value] of Object.entries(event.data)) {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n attrs[`custom.data.${key}`] = value;\n }\n }\n}\n\nexport class OtelTelemetrySink implements TelemetrySink {\n readonly name = \"otel\";\n private readonly config: OtelSinkConfig;\n\n constructor(config: OtelSinkConfig = {}) {\n this.config = {\n serviceName: config.serviceName ?? \"agent-sdk\",\n includePayloads: config.includePayloads ?? false,\n };\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n const api = await getOtelApi();\n if (!api) return;\n\n // biome-ignore lint/style/noNonNullAssertion: serviceName is required in OtelSinkConfig\n const tracer = api.trace.getTracer(this.config.serviceName!, \"1.0.0\");\n\n for (const event of events) {\n // `agent_execution` events carry the full ExecutionTrace under\n // `data.trace` (see TraceCollector.flush). Export it as a proper span\n // tree rather than a single flat telemetry span — this is the path that\n // ships tagged agent traces (partner/project/user) to the OTLP backend.\n if (\n event.type === \"agent_execution\" &&\n this.isExecutionTrace(event.data.trace)\n ) {\n await this.exportTrace(event.data.trace);\n continue;\n }\n\n const span = tracer.startSpan(`telemetry.${event.type}.${event.name}`, {\n attributes: {\n \"telemetry.event.type\": event.type,\n \"telemetry.event.name\": event.name,\n },\n startTime: event.timestamp,\n });\n\n // Add event data as attributes\n if (event.data && typeof event.data === \"object\") {\n for (const [key, value] of Object.entries(event.data)) {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n span.setAttribute(`telemetry.data.${key}`, value);\n }\n }\n }\n\n span.setStatus({ code: api.SpanStatusCode.OK });\n span.end();\n }\n }\n\n /**\n * Export an execution trace as OTEL spans.\n *\n * Creates a parent span for the trace and child spans for each event.\n * Uses the global tracer, so spans flow through the configured processor.\n */\n async exportTrace(trace: ExecutionTrace): Promise<void> {\n const api = await getOtelApi();\n if (!api) return;\n\n // biome-ignore lint/style/noNonNullAssertion: serviceName is required in OtelSinkConfig\n const tracer = api.trace.getTracer(this.config.serviceName!, \"1.0.0\");\n\n // Create parent span for the entire trace\n const traceSpan = tracer.startSpan(\"agent.task\", {\n attributes: buildTraceSpanAttributes(\n trace,\n trace.metadata ? this.flattenMetadata(trace.metadata) : undefined,\n ),\n startTime: trace.startedAt,\n });\n\n // Export each trace event as child spans using the parent context\n const parentContext = api.trace.setSpan(api.context.active(), traceSpan);\n\n for (const event of trace.events) {\n if (!event?.type) continue;\n api.context.with(parentContext, () => {\n this.exportTraceEvent(tracer, api, event);\n });\n }\n\n // Export signals as events on the parent span\n for (const signal of trace.signals) {\n traceSpan.addEvent(`signal.${signal.signal}`, {}, signal.timestamp);\n }\n\n // Set final status based on outcome\n if (trace.outcome === \"failure\") {\n traceSpan.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: \"Task failed\",\n });\n } else {\n traceSpan.setStatus({ code: api.SpanStatusCode.OK });\n }\n\n traceSpan.end(trace.completedAt || new Date());\n }\n\n /**\n * Export a single trace event as an OTEL span.\n */\n private exportTraceEvent(\n tracer: ReturnType<typeof import(\"@opentelemetry/api\").trace.getTracer>,\n api: typeof import(\"@opentelemetry/api\"),\n event: TraceEvent,\n ): void {\n const spanName = this.getSpanName(event);\n const attributes = this.getEventAttributes(event);\n const startTime = this.getEventStartTime(event);\n const endTime = this.getEventEndTime(event);\n\n const span = tracer.startSpan(spanName, {\n attributes,\n startTime,\n });\n\n // Handle errors\n if (event.type === \"error\") {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: event.message,\n });\n span.recordException(new Error(event.message));\n } else if (\n event.type === \"message.part.updated\" &&\n isToolPart(event.part)\n ) {\n const status = event.part.state.status;\n if (status === \"failed\" || status === \"error\") {\n const err =\n typeof event.part.state.error === \"string\"\n ? event.part.state.error\n : \"Tool execution failed\";\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: err,\n });\n span.recordException(new Error(err));\n } else {\n span.setStatus({ code: api.SpanStatusCode.OK });\n }\n } else if (event.type === \"build_result\" && !event.success) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: \"Build failed\",\n });\n } else if (event.type === \"test_result\" && !event.success) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: \"Tests failed\",\n });\n } else if (\n event.type === \"custom\" &&\n event.name === \"startup.phase\" &&\n event.data.status === \"error\"\n ) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message:\n typeof event.data.error === \"string\"\n ? event.data.error\n : \"Startup phase failed\",\n });\n } else {\n span.setStatus({ code: api.SpanStatusCode.OK });\n }\n\n span.end(endTime);\n }\n\n private getEventStartTime(event: TraceEvent): Date {\n if (event.type === \"custom\" && event.name === \"startup.phase\") {\n const durationMs = this.getStartupPhaseDurationMs(event);\n if (typeof durationMs === \"number\") {\n return new Date(event.timestamp.getTime() - durationMs);\n }\n }\n\n return event.timestamp;\n }\n\n private getEventEndTime(event: TraceEvent): Date {\n if (event.type === \"custom\" && event.name === \"startup.phase\") {\n return event.timestamp;\n }\n\n if (\"durationMs\" in event && typeof event.durationMs === \"number\") {\n return new Date(event.timestamp.getTime() + event.durationMs);\n }\n\n return event.timestamp;\n }\n\n private getStartupPhaseDurationMs(\n event: Extract<TraceEvent, { type: \"custom\" }>,\n ): number | undefined {\n return typeof event.data.durationMs === \"number\"\n ? event.data.durationMs\n : undefined;\n }\n\n /**\n * Get span name for a trace event.\n */\n private getSpanName(event: TraceEvent): string {\n switch (event.type) {\n case \"message.part.updated\":\n if (isToolPart(event.part)) {\n return `tool.${event.part.tool}.${event.part.state.status}`;\n }\n if (isReasoningPart(event.part)) return \"llm.reasoning\";\n if (isTextPart(event.part)) return \"llm.text\";\n return \"message.file\";\n case \"message.updated\":\n return \"message.updated\";\n case \"error\":\n return `error.${event.category}`;\n case \"diagnostic\":\n return `diagnostic.${event.language || \"unknown\"}`;\n case \"file_change\":\n return `file.${event.changeType}`;\n case \"build_result\":\n return `build.${event.success ? \"success\" : \"failure\"}`;\n case \"test_result\":\n return `test.${event.success ? \"success\" : \"failure\"}`;\n case \"environment\":\n return \"environment.snapshot\";\n case \"custom\":\n if (event.name === \"startup.phase\") {\n const phase =\n typeof event.data.phase === \"string\" ? event.data.phase : \"unknown\";\n return `startup.${phase}`;\n }\n return `custom.${event.name}`;\n default:\n return \"unknown\";\n }\n }\n\n /**\n * Get OTEL attributes for a trace event.\n */\n private getEventAttributes(\n event: TraceEvent,\n ): Record<string, string | number | boolean | undefined> {\n const attrs: Record<string, string | number | boolean | undefined> = {\n \"event.type\": event.type,\n };\n\n switch (event.type) {\n case \"message.part.updated\":\n addPartUpdateAttributes(attrs, event, this.config.includePayloads);\n break;\n\n case \"message.updated\":\n addMessageUpdateAttributes(attrs, event, this.config.includePayloads);\n break;\n\n case \"error\":\n attrs[\"error.category\"] = event.category;\n attrs[\"error.message\"] = event.message;\n if (event.code) attrs[\"error.code\"] = event.code;\n if (event.source) attrs[\"error.source\"] = event.source;\n break;\n\n case \"diagnostic\":\n attrs[\"diagnostic.file\"] = event.file;\n if (event.language) attrs[\"diagnostic.language\"] = event.language;\n attrs[\"diagnostic.error_delta\"] = event.errorDelta;\n attrs[\"diagnostic.errors_after\"] = event.afterSummary.errors;\n attrs[\"diagnostic.warnings_after\"] = event.afterSummary.warnings;\n break;\n\n case \"file_change\":\n attrs[\"file.path\"] = event.file;\n attrs[\"file.change_type\"] = event.changeType;\n if (event.linesAdded) attrs[\"file.lines_added\"] = event.linesAdded;\n if (event.linesRemoved)\n attrs[\"file.lines_removed\"] = event.linesRemoved;\n break;\n\n case \"build_result\":\n attrs[\"build.success\"] = event.success;\n if (event.command) attrs[\"build.command\"] = event.command;\n if (event.durationMs) attrs[\"build.duration_ms\"] = event.durationMs;\n if (event.errorCount) attrs[\"build.error_count\"] = event.errorCount;\n if (event.warningCount)\n attrs[\"build.warning_count\"] = event.warningCount;\n break;\n\n case \"test_result\":\n attrs[\"test.success\"] = event.success;\n if (event.command) attrs[\"test.command\"] = event.command;\n if (event.durationMs) attrs[\"test.duration_ms\"] = event.durationMs;\n if (event.passed) attrs[\"test.passed\"] = event.passed;\n if (event.failed) attrs[\"test.failed\"] = event.failed;\n if (event.skipped) attrs[\"test.skipped\"] = event.skipped;\n break;\n\n case \"environment\":\n if (event.workingDir) attrs[\"env.working_dir\"] = event.workingDir;\n if (event.platform) attrs[\"env.platform\"] = event.platform;\n break;\n\n case \"custom\":\n attrs[\"custom.name\"] = event.name;\n addCustomEventAttributes(attrs, event);\n break;\n }\n\n return attrs;\n }\n\n /**\n * Flatten metadata object into span attributes\n */\n private flattenMetadata(\n metadata: Record<string, unknown>,\n prefix = \"metadata\",\n ): Record<string, string | number | boolean> {\n const attrs: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n attrs[`${prefix}.${key}`] = value;\n }\n }\n return attrs;\n }\n\n /** Narrow an opaque telemetry `data.trace` to an ExecutionTrace. */\n private isExecutionTrace(value: unknown): value is ExecutionTrace {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"scope\" in value &&\n \"events\" in value &&\n Array.isArray((value as { events: unknown }).events)\n );\n }\n\n async flush(): Promise<void> {\n // Global tracer handles flushing via the SDK\n }\n\n async close(): Promise<void> {\n // Global tracer handles shutdown via the SDK\n }\n}\n\n/**\n * Create an OTEL sink that uses the global tracer.\n *\n * The OTEL SDK must be initialized separately before using this sink.\n */\nexport function createOtelSink(config?: OtelSinkConfig): OtelTelemetrySink {\n return new OtelTelemetrySink(config);\n}\n\n/**\n * Create an OTEL sink from environment variables.\n *\n * Returns a sink that uses the global tracer (which should be initialized\n * separately via NodeSDK with LangfuseSpanProcessor or OTLPTraceExporter).\n */\nexport function createOtelSinkFromEnv(): OtelTelemetrySink | null {\n const enabled = process.env.TELEMETRY_ENABLED === \"true\";\n const hasLangfuse =\n process.env.LANGFUSE_PUBLIC_KEY && process.env.LANGFUSE_SECRET_KEY;\n const hasOtlp = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n\n if (!enabled || (!hasLangfuse && !hasOtlp)) {\n return null;\n }\n\n return new OtelTelemetrySink({\n serviceName: process.env.OTEL_SERVICE_NAME || \"orchestrator\",\n includePayloads: process.env.OTEL_INCLUDE_PAYLOADS === \"true\",\n });\n}\n","/**\n * Telemetry Sinks\n *\n * Output destinations for telemetry data including\n * HTTP endpoints and fan-out to several sinks.\n */\n\nimport type { TelemetryEvent, TelemetrySink } from \"./types.js\";\n\n// HTTP sink for sending telemetry to a remote endpoint\nexport class HttpTelemetrySink implements TelemetrySink {\n readonly name = \"http\";\n private readonly endpoint: string;\n private readonly headers: Record<string, string>;\n private readonly fetchFn: typeof fetch;\n private readonly timeout: number;\n private pendingRequests: Promise<void>[] = [];\n\n constructor(config: {\n endpoint: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n timeout?: number;\n }) {\n this.endpoint = config.endpoint;\n this.headers = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n this.timeout = config.timeout ?? 30000;\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n const request = this.fetchFn(this.endpoint, {\n method: \"POST\",\n headers: this.headers,\n body: JSON.stringify({ events }),\n signal: AbortSignal.timeout(this.timeout),\n }).then((res) => {\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}: ${res.statusText}`);\n }\n });\n\n this.pendingRequests.push(request);\n\n try {\n await request;\n } finally {\n this.pendingRequests = this.pendingRequests.filter((r) => r !== request);\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(this.pendingRequests);\n }\n\n async close(): Promise<void> {\n await this.flush();\n }\n}\n\n// Multi-sink that sends to multiple destinations\nexport class MultiTelemetrySink implements TelemetrySink {\n readonly name = \"multi\";\n private readonly sinks: TelemetrySink[];\n\n constructor(sinks: TelemetrySink[]) {\n this.sinks = sinks;\n }\n\n async send(events: TelemetryEvent[]): Promise<void> {\n await Promise.all(this.sinks.map((sink) => sink.send(events)));\n }\n\n async flush(): Promise<void> {\n await Promise.all(this.sinks.map((sink) => sink.flush()));\n }\n\n async close(): Promise<void> {\n await Promise.all(this.sinks.map((sink) => sink.close()));\n }\n}\n\n// Factory functions\nexport function createHttpSink(config: {\n endpoint: string;\n headers?: Record<string, string>;\n fetch?: typeof fetch;\n timeout?: number;\n}): HttpTelemetrySink {\n return new HttpTelemetrySink(config);\n}\n","/**\n * SSE Event Parser\n *\n * Converts SSE stream events to typed TraceEvents.\n * Used by both orchestrator and simulation to ensure consistent event capture.\n *\n * message.part.updated events are passed through directly without transformation.\n * This preserves full fidelity to what OpenCode outputs.\n */\n\nimport {\n parseSSEData as coreParseSSEData,\n type Part,\n type SSEEventData,\n} from \"@tangle-network/agent-core\";\nimport type {\n CustomEvent,\n ErrorEvent,\n MessagePartUpdatedEventWithTimestamp,\n MessageUpdatedEvent,\n Signal,\n SignalEvent,\n ToolPart,\n ToolState,\n TraceEvent,\n} from \"./trace-types.js\";\n\n// Re-export from sdk-core for backwards compatibility\nexport type { SSEEventData } from \"@tangle-network/agent-core\";\nexport const parseSSEData = coreParseSSEData;\n\n/** Valid signals from SSE status events */\nconst VALID_SIGNALS: Signal[] = [\n \"build_passed\",\n \"build_failed\",\n \"tests_passed\",\n \"tests_failed\",\n \"lint_passed\",\n \"lint_failed\",\n \"user_approved\",\n \"user_rejected\",\n \"task_completed\",\n \"task_abandoned\",\n \"runtime_error\",\n \"timeout\",\n];\n\n/**\n * Provider event shapes that carry a tool-invocation payload either at\n * the top level or under one of the well-known wrappers. Recognized here\n * (and not in the consumer) so trace events look identical regardless of\n * which provider emitted the call.\n */\nconst TOOL_INVOCATION_TYPES = new Set([\n \"tool-invocation\",\n `tool_${\"call\"}`,\n \"computer-use\",\n \"computer_call\",\n]);\n\n/**\n * The ToolState a raw invocation reports. OpenCode-shaped payloads nest it\n * under `state`; flat provider shapes put its fields at the top level.\n */\nfunction rawToolInvocationState(source: Record<string, unknown>): ToolState {\n const stateObj =\n (source.state as Record<string, unknown> | undefined) ?? undefined;\n const input = (source.args ??\n source.arguments ??\n source.input ??\n stateObj?.input ??\n {}) as Record<string, unknown> | undefined;\n // OpenCode-shaped state nests `output` under `state`; flat provider\n // shapes put it at the top level. Check both.\n const output = (source.result ?? source.output ?? stateObj?.output) as\n | unknown\n | undefined;\n const errorMsg =\n typeof source.error === \"string\"\n ? (source.error as string)\n : typeof stateObj?.error === \"string\"\n ? (stateObj.error as string)\n : undefined;\n const stateStatus =\n typeof stateObj?.status === \"string\"\n ? (stateObj.status as string)\n : undefined;\n const explicitStatus =\n typeof source.status === \"string\" ? (source.status as string) : undefined;\n const status =\n stateStatus ??\n explicitStatus ??\n (output !== undefined ? \"completed\" : \"running\");\n\n let toolState: ToolState;\n switch (status) {\n case \"completed\":\n toolState = {\n status: \"completed\",\n input: (input ?? {}) as Record<string, unknown>,\n // ToolStateCompleted.output is `unknown` (required, not optional).\n // Some providers emit `state: {status: \"completed\"}` for side-\n // effect-only tool calls (writes, notifications) without a\n // return value. Coerce undefined → null so the field is always\n // present on the wire (JSON.stringify drops `undefined` keys\n // entirely), and so consumers can rely on `state.output` being\n // defined whenever `state.status === \"completed\"`.\n output: output ?? null,\n };\n break;\n case \"queued\":\n // Some providers report \"queued\" before \"pending\"; treat both\n // as pending in our ToolState (which doesn't have a separate\n // queued variant). The call-site filter then drops both.\n case \"pending\":\n toolState = {\n status: \"pending\",\n input: (input ?? {}) as Record<string, unknown>,\n };\n break;\n case \"running\":\n case \"in_progress\":\n toolState = {\n status: \"running\",\n input: (input ?? {}) as Record<string, unknown>,\n };\n break;\n case \"error\":\n case \"failed\":\n toolState = {\n status,\n input: (input ?? {}) as Record<string, unknown>,\n output,\n error: errorMsg,\n };\n break;\n default:\n // Unknown status — surface as running so the consumer at least\n // gets the call shape; downstream UIs can rely on\n // running/completed parts arriving for the same callId.\n toolState = {\n status: \"running\",\n input: (input ?? {}) as Record<string, unknown>,\n };\n }\n return toolState;\n}\n\n/**\n * Best-effort: lift a raw tool-invocation event into a canonical\n * `message.part.updated` event with a `ToolPart`. Returns null for\n * payloads we cannot recognize, which lets the caller fall through to\n * a `custom` trace event rather than silently misclassifying.\n *\n * Wire contract — what shapes are expected here:\n *\n * This normalizer runs at the trace-event boundary, AFTER provider\n * adapters have done their own normalization. Adapters\n * (sdk-provider-opencode, sdk-provider-amp, sdk-provider-claude-code,\n * etc.) translate provider-native events into our internal\n * AgentStreamEvent shape — typically wrapping tool invocations\n * under `toolInvocation`/`tool_invocation`/`computerUse`/\n * `computer_use`, with `type` set to one of `TOOL_INVOCATION_TYPES`.\n *\n * Provider-native shapes that adapters are expected to unwrap:\n *\n * OpenAI Responses / Chat Completions:\n * `{id, type: \"function\", function: {name, arguments}}` →\n * adapter wraps into an internal tool-invocation event with `toolInvocation: {\n * toolCallId: id, toolName: function.name, args: function.arguments}}`\n *\n * Anthropic tool_use blocks:\n * `{type: \"tool_use\", id, name, input}` →\n * adapter wraps into an internal tool-invocation event with `toolInvocation`.\n *\n * The flat-with-`id` fallback (`source.id` in the callId chain) is\n * a defensive safety net for cases where an adapter forwards the\n * provider's flat shape verbatim. It is NOT a substitute for\n * adapter-side normalization — the literal OpenAI\n * `{type: \"function\", function: {...}}` wrapper is NOT recognized\n * here because `\"function\"` is intentionally not in\n * TOOL_INVOCATION_TYPES (the word collides with too many\n * non-tool-call uses of `function` as a top-level key).\n */\nfunction normalizeRawToolInvocation(\n event: SSEEventData,\n timestamp: Date,\n): MessagePartUpdatedEventWithTimestamp | null {\n const top = event as Record<string, unknown>;\n const wrapped = (top.toolInvocation ??\n top.tool_invocation ??\n top.computerUse ??\n top.computer_use) as Record<string, unknown> | undefined;\n const innerType = typeof top.type === \"string\" ? top.type : undefined;\n const sourceType =\n typeof top.event === \"object\" && top.event !== null\n ? ((top.event as Record<string, unknown>).type as string | undefined)\n : undefined;\n const isToolType =\n (innerType && TOOL_INVOCATION_TYPES.has(innerType)) ||\n (sourceType && TOOL_INVOCATION_TYPES.has(sourceType));\n if (!wrapped && !isToolType) {\n return null;\n }\n const source = (wrapped ?? top) as Record<string, unknown>;\n const isComputerUse =\n innerType === \"computer-use\" ||\n innerType === \"computer_call\" ||\n sourceType === \"computer-use\" ||\n sourceType === \"computer_call\";\n\n const callId = String(\n source.toolCallId ??\n source.tool_call_id ??\n source.callId ??\n source.callID ??\n source.id ??\n \"\",\n );\n const baseName = String(\n source.toolName ?? source.tool_name ?? source.name ?? \"\",\n );\n const toolName = isComputerUse\n ? `computer-use:${\n ((source.action as { type?: string } | undefined)?.type as string) ||\n \"action\"\n }`\n : baseName;\n if (!callId || !toolName) {\n return null;\n }\n\n const toolState = rawToolInvocationState(source);\n\n // PartBase contract on a SYNTHESIZED ToolPart:\n //\n // - `id` = `callId`. The tool call is uniquely identified by\n // its callID, so reusing it here lets a consumer\n // group/lookup-by-id without risk of collision across\n // provider tool calls.\n // - `sessionID` and `messageID` = \"\" (empty string). The\n // originating SSE payload does NOT carry these; they\n // are an OpenCode-shape concept that doesn't exist\n // for raw provider events. Empty string is the honest\n // \"we don't know\" — using a sentinel like\n // \"__synthesized__\" was considered but would force\n // every consumer of `ToolPart.sessionID` to special-\n // case the string, whereas standard \"is this empty?\"\n // checks already work consistently with `\"\"`.\n //\n // Consumers that group parts by `sessionID` should treat empty-\n // string as \"unsynthesized origin\" and not mix it with real\n // session traffic — the trace event itself is a record of the\n // call shape, not of session membership.\n const part: ToolPart = {\n id: callId,\n sessionID: \"\",\n messageID: \"\",\n type: \"tool\",\n callID: callId,\n tool: toolName,\n state: toolState,\n };\n\n return {\n type: \"message.part.updated\",\n part,\n timestamp,\n } satisfies MessagePartUpdatedEventWithTimestamp;\n}\n\n/**\n * Convert SSE event data to a typed TraceEvent.\n * Returns null for events that should be skipped (heartbeats, status-only, etc.)\n *\n * message.part.updated events are passed through directly - no transformation.\n * This preserves full fidelity to what OpenCode outputs.\n *\n * `raw` events that carry a recognized tool-invocation payload are\n * normalized into the same `message.part.updated` shape (with a\n * `ToolPart`) so consumers don't need to reach into provider-specific\n * raw shapes to render tool calls. Unrecognized raw events fall\n * through to a `custom` trace event.\n */\nexport function sseToTraceEvent(event: SSEEventData): TraceEvent | null {\n const timestamp = new Date();\n\n // Recognize tool-invocation payloads regardless of whether the\n // outer wrapper survived as `raw` (orchestrator path), came through\n // as the inner provider type (direct sandbox SDK path), or was\n // emitted with a top-level inner-type marker.\n if (\n event.type === \"raw\" ||\n (typeof event.type === \"string\" && TOOL_INVOCATION_TYPES.has(event.type))\n ) {\n const normalized = normalizeRawToolInvocation(event, timestamp);\n if (normalized) {\n // Apply the same filter that the `message.part.updated`\n // branch below applies — the contract for `message.part.updated`\n // trace events is \"no pending tool states\", and a normalized\n // raw event lands in the same shape, so it must obey the same\n // filter. Without this, a consumer that processes both kinds\n // of events would see pending tool calls from raw\n // normalization but not from direct message.part.updated, an\n // inconsistency in the trace contract. (\"queued\" raw events\n // are mapped to \"pending\" inside the normalizer so this single\n // check covers both source statuses.)\n const status = (normalized.part as { state?: { status?: string } }).state\n ?.status;\n if (status === \"pending\") {\n return null;\n }\n return normalized;\n }\n // Unrecognized shape → custom event so observability still\n // captures the payload but doesn't pretend it's a tool call.\n // Preserve the original event type as the custom event's `name`\n // so trace consumers filtering by `name` can find e.g. a\n // malformed legacy tool invocation under its original name instead of\n // every unrecognized variant collapsing to `name: \"raw\"`.\n //\n // Match the `data` shape produced by the `default:` arm in the\n // switch below (`{eventType, ...event}`) so consumers that\n // inspect `data.eventType` on custom events get a uniform shape\n // regardless of whether the unrecognized event came in as a raw\n // tool-invocation type or as an unknown plain type.\n const customName = typeof event.type === \"string\" ? event.type : \"raw\";\n return {\n type: \"custom\",\n timestamp,\n name: customName,\n data: { eventType: customName, ...event } as Record<string, unknown>,\n } satisfies CustomEvent;\n }\n\n switch (event.type) {\n case \"message.part.updated\": {\n // Pass through message.part.updated events directly - no transformation\n // This preserves full fidelity to what OpenCode outputs\n const part = (event as { part?: Part }).part;\n if (!part) {\n return null;\n }\n\n // Skip pending/queued tool states - they don't contain meaningful data yet\n if (part.type === \"tool\") {\n const status = (part as { state?: { status?: string } }).state?.status;\n if (status === \"pending\" || status === \"queued\") {\n return null;\n }\n }\n\n return {\n type: \"message.part.updated\",\n part,\n timestamp,\n delta: (event as { delta?: string }).delta,\n _meta: (event as { _meta?: unknown })._meta as\n | MessagePartUpdatedEventWithTimestamp[\"_meta\"]\n | undefined,\n } satisfies MessagePartUpdatedEventWithTimestamp;\n }\n\n case \"error\":\n return {\n type: \"error\",\n timestamp,\n category: \"runtime\",\n message: String(event.message || event.error || \"Unknown error\"),\n code: typeof event.code === \"string\" ? event.code : undefined,\n } satisfies ErrorEvent;\n\n case \"status\":\n // Status events don't become trace events, they become signals\n return null;\n\n case \"result\": {\n const finalText =\n typeof (event as { finalText?: unknown }).finalText === \"string\"\n ? (event as { finalText?: string }).finalText\n : typeof (event as { text?: unknown }).text === \"string\"\n ? (event as { text?: string }).text\n : undefined;\n\n return {\n type: \"message.updated\",\n timestamp,\n text: finalText,\n finalText,\n tokenUsage: (event as { tokenUsage?: unknown }).tokenUsage as\n | Record<string, unknown>\n | undefined,\n timing: (event as { timing?: unknown }).timing as\n | Record<string, unknown>\n | undefined,\n toolInvocations: (event as { toolInvocations?: unknown })\n .toolInvocations as unknown[] | undefined,\n metadata: (event as { metadata?: unknown }).metadata as\n | Record<string, unknown>\n | undefined,\n } satisfies MessageUpdatedEvent;\n }\n case \"done\":\n // Terminal events - skip as trace events\n return null;\n\n default:\n // Capture unknown events as custom type for extensibility\n if (event.type && event.type !== \"heartbeat\") {\n return {\n type: \"custom\",\n timestamp,\n name: event.type,\n data: { eventType: event.type, ...event },\n } satisfies CustomEvent;\n }\n return null;\n }\n}\n\n/**\n * Extract a signal from an SSE event if present.\n */\nexport function sseToSignal(event: SSEEventData): SignalEvent | null {\n if (event.type === \"status\" && typeof event.status === \"string\") {\n if (VALID_SIGNALS.includes(event.status as Signal)) {\n return {\n signal: event.status as Signal,\n timestamp: new Date(),\n };\n }\n }\n return null;\n}\n\n/**\n * Check if an SSE event indicates completion (success or failure).\n */\nexport function isCompletionEvent(event: SSEEventData): {\n complete: boolean;\n success: boolean;\n} {\n if (event.type === \"done\" || event.type === \"result\") {\n const success = !(\"success\" in event && event.success === false);\n return { complete: true, success };\n }\n if (event.type === \"error\") {\n return { complete: true, success: false };\n }\n return { complete: false, success: false };\n}\n","/**\n * Trace Collector\n *\n * Collects execution traces and exports them to telemetry sinks.\n * Designed for cross-user data aggregation and analysis.\n */\n\nimport type {\n ExecutionTrace,\n Outcome,\n Signal,\n TraceEvent,\n TraceScope,\n} from \"./trace-types.js\";\nimport type { TelemetrySink } from \"./types.js\";\n\n// Web Crypto instead of a static `node:crypto` import keeps this module's barrel\n// (`@tangle-network/sdk-telemetry`) browser-safe — hub-sdk re-exports the barrel\n// and platform-web ships it to the browser, where a `node:crypto` import is\n// externalized and blanks the page. `globalThis.crypto` is present in Node 20+\n// and secure browser contexts (HTTPS / localhost) but ABSENT over plain HTTP, so\n// fall back to a Math.random v4 there — a trace id needs uniqueness, not\n// cryptographic strength.\nconst randomUUID = (): string => {\n const webCrypto = globalThis.crypto;\n if (webCrypto?.randomUUID) return webCrypto.randomUUID();\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n return (ch === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n};\n\nexport interface TraceCollectorConfig {\n /** Sink to export traces to */\n sink: TelemetrySink;\n /** Max traces to buffer before auto-flush */\n maxBufferSize?: number;\n /** Auto-flush interval in ms (0 = manual only) */\n flushIntervalMs?: number;\n /** Default scope for new traces */\n defaultScope?: TraceScope;\n}\n\n/** Active trace context for tracking a single execution */\nexport interface TraceContext {\n traceId: string;\n startedAt: Date;\n /** Add a typed event to the trace */\n addEvent<T extends TraceEvent>(event: Omit<T, \"timestamp\">): void;\n /** Add a signal (success/failure indicator) */\n addSignal(signal: Signal, metadata?: Record<string, unknown>): void;\n /** Complete the trace successfully */\n complete(metadata?: Record<string, unknown>): ExecutionTrace;\n /** Complete the trace with failure */\n fail(\n error: string | Error,\n metadata?: Record<string, unknown>,\n ): ExecutionTrace;\n /** Abandon the trace */\n abandon(): ExecutionTrace;\n}\n\ninterface ActiveTrace {\n id: string;\n scope: TraceScope;\n task: string;\n events: TraceEvent[];\n signals: Array<{\n signal: Signal;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n }>;\n startedAt: Date;\n metadata?: Record<string, unknown>;\n}\n\nexport class TraceCollector {\n private sink: TelemetrySink;\n private config: Required<\n Omit<TraceCollectorConfig, \"sink\" | \"defaultScope\">\n > & { defaultScope?: TraceScope };\n private activeTraces = new Map<string, ActiveTrace>();\n private completedTraces: ExecutionTrace[] = [];\n private flushTimer?: ReturnType<typeof setInterval>;\n private flushing?: Promise<void>;\n private sequence = 0;\n\n constructor(config: TraceCollectorConfig) {\n this.sink = config.sink;\n this.config = {\n maxBufferSize: config.maxBufferSize ?? 100,\n flushIntervalMs: config.flushIntervalMs ?? 0,\n defaultScope: config.defaultScope,\n };\n\n if (this.config.flushIntervalMs > 0) {\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.config.flushIntervalMs);\n }\n }\n\n /** Start tracking a new execution */\n startTrace(\n task: string,\n scope?: TraceScope,\n metadata?: Record<string, unknown>,\n ): TraceContext {\n const traceId = `trace_${randomUUID()}`;\n const startedAt = new Date();\n const traceScope = scope ?? this.config.defaultScope ?? {};\n\n const activeTrace: ActiveTrace = {\n id: traceId,\n scope: traceScope,\n task,\n events: [],\n signals: [],\n startedAt,\n metadata,\n };\n\n this.activeTraces.set(traceId, activeTrace);\n\n return {\n traceId,\n startedAt,\n\n addEvent: <T extends TraceEvent>(event: Omit<T, \"timestamp\">) => {\n const trace = this.activeTraces.get(traceId);\n if (trace) {\n trace.events.push({ ...event, timestamp: new Date() } as T);\n }\n },\n\n addSignal: (signal, signalMeta) => {\n const trace = this.activeTraces.get(traceId);\n if (trace) {\n trace.signals.push({\n signal,\n timestamp: new Date(),\n metadata: signalMeta,\n });\n }\n },\n\n complete: (completeMeta) => {\n return this.completeTrace(traceId, \"success\", completeMeta);\n },\n\n fail: (error, failMeta) => {\n const trace = this.activeTraces.get(traceId);\n if (trace) {\n const errorMsg = error instanceof Error ? error.message : error;\n trace.events.push({\n type: \"error\",\n timestamp: new Date(),\n category: \"runtime\",\n message: errorMsg,\n stack: error instanceof Error ? error.stack : undefined,\n });\n trace.signals.push({\n signal: \"runtime_error\",\n timestamp: new Date(),\n });\n }\n return this.completeTrace(traceId, \"failure\", failMeta);\n },\n\n abandon: () => {\n return this.completeTrace(traceId, \"unknown\", { abandoned: true });\n },\n };\n }\n\n /** Convenience: track a complete execution with a wrapper function */\n async track<T>(\n task: string,\n fn: (ctx: TraceContext) => Promise<T>,\n options?: { scope?: TraceScope; metadata?: Record<string, unknown> },\n ): Promise<{ result: T; trace: ExecutionTrace }> {\n const ctx = this.startTrace(task, options?.scope, options?.metadata);\n try {\n const result = await fn(ctx);\n const trace = ctx.complete();\n return { result, trace };\n } catch (error) {\n ctx.fail(error instanceof Error ? error : String(error));\n throw error;\n }\n }\n\n /** Flush completed traces to sink, including traces completed during delivery. */\n flush(): Promise<void> {\n if (this.flushing) return this.flushing;\n if (this.completedTraces.length === 0) return Promise.resolve();\n\n // Publish ownership before invoking a sink, including synchronous callbacks.\n this.flushing = Promise.resolve().then(async () => {\n try {\n while (this.completedTraces.length > 0) {\n const count = this.completedTraces.length;\n const events = this.completedTraces.map((trace) => ({\n id: `evt_${randomUUID()}`,\n type: \"agent_execution\" as const,\n name: \"execution_trace\",\n projectRef: trace.scope.projectRef,\n sessionId: trace.scope.sessionId,\n userId: trace.scope.userId,\n data: {\n traceId: trace.id,\n task: trace.task,\n outcome: trace.outcome,\n eventCount: trace.events.length,\n signalCount: trace.signals.length,\n durationMs: trace.completedAt\n ? trace.completedAt.getTime() - trace.startedAt.getTime()\n : undefined,\n // Full trace data for detailed analysis\n trace,\n },\n timestamp: trace.completedAt ?? new Date(),\n sequence: this.sequence++,\n }));\n\n await this.sink.send(events);\n // Only acknowledge this batch; newer completions still need delivery.\n this.completedTraces.splice(0, count);\n }\n } finally {\n this.flushing = undefined;\n }\n });\n return this.flushing;\n }\n\n /** Get count of pending traces */\n getPendingCount(): number {\n return this.completedTraces.length;\n }\n\n /** Get active trace count */\n getActiveCount(): number {\n return this.activeTraces.size;\n }\n\n /** Shutdown collector */\n async shutdown(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n await this.flush();\n await this.sink.flush();\n await this.sink.close();\n }\n\n private completeTrace(\n traceId: string,\n outcome: Outcome,\n metadata?: Record<string, unknown>,\n ): ExecutionTrace {\n const active = this.activeTraces.get(traceId);\n if (!active) {\n throw new Error(`Trace not found: ${traceId}`);\n }\n\n this.activeTraces.delete(traceId);\n\n const completedTrace: ExecutionTrace = {\n id: active.id,\n scope: active.scope,\n task: active.task,\n events: active.events,\n signals: active.signals,\n outcome: this.classifyOutcome(active.signals, outcome),\n startedAt: active.startedAt,\n completedAt: new Date(),\n metadata: { ...active.metadata, ...metadata },\n };\n\n this.completedTraces.push(completedTrace);\n\n if (this.completedTraces.length >= this.config.maxBufferSize) {\n this.flush().catch(() => {});\n }\n\n return completedTrace;\n }\n\n private classifyOutcome(\n signals: Array<{ signal: Signal }>,\n defaultOutcome: Outcome,\n ): Outcome {\n const signalSet = new Set(signals.map((s) => s.signal));\n\n if (signalSet.has(\"task_completed\")) {\n if (\n signalSet.has(\"tests_passed\") ||\n signalSet.has(\"build_passed\") ||\n signalSet.has(\"user_approved\")\n ) {\n return \"success\";\n }\n return \"partial\";\n }\n\n if (\n signalSet.has(\"runtime_error\") ||\n signalSet.has(\"timeout\") ||\n signalSet.has(\"tests_failed\") ||\n signalSet.has(\"build_failed\") ||\n signalSet.has(\"user_rejected\")\n ) {\n return \"failure\";\n }\n\n if (signalSet.has(\"task_abandoned\")) {\n return \"unknown\";\n }\n\n return defaultOutcome;\n }\n}\n\nexport function createTraceCollector(\n config: TraceCollectorConfig,\n): TraceCollector {\n return new TraceCollector(config);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sdk-telemetry",
3
- "version": "0.60.78-develop.20261025204905.3c2273e",
3
+ "version": "0.60.78-develop.20261026082550.33d103d",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",