alibaba / alibaba/open-code-review
refactor(llm): make Go provider registry the single source of truth for the VS Code preset
- Dominant language
- Go
- Stars
- 24.4k
- Forks
- 1.8k
- Avg merge
- 2d 4m
- Merged PRs (30d)
- 102
Description
## Description
The built-in provider registry is currently maintained in **two hand-synced copies**:
- Go (source of truth for the CLI, also the `--model` allowlist): `internal/llm/providers.go` (`var registry`)
- TypeScript (VS Code extension preset): `extensions/vscode/src/shared/providers.ts` (`PROVIDER_PRESETS`)
The TS file even carries the comment `与 internal/llm/providers.go 内置 registry 对齐` ("kept in sync with providers.go"), but there is **no automated check** enforcing it — so the two have already drifted:
| provider | Go `providers.go` | VS Code `providers.ts` |
|---|---|---|
| `anthropic` | `claude-opus-5, claude-sonnet-5, claude-opus-4-8, 4-7, 4-6, sonnet-4-6` | `claude-opus-4-8, 4-7, 4-6, sonnet-4-6` (missing `opus-5` / `sonnet-5`) |
| `volcengine` | 6 models incl. `doubao-seed-evolving`, `doubao-seed-2-1-*` | only 3 (`doubao-seed-2-0-*`) |
| `tencent-tokenhub` | deepseek / glm / kimi / minimax (11 models) | only `hy3-preview` |
This is user-visible: VS Code users cannot pick models that the CLI already supports (e.g. the latest `claude-opus-5`).
This was discovered while reviewing #1210, which had to touch both files to add a single model.
## Scope
- File(s): `internal/llm/providers.go`, `extensions/vscode/src/shared/providers.ts`
- Area: built-in provider registry / VS Code provider preset
- Note: the Go `registry` should remain the source of truth — the `--model` allowlist validation lives in `internal/llm/resolver.go` (`ModelListContains`), and Go is the product core.
## Proposed approach
Make the Go `registry` the single source of truth and generate the TS preset from it, so drift becomes impossible:
1. First, **re-align the existing drift** once (bring `providers.ts` in sync with `providers.go`).
2. Add a small `//go:build ignore` generator (e.g. `internal/llm/gen/`) that serializes the registry's cross-language fields (`name`, `displayName`, `protocol`, `baseUrl`, `authHeader`, `envVar`, `models`) into a generated `providers.ts` (or a shared `providers.json` the extension imports).
3. Mark the output `// Code generated ... DO NOT EDIT.` and wire it via `go:generate`.
4. Add a CI guard: `go generate ./... && git diff --exit-code` fails the build if someone edits Go without regenerating.
An alternative lighter-weight option (if a generator is deemed too heavy): keep both files but add a CI check that parses both lists and fails on mismatch. This stops further drift but does not remove the duplication.
## Acceptance Criteria
- [ ] Existing drift between `providers.go` and `providers.ts` is resolved
- [ ] A single source of truth prevents future drift (generator or shared data file), OR a CI check fails on mismatch
- [ ] Model order and default selection (first entry) are preserved
- [ ] Tests pass (`make test`)
- [ ] Code check passes (`make check`)
## Context
Discovered during review of #1210 (`fix(llm): add deepseek-flash to DeepSeek provider`), which required editing both the Go registry and the VS Code preset by hand — exactly the pattern that leads to drift. The examples above show the drift has already happened.
Contributor guide
Research direction
Start by comparing the registry in internal/llm/providers.go with PROVIDER_PRESETS in extensions/vscode/src/shared/providers.ts, then read internal/llm/resolver.go around ModelListContains. Choose and implement the proposed generator, shared data file, or CI-check approach while preserving model order and the first-entry default; run make test and make check, and verify the drift guard passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, typescript, vscode
- Domain
- developer-experience, tooling
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 50/100