Skip to content

feat(providers): add tabitoken gateway and serve hcnsec's four protocols - #10668

Merged
diegosouzapw merged 5 commits into
diegosouzapw:release/v3.8.50from
yawar-aquil:feat/newapi-gateway-protocols
Aug 20, 2026
Merged

diegosouzapw merged 5 commits into
diegosouzapw:release/v3.8.50from
yawar-aquil:feat/newapi-gateway-protocols

Conversation

@yawar-aquil

@yawar-aquil yawar-aquil commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Two NewAPI-family gateway hosts, plus the one shared capability that made the second one expressible.

  • New provider 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/pricing advertises. The version header is declared on the entry itself because open-sse/executors/default.ts only defaults it for ids starting with anthropic-compatible-; a generic format: "claude" entry has to carry it.
  • hcnsec extended 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.
  • AlternateFormat gains an optional urlBuilder hook (open-sse/config/providers/alternateFormats.ts + a 3-line branch in open-sse/executors/default.ts). Gemini needs a model-scoped path (/v1beta/models/{model}:generateContent), which baseUrl + chatPath constants cannot express. The builder the native gemini provider already used moves to open-sse/config/providers/shared.ts so both call one implementation rather than two copies.
  • Canonical provider count 341 → 342 across README.md, AGENTS.md, llm.txt and its 42 i18n mirrors, package.json, the four canonical-number SVGs, and the regenerated docs/reference/PROVIDER_REFERENCE.md.

Related Issues

  • None — new provider contribution.

Validation

This branch is a true linear rebase onto the current release/v3.8.50 tip (b754e44e): four commits, zero merge commits, git merge-base --is-ancestor b754e44e HEAD true, base ahead by 0. Everything below was re-run on that tip.

  • Change type: provider
  • Focused tests — 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 fail
  • npm run check:provider-consistency → OK — 262 REGISTRY entries, 342 canonical providers, 0 known exceptions
  • npm 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, including llm.txt i18n mirrors match root content: 42 locales and CHANGELOG.md i18n translations validated: 42 locales
  • npm run check:provider-assets → passed
  • node scripts/check/check-changelog-integrity.mjs → OK, no base bullets lost
  • npm run gen:provider-reference → regenerated and committed
  • npx eslint on all changed code files → 0 errors
  • Production-code changes include new/updated automated tests in this PR (Hard Rule fix(oauth): prevent connection test from corrupting valid tokens #8 / fix(ci): add environment for npm token access #18)
  • npm run typecheck:core → 9 pre-existing TS2724 errors, all in open-sse/services/compression/engines/omniglyphAdapter.ts and omniglyphTelemetry.ts. Cause is a dependency skew in my local node_modules (omniglyph@1.3.1 installed 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.

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 onto b754e44e. The four commits below are the whole branch, and git rev-list --merges b754e44e..HEAD is empty.

Tests Added Or Updated

  • tests/unit/newapi-gateway-providers.test.ts — new, 13 tests. Asserts routing through the real DefaultExecutor rather than reading the config back: tabitoken defaults to /v1/messages + x-api-key and switches to Bearer on the OpenAI alternate; its catalog matches the four models its pricing endpoint lists; hcnsec keeps its OpenAI-first defaults and gains exactly ["claude", "openai-responses", "gemini"]; the Gemini alternate builds both …/gemini-3.7-flash:generateContent and …:streamGenerateContent?alt=sse; an undeclared targetFormat falls back to the entry defaults on both hosts; both hosts surface in the dashboard alternate-protocol picker; hcnsec stays regional and non-aggregator.
  • Shared-builder guard in the same file: it 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 native gemini provider.
  • tests/unit/providers-constants-split.test.ts — the APIKEY_PROVIDERS family 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 the targetFormat-fallback plus tabitoken/hcnsec default-routing tests take the existing path. tests/unit/alternate-formats.test.ts continues to cover getTargetFormat / resolveBaseUrl / authHeader resolution.

Reviewer Notes

Security conventions — resolvePublicCred and sanitizeErrorMessage

  • resolvePublicCred() — 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 OAuth client_id/client_secret or 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 in open-sse/config/providers/registry/gemini/index.ts (import { buildGeminiGenerateContentUrl, resolvePublicCred } from "../../shared.ts"); its two existing call sites, clientIdDefault: resolvePublicCred("gemini_id") and clientSecretDefault: resolvePublicCred("gemini_alt"), are unchanged. A grep for credential-shaped literals across the changed production files returns nothing — the ten sk-test… strings in the diff are all fixtures confined to tests/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 no catch, no err.message, no err.stack and 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 in open-sse/executors/default.ts is untouched.

The one quality-baseline change, and why

check:file-size freezes src/shared/constants/providers/apikey/gateways.ts at 1255 lines; registering tabitoken takes it to 1270 (+15, data lines only). Flagging it explicitly rather than letting it pass unremarked in the diff:

The whole baseline delta is machine-checkable: across the file's 608 leaf entries there are exactly 2 differences vs the base — gateways.ts 1255 → 1270 and the one added justification note. 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. git diff on the file is +3/−2 lines.

An earlier revision of this PR did carry 35 unrelated testFrozen shrinks that a check:file-size --update run had swept in alongside the intended edit — --update ratchets the testFrozen block down independently of the frozen block, so they came along silently. They are gone from this history: banking shrinks belongs to the bank-ratchet-shrinks job'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 hcnsec protocols were established, since I have no key for that host

Each 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

  • hcnsec keeps models: []. Every discovery endpoint on that host is auth-gated (pricing.requireAuth: true), so there is no unauthenticated catalog to seed from; it stays passthroughModels: true and relies on live discovery. tabitoken publishes pricing unauthenticated, so its four models are seeded.
  • hcnsec's classification is deliberately unchanged — it is not added to AGGREGATOR_PROVIDER_IDS or PROVIDER_ENDPOINTS, and a test pins that. Its regional.ts catalog entry is untouched too, since its authHint is translated across the i18n locale files and re-wording it would pull ~40 unrelated files into this PR.
  • tabitoken declares only two protocols, not four. The host routes all four, but its own /api/pricing reports supported_endpoint_types covering anthropic + openai for every model it sells, so the entry advertises what the vendor's own metadata backs. Easy to widen later.
  • Why 42 i18n files are in the diff: scripts/check/check-docs-sync.mjs compares each locale's llm.txt body 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.md is a clean +1. The whole content delta is the new tabitoken row, the apikey section count 228 → 229, the total 341 → 342, and the regeneration date. (An earlier revision of this PR also carried a cloudflare-playground row, 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 mentions cloudflare-playground zero times.)
  • Changelog fragment is changelog.d/features/10668-newapi-gateway-protocols.md, named per changelog.d/README.md, carrying one feat(providers) and one feat(sse) bullet. check:changelog-integrity passes.
  • Generated catalog and golden diffs were reviewed as contract changes rather than accepted blindly.

⚠️ base-red inherited: #9985

Copilot AI lite review requested due to automatic review settings August 18, 2026 14:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 tabitoken registry + catalog entries (Claude-first with OpenAI alternate).
  • Extend hcnsec registry entry with claude, openai-responses, and gemini alternates (Gemini via new urlBuilder hook).
  • 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). Since AlternateFormat is 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 headers carries only Anthropic-Version, but the implementation sets headers: getAnthropicCompatHeaders(), which (per the generated translate-path snapshot) appears to include additional headers like Content-Type and sometimes Accept. 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.

@yawar-aquil

Copy link
Copy Markdown
Contributor Author

Rebased onto the current release/v3.8.50 tip (df90591, #10537) — the PR was showing conflicts against the 25 commits that landed after I opened it. It is MERGEABLE again. Three commits, all reverified on the new tip.

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. docs/reference/PROVIDER_REFERENCE.md was resolved by taking the base's version and regenerating it with gen:provider-reference, not by hand-merging a generated file.

One thing worth flagging before you review the diff: the count goes 340 → 342, and only one of those is mine.

check:docs-counts derives the canonical number from the live provider modules and is strict, so the docs must match the code exactly — 341 is not a value I can write. The base's live code already defines 341: cloudflare-playground is registered in src/shared/constants/providers/noauth.ts, open-sse/config/providers/registry/cloudflare-playground/index.ts and open-sse/config/providers/index.ts, but the base's prose and its checked-in PROVIDER_REFERENCE.md still say 340 — that provider landed without the docs being regenerated. Adding tabitoken takes the code to 342, and regenerating emits both rows. Verifiable: git diff <base>..HEAD mentions cloudflare-playground on exactly one line, in the generated file, and my commits touch none of its source modules.

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 docs: PR fixing the base to 341 — happy to split it either way, just tell me which you prefer.

Two failures on this branch are inherited from the base, not introduced here. Both are declared under the existing ⚠️ base-red inherited: #9985:

  • check:docs-counts — 3 failures, all the same claim: README.md / AGENTS.md / llm.txt say 153 migrations while the code has 154. The base tip fails identically, and no commit here touches a migration or that line. Every provider-count assertion in the gate passes.
  • typecheck:core — 9 TS2724 errors, all in open-sse/services/compression/engines/omniglyphAdapter.ts and omniglyphTelemetry.ts. This is a dependency-version skew in my local node_modules (omniglyph@1.3.1 installed against the ^1.4.0 in package.json), not a code defect: none of my 12 changed files appear in the output and git diff <base>..HEAD -- open-sse/services/compression/ is empty. CI's npm ci resolves 1.4.0, so this should not reproduce here.

Green on this branch: the 4 focused test files (40/40), check:provider-consistency (262 REGISTRY entries, 342 canonical, 0 known exceptions), check:provider-assets, check:docs-sync (including llm.txt i18n mirrors match root content: 42 locales), check:changelog-integrity, and eslint on all 12 changed code files.

One cleanup while I was in here: the buildGeminiGenerateContentUrl docblock I added to open-sse/config/providers/shared.ts was written in Portuguese, and that file documents every other export in English. Translated in place (c448293) with the wording and the stated reason for sharing the builder unchanged. alternateFormats.ts keeps its Portuguese JSDoc deliberately — every comment in that file, including the ones already there, is Portuguese, so matching the file was the more consistent choice. Say the word if you'd rather both were English and I'll follow up.

The PR body has been updated so its validation section reflects the new base rather than the numbers from before the rebase.

@diegosouzapw

Copy link
Copy Markdown
Owner

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.
@yawar-aquil
yawar-aquil force-pushed the feat/newapi-gateway-protocols branch from d259070 to bb6e344 Compare August 19, 2026 13:42
@yawar-aquil

Copy link
Copy Markdown
Contributor Author

Thanks for the review — all three points addressed. Taking them in order.

1. Rebased onto the current release/v3.8.50 tip

Done as a rebase, not a merge. An earlier revision of this branch had been brought current with a merge commit; that history is replaced by a linear rebase of identical content onto b754e44e.

$ git rev-list --merges b754e44e..HEAD | wc -l
0
$ git rev-list --count b754e44e..HEAD          # 4 commits, first-parent chain == full list
4
$ git merge-base --is-ancestor b754e44e HEAD && echo linear
linear
$ git rev-list --count HEAD..b754e44e          # base ahead by
0

GitHub reports MERGEABLE. The four commits are the whole branch:

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 real DefaultExecutor rather than reading the config back: tabitoken defaults to /v1/messages + x-api-key and switches to Bearer on its OpenAI alternate; its catalog matches the four models its public /api/pricing lists; hcnsec keeps its OpenAI-first defaults and gains exactly ["claude", "openai-responses", "gemini"]; the Gemini alternate builds both …/gemini-3.7-flash:generateContent and …:streamGenerateContent?alt=sse; an undeclared targetFormat falls back to entry defaults on both hosts; both hosts surface in the dashboard alternate-protocol picker; hcnsec stays 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 native gemini provider.
  • tests/unit/providers-constants-split.test.ts — the APIKEY_PROVIDERS family 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, the targetFormat-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 OAuth client_id/client_secret or 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 in open-sse/config/providers/registry/gemini/index.ts (import { buildGeminiGenerateContentUrl, resolvePublicCred } from "../../shared.ts"); its two existing call sites, clientIdDefault: resolvePublicCred("gemini_id") and clientSecretDefault: resolvePublicCred("gemini_alt"), are unchanged. The ten sk-test… strings in the diff are fixtures confined to the new test file.
  • sanitizeErrorMessage() / buildErrorBody() — the PR adds no error path. There is no catch, no err.message, no err.stack and 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 in open-sse/executors/default.ts is 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.

⚠️ base-red inherited: #9985

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
@diegosouzapw
diegosouzapw merged commit eb6f319 into diegosouzapw:release/v3.8.50 Aug 20, 2026
0 of 3 checks passed
diegosouzapw added a commit to ntdatt812/OmniRoute that referenced this pull request Sep 10, 2026
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.
diegosouzapw pushed a commit that referenced this pull request Sep 10, 2026
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.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…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)
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants