diff options
| author | Jerop Kipruto <[email protected]> | 2025-06-12 16:48:10 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-06-12 20:48:10 +0000 |
| commit | 6723c72fa5468be713c05205c75be532729e8f92 (patch) | |
| tree | 2392b344fb942f1c452e9fca5b5b6d131a827805 /packages/core/src/telemetry/loggers.ts | |
| parent | f8863f4d00f23a3e29496535be6cf0bb80ee43e9 (diff) | |
telemetry: include user decisions in tool call logs (#966)
Add the user's decision (accept, reject, modify) to tool call telemetry to better understand user intent. The decision provides crucial context to the `success` metric, as a user can reject a call that would have succeeded or accept one that fails.
Also prettify the arguments json.
Example:

#750
Diffstat (limited to 'packages/core/src/telemetry/loggers.ts')
| -rw-r--r-- | packages/core/src/telemetry/loggers.ts | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/packages/core/src/telemetry/loggers.ts b/packages/core/src/telemetry/loggers.ts index 49a7019a..66f584e7 100644 --- a/packages/core/src/telemetry/loggers.ts +++ b/packages/core/src/telemetry/loggers.ts @@ -30,6 +30,7 @@ import { recordToolCallMetrics, } from './metrics.js'; import { isTelemetrySdkInitialized } from './sdk.js'; +import { ToolConfirmationOutcome } from '../index.js'; const shouldLogUserPrompts = (config: Config): boolean => config.getTelemetryLogUserPromptsEnabled() ?? false; @@ -40,6 +41,29 @@ function getCommonAttributes(config: Config): LogAttributes { }; } +export enum ToolCallDecision { + ACCEPT = 'accept', + REJECT = 'reject', + MODIFY = 'modify', +} + +export function getDecisionFromOutcome( + outcome: ToolConfirmationOutcome, +): ToolCallDecision { + switch (outcome) { + case ToolConfirmationOutcome.ProceedOnce: + case ToolConfirmationOutcome.ProceedAlways: + case ToolConfirmationOutcome.ProceedAlwaysServer: + case ToolConfirmationOutcome.ProceedAlwaysTool: + return ToolCallDecision.ACCEPT; + case ToolConfirmationOutcome.ModifyWithEditor: + return ToolCallDecision.MODIFY; + case ToolConfirmationOutcome.Cancel: + default: + return ToolCallDecision.REJECT; + } +} + export function logCliConfiguration(config: Config): void { if (!isTelemetrySdkInitialized()) return; @@ -103,15 +127,20 @@ export function logUserPrompt( export function logToolCall( config: Config, - event: Omit<ToolCallEvent, 'event.name' | 'event.timestamp'>, + event: Omit<ToolCallEvent, 'event.name' | 'event.timestamp' | 'decision'>, + outcome?: ToolConfirmationOutcome, ): void { if (!isTelemetrySdkInitialized()) return; + + const decision = outcome ? getDecisionFromOutcome(outcome) : undefined; + const attributes: LogAttributes = { ...getCommonAttributes(config), ...event, 'event.name': EVENT_TOOL_CALL, 'event.timestamp': new Date().toISOString(), - function_args: JSON.stringify(event.function_args), + function_args: JSON.stringify(event.function_args, null, 2), + decision, }; if (event.error) { attributes['error.message'] = event.error; @@ -121,7 +150,7 @@ export function logToolCall( } const logger = logs.getLogger(SERVICE_NAME); const logRecord: LogRecord = { - body: `Tool call: ${event.function_name}. Success: ${event.success}. Duration: ${event.duration_ms}ms.`, + body: `Tool call: ${event.function_name}${decision ? `. Decision: ${decision}` : ''}. Success: ${event.success}. Duration: ${event.duration_ms}ms.`, attributes, }; logger.emit(logRecord); @@ -130,6 +159,7 @@ export function logToolCall( event.function_name, event.duration_ms, event.success, + decision, ); } |
