feat(providers): add tabitoken gateway and serve hcnsec's four protocols - #10668
diegosouzapw merged 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds a new NewAPI gateway provider (tabitoken), expands hcnsec to expose additional upstream protocols, and introduces an AlternateFormat.urlBuilder hook to support Gemini’s model-scoped URL shape—plus associated tests and documentation/provider-count updates.
Changes:
- Add
tabitokenregistry + catalog entries (Claude-first with OpenAI alternate). - Extend
hcnsecregistry entry withclaude,openai-responses, andgeminialternates (Gemini via newurlBuilderhook). - Extract and share
buildGeminiGenerateContentUrl, update executor routing, and bump canonical provider counts/docs/snapshots.
Reviewed changes
Copilot reviewed 61 out of 65 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/providers-constants-split.test.ts | Updates API-key provider partition/count assertion to 229. |
| tests/unit/newapi-gateway-providers.test.ts | Adds integration-style tests for tabitoken, hcnsec, and the shared Gemini URL builder. |
| tests/snapshots/provider/translate-path.json | Regenerates snapshot to include tabitoken translation outputs. |
| src/shared/constants/providers/apikey/gateways.ts | Adds tabitoken to the API-key gateways catalog entry list. |
| src/shared/constants/providers.ts | Adds tabitoken to AGGREGATOR_PROVIDER_IDS. |
| src/shared/constants/config.ts | Adds a display endpoint for tabitoken. |
| package.json | Bumps provider count in package description (341 → 342). |
| open-sse/executors/default.ts | Adds AlternateFormat.urlBuilder branch when building upstream URLs. |
| open-sse/config/providers/shared.ts | Extracts buildGeminiGenerateContentUrl into shared helpers. |
| open-sse/config/providers/registry/tabitoken/index.ts | Introduces the tabitoken registry entry and seeded model list. |
| open-sse/config/providers/registry/hcnsec/index.ts | Adds new alternates (Claude/Responses/Gemini) for hcnsec. |
| open-sse/config/providers/registry/gemini/index.ts | Switches native gemini provider to use the shared URL builder. |
| open-sse/config/providers/index.ts | Registers tabitoken in the global registry map. |
| open-sse/config/providers/alternateFormats.ts | Adds optional urlBuilder to AlternateFormat. |
| llm.txt | Updates provider-count references (341 → 342). |
| docs/reference/PROVIDER_REFERENCE.md | Regenerates provider reference (counts + new tabitoken row + updated dates). |
| docs/i18n/zh-TW/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/zh-CN/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/vi/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ur/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/uk-UA/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/tr/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/th/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/te/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ta/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/sw/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/sv/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/sk/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ru/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ro/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/pt/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/pt-BR/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/pl/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/phi/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/no/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/nl/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ms/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/mr/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ko/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ja/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/it/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/in/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/id/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/hu/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/hi/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/he/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/gu/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/fr/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/fi/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/fa/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/es/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/de/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/da/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/cs/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/bn/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/bg/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/az/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/i18n/ar/llm.txt | Mirrors provider-count updates for i18n doc sync. |
| docs/diagrams/readme-hero.svg | Updates embedded provider-count text (341 → 342). |
| docs/diagrams/promise-pillars.svg | Updates embedded provider-count text (341 → 342). |
| docs/diagrams/comparison-table.svg | Updates embedded provider-count text (341 → 342). |
| docs/diagrams/cli-terminal.svg | Updates embedded provider-count text (341 → 342). |
| changelog.d/features/pending-newapi-gateway-protocols.md | Adds changelog entries for provider additions + urlBuilder feature. |
| README.md | Updates provider-count references and anchor text (341 → 342). |
| AGENTS.md | Updates provider-count blurb (341 → 342). |
Suppressed comments (4)
src/shared/constants/providers.ts:1
- There is an extra semicolon after the Set initialization (
]);;). This is a small correctness/style issue that can trip formatters and looks accidental; remove the redundant semicolon so the statement ends with a single;.
open-sse/config/providers/shared.ts:1 - This docblock is written in Portuguese and also contains missing diacritics (e.g.,
nao,expoe,copia). If the codebase convention is English docs/comments (as most surrounding provider config appears to be), consider translating this comment to English and correcting spelling/accents to keep documentation consistent and broadly maintainable.
open-sse/config/providers/alternateFormats.ts:1 - Same issue as in shared.ts: this new public interface documentation is in Portuguese (with missing accents like
nao,sao,proposito). SinceAlternateFormatis part of a shared config API surface, it would be clearer to keep the JSDoc in English (and fix spelling) for consistency with the rest of the project and for external contributors.
open-sse/config/providers/registry/tabitoken/index.ts:1 - The comment says the entry
headerscarries onlyAnthropic-Version, but the implementation setsheaders: getAnthropicCompatHeaders(), which (per the generated translate-path snapshot) appears to include additional headers likeContent-Typeand sometimesAccept. To avoid misleading future edits, update the comment to reflect the actual header set being applied (e.g., 'Anthropic-compatible headers including Anthropic-Version and JSON content-type').
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
3702e34 to
c448293
Compare
|
Rebased onto the current How the conflicts were resolved. All 51 were in the provider-count docs, none in code. Rather than re-run a global find-and-replace on the new base, I re-derived each edit: for every line my commit had changed, I took the base's own text for that line and applied only the count substitution, then asserted every target site was found before writing (189/189 across 50 files). Each count file's staged diff against the base was then checked individually to confirm it contains only count lines, so none of the 25 upstream commits' edits were clobbered. One thing worth flagging before you review the diff: the count goes 340 → 342, and only one of those is mine.
If you would rather not carry someone else's doc correction in a provider PR, I can drop the count files from here and open a separate one-line Two failures on this branch are inherited from the base, not introduced here. Both are declared under the existing
Green on this branch: the 4 focused test files (40/40), One cleanup while I was in here: the The PR body has been updated so its validation section reflects the new base rather than the numbers from before the rebase. |
|
Thanks for the contribution — adding a tabitoken gateway that serves multiple protocols is a direction that fits the existing functional-gateway architecture. Before this can merge, please (1) rebase onto the current release/v3.8.50 tip to resolve the merge conflict, and (2) confirm the PR includes unit tests for the changed production code per the project's Hard Rule #18, and that any public upstream credentials and error responses follow the repo's resolvePublicCred / sanitizeErrorMessage conventions. I was not able to complete a line-level review in this pass, so please make sure the diff is clean before re-requesting. |
tabitoken (https://tabitoken.com) is a NewAPI-family gateway. Its public /api/pricing lists four Claude models whose `supported_endpoint_types` cover anthropic + openai, so the entry is Claude-first (/v1/messages, x-api-key, Anthropic-Version: 2023-06-01) with one OpenAI alternate. The version header is declared on the entry because open-sse/executors/default.ts only defaults it for ids starting with `anthropic-compatible-`; a generic `format: "claude"` entry has to carry it itself. hcnsec (https://api.hcnsec.cn) was already registered as an OpenAI-only regional provider, but the host serves four protocols — Chat, Responses, Claude and Gemini. Each was probed before being declared: all reach the NewAPI token layer ({"error":{"type":"new_api_error"}}) rather than a 404, which is what distinguishes a served route from an absent one. Its defaults are untouched; three alternates are added. `models: []` stays, because every discovery endpoint is auth-gated (pricing.requireAuth: true) — the catalog is passthrough-only. The Gemini protocol needs a model-scoped path (/v1beta/models/{model}:generateContent), which no AlternateFormat could express. AlternateFormat gains an optional urlBuilder hook, and the builder the native gemini provider already used moves to providers/shared.ts so both call one implementation. A test asserts the function identity rather than the resulting string, so a future copy-paste fails instead of silently drifting. Also bumps the canonical provider count 341 -> 342 across README, AGENTS.md, llm.txt and its 42 byte-strict i18n mirrors, package.json, the four canonical-number SVGs, and the regenerated PROVIDER_REFERENCE.md.
changelog.d/README.md requires <PR-number>-<short-slug>.md so aggregation order is deterministic, and the repo's fragment bullets carry the PR link plus the contributor credit. Adds both now that the PR number is known.
shared.ts documents its exports in English, so the new buildGeminiGenerateContentUrl docblock was the only Portuguese block in the file. Translated in place; the wording and the reason the builder is shared are unchanged. alternateFormats.ts keeps its Portuguese JSDoc, which matches every other comment in that file.
…tion
Adding the tabitoken gateway grows src/shared/constants/providers/apikey/
gateways.ts from 1255 to 1270 lines, over its frozen size. The growth is
+15 data lines and is entirely this PR's own diff, reproducible on this
branch alone -- so it is not the combination drift that WS5.5 reserves for
the release captain, and it must not be pushed onto the release branch.
Extraction is not an available alternative here: the file is pure data
("Pure data; merged by apikey/index.ts via spread" in its own header) and
is already decomposed into 6 family files under apikey/, so one new gateway
entry is irreducible growth.
Rebaselined with a justification note, following the precedent already in
this file for the same path: _rebaseline_2026_08_14_imagetotext_servicekinds
(diegosouzapw#10275/diegosouzapw#10291, gateways.ts 1250->1255, data lines only) and
_rebaseline_2026_08_11_v3850_merge_storm_provider_registry.
d259070 to
bb6e344
Compare
|
Thanks for the review — all three points addressed. Taking them in order. 1. Rebased onto the current
|
44acd14 |
feat(providers): add tabitoken gateway and serve hcnsec's four protocols |
5f9102e |
docs(changelog): rename the NewAPI gateway fragment to its PR number |
f62bed5 |
docs(sse): write the shared Gemini route-builder docblock in English |
bb6e344 |
chore(quality): rebaseline gateways.ts for the tabitoken catalog addition |
2. Unit tests for the changed production code (Hard Rule #18 / #8)
Yes. The production delta is 10 .ts files — three provider config modules, the shared route builder, the count constants, and a 3-line branch in open-sse/executors/default.ts. Tests in the same PR:
tests/unit/newapi-gateway-providers.test.ts— new, 13 tests. Asserts routing through the realDefaultExecutorrather than reading the config back:tabitokendefaults to/v1/messages+x-api-keyand switches toBeareron its OpenAI alternate; its catalog matches the four models its public/api/pricinglists;hcnseckeeps its OpenAI-first defaults and gains exactly["claude", "openai-responses", "gemini"]; the Gemini alternate builds both…/gemini-3.7-flash:generateContentand…:streamGenerateContent?alt=sse; an undeclaredtargetFormatfalls back to entry defaults on both hosts; both hosts surface in the dashboard alternate-protocol picker;hcnsecstays regional and non-aggregator.- The shared-builder guard asserts function identity (
geminiProvider.urlBuilder === buildGeminiGenerateContentUrl) rather than the resulting string, so a future copy-paste of the builder fails the test instead of silently drifting from the nativegeminiprovider. tests/unit/providers-constants-split.test.ts— theAPIKEY_PROVIDERSfamily count lock moves to 229 (every id must live in exactly one of the 6 family files).- The new
if (alternate.urlBuilder)branch is covered in both directions: the Gemini-alternate tests take it, thetargetFormat-fallback and default-routing tests take the pre-existing path.
$ node --import tsx/esm --test tests/unit/newapi-gateway-providers.test.ts \
tests/unit/hcnsec-provider.test.ts tests/unit/providers-constants-split.test.ts \
tests/unit/alternate-formats.test.ts
ℹ tests 40 ℹ pass 40 ℹ fail 0
3. resolvePublicCred / sanitizeErrorMessage
Both checked against the actual diff rather than assumed:
resolvePublicCred()— there is no public upstream credential in this PR. Both hosts authenticate with a user-supplied API key read from the provider connection at runtime; neither ships a public OAuthclient_id/client_secretor a Firebase Web key, so Hard Rule chore(ui): rebrand to OmniRoute #11 has nothing to route. The only line in the diff that mentions the helper is an import-list append inopen-sse/config/providers/registry/gemini/index.ts(import { buildGeminiGenerateContentUrl, resolvePublicCred } from "../../shared.ts"); its two existing call sites,clientIdDefault: resolvePublicCred("gemini_id")andclientSecretDefault: resolvePublicCred("gemini_alt"), are unchanged. The tensk-test…strings in the diff are fixtures confined to the new test file.sanitizeErrorMessage()/buildErrorBody()— the PR adds no error path. There is nocatch, noerr.message, noerr.stackand no response body constructed anywhere in the diff, so Hard Rule fix(ui): fix Select dropdown dark theme inconsistency #12 has no call site here. Every existing error path inopen-sse/executors/default.tsis untouched — the 3 added lines return a URL string.
On the diff being clean — one thing I want to flag rather than let you find it
check:file-size freezes src/shared/constants/providers/apikey/gateways.ts at 1255; registering tabitoken takes it to 1270 (+15, data lines only), so the branch carries one baseline entry change plus its justification note. The delta is machine-checkable — across the baseline file's 608 leaf entries there are exactly 2 differences vs the base:
[CHANGED] frozen › src/shared/constants/providers/apikey/gateways.ts 1255 -> 1270
[ADDED] frozen › _rebaseline_2026_08_19_10668_tabitoken_gateway
All 59 pre-existing _rebaseline_* notes are byte-identical (none deleted, none reworded), all 46 testFrozen entries match the base exactly, and cap/testCap are untouched at 1000. Rationale in the note: it is this PR's own growth, reproducible on the branch alone, so the WS5.5 release-captain rule does not apply; extraction is not available because the file is pure data (its own header says "Pure data; merged by apikey/index.ts via spread") and is already split into six family files under apikey/; and _rebaseline_2026_08_14_imagetotext_servicekinds (#10275 / #10291) is the same shape on this same file, 1250 → 1255 for data lines only.
Worth mentioning because it is the kind of thing that should not pass unremarked: an earlier revision of this branch also carried 35 unrelated testFrozen shrinks. check:file-size --update gates its frozen and testFrozen blocks independently, so a run made for the one intended edit ratcheted the test block down silently. They are gone from this history — banking shrinks belongs to the bank-ratchet-shrinks job's own always-current PR per docs/architecture/QUALITY_GATES.md, and carrying them here would retroactively tighten ceilings other in-flight PRs are already sized against.
Gates re-run on the new tip
| Gate | Result |
|---|---|
check:provider-consistency |
OK — 262 REGISTRY entries, 342 canonical, 0 known exceptions |
check:file-size |
OK — 140 frozen files, 46 frozen test files |
check:docs-sync |
PASS — incl. llm.txt i18n mirrors 42 locales, CHANGELOG 42 locales |
check:docs-counts |
pass — every provider-count assertion; 1 soft advisory drift on the cloud-agents count, pre-existing on the base |
check:provider-assets |
passed |
check:changelog-integrity |
OK — no base bullets lost |
eslint (12 changed files) |
0 errors |
typecheck:core reports 9 pre-existing TS2724 errors in open-sse/services/compression/engines/omniglyphAdapter.ts / omniglyphTelemetry.ts — a dependency skew in my local node_modules (omniglyph@1.3.1 against the ^1.4.0 in package.json), not this branch: none of the changed files appear in the output and git diff b754e44e..HEAD -- open-sse/services/compression/ is empty. CI's npm ci resolves 1.4.0.
The PR body is updated to match this state. Re-requesting review. One note on CI: as a fork PR the workflows need maintainer approval to run, which is why the checks show only Mergify and mergeStateStatus reads UNSTABLE rather than failing — happy to have them run whenever you approve the workflow.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
eb6f319
into
diegosouzapw:release/v3.8.50
check:file-size freezes src/shared/constants/providers/apikey/gateways.ts at 1462 lines, so a new catalog entry fails the gate on arrival. This PR's entry and diegosouzapw#13025's take it to 1502 together. Annotated rather than split: the file is declarative provider data, already divided into six family files under apikey/, and every previous gateway entry took the same route (diegosouzapw#11786 seekai, diegosouzapw#10987 logfare, diegosouzapw#10668 tabitoken, diegosouzapw#10531 freebuff, diegosouzapw#11631 1min.ai). Splitting a catalog for two entries would break the semantic-families rule instead of helping. The bump covers both entries because they land in the same batch.
Merged with a rebaseline commit added on top of your branch: check:file-size freezes the gateways catalog at 1462 lines, so any new entry fails the gate on arrival. The annotation covers this entry and EURouter's (#13025) together, following the route every previous gateway entry took (#11786 seekai, #10987 logfare, #10668 tabitoken, #10531 freebuff, #11631 1min.ai) — the file is declarative data already split into six family files, so splitting it for two entries would break the semantic-families rule. Validated in a combined worktree with 13 sibling PRs: 132 focused tests pass, typecheck:core clean, file-size green after the rebaseline. Thank you for stating plainly what you did not verify. "The endpoint exists and is key-gated; catalog, streaming and tool calls not exercised" is worth more than a confident entry that turns out to be guesswork, and the conservative entry that follows from it — empty models, no capability declared, hasFree false with the billing shape spelled out — is exactly right.
…ols (diegosouzapw#10668) Obrigado — PR muito bem documentado e verificado. Adiciona o gateway TabiToken (Anthropic-first, /v1/messages, x-api-key) e estende hcnsec de 1 para 4 protocolos (Chat, Responses, Anthropic Messages, Gemini). AlternateFormat ganha o hook urlBuilder opcional (necessário para o path model-scoped do Gemini), compartilhado com o provider gemini nativo em vez de duplicado. Reconciliado nesta sessão contra o release tip atualizado (base drift real: 343→345 canônicos entre quando o PR foi criado e o merge, mais os PRs diegosouzapw#10673/diegosouzapw#10658 mergeados nesse meio-tempo). Conflitos em contagens de providers (docs, file-size baseline, teste de partição) resolvidos additivamente. Validação (reconciliação a partir de origin/release/v3.8.50): - typecheck:core limpo, complexity/cognitive-complexity dentro do baseline - npm run check:provider-consistency — OK (266 REGISTRY entries, 346 providers canônicos, 0 exceções) - 40/40 testes passando (newapi-gateway-providers, hcnsec-provider, providers-constants-split, alternate-formats)
…ouzapw#13024) Merged with a rebaseline commit added on top of your branch: check:file-size freezes the gateways catalog at 1462 lines, so any new entry fails the gate on arrival. The annotation covers this entry and EURouter's (diegosouzapw#13025) together, following the route every previous gateway entry took (diegosouzapw#11786 seekai, diegosouzapw#10987 logfare, diegosouzapw#10668 tabitoken, diegosouzapw#10531 freebuff, diegosouzapw#11631 1min.ai) — the file is declarative data already split into six family files, so splitting it for two entries would break the semantic-families rule. Validated in a combined worktree with 13 sibling PRs: 132 focused tests pass, typecheck:core clean, file-size green after the rebaseline. Thank you for stating plainly what you did not verify. "The endpoint exists and is key-gated; catalog, streaming and tool calls not exercised" is worth more than a confident entry that turns out to be guesswork, and the conservative entry that follows from it — empty models, no capability declared, hasFree false with the billing shape spelled out — is exactly right.
Summary
Two NewAPI-family gateway hosts, plus the one shared capability that made the second one expressible.
tabitoken(https://tabitoken.com) — an Anthropic-first gateway (/v1/messages,x-api-key,Anthropic-Version: 2023-06-01) with one OpenAI-format alternate, seeded with the four models its public/api/pricingadvertises. The version header is declared on the entry itself becauseopen-sse/executors/default.tsonly defaults it for ids starting withanthropic-compatible-; a genericformat: "claude"entry has to carry it.hcnsecextended from one protocol to four (https://api.hcnsec.cn) — it was already registered as an OpenAI-only regional provider, but the host serves Chat, Responses, Anthropic Messages and Gemini. Its defaults are untouched; three alternates are added.AlternateFormatgains an optionalurlBuilderhook (open-sse/config/providers/alternateFormats.ts+ a 3-line branch inopen-sse/executors/default.ts). Gemini needs a model-scoped path (/v1beta/models/{model}:generateContent), whichbaseUrl+chatPathconstants cannot express. The builder the nativegeminiprovider already used moves toopen-sse/config/providers/shared.tsso both call one implementation rather than two copies.README.md,AGENTS.md,llm.txtand its 42 i18n mirrors,package.json, the four canonical-number SVGs, and the regenerateddocs/reference/PROVIDER_REFERENCE.md.Related Issues
Validation
This branch is a true linear rebase onto the current
release/v3.8.50tip (b754e44e): four commits, zero merge commits,git merge-base --is-ancestor b754e44e HEADtrue, base ahead by 0. Everything below was re-run on that tip.node --import tsx/esm --test tests/unit/newapi-gateway-providers.test.ts tests/unit/hcnsec-provider.test.ts tests/unit/providers-constants-split.test.ts tests/unit/alternate-formats.test.ts→ 40/40 pass, 0 failnpm run check:provider-consistency→ OK — 262 REGISTRY entries, 342 canonical providers, 0 known exceptionsnpm run check:file-size→ OK — 140 frozen files, 46 frozen test files (one baseline entry changes; see the note below)npm run check:docs-counts→ pass. One soft advisory drift on the cloud-agents count, pre-existing on the base and untouched here; every provider-count assertion passes.npm run check:docs-sync→ PASS, includingllm.txt i18n mirrors match root content: 42 localesandCHANGELOG.md i18n translations validated: 42 localesnpm run check:provider-assets→ passednode scripts/check/check-changelog-integrity.mjs→ OK, no base bullets lostnpm run gen:provider-reference→ regenerated and committednpx eslinton all changed code files → 0 errorsnpm run typecheck:core→ 9 pre-existingTS2724errors, all inopen-sse/services/compression/engines/omniglyphAdapter.tsandomniglyphTelemetry.ts. Cause is a dependency skew in my localnode_modules(omniglyph@1.3.1installed against the^1.4.0inpackage.json), not this branch: none of the changed files appear in the output andgit diff b754e44e..HEAD -- open-sse/services/compression/is empty. CI'snpm ciresolves 1.4.0.On the requested rebase. Done as asked —
git rebase, not a merge. An earlier revision of this PR had been brought current with a merge commit; that history has been replaced by a linear rebase of identical content ontob754e44e. The four commits below are the whole branch, andgit rev-list --merges b754e44e..HEADis empty.Tests Added Or Updated
tests/unit/newapi-gateway-providers.test.ts— new, 13 tests. Asserts routing through the realDefaultExecutorrather than reading the config back:tabitokendefaults to/v1/messages+x-api-keyand switches toBeareron the OpenAI alternate; its catalog matches the four models its pricing endpoint lists;hcnseckeeps its OpenAI-first defaults and gains exactly["claude", "openai-responses", "gemini"]; the Gemini alternate builds both…/gemini-3.7-flash:generateContentand…:streamGenerateContent?alt=sse; an undeclaredtargetFormatfalls back to the entry defaults on both hosts; both hosts surface in the dashboard alternate-protocol picker;hcnsecstays regional and non-aggregator.geminiProvider.urlBuilder === buildGeminiGenerateContentUrl) rather than the resulting string, so a future copy-paste of the builder fails the test instead of silently drifting from the nativegeminiprovider.tests/unit/providers-constants-split.test.ts— theAPIKEY_PROVIDERSfamily count lock moves to 229 (the file asserts every id lives in exactly one of the 6 family files, no loss and no duplicate).tests/snapshots/provider/translate-path.json— golden regenerated for the new entries.Coverage Notes
The production surface is three config modules plus one 3-line branch in
open-sse/executors/default.ts. That new branch (if (alternate.urlBuilder) return alternate.urlBuilder(...)) is covered in both directions: the Gemini-alternate tests take it, and thetargetFormat-fallback plustabitoken/hcnsecdefault-routing tests take the existing path.tests/unit/alternate-formats.test.tscontinues to covergetTargetFormat/resolveBaseUrl/authHeaderresolution.Reviewer Notes
Security conventions —
resolvePublicCredandsanitizeErrorMessageresolvePublicCred()— there is no public upstream credential in this diff. Both hosts authenticate with a user-supplied API key read from the provider connection at runtime; neither ships a public OAuthclient_id/client_secretor a Firebase Web key, so Hard Rule chore(ui): rebrand to OmniRoute #11 has nothing to route. The only line in the PR that mentions the helper is an import-list append inopen-sse/config/providers/registry/gemini/index.ts(import { buildGeminiGenerateContentUrl, resolvePublicCred } from "../../shared.ts"); its two existing call sites,clientIdDefault: resolvePublicCred("gemini_id")andclientSecretDefault: resolvePublicCred("gemini_alt"), are unchanged. A grep for credential-shaped literals across the changed production files returns nothing — the tensk-test…strings in the diff are all fixtures confined totests/unit/newapi-gateway-providers.test.ts.sanitizeErrorMessage()/buildErrorBody()— the PR adds no error path. The production delta is three provider config modules plus a 3-line URL branch that returns a string. There is nocatch, noerr.message, noerr.stackand no response body constructed anywhere in the diff, so Hard Rule fix(ui): fix Select dropdown dark theme inconsistency #12 has no call site here. Every existing error path inopen-sse/executors/default.tsis untouched.The one quality-baseline change, and why
check:file-sizefreezessrc/shared/constants/providers/apikey/gateways.tsat 1255 lines; registeringtabitokentakes it to 1270 (+15, data lines only). Flagging it explicitly rather than letting it pass unremarked in the diff:docs/architecture/QUALITY_GATES.mddoes not apply here.apikey/._rebaseline_2026_08_14_imagetotext_servicekinds(feat(providers): declare imageToText serviceKind on major vision providers #10275 / feat(providers): derive imageToText from the OCR registry + chutes dots.ocr seed #10291) raised this same file 1250 → 1255 for data lines only, and_rebaseline_2026_08_11_v3850_merge_storm_provider_registrycovers it as an owner-authorized case.The whole baseline delta is machine-checkable: across the file's 608 leaf entries there are exactly 2 differences vs the base —
gateways.ts1255 → 1270 and the one added justification note. All 59 pre-existing_rebaseline_*notes are byte-identical (none deleted, none reworded), all 46testFrozenentries match the base exactly, andcap/testCapare untouched at 1000.git diffon the file is +3/−2 lines.An earlier revision of this PR did carry 35 unrelated
testFrozenshrinks that acheck:file-size --updaterun had swept in alongside the intended edit —--updateratchets thetestFrozenblock down independently of thefrozenblock, so they came along silently. They are gone from this history: banking shrinks belongs to thebank-ratchet-shrinksjob's own always-current PR (docs/architecture/QUALITY_GATES.md), and carrying them in a provider PR would retroactively tighten ceilings other in-flight PRs are already sized against.How the four
hcnsecprotocols were established, since I have no key for that hostEach candidate route was probed directly. All four return the NewAPI token layer (
{"error":{"type":"new_api_error"}}) rather than a 404 — an authenticated-but-unauthorized response proves the route is served, whereas an absent route 404s. I did not infer any endpoint from the vendor's documentation alone. If you would rather see a keyed round-trip before merging the Gemini alternate, I can split that one out.Remaining notes
hcnseckeepsmodels: []. Every discovery endpoint on that host is auth-gated (pricing.requireAuth: true), so there is no unauthenticated catalog to seed from; it stayspassthroughModels: trueand relies on live discovery.tabitokenpublishes pricing unauthenticated, so its four models are seeded.hcnsec's classification is deliberately unchanged — it is not added toAGGREGATOR_PROVIDER_IDSorPROVIDER_ENDPOINTS, and a test pins that. Itsregional.tscatalog entry is untouched too, since itsauthHintis translated across the i18n locale files and re-wording it would pull ~40 unrelated files into this PR.tabitokendeclares only two protocols, not four. The host routes all four, but its own/api/pricingreportssupported_endpoint_typescovering anthropic + openai for every model it sells, so the entry advertises what the vendor's own metadata backs. Easy to widen later.scripts/check/check-docs-sync.mjscompares each locale'sllm.txtbody against the root file, so the provider-count line has to be replicated in all 42 or the docs gate fails. No translated prose was touched — each locale's diff is only its count line.docs/reference/PROVIDER_REFERENCE.mdis a clean +1. The whole content delta is the newtabitokenrow, theapikeysection count 228 → 229, the total 341 → 342, and the regeneration date. (An earlier revision of this PR also carried acloudflare-playgroundrow, because the base's checked-in catalog had not been regenerated after that provider landed; the base has since regenerated it, so that row is gone from this diff — it now mentionscloudflare-playgroundzero times.)changelog.d/features/10668-newapi-gateway-protocols.md, named perchangelog.d/README.md, carrying onefeat(providers)and onefeat(sse)bullet.check:changelog-integritypasses.