From f815eba94212d7a24e3add501d51fa80a28d0fbb Mon Sep 17 00:00:00 2001 From: hubwriter Date: Wed, 28 Jan 2026 22:02:45 +0000 Subject: [PATCH 1/2] [2026-02-01] ACP Support in Copilot CLI [public preview] (#59333) Co-authored-by: Claire W <78226508+crwaters16@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- content/copilot/reference/acp-server.md | 398 ++++++++++++++++++++++++ content/copilot/reference/index.md | 1 + 2 files changed, 399 insertions(+) create mode 100644 content/copilot/reference/acp-server.md diff --git a/content/copilot/reference/acp-server.md b/content/copilot/reference/acp-server.md new file mode 100644 index 000000000000..8b5657007fb0 --- /dev/null +++ b/content/copilot/reference/acp-server.md @@ -0,0 +1,398 @@ +--- +title: "Copilot CLI ACP server" +shortTitle: ACP server +intro: "Learn about {% data variables.copilot.copilot_cli %}'s Agent Client Protocol server." +versions: + feature: copilot +topics: + - Copilot +category: + - Configure Copilot +contentType: reference +--- + + +## Overview + +Agent Client Protocol (ACP) is a standardized protocol that enables external clients, such as IDEs, editors, and other tools, to communicate with the {% data variables.product.prodname_copilot_short %} agent runtime. It provides a structured way to create and manage agent sessions, send prompts, receive streaming responses, and handle permission requests. + +## Architecture + +```text +┌─────────────────┐ ┌─────────────────────┐ +│ IDE / Editor │ ACP │ Copilot Agent │ +│ (ACP Client) │◄───────►│ Runtime │ +│ │ stdio/ │ (ACP Server) │ +│ │ TCP │ │ +└─────────────────┘ └─────────────────────┘ +``` + +The ACP server runs as part of {% data variables.copilot.copilot_cli %} and exposes the agent's capabilities through a well-defined protocol. + +## Starting the ACP server + +### Stdio Mode (Recommended for IDE Integration) + +```bash +copilot --acp --stdio +``` + +Communication happens over stdin/stdout using newline-delimited JSON (NDJSON). + +### TCP Mode + +```bash +copilot --acp --port 3000 +``` + +Communication happens over a TCP socket on the specified port. + +## Protocol flow + +### 1. Initialize connection + +```typescript +// Client sends initialize request +const response = await connection.initialize({ + clientInfo: { + name: "MyIDE", + version: "1.0" + } +}); + +// Server responds with capabilities +// { +// serverInfo: { name: "copilot-agent-runtime", version: "x.x.x" }, +// capabilities: { ... } +// } +``` + +### 2. Create a session + +```typescript +const session = await connection.newSession({ + cwd: "/path/to/project" +}); + +// Returns: { sessionId: "uuid-..." } +``` + +### 3. Send prompts + +```typescript +await connection.prompt({ + sessionId: session.sessionId, + prompt: [ + { type: "text", text: "Fix the authentication bug in login.ts" } + ] +}); +``` + +### 4. Receive session updates + +The client receives real-time updates via the `sessionUpdate` callback: + +```typescript +const client: acp.Client = { + async sessionUpdate(params) { + // params.state: "idle" | "working" + // params.lastUpdateId: number + // params.updates: Array of content updates + + for (const update of params.updates) { + switch (update.type) { + case "text": + console.log("Agent says:", update.text); + break; + case "tool": + console.log("Tool execution:", update.name, update.status); + break; + } + } + } +}; +``` + +### 5. Handle permission requests + +The agent requests permission for sensitive operations: + +```typescript +const client: acp.Client = { + async requestPermission(params) { + // params.request contains details about what permission is needed + // e.g., tool execution, file access, URL fetch + + // Display dialog to user and return their choice + return { + outcome: { + outcome: "selected", + optionId: "allow_once" // or "allow_always" or "reject_once" + } + }; + } +}; +``` + +## Content types + +### Text content + +```typescript +{ + type: "text", + text: "Your message here" +} +``` + +### Image content + +```typescript +{ + type: "image", + data: "", + mimeType: "image/png" // or "image/jpeg", "image/gif", "image/webp" +} +``` + +### Embedded resources + +```typescript +{ + type: "resource", + resource: { + uri: "file:///path/to/file.txt", + text: "file contents", + mimeType: "text/plain" + } +} +``` + +### Blob data + +```typescript +{ + type: "blob", + data: "", + mimeType: "application/octet-stream" +} +``` + +## Tool execution updates + +When the agent executes tools, clients receive detailed updates: + +```typescript +{ + type: "tool", + id: "tool-execution-id", + name: "edit", // Tool name + status: "running", // "running" | "completed" + kind: "edit", // Tool category + input: { ... }, // Tool parameters + output: { ... }, // Tool result (when completed) + diff: "..." // Diff content for edit operations +} +``` + +### Tool kinds + +| Kind | Description | +|------|-------------| +| `execute` | Command execution (bash) | +| `read` | File reading operations | +| `edit` | File modifications | +| `delete` | File deletions | +| `create` | File creation | +| `search` | Code search (grep, glob) | +| `fetch` | Web fetching | +| `agent` | Sub-agent invocation | +| `github` | GitHub API operations | +| `other` | Other tool types | + +## Permission types + +### Tool permissions + +Requested when the agent wants to execute a tool: + +```typescript +{ + type: "tool", + toolName: "bash", + input: { command: "npm install" } +} +``` + +### Path permissions + +Requested for file system access: + +```typescript +{ + type: "path", + path: "/path/to/sensitive/file", + operation: "write" // or "read" +} +``` + +### URL permissions + +Requested for network access: + +```typescript +{ + type: "url", + url: "https://api.example.com/data", + operation: "fetch" +} +``` + +## Session lifecycle + +```text +┌─────────────┐ +│ Created │ +└──────┬──────┘ + │ prompt() + ▼ +┌─────────────┐ +│ Working │◄───┐ +└──────┬──────┘ │ + │ │ prompt() + ▼ │ +┌─────────────┐ │ +│ Idle │────┘ +└──────┬──────┘ + │ destroy() + ▼ +┌─────────────┐ +│ Destroyed │ +└─────────────┘ +``` + +## Error handling + +Errors are communicated through the protocol's standard error response format: + +```typescript +{ + error: { + code: -32600, + message: "Invalid request", + data: { ... } + } +} +``` + +## Example: Full Client Implementation + +```typescript +import * as acp from '@anthropic/acp-sdk'; +import { spawn } from 'child_process'; + +async function main() { + // Start the ACP server + const process = spawn('copilot', ['--acp', '--stdio'], { + stdio: ['pipe', 'pipe', 'inherit'] + }); + + // Create transport stream + const stream = acp.ndJsonStream(process.stdin, process.stdout); + + // Define client handlers + const client: acp.Client = { + async requestPermission(params) { + console.log('Permission requested:', params.request); + // Auto-approve for this example + return { + outcome: { outcome: "selected", optionId: "allow_once" } + }; + }, + + async sessionUpdate(params) { + console.log(`Session ${params.sessionId} state: ${params.state}`); + for (const update of params.updates) { + if (update.type === 'text') { + process.stdout.write(update.text); + } else if (update.type === 'tool') { + console.log(`Tool: ${update.name} - ${update.status}`); + } + } + } + }; + + // Establish connection + const connection = new acp.ClientSideConnection(client, stream); + + // Initialize + await connection.initialize({ + clientInfo: { name: "example-client", version: "1.0.0" } + }); + + // Create session + const session = await connection.newSession({ + cwd: process.cwd() + }); + + // Send prompt + await connection.prompt({ + sessionId: session.sessionId, + prompt: [ + { type: "text", text: "List the files in the current directory" } + ] + }); + + // Wait for completion (in real app, handle via sessionUpdate) + await new Promise(resolve => setTimeout(resolve, 10000)); + + // Cleanup + process.kill(); +} + +main().catch(console.error); +``` + +## Configuration + +### Runtime settings + +The ACP server inherits settings from the {% data variables.product.prodname_copilot_short %} runtime: + +* **Model selection**: Configured via environment or runtime settings +* **Tool permissions**: Managed through the permission service +* **Logging**: Configurable log level and directory + +### Environment variables + +| Variable | Description | +|----------|-------------| +| `COPILOT_LOG_LEVEL` | Log verbosity (debug, info, warn, error) | +| `COPILOT_LOG_DIR` | Directory for log files | + +## Best practices + +1. **Use Stdio Mode for IDEs**: More reliable than TCP for local integrations +1. **Handle Permissions Gracefully**: Always implement the `requestPermission` callback +1. **Process Updates Incrementally**: Don't wait for completion to show progress +1. **Clean Up Sessions**: Call destroy when done to free resources +1. **Handle Reconnection**: Implement retry logic for network transports + +## Source files + +| File | Description | +|------|-------------| +| `src/cli/acp/server.ts` | Main ACP server implementation | +| `src/cli/acp/mapping.ts` | Event transformation layer | +| `src/cli/acp/permissionHandlers.ts` | Permission request handlers | +| `src/cli/acp/permissionMapping.ts` | Permission mapping utilities | + +## Testing + +ACP has end-to-end tests that can be run with: + +```bash +CI=true npm run test:cli-e2e -- test/cli/e2e/acp.test.ts +``` + +Test captures are available in `test/cli/e2e/captures/acp/` showing various content type handling scenarios. diff --git a/content/copilot/reference/index.md b/content/copilot/reference/index.md index b4c820a9f00e..b60d775408d8 100644 --- a/content/copilot/reference/index.md +++ b/content/copilot/reference/index.md @@ -12,6 +12,7 @@ children: - /copilot-feature-matrix - /keyboard-shortcuts - /custom-agents-configuration + - /acp-server - /hooks-configuration - /custom-instructions-support - /policy-conflicts From 5ffcb9685b31be3b7ab888804ade262213ee11c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 00:05:10 +0000 Subject: [PATCH 2/2] Bump github/gh-base-image/gh-base-noble from 20260126-172357-g0b997f8b3 to 20260128-000359-ga6d0dc7c0 in the baseimages group (#59395) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index dd3fa4e6e71b..35c61add1f54 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ # --------------------------------------------------------------- # To update the sha: # https://github.com/github/gh-base-image/pkgs/container/gh-base-image%2Fgh-base-noble -FROM ghcr.io/github/gh-base-image/gh-base-noble:20260126-172357-g0b997f8b3@sha256:738abde0d24406108b0eb4dc3ae2b934a4d2fb08750af8b80b36c16b4ca7ad18 AS base +FROM ghcr.io/github/gh-base-image/gh-base-noble:20260128-000359-ga6d0dc7c0@sha256:e2dd6aa64dc4b3fd0fee388a817b2ce0ce239f1da31fd628c359a74832abdfcb AS base # Install curl for Node install and determining the early access branch # Install git for cloning docs-early-access & translations repos