openlit 1.10.0 → 1.12.0

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 (195) hide show
  1. package/README.md +35 -1
  2. package/dist/config.d.ts +12 -4
  3. package/dist/config.js +7 -17
  4. package/dist/config.js.map +1 -1
  5. package/dist/evals/llm/anthropic.js +10 -6
  6. package/dist/evals/llm/anthropic.js.map +1 -1
  7. package/dist/evals/llm/openai.js +9 -5
  8. package/dist/evals/llm/openai.js.map +1 -1
  9. package/dist/features/__tests__/rule-engine.test.d.ts +1 -0
  10. package/dist/features/__tests__/rule-engine.test.js +146 -0
  11. package/dist/features/__tests__/rule-engine.test.js.map +1 -0
  12. package/dist/features/base.d.ts +2 -0
  13. package/dist/features/base.js +2 -0
  14. package/dist/features/base.js.map +1 -1
  15. package/dist/features/rule-engine.d.ts +6 -0
  16. package/dist/features/rule-engine.js +60 -0
  17. package/dist/features/rule-engine.js.map +1 -0
  18. package/dist/features/vault.js +1 -1
  19. package/dist/features/vault.js.map +1 -1
  20. package/dist/helpers.d.ts +93 -1
  21. package/dist/helpers.js +270 -8
  22. package/dist/helpers.js.map +1 -1
  23. package/dist/index.d.ts +6 -5
  24. package/dist/index.js +95 -50
  25. package/dist/index.js.map +1 -1
  26. package/dist/instrumentation/__tests__/anthropic-wrapper.test.js +215 -27
  27. package/dist/instrumentation/__tests__/anthropic-wrapper.test.js.map +1 -1
  28. package/dist/instrumentation/__tests__/base-wrapper.test.js +19 -23
  29. package/dist/instrumentation/__tests__/base-wrapper.test.js.map +1 -1
  30. package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.d.ts +1 -0
  31. package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.js +422 -0
  32. package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.js.map +1 -0
  33. package/dist/instrumentation/__tests__/chroma-trace-comparison.test.js +1 -1
  34. package/dist/instrumentation/__tests__/chroma-trace-comparison.test.js.map +1 -1
  35. package/dist/instrumentation/__tests__/cohere-wrapper.test.js +150 -25
  36. package/dist/instrumentation/__tests__/cohere-wrapper.test.js.map +1 -1
  37. package/dist/instrumentation/__tests__/google-ai-trace-comparison.test.js +152 -33
  38. package/dist/instrumentation/__tests__/google-ai-trace-comparison.test.js.map +1 -1
  39. package/dist/instrumentation/__tests__/groq-trace-comparison.test.js +391 -45
  40. package/dist/instrumentation/__tests__/groq-trace-comparison.test.js.map +1 -1
  41. package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.d.ts +2 -2
  42. package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.js +323 -31
  43. package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.js.map +1 -1
  44. package/dist/instrumentation/__tests__/langchain-wrapper.test.d.ts +1 -0
  45. package/dist/instrumentation/__tests__/langchain-wrapper.test.js +282 -0
  46. package/dist/instrumentation/__tests__/langchain-wrapper.test.js.map +1 -0
  47. package/dist/instrumentation/__tests__/milvus-trace-comparison.test.js +1 -1
  48. package/dist/instrumentation/__tests__/milvus-trace-comparison.test.js.map +1 -1
  49. package/dist/instrumentation/__tests__/mistral-trace-comparison.test.d.ts +0 -3
  50. package/dist/instrumentation/__tests__/mistral-trace-comparison.test.js +275 -68
  51. package/dist/instrumentation/__tests__/mistral-trace-comparison.test.js.map +1 -1
  52. package/dist/instrumentation/__tests__/openai-wrapper.test.js +7 -9
  53. package/dist/instrumentation/__tests__/openai-wrapper.test.js.map +1 -1
  54. package/dist/instrumentation/__tests__/qdrant-trace-comparison.test.js +1 -1
  55. package/dist/instrumentation/__tests__/qdrant-trace-comparison.test.js.map +1 -1
  56. package/dist/instrumentation/__tests__/replicate-trace-comparison.test.d.ts +2 -1
  57. package/dist/instrumentation/__tests__/replicate-trace-comparison.test.js +209 -21
  58. package/dist/instrumentation/__tests__/replicate-trace-comparison.test.js.map +1 -1
  59. package/dist/instrumentation/__tests__/together-trace-comparison.test.js +231 -51
  60. package/dist/instrumentation/__tests__/together-trace-comparison.test.js.map +1 -1
  61. package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.d.ts +8 -0
  62. package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.js +446 -0
  63. package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.js.map +1 -0
  64. package/dist/instrumentation/anthropic/index.d.ts +2 -3
  65. package/dist/instrumentation/anthropic/index.js.map +1 -1
  66. package/dist/instrumentation/anthropic/wrapper.d.ts +1 -3
  67. package/dist/instrumentation/anthropic/wrapper.js +211 -91
  68. package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
  69. package/dist/instrumentation/azure-ai-inference/index.d.ts +11 -0
  70. package/dist/instrumentation/azure-ai-inference/index.js +76 -0
  71. package/dist/instrumentation/azure-ai-inference/index.js.map +1 -0
  72. package/dist/instrumentation/azure-ai-inference/wrapper.d.ts +42 -0
  73. package/dist/instrumentation/azure-ai-inference/wrapper.js +515 -0
  74. package/dist/instrumentation/azure-ai-inference/wrapper.js.map +1 -0
  75. package/dist/instrumentation/base-wrapper.d.ts +2 -1
  76. package/dist/instrumentation/base-wrapper.js +35 -23
  77. package/dist/instrumentation/base-wrapper.js.map +1 -1
  78. package/dist/instrumentation/bedrock/wrapper.d.ts +21 -3
  79. package/dist/instrumentation/bedrock/wrapper.js +318 -265
  80. package/dist/instrumentation/bedrock/wrapper.js.map +1 -1
  81. package/dist/instrumentation/chroma/wrapper.js +1 -1
  82. package/dist/instrumentation/chroma/wrapper.js.map +1 -1
  83. package/dist/instrumentation/claude-agent-sdk/index.d.ts +23 -0
  84. package/dist/instrumentation/claude-agent-sdk/index.js +83 -0
  85. package/dist/instrumentation/claude-agent-sdk/index.js.map +1 -0
  86. package/dist/instrumentation/claude-agent-sdk/wrapper.d.ts +13 -0
  87. package/dist/instrumentation/claude-agent-sdk/wrapper.js +1031 -0
  88. package/dist/instrumentation/claude-agent-sdk/wrapper.js.map +1 -0
  89. package/dist/instrumentation/cohere/index.d.ts +2 -3
  90. package/dist/instrumentation/cohere/index.js.map +1 -1
  91. package/dist/instrumentation/cohere/wrapper.d.ts +1 -1
  92. package/dist/instrumentation/cohere/wrapper.js +215 -56
  93. package/dist/instrumentation/cohere/wrapper.js.map +1 -1
  94. package/dist/instrumentation/google-adk/index.d.ts +57 -0
  95. package/dist/instrumentation/google-adk/index.js +371 -0
  96. package/dist/instrumentation/google-adk/index.js.map +1 -0
  97. package/dist/instrumentation/google-adk/utils.d.ts +45 -0
  98. package/dist/instrumentation/google-adk/utils.js +663 -0
  99. package/dist/instrumentation/google-adk/utils.js.map +1 -0
  100. package/dist/instrumentation/google-adk/wrapper.d.ts +11 -0
  101. package/dist/instrumentation/google-adk/wrapper.js +391 -0
  102. package/dist/instrumentation/google-adk/wrapper.js.map +1 -0
  103. package/dist/instrumentation/google-ai/wrapper.d.ts +7 -4
  104. package/dist/instrumentation/google-ai/wrapper.js +197 -61
  105. package/dist/instrumentation/google-ai/wrapper.js.map +1 -1
  106. package/dist/instrumentation/groq/wrapper.js +137 -65
  107. package/dist/instrumentation/groq/wrapper.js.map +1 -1
  108. package/dist/instrumentation/huggingface/wrapper.js +241 -39
  109. package/dist/instrumentation/huggingface/wrapper.js.map +1 -1
  110. package/dist/instrumentation/index.d.ts +2 -2
  111. package/dist/instrumentation/index.js +64 -6
  112. package/dist/instrumentation/index.js.map +1 -1
  113. package/dist/instrumentation/langchain/index.d.ts +0 -7
  114. package/dist/instrumentation/langchain/index.js +2 -20
  115. package/dist/instrumentation/langchain/index.js.map +1 -1
  116. package/dist/instrumentation/langchain/wrapper.d.ts +35 -0
  117. package/dist/instrumentation/langchain/wrapper.js +1098 -184
  118. package/dist/instrumentation/langchain/wrapper.js.map +1 -1
  119. package/dist/instrumentation/langgraph/index.d.ts +12 -0
  120. package/dist/instrumentation/langgraph/index.js +99 -0
  121. package/dist/instrumentation/langgraph/index.js.map +1 -0
  122. package/dist/instrumentation/langgraph/wrapper.d.ts +20 -0
  123. package/dist/instrumentation/langgraph/wrapper.js +619 -0
  124. package/dist/instrumentation/langgraph/wrapper.js.map +1 -0
  125. package/dist/instrumentation/llamaindex/index.d.ts +31 -6
  126. package/dist/instrumentation/llamaindex/index.js +180 -61
  127. package/dist/instrumentation/llamaindex/index.js.map +1 -1
  128. package/dist/instrumentation/llamaindex/wrapper.d.ts +15 -3
  129. package/dist/instrumentation/llamaindex/wrapper.js +670 -179
  130. package/dist/instrumentation/llamaindex/wrapper.js.map +1 -1
  131. package/dist/instrumentation/milvus/wrapper.js +1 -1
  132. package/dist/instrumentation/milvus/wrapper.js.map +1 -1
  133. package/dist/instrumentation/mistral/wrapper.js +154 -79
  134. package/dist/instrumentation/mistral/wrapper.js.map +1 -1
  135. package/dist/instrumentation/ollama/index.js +33 -4
  136. package/dist/instrumentation/ollama/index.js.map +1 -1
  137. package/dist/instrumentation/ollama/wrapper.d.ts +28 -2
  138. package/dist/instrumentation/ollama/wrapper.js +432 -48
  139. package/dist/instrumentation/ollama/wrapper.js.map +1 -1
  140. package/dist/instrumentation/openai/index.d.ts +2 -3
  141. package/dist/instrumentation/openai/index.js.map +1 -1
  142. package/dist/instrumentation/openai/wrapper.js +293 -194
  143. package/dist/instrumentation/openai/wrapper.js.map +1 -1
  144. package/dist/instrumentation/openai-agents/index.d.ts +20 -0
  145. package/dist/instrumentation/openai-agents/index.js +174 -0
  146. package/dist/instrumentation/openai-agents/index.js.map +1 -0
  147. package/dist/instrumentation/openai-agents/processor.d.ts +35 -0
  148. package/dist/instrumentation/openai-agents/processor.js +249 -0
  149. package/dist/instrumentation/openai-agents/processor.js.map +1 -0
  150. package/dist/instrumentation/openai-agents/utils.d.ts +20 -0
  151. package/dist/instrumentation/openai-agents/utils.js +624 -0
  152. package/dist/instrumentation/openai-agents/utils.js.map +1 -0
  153. package/dist/instrumentation/pinecone/wrapper.js +2 -2
  154. package/dist/instrumentation/pinecone/wrapper.js.map +1 -1
  155. package/dist/instrumentation/qdrant/wrapper.js +1 -1
  156. package/dist/instrumentation/qdrant/wrapper.js.map +1 -1
  157. package/dist/instrumentation/replicate/wrapper.js +103 -21
  158. package/dist/instrumentation/replicate/wrapper.js.map +1 -1
  159. package/dist/instrumentation/strands/index.d.ts +21 -0
  160. package/dist/instrumentation/strands/index.js +83 -0
  161. package/dist/instrumentation/strands/index.js.map +1 -0
  162. package/dist/instrumentation/strands/processor.d.ts +45 -0
  163. package/dist/instrumentation/strands/processor.js +545 -0
  164. package/dist/instrumentation/strands/processor.js.map +1 -0
  165. package/dist/instrumentation/strands/utils.d.ts +24 -0
  166. package/dist/instrumentation/strands/utils.js +360 -0
  167. package/dist/instrumentation/strands/utils.js.map +1 -0
  168. package/dist/instrumentation/together/wrapper.js +125 -51
  169. package/dist/instrumentation/together/wrapper.js.map +1 -1
  170. package/dist/instrumentation/vercel-ai/wrapper.d.ts +28 -2
  171. package/dist/instrumentation/vercel-ai/wrapper.js +314 -164
  172. package/dist/instrumentation/vercel-ai/wrapper.js.map +1 -1
  173. package/dist/llm/anthropic.js +10 -6
  174. package/dist/llm/anthropic.js.map +1 -1
  175. package/dist/llm/openai.js +9 -5
  176. package/dist/llm/openai.js.map +1 -1
  177. package/dist/otel/__tests__/metrics.test.js +16 -27
  178. package/dist/otel/__tests__/metrics.test.js.map +1 -1
  179. package/dist/otel/events.d.ts +11 -0
  180. package/dist/otel/events.js +74 -0
  181. package/dist/otel/events.js.map +1 -0
  182. package/dist/otel/metrics.d.ts +5 -6
  183. package/dist/otel/metrics.js +66 -48
  184. package/dist/otel/metrics.js.map +1 -1
  185. package/dist/otel/tracing.d.ts +6 -2
  186. package/dist/otel/tracing.js +71 -24
  187. package/dist/otel/tracing.js.map +1 -1
  188. package/dist/otel/utils.d.ts +11 -0
  189. package/dist/otel/utils.js +34 -0
  190. package/dist/otel/utils.js.map +1 -0
  191. package/dist/semantic-convention.d.ts +44 -5
  192. package/dist/semantic-convention.js +51 -8
  193. package/dist/semantic-convention.js.map +1 -1
  194. package/dist/types.d.ts +74 -22
  195. package/package.json +41 -9
@@ -0,0 +1,1031 @@
1
+ "use strict";
2
+ /**
3
+ * Claude Agent SDK wrapper — OTel GenAI semantic convention compliant.
4
+ *
5
+ * Wraps the `query()` async generator to produce `invoke_agent`, `execute_tool`,
6
+ * and `chat` child spans. Tool spans are created via SDK hooks (PreToolUse /
7
+ * PostToolUse / PostToolUseFailure). A message-based fallback handles cases
8
+ * where hooks cannot be injected.
9
+ *
10
+ * Mirrors the Python SDK instrumentation in
11
+ * sdk/python/src/openlit/instrumentation/claude_agent_sdk/.
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ var __importDefault = (this && this.__importDefault) || function (mod) {
47
+ return (mod && mod.__esModule) ? mod : { "default": mod };
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.patchQuery = patchQuery;
51
+ const api_1 = require("@opentelemetry/api");
52
+ const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
53
+ const semantic_convention_1 = __importDefault(require("../../semantic-convention"));
54
+ const config_1 = __importDefault(require("../../config"));
55
+ const helpers_1 = __importStar(require("../../helpers"));
56
+ const constant_1 = require("../../constant");
57
+ const metrics_1 = __importDefault(require("../../otel/metrics"));
58
+ // ---------------------------------------------------------------------------
59
+ // Constants
60
+ // ---------------------------------------------------------------------------
61
+ const [SERVER_ADDRESS, SERVER_PORT] = (0, helpers_1.getServerAddressForProvider)('anthropic');
62
+ const GEN_AI_SYSTEM_ATTR = 'gen_ai.system';
63
+ const GEN_AI_SYSTEM_VALUE = 'anthropic';
64
+ const ANTHROPIC_FINISH_REASON_MAP = {
65
+ end_turn: 'stop',
66
+ max_tokens: 'length',
67
+ stop_sequence: 'stop',
68
+ tool_use: 'tool_call',
69
+ };
70
+ const OPERATION_MAP = {
71
+ query: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT,
72
+ execute_tool: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_TOOLS,
73
+ subagent: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT,
74
+ chat: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
75
+ create_agent: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CREATE_AGENT,
76
+ };
77
+ // ---------------------------------------------------------------------------
78
+ // Helpers
79
+ // ---------------------------------------------------------------------------
80
+ function truncateContent(content) {
81
+ const maxLen = config_1.default.maxContentLength;
82
+ if (maxLen != null && maxLen > 0 && content.length > maxLen) {
83
+ return content.slice(0, maxLen);
84
+ }
85
+ return content;
86
+ }
87
+ function mapFinishReason(rawReason) {
88
+ if (!rawReason)
89
+ return 'stop';
90
+ return ANTHROPIC_FINISH_REASON_MAP[rawReason] || rawReason;
91
+ }
92
+ function resolveAgentName(options) {
93
+ if (!options)
94
+ return null;
95
+ for (const key of ['agent_name', 'agentName', 'name']) {
96
+ const val = options[key];
97
+ if (val && typeof val === 'string' && val.trim())
98
+ return val.trim();
99
+ }
100
+ return null;
101
+ }
102
+ function generateSpanName(endpoint, entityName) {
103
+ const operation = OPERATION_MAP[endpoint] || semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT;
104
+ if (entityName)
105
+ return `${operation} ${entityName}`;
106
+ return operation;
107
+ }
108
+ function extractUsage(usage) {
109
+ const attrs = {};
110
+ if (!usage)
111
+ return attrs;
112
+ const rawInput = parseInt(usage.input_tokens, 10) || 0;
113
+ const outputTokens = parseInt(usage.output_tokens, 10);
114
+ if (!isNaN(outputTokens)) {
115
+ attrs[semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS] = outputTokens;
116
+ }
117
+ let cacheReadInt = 0;
118
+ const cacheRead = usage.cache_read_input_tokens;
119
+ if (cacheRead != null) {
120
+ cacheReadInt = parseInt(cacheRead, 10) || 0;
121
+ if (cacheReadInt) {
122
+ attrs[semantic_convention_1.default.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] = cacheReadInt;
123
+ }
124
+ }
125
+ let cacheCreationInt = 0;
126
+ const cacheCreation = usage.cache_creation_input_tokens ?? usage.cache_write_input_tokens;
127
+ if (cacheCreation != null) {
128
+ cacheCreationInt = parseInt(cacheCreation, 10) || 0;
129
+ if (cacheCreationInt) {
130
+ attrs[semantic_convention_1.default.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] = cacheCreationInt;
131
+ }
132
+ }
133
+ attrs[semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS] = rawInput + cacheReadInt + cacheCreationInt;
134
+ return attrs;
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // ToolSpanTracker — manages in-flight tool spans created by SDK hooks
138
+ // ---------------------------------------------------------------------------
139
+ class ToolSpanTracker {
140
+ constructor(tracer, parentSpan, captureContent) {
141
+ this._inFlight = new Map();
142
+ this._completed = new Set();
143
+ this._tracer = tracer;
144
+ this._parentSpan = parentSpan;
145
+ this._captureContent = captureContent;
146
+ }
147
+ startTool(toolName, toolInput, toolUseId) {
148
+ const spanName = generateSpanName('execute_tool', toolName);
149
+ const parentCtx = api_1.trace.setSpan(api_1.context.active(), this._parentSpan);
150
+ const span = this._tracer.startSpan(spanName, {
151
+ kind: api_1.SpanKind.INTERNAL,
152
+ attributes: {
153
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_TOOLS,
154
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_CLAUDE_AGENT_SDK,
155
+ },
156
+ }, parentCtx);
157
+ setToolSpanAttributes(span, toolName, toolInput, toolUseId, this._captureContent);
158
+ this._inFlight.set(toolUseId, span);
159
+ }
160
+ endTool(toolUseId, toolResponse) {
161
+ const span = this._inFlight.get(toolUseId);
162
+ if (!span)
163
+ return;
164
+ this._inFlight.delete(toolUseId);
165
+ finalizeToolSpan(span, toolResponse, this._captureContent);
166
+ span.end();
167
+ this._completed.add(toolUseId);
168
+ }
169
+ endToolError(toolUseId, error) {
170
+ const span = this._inFlight.get(toolUseId);
171
+ if (!span)
172
+ return;
173
+ this._inFlight.delete(toolUseId);
174
+ finalizeToolSpan(span, null, this._captureContent, true, error);
175
+ span.end();
176
+ this._completed.add(toolUseId);
177
+ }
178
+ endAll() {
179
+ for (const [_toolUseId, span] of this._inFlight) {
180
+ finalizeToolSpan(span, null, this._captureContent, true, 'abandoned');
181
+ span.end();
182
+ }
183
+ this._inFlight.clear();
184
+ }
185
+ }
186
+ // ---------------------------------------------------------------------------
187
+ // SubagentSpanTracker — manages subagent spans for Task tool
188
+ // ---------------------------------------------------------------------------
189
+ class SubagentSpanTracker {
190
+ constructor(tracer, toolTracker) {
191
+ this._inFlight = new Map();
192
+ this._toolUseToTask = new Map();
193
+ this._tracer = tracer;
194
+ this._toolTracker = toolTracker;
195
+ }
196
+ startSubagent(taskId, description, toolUseId) {
197
+ const name = description || taskId || 'subagent';
198
+ const spanName = generateSpanName('subagent', name);
199
+ if (toolUseId) {
200
+ this._toolUseToTask.set(toolUseId, taskId);
201
+ }
202
+ let parentSpan;
203
+ if (toolUseId) {
204
+ parentSpan = this._toolTracker._inFlight.get(toolUseId);
205
+ }
206
+ const ctx = parentSpan ? api_1.trace.setSpan(api_1.context.active(), parentSpan) : undefined;
207
+ const span = this._tracer.startSpan(spanName, {
208
+ kind: api_1.SpanKind.INTERNAL,
209
+ attributes: {
210
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT,
211
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_CLAUDE_AGENT_SDK,
212
+ },
213
+ }, ctx);
214
+ span.setAttribute(GEN_AI_SYSTEM_ATTR, GEN_AI_SYSTEM_VALUE);
215
+ span.setAttribute(semantic_convention_1.default.GEN_AI_AGENT_NAME, String(name));
216
+ span.setAttribute(semantic_convention_1.default.ATTR_DEPLOYMENT_ENVIRONMENT, config_1.default.environment ?? 'default');
217
+ span.setAttribute(semantic_conventions_1.ATTR_SERVICE_NAME, config_1.default.applicationName ?? 'default');
218
+ span.setAttribute(semantic_convention_1.default.GEN_AI_SDK_VERSION, constant_1.SDK_VERSION);
219
+ this._inFlight.set(taskId, span);
220
+ }
221
+ endSubagent(taskId, isError = false, errorMessage, usage) {
222
+ const span = this._inFlight.get(taskId);
223
+ if (!span)
224
+ return;
225
+ this._inFlight.delete(taskId);
226
+ if (usage) {
227
+ if (usage.total_tokens != null) {
228
+ span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, Number(usage.total_tokens) || 0);
229
+ }
230
+ if (usage.tool_uses != null) {
231
+ span.setAttribute('gen_ai.agent.tool_uses', Number(usage.tool_uses) || 0);
232
+ }
233
+ if (usage.duration_ms != null) {
234
+ span.setAttribute('gen_ai.agent.duration_ms', Number(usage.duration_ms) || 0);
235
+ }
236
+ }
237
+ if (isError) {
238
+ const err = errorMessage ? String(errorMessage) : 'task failed';
239
+ span.setAttribute(semantic_convention_1.default.ERROR_TYPE, 'SubagentError');
240
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err });
241
+ }
242
+ else {
243
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
244
+ }
245
+ span.end();
246
+ }
247
+ getSpanForToolUseId(toolUseId) {
248
+ const taskId = this._toolUseToTask.get(toolUseId);
249
+ return taskId ? this._inFlight.get(taskId) : undefined;
250
+ }
251
+ endAll() {
252
+ for (const taskId of this._inFlight.keys()) {
253
+ this.endSubagent(taskId, true, 'abandoned');
254
+ }
255
+ }
256
+ }
257
+ // ---------------------------------------------------------------------------
258
+ // Tool span attributes
259
+ // ---------------------------------------------------------------------------
260
+ function setToolSpanAttributes(span, toolName, toolInput, toolUseId, captureContent) {
261
+ span.setAttribute(GEN_AI_SYSTEM_ATTR, GEN_AI_SYSTEM_VALUE);
262
+ span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_NAME, String(toolName));
263
+ const toolType = String(toolName).startsWith('mcp__') ? 'extension' : 'function';
264
+ span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_TYPE, toolType);
265
+ if (toolUseId) {
266
+ span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_CALL_ID, String(toolUseId));
267
+ }
268
+ span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, SERVER_ADDRESS);
269
+ span.setAttribute(semantic_convention_1.default.SERVER_PORT, SERVER_PORT);
270
+ span.setAttribute(semantic_convention_1.default.ATTR_DEPLOYMENT_ENVIRONMENT, config_1.default.environment ?? 'default');
271
+ span.setAttribute(semantic_conventions_1.ATTR_SERVICE_NAME, config_1.default.applicationName ?? 'default');
272
+ span.setAttribute(semantic_convention_1.default.GEN_AI_SDK_VERSION, constant_1.SDK_VERSION);
273
+ if (captureContent && toolInput != null) {
274
+ try {
275
+ const argsStr = typeof toolInput === 'string' ? toolInput : JSON.stringify(toolInput);
276
+ span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_CALL_ARGUMENTS, truncateContent(argsStr));
277
+ }
278
+ catch { /* ignore */ }
279
+ }
280
+ (0, helpers_1.applyCustomSpanAttributes)(span);
281
+ }
282
+ function finalizeToolSpan(span, toolResponse, captureContent, isError = false, errorMessage) {
283
+ if (isError) {
284
+ const errMsg = errorMessage ? String(errorMessage) : 'tool execution failed';
285
+ span.setAttribute(semantic_convention_1.default.ERROR_TYPE, 'ToolExecutionError');
286
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: errMsg });
287
+ }
288
+ else {
289
+ if (captureContent && toolResponse != null) {
290
+ span.setAttribute(semantic_convention_1.default.GEN_AI_TOOL_CALL_RESULT, truncateContent(String(toolResponse)));
291
+ }
292
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
293
+ }
294
+ }
295
+ // ---------------------------------------------------------------------------
296
+ // Hook injection — merges OpenLIT hooks into user-provided options
297
+ // ---------------------------------------------------------------------------
298
+ function injectHooks(options, toolTracker, subagentTracker) {
299
+ if (!options.hooks) {
300
+ options.hooks = {};
301
+ }
302
+ const preToolUse = async (input, toolUseId) => {
303
+ try {
304
+ const toolName = input.tool_name || 'unknown';
305
+ const toolInput = input.tool_input;
306
+ const id = toolUseId || input.tool_use_id;
307
+ if (id)
308
+ toolTracker.startTool(toolName, toolInput, id);
309
+ }
310
+ catch { /* swallow */ }
311
+ return {};
312
+ };
313
+ const postToolUse = async (input, toolUseId) => {
314
+ try {
315
+ const toolResponse = input.tool_response;
316
+ const id = toolUseId || input.tool_use_id;
317
+ if (id)
318
+ toolTracker.endTool(id, toolResponse);
319
+ }
320
+ catch { /* swallow */ }
321
+ return {};
322
+ };
323
+ const postToolUseFailure = async (input, toolUseId) => {
324
+ try {
325
+ const error = input.error || 'unknown error';
326
+ const id = toolUseId || input.tool_use_id;
327
+ if (id)
328
+ toolTracker.endToolError(id, error);
329
+ }
330
+ catch { /* swallow */ }
331
+ return {};
332
+ };
333
+ const subagentStart = async (input, toolUseId) => {
334
+ try {
335
+ const agentId = input.agent_id;
336
+ if (agentId) {
337
+ const description = input.description || agentId;
338
+ subagentTracker.startSubagent(agentId, description, toolUseId ?? undefined);
339
+ }
340
+ }
341
+ catch { /* swallow */ }
342
+ return {};
343
+ };
344
+ const subagentStop = async (input) => {
345
+ try {
346
+ const agentId = input.agent_id;
347
+ if (!agentId)
348
+ return {};
349
+ const error = input.error;
350
+ subagentTracker.endSubagent(agentId, !!error, error);
351
+ }
352
+ catch { /* swallow */ }
353
+ return {};
354
+ };
355
+ const hookPairs = [
356
+ ['PreToolUse', preToolUse],
357
+ ['PostToolUse', postToolUse],
358
+ ['PostToolUseFailure', postToolUseFailure],
359
+ ['SubagentStart', subagentStart],
360
+ ['SubagentStop', subagentStop],
361
+ ];
362
+ for (const [event, callback] of hookPairs) {
363
+ const matcher = { hooks: [callback] };
364
+ if (options.hooks[event]) {
365
+ options.hooks[event].push(matcher);
366
+ }
367
+ else {
368
+ options.hooks[event] = [matcher];
369
+ }
370
+ }
371
+ }
372
+ function hasLlmCallData(msg) {
373
+ return msg.message?.model != null && msg.message?.usage != null;
374
+ }
375
+ function bufferChatMessage(sdkMsg, chatState) {
376
+ if (!hasLlmCallData(sdkMsg))
377
+ return;
378
+ chatState.pendingChatMsg = sdkMsg;
379
+ chatState.pendingChatMsgId = sdkMsg.message?.id;
380
+ chatState.pendingStartMs = chatState.lastBoundaryMs;
381
+ chatState.pendingEndMs = Date.now();
382
+ }
383
+ function flushPendingChat(tracer, parentSpan, chatState, captureContent, subagentTracker) {
384
+ const sdkMsg = chatState.pendingChatMsg;
385
+ if (!sdkMsg)
386
+ return;
387
+ delete chatState.pendingChatMsg;
388
+ delete chatState.pendingChatMsgId;
389
+ const endMs = chatState.pendingEndMs ?? Date.now();
390
+ const savedStartMs = chatState.pendingStartMs;
391
+ delete chatState.pendingStartMs;
392
+ delete chatState.pendingEndMs;
393
+ const betaMessage = sdkMsg.message;
394
+ const model = String(betaMessage?.model || 'unknown');
395
+ const spanName = generateSpanName('chat', model);
396
+ let effectiveParent = parentSpan;
397
+ const parentToolUseId = sdkMsg.parent_tool_use_id;
398
+ if (parentToolUseId) {
399
+ const subagentSpan = subagentTracker.getSpanForToolUseId(parentToolUseId);
400
+ if (subagentSpan)
401
+ effectiveParent = subagentSpan;
402
+ }
403
+ const parentCtx = api_1.trace.setSpan(api_1.context.active(), effectiveParent);
404
+ const startMs = savedStartMs ?? chatState.lastBoundaryMs ?? endMs;
405
+ const chatSpan = tracer.startSpan(spanName, {
406
+ kind: api_1.SpanKind.CLIENT,
407
+ attributes: {
408
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
409
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_ANTHROPIC,
410
+ },
411
+ startTime: new Date(startMs),
412
+ }, parentCtx);
413
+ const inputMessages = chatState.pendingInput;
414
+ delete chatState.pendingInput;
415
+ setChatSpanAttributes(chatSpan, sdkMsg, captureContent, inputMessages);
416
+ chatSpan.end(new Date(endMs));
417
+ chatState.lastBoundaryMs = endMs;
418
+ }
419
+ // ---------------------------------------------------------------------------
420
+ // Chat span attributes
421
+ // ---------------------------------------------------------------------------
422
+ function setChatSpanAttributes(span, sdkMsg, captureContent, inputMessages) {
423
+ try {
424
+ const betaMessage = sdkMsg.message;
425
+ const model = betaMessage?.model ? String(betaMessage.model) : null;
426
+ span.setAttribute(GEN_AI_SYSTEM_ATTR, GEN_AI_SYSTEM_VALUE);
427
+ span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, SERVER_ADDRESS);
428
+ span.setAttribute(semantic_convention_1.default.SERVER_PORT, SERVER_PORT);
429
+ span.setAttribute(semantic_conventions_1.ATTR_TELEMETRY_SDK_NAME, constant_1.SDK_NAME);
430
+ span.setAttribute(semantic_convention_1.default.ATTR_DEPLOYMENT_ENVIRONMENT, config_1.default.environment ?? 'default');
431
+ span.setAttribute(semantic_conventions_1.ATTR_SERVICE_NAME, config_1.default.applicationName ?? 'default');
432
+ span.setAttribute(semantic_convention_1.default.GEN_AI_SDK_VERSION, constant_1.SDK_VERSION);
433
+ if (model) {
434
+ span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_MODEL, model);
435
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, model);
436
+ }
437
+ const usage = betaMessage?.usage;
438
+ const usageAttrs = usage ? extractUsage(usage) : {};
439
+ for (const [key, value] of Object.entries(usageAttrs)) {
440
+ span.setAttribute(key, value);
441
+ }
442
+ let stopReason = betaMessage?.stop_reason;
443
+ if (!stopReason) {
444
+ const content = betaMessage?.content;
445
+ if (Array.isArray(content)) {
446
+ for (const block of content) {
447
+ if (block.type === 'tool_use') {
448
+ stopReason = 'tool_use';
449
+ break;
450
+ }
451
+ }
452
+ }
453
+ }
454
+ const mappedReason = mapFinishReason(stopReason);
455
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, [mappedReason]);
456
+ const messageId = betaMessage?.id;
457
+ if (messageId) {
458
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, String(messageId));
459
+ }
460
+ const sessionId = sdkMsg.session_id;
461
+ if (sessionId) {
462
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CONVERSATION_ID, String(sessionId));
463
+ }
464
+ const inputTokens = usageAttrs[semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS] ?? 0;
465
+ const outputTokens = usageAttrs[semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS] ?? 0;
466
+ const pricingInfo = config_1.default.pricingInfo || {};
467
+ const cost = model ? helpers_1.default.getChatModelCost(model, pricingInfo, inputTokens, outputTokens) : 0;
468
+ span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_COST, cost);
469
+ let outputMessages = null;
470
+ if (captureContent) {
471
+ if (inputMessages) {
472
+ span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, JSON.stringify(inputMessages));
473
+ }
474
+ outputMessages = buildOutputMessages(betaMessage, mappedReason);
475
+ if (outputMessages) {
476
+ span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, JSON.stringify(outputMessages));
477
+ }
478
+ }
479
+ (0, helpers_1.applyCustomSpanAttributes)(span);
480
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
481
+ if (captureContent) {
482
+ emitChatInferenceEvent(span, model, messageId, sessionId, mappedReason, usageAttrs, inputMessages, outputMessages);
483
+ }
484
+ if (!config_1.default.disableMetrics) {
485
+ recordChatMetrics(model, inputTokens, outputTokens, cost);
486
+ }
487
+ }
488
+ catch { /* swallow */ }
489
+ }
490
+ // ---------------------------------------------------------------------------
491
+ // Build OTel-compliant output messages from BetaMessage content blocks
492
+ // ---------------------------------------------------------------------------
493
+ function buildOutputMessages(betaMessage, mappedFinishReason) {
494
+ try {
495
+ const content = betaMessage?.content;
496
+ if (!content || !Array.isArray(content))
497
+ return null;
498
+ const parts = [];
499
+ for (const block of content) {
500
+ if (block.type === 'text') {
501
+ if (block.text) {
502
+ parts.push({ type: 'text', content: truncateContent(String(block.text)) });
503
+ }
504
+ }
505
+ else if (block.type === 'thinking') {
506
+ if (block.thinking) {
507
+ parts.push({ type: 'reasoning', content: truncateContent(String(block.thinking)) });
508
+ }
509
+ }
510
+ else if (block.type === 'tool_use') {
511
+ let toolInput = block.input || {};
512
+ if (typeof toolInput !== 'object') {
513
+ try {
514
+ toolInput = JSON.parse(String(toolInput));
515
+ }
516
+ catch {
517
+ toolInput = {};
518
+ }
519
+ }
520
+ parts.push({
521
+ type: 'tool_call',
522
+ id: String(block.id || ''),
523
+ name: String(block.name || 'unknown'),
524
+ arguments: toolInput,
525
+ });
526
+ }
527
+ }
528
+ if (parts.length === 0)
529
+ return null;
530
+ return [{ role: 'assistant', parts, finish_reason: mappedFinishReason }];
531
+ }
532
+ catch {
533
+ return null;
534
+ }
535
+ }
536
+ // ---------------------------------------------------------------------------
537
+ // Build OTel input from UserMessage tool results
538
+ // ---------------------------------------------------------------------------
539
+ function buildInputFromToolResults(sdkMsg) {
540
+ try {
541
+ const messageParam = sdkMsg.message;
542
+ const content = messageParam?.content;
543
+ if (!content || !Array.isArray(content))
544
+ return null;
545
+ const parts = [];
546
+ for (const block of content) {
547
+ if (block.type === 'tool_result') {
548
+ const toolUseId = block.tool_use_id;
549
+ let resultContent = block.content;
550
+ if (Array.isArray(resultContent)) {
551
+ resultContent = resultContent.map((c) => c.text || JSON.stringify(c)).join('');
552
+ }
553
+ parts.push({
554
+ type: 'tool_call_response',
555
+ id: toolUseId ? String(toolUseId) : '',
556
+ response: resultContent ? truncateContent(String(resultContent)) : '',
557
+ });
558
+ }
559
+ }
560
+ if (parts.length === 0)
561
+ return null;
562
+ return [{ role: 'user', parts }];
563
+ }
564
+ catch {
565
+ return null;
566
+ }
567
+ }
568
+ // ---------------------------------------------------------------------------
569
+ // Emit gen_ai.client.inference.operation.details event for chat spans
570
+ // ---------------------------------------------------------------------------
571
+ function emitChatInferenceEvent(span, model, messageId, sessionId, mappedReason, usageAttrs, inputMessages, outputMessages) {
572
+ if (config_1.default.disableEvents)
573
+ return;
574
+ try {
575
+ const attributes = {
576
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
577
+ [semantic_convention_1.default.SERVER_ADDRESS]: SERVER_ADDRESS,
578
+ [semantic_convention_1.default.SERVER_PORT]: SERVER_PORT,
579
+ };
580
+ if (model) {
581
+ attributes[semantic_convention_1.default.GEN_AI_REQUEST_MODEL] = model;
582
+ attributes[semantic_convention_1.default.GEN_AI_RESPONSE_MODEL] = model;
583
+ }
584
+ if (messageId) {
585
+ attributes[semantic_convention_1.default.GEN_AI_RESPONSE_ID] = String(messageId);
586
+ }
587
+ if (sessionId) {
588
+ attributes[semantic_convention_1.default.GEN_AI_CONVERSATION_ID] = String(sessionId);
589
+ }
590
+ if (mappedReason) {
591
+ attributes[semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON] = [mappedReason];
592
+ }
593
+ for (const [key, value] of Object.entries(usageAttrs)) {
594
+ attributes[key] = value;
595
+ }
596
+ if (inputMessages != null) {
597
+ attributes[semantic_convention_1.default.GEN_AI_INPUT_MESSAGES] = inputMessages;
598
+ }
599
+ if (outputMessages != null) {
600
+ attributes[semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES] = outputMessages;
601
+ }
602
+ helpers_1.default.emitInferenceEvent(span, attributes);
603
+ }
604
+ catch { /* swallow */ }
605
+ }
606
+ // ---------------------------------------------------------------------------
607
+ // Chat metrics
608
+ // ---------------------------------------------------------------------------
609
+ function recordChatMetrics(model, inputTokens, outputTokens, cost) {
610
+ try {
611
+ const attributes = {
612
+ [semantic_conventions_1.ATTR_TELEMETRY_SDK_NAME]: constant_1.SDK_NAME,
613
+ [semantic_conventions_1.ATTR_SERVICE_NAME]: config_1.default.applicationName ?? 'default',
614
+ [semantic_convention_1.default.ATTR_DEPLOYMENT_ENVIRONMENT]: config_1.default.environment ?? 'default',
615
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_ANTHROPIC,
616
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
617
+ [semantic_convention_1.default.SERVER_ADDRESS]: SERVER_ADDRESS,
618
+ [semantic_convention_1.default.SERVER_PORT]: SERVER_PORT,
619
+ };
620
+ if (model) {
621
+ attributes[semantic_convention_1.default.GEN_AI_REQUEST_MODEL] = model;
622
+ }
623
+ if (inputTokens && metrics_1.default.genaiClientUsageTokens) {
624
+ metrics_1.default.genaiClientUsageTokens.record(inputTokens, {
625
+ ...attributes,
626
+ [semantic_convention_1.default.GEN_AI_TOKEN_TYPE]: semantic_convention_1.default.GEN_AI_TOKEN_TYPE_INPUT,
627
+ });
628
+ }
629
+ if (outputTokens && metrics_1.default.genaiClientUsageTokens) {
630
+ metrics_1.default.genaiClientUsageTokens.record(outputTokens, {
631
+ ...attributes,
632
+ [semantic_convention_1.default.GEN_AI_TOKEN_TYPE]: semantic_convention_1.default.GEN_AI_TOKEN_TYPE_OUTPUT,
633
+ });
634
+ }
635
+ if (cost && metrics_1.default.genaiCost) {
636
+ metrics_1.default.genaiCost.record(cost, attributes);
637
+ }
638
+ }
639
+ catch { /* swallow */ }
640
+ }
641
+ // ---------------------------------------------------------------------------
642
+ // Process result message — finalize root span with usage/cost data
643
+ // ---------------------------------------------------------------------------
644
+ function processResultMessage(span, sdkMsg, captureContent) {
645
+ const resultUsage = { inputTokens: 0, outputTokens: 0 };
646
+ try {
647
+ const sessionId = sdkMsg.session_id;
648
+ if (sessionId) {
649
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CONVERSATION_ID, String(sessionId));
650
+ }
651
+ const usage = sdkMsg.usage;
652
+ if (usage) {
653
+ const usageAttrs = extractUsage(usage);
654
+ for (const [key, value] of Object.entries(usageAttrs)) {
655
+ span.setAttribute(key, value);
656
+ }
657
+ resultUsage.inputTokens = usageAttrs[semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS] ?? 0;
658
+ resultUsage.outputTokens = usageAttrs[semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS] ?? 0;
659
+ }
660
+ const totalCost = sdkMsg.total_cost_usd;
661
+ if (totalCost != null) {
662
+ span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_COST, Number(totalCost) || 0);
663
+ }
664
+ const modelUsage = sdkMsg.modelUsage;
665
+ if (modelUsage && typeof modelUsage === 'object') {
666
+ const modelNames = Object.keys(modelUsage);
667
+ if (modelNames.length > 0) {
668
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, String(modelNames[0]));
669
+ }
670
+ }
671
+ if (sdkMsg.num_turns != null) {
672
+ span.setAttribute('gen_ai.agent.num_turns', Number(sdkMsg.num_turns) || 0);
673
+ }
674
+ if (sdkMsg.duration_ms != null) {
675
+ span.setAttribute('gen_ai.agent.duration_ms', Number(sdkMsg.duration_ms) || 0);
676
+ }
677
+ if (sdkMsg.duration_api_ms != null) {
678
+ span.setAttribute('gen_ai.agent.duration_api_ms', Number(sdkMsg.duration_api_ms) || 0);
679
+ }
680
+ if (sdkMsg.is_error) {
681
+ const errResult = sdkMsg.errors?.join('; ') || sdkMsg.result || 'unknown error';
682
+ span.setAttribute(semantic_convention_1.default.ERROR_TYPE, 'AgentError');
683
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: String(errResult) });
684
+ }
685
+ else {
686
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
687
+ }
688
+ if (captureContent) {
689
+ const result = sdkMsg.result;
690
+ if (result) {
691
+ span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, JSON.stringify([{
692
+ role: 'assistant',
693
+ parts: [{ type: 'text', content: truncateContent(String(result)) }],
694
+ }]));
695
+ }
696
+ }
697
+ }
698
+ catch { /* swallow */ }
699
+ return resultUsage;
700
+ }
701
+ // ---------------------------------------------------------------------------
702
+ // Message stream processor
703
+ // ---------------------------------------------------------------------------
704
+ function processMessage(sdkMsg, span, toolTracker, subagentTracker, captureContent, tracer, chatState) {
705
+ const msgType = sdkMsg.type;
706
+ let resultUsage = null;
707
+ if (msgType === 'assistant') {
708
+ updateRootFromAssistant(span, sdkMsg);
709
+ if (hasLlmCallData(sdkMsg)) {
710
+ const newMsgId = sdkMsg.message?.id;
711
+ const pendingMsgId = chatState.pendingChatMsgId;
712
+ if (pendingMsgId != null && newMsgId !== pendingMsgId) {
713
+ flushPendingChat(tracer, span, chatState, captureContent, subagentTracker);
714
+ }
715
+ bufferChatMessage(sdkMsg, chatState);
716
+ }
717
+ }
718
+ else if (msgType === 'user') {
719
+ flushPendingChat(tracer, span, chatState, captureContent, subagentTracker);
720
+ if (captureContent) {
721
+ const toolInput = buildInputFromToolResults(sdkMsg);
722
+ if (toolInput) {
723
+ chatState.pendingInput = toolInput;
724
+ }
725
+ }
726
+ }
727
+ else if (msgType === 'result') {
728
+ flushPendingChat(tracer, span, chatState, captureContent, subagentTracker);
729
+ resultUsage = processResultMessage(span, sdkMsg, captureContent);
730
+ }
731
+ else if (msgType === 'system' && sdkMsg.subtype === 'task_started') {
732
+ flushPendingChat(tracer, span, chatState, captureContent, subagentTracker);
733
+ try {
734
+ const taskId = sdkMsg.task_id;
735
+ const description = sdkMsg.description;
736
+ const toolUseId = sdkMsg.tool_use_id;
737
+ if (taskId) {
738
+ subagentTracker.startSubagent(taskId, description, toolUseId);
739
+ }
740
+ }
741
+ catch { /* swallow */ }
742
+ }
743
+ else if (msgType === 'system' && sdkMsg.subtype === 'task_notification') {
744
+ flushPendingChat(tracer, span, chatState, captureContent, subagentTracker);
745
+ try {
746
+ const taskId = sdkMsg.task_id;
747
+ const status = sdkMsg.status;
748
+ const isError = status === 'failed' || status === 'stopped';
749
+ const errorMsg = isError ? sdkMsg.summary : null;
750
+ const taskUsage = sdkMsg.usage;
751
+ if (taskId) {
752
+ subagentTracker.endSubagent(taskId, isError, errorMsg, taskUsage);
753
+ }
754
+ }
755
+ catch { /* swallow */ }
756
+ }
757
+ chatState.lastBoundaryMs = Date.now();
758
+ return resultUsage;
759
+ }
760
+ function updateRootFromAssistant(span, sdkMsg) {
761
+ try {
762
+ const model = sdkMsg.message?.model;
763
+ if (model) {
764
+ span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_MODEL, String(model));
765
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, String(model));
766
+ }
767
+ const sessionId = sdkMsg.session_id;
768
+ if (sessionId) {
769
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CONVERSATION_ID, String(sessionId));
770
+ }
771
+ }
772
+ catch { /* swallow */ }
773
+ }
774
+ // ---------------------------------------------------------------------------
775
+ // Message-based tool span fallback (when hooks don't fire)
776
+ // ---------------------------------------------------------------------------
777
+ function processToolBlocksFromMessages(sdkMsg, toolTracker, subagentTracker) {
778
+ const msgType = sdkMsg.type;
779
+ if (msgType === 'assistant') {
780
+ const content = sdkMsg.message?.content;
781
+ if (!content || !Array.isArray(content))
782
+ return;
783
+ const parentToolUseId = sdkMsg.parent_tool_use_id;
784
+ let effectiveParent;
785
+ if (parentToolUseId) {
786
+ effectiveParent = subagentTracker.getSpanForToolUseId(parentToolUseId);
787
+ }
788
+ for (const block of content) {
789
+ if (block.type === 'tool_use') {
790
+ const toolName = block.name || 'unknown';
791
+ const toolInput = block.input;
792
+ const toolId = block.id;
793
+ if (toolId && !toolTracker._inFlight.has(toolId) && !toolTracker._completed.has(toolId)) {
794
+ if (effectiveParent) {
795
+ const spanName = generateSpanName('execute_tool', toolName);
796
+ const parentCtx = api_1.trace.setSpan(api_1.context.active(), effectiveParent);
797
+ const span = toolTracker['_tracer'].startSpan(spanName, {
798
+ kind: api_1.SpanKind.INTERNAL,
799
+ attributes: {
800
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_TOOLS,
801
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_CLAUDE_AGENT_SDK,
802
+ },
803
+ }, parentCtx);
804
+ setToolSpanAttributes(span, toolName, toolInput, toolId, config_1.default.captureMessageContent ?? true);
805
+ toolTracker._inFlight.set(toolId, span);
806
+ }
807
+ else {
808
+ toolTracker.startTool(toolName, toolInput, toolId);
809
+ }
810
+ }
811
+ }
812
+ }
813
+ }
814
+ else if (msgType === 'user') {
815
+ const content = sdkMsg.message?.content;
816
+ if (!content || !Array.isArray(content))
817
+ return;
818
+ for (const block of content) {
819
+ if (block.type === 'tool_result') {
820
+ const toolUseId = block.tool_use_id;
821
+ const isError = block.is_error;
822
+ const resultContent = block.content;
823
+ if (toolUseId && toolTracker._inFlight.has(toolUseId)) {
824
+ if (isError) {
825
+ toolTracker.endToolError(toolUseId, resultContent);
826
+ }
827
+ else {
828
+ toolTracker.endTool(toolUseId, resultContent);
829
+ }
830
+ }
831
+ }
832
+ }
833
+ }
834
+ }
835
+ // ---------------------------------------------------------------------------
836
+ // Set initial span attributes on the root invoke_agent span
837
+ // ---------------------------------------------------------------------------
838
+ function setInitialSpanAttributes(span, options, prompt, captureContent) {
839
+ try {
840
+ span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT);
841
+ span.setAttribute(semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL, semantic_convention_1.default.GEN_AI_SYSTEM_CLAUDE_AGENT_SDK);
842
+ span.setAttribute(GEN_AI_SYSTEM_ATTR, GEN_AI_SYSTEM_VALUE);
843
+ span.setAttribute(semantic_conventions_1.ATTR_TELEMETRY_SDK_NAME, constant_1.SDK_NAME);
844
+ span.setAttribute(semantic_convention_1.default.ATTR_DEPLOYMENT_ENVIRONMENT, config_1.default.environment ?? 'default');
845
+ span.setAttribute(semantic_conventions_1.ATTR_SERVICE_NAME, config_1.default.applicationName ?? 'default');
846
+ span.setAttribute(semantic_convention_1.default.GEN_AI_SDK_VERSION, constant_1.SDK_VERSION);
847
+ span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, SERVER_ADDRESS);
848
+ span.setAttribute(semantic_convention_1.default.SERVER_PORT, SERVER_PORT);
849
+ const agentName = resolveAgentName(options);
850
+ if (agentName) {
851
+ span.setAttribute(semantic_convention_1.default.GEN_AI_AGENT_NAME, agentName);
852
+ }
853
+ const model = options?.model;
854
+ if (model) {
855
+ span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_MODEL, String(model));
856
+ }
857
+ if (captureContent) {
858
+ const systemPrompt = options?.systemPrompt;
859
+ if (systemPrompt && typeof systemPrompt === 'string') {
860
+ span.setAttribute(semantic_convention_1.default.GEN_AI_SYSTEM_INSTRUCTIONS, JSON.stringify([{ type: 'text', content: truncateContent(systemPrompt) }]));
861
+ }
862
+ if (prompt && typeof prompt === 'string') {
863
+ span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, JSON.stringify([{
864
+ role: 'user',
865
+ parts: [{ type: 'text', content: truncateContent(prompt) }],
866
+ }]));
867
+ }
868
+ }
869
+ (0, helpers_1.applyCustomSpanAttributes)(span);
870
+ }
871
+ catch { /* swallow */ }
872
+ }
873
+ // ---------------------------------------------------------------------------
874
+ // Finalize root span — record duration and token usage metrics
875
+ // ---------------------------------------------------------------------------
876
+ function finalizeSpan(span, startTime, inputTokens, outputTokens) {
877
+ try {
878
+ const duration = (Date.now() / 1000) - startTime;
879
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
880
+ if (!config_1.default.disableMetrics) {
881
+ const attributes = {
882
+ [semantic_conventions_1.ATTR_TELEMETRY_SDK_NAME]: constant_1.SDK_NAME,
883
+ [semantic_conventions_1.ATTR_SERVICE_NAME]: config_1.default.applicationName ?? 'default',
884
+ [semantic_convention_1.default.ATTR_DEPLOYMENT_ENVIRONMENT]: config_1.default.environment ?? 'default',
885
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_CLAUDE_AGENT_SDK,
886
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT,
887
+ [GEN_AI_SYSTEM_ATTR]: GEN_AI_SYSTEM_VALUE,
888
+ [semantic_convention_1.default.SERVER_ADDRESS]: SERVER_ADDRESS,
889
+ [semantic_convention_1.default.SERVER_PORT]: SERVER_PORT,
890
+ };
891
+ if (metrics_1.default.genaiClientOperationDuration) {
892
+ metrics_1.default.genaiClientOperationDuration.record(duration, attributes);
893
+ }
894
+ if (inputTokens && metrics_1.default.genaiClientUsageTokens) {
895
+ metrics_1.default.genaiClientUsageTokens.record(inputTokens, {
896
+ ...attributes,
897
+ [semantic_convention_1.default.GEN_AI_TOKEN_TYPE]: semantic_convention_1.default.GEN_AI_TOKEN_TYPE_INPUT,
898
+ });
899
+ }
900
+ if (outputTokens && metrics_1.default.genaiClientUsageTokens) {
901
+ metrics_1.default.genaiClientUsageTokens.record(outputTokens, {
902
+ ...attributes,
903
+ [semantic_convention_1.default.GEN_AI_TOKEN_TYPE]: semantic_convention_1.default.GEN_AI_TOKEN_TYPE_OUTPUT,
904
+ });
905
+ }
906
+ }
907
+ }
908
+ catch { /* swallow */ }
909
+ }
910
+ // ---------------------------------------------------------------------------
911
+ // patchQuery — wraps the `query()` export from @anthropic-ai/claude-agent-sdk
912
+ // ---------------------------------------------------------------------------
913
+ function patchQuery(tracer) {
914
+ return (originalQuery) => {
915
+ return function wrappedQuery(params) {
916
+ const captureContent = config_1.default.captureMessageContent ?? true;
917
+ const prompt = params.prompt;
918
+ const userOptions = params.options;
919
+ const options = userOptions ? { ...userOptions } : {};
920
+ const agentName = resolveAgentName(options);
921
+ const spanName = generateSpanName('query', agentName);
922
+ const span = tracer.startSpan(spanName, {
923
+ kind: api_1.SpanKind.INTERNAL,
924
+ attributes: {
925
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_AGENT,
926
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: semantic_convention_1.default.GEN_AI_SYSTEM_CLAUDE_AGENT_SDK,
927
+ },
928
+ });
929
+ const spanContext = api_1.trace.setSpan(api_1.context.active(), span);
930
+ const startTime = Date.now() / 1000;
931
+ const chatState = { lastBoundaryMs: Date.now() };
932
+ const toolTracker = new ToolSpanTracker(tracer, span, captureContent);
933
+ const subagentTracker = new SubagentSpanTracker(tracer, toolTracker);
934
+ const aggregateUsage = { inputTokens: 0, outputTokens: 0 };
935
+ if (prompt && typeof prompt === 'string' && captureContent) {
936
+ chatState.pendingInput = [{
937
+ role: 'user',
938
+ parts: [{ type: 'text', content: truncateContent(prompt) }],
939
+ }];
940
+ }
941
+ injectHooks(options, toolTracker, subagentTracker);
942
+ setInitialSpanAttributes(span, options, prompt, captureContent);
943
+ (0, helpers_1.setFrameworkLlmActive)();
944
+ let query;
945
+ try {
946
+ query = api_1.context.with(spanContext, () => {
947
+ return originalQuery.call(this, { prompt, options });
948
+ });
949
+ }
950
+ catch (e) {
951
+ (0, helpers_1.resetFrameworkLlmActive)();
952
+ helpers_1.default.handleException(span, e);
953
+ span.end();
954
+ throw e;
955
+ }
956
+ let done = false;
957
+ const cleanup = () => {
958
+ if (done)
959
+ return;
960
+ done = true;
961
+ (0, helpers_1.resetFrameworkLlmActive)();
962
+ subagentTracker.endAll();
963
+ toolTracker.endAll();
964
+ finalizeSpan(span, startTime, aggregateUsage.inputTokens, aggregateUsage.outputTokens);
965
+ span.end();
966
+ };
967
+ const originalNext = query.next.bind(query);
968
+ const originalReturn = query.return?.bind(query);
969
+ const originalThrow = query.throw?.bind(query);
970
+ return new Proxy(query, {
971
+ get(target, prop, receiver) {
972
+ if (prop === 'next') {
973
+ return async function (...args) {
974
+ try {
975
+ const result = await originalNext(...args);
976
+ if (result.done) {
977
+ if (!done) {
978
+ flushPendingChat(tracer, span, chatState, captureContent, subagentTracker);
979
+ if (aggregateUsage.inputTokens === 0 && aggregateUsage.outputTokens === 0) {
980
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
981
+ }
982
+ }
983
+ cleanup();
984
+ return result;
985
+ }
986
+ const sdkMsg = result.value;
987
+ try {
988
+ const msgUsage = processMessage(sdkMsg, span, toolTracker, subagentTracker, captureContent, tracer, chatState);
989
+ if (msgUsage) {
990
+ aggregateUsage.inputTokens = msgUsage.inputTokens;
991
+ aggregateUsage.outputTokens = msgUsage.outputTokens;
992
+ }
993
+ processToolBlocksFromMessages(sdkMsg, toolTracker, subagentTracker);
994
+ }
995
+ catch { /* swallow processing errors */ }
996
+ return result;
997
+ }
998
+ catch (e) {
999
+ if (!done) {
1000
+ helpers_1.default.handleException(span, e);
1001
+ }
1002
+ cleanup();
1003
+ throw e;
1004
+ }
1005
+ };
1006
+ }
1007
+ if (prop === 'return') {
1008
+ return async function (value) {
1009
+ cleanup();
1010
+ return originalReturn ? originalReturn(value) : { done: true, value };
1011
+ };
1012
+ }
1013
+ if (prop === 'throw') {
1014
+ return async function (e) {
1015
+ if (!done) {
1016
+ helpers_1.default.handleException(span, e instanceof Error ? e : new Error(String(e)));
1017
+ }
1018
+ cleanup();
1019
+ return originalThrow ? originalThrow(e) : { done: true, value: undefined };
1020
+ };
1021
+ }
1022
+ if (prop === Symbol.asyncIterator) {
1023
+ return function () { return receiver; };
1024
+ }
1025
+ return Reflect.get(target, prop, receiver);
1026
+ },
1027
+ });
1028
+ };
1029
+ };
1030
+ }
1031
+ //# sourceMappingURL=wrapper.js.map