feat(providers): dedicated BYOK-vendor providers make hermes/openclaw vendor menus routable (cp#529) #2262

Merged
hongming merged 1 commits from feat/cp529-byok-vendor-providers into main 2026-06-04 23:38:34 +00:00
Owner

What

The 20 ids cp#529's routability-aware drift checker flagged as residual drift are CUSTOMER BYOK vendor models for the SHARED upstream vendors (anthropic, openai, gemini, minimax, groq). They were left unroutable because wiring them through the platform-shared platform provider would bill the platform's key (a money bug).

This PR makes them routable WITHOUT trimming them, by adding 5 dedicated NON-PLATFORM BYOK-vendor providers and wiring them as name-only prefix-routing arms (zero models → no change to the platform menu / ModelsForRuntime):

provider protocol base_url matcher
byok-anthropic anthropic api.anthropic.com/v1 ^anthropic/
byok-openai openai api.openai.com/v1 ^openai[:/]
byok-gemini openai generativelanguage.googleapis.com/v1beta/openai ^gemini/
byok-minimax openai api.minimax.io/v1 (?i)^(minimax[:/]|codex-minimax-)
groq openai api.groq.com/openai/v1 ^groq:

Wired in:

  • hermes + byok-anthropic, byok-gemini, byok-openai, byok-minimax → resolves anthropic/*, gemini/*, openai/*, minimax/* (12 ids)
  • openclaw + byok-openai, byok-minimax, groq → resolves openai:*, minimax:*, groq:* (7 ids). The openclaw runtime DEFAULT minimax:MiniMax-M2.7 now resolves.
  • codex + byok-minimax → resolves the BYOK token-plan id codex-minimax-m2.7 (the template's minimax-token-plan route — same upstream api.minimax.io, tenant MINIMAX_API_KEY) via a narrowly-anchored ^codex-minimax- leg, not a broad matcher.

Billing-safe

Every new provider has name != "platform"IsPlatform() == false → BYOK billing. The workspace env supplies the tenant's vendor key; the platform key is never used. Verified in the DeriveProvider harness output below (IsPlatform=false for all).

Collision-free (DeriveProvider verification)

Every matcher is namespaced (slash/colon form), disjoint from the platform vendors' BARE matchers (anthropic-api ^claude, openai-subscription ^gpt-, openai-api ^openai-api[:/], minimax (?i)^minimax-m, google ^gemini-, minimax-cn ^minimax-cn[:/]). A throwaway LoadManifest() + DeriveProvider(runtime, id, nil) harness resolved all 20 ids + codex-minimax-m2.7 to EXACTLY ONE provider, no overlap, no error, none platform:

OK    hermes    anthropic/claude-haiku-4-5      -> byok-anthropic   (IsPlatform=false)
OK    hermes    anthropic/claude-opus-4-1       -> byok-anthropic   (IsPlatform=false)
OK    hermes    anthropic/claude-sonnet-4-5     -> byok-anthropic   (IsPlatform=false)
OK    hermes    gemini/gemini-2.5-flash         -> byok-gemini      (IsPlatform=false)
OK    hermes    gemini/gemini-2.5-pro           -> byok-gemini      (IsPlatform=false)
OK    hermes    minimax/MiniMax-M1              -> byok-minimax     (IsPlatform=false)
OK    hermes    minimax/MiniMax-M2.7           -> byok-minimax     (IsPlatform=false)
OK    hermes    minimax/MiniMax-M2.7-highspeed -> byok-minimax     (IsPlatform=false)
OK    hermes    openai/gpt-4o                  -> byok-openai      (IsPlatform=false)
OK    hermes    openai/gpt-4o-mini             -> byok-openai      (IsPlatform=false)
OK    hermes    openai/gpt-5                   -> byok-openai      (IsPlatform=false)
OK    hermes    openai/gpt-5-mini             -> byok-openai      (IsPlatform=false)
OK    openclaw  groq:llama-3.3-70b-versatile  -> groq             (IsPlatform=false)
OK    openclaw  groq:meta-llama/llama-4-scout-17b-16e-instruct -> groq  (IsPlatform=false)
OK    openclaw  minimax:MiniMax-M2.7          -> byok-minimax     (IsPlatform=false)
OK    openclaw  minimax:MiniMax-M2.7-highspeed-> byok-minimax     (IsPlatform=false)
OK    openclaw  openai:gpt-4.1-mini           -> byok-openai      (IsPlatform=false)
OK    openclaw  openai:gpt-4o                 -> byok-openai      (IsPlatform=false)
OK    openclaw  openai:o4-mini               -> byok-openai      (IsPlatform=false)
OK    codex     codex-minimax-m2.7           -> byok-minimax     (IsPlatform=false)

ALL 20 RESOLVED — EXACTLY ONE PROVIDER, NO ERROR, NONE PLATFORM

Drift = 0

go run ./cmd/check-template-models:

OK           claude-code-default    27 model id(s) all resolve
OK           hermes                 37 model id(s) all resolve
OK           codex                  9 model id(s) all resolve
OK           openclaw               13 model id(s) all resolve
UNREACHABLE  google-adk             template config.yaml HTTP 404 (pre-existing, non-blocking)
summary: 4 clean, 0 skipped, 1 unreachable, 0 failing
check-template-models: OK

(google-adk is a transient template-fetch 404, unchanged from before this PR, and the checker deliberately does not block on it. It is outside the 20 ids.) The gate is ready to go enforcing.

Tests / codegen

  • internal/providers + gen + cmd/check-template-models: PASS (runtimes_test.go native-set expectations updated for the new arms).
  • internal/handlers: PASS.
  • go test -tags serving_e2e -run TestEveryOfferedProviderHasAnArm ./internal/servinge2e/...: PASS (name-only BYOK arms are exempt from platform serving coverage, cp#529).
  • registry_gen.go regenerated via go generate ./cmd/gen-providers/.

Byte-sync — the two PRs MUST land together

providers.yaml is byte-identical across both repos (diff -u empty). This PR is paired with molecule-core / molecule-controlplane feat/cp529-byok-vendor-providers. molecule-core's copy also bumps canonicalProvidersYAMLSHA256 to the new canonical sha (846ddef1…), gated by the sync-providers-yaml drift check. Merging one without the other will turn that gate red.

🤖 Generated with Claude Code

## What The 20 ids cp#529's routability-aware drift checker flagged as **residual drift** are CUSTOMER BYOK vendor models for the SHARED upstream vendors (anthropic, openai, gemini, minimax, groq). They were left unroutable because wiring them through the platform-shared `platform` provider would bill the **platform's** key (a money bug). This PR makes them routable WITHOUT trimming them, by adding **5 dedicated NON-PLATFORM BYOK-vendor providers** and wiring them as **name-only prefix-routing arms** (zero models → no change to the platform menu / `ModelsForRuntime`): | provider | protocol | base_url | matcher | |---|---|---|---| | `byok-anthropic` | anthropic | api.anthropic.com/v1 | `^anthropic/` | | `byok-openai` | openai | api.openai.com/v1 | `^openai[:/]` | | `byok-gemini` | openai | generativelanguage.googleapis.com/v1beta/openai | `^gemini/` | | `byok-minimax` | openai | api.minimax.io/v1 | `(?i)^(minimax[:/]\|codex-minimax-)` | | `groq` | openai | api.groq.com/openai/v1 | `^groq:` | Wired in: - **hermes** + `byok-anthropic, byok-gemini, byok-openai, byok-minimax` → resolves `anthropic/*`, `gemini/*`, `openai/*`, `minimax/*` (12 ids) - **openclaw** + `byok-openai, byok-minimax, groq` → resolves `openai:*`, `minimax:*`, `groq:*` (7 ids). **The openclaw runtime DEFAULT `minimax:MiniMax-M2.7` now resolves.** - **codex** + `byok-minimax` → resolves the BYOK token-plan id `codex-minimax-m2.7` (the template's `minimax-token-plan` route — same upstream api.minimax.io, tenant `MINIMAX_API_KEY`) via a **narrowly-anchored** `^codex-minimax-` leg, not a broad matcher. ## Billing-safe Every new provider has `name != "platform"` → `IsPlatform() == false` → BYOK billing. The workspace env supplies the tenant's vendor key; the platform key is never used. Verified in the DeriveProvider harness output below (`IsPlatform=false` for all). ## Collision-free (DeriveProvider verification) Every matcher is **namespaced** (slash/colon form), disjoint from the platform vendors' BARE matchers (`anthropic-api ^claude`, `openai-subscription ^gpt-`, `openai-api ^openai-api[:/]`, `minimax (?i)^minimax-m`, `google ^gemini-`, `minimax-cn ^minimax-cn[:/]`). A throwaway `LoadManifest()` + `DeriveProvider(runtime, id, nil)` harness resolved all 20 ids + `codex-minimax-m2.7` to **EXACTLY ONE** provider, no overlap, no error, none platform: ``` OK hermes anthropic/claude-haiku-4-5 -> byok-anthropic (IsPlatform=false) OK hermes anthropic/claude-opus-4-1 -> byok-anthropic (IsPlatform=false) OK hermes anthropic/claude-sonnet-4-5 -> byok-anthropic (IsPlatform=false) OK hermes gemini/gemini-2.5-flash -> byok-gemini (IsPlatform=false) OK hermes gemini/gemini-2.5-pro -> byok-gemini (IsPlatform=false) OK hermes minimax/MiniMax-M1 -> byok-minimax (IsPlatform=false) OK hermes minimax/MiniMax-M2.7 -> byok-minimax (IsPlatform=false) OK hermes minimax/MiniMax-M2.7-highspeed -> byok-minimax (IsPlatform=false) OK hermes openai/gpt-4o -> byok-openai (IsPlatform=false) OK hermes openai/gpt-4o-mini -> byok-openai (IsPlatform=false) OK hermes openai/gpt-5 -> byok-openai (IsPlatform=false) OK hermes openai/gpt-5-mini -> byok-openai (IsPlatform=false) OK openclaw groq:llama-3.3-70b-versatile -> groq (IsPlatform=false) OK openclaw groq:meta-llama/llama-4-scout-17b-16e-instruct -> groq (IsPlatform=false) OK openclaw minimax:MiniMax-M2.7 -> byok-minimax (IsPlatform=false) OK openclaw minimax:MiniMax-M2.7-highspeed-> byok-minimax (IsPlatform=false) OK openclaw openai:gpt-4.1-mini -> byok-openai (IsPlatform=false) OK openclaw openai:gpt-4o -> byok-openai (IsPlatform=false) OK openclaw openai:o4-mini -> byok-openai (IsPlatform=false) OK codex codex-minimax-m2.7 -> byok-minimax (IsPlatform=false) ALL 20 RESOLVED — EXACTLY ONE PROVIDER, NO ERROR, NONE PLATFORM ``` ## Drift = 0 `go run ./cmd/check-template-models`: ``` OK claude-code-default 27 model id(s) all resolve OK hermes 37 model id(s) all resolve OK codex 9 model id(s) all resolve OK openclaw 13 model id(s) all resolve UNREACHABLE google-adk template config.yaml HTTP 404 (pre-existing, non-blocking) summary: 4 clean, 0 skipped, 1 unreachable, 0 failing check-template-models: OK ``` (google-adk is a transient template-fetch 404, unchanged from before this PR, and the checker deliberately does not block on it. It is outside the 20 ids.) **The gate is ready to go enforcing.** ## Tests / codegen - `internal/providers` + `gen` + `cmd/check-template-models`: PASS (`runtimes_test.go` native-set expectations updated for the new arms). - `internal/handlers`: PASS. - `go test -tags serving_e2e -run TestEveryOfferedProviderHasAnArm ./internal/servinge2e/...`: PASS (name-only BYOK arms are exempt from platform serving coverage, cp#529). - `registry_gen.go` regenerated via `go generate ./cmd/gen-providers/`. ## Byte-sync — the two PRs MUST land together `providers.yaml` is byte-identical across both repos (`diff -u` empty). This PR is paired with **molecule-core / molecule-controlplane** `feat/cp529-byok-vendor-providers`. molecule-core's copy also bumps `canonicalProvidersYAMLSHA256` to the new canonical sha (`846ddef1…`), gated by the `sync-providers-yaml` drift check. Merging one without the other will turn that gate red. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hongming added 1 commit 2026-06-04 23:32:01 +00:00
feat(providers): dedicated BYOK-vendor providers make hermes/openclaw vendor menus routable (cp#529)
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 2s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 5s
CI / Detect changes (pull_request) Successful in 8s
E2E API Smoke Test / detect-changes (pull_request) Successful in 6s
E2E Chat / detect-changes (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 5s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 27s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 2s
Harness Replays / detect-changes (pull_request) Successful in 3s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 3s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 4s
CI / Python Lint & Test (pull_request) Successful in 1m9s
gate-check-v3 / gate-check (pull_request_target) Successful in 10s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 21s
security-review / approved (pull_request_target) Failing after 8s
qa-review / approved (pull_request_target) Failing after 8s
verify-providers-gen / Regenerate providers artifact and fail on drift (pull_request) Successful in 25s
CI / Canvas (Next.js) (pull_request) Successful in 2s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
E2E Chat / E2E Chat (pull_request) Successful in 10s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 3s
Harness Replays / Harness Replays (pull_request) Successful in 3s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4s
CI / Canvas Deploy Status (pull_request) Has been skipped
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m1s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Failing after 2m16s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 57s
sop-tier-check / tier-check (pull_request_target) Has been cancelled
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
sync-providers-yaml / Compare synced providers.yaml against controlplane canonical (pull_request) Successful in 4s
sop-checklist / all-items-acked (pull_request_target) Successful in 4s
sop-checklist / review-refire (pull_request_target) Has been skipped
qa-review / approved (pull_request_review) Has been skipped
security-review / approved (pull_request_review) Has been skipped
sop-tier-check / tier-check (pull_request_review) Successful in 6s
CI / Platform (Go) (pull_request) Failing after 3m23s
CI / all-required (pull_request) Has been skipped
E2E Staging SaaS (full lifecycle) / E2E Staging Platform Boot (pull_request) Failing after 5m54s
audit-force-merge / audit (pull_request_target) Successful in 6s
79162509d0
Byte-synced mirror of the canonical change in molecule-controlplane
internal/providers/providers.yaml: add 5 NON-PLATFORM BYOK-vendor
provider entries (byok-anthropic, byok-openai, byok-gemini,
byok-minimax, groq) and wire them as name-only prefix-routing arms
into the hermes / openclaw / codex runtime native sets so the 20
residual ids cp#529 flagged as drift become routable with the
TENANT's OWN vendor key (billing-safe), not the platform-shared key.

- hermes: + byok-anthropic, byok-gemini, byok-openai, byok-minimax (12 ids)
- openclaw: + byok-openai, byok-minimax, groq (7 ids; runtime DEFAULT
  minimax:MiniMax-M2.7 now resolves)
- codex: + byok-minimax (codex-minimax-m2.7 via narrow ^codex-minimax- leg)

Billing-safe: every new provider IsPlatform()==false -> BYOK billing.
Collision-free: all matchers namespaced, disjoint from the platform
vendors' bare matchers; DeriveProvider resolves all 20 ids +
codex-minimax-m2.7 to exactly one non-platform provider.

This is the molecule-core SIDE of the synced registry: providers.yaml
is byte-identical to controlplane's (diff -u empty), registry_gen.go
regenerated, and canonicalProvidersYAMLSHA256 bumped to the new
canonical sha. The two PRs must land together.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hongming added the tier:medium label 2026-06-04 23:35:31 +00:00
core-qa approved these changes 2026-06-04 23:35:31 +00:00
core-qa left a comment
Member

cp#529 BYOK-vendor providers. Independently verified DeriveProvider: 20 ids -> byok-* (non-platform/BYOK), platform models unchanged, namespaced matchers disjoint from platform bare-form matchers (no collision), codex-minimax narrow-anchored, drift=0, byte-synced. Approve.

cp#529 BYOK-vendor providers. Independently verified DeriveProvider: 20 ids -> byok-* (non-platform/BYOK), platform models unchanged, namespaced matchers disjoint from platform bare-form matchers (no collision), codex-minimax narrow-anchored, drift=0, byte-synced. Approve.
core-security approved these changes 2026-06-04 23:35:33 +00:00
core-security left a comment
Member

cp#529 BYOK-vendor providers. Independently verified DeriveProvider: 20 ids -> byok-* (non-platform/BYOK), platform models unchanged, namespaced matchers disjoint from platform bare-form matchers (no collision), codex-minimax narrow-anchored, drift=0, byte-synced. Approve.

cp#529 BYOK-vendor providers. Independently verified DeriveProvider: 20 ids -> byok-* (non-platform/BYOK), platform models unchanged, namespaced matchers disjoint from platform bare-form matchers (no collision), codex-minimax narrow-anchored, drift=0, byte-synced. Approve.
hongming merged commit 6a44d8b175 into main 2026-06-04 23:38:34 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2262