55
}
56
}
58
>
/** Per-tool-call timing state, keyed by `session:toolCallId`. */
59
>
interface IToolCallTiming {
60
>
readonly stopWatch: StopWatch;
61
>
readonly provider: string;
62
>
readonly session: string;
63
>
readonly toolId: string;
64
>
readonly toolSourceKind: string;
65
>
}
66
>
67
>
interface IStalledToolCall {
68
>
readonly blockerKind: ToolCallBlockerRequest['kind'];
69
>
readonly completionStopWatch: StopWatch;
70
>
}
71
>
72
>
/**
73
>
* Tracks completed and stalled tool calls for agent host sessions.
74
>
*
75
>
* Lifecycle per tool call:
76
>
* 1. {@link toolCallStarted} — begins a stopwatch and records the tool's
77
>
* name and source kind (only the start action carries these)
78
>
* 2. {@link toolCallCompleted} — emits the telemetry event and clears state
79
>
* 3. {@link toolCallBlocked} / {@link toolCallUnblocked} — emits once when a
80
>
* confirmation or client execution remains unresolved past the threshold
81
>
*
82
>
* In-flight tool calls that never complete (e.g. the turn is cancelled mid
83
>
* tool call) are dropped via {@link clearSession} / {@link clear} so the
84
>
* tracking map cannot leak.
85
>
*/
86
>
export class AgentHostToolCallTracker extends Disposable {
87
>
88
>
private readonly _toolCalls = new Map<string, IToolCallTiming>();
89
>
private readonly _toolCallStallTimers = this._register(new DisposableMap<string>());
90
>
private readonly _stalledToolCalls = new Map<string, IStalledToolCall>();
91
>
92
>
constructor(private readonly _reporter: AgentHostTelemetryReporter) {
93
super();
94
}
96
>
toolCallStarted(provider: string, session: string, toolCallId: string, toolName: string, contributor: ToolCallContributor | undefined): void {
97
this._toolCalls.set(this._key(session, toolCallId), {
98
stopWatch: StopWatch.create(true),