Skip to content

feat(core): vendor-neutral model-gateway config (ELIZA_MODEL_GATEWAY_URL/TOKEN) with fail-closed strict mode (#11536 E1) - #11660

Merged
lalalune merged 2 commits into
developfrom
sol/11536-e1-gateway-config
Jul 2, 2026
Merged

feat(core): vendor-neutral model-gateway config (ELIZA_MODEL_GATEWAY_URL/TOKEN) with fail-closed strict mode (#11536 E1)#11660
lalalune merged 2 commits into
developfrom
sol/11536-e1-gateway-config

Conversation

@0xSolace

@0xSolace 0xSolace commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

What

Implements phase E1 of #11536: a vendor-neutral model-gateway config layer so a single OpenAI-compatible gateway (credential broker) can front all model traffic, and raw provider keys never reach the model client.

Sibling layer (E2)

PR #11651 (merged) landed the E2 slice under plugins/plugin-agent-orchestrator/src/services/model-gateway.ts — the spawned sub-agent env path (rewrites a child process env so Codex/Claude-Code point at the gateway). This PR is the complementary core-runtime resolution layer (documents config → llm.ts, inference-provider) — the paths #11651 leaves untouched.

The two layers share the canonical env-var-name contract (ELIZA_MODEL_GATEWAY_URL / ELIZA_MODEL_GATEWAY_TOKEN). This module mirrors #11651's exported constant names (MODEL_GATEWAY_URL_KEY / MODEL_GATEWAY_TOKEN_KEY) for cross-layer greppability but duplicates rather than imports them — packages/core must not depend on a plugin (dependency direction). A test pins the shared strings so the contract can't drift.

How

New packages/core/src/model-gateway.ts:

  • Precedence at the same layer as the raw vars. ELIZA_MODEL_GATEWAY_URL takes precedence as the effective base URL and ELIZA_MODEL_GATEWAY_TOKEN as the effective api key at the exact resolution point that consumes OPENAI_BASE_URL / OPENAI_API_KEY. Every OpenAI-compatible client inherits gateway mode automatically. Vendor-neutral: the gateway only has to be OpenAI-compatible.
  • Scrubber. When gateway mode is on, the raw provider key is dropped from the resolved OpenAI-compatible config so it never travels alongside the gateway token.
  • Fail-closed strict mode (E1-only; the E2 sub-agent module has no strict mode). ELIZA_MODEL_GATEWAY_STRICT=1 + a raw provider key present while gateway mode is on → hard error (ModelGatewayStrictError) naming the offending variable. Non-strict: gateway silently wins.

Choke points wired

  • packages/core/src/features/documents/config.ts — applies gateway resolution to the resolved ModelConfig (OPENAI_BASE_URL / OPENAI_API_KEY), which feeds both createOpenAI call sites in llm.ts (text generation + embeddings). Strict-mode throw propagates through the existing error handling.
  • packages/core/src/testing/inference-provider.ts — openai provider endpoint detection uses the gateway URL when gateway mode is on (defensive: a strict-mode misconfig does not crash detection; authoritative enforcement lives in the runtime config layer).
  • Exported from both node + browser barrels (pure string logic, no Node deps).

Tests

packages/core/src/model-gateway.test.ts (17 tests) next to the module per repo convention:

  • canonical env-var-name contract + alias pinning (shared with feat(orchestrator): vendor-neutral model-gateway mode for spawned coding sub-agents (#11536 E2) #11651)
  • gateway URL/token precedence (incl. overriding raw OPENAI_BASE_URL/OPENAI_API_KEY, whitespace trimming, no-token case)
  • strict-mode fail-closed names the offending var(s); does not fail-closed when gateway mode is off; non-strict path silently wins
  • scrubber: resolved config carries no raw key material when gateway mode is on (incl. no-token case)

Targeted suites green: 37 passing (model-gateway 17, inference-timing 12, live-provider 8), zero new failures. Pre-existing failures in features/documents/* are an unrelated missing optional dep (mammoth) in the worktree, confirmed on the clean baseline. Biome clean on all touched files. Rebased on latest develop (includes #11651).

Scope

Core runtime only. Does not touch packages/cloud/** (PR #11528's lane), packages/app, packages/ui, binaries, or lockfiles.

Part of #11536. Sibling: #11651.

[sol-forge] — [sol-orch]

@greptile-apps greptile-apps Bot 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4290d2a7-a371-47e8-a87f-6f615ddbe7a4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sol/11536-e1-gateway-config

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…URL/TOKEN) with fail-closed strict mode (#11536 E1)

Add a vendor-neutral credential-broker gateway layer so a single
OpenAI-compatible gateway can front all model traffic without raw
provider keys ever reaching the model client.

- New packages/core/src/model-gateway.ts: resolveModelGateway() /
  applyModelGateway(). ELIZA_MODEL_GATEWAY_URL takes precedence as the
  effective base URL and ELIZA_MODEL_GATEWAY_TOKEN as the effective api
  key at the same resolution layer that consumes OPENAI_BASE_URL /
  OPENAI_API_KEY, so every OpenAI-compatible client inherits gateway
  mode. Vendor-neutral: the gateway only needs to be OpenAI-compatible.
- Scrubber: when gateway mode is on, the raw provider key is dropped
  from the resolved OpenAI-compatible config so it never travels with
  the gateway request.
- Fail-closed strict mode (ELIZA_MODEL_GATEWAY_STRICT=1): if a raw
  provider key is present while gateway mode is on, throw
  ModelGatewayStrictError naming the offending var. Non-strict: gateway
  silently wins.
- Wire choke points: features/documents/config.ts (feeds llm.ts embed +
  text createOpenAI baseURL/apiKey) and testing/inference-provider.ts
  openai endpoint detection.
- Export from both node + browser barrels (pure string logic, no Node
  deps).
- Tests next to the module: URL/token precedence, strict fail-closed
  names the offending var, resolved config carries no raw key material
  when gateway mode on, canonical env-var-name contract.

Sibling layer: PR #11651 (E2, merged) covers the spawned sub-agent env
path in plugins/plugin-agent-orchestrator. It defines the canonical
env-var-name contract (ELIZA_MODEL_GATEWAY_URL / _TOKEN). This module
mirrors those constant names (MODEL_GATEWAY_URL_KEY / _TOKEN_KEY) for
cross-layer greppability but DUPLICATES rather than imports them, since
packages/core must not depend on a plugin.

Core runtime only; does not touch packages/cloud.

Co-authored-by: wakesync <shadow@shad0w.xyz>
@0xSolace
0xSolace force-pushed the sol/11536-e1-gateway-config branch from 864ea9d to 2c18fa4 Compare July 2, 2026 23:06

@greptile-apps greptile-apps Bot 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@lalalune lalalune left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed #11660 against #11536 E1 and the merged sibling lanes (#11528 cloud hosted-agent wiring, #11651 spawned sub-agent gateway env).

Verdict: approve. This is correctly scoped to the core OpenAI-compatible model-client config layer: gateway URL/token take precedence at the same documents config resolution point as OPENAI_BASE_URL/OPENAI_API_KEY, raw OpenAI key material is scrubbed before the createOpenAI call sites receive config, and strict mode fails closed when raw provider keys coexist with gateway mode. The duplicated canonical env-var names are intentional because packages/core must not depend on the orchestrator plugin.

Change I added: sorted the new model-gateway barrel export in index.browser.ts and index.node.ts so Biome passes.

Local verification on da275c6802:

  • bun run --cwd packages/core test -- src/model-gateway.test.ts src/__tests__/inference-timing.test.ts src/testing/live-provider.test.ts -> 3 files / 37 tests passed
  • PATH="$PWD/node_modules/.bin:$PATH" bun run --cwd packages/core typecheck -> passed
  • bunx @biomejs/biome check packages/core/src/model-gateway.ts packages/core/src/model-gateway.test.ts packages/core/src/features/documents/config.ts packages/core/src/testing/inference-provider.ts packages/core/src/index.browser.ts packages/core/src/index.node.ts -> passed
  • git diff --check origin/develop...HEAD and git diff --check -> passed

#11536 remains open for later phases; this only resolves E1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants