Skip to content
Merged
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
5 changes: 3 additions & 2 deletions nodejs/src/protocols/acp/acp-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,10 @@ class AcpConnection implements ProtocolConnection {

if (config.model) {
const id = ++this.requestId;
await this.transport.sendRequest(id, "session/set_model", {
await this.transport.sendRequest(id, "session/set_config_option", {
sessionId,
modelId: config.model,
configId: "model",
value: config.model,
});
}
}
Expand Down
26 changes: 9 additions & 17 deletions nodejs/src/protocols/acp/acp-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,31 +87,23 @@ export interface AcpServerCapabilities {
// ============================================================================

/**
* ACP session/set_model request params
* ACP session/set_config_option request params
* @see https://agentclientprotocol.com/protocol/session-config-options
*/
export interface AcpSetModelParams {
export interface AcpSetConfigOptionParams {
sessionId: string;
modelId: string;
configId: string;
value: string;
}

/**
* ACP session/set_model response
* ACP session/set_config_option response
* Returns the complete configuration state after the change.
*/
export interface AcpSetModelResult {}

/**
* ACP session/set_mode request params
*/
export interface AcpSetModeParams {
sessionId: string;
modeId: string;
export interface AcpSetConfigOptionResult {
[configId: string]: string;
}

/**
* ACP session/set_mode response
*/
export interface AcpSetModeResult {}

// ============================================================================
// ACP Session Types
// ============================================================================
Expand Down
24 changes: 15 additions & 9 deletions nodejs/test/protocols/acp/acp-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
await new Promise((resolve) => setImmediate(resolve));

// Verify spawn was called with only cliArgs (no SDK-managed args)
expect(spawn).toHaveBeenCalledWith(

Check failure on line 60 in nodejs/test/protocols/acp/acp-adapter.test.ts

View workflow job for this annotation

GitHub Actions / Node.js SDK Tests (windows-latest)

test/protocols/acp/acp-adapter.test.ts > AcpProtocolAdapter > start > should spawn CLI with correct arguments for ACP (no --headless, --stdio, --log-level)

AssertionError: expected "vi.fn()" to be called with arguments: [ 'gemini', …(2) ] Received: 1st vi.fn() call: @@ -1,12 +1,206 @@ [ - "gemini", + "cmd", [ + "/c", + "gemini", "--experimental-acp", ], - ObjectContaining { + { "cwd": "/test/dir", + "env": { + "ACTIONS_ORCHESTRATION_ID": "4416e788-ef3a-4441-b1a6-629cd3f07aeb.test.windows-latest", + "ACTIONS_RUNNER_ACTION_ARCHIVE_CACHE": "C:\\actionarchivecache\\", + "AGENT_TOOLSDIRECTORY": "C:\\hostedtoolcache\\windows", + "ALLUSERSPROFILE": "C:\\ProgramData", + "ANDROID_HOME": "C:\\Android\\android-sdk", + "ANDROID_NDK": "C:\\Android\\android-sdk\\ndk\\27.3.13750724", + "ANDROID_NDK_HOME": "C:\\Android\\android-sdk\\ndk\\27.3.13750724", + "ANDROID_NDK_LATEST_HOME": "C:\\Android\\android-sdk\\ndk\\29.0.14206865", + "ANDROID_NDK_ROOT": "C:\\Android\\android-sdk\\ndk\\27.3.13750724", + "ANDROID_SDK_ROOT": "C:\\Android\\android-sdk", + "ANT_HOME": "C:\\ProgramData\\chocolatey\\lib\\ant\\tools\\apache-ant-1.10.15", + "APPDATA": "C:\\Users\\runneradmin\\AppData\\Roaming", + "AZURE_CONFIG_DIR": "C:\\azureCli", + "AZURE_DEVOPS_CACHE_DIR": "C:\\azureDevOpsCli\\cache", + "AZURE_EXTENSION_DIR": "C:\\Program Files\\Common Files\\AzureCliExtensionDirectory", + "AZ_DEVOPS_GLOBAL_CONFIG_DIR": "C:\\azureDevOpsCli", + "BASE_URL": "/", + "CABAL_DIR": "C:\\cabal", + "CHOCOLATEYINSTALL": "C:\\ProgramData\\chocolatey", + "CHROMEWEBDRIVER": "C:\\SeleniumWebDrivers\\ChromeDriver", + "CI": "true", + "COBERTURA_HOME": "C:\\cobertura-2.1.1", + "COLOR": "0", + "COMMONPROGRAMFILES": "C:\\Program Files\\Common Files", + "COMMONPROGRAMFILES(X86)": "C:\\Program Files (x86)\\Common Files", + "COMMONPROGRAMW6432": "C:\\Program Files\\Common Files", + "COMPUTERNAME": "runnervm9tapx", + "COMSPEC": "C:\\Windows\\system32\\cmd.exe", + "CONDA": "C:\\Miniconda", + "COPILOT_CLI_PATH": "D:/a/copilot-sdk-acp/copilot-sdk-acp/nodejs/node_modules/@github/copilot/index.js", + "COPILOT_HMAC_KEY": "", + "DEV": "1", + "DOTNET_MULTILEVEL_LOOKUP": "0", + "DOTNET_NOLOGO": "1", + "DOTNET_SKIP_FIRST_TIME_EXPERIENCE": "1", + "DRIVERDATA": "C:\\Windows\\System32\\Drivers\\DriverData", + "EDGEWEBDRIVER": "C:\\SeleniumWebDrivers\\EdgeDriver", + "EDITOR": "C:\\Windows\\notepad.exe", + "ENABLE_RUNNER_TRACING": "true", + "EXEPATH": "C:\\Program Files\\Git\\bin", + "FORCE_TTY": "", + "GCM_INTERACTIVE": "Never", + "GECKOWEBDRIVER": "C:\\SeleniumWebDrivers\\GeckoDriver", + "GHCUP_INSTALL_BASE_PREFIX": "C:\\", + "GHCUP_MSYS2": "C:\\msys64", + "GITHUB_ACTION": "__run_7", + "GITHUB_ACTIONS": "true", + "GITHUB_ACTION_REF": "", + "GITHUB_ACTION_REPOSITORY": "", + "GITHUB_ACTOR": "yazelin", + "GITHUB_ACTOR_ID": "6235553", + "GITHUB_API_URL": "https://api.github.com", + "GITHUB_BASE_REF": "main", + "GITHUB_ENV": "D:\\a\\_temp\\_runner_file_commands\\set_env_04c03f5d-c1a0-4471-a816-7c4568627371", + "GITHUB_EVENT_NAME": "pull_request", + "GITHUB_EVENT_PATH": "D:\\a\\_temp\\_github_workflow\\event.json", + "GITHUB_GRAPHQL_URL": "https://api.github.com/graphql", + "GITHUB_HEAD_REF": "fix/use-standard-acp-config-option", + "GITHUB_JOB": "test", + "GITHUB_OUTPUT": "D:\\a\\_temp\\_runner_file_commands\\set_output_04c03f5d-c1a0-4471-a816-7c4568627371", + "GITHUB_PATH": "D:\\a\\_temp\\_runner_file_commands\\add_path_04c03f5d-c1a0-4471-a816-7c4568627371", + "GITHUB_REF": "refs/pull/7/merge", + "GITHUB_REF_NAME": "7/merge", + "GITHUB_REF_PROTECTED": "false", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "yazelin/copilot-sdk-acp", + "GITHUB_REPOSITORY_ID": "1150207417", + "GITHUB_REPOSITORY_OWNER": "yazelin", + "GITHUB_REPOSITORY_OWNER_ID": "6235553", + "GITHUB_RETENTION_DAYS": "90", +
"gemini",
["--experimental-acp"],
expect.objectContaining({
Expand Down Expand Up @@ -158,11 +158,16 @@
};
mockProcess.stdout.write(JSON.stringify(response) + "\n");

// session.create with model triggers session/set_model
// session.create with model triggers session/set_config_option
await new Promise((resolve) => setImmediate(resolve));
const sentData2 = mockProcess.stdin.read();
const sentMessage2 = JSON.parse(sentData2.toString().trim());
expect(sentMessage2.method).toBe("session/set_model");
expect(sentMessage2.method).toBe("session/set_config_option");
expect(sentMessage2.params).toEqual({
sessionId: "acp-session-123",
configId: "model",
value: "gemini-pro",
});

const response2 = {
jsonrpc: "2.0",
Expand All @@ -175,7 +180,7 @@
expect(result).toEqual({ sessionId: "acp-session-123" });
});

it("should call session/set_model after session.create when model is provided", async () => {
it("should call session/set_config_option after session.create when model is provided", async () => {
adapter.start();
await new Promise((resolve) => setImmediate(resolve));

Expand Down Expand Up @@ -203,16 +208,17 @@
// Wait for the set_model request to be sent
await new Promise((resolve) => setImmediate(resolve));

// Read the session/set_model request
// Read the session/set_config_option request
const sentData2 = mockProcess.stdin.read();
const sentMessage2 = JSON.parse(sentData2.toString().trim());
expect(sentMessage2.method).toBe("session/set_model");
expect(sentMessage2.method).toBe("session/set_config_option");
expect(sentMessage2.params).toEqual({
sessionId: "acp-session-456",
modelId: "claude-sonnet-4-5-20250929",
configId: "model",
value: "claude-sonnet-4-5-20250929",
});

// Respond to session/set_model
// Respond to session/set_config_option
const response2 = {
jsonrpc: "2.0",
id: sentMessage2.id,
Expand All @@ -224,7 +230,7 @@
expect(result).toEqual({ sessionId: "acp-session-456" });
});

it("should not call session/set_model when model is not provided", async () => {
it("should not call session/set_config_option when model is not provided", async () => {
adapter.start();
await new Promise((resolve) => setImmediate(resolve));

Expand All @@ -251,7 +257,7 @@
const result = await createPromise;
expect(result).toEqual({ sessionId: "acp-session-789" });

// Verify no additional request was sent (no session/set_model)
// Verify no additional request was sent (no session/set_config_option)
await new Promise((resolve) => setImmediate(resolve));
const extraData = mockProcess.stdin.read();
expect(extraData).toBeNull();
Expand Down
Loading