Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 36 additions & 36 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
},
"dependencies": {
"@anthropic-ai/sdk": "^0.82.0",
"@github/copilot": "1.0.81-0",
"@github/copilot": "1.0.81-3",
"@github/copilot-sdk": "1.0.11",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
Expand Down
72 changes: 36 additions & 36 deletions remote/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion remote/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"@github/copilot": "1.0.81-0",
"@github/copilot": "1.0.81-3",
"@github/copilot-sdk": "1.0.11",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
Expand Down
31 changes: 31 additions & 0 deletions src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,7 @@ export class CopilotAgentSession extends Disposable {
this._reconcileMcpServerEnablement().catch(error => this._logService.error(error, `[Copilot:${this.sessionId}] Failed to reconcile MCP enablement after customizations changed`));
}));
this._subscribeToEvents();
await this._registerSamplingInterest();
this._subscribeForLogging();
this._subscribeForMemoInvalidation();
this._subscribeForInstructionsCollectedTelemetry();
Expand Down Expand Up @@ -2885,6 +2886,36 @@ export class CopilotAgentSession extends Disposable {
}
}

/**
* Advertises the MCP `sampling` client capability to plugin MCP
* servers for the lifetime of this session.
*
* The Copilot runtime only exposes the `sampling` capability to a
* plugin server (so its `createMessage` calls succeed rather than
* failing with "sampling is not supported by this client") when the
* session has a live consumer registered for the `sampling.requested`
* event. SDK clients that drive sampling purely through
* {@link rpc.mcp.executeSampling} (as we do in
* {@link _handleSamplingCreateMessage}) do not implicitly count as a
* consumer, so we register interest explicitly and release it on
* disposal.
*/
private async _registerSamplingInterest(): Promise<void> {
try {
const { handle } = await this._wrapper.session.rpc.eventLog.registerInterest({ eventType: 'sampling.requested' });
if (this._store.isDisposed) {
await this._wrapper.session.rpc.eventLog.releaseInterest({ handle }).catch(() => undefined);
return;
}
this._register(toDisposable(() => {
this._wrapper.session.rpc.eventLog.releaseInterest({ handle }).catch(error =>
this._logService.error(error, `[Copilot:${this.sessionId}] Failed to release sampling.requested interest`));
}));
} catch (error) {
this._logService.error(error, `[Copilot:${this.sessionId}] Failed to register sampling.requested interest`);
}
}

/**
* Selects (or clears) a custom agent on the live SDK session.
* Mirrors the SDK's `rpc.agent.select` / `rpc.agent.deselect` pair.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@ const ORDINAL_UUID_RE = /\$\{uuid_\d+\}/g;
/** Stands in for a path, whose spelling is per-machine. */
const PATH_PLACEHOLDER = '${path}';

/**
* Runtime-injected one-turn "change notice" blocks that the CLI/runtime prepends
* to the next user message when something about the environment changed since the
* previous turn: the working directory (`<working_directory_changed>`), the
* explicit additional-directory set (`<additional_directories_changed>`), or the
* available tools / model (`<tools_changed_notice>`, e.g. when `exit_plan_mode`
* is withdrawn after a plan is approved).
*
* These blocks are authored by the runtime, not by the host: whether one appears
* depends on session timing and runtime version rather than on anything VS Code
* composes, so a bump that starts emitting a new notice would otherwise read as a
* host regression. Like a `tool_result` payload or a run-time id, their presence
* is environment-derived and not part of the host-authored structure this
* projection asserts, so both sides elide them (including the whitespace that
* separates the notice from the actual message) before comparison.
*/
const CHANGE_NOTICE_RE = /<(tools_changed_notice|working_directory_changed|additional_directories_changed)>[\s\S]*?<\/\1>\n*/g;

/** Removes any runtime-injected change-notice block from a message's text. */
function elideChangeNotices(text: string): string {
return text.replace(CHANGE_NOTICE_RE, '');
}

/**
* A path: a recorder placeholder root (`${workdir}`, with or without a
* trailing segment), a Windows absolute path (`C:\x\y`), or a POSIX absolute
Expand Down Expand Up @@ -105,7 +128,7 @@ export interface IProjectedModelRequest {
}

function elideRuntimeIds(text: string): string {
return elidePaths(text.replace(RAW_UUID_RE, RUNTIME_ID_PLACEHOLDER).replace(ORDINAL_UUID_RE, RUNTIME_ID_PLACEHOLDER));
return elidePaths(elideChangeNotices(text).replace(RAW_UUID_RE, RUNTIME_ID_PLACEHOLDER).replace(ORDINAL_UUID_RE, RUNTIME_ID_PLACEHOLDER));
}

function projectValue(value: unknown): unknown {
Expand Down
Loading