feat(ai): add ClinePass provider - #572
Conversation
d36918a to
039cbc4
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d36918a7dd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| readonly "anthropic": typeof ANTHROPIC_MODELS; | ||
| readonly "azure-openai-responses": typeof AZURE_OPENAI_RESPONSES_MODELS; | ||
| readonly "cerebras": typeof CEREBRAS_MODELS; | ||
| readonly "cline-pass": typeof CLINE_PASS_MODELS; |
There was a problem hiding this comment.
Regenerate the model-data manifest
Adding ClinePass to the generated catalog expands the provider set, but packages/ai/src/providers/data/.manifest.json remains unchanged and contains neither cline-pass.json nor the new structure hash. Consequently, npm --prefix packages/ai run check:model-data reports a catalog/manifest mismatch, preventing validation and offline builds until the manifest is regenerated and committed.
AGENTS.md reference: packages/ai/src/providers/AGENTS.md:L23-L24
Useful? React with 👍 / 👎.
| const envMap: Record<string, string> = { | ||
| "alibaba-token-plan": "ALIBABA_TOKEN_PLAN_API_KEY", | ||
| "ant-ling": "ANT_LING_API_KEY", | ||
| "cline-pass": "CLINE_API_KEY", |
There was a problem hiding this comment.
Add the new key to every hermetic environment sanitizer
When a developer has CLINE_API_KEY set, this new credential is now discovered, but the coding-agent sanitizers in test/helpers/rpc-hermetic.ts, scripts/qa-app-server/lib/env.mjs, and both task17 REAL_PROVIDER_ENV_KEYS lists do not clear it. Direct package tests and app-server QA can therefore inherit a real credential and expose ClinePass models in runs intended to contain only faux/mock providers; add the key to those related environment surfaces as well.
AGENTS.md reference: AGENTS.md:L90-L90
Useful? React with 👍 / 👎.
Register the cline-pass provider against ClinePass OpenAI-compatible endpoint at https://api.cline.bot/api/v1, generate its 11-model tool-capable catalog from models.dev, and resolve keys from CLINE_API_KEY. Thinking is normalized through the nested OpenRouter-style reasoning object, and the gateway effort vocabulary (none/low/medium/high/xhigh) overrides upstream direct-endpoint maps.
Default cline-pass to cline-pass/kimi-k3, display it as ClinePass, and document CLINE_API_KEY in --help.
List ClinePass in provider tables and changelog, seed CLINE_API_KEY through devcontainer/devenv setup, and unset it in test.sh so hermetic runs stay offline.
CONTRIBUTING.md requires a nearest-changes.md section for every modification to an upstream-tracked file. Document the ClinePass provider registration, the CLI help/default-model wiring, and the browser key-validation entries, including the pre-existing no-proxy limitation inherited from the shared proxy path.
039cbc4 to
ee35c6d
Compare
…ider # Conflicts: # packages/ai/src/changes.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 313f05d117
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }, | ||
| ); | ||
|
|
||
| describe.skipIf(!process.env.CLINE_API_KEY)("ClinePass Provider (Kimi K3 via OpenAI Completions)", () => { |
There was a problem hiding this comment.
Require explicit opt-in before running ClinePass live tests
When CLINE_API_KEY is present, an ordinary npm test now runs this paid, network-dependent stream matrix and the other newly added ClinePass suites automatically; the devcontainer and setup changes make that ambient-key scenario especially likely. This can consume subscription quota and make the default test result depend on the live service, so resolve the key through getLiveEnvApiKey and require PI_ENABLE_LIVE_API_TESTS=1 or a ClinePass-specific live-test flag before enabling these suites.
AGENTS.md reference: packages/ai/AGENTS.md:L50-L50
Useful? React with 👍 / 👎.
Summary
Adds a built-in
cline-passprovider for ClinePass, Cline's OpenAI-compatible subscription endpoint athttps://api.cline.bot/api/v1, following the existingalibaba-token-plan/openroutergateway pattern.cline-passprovider; non-tool-capable entries filtered by thetool_callgateprovider/modelid shape, and normalizes thinking through the nestedreasoningobject rather than provider-specific parameters. Its verified effort vocabulary (none/low/medium/high/xhigh) is applied after the upstream-model rules so the gateway's contract wins over direct-endpoint maps; pi'sminimalandmaxhave no ClinePass equivalent and clamp tolow/xhighCLINE_API_KEYenv detection,ClinePassdisplay name for/login, default modelcline-pass/kimi-k3, CLI--helpenv row, providers.md / README, devcontainer + devenv env surfaces, andCLINE_API_KEYunset intest.sh/pi-test.shso hermetic runs stay offlinedescribe.skipIf(!process.env.CLINE_API_KEY), the same shape the other ~24 API-key providers use — no new opt-in flag is introducedpackages/ai/src/changes.md,packages/coding-agent/src/cli/changes.md,packages/coding-agent/src/core/changes.md, and a newpackages/web-ui/src/changes.mdWhy this belongs in core
Provider registration,
KnownProvider, and browser-safe credential detection are composed insidepackages/aibefore any extension loads.model-resolver.tsandprovider-display-names.tsare typedRecord<KnownProvider, string>, so adding a provider is a compile-time obligation across those maps rather than something an extension can supply. An extension can add a model entry; it cannot make a provider first-class in the generated catalog or inenv-api-keys.tscredential probing.Per
packages/ai/src/providers/AGENTS.mdsteps 2-4, no new wire implementation, package subpath, or option transform is needed: ClinePass reusesopenAICompletionsApi()exactly asalibaba-token-plan.tsandopenrouter.tsdo.git diff --name-only <base>..HEAD -- packages/ai/src/api packages/ai/package.jsonis empty.Verification
npm run check— exit 0 (Biome, pinned-deps, ts-imports, shrinkwrap, install-lock,tsgo --noEmit, browser smoke, web-ui check)node --test scripts/*.test.mjs— 72 passed / 0 failedpackages/ai— 173 files passed / 25 skipped; 1,534 tests passed / 824 skipped / 0 failed, withCLINE_API_KEYunsetpackages/coding-agent— 6,153 passed / 33 skipped / 3 failed in the full-suite run. None of the three failing files (footer-data-provider,permission/external-dir,app-server-thread-handlers-archive) is touched by this branch, and all three were re-run individually at the base commit in a detached worktree with these commits absent — each exits 1 there as well, so all three are pre-existing failures independent of this change.permission/external-dir(symlinked cwd) andapp-server-thread-handlers-archive(unarchive) also fail individually on this branch;footer-data-provider(reftable branch detection) passes individually on this branch, so its failure additionally depends on the surrounding environmentnpx tsgo --noEmitexit 0 at each of the 6 commits in a detached worktree, so the history is bisectablesenpi --list-models | grep -c '^cline-pass '→11;senpi --helplistsCLINE_API_KEY - ClinePass API keypackages/ai/test/cline-pass-request.test.tscaptures the outgoing request and pins the endpointhttps://api.cline.bot/api/v1/chat/completions, theBearerheader, the full model id, the nestedreasoning: { effort }object, and the absence ofreasoning_effort. Mutation-verified: changing thebaseUrlinproviders/data/cline-pass.json(the catalog the runtime reads) turns the suite red at the endpoint assertionCompatibility
models.generated.ts,providers/data/cline-pass.json, andproviders/data/.manifest.jsonare regenerated artifacts fromnpm run generate:modelsandnpm run hydrate:model-data— not hand-edited.mainwith zero conflicts.packages/ai/src/providers/data/.manifest.jsonis regenerated and committed inside the first commit, sonpm --prefix packages/ai run check:model-dataexits 0 at every commit in the series (verified per-commit in a detached worktree). If a future rebase does conflict on the manifest, resolve it by regenerating rather than hand-merging: it is a single JSON object whosefilesmap holds one hash per provider catalog, so a textual union produces two concatenated objects and invalid JSON. Usenpm run hydrate:model-data, thennpm run check:model-data.CLINE_API_KEYfollows this client's<PROVIDER>_API_KEYconvention, but ClinePass's published API docs specify only theAuthorization: Bearerheader and do not name an environment variable; (2) model ids, pricing, and context windows come from models.dev rather than a first-party ClinePass model list.Review follow-ups
Both P2 findings from the automated reviewer are addressed in this series:
packages/ai/src/providers/data/.manifest.jsonnow ships in the first commit with thecline-pass.jsonhash and the updatedstructureHash. It was regenerated through the repo's owncreateModelDataManifest(), so all 38 pre-existing provider hashes are byte-identical and onlycline-pass.jsonis added.check:model-dataexits 0 at all 6 commits.CLINE_API_KEYisolated in app-server QA. Added toREAL_PROVIDER_ENV_KEYSin bothtest/qa/app-server/task17-model-list.tsandtask17-unimplemented.ts, immediately afterALIBABA_TOKEN_PLAN_API_KEY, matching commitb700ddaf7("test: isolate Alibaba token plan credentials"). Verified on the real surface: withCLINE_API_KEYset in the environment,task17-model-list.tsexited 1 before the change and exits 0 after.test/helpers/rpc-hermetic.tsdeliberately not touched. ItsPROVIDER_ENV_KEYSlist is not exhaustive — it already omitsALIBABA_TOKEN_PLAN_API_KEY,ANT_LING_API_KEY, and theXIAOMI_*keys — andb700ddaf7skipped it for the same reason. Adding onlyCLINE_API_KEYthere would introduce an inconsistency rather than remove one. Happy to add it if you would prefer that list become exhaustive.Known limitations
applyProxyIfNeeded()returns the unproxied model when no proxy URL is configured, before consultingshouldUseProxyForProvider(). With the CORS proxy setting off, a valid ClinePass key is reported as invalid instead of surfacing "this provider requires the proxy".zaihas behaved this way since b6b64df; ClinePass joins that existing class. Fixing it changes the shared no-proxy path for every proxy-required provider, which does not belong in a provider addition.cline-pass-request.test.tsresolves its model throughgetModels("cline-pass"), which is the catalog the runtime reads and the valuemodels.tssends, so the wire contract is genuinely pinned. It does not additionally assertclinePassProvider()'s own factory-levelbaseUrl; adding that assertion would tighten coverage for dynamically-registered models.Summary by cubic
Adds a built-in
cline-passprovider for ClinePass’s OpenAI-compatible endpoint athttps://api.cline.bot/api/v1, withcline-pass/kimi-k3as the default model,CLINE_API_KEYauth, proxy-aware web UI, and a generated catalog of 11 tool-capable models using normalizedreasoning: { effort }.New Features
cline-passathttps://api.cline.bot/api/v1; keepsprovider/modelIDs and uses OpenRouter-stylereasoning.effort(none/low/medium/high/xhigh), clamping unsupported values and applying gateway rules over upstream (DeepSeek/Qwen/Kimi/GLM preserved under nested reasoning).CLINE_API_KEY; CLI--helplists it; display name ClinePass; defaultcline-pass/kimi-k3wired into the model resolver; devcontainer seeds the key; tests/scripts unset it for hermetic runs.CLINE_API_KEY; request contract pinned (endpoint.../chat/completions, bearer header, full model ID, nestedreasoning,max_tokens).Migration
CLINE_API_KEYto usecline-pass.cline-pass(direct browser calls are blocked byapi.cline.bot).Written for commit 313f05d. Summary will update on new commits.