@traceroot-ai/traceroot 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export declare function wireClaudeAgentSDKInstrumentation(mod: unknown): void;
2
+ //# sourceMappingURL=claude-agent-sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-agent-sdk.d.ts","sourceRoot":"","sources":["../src/claude-agent-sdk.ts"],"names":[],"mappings":"AAm1BA,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAgBpE"}
@@ -0,0 +1,678 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wireClaudeAgentSDKInstrumentation = wireClaudeAgentSDKInstrumentation;
4
+ const api_1 = require("@opentelemetry/api");
5
+ const constants_1 = require("./constants");
6
+ // Use the global symbol registry so duplicated package copies still avoid double wrapping.
7
+ const WRAPPED = Symbol.for('traceroot.claude_agent_sdk.wrapped');
8
+ const ROOT_LLM_PARENT_KEY = '__root__';
9
+ const LLM_SPAN_NAME = 'anthropic.messages.create';
10
+ const QUERY_SPAN_NAME = 'ClaudeAgent.query';
11
+ const OI_SPAN_KIND_VALUE = {
12
+ AGENT: 'AGENT',
13
+ LLM: 'LLM',
14
+ TOOL: 'TOOL',
15
+ };
16
+ const LLM_TOKEN_ATTRIBUTES = {
17
+ TOTAL: 'llm.token_count.total',
18
+ CACHE_READ: 'llm.token_count.prompt_details.cache_read',
19
+ CACHE_CREATION: 'llm.token_count.prompt_details.cache_creation',
20
+ };
21
+ const GEN_AI_ATTRIBUTES = {
22
+ RESPONSE_MODEL: 'gen_ai.response.model',
23
+ TOOL_CALL_ID: 'gen_ai.tool.call.id',
24
+ TOOL_NAME: 'gen_ai.tool.name',
25
+ };
26
+ const CLAUDE_AGENT_ATTRIBUTES = {
27
+ AGENT_ID: 'claude_agent_sdk.agent_id',
28
+ AGENT_TYPE: 'claude_agent_sdk.agent_type',
29
+ CWD: 'claude_agent_sdk.cwd',
30
+ DURATION_MS: 'claude_agent_sdk.duration_ms',
31
+ MODEL: 'claude_agent_sdk.model',
32
+ NUM_TURNS: 'claude_agent_sdk.num_turns',
33
+ TOOL_USE_COUNT: 'claude_agent_sdk.tool_use_count',
34
+ TOOL_USE_ID: 'claude_agent_sdk.tool_use_id',
35
+ TOTAL_COST_USD: 'claude_agent_sdk.total_cost_usd',
36
+ };
37
+ function tryStringify(value) {
38
+ if (value === undefined)
39
+ return undefined;
40
+ if (typeof value === 'string')
41
+ return value;
42
+ try {
43
+ return JSON.stringify(value);
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ }
49
+ function setJsonAttribute(span, key, value) {
50
+ const serialized = tryStringify(value);
51
+ if (serialized !== undefined)
52
+ span.setAttribute(key, serialized);
53
+ }
54
+ function getToolUseId(input, toolUseId) {
55
+ return toolUseId ?? (typeof input.tool_use_id === 'string' ? input.tool_use_id : undefined);
56
+ }
57
+ function getString(input, key) {
58
+ const value = input[key];
59
+ return typeof value === 'string' ? value : undefined;
60
+ }
61
+ function getNumber(input, key) {
62
+ const value = input[key];
63
+ return typeof value === 'number' ? value : undefined;
64
+ }
65
+ function getUsage(message) {
66
+ return message.message?.usage ?? message.usage;
67
+ }
68
+ function setUsageAttributes(span, usage) {
69
+ if (!usage)
70
+ return;
71
+ const cacheRead = usage.cache_read_input_tokens ?? 0;
72
+ const cacheCreation = usage.cache_creation_input_tokens ?? 0;
73
+ const prompt = (usage.input_tokens ?? 0) + cacheRead + cacheCreation;
74
+ const completion = usage.output_tokens ?? 0;
75
+ if (prompt > 0)
76
+ span.setAttribute(constants_1.OI_LLM_TOKEN_COUNT_PROMPT, prompt);
77
+ if (completion > 0)
78
+ span.setAttribute(constants_1.OI_LLM_TOKEN_COUNT_COMPLETION, completion);
79
+ if (prompt > 0 || completion > 0) {
80
+ span.setAttribute(LLM_TOKEN_ATTRIBUTES.TOTAL, prompt + completion);
81
+ }
82
+ if (cacheRead > 0) {
83
+ span.setAttribute(LLM_TOKEN_ATTRIBUTES.CACHE_READ, cacheRead);
84
+ }
85
+ if (cacheCreation > 0) {
86
+ span.setAttribute(LLM_TOKEN_ATTRIBUTES.CACHE_CREATION, cacheCreation);
87
+ }
88
+ }
89
+ function setCommonModel(span, model) {
90
+ if (!model)
91
+ return;
92
+ span.setAttribute(constants_1.OI_LLM_MODEL_NAME, model);
93
+ span.setAttribute(GEN_AI_ATTRIBUTES.RESPONSE_MODEL, model);
94
+ }
95
+ function getMessageModel(message, options) {
96
+ return message.message?.model ?? options?.model;
97
+ }
98
+ function llmParentKey(parentToolUseId) {
99
+ return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
100
+ }
101
+ function isTaskSiblingTool(toolName) {
102
+ return toolName === 'Agent' || toolName === 'Task' || toolName === 'Bash';
103
+ }
104
+ function getParentToolUseIdForTool(state, toolUseId, input) {
105
+ if (state.toolUseToParent.has(toolUseId)) {
106
+ return state.toolUseToParent.get(toolUseId) ?? null;
107
+ }
108
+ const agentId = getString(input, 'agent_id');
109
+ if (!agentId)
110
+ return null;
111
+ return state.agentIdToToolUseId.get(agentId) ?? null;
112
+ }
113
+ function getToolParentContext(state, input) {
114
+ const agentId = getString(input, 'agent_id');
115
+ const subagentToolUseId = agentId ? state.agentIdToToolUseId.get(agentId) : undefined;
116
+ const subagent = subagentToolUseId ? state.subagents.get(subagentToolUseId) : undefined;
117
+ return subagent?.ctx ?? state.ctx;
118
+ }
119
+ function getTaskParentContext(state, parentToolUseId) {
120
+ if (parentToolUseId) {
121
+ return state.subagents.get(parentToolUseId)?.ctx ?? state.ctx;
122
+ }
123
+ return state.ctx;
124
+ }
125
+ function ensureActiveLLMSpan(state, parentToolUseId, startTime) {
126
+ const parentKey = llmParentKey(parentToolUseId);
127
+ const existing = state.activeLLMSpansByParent.get(parentKey);
128
+ if (existing)
129
+ return existing;
130
+ const parentCtx = getTaskParentContext(state, parentToolUseId);
131
+ const span = state.tracer.startSpan(LLM_SPAN_NAME, {
132
+ attributes: {
133
+ [constants_1.OI_SPAN_KIND]: OI_SPAN_KIND_VALUE.LLM,
134
+ },
135
+ startTime,
136
+ }, parentCtx);
137
+ const llm = { ctx: api_1.trace.setSpan(parentCtx, span), span };
138
+ state.activeLLMSpansByParent.set(parentKey, llm);
139
+ return llm;
140
+ }
141
+ function resolveToolParentContext(state, toolUseId, toolName, input) {
142
+ const parentToolUseId = getParentToolUseIdForTool(state, toolUseId, input);
143
+ if (isTaskSiblingTool(toolName)) {
144
+ return getTaskParentContext(state, parentToolUseId);
145
+ }
146
+ const parentKey = llmParentKey(parentToolUseId);
147
+ const activeLLM = state.activeLLMSpansByParent.get(parentKey);
148
+ // Claude hook events can arrive before the assistant message that creates the
149
+ // LLM turn span. In that case, keep the tool under the task/subagent context.
150
+ return activeLLM?.ctx ?? getToolParentContext(state, input);
151
+ }
152
+ function findActiveAgentToolUseId(state) {
153
+ for (const tool of state.tools.values()) {
154
+ if (tool.name === 'Agent' && !tool.hasSubagent)
155
+ return tool.toolUseId;
156
+ }
157
+ return undefined;
158
+ }
159
+ function canonicalSubagentToolUseId(state, rawToolUseId, input) {
160
+ const existing = state.rawSubagentToolUseIdToToolUseId.get(rawToolUseId);
161
+ if (existing)
162
+ return existing;
163
+ if (state.tools.has(rawToolUseId)) {
164
+ state.rawSubagentToolUseIdToToolUseId.set(rawToolUseId, rawToolUseId);
165
+ return rawToolUseId;
166
+ }
167
+ const agentId = input ? getString(input, 'agent_id') : undefined;
168
+ const agentToolUseId = agentId ? state.agentIdToToolUseId.get(agentId) : undefined;
169
+ if (agentToolUseId) {
170
+ state.rawSubagentToolUseIdToToolUseId.set(rawToolUseId, agentToolUseId);
171
+ return agentToolUseId;
172
+ }
173
+ const activeAgentToolUseId = findActiveAgentToolUseId(state);
174
+ if (activeAgentToolUseId) {
175
+ state.rawSubagentToolUseIdToToolUseId.set(rawToolUseId, activeAgentToolUseId);
176
+ return activeAgentToolUseId;
177
+ }
178
+ state.rawSubagentToolUseIdToToolUseId.set(rawToolUseId, rawToolUseId);
179
+ return rawToolUseId;
180
+ }
181
+ function ensureSubagent(state, toolUseId, input) {
182
+ const existing = state.subagents.get(toolUseId);
183
+ if (existing)
184
+ return existing;
185
+ const toolState = state.tools.get(toolUseId);
186
+ if (toolState)
187
+ toolState.hasSubagent = true;
188
+ const parentCtx = toolState?.ctx ?? state.ctx;
189
+ const span = state.tracer.startSpan('Subagent', {
190
+ attributes: {
191
+ [constants_1.OI_SPAN_KIND]: OI_SPAN_KIND_VALUE.AGENT,
192
+ ...(input && getString(input, 'agent_type')
193
+ ? { [CLAUDE_AGENT_ATTRIBUTES.AGENT_TYPE]: getString(input, 'agent_type') }
194
+ : {}),
195
+ [CLAUDE_AGENT_ATTRIBUTES.TOOL_USE_ID]: toolUseId,
196
+ },
197
+ }, parentCtx);
198
+ const stateEntry = {
199
+ agentId: input ? getString(input, 'agent_id') : undefined,
200
+ ctx: api_1.trace.setSpan(parentCtx, span),
201
+ span,
202
+ toolUseId,
203
+ };
204
+ state.subagents.set(toolUseId, stateEntry);
205
+ if (stateEntry.agentId)
206
+ state.agentIdToToolUseId.set(stateEntry.agentId, toolUseId);
207
+ return stateEntry;
208
+ }
209
+ function cleanupToolUseMappings(state, rawToolUseId, toolUseId) {
210
+ state.toolUseToParent.delete(rawToolUseId);
211
+ state.toolUseToParent.delete(toolUseId);
212
+ state.rawSubagentToolUseIdToToolUseId.delete(rawToolUseId);
213
+ }
214
+ function cleanupSubagentMappings(state, subagent) {
215
+ if (subagent.agentId)
216
+ state.agentIdToToolUseId.delete(subagent.agentId);
217
+ }
218
+ function createTracingHooks(state) {
219
+ const preToolUse = async (input, toolUseIdArg) => {
220
+ if (input.hook_event_name !== 'PreToolUse')
221
+ return {};
222
+ const now = new Date();
223
+ const toolUseId = getToolUseId(input, toolUseIdArg);
224
+ const toolName = getString(input, 'tool_name');
225
+ if (!toolUseId || !toolName)
226
+ return {};
227
+ const startTime = now;
228
+ const parentCtx = resolveToolParentContext(state, toolUseId, toolName, input);
229
+ const span = state.tracer.startSpan(toolName, {
230
+ attributes: {
231
+ [constants_1.OI_SPAN_KIND]: OI_SPAN_KIND_VALUE.TOOL,
232
+ [constants_1.TOOL_NAME]: toolName,
233
+ [GEN_AI_ATTRIBUTES.TOOL_NAME]: toolName,
234
+ [GEN_AI_ATTRIBUTES.TOOL_CALL_ID]: toolUseId,
235
+ ...(getString(input, 'cwd')
236
+ ? { [CLAUDE_AGENT_ATTRIBUTES.CWD]: getString(input, 'cwd') }
237
+ : {}),
238
+ ...(getString(input, 'session_id')
239
+ ? { [constants_1.OI_TRACE_SESSION_ID]: getString(input, 'session_id') }
240
+ : {}),
241
+ },
242
+ startTime,
243
+ }, parentCtx);
244
+ setJsonAttribute(span, constants_1.OI_INPUT_VALUE, input.tool_input);
245
+ state.tools.set(toolUseId, {
246
+ ctx: api_1.trace.setSpan(parentCtx, span),
247
+ hasSubagent: false,
248
+ name: toolName,
249
+ span,
250
+ toolUseId,
251
+ });
252
+ return {};
253
+ };
254
+ const postToolUse = async (input, toolUseIdArg) => {
255
+ if (input.hook_event_name !== 'PostToolUse')
256
+ return {};
257
+ const now = new Date();
258
+ const rawToolUseId = getToolUseId(input, toolUseIdArg);
259
+ if (!rawToolUseId)
260
+ return {};
261
+ const toolUseId = state.tools.has(rawToolUseId)
262
+ ? rawToolUseId
263
+ : canonicalSubagentToolUseId(state, rawToolUseId, input);
264
+ const tool = state.tools.get(toolUseId);
265
+ if (tool) {
266
+ setJsonAttribute(tool.span, constants_1.OI_OUTPUT_VALUE, input.tool_response);
267
+ tool.span.setStatus({ code: api_1.SpanStatusCode.OK });
268
+ tool.span.end(now);
269
+ state.tools.delete(toolUseId);
270
+ cleanupToolUseMappings(state, rawToolUseId, toolUseId);
271
+ }
272
+ const subagent = state.subagents.get(toolUseId);
273
+ const response = input.tool_response;
274
+ if (subagent && !subagent.ended && response && typeof response === 'object') {
275
+ const record = response;
276
+ const agentType = getString(record, 'agentType');
277
+ if (agentType)
278
+ subagent.span.setAttribute(CLAUDE_AGENT_ATTRIBUTES.AGENT_TYPE, agentType);
279
+ const agentId = getString(record, 'agentId');
280
+ if (agentId)
281
+ subagent.span.setAttribute(CLAUDE_AGENT_ATTRIBUTES.AGENT_ID, agentId);
282
+ const durationMs = getNumber(record, 'totalDurationMs');
283
+ if (durationMs !== undefined)
284
+ subagent.span.setAttribute(CLAUDE_AGENT_ATTRIBUTES.DURATION_MS, durationMs);
285
+ const toolUseCount = getNumber(record, 'totalToolUseCount');
286
+ if (toolUseCount !== undefined) {
287
+ subagent.span.setAttribute(CLAUDE_AGENT_ATTRIBUTES.TOOL_USE_COUNT, toolUseCount);
288
+ }
289
+ setJsonAttribute(subagent.span, constants_1.OI_OUTPUT_VALUE, record.content);
290
+ subagent.span.setStatus({ code: api_1.SpanStatusCode.OK });
291
+ subagent.span.end(now);
292
+ subagent.ended = true;
293
+ cleanupSubagentMappings(state, subagent);
294
+ }
295
+ return {};
296
+ };
297
+ const postToolUseFailure = async (input, toolUseIdArg) => {
298
+ if (input.hook_event_name !== 'PostToolUseFailure')
299
+ return {};
300
+ const now = new Date();
301
+ const rawToolUseId = getToolUseId(input, toolUseIdArg);
302
+ if (!rawToolUseId)
303
+ return {};
304
+ const toolUseId = state.tools.has(rawToolUseId)
305
+ ? rawToolUseId
306
+ : canonicalSubagentToolUseId(state, rawToolUseId, input);
307
+ const error = getString(input, 'error') ?? 'Tool failed';
308
+ const tool = state.tools.get(toolUseId);
309
+ if (tool) {
310
+ tool.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error });
311
+ tool.span.recordException(new Error(error));
312
+ tool.span.end(now);
313
+ state.tools.delete(toolUseId);
314
+ cleanupToolUseMappings(state, rawToolUseId, toolUseId);
315
+ }
316
+ const subagent = state.subagents.get(toolUseId);
317
+ if (subagent && !subagent.ended) {
318
+ subagent.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error });
319
+ subagent.span.recordException(new Error(error));
320
+ subagent.span.end(now);
321
+ subagent.ended = true;
322
+ cleanupSubagentMappings(state, subagent);
323
+ }
324
+ return {};
325
+ };
326
+ const subagentStart = async (input, toolUseIdArg) => {
327
+ if (input.hook_event_name !== 'SubagentStart')
328
+ return {};
329
+ const rawToolUseId = getToolUseId(input, toolUseIdArg);
330
+ if (!rawToolUseId)
331
+ return {};
332
+ const toolUseId = canonicalSubagentToolUseId(state, rawToolUseId, input);
333
+ const subagent = ensureSubagent(state, toolUseId, input);
334
+ const agentId = getString(input, 'agent_id');
335
+ if (agentId) {
336
+ subagent.agentId = agentId;
337
+ state.agentIdToToolUseId.set(agentId, toolUseId);
338
+ subagent.span.setAttribute(CLAUDE_AGENT_ATTRIBUTES.AGENT_ID, agentId);
339
+ }
340
+ const agentType = getString(input, 'agent_type');
341
+ if (agentType)
342
+ subagent.span.setAttribute(CLAUDE_AGENT_ATTRIBUTES.AGENT_TYPE, agentType);
343
+ return {};
344
+ };
345
+ const subagentStop = async (input, toolUseIdArg) => {
346
+ if (input.hook_event_name !== 'SubagentStop')
347
+ return {};
348
+ const now = new Date();
349
+ const rawToolUseId = getToolUseId(input, toolUseIdArg);
350
+ if (!rawToolUseId)
351
+ return {};
352
+ const toolUseId = canonicalSubagentToolUseId(state, rawToolUseId, input);
353
+ const subagent = state.subagents.get(toolUseId);
354
+ if (!subagent || subagent.ended)
355
+ return {};
356
+ const output = input.last_assistant_message;
357
+ if (output !== undefined)
358
+ setJsonAttribute(subagent.span, constants_1.OI_OUTPUT_VALUE, output);
359
+ subagent.span.setStatus({ code: api_1.SpanStatusCode.OK });
360
+ subagent.span.end(now);
361
+ subagent.ended = true;
362
+ cleanupSubagentMappings(state, subagent);
363
+ return {};
364
+ };
365
+ return {
366
+ PostToolUse: [{ hooks: [postToolUse] }],
367
+ PostToolUseFailure: [{ hooks: [postToolUseFailure] }],
368
+ PreToolUse: [{ hooks: [preToolUse] }],
369
+ SubagentStart: [{ hooks: [subagentStart] }],
370
+ SubagentStop: [{ hooks: [subagentStop] }],
371
+ };
372
+ }
373
+ function mergeHooks(options, hooks) {
374
+ const existing = options?.hooks ?? {};
375
+ const merged = { ...existing };
376
+ for (const [event, matchers] of Object.entries(hooks)) {
377
+ merged[event] = [...(existing[event] ?? []), ...matchers];
378
+ }
379
+ return { ...(options ?? {}), hooks: merged };
380
+ }
381
+ function trackToolUseContext(state, message) {
382
+ if (message.type !== 'assistant' || !Array.isArray(message.message?.content))
383
+ return;
384
+ const parentToolUseId = message.parent_tool_use_id ?? null;
385
+ for (const block of message.message.content) {
386
+ if (!block || typeof block !== 'object')
387
+ continue;
388
+ const record = block;
389
+ if (record.type !== 'tool_use' || typeof record.id !== 'string')
390
+ continue;
391
+ state.toolUseToParent.set(record.id, parentToolUseId);
392
+ }
393
+ }
394
+ function emitLLMSpan(state, messages, endTime) {
395
+ if (messages.length === 0)
396
+ return;
397
+ const firstMessage = messages[0];
398
+ const lastMessage = messages[messages.length - 1];
399
+ if (firstMessage.type !== 'assistant' || !lastMessage.message)
400
+ return;
401
+ const parentToolUseId = firstMessage.parent_tool_use_id ?? null;
402
+ const parentKey = llmParentKey(parentToolUseId);
403
+ const activeLLM = ensureActiveLLMSpan(state, parentToolUseId, state.currentMessageStartTime);
404
+ const model = getMessageModel(lastMessage, state.params.options);
405
+ const span = activeLLM.span;
406
+ setCommonModel(span, model);
407
+ setUsageAttributes(span, getUsage(lastMessage));
408
+ if (!firstMessage.parent_tool_use_id) {
409
+ if (typeof state.params.prompt === 'string') {
410
+ setJsonAttribute(span, constants_1.OI_INPUT_VALUE, [{ role: 'user', content: state.params.prompt }]);
411
+ }
412
+ }
413
+ const output = messages
414
+ .map((message) => message.message?.content !== undefined || message.message?.role !== undefined
415
+ ? {
416
+ role: message.message?.role ?? 'assistant',
417
+ content: message.message?.content,
418
+ }
419
+ : undefined)
420
+ .filter((message) => message !== undefined);
421
+ if (output.length > 0) {
422
+ setJsonAttribute(span, constants_1.OI_OUTPUT_VALUE, output);
423
+ }
424
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
425
+ span.end(endTime);
426
+ state.activeLLMSpansByParent.delete(parentKey);
427
+ state.accumulatedOutputTokens += getUsage(lastMessage)?.output_tokens ?? 0;
428
+ state.currentMessageStartTime = endTime;
429
+ }
430
+ function flushPendingLLMSpan(state, endTime = new Date()) {
431
+ if (state.pendingAssistantMessages.length === 0)
432
+ return;
433
+ emitLLMSpan(state, state.pendingAssistantMessages, endTime);
434
+ state.pendingAssistantMessages = [];
435
+ }
436
+ function shouldFlushBeforeAssistantMessage(state, message) {
437
+ const pending = state.pendingAssistantMessages;
438
+ if (pending.length === 0)
439
+ return false;
440
+ const first = pending[0];
441
+ const nextMessageId = message.message?.id;
442
+ if (nextMessageId && nextMessageId !== state.currentMessageId)
443
+ return true;
444
+ return (first.parent_tool_use_id !== message.parent_tool_use_id ||
445
+ getMessageModel(first, state.params.options) !== getMessageModel(message, state.params.options));
446
+ }
447
+ function updateCurrentMessageId(state, message) {
448
+ const messageId = message.message?.id;
449
+ if (messageId)
450
+ state.currentMessageId = messageId;
451
+ }
452
+ function adjustPendingAssistantUsageFromResult(state, resultMessage) {
453
+ if (state.pendingAssistantMessages.length === 0)
454
+ return;
455
+ const finalUsage = getUsage(resultMessage);
456
+ if (!finalUsage)
457
+ return;
458
+ const finalOutputTokens = finalUsage?.output_tokens;
459
+ if (finalOutputTokens === undefined)
460
+ return;
461
+ const lastMessage = state.pendingAssistantMessages[state.pendingAssistantMessages.length - 1];
462
+ const lastUsage = lastMessage?.message?.usage;
463
+ if (!lastUsage)
464
+ return;
465
+ const remainingOutputTokens = finalOutputTokens - state.accumulatedOutputTokens;
466
+ if (remainingOutputTokens >= 0) {
467
+ lastUsage.output_tokens = remainingOutputTokens;
468
+ }
469
+ if (finalUsage.cache_read_input_tokens !== undefined) {
470
+ lastUsage.cache_read_input_tokens = finalUsage.cache_read_input_tokens;
471
+ }
472
+ if (finalUsage.cache_creation_input_tokens !== undefined) {
473
+ lastUsage.cache_creation_input_tokens = finalUsage.cache_creation_input_tokens;
474
+ }
475
+ }
476
+ function processMessage(state, message, params) {
477
+ trackToolUseContext(state, message);
478
+ if (message.type === 'system' && message.subtype === 'init') {
479
+ const model = typeof message.model === 'string' ? message.model : params.options?.model;
480
+ if (model)
481
+ state.querySpan.setAttribute(CLAUDE_AGENT_ATTRIBUTES.MODEL, model);
482
+ if (typeof message.session_id === 'string') {
483
+ state.querySpan.setAttribute(constants_1.OI_TRACE_SESSION_ID, message.session_id);
484
+ }
485
+ return;
486
+ }
487
+ if (message.type === 'assistant') {
488
+ const now = new Date();
489
+ const messageId = message.message?.id;
490
+ if (messageId && messageId !== state.currentMessageId) {
491
+ flushPendingLLMSpan(state, now);
492
+ state.currentMessageId = messageId;
493
+ state.currentMessageStartTime = now;
494
+ }
495
+ else if (shouldFlushBeforeAssistantMessage(state, message)) {
496
+ flushPendingLLMSpan(state, now);
497
+ updateCurrentMessageId(state, message);
498
+ }
499
+ else {
500
+ updateCurrentMessageId(state, message);
501
+ }
502
+ if (message.message?.usage) {
503
+ ensureActiveLLMSpan(state, message.parent_tool_use_id ?? null, state.currentMessageStartTime);
504
+ }
505
+ state.pendingAssistantMessages.push(message);
506
+ return;
507
+ }
508
+ if (message.type === 'result') {
509
+ const now = new Date();
510
+ adjustPendingAssistantUsageFromResult(state, message);
511
+ flushPendingLLMSpan(state, now);
512
+ if (typeof message.result === 'string') {
513
+ state.querySpan.setAttribute(constants_1.OI_OUTPUT_VALUE, message.result);
514
+ }
515
+ if (typeof message.session_id === 'string') {
516
+ state.querySpan.setAttribute(constants_1.OI_TRACE_SESSION_ID, message.session_id);
517
+ }
518
+ if (typeof message.num_turns === 'number') {
519
+ state.querySpan.setAttribute(CLAUDE_AGENT_ATTRIBUTES.NUM_TURNS, message.num_turns);
520
+ }
521
+ if (typeof message.total_cost_usd === 'number') {
522
+ state.querySpan.setAttribute(CLAUDE_AGENT_ATTRIBUTES.TOTAL_COST_USD, message.total_cost_usd);
523
+ }
524
+ }
525
+ }
526
+ function endInFlight(state, status) {
527
+ const now = new Date();
528
+ flushPendingLLMSpan(state, now);
529
+ for (const tool of state.tools.values()) {
530
+ if (status)
531
+ tool.span.setStatus(status);
532
+ tool.span.end(now);
533
+ }
534
+ state.tools.clear();
535
+ for (const subagent of state.subagents.values()) {
536
+ if (!subagent.ended) {
537
+ if (status)
538
+ subagent.span.setStatus(status);
539
+ subagent.span.end(now);
540
+ subagent.ended = true;
541
+ }
542
+ }
543
+ state.subagents.clear();
544
+ state.activeLLMSpansByParent.clear();
545
+ state.agentIdToToolUseId.clear();
546
+ state.rawSubagentToolUseIdToToolUseId.clear();
547
+ state.toolUseToParent.clear();
548
+ }
549
+ function wrapQuery(original) {
550
+ const tracer = api_1.trace.getTracer('@traceroot-ai/claude-agent-sdk');
551
+ return function wrappedQuery(params) {
552
+ const parentCtx = api_1.context.active();
553
+ return {
554
+ [Symbol.asyncIterator]() {
555
+ const querySpan = tracer.startSpan(QUERY_SPAN_NAME, {
556
+ attributes: {
557
+ [constants_1.OI_SPAN_KIND]: OI_SPAN_KIND_VALUE.AGENT,
558
+ ...(params.options?.model
559
+ ? { [CLAUDE_AGENT_ATTRIBUTES.MODEL]: params.options.model }
560
+ : {}),
561
+ },
562
+ }, parentCtx);
563
+ if (typeof params.prompt === 'string')
564
+ querySpan.setAttribute(constants_1.OI_INPUT_VALUE, params.prompt);
565
+ const state = {
566
+ accumulatedOutputTokens: 0,
567
+ activeLLMSpansByParent: new Map(),
568
+ agentIdToToolUseId: new Map(),
569
+ currentMessageStartTime: new Date(),
570
+ ctx: api_1.trace.setSpan(parentCtx, querySpan),
571
+ params,
572
+ pendingAssistantMessages: [],
573
+ querySpan,
574
+ rawSubagentToolUseIdToToolUseId: new Map(),
575
+ subagents: new Map(),
576
+ toolUseToParent: new Map(),
577
+ tools: new Map(),
578
+ tracer,
579
+ };
580
+ const modifiedParams = {
581
+ ...params,
582
+ options: mergeHooks(params.options, createTracingHooks(state)),
583
+ };
584
+ let finished = false;
585
+ const finish = (status = { code: api_1.SpanStatusCode.OK }, error) => {
586
+ if (finished)
587
+ return;
588
+ finished = true;
589
+ endInFlight(state, status);
590
+ if (error !== undefined) {
591
+ querySpan.recordException(error instanceof Error ? error : new Error(String(error)));
592
+ }
593
+ querySpan.setStatus(status);
594
+ querySpan.end();
595
+ };
596
+ let inner;
597
+ try {
598
+ inner = original(modifiedParams)[Symbol.asyncIterator]();
599
+ }
600
+ catch (error) {
601
+ const message = error instanceof Error ? error.message : String(error);
602
+ finish({ code: api_1.SpanStatusCode.ERROR, message }, error);
603
+ throw error;
604
+ }
605
+ return {
606
+ async next() {
607
+ try {
608
+ const result = await api_1.context.with(state.ctx, () => inner.next());
609
+ if (!result.done) {
610
+ processMessage(state, result.value, params);
611
+ }
612
+ else {
613
+ finish();
614
+ }
615
+ return result;
616
+ }
617
+ catch (error) {
618
+ const message = error instanceof Error ? error.message : String(error);
619
+ finish({ code: api_1.SpanStatusCode.ERROR, message }, error);
620
+ throw error;
621
+ }
622
+ },
623
+ async return(value) {
624
+ if (finished)
625
+ return { done: true, value: undefined };
626
+ try {
627
+ const result = inner.return
628
+ ? await inner.return(value)
629
+ : { done: true, value: undefined };
630
+ finish();
631
+ return result;
632
+ }
633
+ catch (error) {
634
+ const message = error instanceof Error ? error.message : String(error);
635
+ finish({ code: api_1.SpanStatusCode.ERROR, message }, error);
636
+ throw error;
637
+ }
638
+ },
639
+ async throw(error) {
640
+ const message = error instanceof Error ? error.message : String(error);
641
+ if (finished)
642
+ throw error;
643
+ try {
644
+ if (inner.throw) {
645
+ const result = await inner.throw(error);
646
+ finish({ code: api_1.SpanStatusCode.ERROR, message }, error);
647
+ return result;
648
+ }
649
+ finish({ code: api_1.SpanStatusCode.ERROR, message }, error);
650
+ throw error;
651
+ }
652
+ catch (thrown) {
653
+ const thrownMessage = thrown instanceof Error ? thrown.message : String(thrown);
654
+ finish({ code: api_1.SpanStatusCode.ERROR, message: thrownMessage }, thrown);
655
+ throw thrown;
656
+ }
657
+ },
658
+ };
659
+ },
660
+ };
661
+ };
662
+ }
663
+ function wireClaudeAgentSDKInstrumentation(mod) {
664
+ const sdk = mod;
665
+ if (!sdk || typeof sdk !== 'object' || typeof sdk.query !== 'function') {
666
+ throw new Error('[TraceRoot] instrumentModules.claudeAgentSDK does not expose query. ' +
667
+ 'Pass a mutable module namespace, e.g. `{ ...claudeAgentSDK }`.');
668
+ }
669
+ if (sdk[WRAPPED])
670
+ return;
671
+ sdk.query = wrapQuery(sdk.query);
672
+ Object.defineProperty(sdk, WRAPPED, {
673
+ configurable: false,
674
+ enumerable: false,
675
+ value: true,
676
+ });
677
+ }
678
+ //# sourceMappingURL=claude-agent-sdk.js.map