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 { generateUuid } from '../../../../base/common/uuid.js';
7
>
import { toToolCallMeta } from '../../common/meta/agentToolCallMeta.js';
8
>
import { ActionType, type SessionAction, type ChatAction } from '../../common/state/sessionActions.js';
9
>
import { MessageKind, ResponsePartKind, ToolCallConfirmationReason, ToolCallContributorKind, ToolResultContentType, TurnState } from '../../common/state/sessionState.js';
10
>
import { extractForwardedErrorInfo } from '../shared/forwardedChatError.js';
11
>
import { getServerToolDisplay } from '../shared/serverToolGroups.js';
12
>
import { ActiveClientToolSet } from '../activeClientState.js';
13
>
import { unwrapShellInvocation } from './codexShellCommand.js';
14
>
import type { AgentMessageDeltaNotification } from './protocol/generated/v2/AgentMessageDeltaNotification.js';
15
>
import type { CommandExecutionOutputDeltaNotification } from './protocol/generated/v2/CommandExecutionOutputDeltaNotification.js';
16
>
import type { FileChangeOutputDeltaNotification } from './protocol/generated/v2/FileChangeOutputDeltaNotification.js';
17
>
import type { FileChangePatchUpdatedNotification } from './protocol/generated/v2/FileChangePatchUpdatedNotification.js';
18
>
import type { FileUpdateChange } from './protocol/generated/v2/FileUpdateChange.js';
19
>
import type { ItemCompletedNotification } from './protocol/generated/v2/ItemCompletedNotification.js';
20
>
import type { ItemStartedNotification } from './protocol/generated/v2/ItemStartedNotification.js';
21
>
import type { McpToolCallProgressNotification } from './protocol/generated/v2/McpToolCallProgressNotification.js';
22
>
import type { McpToolCallResult } from './protocol/generated/v2/McpToolCallResult.js';
23
>
import type { ReasoningSummaryPartAddedNotification } from './protocol/generated/v2/ReasoningSummaryPartAddedNotification.js';
24
>
import type { ReasoningSummaryTextDeltaNotification } from './protocol/generated/v2/ReasoningSummaryTextDeltaNotification.js';
25
>
import type { ReasoningTextDeltaNotification } from './protocol/generated/v2/ReasoningTextDeltaNotification.js';
26
>
import type { ThreadTokenUsageUpdatedNotification } from './protocol/generated/v2/ThreadTokenUsageUpdatedNotification.js';
27
>
import type { TurnCompletedNotification } from './protocol/generated/v2/TurnCompletedNotification.js';
28
>
import type { TurnStartedNotification } from './protocol/generated/v2/TurnStartedNotification.js';
29
>
import type { UserInput } from './protocol/generated/v2/UserInput.js';
30
>
import type { WebSearchAction } from './protocol/generated/v2/WebSearchAction.js';
31
>
import type { DynamicToolCallOutputContentItem } from './protocol/generated/v2/DynamicToolCallOutputContentItem.js';
32
>
import type { JsonValue } from './protocol/generated/serde_json/JsonValue.js';
33
>
import type { CollabAgentTool } from './protocol/generated/v2/CollabAgentTool.js';
34
>
import type { CollabAgentState } from './protocol/generated/v2/CollabAgentState.js';
35
>
36
>
/**
37
>
* Per-session mutable state held by the mapper. Carries the bookkeeping
38
>
* needed to glue codex's item-stream (each `agentMessage` item has its
39
>
* own id) to the agent host protocol (each markdown part has its own id).
40
>
*
41
>
* Phase 2 tracks only `itemId → partId` for agent messages. Phase 4
42
>
* extends this with tool-call correlation; Phase 6 adds reasoning parts.
43
>
*/
44
>
export interface ICodexSessionMapState {
45
>
/** Stable codex `itemId` → our markdown response part id. */
46
>
readonly itemToPartId: Map<string, string>;
47
>
/**
48
>
* Stable codex `itemId` → tool-call bookkeeping. Phase 4 tracks
49
>
* `commandExecution` here so completion/approval handlers can find
50
>
* the right toolCallId/turnId for each item.
51
>
*/
52
>
readonly itemToToolCall: Map<string, ICodexToolCallEntry>;
53
>
/** Stable codex reasoning item/index → our reasoning response part id. */
54
>
readonly itemToReasoningPartId: Map<string, string>;
55
>
/** Current turn id (per `turn/started`). */
56
>
currentTurnId: string | undefined;
57
>
/**
58
>
* Live registry of the session's client-provided (`dynamicTools`) tools,
59
>
* keyed by contributing workbench client. A `dynamicToolCall` tool-call
60
>
* start is stamped with the owning client (so the workbench routes
61
>
* execution back to it) resolved via {@link ActiveClientToolSet.ownerOf}.
62
>
*/
63
>
clientToolSet: ActiveClientToolSet;
64
>
/**
65
>
* Names of the agent host's server tools (executed in-process). A
66
>
* `dynamicToolCall` for one of these omits the `Client` contributor so the
67
>
* workbench does not try to route execution to a client — the agent host
68
>
* answers the `item/tool/call` directly.
69
>
*/
70
>
serverToolNames: ReadonlySet<string>;
71
>
/**
72
>
* Server name → customization id for the session's MCP servers, used to
73
>
* stamp the {@link ToolCallContributorKind.MCP} contributor on `mcpToolCall`
74
>
* starts so clients can correlate the call with its originating server
75
>
* customization. Owned and populated by the agent (mirrors
76
>
* {@link clientToolSet}); empty until the agent first applies the inventory.
77
>
*/
78
>
readonly mcpCustomizationIds: Map<string, string>;
79
>
/**
80
>
* Tool call ids the host declined at the approval prompt. Codex reports the
81
>
* resulting `item/completed` as a generic failure, so the completion handler
82
>
* consults this set to emit a `userCancelled` (`error.code = 'denied'`)
83
>
* result instead. Drained on completion and cleared per turn.
84
>
*/
85
>
readonly declinedToolCalls: Set<string>;
86
>
/**
87
>
* A `commandExecution` that completed successfully with NO output is
88
>
* potentially a sandbox pre-flight. When Codex runs a network (or otherwise
89
>
* escalated) command under `on-request` + `workspace-write` it first attempts
90
>
* it inside the sandbox — which completes instantly with no output because
91
>
* the sandbox blocked it — then re-runs the SAME command as a separate
92
>
* `commandExecution` item guarded by an approval request. Rendering both
93
>
* items draws the command box twice. To coalesce them we defer the
94
>
* pre-flight's completion here: if the next `commandExecution` in the turn
95
>
* re-runs the same command it reuses this (still-open) tool call for a single
96
>
* box; otherwise the deferred completion is flushed (on the next item or at
97
>
* turn end) so a genuinely output-less command still finalizes.
98
>
*/
99
>
pendingPreflight: ICodexPendingPreflight | undefined;
100
>
}
101
>
102
>
/**
103
>
* A deferred `commandExecution` completion held back to coalesce a sandbox
104
>
* pre-flight with its approval-guarded re-run. See
105
>
* {@link ICodexSessionMapState.pendingPreflight}.
106
>
*/
107
>
interface ICodexPendingPreflight {
108
>
readonly toolCallId: string;
109
>
readonly turnId: string;
110
>
/** Unwrapped command text, used to match the re-run. */
111
>
readonly command: string;
112
>
/** The `ChatToolCallComplete` action to emit if the pre-flight is not reused. */
113
>
readonly completion: (SessionAction | ChatAction)[];
114
>
}
115
>
116
>
export interface ICodexToolCallEntry {
117
>
readonly toolCallId: string;
118
>
readonly turnId: string;
119
>
readonly toolName: string;
120
>
output: string;
121
>
}
122
>
123
>
export function createCodexSessionMapState(serverToolNames: ReadonlySet<string> = new Set(), clientToolSet: ActiveClientToolSet = new ActiveClientToolSet()): ICodexSessionMapState {
124
return {
125
itemToPartId: new Map(),