Sync models without an API key (public endpoint) + use real API metadata - #5
Draft
KRoperUK wants to merge 4 commits into
Draft
Sync models without an API key (public endpoint) + use real API metadata#5KRoperUK wants to merge 4 commits into
KRoperUK wants to merge 4 commits into
Conversation
- Fetch model list from CommandCode API on plugin config hook - Merge with local models.json (API provides context_length, local provides curated cost/tier/reasoning) - Persist merged result back to models.json for offline fallback - Treat empty API response as failure to avoid wiping local models - Add idempotency to saveModels (only write when content changed) - Add new models and fix context sizes in models.json - Add unit tests for mergeModels (pure) and integration tests using existing mockFetch helpers
- Switch from disk write to in-memory merge; sync updates no longer
persist between startups
- Add config-file opt-out at
~/.config/opencode/commandcode-go-opencode-provider.json
with `disableModelSync: true` to skip the API fetch entirely
- loadModels: throw actionable error on missing/corrupt bundled
models.json ("please reinstall commandcode-go-opencode-provider",
original error chained via Error.cause)
- Tests: add withFakeConfig / withMissingModels / withCorruptModels
helpers and structural assertions for bundled, opt-out, and
load-error paths
- README: document the opt-out workflow and bundled-list refresh
via `bun run sync`
…adata Builds on the auto-sync work. Three improvements to how the runtime sync discovers models: - Drop the COMMANDCODE_API_KEY requirement for the model fetch. The listing endpoint (/provider/v1/models) is public, so requiring the env var meant users who authenticate via /connect (the common case — it doesn't export the env var) got no auto-sync at all. The request now runs unauthenticated when no key is present, and still sends the key as a Bearer token when it is. - Use the display name the API returns for new API-only models, instead of deriving it from the id (e.g. "MiMo V2.5 Pro" rather than "mimo-v2.5-pro"). - Derive tier from the id namespace instead of hardcoding "open-source", and stop fabricating a 0.5/2 price for unpriced models (zeroed instead, so cost accounting isn't fed an invented rate). Tests: rework the "missing API key" case to assert the fetch still happens with no Authorization header and merges API-only models; add a test for the API-provided name. 87 pass, typecheck clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds directly on @augustoolucas's auto-sync work in #1 and tightens three things in how the runtime sync discovers models.
1. Sync works without an API key (the big one)
#1 gates the fetch behind
COMMANDCODE_API_KEY:But
/provider/v1/modelsis a public, unauthenticated endpoint (verified: it returns the full catalog with noAuthorizationheader). Most users authenticate via/connect, which does not exportCOMMANDCODE_API_KEY— so as written, auto-sync silently does nothing for them. This change runs the request unauthenticated when no key is present, and still sendsBearer <key>when one is:2. Use the display name the API returns
The endpoint returns a
namefield (e.g."MiMo V2.5 Pro"), but #1 derives the name from the id (id.split("/").pop()→"mimo-v2.5-pro").ApiModelnow capturesnameandmergeModelsprefers it, falling back to the id segment.3. Correct tier + honest pricing for API-only models
For models present in the API but not in the bundled
models.json, #1 hardcodestier: "open-source"andcost: { input: 0.5, output: 2 }. Tier is now derived from the id namespace (bare ids likegpt-*/claude-*are premium; namespaced are open-source), and the invented price is replaced with0/0so cost accounting isn't fed a fabricated rate.Tests
Authorizationheader and merges API-only models.nameis used for new models.bun test tests/unit/→ 87 pass, 0 fail;tsc --noEmitclean.🤖 Generated with Claude Code