Repository navigation
feat(agent): manage Copilot CLI and VS Code Copilot Chat - #135
Conversation
16214d3 to
a0f8d73
Compare
23360c9 to
4318c32
Compare
|
@copilot resolve the merge conflicts in this pull request |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Permission drift can expose pairing values, and an invalid VS Code sidecar can prevent restoration of user settings.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Adds managed GitHub Copilot CLI and VS Code Copilot Chat routing through the local LLM proxy.
Changes:
- Adds Copilot/VS Code configuration reconcilers, discovery, schemas, and controller UI.
- Adds proxy authentication, GitHub OAuth, pass-through, and WebSocket support.
- Expands lifecycle tests, fixtures, and documentation.
| File | Description |
|---|---|
schema/daemon-config.md |
Documents new configuration keys. |
schema/daemon-config.json |
Adds generated schemas for proxy and Copilot programs. |
README.md |
Documents proxy setup, routes, security, and managed programs. |
frontend/ui/src/tools.tsx |
Adds Copilot CLI display metadata. |
frontend/desktop/src/views/StatusView.stories.tsx |
Covers bound and failed proxy states. |
frontend/desktop/src/types.ts |
Types proxy status information. |
frontend/desktop/src/stories/fixtures.ts |
Adds proxy status fixtures. |
frontend/desktop/src/components/DaemonInformation.tsx |
Displays local proxy status. |
frontend/controller/src/views/ConfigurationView.tsx |
Adds proxy URL and Copilot program controls. |
frontend/controller/src/types.ts |
Extends controller configuration types. |
crates/core/src/model.rs |
Adds proxy status models. |
crates/core/src/config.rs |
Adds and validates proxy and Copilot configuration. |
crates/agent/tests/integration.rs |
Registers Copilot integration tests. |
crates/agent/tests/common/gateway.rs |
Captures forwarded LLM tokens. |
crates/agent/tests/common/container.rs |
Improves container file and process handling. |
crates/agent/src/remote.rs |
Bounds controller credential requests. |
crates/agent/src/reconcile/plan.rs |
Adds private-directory planning. |
crates/agent/src/reconcile/mod.rs |
Registers new reconcilers and proxy context. |
crates/agent/src/provider/vscode/testdata/Dockerfile |
Prepares VS Code test runtime state. |
crates/agent/src/provider/vscode/testdata/chatLanguageModels.lab.json |
Adds a managed-model fixture. |
crates/agent/src/provider/vscode/settings.rs |
Manages Copilot CAPI settings in JSONC. |
crates/agent/src/provider/vscode/reconcile.rs |
Manages custom endpoint models. |
crates/agent/src/provider/vscode/mod.rs |
Integrates VS Code reconciliation. |
crates/agent/src/provider/vscode/integration_tests.rs |
Tests both VS Code modes and tunneling. |
crates/agent/src/provider/vscode/discovery.rs |
Exposes the shared VS Code profile path. |
crates/agent/src/provider/README.md |
Updates the provider feature matrix. |
crates/agent/src/provider/mod.rs |
Registers Copilot and proxy context. |
crates/agent/src/provider/json_merge.rs |
Adds root-array and keyed-array merging. |
crates/agent/src/provider/copilot/testdata/providers.lab.json |
Adds a Copilot provider fixture. |
crates/agent/src/provider/copilot/testdata/Dockerfile |
Adds a Copilot CLI test image. |
crates/agent/src/provider/copilot/reconcile.rs |
Reconciles Copilot CLI providers and models. |
crates/agent/src/provider/copilot/mod.rs |
Integrates the Copilot provider. |
crates/agent/src/provider/copilot/integration_tests.rs |
Tests Copilot lifecycle and proxy routing. |
crates/agent/src/provider/copilot/discovery.rs |
Discovers Copilot CLI installations. |
crates/agent/src/provider/claude_code/mod.rs |
Updates reconcile test context. |
crates/agent/src/oidc.rs |
Extends authorization pages for GitHub. |
crates/agent/src/lib.rs |
Registers proxy and GitHub OAuth modules. |
crates/agent/src/identity.rs |
Adds device-ID-only loading. |
crates/agent/src/github_oauth.rs |
Implements GitHub device authorization and refresh. |
crates/agent/src/github_oauth.html |
Adds the GitHub authorization page. |
crates/agent/src/gateway_oidc.rs |
Chains GitHub authorization after OIDC. |
crates/agent/src/api.rs |
Exposes shared gateway credential acquisition. |
crates/agent/Cargo.toml |
Adds agent proxy and JSONC dependencies. |
Cargo.toml |
Adds workspace networking and JSONC dependencies. |
Cargo.lock |
Locks the new dependencies. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let action = match existing.as_deref() { | ||
| Some(existing) if existing == contents => "unchanged", | ||
| Some(_) => "update", | ||
| None => "create", | ||
| }; | ||
| plan.record_diff( | ||
| record( | ||
| plan, | ||
| display_name, | ||
| description, | ||
| action, | ||
| path, | ||
| existing.as_deref(), | ||
| Some(&contents), | ||
| options.redact_diff, | ||
| ); | ||
|
|
||
| if action != "unchanged" { | ||
| plan.write_file(path, &contents, 0o644)?; | ||
| plan.write_file(path, &contents, options.mode)?; |
| let state = bytes.as_deref().and_then(|bytes| { | ||
| let state = read_state(bytes); | ||
| if state.is_none() { | ||
| warn!(path = %state_path.display(), "ignoring a VS Code settings sidecar that cannot be parsed"); | ||
| } | ||
| state |
There was a problem hiding this comment.
Fixed in 6bcbcb6: an unreadable .settings.json.agentdesktop now fails the apply, as the providers.json and chatLanguageModels.json sidecars already do, so the user's earlier overrideCapiUrl is never dropped. The error names the path (and the line and column for a syntax error), never a value from the file; the README says to fix or delete it. Test: corrupt_sidecar_does_not_lose_the_users_override.
Part of agentdesktop-dev#86. Two programs that point Copilot at the local LLM proxy, user mode only: - `programs.copilot` writes the Copilot CLI's BYOK provider registry (`~/.copilot/providers.json`, or `$COPILOT_HOME` / `COPILOT_PROVIDERS_CONFIG`): providers `agentdesktop` (OpenAI-shaped) and `agentdesktop-anthropic` on the proxy's `/copilot-cli` route, with the pairing header; the user's own providers are kept. Discovery reports the CLI and its version from the npm manifest. - `programs.vscode` with `copilotChat: ownModels` (default) writes `chatLanguageModels.json` for Copilot Chat's built-in Custom Endpoint provider on `/vscode-copilot`; the user's entries are kept. - `copilotChat: githubModels` keeps GitHub's own models and the user's Copilot seat: the daemon sets `github.copilot.advanced.debug.overrideCapiUrl` in the user `settings.json` to the proxy's `/vscode-copilot-capi/<pairing>` route (pairing in the path, since VS Code cannot add a header), forwards to `llmGateway.proxyUrl` with the client's Copilot token moved aside, tunnels the Responses WebSocket for agent mode, forwards `_ping` without a credential, and keeps the override out of Settings Sync. `settings.json` is edited in place (JSONC): only the managed keys change, comments, key order and formatting stay, and removal restores the file byte for byte. Managed files are written 0600 and carry a sidecar that records what the daemon added, so removal takes out exactly that. A file the daemon cannot parse is a conflict and left alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…recision - Copilot CLI: removing our providers by their pairing header (no sidecar) no longer adds "models": null to a providers.json that has no models key. - README: the CAPI WebSocket tunnel closes after 4 to 5 minutes with the controller's default gatewayJwt.lifetime, also mid-turn; VS Code's reconnect behaviour is not verified. - README: the settings.json removal exceptions are listed in full (multi-line empty object, comment-only file). - README: the providers.json sidecar holds the user's own apiKey values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4318c32 to
588c8a8
Compare
…idecar mode repaired Review on agentdesktop-dev#135. - `.settings.json.agentdesktop` that is not JSON or not a known settings state now fails the apply, as the providers.json and chatLanguageModels.json sidecars already do: like a conflict, every managed file on the device stays untouched, also while `programs.vscode` is not configured (removal reads the sidecar too), and the daemon does not start. Before, the sidecar was ignored and rebuilt from the sidecar-less rules, so a user's own `overrideCapiUrl` was lost on removal. The error names the sidecar path and, for a syntax error, the line and column only, never a value. A sidecar without `version` (the earlier whole-document form) is still upgraded; a leading byte-order mark is accepted. - An identical sidecar whose mode is looser than 0600 is written again at 0600, as settings.json is; settings.json and its sidecar use the same check (a 0700 settings.json is now also tightened). The rewrite of the sidecar alone is not shown in the plan summary, since settings.json is unchanged. - README: the unreadable-sidecar behaviour and the sidecar's mode. Behaviour change: the test `an_unreadable_sidecar_warns_and_apply_proceeds` is replaced. Tests: 9 new, 2 of them unix-only. The file-mode tests in this module (old and new) assume umask 022. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Part of #86 (series overview: #86 overview). Stacked on #134; review the last three commits (the second fixes a providers.json edge case and makes the README more precise; the third addresses the review below).
Why
The clients still have to be pointed at the proxy by hand, on each machine, with the pairing value.
Change
Two managed programs, user mode only.
programs.copilotwrites the Copilot CLI's bring-your-own-key provider file (~/.copilot/providers.json). It adds two providers on/copilot-cliand keeps the user's own.programs.vscode,copilotChat: ownModels(default), writeschatLanguageModels.jsonfor Copilot Chat's Custom Endpoint provider on/vscode-copilot.copilotChat: githubModelskeeps GitHub's models and the user's Copilot seat:github.copilot.advanced.debug.overrideCapiUrl(the Copilot API base URL) in the usersettings.jsonto/vscode-copilot-capi/<pairing>. The pairing value is in the path, because VS Code cannot add a header.x-llm-token, puts the gateway identity inAuthorization, and forwards tollmGateway.proxyUrl.settings.jsonis edited in place (JSONC): only the managed keys change. Removal restores the file byte for byte.Risk and compatibility
overrideCapiUrlis an undocumented Copilot Chat setting.How to review
provider/copilot/reconcile.rsandprovider/vscode/{reconcile,settings}.rshold the three writers.llm_proxy.rsadditions hold the Copilot API route and the tunnel.json_merge.rsadds root-array support.Review fixes
The last commit (6bcbcb6) addresses the Copilot review:
.settings.json.agentdesktopnow fails the apply, as the providers.json and chatLanguageModels.json sidecars already do. Before, it was ignored and the user's ownoverrideCapiUrlwas lost on removal. The error names the path and, for a syntax error, the line and column, never a value.failed, both files unchanged, the user's value back after removal).Tests
CI green, including Docker lifecycle tests for all three writers and the WebSocket tunnel. Lab-tested on a Linux VM with VS Code 1.139, Copilot CLI 1.0.88 and a Copilot Business seat; the steps are in the guide in #138. After the rebase onto the review fixes in #134, the WebSocket tunnel takes its deadline from the shared credential fetch; that change is covered by unit tests only, not re-tested on the live Copilot path. The tunnel closes when that credential expires (4 to 5 minutes with the default
gatewayJwt.lifetime), also mid-turn; whether VS Code then reconnects without the user noticing has not been verified.Follow-ups
--dry-runpreview for the Copilot programs: No --dry-run preview for the Copilot programs LutzLange/agentdesktop#25.Screenshot
Controller configuration view with the two Copilot programs and the pass-through URL.
🤖 Generated with Claude Code