Update Github Copilot to latest version (#2864)

* Update to latest version of Github Copilot CLI

* Use 0.0.381

* Reverts

* Update src/extension/agents/copilotcli/node/copilotcliSession.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Updates

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Don Jayamanne
2026-01-15 12:36:52 +11:00
committed by GitHub
parent cc301ab73f
commit dfaa4f6d5f
11 changed files with 190 additions and 98 deletions

View File

@@ -20,11 +20,15 @@ assets/walkthroughs/**
!dist/suggestionsPanelWebview.js
!node_modules/@vscode/copilot-typescript-server-plugin/package.json
!node_modules/@vscode/copilot-typescript-server-plugin/dist/*.js
!node_modules/@github/copilot/**/package.json
node_modules/@github/copilot/index.js
node_modules/@github/copilot/clipboard/**
node_modules/@github/copilot/prebuilds/**
node_modules/@github/copilot/sharp/**
!node_modules/@github/copilot/package.json
!node_modules/@github/copilot/sdk/**/package.json
!node_modules/@github/copilot/sdk/*.js
!node_modules/@github/copilot/sdk/worker/*.js
!node_modules/@github/copilot/node_modules/**/*.js
!node_modules/@github/copilot/sdk/sharp/**
!CHANGELOG.md
!README.md
!package.json

View File

@@ -13,7 +13,7 @@
"@anthropic-ai/claude-agent-sdk": "0.2.5",
"@anthropic-ai/sdk": "^0.71.2",
"@github/blackbird-external-ingest-utils": "^0.1.0",
"@github/copilot": "^0.0.366",
"@github/copilot": "^0.0.381",
"@google/genai": "^1.22.0",
"@humanwhocodes/gitignore-to-minimatch": "1.0.2",
"@microsoft/tiktokenizer": "^1.0.10",
@@ -3067,15 +3067,119 @@
"license": "MIT"
},
"node_modules/@github/copilot": {
"version": "0.0.366",
"resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-0.0.366.tgz",
"integrity": "sha512-mJ3wAvn4/yCrQBG5kcn2SOvWQSlrftkbpaAUBXX4l42y6Xsi4d9teuEdcwKOsUWLNDavpt3ecoCDnZUaCb/81A==",
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-0.0.381.tgz",
"integrity": "sha512-9AaInHlic/jQiMmm2UWitkDszmR5RihnKQBesfCBx8ow1pqZ4cx4q1DLh1l5xeJB6Cnl7Deoj5Md3FrvH8ugyw==",
"license": "SEE LICENSE IN LICENSE.md",
"bin": {
"copilot": "index.js"
"copilot": "npm-loader.js"
},
"engines": {
"node": ">=22"
},
"optionalDependencies": {
"@github/copilot-darwin-arm64": "0.0.381",
"@github/copilot-darwin-x64": "0.0.381",
"@github/copilot-linux-arm64": "0.0.381",
"@github/copilot-linux-x64": "0.0.381",
"@github/copilot-win32-arm64": "0.0.381",
"@github/copilot-win32-x64": "0.0.381"
}
},
"node_modules/@github/copilot-darwin-arm64": {
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-0.0.381.tgz",
"integrity": "sha512-Fw8bo5VkeU0NN6Ca1V+igBNYvnhi+R9lc+B8/GMEiokhVIrmxXoOFk4IUeCO33tDfmQnYpuuopyaDdaKd+YOfA==",
"cpu": [
"arm64"
],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
"darwin"
],
"bin": {
"copilot-darwin-arm64": "copilot"
}
},
"node_modules/@github/copilot-darwin-x64": {
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-0.0.381.tgz",
"integrity": "sha512-z0sS/MnO/FhY9XmaVD50OssOQuSD4REatWZUyhBVnAqfVEHy0k7QKtU4Y/JvjTSoFr1Ve0S7WlKsIBZbpi7OyQ==",
"cpu": [
"x64"
],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
"darwin"
],
"bin": {
"copilot-darwin-x64": "copilot"
}
},
"node_modules/@github/copilot-linux-arm64": {
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-0.0.381.tgz",
"integrity": "sha512-GnFPEPXxT0FbbnZYJ78KzUtt8mOcqxt+DLsQ8UqrkIvQJdpQh8aJASpLGhhgSLHvtbMDc+UQjGzeigxrgqX5UQ==",
"cpu": [
"arm64"
],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
"linux"
],
"bin": {
"copilot-linux-arm64": "copilot"
}
},
"node_modules/@github/copilot-linux-x64": {
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-0.0.381.tgz",
"integrity": "sha512-IPNzfopRDGfGOpbyUqOyY6GpQ+IWn7NFoDJcibQxLjYGSKrt88u5/rmse0oQ1t9QYQD6GsUfQ2ILkCNXQoCjOA==",
"cpu": [
"x64"
],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
"linux"
],
"bin": {
"copilot-linux-x64": "copilot"
}
},
"node_modules/@github/copilot-win32-arm64": {
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-0.0.381.tgz",
"integrity": "sha512-RsdGcDYNt6SopBM2zxKWWrn40S+Rff5UAGBG7fXyNCKjfTR6BA6jgy/x3KSKpy/1yUEqhtRZHMR0H0BMUHaZyQ==",
"cpu": [
"arm64"
],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
"win32"
],
"bin": {
"copilot-win32-arm64": "copilot.exe"
}
},
"node_modules/@github/copilot-win32-x64": {
"version": "0.0.381",
"resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-0.0.381.tgz",
"integrity": "sha512-IfWhMKK+h1ZZ7h4PWyDPl7+BJ0ZxAozU1Pn968rfod1Uzacdm+uOZBqK7ui0TgmQ+M5k6DCRwNHpU1e6E1s7Gw==",
"cpu": [
"x64"
],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
"win32"
],
"bin": {
"copilot-win32-x64": "copilot.exe"
}
},
"node_modules/@google/genai": {

View File

@@ -5191,7 +5191,7 @@
"@anthropic-ai/claude-agent-sdk": "0.2.5",
"@anthropic-ai/sdk": "^0.71.2",
"@github/blackbird-external-ingest-utils": "^0.1.0",
"@github/copilot": "^0.0.366",
"@github/copilot": "^0.0.381",
"@google/genai": "^1.22.0",
"@humanwhocodes/gitignore-to-minimatch": "1.0.2",
"@microsoft/tiktokenizer": "^1.0.10",

View File

@@ -61,60 +61,6 @@ const treeSitterGrammars: ITreeSitterGrammar[] = [
const REPO_ROOT = path.join(__dirname, '..');
/**
* @github/copilot depends on sharp which has native dependencies that are hard to distribute.
* This function creates a shim for the sharp module that @github/copilot expects.
* The shim provides a minimal implementation of the sharp API to satisfy @github/copilot's requirements.
* Its non-functional and only intended to make the module load without errors.
*
* We create a directory @github/copilot/node_modules/sharp, so that
* the node module resolution algorithm finds our shim instead of trying to load the real sharp module. This also ensure the shims are specific to this package.
*/
async function createCopilotCliSharpShim() {
const copilotCli = path.join(REPO_ROOT, 'node_modules', '@github', 'copilot');
const sharpShim = path.join(copilotCli, 'node_modules', 'sharp');
const copilotPackageJsonFile = path.join(copilotCli, 'package.json');
const copilotPackageJson = JSON.parse(fs.readFileSync(copilotPackageJsonFile, 'utf-8'));
if (copilotPackageJson.dependencies) {
delete copilotPackageJson.dependencies.sharp;
}
await fs.promises.writeFile(copilotPackageJsonFile, JSON.stringify(copilotPackageJson, undefined, 2), 'utf-8');
await fs.promises.rm(sharpShim, { recursive: true, force: true });
await fs.promises.mkdir(path.join(sharpShim, 'lib'), { recursive: true });
await fs.promises.writeFile(path.join(sharpShim, 'package.json'), JSON.stringify({
"name": "sharp",
"type": "commonjs",
"main": "lib/index.js"
}, undefined, 2));
await fs.promises.writeFile(path.join(sharpShim, 'lib', 'index.js'), `
const Sharp = function (inputBuffer, options) {
if (arguments.length === 1 && !is.defined(input)) {
throw new Error('Invalid input');
}
if (!(this instanceof Sharp)) {
return new Sharp(input, options);
}
this.inputBuffer = inputBuffer;
return this;
};
Sharp.prototype.resize = function () {
const that = this;
const img = {
toBuffer: () => that.inputBuffer,
png: () => img,
jpeg: () => img
};
return img;
};
module.exports = Sharp;
`);
}
/**
* @github/copilot/sdk/index.js depends on @github/copilot/worker/*.js files.
* We need to copy these files into the sdk directory to ensure they are available at runtime.
@@ -123,6 +69,17 @@ async function copyCopilotCliWorkerFiles() {
const sourceDir = path.join(REPO_ROOT, 'node_modules', '@github', 'copilot', 'worker');
const targetDir = path.join(REPO_ROOT, 'node_modules', '@github', 'copilot', 'sdk', 'worker');
await copyCopilotCLIFolders(sourceDir, targetDir);
}
async function copyCopilotCliSharpFiles() {
const sourceDir = path.join(REPO_ROOT, 'node_modules', '@github', 'copilot', 'sharp');
const targetDir = path.join(REPO_ROOT, 'node_modules', '@github', 'copilot', 'sdk', 'sharp');
await copyCopilotCLIFolders(sourceDir, targetDir);
}
async function copyCopilotCLIFolders(sourceDir: string, targetDir: string) {
await fs.promises.rm(targetDir, { recursive: true, force: true });
await fs.promises.mkdir(targetDir, { recursive: true });
await fs.promises.cp(sourceDir, targetDir, { recursive: true, force: true });
@@ -144,8 +101,8 @@ async function main() {
'node_modules/@github/blackbird-external-ingest-utils/pkg/nodejs/external_ingest_utils_bg.wasm',
], 'dist');
await createCopilotCliSharpShim();
await copyCopilotCliWorkerFiles();
await copyCopilotCliSharpFiles();
// Check if the base cache file exists
const baseCachePath = path.join('test', 'simulation', 'cache', 'base.sqlite');

View File

@@ -403,11 +403,15 @@ export function buildChatHistoryFromEvents(sessionId: string, events: readonly S
turns.push(new ChatRequestTurn2(prompt, undefined, references, '', [], undefined, details?.requestId));
break;
}
case 'assistant.message': {
if (typeof event.data.chunkContent === 'string') {
case 'assistant.message_delta': {
if (typeof event.data.deltaContent === 'string') {
processedMessages.add(event.data.messageId);
currentAssistantMessage.chunks.push(event.data.chunkContent);
} else if (event.data.content && !processedMessages.has(event.data.messageId)) {
currentAssistantMessage.chunks.push(event.data.deltaContent);
}
break;
}
case 'assistant.message': {
if (event.data.content && !processedMessages.has(event.data.messageId)) {
processAssistantMessage(event.data.content);
}
break;
@@ -566,6 +570,7 @@ function formatProgressToolInvocation(invocation: ChatToolInvocationPart, toolCa
}
function formatViewToolInvocation(invocation: ChatToolInvocationPart, toolCall: ViewTool): void {
const args = toolCall.arguments;

View File

@@ -39,7 +39,6 @@ export class CopilotCLISessionOptions {
private readonly agent?: SweCustomAgent;
private readonly customAgents?: SweCustomAgent[];
private readonly mcpServers?: SessionOptions['mcpServers'];
private readonly logger: ReturnType<typeof getCopilotLogger>;
private readonly requestPermissionRejected: NonNullable<SessionOptions['requestPermission']>;
private requestPermissionHandler: NonNullable<SessionOptions['requestPermission']>;
constructor(options: { model?: string; isolationEnabled?: boolean; workingDirectory?: Uri; mcpServers?: SessionOptions['mcpServers']; agent?: SweCustomAgent; customAgents?: SweCustomAgent[] }, logger: ILogService) {
@@ -49,7 +48,6 @@ export class CopilotCLISessionOptions {
this.mcpServers = options.mcpServers;
this.agent = options.agent;
this.customAgents = options.customAgents;
this.logger = getCopilotLogger(logger);
this.requestPermissionRejected = async (permission: PermissionRequest): ReturnType<NonNullable<SessionOptions['requestPermission']>> => {
logger.info(`[CopilotCLISession] Permission request denied for permission as no handler was set: ${permission.kind}`);
return {
@@ -70,7 +68,6 @@ export class CopilotCLISessionOptions {
public toSessionOptions(): Readonly<SessionOptions & { requestPermission: NonNullable<SessionOptions['requestPermission']> }> {
const allOptions: SessionOptions = {
logger: this.logger,
requestPermission: async (request: PermissionRequest) => {
return await this.requestPermissionHandler(request);
}
@@ -148,7 +145,7 @@ export class CopilotCLIModels implements ICopilotCLIModels {
const [{ getAvailableModels }, authInfo] = await Promise.all([this.copilotCLISDK.getPackage(), this.copilotCLISDK.getAuthInfo()]);
try {
const models = await getAvailableModels(authInfo);
return models.map(model => ({ id: model.model, name: model.label }));
return models.map(model => ({ id: model.id, name: model.name }));
} catch (ex) {
this.logService.error(`[CopilotCLISession] Failed to fetch models`, ex);
return [];

View File

@@ -189,17 +189,21 @@ export class CopilotCLISession extends DisposableStore implements ICopilotCLISes
await raceCancellation(this._sdkSession.setSelectedModel(modelId), token);
}
disposables.add(toDisposable(this._sdkSession.on('*', (event) => this.logService.trace(`[CopilotCLISession]CopilotCLI Event: ${JSON.stringify(event, null, 2)}`))));
disposables.add(toDisposable(this._sdkSession.on('*', (event) => {
this.logService.trace(`[CopilotCLISession] CopilotCLI Event: ${JSON.stringify(event, null, 2)}`);
})));
disposables.add(toDisposable(this._sdkSession.on('user.message', (event) => {
sdkRequestId = event.id;
})));
disposables.add(toDisposable(this._sdkSession.on('assistant.message', (event) => {
// Support for streaming chunked messages.
if (typeof event.data.chunkContent === 'string' && event.data.chunkContent.length) {
disposables.add(toDisposable(this._sdkSession.on('assistant.message_delta', (event) => {
// Support for streaming delta messages.
if (typeof event.data.deltaContent === 'string' && event.data.deltaContent.length) {
chunkMessageIds.add(event.data.messageId);
assistantMessageChunks.push(event.data.chunkContent);
this._stream?.markdown(event.data.chunkContent);
assistantMessageChunks.push(event.data.deltaContent);
this._stream?.markdown(event.data.deltaContent);
}
})));
disposables.add(toDisposable(this._sdkSession.on('assistant.message', (event) => {
if (typeof event.data.content === 'string' && event.data.content.length && !chunkMessageIds.has(event.data.messageId)) {
assistantMessageChunks.push(event.data.content);
this._stream?.markdown(event.data.content);

View File

@@ -24,7 +24,6 @@ import { ChatSessionStatus } from '../../../../vscodeTypes';
import { stripReminders } from '../common/copilotCLITools';
import { CopilotCLISessionOptions, ICopilotCLIAgents, ICopilotCLISDK } from './copilotCli';
import { CopilotCLISession, ICopilotCLISession } from './copilotcliSession';
import { getCopilotLogger } from './logger';
import { ICopilotCLIMCPHandler } from './mcpHandler';
const COPILOT_CLI_WORKSPACE_JSON_FILE_KEY = 'github.copilot.cli.workspaceSessionFile';
@@ -86,9 +85,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
this.monitorSessionFiles();
this._sessionManager = new Lazy<Promise<internal.LocalSessionManager>>(async () => {
const { internal } = await this.copilotCLISDK.getPackage();
return new internal.LocalSessionManager({
logger: getCopilotLogger(this.logService)
});
return new internal.LocalSessionManager({});
});
this._sessionTracker = this.instantiationService.createInstance(CopilotCLISessionWorkspaceTracker);
}

View File

@@ -155,7 +155,7 @@ describe('CopilotCLI permissionHelpers', () => {
describe('getConfirmationToolParams', () => {
it('maps shell requests to terminal confirmation tool', async () => {
const result = await getConfirmationToolParams(instaService, { kind: 'shell', fullCommandText: 'rm -rf /tmp/test', canOfferSessionApproval: true, commands: [], hasWriteFileRedirection: true, intention: '', possiblePaths: [] });
const result = await getConfirmationToolParams(instaService, { kind: 'shell', fullCommandText: 'rm -rf /tmp/test', canOfferSessionApproval: true, commands: [], hasWriteFileRedirection: true, intention: '', possiblePaths: [], possibleUrls: [] });
assert(!!result);
expect(result.tool).toBe(ToolName.CoreTerminalConfirmationTool);
});

View File

@@ -55,20 +55,9 @@ describe('CopilotCLI SDK Upgrade', function () {
path.join('ripgrep', 'bin', 'linux-x64', 'rg'),
path.join('ripgrep', 'bin', 'linux-arm64', 'rg'),
// sharp related files
path.join('sharp', 'node_modules', '@img', 'sharp-libvips-linux-arm64', 'lib', 'libvips-cpp.so.8.17.3'),
path.join('sharp', 'node_modules', '@img', 'sharp-libvips-linux-x64', 'lib', 'libvips-cpp.so.8.17.3'),
path.join('sharp', 'node_modules', '@img', 'sharp-darwin-arm64', 'lib', 'sharp-darwin-arm64.node'),
path.join('sharp', 'node_modules', '@img', 'sharp-darwin-x64', 'lib', 'sharp-darwin-x64.node'),
path.join('sharp', 'node_modules', '@img', 'sharp-libvips-darwin-arm64', 'lib', 'libvips-cpp.8.17.3.dylib'),
path.join('sharp', 'node_modules', '@img', 'sharp-libvips-darwin-x64', 'lib', 'libvips-cpp.8.17.3.dylib'),
path.join('sharp', 'node_modules', '@img', 'sharp-linux-arm64', 'lib', 'sharp-linux-arm64.node'),
path.join('sharp', 'node_modules', '@img', 'sharp-linux-x64', 'lib', 'sharp-linux-x64.node'),
path.join('sharp', 'node_modules', '@img', 'sharp-win32-arm64', 'lib', 'libvips-42.dll'),
path.join('sharp', 'node_modules', '@img', 'sharp-win32-arm64', 'lib', 'libvips-cpp-8.17.3.dll'),
path.join('sharp', 'node_modules', '@img', 'sharp-win32-arm64', 'lib', 'sharp-win32-arm64.node'),
path.join('sharp', 'node_modules', '@img', 'sharp-win32-x64', 'lib', 'libvips-42.dll'),
path.join('sharp', 'node_modules', '@img', 'sharp-win32-x64', 'lib', 'libvips-cpp-8.17.3.dll'),
path.join('sharp', 'node_modules', '@img', 'sharp-win32-x64', 'lib', 'sharp-win32-x64.node'),
path.join('sharp', 'node_modules', '@img', 'sharp-wasm32', 'lib', 'sharp-wasm32.node.wasm'),
// sharp related files, files copied by us.
path.join('sdk', 'sharp', 'node_modules', '@img', 'sharp-wasm32', 'lib', 'sharp-wasm32.node.wasm'),
// parsing commands for shell.
'tree-sitter-bash.wasm',
'tree-sitter-powershell.wasm',
@@ -134,4 +123,4 @@ async function findAllBinaries(dir: string): Promise<string[]> {
await findFilesRecursively(dir);
return binaryFiles;
}
}

View File

@@ -6,6 +6,7 @@
import { SessionOptions } from '@github/copilot/sdk';
import assert from 'assert';
import * as fs from 'fs/promises';
import * as http from 'http';
import { platform, tmpdir } from 'os';
import * as path from 'path';
import type { ChatPromptReference } from 'vscode';
@@ -117,7 +118,6 @@ function registerChatServices(testingServiceCollection: TestingServiceCollection
mutableOptions.copilotUrl = this.testOptions.copilotUrl ?? options.copilotUrl;
mutableOptions.enableStreaming = true;
mutableOptions.skipCustomInstructions = true;
mutableOptions.disableHttpLogging = true;
return options;
}
}
@@ -145,6 +145,41 @@ function registerChatServices(testingServiceCollection: TestingServiceCollection
this.adapterFactories.set('/chat/completions', oaiAdapterFactory);
requestHooks.forEach(requestHook => oaiAdapterFactory.addHooks(requestHook));
responseHooks.forEach(responseHook => oaiAdapterFactory.addHooks(undefined, responseHook));
this.requestHandlers.set('/graphql', { method: 'POST', handler: this.graphqlHandler.bind(this) });
this.requestHandlers.set('/models', { method: 'GET', handler: this.modelsHandler.bind(this) });
}
private async graphqlHandler(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
res.writeHead(200, { 'Content-Type': 'application/json' });
const data = {
viewer: {
login: '',
copilotEndpoints: {
api: `http://localhost:${this.config.port}`
}
}
};
res.end(JSON.stringify({ data }));
}
private async modelsHandler(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
res.writeHead(200, { 'Content-Type': 'application/json', 'x-github-request-id': 'TESTREQUESTID1234' });
const endpoints = await this.endpointProvider.getAllChatEndpoints();
const data = endpoints.map(e => {
return {
id: e.model,
name: e.model,
capabilities: {
supports: {
vision: e.supportsVision,
},
limits: {
max_prompt_tokens: e.modelMaxPromptTokens,
max_context_window_tokens: e.maxOutputTokens,
}
}
};
});
res.end(JSON.stringify({ data }));
}
}