1
>
/*---------------------------------------------------------------------------------------------
claudeMapSessionEvents.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import type { SDKMessage } from '@anthropic-ai/claude-agent-sdk';
7
>
import type { URI } from '../../../../base/common/uri.js';
8
>
import { LogLevel, type ILogService } from '../../../log/common/log.js';
9
>
import type { AgentSignal } from '../../common/agentService.js';
10
>
import { ActionType } from '../../common/state/sessionActions.js';
11
>
import { ResponsePartKind, ToolResultContentType, type ToolResultContent, type ToolResultFileEditContent } from '../../common/state/sessionState.js';
12
>
import { extractForwardedErrorInfo } from '../shared/forwardedChatError.js';
13
>
import { buildTopLevelSubagentReadyAction, emitInnerAssistantSignals, mapSubagentSystemMessage, SUBAGENT_SPAWNING_TOOL_NAMES, tagWithParent } from './claudeSubagentSignals.js';
14
>
import type { SubagentRegistry } from './claudeSubagentRegistry.js';
15
>
import { stripClientToolNamePrefix, hasClientToolNamePrefix } from './clientTools/claudeClientToolMcpServer.js';
16
>
import { buildClaudeToolMeta, getClaudePastTenseMessage, getClaudeToolDisplayName } from './claudeToolDisplay.js';
17
>
import { claudeToolDenialCode } from './claudeToolDenial.js';
18
>
import { ClaudeToolCallRegistry } from './claudeToolCallRegistry.js';
19
>
import { ToolCallConfirmationReason, ToolCallContributorKind, type StringOrMarkdown } from '../../common/state/protocol/state.js';
20
>
21
>
/**
22
>
* Cross-call state for {@link mapSDKMessageToAgentSignals}. One instance
23
>
* lives per {@link ClaudeAgentSession} and is threaded through every
24
>
* mapper invocation for that session's lifetime.
25
>
*
26
>
* Three scopes:
27
>
*
28
>
* - **Per-message** (`activeToolBlocks`, `currentMessageId`): mirror
29
>
* the SDK's per-message `BetaRawContentBlockStartEvent.index`
30
>
* namespace. Reset on every `message_start`. `activeToolBlocks` lets
31
>
* `input_json_delta` look up the tool block that owns the current
32
>
* index. `currentMessageId` qualifies text/thinking part ids so a
33
>
* later message in the same turn does not collide with an earlier
34
>
* message that used the same `index` for a different block kind
35
>
* (e.g. turn one: `thinking@0`; turn two after `tool_result`:
36
>
* `text@0`).
37
>
* - **Cross-message** (`toolCallTurnIds`, `toolCallNames`): a `tool_use`
38
>
* lands in one assistant message, the matching `tool_result` arrives
39
>
* in a later synthetic `user` message. Keyed by the SDK's globally-
40
>
* unique `block.id` so re-use of `index` between messages is harmless.
41
>
* Drained on `tool_result` (happy path) or on the turn's `result`
42
>
* envelope as a defense-in-depth fallback so an SDK that never
43
>
* delivers `tool_result` cannot leak entries across turns.
44
>
*
45
>
* Encapsulated as a class (vs. a plain interface) so the maps' mutators
46
>
* are not part of the public surface — Phase 6.1's lesson — and the
47
>
* lifecycle invariants live behind named methods.
48
>
*/
49
>
export class ClaudeMapperState {
50
private readonly _activeToolBlocks = new Map<number, { toolUseId: string; toolName: string }>();
51
/**