Skip to content

Commit c485ac1

Browse files
committed
fix(telemetry): address review feedback from wenshao
- Add debugLogger.warn in catch blocks of endLLMRequestSpan/endToolSpan/ endToolExecutionSpan instead of silent swallowing - Add JSDoc on endToolSpan documenting intentional no-metadata-no-status contract with setToolSpanFailure/setToolSpanCancelled - Add warning in startToolExecutionSpan when called outside runInToolSpanContext (no active toolContext) - Sanitize error message in endToolExecutionSpan: use constant TOOL_SPAN_STATUS_TOOL_EXCEPTION instead of raw error message
1 parent 34d7ab9 commit c485ac1

2 files changed

Lines changed: 31 additions & 22 deletions

File tree

packages/core/src/core/coreToolScheduler.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,9 +1898,7 @@ export class CoreToolScheduler {
18981898
const toolUseId = generateToolUseId();
18991899

19001900
// Get MessageBus for hook execution
1901-
const messageBus = this.config.getMessageBus() as
1902-
| MessageBus
1903-
| undefined;
1901+
const messageBus = this.config.getMessageBus() as MessageBus | undefined;
19041902
const hooksEnabled = !this.config.getDisableAllHooks();
19051903

19061904
// PreToolUse Hook
@@ -2092,10 +2090,7 @@ export class CoreToolScheduler {
20922090
? toolResult.resultFilePaths
20932091
: [];
20942092
const candidatePaths = Array.from(
2095-
new Set([
2096-
...inputPaths.map((p) => unescapePath(p)),
2097-
...resultPaths,
2098-
]),
2093+
new Set([...inputPaths.map((p) => unescapePath(p)), ...resultPaths]),
20992094
);
21002095

21012096
if (candidatePaths.length > 0) {
@@ -2137,9 +2132,7 @@ export class CoreToolScheduler {
21372132
// and would waste a turn trying. Gate the reminder on
21382133
// whether the active tool registry actually exposes
21392134
// SkillTool to the model.
2140-
const hasSkillTool = !!this.toolRegistry.getTool(
2141-
ToolNames.SKILL,
2142-
);
2135+
const hasSkillTool = !!this.toolRegistry.getTool(ToolNames.SKILL);
21432136
if (hasSkillTool) {
21442137
// Escape skill names defensively: validateSkillName already
21452138
// excludes `<>&` for parsed file-based skills, but
@@ -2171,11 +2164,7 @@ export class CoreToolScheduler {
21712164
}
21722165
}
21732166

2174-
const response = convertToFunctionResponse(
2175-
toolName,
2176-
callId,
2177-
content,
2178-
);
2167+
const response = convertToFunctionResponse(toolName, callId, content);
21792168
const successResponse: ToolCallResponseInfo = {
21802169
callId,
21812170
responseParts: response,
@@ -2232,7 +2221,7 @@ export class CoreToolScheduler {
22322221
: String(executionError);
22332222
endToolExecutionSpan(execSpan, {
22342223
success: false,
2235-
error: errorMessage,
2224+
error: TOOL_SPAN_STATUS_TOOL_EXCEPTION,
22362225
});
22372226

22382227
if (signal.aborted) {

packages/core/src/telemetry/session-tracing.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import {
2222
SPAN_TOOL_EXECUTION,
2323
} from './constants.js';
2424
import { isTelemetrySdkInitialized } from './sdk.js';
25+
import { createDebugLogger } from '../utils/debugLogger.js';
26+
27+
const debugLogger = createDebugLogger('SESSION_TRACING');
2528

2629
type InteractionStatus = 'ok' | 'error' | 'cancelled';
2730

@@ -254,8 +257,10 @@ export function endLLMRequestSpan(
254257
}
255258

256259
span.end();
257-
} catch {
258-
// OTel errors must not affect API behavior.
260+
} catch (error) {
261+
debugLogger.warn(
262+
`Failed to end LLM request span: ${error instanceof Error ? error.message : String(error)}`,
263+
);
259264
}
260265
activeSpans.delete(spanId);
261266
strongSpans.delete(spanId);
@@ -312,6 +317,12 @@ export function runInToolSpanContext<T>(span: Span, fn: () => T): T {
312317
return toolContext.run(spanCtx, fn);
313318
}
314319

320+
/**
321+
* When metadata is omitted, span status is NOT set — callers on failure paths
322+
* must pre-set status via setToolSpanFailure/setToolSpanCancelled before calling
323+
* this. This asymmetry with endLLMRequestSpan (which defaults to OK) is intentional:
324+
* tool spans have multiple failure modes that set status before endToolSpan runs.
325+
*/
315326
export function endToolSpan(span: Span, metadata?: ToolSpanMetadata): void {
316327
const spanId = getSpanId(span);
317328
const spanCtx = activeSpans.get(spanId)?.deref();
@@ -343,8 +354,10 @@ export function endToolSpan(span: Span, metadata?: ToolSpanMetadata): void {
343354
}
344355

345356
spanCtx.span.end();
346-
} catch {
347-
// OTel errors must not affect tool scheduling.
357+
} catch (error) {
358+
debugLogger.warn(
359+
`Failed to end tool span: ${error instanceof Error ? error.message : String(error)}`,
360+
);
348361
}
349362
activeSpans.delete(spanId);
350363
strongSpans.delete(spanId);
@@ -358,6 +371,11 @@ export function startToolExecutionSpan(): Span {
358371
}
359372

360373
const parentCtx = toolContext.getStore();
374+
if (!parentCtx) {
375+
debugLogger.warn(
376+
'startToolExecutionSpan called outside runInToolSpanContext — span will not be parented to tool span',
377+
);
378+
}
361379
const ctx = parentCtx
362380
? trace.setSpan(otelContext.active(), parentCtx.span)
363381
: otelContext.active();
@@ -416,8 +434,10 @@ export function endToolExecutionSpan(
416434
}
417435

418436
spanCtx.span.end();
419-
} catch {
420-
// OTel errors must not affect tool scheduling.
437+
} catch (error) {
438+
debugLogger.warn(
439+
`Failed to end tool execution span: ${error instanceof Error ? error.message : String(error)}`,
440+
);
421441
}
422442
activeSpans.delete(spanId);
423443
strongSpans.delete(spanId);

0 commit comments

Comments
 (0)