Skip to content

feat(daemon): add Command Code as a model provider - #30

Open
rodrigovzq wants to merge 2 commits into
Gentleman-Programming:mainfrom
rodrigovzq:feat/command-code-provider
Open

rodrigovzq wants to merge 2 commits into
Gentleman-Programming:mainfrom
rodrigovzq:feat/command-code-provider

Conversation

@rodrigovzq

Copy link
Copy Markdown

What

Adds Command Code as a model provider, from the setup already used in OpenCode. Two providers share one API key and one gateway (https://api.commandcode.ai/provider/v1):

  • commandcode — OpenAI chat-completions API, 75 models (GPT, DeepSeek, Kimi, GLM, MiniMax, MiMo, Qwen, Gemini, Grok, …).
  • commandcode-anthropic — Anthropic messages API, 10 Claude models.

Sign in once in Accounts (the key stays in the assistant's own auth.json, 0600, or is read from COMMANDCODE_API_KEY); the models then appear in the picker grouped by provider.

How

  • packages/daemon/src/extensions/command-code.ts (new): two native Pi providers + the catalog. Self-contained, so the engine can load it with -e.
  • packages/daemon/src/auth.ts: registers both in the daemon's ModelRuntime, so Accounts lists them.
  • packages/daemon/src/daemon.ts and runtime-build.ts: pass -e …/command-code.ts to the engine (like the approval guard) and copy the file into the installed runtime.
  • Base URLs differ by design: the OpenAI SDK appends /chat/completions (base …/provider/v1), the Anthropic SDK appends /v1/messages (base …/provider); both reach /provider/v1/….

Tests

  • packages/daemon/test/command-code.test.ts (new): catalog ids/api/base URLs, both providers offered for API-key sign-in, login stores the key 0600 and a fresh runtime sees it, logout clears it.
  • runtime-build.test.ts / connectors-gateway.test.ts: updated for the copied extension and the engine -e argument.

pnpm typecheck, pnpm test (676 passed / 5 skipped) and biome check are green.

Notes

Offline runtime; a real sign-in and a live stream are not verified here. Spec: odd/tasks/gentle-dot.md S34/T35/L118.

@Alan-TheGentleman Alan-TheGentleman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this, Rodrigo. It's carefully done and the tests are solid. Three changes before we can merge it:

  1. Protect the extension. The engine loads command-code.ts with -e, but its path isn't in the guard's protectedPaths the way the approval guard's own file is. Since it's code the engine runs, please add it there so the agent's file tools can't rewrite it.
  2. Drop the edits to odd/tasks/gentle-dot.md. That file is the maintainer's log, and your S34/T35/L118 now collide with entries we've already added. Please keep the PR to code, tests, and docs.
  3. List the models from the gateway instead of a fixed catalog (75 + 10 today, with refreshModels empty). A hardcoded list goes stale as soon as Command Code adds or removes one. If the gateway exposes a models endpoint, use it with a small fallback.

Happy to review again once these are in.

@rodrigovzq

Copy link
Copy Markdown
Author

Thanks for the review, Alan. All three are in (b7e946f):

  1. Extension protected. The daemon now marks both -e extensions as protected paths. I generalized the single guardPath option to extensionPaths, so the approval guard's file and command-code.ts are both covered.
  2. odd/tasks/gentle-dot.md dropped. Reverted; the PR is code, tests, and docs only.
  3. Models from the gateway. The providers now read GET /provider/v1/models and filter by supported_endpoints (/chat/completions for commandcode, /messages for commandcode-anthropic), so each provider gets its own list. The static catalog stays as the offline fallback and still supplies the values the gateway does not publish (output limit, cost). A blocked or failed fetch keeps the fallback.

Verified: pnpm typecheck, pnpm test 679 passed / 5 skipped, biome check clean. Happy to adjust the refresh wiring if you'd do it differently.

Two providers behind one Command Code key and gateway:
- commandcode: OpenAI chat-completions, 75 models.
- commandcode-anthropic: Anthropic messages, 10 Claude models.

The daemon registers both in its ModelRuntime (Accounts sign-in and the model
picker) and loads the same module into the engine with -e, like the approval
guard; runtime-build.ts copies it into the installed app. Sign-in keeps the key
in the assistant's own auth.json (0600), or reads COMMANDCODE_API_KEY. The base
URLs differ by design: the OpenAI SDK appends /chat/completions and the Anthropic
SDK /v1/messages, so both reach /provider/v1/... .

Spec: odd/tasks/gentle-dot.md S34/T35/L118.
…gateway

Addresses the review on the Command Code provider:
- Both engine extensions (approval guard and Command Code) are now protected
  paths, so the agent's file tools cannot rewrite them. extensionPaths replaces
  the single guardPath option.
- The catalog is read from the gateway's GET /provider/v1/models and filtered by
  supported_endpoints (/chat/completions for commandcode, /messages for
  commandcode-anthropic); the static list stays as the offline fallback.
- Drops the odd/tasks/gentle-dot.md edits: that log belongs to the maintainers.

pnpm typecheck, pnpm test 679 passed / 5 skipped, biome clean.
@rodrigovzq
rodrigovzq force-pushed the feat/command-code-provider branch from b7e946f to 1393931 Compare October 13, 2026 16:51
@rodrigovzq

Copy link
Copy Markdown
Author

@Alan-TheGentleman all three items are in (1393931), and I rebased the branch onto main so it is mergeable again. Could you take another look when you get a chance? No rush.

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