Skip to content

feat: add copilot-acp provider#8154

Merged
codefromthecrypt merged 1 commit into
mainfrom
feat/copilot-acp-provider
Mar 30, 2026
Merged

feat: add copilot-acp provider#8154
codefromthecrypt merged 1 commit into
mainfrom
feat/copilot-acp-provider

Conversation

@codefromthecrypt
Copy link
Copy Markdown
Collaborator

Summary

Add an ACP provider for GitHub's Copilot CLI. Copilot CLI supports ACP natively via its --acp flag.

Notable limitations

  • MCP not yet supported: copilot ignores mcpServers in session/new (github/copilot-cli#1040)
  • No session/close
  • No terminal or fs delegation: all execution is local

Type of Change

  • Feature
  • Tests

AI Assistance

  • This PR was created or reviewed with AI assistance

Testing

Provider integration tests

$ source bin/activate-hermit
$ npm install -g @github/copilot
$ cargo test --test providers -- test_copilot_acp_provider --nocapture
running 1 test
=== copilot-acp::model_listing ===
&models = [
    "claude-sonnet-4.6", "claude-sonnet-4.5", "claude-haiku-4.5",
    "claude-opus-4.6", "claude-opus-4.5", "claude-sonnet-4",
    "gpt-5.4", "gpt-5.3-codex", "gpt-5.2-codex", "gpt-5.2",
    "gpt-5.1-codex-max", "gpt-5.1-codex", "gpt-5.1",
    "gpt-5.4-mini", "gpt-5.1-codex-mini", "gpt-5-mini", "gpt-4.1",
]
=== copilot-acp::basic_response === Hello! 👋 How can I help you today?
=== copilot-acp::model_switch (claude-sonnet-4.6 -> gpt-4.1) === Hello! 👋 How can I help you today?
=== copilot-acp::permission_allow ===
=== copilot-acp::permission_deny ===
test test_copilot_acp_provider ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 19 filtered out; finished in 36.69s

============== Providers ==============
✅ copilot-acp
=======================================

MCP tool tests skipped — github/copilot-cli#1040.

Goose CLI

$ GOOSE_PROVIDER=copilot-acp GOOSE_MODEL=current RUST_LOG=debug,sacp=trace target/release/goose run -t 'say hello'

    __( O)>  ● new session · copilot-acp current
   \____)    20260327_1
     L L     goose is ready
Hello! How can I help you with the goose project today?
$ grep -rh 'resolved ACP model' ~/.local/state/goose/logs/
{"timestamp":"2026-03-27T15:00:00.309339Z","level":"INFO","fields":{"message":"resolved ACP model","from":"current","to":"claude-sonnet-4.6"},"target":"goose::acp::provider"}

Goose CLI — permission routing (approve mode)

$ rm -rf ~/.local/state/goose/logs ~/.local/share/goose/sessions
$ GOOSE_PROVIDER=copilot-acp GOOSE_MODEL=current GOOSE_MODE=approve RUST_LOG=debug,sacp=trace target/release/goose run -t 'Write the word hello to /tmp/test-copilot-acp.txt'

    __( O)>  ● new session · copilot-acp current
   \____)    20260327_1
     L L     goose is ready
$ grep -rh 'request_permission' ~/.local/state/goose/logs/ | head -1
{"timestamp":"2026-03-27T15:01:36.152998Z","level":"TRACE","fields":{"message":"Received JSON-RPC message","message":"{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"session/request_permission\",\"params\":{\"sessionId\":\"8c5ef659-503a-4e47-bfda-d19598962e12\",\"toolCall\":{\"toolCallId\":\"shell-permission\",\"title\":\"Write hello to file\",\"kind\":\"execute\",\"status\":\"pending\",\"rawInput\":{\"command\":\"echo \\\"hello\\\" > /tmp/test-copilot-acp.txt\",\"commands\":[\"echo \\\"hello\\\" > /tmp/test-copilot-acp.txt\"]}},\"options\":[{\"optionId\":\"allow_once\",\"kind\":\"allow_once\",\"name\":\"Allow once\"},{\"optionId\":\"allow_always\",\"kind\":\"allow_always\",\"name\":\"Always allow\"},{\"optionId\":\"reject_once\",\"kind\":\"reject_once\",\"name\":\"Deny\"}]}}"},"target":"sacp::jsonrpc::transport_actor"}

Copilot-side logs (~/.copilot/logs/)

$ cat $(ls -t ~/.copilot/logs/process-*.log | head -1)
2026-03-27T15:01:26.901Z [INFO] Starting ACP server (stdio)
2026-03-27T15:01:28.861Z [INFO] MCP config prepared for ACP mode
2026-03-27T15:01:28.861Z [INFO] ACP server started (stdio mode)
2026-03-27T15:01:28.862Z [INFO] ACP initialize request from client: unknown
2026-03-27T15:01:30.139Z [INFO] Created ACP session: bc0c6272-e52b-4683-a747-9c620a34a44c
2026-03-27T15:01:31.084Z [INFO] Created ACP session: 8c5ef659-503a-4e47-bfda-d19598962e12
2026-03-27T15:01:31.663Z [INFO] Created ACP session: 0780520e-8672-49da-8365-5959f960752c
2026-03-27T15:01:31.667Z [INFO] Using default model: claude-sonnet-4.6

Signed-off-by: Adrian Cole <adrian@tetrate.io>
@codefromthecrypt codefromthecrypt force-pushed the feat/copilot-acp-provider branch from cb61f72 to de40be8 Compare March 27, 2026 15:09
@codefromthecrypt
Copy link
Copy Markdown
Collaborator Author

codefromthecrypt commented Mar 27, 2026

@michaelneale @DOsinga @alexhancock FYI this is the only ACP provider so far that eagerly persists ACP sessions on session/new. the other 3 only persist after first prompt.

What this means is that for goose term which expects a session to survive before a prompt is sent, all but this ACP provider will have a glitch we need to think through.

@codefromthecrypt
Copy link
Copy Markdown
Collaborator Author

oops was wrong.. copilot does write logs even before a session has a prompt, but it doesn't support load really as everything is process-local. github/copilot-cli#1767

Copy link
Copy Markdown
Collaborator

@DOsinga DOsinga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good — clean, follows the existing ACP provider pattern exactly, CI passes.

One thought for a follow-up: now that we have three ACP providers (claude-acp, codex-acp, copilot-acp) that are structurally almost identical — same from_env skeleton, same ProviderDef impl, just different constants and mode/permission mappings — would it make sense to turn these into a declarative ACP provider type? Something like the existing declarative OpenAI-compatible providers, where each ACP provider is just a config struct (binary name, mode mapping, permission mapping, setup steps, etc.) and the shared from_env logic lives in one place.

Not blocking this PR on that — just curious what you think. You built the ACP infra so you'd know best whether the remaining differences (codex-acp's sandbox args, claude-acp's env_remove, etc.) make that awkward or whether they'd fit cleanly into a config-driven approach.

@codefromthecrypt codefromthecrypt added this pull request to the merge queue Mar 30, 2026
Merged via the queue into main with commit 764760e Mar 30, 2026
25 checks passed
@codefromthecrypt codefromthecrypt deleted the feat/copilot-acp-provider branch March 30, 2026 14:22
michaelneale added a commit that referenced this pull request Mar 30, 2026
* origin/main:
  removed unused welcome route (#8196)
  fix: use build_host_url for GCP Vertex AI location fallback (#8185)
  fix: remove ui/acp/.npmrc to allow auth token inheritance
  fix(openai): use safely_parse_json for streaming tool arguments (#8208)
  feat: add copilot-acp provider (#8154)
  chore(deps): bump path-to-regexp from 8.3.0 to 8.4.0 in /evals/open-model-gym/mcp-harness (#8178)
  fix: add NODE_AUTH_TOKEN and always-auth (#8163)
  fix: i18n compile on windows (#8202)
hydrosquall pushed a commit to hydrosquall/goose that referenced this pull request Mar 31, 2026
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Signed-off-by: Cameron Yick <cameron.yick@datadoghq.com>
@codefromthecrypt
Copy link
Copy Markdown
Collaborator Author

@DOsinga I completely agree. I will raise a pr on this

lifeizhou-ap added a commit that referenced this pull request Apr 1, 2026
* origin/main: (85 commits)
  docs: standardize on ~/.agents/skills/ as canonical skill path (#8239)
  feat: bump versions (already published) (#8240)
  Revert "fix: rename bin for the tui (#8231)" (#8238)
  docs: update reusable recipes docs (#8232)
  docs: add GOOSE_SHELL env var (#8233)
  feat(security): add egress logging inspector (#8149)
  blog: Adversary Mode — A Second Pair of Eyes on Every Tool Call (#8220)
  fix: rename bin for the tui (#8231)
  feat: goose serve (#8209)
  refactor: make --text mode independent of the normal TUI (#8210)
  refactor: handle complex streaming/scrolling with better rendering (#8214)
  Add Inference Mesh settings tab (#8094)
  only run windows compile on main branch (#8216)
  used simplified privacy info modal and removed unnecessary components (#8200)
  removed unused welcome route (#8196)
  fix: use build_host_url for GCP Vertex AI location fallback (#8185)
  fix: remove ui/acp/.npmrc to allow auth token inheritance
  fix(openai): use safely_parse_json for streaming tool arguments (#8208)
  feat: add copilot-acp provider (#8154)
  chore(deps): bump path-to-regexp from 8.3.0 to 8.4.0 in /evals/open-model-gym/mcp-harness (#8178)
  ...

# Conflicts:
#	ui/desktop/.gitignore
#	ui/desktop/src/components/Layout/CondensedRenderer.tsx
#	ui/desktop/src/components/Layout/navigation/ChatSessionsDropdown.tsx
#	ui/desktop/src/components/Layout/navigation/SessionsList.tsx
#	ui/desktop/src/components/ParameterInputModal.tsx
#	ui/desktop/src/components/parameter/ParameterInput.tsx
#	ui/desktop/src/components/recipes/RecipeActivityEditor.tsx
#	ui/desktop/src/components/recipes/shared/CreateSubRecipeInline.tsx
#	ui/desktop/src/main.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants