@introspection-sdk/introspection-node 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-check-types.log +4 -0
  3. package/.turbo/turbo-lint.log +5 -0
  4. package/dist/client.d.ts +42 -132
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +67 -366
  7. package/dist/client.js.map +1 -0
  8. package/dist/converters/claude.d.ts +4 -0
  9. package/dist/converters/claude.d.ts.map +1 -1
  10. package/dist/converters/claude.js +7 -0
  11. package/dist/converters/claude.js.map +1 -0
  12. package/dist/converters/gemini.d.ts +90 -0
  13. package/dist/converters/gemini.d.ts.map +1 -0
  14. package/dist/converters/gemini.js +171 -0
  15. package/dist/converters/gemini.js.map +1 -0
  16. package/dist/converters/index.d.ts +1 -1
  17. package/dist/converters/index.d.ts.map +1 -1
  18. package/dist/converters/index.js +2 -1
  19. package/dist/converters/index.js.map +1 -0
  20. package/dist/converters/openai.js +1 -0
  21. package/dist/converters/openai.js.map +1 -0
  22. package/dist/converters/openclaw.d.ts +16 -0
  23. package/dist/converters/openclaw.d.ts.map +1 -0
  24. package/dist/converters/openclaw.js +49 -0
  25. package/dist/converters/openinference.js +1 -0
  26. package/dist/converters/openinference.js.map +1 -0
  27. package/dist/converters/vercel.d.ts.map +1 -1
  28. package/dist/converters/vercel.js +31 -3
  29. package/dist/converters/vercel.js.map +1 -0
  30. package/dist/http.d.ts +36 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/http.js +145 -0
  33. package/dist/http.js.map +1 -0
  34. package/dist/index.d.ts +24 -27
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +22 -32
  37. package/dist/index.js.map +1 -0
  38. package/dist/otel/anthropic.d.ts +62 -0
  39. package/dist/otel/anthropic.d.ts.map +1 -0
  40. package/dist/otel/anthropic.js +425 -0
  41. package/dist/otel/anthropic.js.map +1 -0
  42. package/dist/otel/claude-hooks.d.ts +346 -0
  43. package/dist/otel/claude-hooks.d.ts.map +1 -0
  44. package/dist/otel/claude-hooks.js +645 -0
  45. package/dist/otel/claude-hooks.js.map +1 -0
  46. package/dist/otel/claude-wrapper.d.ts +93 -0
  47. package/dist/otel/claude-wrapper.d.ts.map +1 -0
  48. package/dist/otel/claude-wrapper.js +155 -0
  49. package/dist/otel/claude-wrapper.js.map +1 -0
  50. package/dist/otel/gemini.d.ts +48 -0
  51. package/dist/otel/gemini.d.ts.map +1 -0
  52. package/dist/otel/gemini.js +297 -0
  53. package/dist/otel/gemini.js.map +1 -0
  54. package/dist/otel/index.d.ts +27 -0
  55. package/dist/otel/index.d.ts.map +1 -0
  56. package/dist/otel/index.js +33 -0
  57. package/dist/otel/index.js.map +1 -0
  58. package/dist/otel/langchain-handler.d.ts +112 -0
  59. package/dist/otel/langchain-handler.d.ts.map +1 -0
  60. package/dist/otel/langchain-handler.js +555 -0
  61. package/dist/otel/langchain-handler.js.map +1 -0
  62. package/dist/otel/logs.d.ts +82 -0
  63. package/dist/otel/logs.d.ts.map +1 -0
  64. package/dist/otel/logs.js +271 -0
  65. package/dist/otel/logs.js.map +1 -0
  66. package/dist/otel/mastra-exporter.d.ts +87 -0
  67. package/dist/otel/mastra-exporter.d.ts.map +1 -0
  68. package/dist/otel/mastra-exporter.js +525 -0
  69. package/dist/otel/mastra-exporter.js.map +1 -0
  70. package/dist/otel/pi.d.ts +59 -0
  71. package/dist/otel/pi.d.ts.map +1 -0
  72. package/dist/otel/pi.js +67 -0
  73. package/dist/otel/pi.js.map +1 -0
  74. package/dist/otel/setup.d.ts +23 -0
  75. package/dist/otel/setup.d.ts.map +1 -0
  76. package/dist/otel/setup.js +127 -0
  77. package/dist/otel/setup.js.map +1 -0
  78. package/dist/otel/span-processor.d.ts +62 -0
  79. package/dist/otel/span-processor.d.ts.map +1 -0
  80. package/dist/otel/span-processor.js +319 -0
  81. package/dist/otel/span-processor.js.map +1 -0
  82. package/dist/otel/tracing-processor.d.ts +139 -0
  83. package/dist/otel/tracing-processor.d.ts.map +1 -0
  84. package/dist/otel/tracing-processor.js +418 -0
  85. package/dist/otel/tracing-processor.js.map +1 -0
  86. package/dist/resources/experiments.d.ts +31 -0
  87. package/dist/resources/experiments.d.ts.map +1 -0
  88. package/dist/resources/experiments.js +133 -0
  89. package/dist/resources/experiments.js.map +1 -0
  90. package/dist/resources/recipes.d.ts +22 -0
  91. package/dist/resources/recipes.d.ts.map +1 -0
  92. package/dist/resources/recipes.js +61 -0
  93. package/dist/resources/recipes.js.map +1 -0
  94. package/dist/resources/runtimes.d.ts +76 -0
  95. package/dist/resources/runtimes.d.ts.map +1 -0
  96. package/dist/resources/runtimes.js +179 -0
  97. package/dist/resources/runtimes.js.map +1 -0
  98. package/dist/runner-resources/files.d.ts +35 -0
  99. package/dist/runner-resources/files.d.ts.map +1 -0
  100. package/dist/runner-resources/files.js +131 -0
  101. package/dist/runner-resources/files.js.map +1 -0
  102. package/dist/runner-resources/tasks.d.ts +39 -0
  103. package/dist/runner-resources/tasks.d.ts.map +1 -0
  104. package/dist/runner-resources/tasks.js +129 -0
  105. package/dist/runner-resources/tasks.js.map +1 -0
  106. package/dist/runner.d.ts +80 -0
  107. package/dist/runner.d.ts.map +1 -0
  108. package/dist/runner.js +159 -0
  109. package/dist/runner.js.map +1 -0
  110. package/dist/streaming.d.ts +8 -0
  111. package/dist/streaming.d.ts.map +1 -0
  112. package/dist/streaming.js +67 -0
  113. package/dist/streaming.js.map +1 -0
  114. package/dist/types/genai.d.ts +165 -0
  115. package/dist/types/genai.d.ts.map +1 -0
  116. package/dist/types/genai.js +82 -0
  117. package/dist/types.js +1 -0
  118. package/dist/types.js.map +1 -0
  119. package/dist/utils.js +1 -0
  120. package/dist/utils.js.map +1 -0
  121. package/dist/version.js +1 -0
  122. package/dist/version.js.map +1 -0
  123. package/package.json +81 -24
  124. package/src/client.ts +76 -473
  125. package/src/converters/claude.ts +10 -0
  126. package/src/converters/gemini.ts +243 -0
  127. package/src/converters/index.ts +13 -7
  128. package/src/converters/vercel.ts +41 -3
  129. package/src/http.ts +163 -0
  130. package/src/index.ts +110 -75
  131. package/src/{anthropic.ts → otel/anthropic.ts} +95 -8
  132. package/src/{claude-hooks.ts → otel/claude-hooks.ts} +119 -20
  133. package/src/{claude-wrapper.ts → otel/claude-wrapper.ts} +1 -1
  134. package/src/otel/gemini.ts +397 -0
  135. package/src/otel/index.ts +80 -0
  136. package/src/{langchain-handler.ts → otel/langchain-handler.ts} +53 -6
  137. package/src/otel/logs.ts +394 -0
  138. package/src/{mastra-exporter.ts → otel/mastra-exporter.ts} +83 -22
  139. package/src/otel/pi.ts +88 -0
  140. package/src/otel/setup.ts +174 -0
  141. package/src/{span-processor.ts → otel/span-processor.ts} +11 -6
  142. package/src/{tracing-processor.ts → otel/tracing-processor.ts} +94 -19
  143. package/src/resources/experiments.ts +170 -0
  144. package/src/resources/recipes.ts +73 -0
  145. package/src/resources/runtimes.ts +231 -0
  146. package/src/runner-resources/files.ts +163 -0
  147. package/src/runner-resources/tasks.ts +156 -0
  148. package/src/runner.ts +194 -0
  149. package/src/streaming.ts +57 -0
  150. package/src/ai-sdk-integration.ts +0 -691
  151. package/src/converters/ai-sdk.ts +0 -323
@@ -9,10 +9,12 @@
9
9
 
10
10
  import {
11
11
  context as otelContext,
12
+ propagation,
12
13
  trace as otelTrace,
13
14
  Span as OtelSpan,
14
15
  SpanKind,
15
16
  SpanStatusCode,
17
+ type Attributes,
16
18
  } from "@opentelemetry/api";
17
19
  import {
18
20
  BasicTracerProvider,
@@ -28,12 +30,12 @@ import {
28
30
  } from "@opentelemetry/resources";
29
31
  import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
30
32
 
31
- import { logger, withOtlpHttpsProxy } from "./utils.js";
32
- import { VERSION } from "./version.js";
33
+ import { logger, withOtlpHttpsProxy } from "../utils.js";
34
+ import { VERSION } from "../version.js";
33
35
  import {
34
36
  convertClaudeSessionToOtelAttributes,
35
37
  type ClaudeContentBlock,
36
- } from "./converters/claude.js";
38
+ } from "../converters/claude.js";
37
39
 
38
40
  // ---------------------------------------------------------------------------
39
41
  // Claude Agent SDK Hook types
@@ -241,6 +243,8 @@ export interface ClaudeAssistantMessage {
241
243
  usage?: {
242
244
  input_tokens?: number;
243
245
  output_tokens?: number;
246
+ cache_read_input_tokens?: number;
247
+ cache_creation_input_tokens?: number;
244
248
  };
245
249
  content?: Array<{ type: string; text?: string }>;
246
250
  };
@@ -271,12 +275,16 @@ export interface ClaudeHooksAdvancedOptions {
271
275
  export interface IntrospectionClaudeHooksOptions {
272
276
  /** Authentication token (env: INTROSPECTION_TOKEN) */
273
277
  token?: string;
274
- /** Base URL for the API (env: INTROSPECTION_BASE_URL) */
278
+ /** Base URL for the API (env: INTROSPECTION_BASE_OTEL_URL) */
275
279
  baseUrl?: string;
276
280
  /** Service name for the OTel resource (defaults to "claude-agent") */
277
281
  serviceName?: string;
278
282
  /** Agent name set on session spans as gen_ai.agent.name (defaults to serviceName) */
279
283
  agentName?: string;
284
+ /** Agent ID set on session spans as gen_ai.agent.id */
285
+ agentId?: string;
286
+ /** Conversation ID set on session spans as gen_ai.conversation.id */
287
+ conversationId?: string;
280
288
  /** Additional headers to include in requests */
281
289
  additionalHeaders?: Record<string, string>;
282
290
  /** Advanced options for testing and customization */
@@ -319,6 +327,8 @@ export class IntrospectionClaudeHooks {
319
327
  private _tracerProvider: BasicTracerProvider;
320
328
  private _tracer: ReturnType<BasicTracerProvider["getTracer"]>;
321
329
  private _agentName: string;
330
+ private _agentId?: string;
331
+ private _conversationId?: string;
322
332
  private _sessionSpans: Map<string, OtelSpan> = new Map();
323
333
  private _toolSpans: Map<string, OtelSpan> = new Map();
324
334
  private _subagentSpans: Map<string, OtelSpan> = new Map();
@@ -327,6 +337,8 @@ export class IntrospectionClaudeHooks {
327
337
  {
328
338
  input: number;
329
339
  output: number;
340
+ cacheRead: number;
341
+ cacheCreation: number;
330
342
  cost?: number;
331
343
  model?: string;
332
344
  inputPrompt?: string;
@@ -343,6 +355,8 @@ export class IntrospectionClaudeHooks {
343
355
  const advanced = options.advanced;
344
356
  const serviceName = options.serviceName || "claude-agent";
345
357
  this._agentName = options.agentName || serviceName;
358
+ this._agentId = options.agentId;
359
+ this._conversationId = options.conversationId;
346
360
  const resource = defaultResource().merge(
347
361
  resourceFromAttributes({ [ATTR_SERVICE_NAME]: serviceName }),
348
362
  );
@@ -355,7 +369,7 @@ export class IntrospectionClaudeHooks {
355
369
 
356
370
  const baseUrl =
357
371
  options.baseUrl ||
358
- process.env.INTROSPECTION_BASE_URL ||
372
+ process.env.INTROSPECTION_BASE_OTEL_URL ||
359
373
  "https://otel.introspection.dev";
360
374
 
361
375
  const headers: Record<string, string> = {
@@ -455,6 +469,32 @@ export class IntrospectionClaudeHooks {
455
469
  };
456
470
  }
457
471
 
472
+ /**
473
+ * Resolve effective agent / conversation identity for a session, in order
474
+ * of precedence: OTel baggage on the active context > constructor option >
475
+ * the Claude session ID. Lets callers override identity per-invocation via
476
+ * `IntrospectionClient.withAgent()` / `.withConversation()` without
477
+ * having to construct a new hooks instance per call.
478
+ *
479
+ * Requires an active context manager — see {@link setupTracing}.
480
+ */
481
+ private _resolveIdentity(sessionId: string): {
482
+ agentName: string;
483
+ agentId?: string;
484
+ conversationId: string;
485
+ } {
486
+ const baggage = propagation.getBaggage(otelContext.active());
487
+ const baggageAgentName = baggage?.getEntry("gen_ai.agent.name")?.value;
488
+ const baggageAgentId = baggage?.getEntry("gen_ai.agent.id")?.value;
489
+ const baggageConvId = baggage?.getEntry("gen_ai.conversation.id")?.value;
490
+
491
+ return {
492
+ agentName: baggageAgentName || this._agentName,
493
+ agentId: baggageAgentId || this._agentId,
494
+ conversationId: baggageConvId || this._conversationId || sessionId,
495
+ };
496
+ }
497
+
458
498
  /**
459
499
  * Set the input prompt for a session so it appears as
460
500
  * `gen_ai.input.messages` on the session span.
@@ -470,6 +510,8 @@ export class IntrospectionClaudeHooks {
470
510
  const existing = this._sessionUsage.get(sessionId) || {
471
511
  input: 0,
472
512
  output: 0,
513
+ cacheRead: 0,
514
+ cacheCreation: 0,
473
515
  };
474
516
  existing.inputPrompt = prompt;
475
517
  this._sessionUsage.set(sessionId, existing);
@@ -496,12 +538,17 @@ export class IntrospectionClaudeHooks {
496
538
  const existing = this._sessionUsage.get(sessionId) || {
497
539
  input: 0,
498
540
  output: 0,
541
+ cacheRead: 0,
542
+ cacheCreation: 0,
499
543
  };
500
544
  existing.systemInstructions = instructions;
501
545
  this._sessionUsage.set(sessionId, existing);
502
546
  } else {
503
547
  this._pendingSystemInstructions = instructions;
504
548
  }
549
+ logger.info(
550
+ `System instructions set (${instructions.length} chars)${sessionId ? ` for session ${sessionId}` : " (pending)"}`,
551
+ );
505
552
  }
506
553
 
507
554
  private _pendingSystemInstructions?: string;
@@ -530,6 +577,8 @@ export class IntrospectionClaudeHooks {
530
577
  const existing = this._sessionUsage.get(sessionId) || {
531
578
  input: 0,
532
579
  output: 0,
580
+ cacheRead: 0,
581
+ cacheCreation: 0,
533
582
  };
534
583
 
535
584
  // Track usage
@@ -537,6 +586,8 @@ export class IntrospectionClaudeHooks {
537
586
  if (usage) {
538
587
  existing.input += usage.input_tokens || 0;
539
588
  existing.output += usage.output_tokens || 0;
589
+ existing.cacheRead += usage.cache_read_input_tokens || 0;
590
+ existing.cacheCreation += usage.cache_creation_input_tokens || 0;
540
591
  if (assistantMsg.message?.model) {
541
592
  existing.model = assistantMsg.message.model;
542
593
  }
@@ -575,12 +626,31 @@ export class IntrospectionClaudeHooks {
575
626
  const existing = this._sessionUsage.get(sessionId) || {
576
627
  input: 0,
577
628
  output: 0,
629
+ cacheRead: 0,
630
+ cacheCreation: 0,
578
631
  };
579
632
 
580
633
  if (resultMsg.usage) {
581
634
  // Result message has final totals
582
635
  existing.input = resultMsg.usage.input_tokens || existing.input;
583
636
  existing.output = resultMsg.usage.output_tokens || existing.output;
637
+ if (resultMsg.usage.cache_read_input_tokens != null) {
638
+ existing.cacheRead = resultMsg.usage.cache_read_input_tokens;
639
+ }
640
+ if (resultMsg.usage.cache_creation_input_tokens != null) {
641
+ existing.cacheCreation = resultMsg.usage.cache_creation_input_tokens;
642
+ }
643
+ }
644
+ // Fallback: aggregate cache tokens from per-model breakdown when top-level usage omits them
645
+ if (
646
+ resultMsg.modelUsage &&
647
+ existing.cacheRead === 0 &&
648
+ existing.cacheCreation === 0
649
+ ) {
650
+ for (const modelData of Object.values(resultMsg.modelUsage)) {
651
+ existing.cacheRead += modelData.cacheReadInputTokens || 0;
652
+ existing.cacheCreation += modelData.cacheCreationInputTokens || 0;
653
+ }
584
654
  }
585
655
  if (resultMsg.total_cost_usd !== undefined) {
586
656
  existing.cost = resultMsg.total_cost_usd;
@@ -617,16 +687,23 @@ export class IntrospectionClaudeHooks {
617
687
  }
618
688
 
619
689
  logger.debug(`Starting session span from init message: ${sessionId}`);
690
+ const ids = this._resolveIdentity(sessionId);
691
+ const attrs: Attributes = {
692
+ "gen_ai.system": "anthropic",
693
+ "gen_ai.operation.name": "chat",
694
+ "gen_ai.agent.name": ids.agentName,
695
+ "gen_ai.conversation.id": ids.conversationId,
696
+ "claude.session_id": sessionId,
697
+ "claude.source": "message",
698
+ };
699
+
700
+ if (ids.agentId) {
701
+ attrs["gen_ai.agent.id"] = ids.agentId;
702
+ }
620
703
 
621
704
  const span = this._tracer.startSpan("claude.session", {
622
705
  kind: SpanKind.CLIENT,
623
- attributes: {
624
- "gen_ai.system": "anthropic",
625
- "gen_ai.operation.name": "chat",
626
- "gen_ai.agent.name": this._agentName,
627
- "claude.session_id": sessionId,
628
- "claude.source": "message",
629
- },
706
+ attributes: attrs,
630
707
  });
631
708
 
632
709
  // Add model if present in init message
@@ -651,12 +728,14 @@ export class IntrospectionClaudeHooks {
651
728
  const sessionData: {
652
729
  input: number;
653
730
  output: number;
731
+ cacheRead: number;
732
+ cacheCreation: number;
654
733
  model?: string;
655
734
  inputPrompt?: string;
656
735
  responseContent?: string;
657
736
  toolNames?: string[];
658
737
  systemInstructions?: string;
659
- } = { input: 0, output: 0, model };
738
+ } = { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, model };
660
739
 
661
740
  if (tools && tools.length > 0) {
662
741
  sessionData.toolNames = tools;
@@ -701,6 +780,8 @@ export class IntrospectionClaudeHooks {
701
780
  model: usage?.model,
702
781
  inputTokens: usage?.input,
703
782
  outputTokens: usage?.output,
783
+ cacheReadInputTokens: usage?.cacheRead || undefined,
784
+ cacheCreationInputTokens: usage?.cacheCreation || undefined,
704
785
  costUsd: usage?.cost,
705
786
  stopReason: usage?.stopReason,
706
787
  responseId: usage?.responseId,
@@ -747,15 +828,27 @@ export class IntrospectionClaudeHooks {
747
828
  const sessionInput = input as SessionStartHookInput;
748
829
  logger.debug(`SessionStart hook: ${sessionInput.session_id}`);
749
830
 
831
+ // Resolve identity via _resolveIdentity so baggage on the active context
832
+ // takes precedence over constructor defaults, matching the message-init
833
+ // path in _startSessionFromMessage. Without this, the SessionStart hook
834
+ // would always stamp the constructor-time agentName / sessionId even
835
+ // when the caller wrapped the query in withAgent() / withConversation().
836
+ const ids = this._resolveIdentity(sessionInput.session_id);
837
+ const attrs: Attributes = {
838
+ "gen_ai.system": "anthropic",
839
+ "gen_ai.operation.name": "chat",
840
+ "gen_ai.agent.name": ids.agentName,
841
+ "gen_ai.conversation.id": ids.conversationId,
842
+ "claude.session_id": sessionInput.session_id,
843
+ "claude.source": sessionInput.source,
844
+ };
845
+ if (ids.agentId) {
846
+ attrs["gen_ai.agent.id"] = ids.agentId;
847
+ }
848
+
750
849
  const span = this._tracer.startSpan("claude.session", {
751
850
  kind: SpanKind.CLIENT,
752
- attributes: {
753
- "gen_ai.system": "anthropic",
754
- "gen_ai.operation.name": "chat",
755
- "gen_ai.agent.name": this._agentName,
756
- "claude.session_id": sessionInput.session_id,
757
- "claude.source": sessionInput.source,
758
- },
851
+ attributes: attrs,
759
852
  });
760
853
 
761
854
  if (sessionInput.model) {
@@ -771,11 +864,15 @@ export class IntrospectionClaudeHooks {
771
864
  const sessionUsage: {
772
865
  input: number;
773
866
  output: number;
867
+ cacheRead: number;
868
+ cacheCreation: number;
774
869
  inputPrompt?: string;
775
870
  systemInstructions?: string;
776
871
  } = {
777
872
  input: 0,
778
873
  output: 0,
874
+ cacheRead: 0,
875
+ cacheCreation: 0,
779
876
  };
780
877
  if (this._pendingInputPrompt) {
781
878
  sessionUsage.inputPrompt = this._pendingInputPrompt;
@@ -813,6 +910,8 @@ export class IntrospectionClaudeHooks {
813
910
  model: usage.model,
814
911
  inputTokens: usage.input,
815
912
  outputTokens: usage.output,
913
+ cacheReadInputTokens: usage.cacheRead || undefined,
914
+ cacheCreationInputTokens: usage.cacheCreation || undefined,
816
915
  costUsd: usage.cost,
817
916
  stopReason: usage.stopReason,
818
917
  responseId: usage.responseId,
@@ -26,7 +26,7 @@ import {
26
26
  type ClaudeHooksConfig,
27
27
  type ClaudeSDKMessage,
28
28
  } from "./claude-hooks.js";
29
- import { logger } from "./utils.js";
29
+ import { logger } from "../utils.js";
30
30
 
31
31
  // --- Public types ---
32
32