mapSessionEvents.ts ×12

Frontier kind: Code frontier

unlabeled · c_1b7b946fe7e7

462 tests · 32508 LOC · 175 files · introduces 0 tests · 257 LOC · 4 files

Introduces — evidence that enters the hierarchy at this concept

Code
26 ranges257 lines · 4 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2681 ranges32508 lines · 175 files · Browse complete extent
All tests (intent)
462 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

4 files ranked by introduced lines: 257 introduced LOC across 26 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/copilot/mapSessionEvents.ts 141 introduced LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mapSessionEvents.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 { AssistantMessageToolRequest, Attachment, SessionEvent, ToolExecutionCompleteContent, ToolExecutionCompleteData } from '@github/copilot-sdk';
7 > import { decodeBase64 } from '../../../../base/common/buffer.js';
8 > import { basename } from '../../../../base/common/path.js';
9 > import { isString } from '../../../../base/common/types.js';
10 > import { URI } from '../../../../base/common/uri.js';
11 > import { generateUuid } from '../../../../base/common/uuid.js';
12 > import { AgentSession } from '../../common/agentService.js';
13 > import { stripRedundantCdPrefix } from '../../common/commandLineHelpers.js';
14 > import { toToolCallMeta, type IToolCallUiMeta } from '../../common/meta/agentToolCallMeta.js';
15 > import { IFileEditRecord, ISessionDatabase } from '../../common/sessionDataService.js';
16 > import { MessageAttachmentKind, type MessageAttachment } from '../../common/state/protocol/state.js';
17 > import { MessageKind, ResponsePartKind, ToolCallConfirmationReason, ToolCallContributorKind, ToolCallStatus, ToolResultContentType, TurnState, buildSubagentSessionUri, type AgentSelection, type Message, type ModelSelection, type ResponsePart, type StringOrMarkdown, type TerminalCommandResult, type ToolCallCompletedState, type ToolResultContent, type ToolResultTerminalContent, type Turn, type UsageInfo } from '../../common/state/sessionState.js';
18 > import { buildNonPtyShellTerminalUri } from './copilotNonPtyShellTerminals.js';
19 > import { getInvocationMessage, getPastTenseMessage, getShellIntention, getShellLanguage, getSubagentMetadata, getTaskCompleteMarkdown, getToolDisplayName, getToolInputString, getToolKind, isEditTool, isHiddenTool, isTaskCompleteTool, synthesizeSkillToolCall } from './copilotToolDisplay.js';
20 > import { buildSessionDbUri } from '../shared/fileEditTracker.js';
21 > import { getMediaMime } from '../../../../base/common/mime.js';
22 > import { buildCopilotSystemNotification } from './copilotSystemNotification.js';
23 > import { buildMcpChannel, buildMcpTopLevelCustomizationId } from '../shared/mcpCustomizationController.js';
24 > import { readSimpleAttachmentDisplayKindFromMimeType } from './copilotAttachmentUtils.js';
25 >
26 function tryStringify(value: unknown): string | undefined {
27 try {
31 }
32 }
34 > /**
35 > * Returns true if the event is a SDK-injected `user.message` that should not
36 > * be shown to the user (e.g. skill-content injection).
37 > *
38 > * The SDK marks these via a non-`'user'` `source` field. Older sessions
39 > * persisted before `source` existed will not be filtered; that is accepted
40 > * leakage rather than guessed-at content sniffing.
41 > */
42 function isSyntheticUserMessage(event: SessionEvent): boolean {
43 if (event.type !== 'user.message') {
47 return !!source && source.toLowerCase() !== 'user';
48 }
50 > /**
51 > * Converts SDK `tool.execution_complete` content blocks into AHP tool result
52 > * content. A `shell_exit` block becomes {@link TerminalCommandResult} data on
53 > * the tool call's terminal content block; when no terminal block exists yet
54 > * (e.g. history replay, where no live channel survives) and `terminal` is
55 > * provided, a non-pty terminal block is synthesized so the outcome still
56 > * renders from `result.preview`. Returns the `shell_exit` outcome, if any, so
57 > * the live path can settle the non-pty output channel from it.
58 > */
59 > export interface ISdkShellExit {
60 > readonly shellId: string;
61 > readonly result: TerminalCommandResult;
62 > }
63 >
64 > export function appendSdkToolResultContent(content: ToolResultContent[], sdkContents: readonly ToolExecutionCompleteContent[] | undefined, terminal?: { session: URI | string; toolCallId: string; title: string }): ISdkShellExit | undefined {
65 let shellExit: ISdkShellExit | undefined;
66 for (const sdkContent of sdkContents ?? []) {
92 return shellExit;
93 }
95 > // =============================================================================
96 > // Single-pass turn builder
97 > // =============================================================================
98 >
99 > /** Per-tool-call info captured from `tool.execution_start` and reused at `tool.execution_complete`. */
100 > interface IToolStartInfo {
101 > readonly toolName: string;
102 > readonly displayName: string;
103 > readonly invocationMessage: StringOrMarkdown;
104 > readonly toolInput?: string;
105 > readonly toolKind?: 'terminal' | 'subagent' | 'search';
106 > readonly language?: string;
107 > /** Intention (why the command runs) for shell tools, from their `description` argument. */
108 > readonly intention?: string;
109 > readonly subagentAgentName?: string;
110 > readonly subagentDescription?: string;
111 > readonly parameters: Record<string, unknown> | undefined;
112 > readonly parentToolCallId?: string;
113 > readonly mcpServerName?: string;
114 > readonly mcpToolName?: string;
115 > readonly mcpUiResourceUri?: string;
116 > }
117 >
118 > /** Subagent metadata seen via `subagent.started`, applied to the parent tool call's content at `tool.execution_complete`. */
119 > interface ISubagentInfo {
120 > readonly agentName: string;
121 > readonly agentDisplayName: string;
122 > readonly agentDescription?: string;
123 > }
124 >
125 > /**
126 > * Mutable per-turn state used while iterating events. The parent session
127 > * has one builder; each subagent turn (one per `parentToolCallId`) has its
128 > * own builder so inner events route there directly.
129 > */
130 > interface ITurnBuilder {
131 > id: string;
132 > message: Message;
133 > readonly responseParts: ResponsePart[];
134 > usage: UsageInfo | undefined;
135 > /** Tool starts seen but not yet completed in this turn, keyed by toolCallId. */
136 > readonly pendingTools: Map<string, IToolStartInfo>;
137 > }
138 >
139 > export interface IMapSessionEventsOptions {
140 > readonly workingDirectory?: URI;
141 > readonly model?: ModelSelection;
142 > readonly agent?: AgentSelection;
143 > }
144 >
145 function newTurnBuilder(id: string, text: string, options?: { attachments?: MessageAttachment[]; model?: ModelSelection; agent?: AgentSelection; origin?: MessageKind }): ITurnBuilder {
146 const message: Message = {
153 return { id, message, responseParts: [], usage: undefined, pendingTools: new Map() };
154 }
156 function readStringProperty(source: unknown, key: string): string | undefined {
157 if (!source || typeof source !== 'object' || Array.isArray(source)) {
161 return typeof value === 'string' && value.length > 0 ? value : undefined;
162 }
164 function readMcpUiResourceUri(source: unknown): string | undefined {
165 if (!source || typeof source !== 'object' || Array.isArray(source)) {
180 return readStringProperty(ui, 'resourceUri');
181 }
183 function makeToolStartInfo(toolName: string, rawArguments: unknown, parentToolCallId: string | undefined, workingDirectory: URI | undefined, source: unknown): IToolStartInfo | undefined {
184 if (isHiddenTool(toolName)) {
215 };
216 }
218 function finalizeTurn(builder: ITurnBuilder, state: TurnState): Turn {
219 return {
225 };
226 }
228 > /**
229 > * Maps raw SDK session events directly into agent-protocol {@link Turn}s
230 > * for the parent session and any subagent child sessions, restoring stored
231 > * file-edit metadata from the session database when available.
232 > *
233 > * Subagent inner events are routed to per-`parentToolCallId` turn builders
234 > * so they appear under their own session view rather than polluting the
235 > * parent transcript. Each subagent's tool calls are returned via
236 > * {@link mapSessionEventsToTurns.subagentTurnsByToolCallId} so callers can
237 > * expose `getSubagentMessages` cheaply.
238 > *
239 > * If `workingDirectory` is provided, redundant `cd <workingDirectory> &&`
240 > * (or PowerShell equivalent) prefixes are stripped from shell tool
241 > * commands so clients see the simplified form.
242 > */
243 export async function mapSessionEvents(
244 session: URI,
649 }
650 }
652 > /**
653 > * Translates the SDK's `UserMessageAttachment[]` payload back into the
654 > * agent-protocol {@link MessageAttachment} shape. Text blob attachments
655 > * surface as {@link MessageAttachmentKind.Simple}; other blobs surface as
656 > * inline {@link MessageAttachmentKind.EmbeddedResource} payloads.
657 > * File/directory/selection variants reconstruct local `Resource`
658 > * attachments. We don't try to re-link these to the on-disk snapshots
659 > * produced by the agent host's attachment rewriter — the SDK keeps a
660 > * copy of the bytes / paths it actually saw on send, which is the
661 > * authoritative record for replay.
662 > */
663 function sdkAttachmentsToProtocol(
664 attachments: readonly Attachment[] | undefined,
676 return out.length > 0 ? out : undefined;
677 }
679 function sdkAttachmentToProtocol(
680 attachment: Attachment,
732 }
733 }
735 > /**
736 > * Builds a {@link ToolCallCompletedState}-shaped response part from an
737 > * SDK `tool.execution_complete` event. Restores file-edit content
738 > * references from `storedEdits` and merges subagent metadata when the
739 > * tool call spawned a child session.
740 > */
741 function makeCompletedToolCallPart(
742 d: ToolExecutionCompleteData,
src/vs/platform/agentHost/node/copilot/copilotNonPtyShellTerminals.ts 86 introduced LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- copilotNonPtyShellTerminals.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 { Disposable, toDisposable } from '../../../../base/common/lifecycle.js';
7 > import { URI } from '../../../../base/common/uri.js';
8 > import { AgentSession } from '../../common/agentService.js';
9 > import { TerminalClaimKind, type TerminalCommandResult, type TerminalSessionClaim } from '../../common/state/protocol/state.js';
10 > import { IAgentHostTerminalManager } from '../agentHostTerminalManager.js';
11 >
12 > /**
13 > * Builds the terminal channel URI for a runtime-executed (non-pty) shell tool
14 > * call. The session owns the terminal namespace and each tool call addresses a
15 > * distinct child terminal, keeping the URI stable across live streaming and
16 > * history replay without colliding with other sessions or tool calls.
17 > */
18 > export function buildNonPtyShellTerminalUri(session: URI | string, toolCallId: string): string {
19 return `agenthost-terminal://shell/${encodeURIComponent(AgentSession.id(session))}/${encodeURIComponent(toolCallId)}`;
20 }
22 > interface INonPtyShellStream {
23 > readonly uri: string;
24 > readonly title: string;
25 > created: boolean;
26 > /** The last cumulative snapshot written to the channel. */
27 > lastEmitted: string;
28 > finalized: boolean;
29 > }
30 >
31 > /**
32 > * Extracts the command result from the runtime's stable text fallback. The
33 > * external SDK bridge currently removes the equivalent `shell_exit` content
34 > * block for compatibility with older SDK clients.
35 > */
36 function parseCompletedShell(text: string | undefined): TerminalCommandResult | undefined {
37 const match = text && /<shellId: ([^>\r\n]+) completed with exit code (-?\d+)>\s*$/.exec(text);
44 };
45 }
47 > export interface INonPtyShellToolCompletion {
48 > readonly uri: string;
49 > readonly result?: TerminalCommandResult;
50 > readonly shouldRetire: boolean;
51 > }
52 >
53 > /**
54 > * Streams output of SDK-runtime-executed shell tool calls into output-only
55 > * AHP terminal channels. The runtime reports ANSI-stripped plain-text output
56 > * via `tool.execution_partial_result` as throttled cumulative snapshots that
57 > * may be rewritten once output is truncated (a trailing truncation marker
58 > * under the emit cap, a rolling tail past the large-output threshold); this
59 > * class emits only the unseen suffix as `terminal/data` while the snapshot
60 > * grows in place, and resets the channel when the snapshot was rewritten, so
61 > * subscribed clients receive live plain-text output (`isPty: false` — no VT
62 > * parsing needed).
63 > *
64 > * Created once per session and disposed with it, matching the pty-backed
65 > * `ShellManager` lifecycle.
66 > */
67 > export class NonPtyShellTerminalStreams extends Disposable {
68 >
69 > private readonly _streams = new Map<string, INonPtyShellStream>();
70 >
71 > constructor(
72 private readonly _sessionUri: URI,
73 @IAgentHostTerminalManager private readonly _terminalManager: IAgentHostTerminalManager,
84 }));
85 }
87 > /**
88 > * Appends the unseen suffix of `cumulativeOutput` to the tool call's
89 > * output terminal, creating the channel on first call. Returns the channel
90 > * URI and whether this call created it (so the caller can attach the
91 > * terminal content block exactly once).
92 > */
93 > track(toolCallId: string, title: string): void {
94 if (!this._streams.has(toolCallId)) {
95 this._streams.set(toolCallId, {
102 }
103 }
105 > append(toolCallId: string, cumulativeOutput: string): { uri: string; created: boolean } | undefined {
106 const stream = this._streams.get(toolCallId);
107 if (!stream) {
127 return { uri: stream.uri, created };
128 }
130 > /**
131 > * Records the process lifecycle information carried by tool completion.
132 > * A structured shell exit settles the channel.
133 > */
134 > completeToolCall(toolCallId: string, toolOutput: string | undefined, shellExit: { shellId: string; result: TerminalCommandResult } | undefined): INonPtyShellToolCompletion | undefined {
135 const stream = this._streams.get(toolCallId);
136 if (!stream) {
161 };
162 }
164 > /**
165 > * Releases the live output resource after its static completion has been
166 > * published. Repeated calls are safe and do not dispose the resource twice.
167 > */
168 > retire(toolCallId: string): void {
169 const stream = this._streams.get(toolCallId);
170 if (!stream) {
176 }
177 }
179 > private _finalize(stream: INonPtyShellStream, exitCode: number): void {
180 if (stream.finalized) {
181 return;
184 this._terminalManager.finalizeOutputTerminal(stream.uri, exitCode);
185 }
187 > private _createTerminal(toolCallId: string, stream: INonPtyShellStream): void {
188 const claim: TerminalSessionClaim = {
189 kind: TerminalClaimKind.Session,
src/vs/platform/agentHost/node/copilot/copilotSystemNotification.ts 18 introduced LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- copilotSystemNotification.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 { SessionEventPayload, SystemNotification } from '@github/copilot-sdk';
7 > import { softAssertNever } from '../../../../base/common/assert.js';
8 > import { localize } from '../../../../nls.js';
9 >
10 > export interface ICopilotSystemNotification {
11 > /** Text for a new system-origin AHP turn; derived from SDK `data.kind` metadata, e.g. shell completion `description`. */
12 > readonly messageText: string;
13 > /** Whether the runtime notification wakes the agent loop when it arrives while idle. */
14 > readonly startsTurn: boolean;
15 > }
16 >
17 > export function buildCopilotSystemNotification(event: SessionEventPayload<'system.notification'>): ICopilotSystemNotification | undefined {
18 const data = event.data;
19 const kind: SystemNotification = data.kind;
61 }
62 }
64 function cleanSystemNotificationContent(content: string): string {
65 const trimmed = content.trim();
src/vs/platform/agentHost/node/copilot/copilotAttachmentUtils.ts 12 introduced LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- copilotAttachmentUtils.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 { SimpleMessageAttachment } from '../../common/state/protocol/state.js';
7 >
8 > const attachmentDisplayKindParameter = 'x-vscode-display-kind=';
9 >
10 > export function addSimpleAttachmentDisplayKindToMimeType(attachment: SimpleMessageAttachment): string {
11 if (attachment.displayKind === undefined) {
12 return 'text/plain';
14 return `text/plain; ${attachmentDisplayKindParameter}${encodeURIComponent(attachment.displayKind)}`;
15 }
17 > export function readSimpleAttachmentDisplayKindFromMimeType(mimeType: string): string | undefined {
18 const parameter = mimeType.split(';').map(part => part.trim()).find(part => part.startsWith(attachmentDisplayKindParameter));
19 if (!parameter) {