feat(providers): Concentrate as a first-class opt-in BYOK Responses gateway - #5725
feat(providers): Concentrate as a first-class opt-in BYOK Responses gateway#5725Hmbown wants to merge 3 commits into
Conversation
…ateway Adds `concentrate` (aliases `concentrate-ai`, `concentrate_ai`, `concentrateai`) inside the existing provider authorities — no parallel secret store, router, or runtime: - Identity/metadata: `ProviderKind::Concentrate`, hand-written `impl Provider` with `WirePolicy::Fixed(WireFormat::Responses)` (the gateway documents the Responses API as its production surface), default base URL `https://api.concentrate.ai/v1`, default model `deepseek-v4-pro`, env `CONCENTRATE_API_KEY` (+ `CONCENTRATE_BASE_URL`, `CONCENTRATE_MODEL`), its own secret-store slot, credential help. - Routing: aggregator-class pass-through. A plain catalog id lets the gateway choose the upstream provider, `provider/model` pins one, and only the gateway's own `concentrate/` namespace is stripped so `concentrate/auto` reaches its `auto` router while Codewhale's bare `auto` stays the resolver sentinel (provider default). - Wire: the Responses body carries only documented fields — `model`, `input`, `stream`, `max_output_tokens`, `tools`/`tool_choice`/ `parallel_tool_calls`, `reasoning.effort` — with the system prompt as a leading `system` input item (`instructions`, `store`, `include`, and `reasoning.summary` are absent from the gateway's parameter reference). Streaming rides the existing typed `response.*` SSE parser and ends on `response.completed` without a `[DONE]` sentinel. - Catalog: the unauthenticated `GET /v1/models` (OpenAI list shape) joins the named-gateway live-catalog path; rows stay provider-scoped and unclaimed. - Errors (provider-neutral): a 402 "insufficient credits/funds" body now classifies as quota (RateLimit) instead of falling through, and a flat `{"error":"<class>","message":"<detail>"}` body surfaces both halves in the TUI sanitizer instead of the class alone. - Registry parity: `ProviderKind::ALL` 42→43, registry 47→48, golden route ids + providers-export golden regenerated, `scripts/check-provider-registry.py` manual-impl allowlist, web facts label maps + `facts.generated.ts` (providers 45→46), docs rows in PROVIDERS.md (+ a Concentrate Notes section) and CONFIGURATION.md, CHANGELOG. Commercial boundary, preserved in code and docs: BYOK only. Concentrate's Terms of Service forbid resale, white-label, and service-bureau use without written consent and its AUP forbids key sharing, so there is no Codewhale-owned key, no stored customer key, no default or managed routing, and no markup; any hosted lane is gated on written consent, terms, and billing approval (ops evidence concentrate-gateway-20260829/CHECKLIST.md). A saved or environment Concentrate key is bound to the official base URL and is never sent to any other endpoint — a custom endpoint receives a key only when `base_url` and `api_key` are both written into `[providers.concentrate]`. Keyless dogfood: `scripts/concentrate-selftest.sh` boots `scripts/concentrate-stub.py` (the documented contract on loopback: `/v1/responses/health`, unauthenticated `/v1/models`, typed-SSE `/v1/responses`, documented error bodies) and drives the real `codewhale exec --auto --output-format stream-json` path through it, asserting the URL, bearer header, verbatim model, only-documented fields, system item first, the completed-turn receipt, and the wrong-key 401. No network call leaves the machine; no account exists in the loop. Contract sources (fetched 2026-08-29): https://concentrate.ai/docs/api-reference/introduction https://concentrate.ai/docs/api-reference/endpoint/request-parameters https://concentrate.ai/docs/api-reference/endpoint/streaming https://concentrate.ai/docs/api-reference/endpoint/errors https://concentrate.ai/docs/api-reference/endpoint/list-models https://concentrate.ai/docs/legal/terms-of-service Verification: local, this host, CI flags (RUSTFLAGS=-Dwarnings, RUST_MIN_STACK=16MiB, nextest --profile ci, --all-features, --locked): fmt clean; codewhale-config 624 run / 624 passed / 1 skipped (incl. new concentrate_resolves_… and concentrate_passes_ids_through_and_strips_only_its_own_namespace, regenerated goldens); codewhale-secrets 62/62; codewhale-tui focused (concentrate + error_taxonomy + client::responses + llm_client + provider config + catalog filters) 440 run / 440 passed; debug CLI built; scripts/concentrate-selftest.sh PASS ×3 (concentrate/auto → wire `auto`, openai/gpt-5.6-sol, deepseek-v4-pro); scripts/check-provider-registry.py PASS; clippy config+secrets and tui (--all-targets --all-features, CI allow list) clean; web facts regenerated (providers 46) + check-facts OK; dead-code budget PASS; git diff --check clean. Not done: no live Concentrate canary (needs a key and founder-gated spend); Windows-target compile is hosted-CI-only on this host. No-Issue: provider addition requested by the founder; no tracking issue exists. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| provider = "concentrate" | ||
|
|
||
| [providers.concentrate] | ||
| api_key = "concentrate-config-key" |
There was a problem hiding this comment.
Blocker This changed line looks like a hardcoded secret.
|
|
||
| [providers.concentrate] | ||
| base_url = "http://127.0.0.1:8790/v1" | ||
| api_key = "stub-key" |
There was a problem hiding this comment.
Blocker This changed line looks like a hardcoded secret.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @Hmbown's task in 3m 17s —— View job Claude finished reviewing this PR
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2860a5710f
ℹ️ 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".
| && let Some(kind) = provider.kind() | ||
| if matches!( | ||
| provider, | ||
| ApiProvider::Telecomjs | ApiProvider::Edenai | ApiProvider::Concentrate |
There was a problem hiding this comment.
Do not treat the public catalog as key verification
For Concentrate, GET /v1/models is explicitly unauthenticated (docs/PROVIDERS.md:670), so this request returns 2xx even when api_key is invalid. The guided provider setup consequently records a successful observed probe and advances to model selection for any nonempty key, only failing on the first POST /responses; special-case this provider as an unobserved probe or validate against an authenticated endpoint.
Useful? React with 👍 / 👎.
| if "ok from the concentrate stub" in text: | ||
| print("ok: reply text reached the CLI output") | ||
| else: | ||
| print("note: reply text not found in `content` events (types above are the receipt); raw events kept for inspection") |
There was a problem hiding this comment.
Fail the self-test when reply content is missing
If the Responses parser or stream-json renderer drops every content event while still emitting a done receipt, this branch merely prints a note and the script exits successfully. That means the advertised end-to-end assertion that the stub reply reached CLI output can regress while CONCENTRATE SELFTEST PASS is still reported; make the missing expected text an assertion failure.
AGENTS.md reference: AGENTS.md:L83-L85
Useful? React with 👍 / 👎.
| || lower.contains("insufficient credits") | ||
| || lower.contains("insufficient funds") | ||
| || lower.contains("payment required") | ||
| || lower.contains("http 402") |
There was a problem hiding this comment.
Classify 402 exhaustion in the typed HTTP path
A real Concentrate 402 is converted by send_with_retry through LlmError::from_http_response before this string classifier is consulted, and has_explicit_quota_phrase recognizes neither “insufficient funds” nor “insufficient credits.” The resulting downcastable LlmError::Other takes precedence in envelope_for_llm_error, so the UI reports an Internal, recoverable failure instead of the quota category promised here; add these phrases to the typed quota-evidence path (the new test currently hides this by reclassifying only the formatted string).
Useful? React with 👍 / 👎.
Hosted `Test (ubuntu-latest)` on #5725 failed exactly one test out of 13,958: `cli_provider_helpers_follow_config_metadata` still asserted the pre-Concentrate registry sizes (47 full / 42 catalog). The config crate's twin assertion was updated in the parent commit; this mirrors it. The rest of the test (env vars and secret-store slot per registry kind) already held for `concentrate`. Local: codewhale-cli 276 run / 276 passed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Hosted |
| provider = "concentrate" | ||
|
|
||
| [providers.concentrate] | ||
| api_key = "concentrate-config-key" |
There was a problem hiding this comment.
Blocker This changed line looks like a hardcoded secret.
|
|
||
| [providers.concentrate] | ||
| base_url = "http://127.0.0.1:8790/v1" | ||
| api_key = "stub-key" |
There was a problem hiding this comment.
Blocker This changed line looks like a hardcoded secret.
|
Claude finished @Hmbown's task in 1m 34s —— View job Claude finished reviewing this PRTodo list
SummaryThis 1. (Unresolved, real bug) 402 quota classification never reaches the typed error path — 2. (Unresolved) Public, unauthenticated 3. (Unresolved) 4. (Unresolved, minor) None of these are regressions from Not a real issue: the earlier Codewhale-agent "hardcoded secret" flags on |
|
Hosted |
|
Matrix settled at |
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
| provider = "concentrate" | ||
|
|
||
| [providers.concentrate] | ||
| api_key = "concentrate-config-key" |
There was a problem hiding this comment.
Blocker This changed line looks like a hardcoded secret.
|
|
||
| [providers.concentrate] | ||
| base_url = "http://127.0.0.1:8790/v1" | ||
| api_key = "stub-key" |
There was a problem hiding this comment.
Blocker This changed line looks like a hardcoded secret.

Summary
Adds Concentrate (
concentrate) as a first-class, opt-in, BYOK provider — the OpenAI Responses-compatible gateway athttps://api.concentrate.ai/v1— inside the existing provider authorities (no parallel secret store, router, or runtime). Mirrors the Eden AI aggregator addition across the registry, config tables, env overrides, secrets, TUI wiring, docs, web facts, and goldens.ProviderKind::Concentrate(+concentrate-ai/concentrate_ai/concentrateai), hand-writtenimpl ProviderwithWirePolicy::Fixed(Responses), default modeldeepseek-v4-pro, envCONCENTRATE_API_KEY/CONCENTRATE_BASE_URL/CONCENTRATE_MODEL, own secret-store slot.provider/modelpins it; only the gateway's ownconcentrate/namespace is stripped soconcentrate/autoreaches its router (Codewhale's bareautostays the resolver sentinel).model,input,stream,max_output_tokens,tools/tool_choice/parallel_tool_calls,reasoning.effort); system prompt as a leadingsysteminput item; typedresponse.*SSE via the existing parser, ending onresponse.completed(no[DONE]).GET /v1/modelsthrough the existing named-gateway live-catalog path (rows provider-scoped, unclaimed).{"error","message"}bodies surface both halves.base_urlandapi_keyare both in[providers.concentrate]). Hosted-lane activation stays gated on written consent, terms, and billing approval (ops evidenceconcentrate-gateway-20260829/CHECKLIST.md).scripts/concentrate-selftest.shbootsscripts/concentrate-stub.py(the documented contract on loopback) and drives the realcodewhale exec --auto --output-format stream-jsonpath through it, asserting URL, bearer header, verbatim model, only-documented fields, system-first input, the completed-turn receipt, and the wrong-key 401. No network call leaves the machine.Contract sources (fetched 2026-08-29): introduction, request parameters, streaming, errors, list models, health.
No-Issue: founder-requested provider addition; no tracking issue exists.
Testing
Local, hosted-equivalent flags (
RUSTFLAGS=-Dwarnings,RUST_MIN_STACK=16MiB,cargo nextest … --all-features --locked --profile ci), summary in the ops evidence:cargo fmt --all -- --check: cleancodewhale-config: 624 run / 624 passed / 1 skipped — incl. newconcentrate_resolves_named_responses_gateway_and_environment_overrides(aliases, metadata, fixed Responses wire, secret slot, env + config resolution, and the credential-scope rule that an env key is never sent to a non-official base URL) andconcentrate_passes_ids_through_and_strips_only_its_own_namespace(plain /provider/modelverbatim,concentrate/auto→auto, bareauto→ provider default, all on the Responses protocol); goldens regenerated (golden_route_ids.txt,providers-export.golden.json); count assertions 47→48 / 42→43; expected-wire tables updated.codewhale-secrets: 62 run / 62 passed — incl.concentrate_env_aliases_resolve(own slot; no cross-provider bleed).codewhale-tuifocused (concentrate | error_taxonomy:: | client::responses::tests:: | llm_client:: | config provider tests | edenai|telecomjs|opencode_zen_responses|catalog): 440 run / 440 passed — incl.concentrate_responses_request_matches_the_documented_contract(wiremock:POST /v1/responses,Bearerheader, verbatimprovider/model, nostore/include/instructions/messages, system item first, typed-event SSE without[DONE]assembles text + usage 12/5, official URL maps to/v1/responses),concentrate_error_bodies_surface_verbatim_and_classify(401 → Authentication with "Invalid API key", 402 → quota with "insufficient credits", 400 → InvalidInput with "Invalid model name"),concentrate_live_catalog_is_provider_scoped_and_marks_the_default,concentrate_responses_body_sends_only_documented_fields,insufficient_credits_classifies_as_rate_limit_not_auth,flat_error_and_message_body_surfaces_both_halves.scripts/concentrate-selftest.shwith the debug CLI):concentrate/auto(wireauto),openai/gpt-5.6-sol,deepseek-v4-pro— health 200, catalog without a key, exactly one bearer-authenticatedPOST /v1/responseswith the verbatim model,stream:true, system item first, only documented fields; stream-json receiptcontent…turn_usage, session_capture, metadata, done; wrong key → documented 401 → exit 1. Defeat evidence: the first run (env key only) reached the stub with an empty Authorization header, which is the credential-scope rule working; the recipe now writesbase_url+api_keyinto[providers.concentrate]as a BYOK user pointing at a local gateway would.scripts/check-provider-registry.pyPASS;cargo clippyfor config+secrets and tui (--all-targets --all-features, CI allow list) clean;node web/scripts/derive-facts.mjs(providers 46) +check-factsOK; dead-code budget PASS (444/444);git diff --checkclean.Not done: no live Concentrate canary (needs a key and founder-gated spend — the live gateway was never contacted beyond the public, unauthenticated
/v1/modelsread used to pin the catalog shape); Windows-target compile is hosted-CI-only on this macOS host.cargo fmt --all -- --checkcargo clippyon the changed crates, all targets, all features, CI allow listcargo test --workspace --all-features --locked(hosted CI; locally the changed crates' suites passed as above)🤖 Generated with Claude Code