fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up) - #346

Merged
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers
May 18, 2026
Merged

fix(core): expand model.provider runtime JSON schema enum to match Provider variants (#345 follow-up)#346
moonming merged 2 commits into
mainfrom
fix/runtime-schema-long-tail-providers

Conversation

@moonming

@moonmingmoonming commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

ai-gateway #345 (P2-A) added 11 long-tail OpenAI-adapter Provider::* variants + Hub registrations. The dashboard-side schema in schemas/resources/model.schema.json regenerated correctly. But there's a SEPARATELY-MAINTAINED hardcoded JSON schema in crates/aisix-core/src/models/schema.rs::model_schema() that backs aisix-etcd::loader's runtime validate_model check — and nobody updated it.

Result: cp-api admits a groq/mistral/etc. ProviderKey and Model (per #336 long-tail admission). The DP's aisix-etcd::loader reads the Model from etcd and validates against the OLD 6-value schema:

schema validation failed at `/provider`: "groq" is not one of ["openai","anthropic","google","deepseek","cohere","jina"]

Model rejected. Never appears in /v1/models. Customer's chat 404s on the alias.

Surfaced by AISIX-Cloud PR #366 e2e — first iteration of the D3.2 long-tail matrix. The groq Model creation succeeded at cp-api but the DP never saw it. Logs showed the schema rejection.

Fix

crates/aisix-core/src/models/schema.rs:120 — extend the provider enum from 6 to 17 values to match every Provider::as_str() output post-#345.

The existing negative-test model_unknown_provider_value_fails used "mistral" as the "unknown value" sentinel. Since mistral is now valid, renamed the fixture string to "this-is-not-a-provider-id" so the negative-test still pins the rejection class.

Why a separate schema even exists

aisix-etcd::loader::validate_and_parse runs schema validation BEFORE serde deserialization to fail-loud-and-skip on malformed entries (rather than crashing the DP). The schema is the gate; serde is the parser. Both must agree on the enum.

The dashboard-facing JSON schemas in schemas/resources/*.schema.json are GENERATED from the Rust types via cargo run --bin dump-schema (drift CI check enforces). The runtime validator's schema in schema.rs is hand-written and not gated by the drift check — a structural gap that this PR addresses with a behavioral fix only; a future refactor could fold the two sources together.

Test plan

References (per CLAUDE.md §7)

Refs api7/AISIX-Cloud#366

Summary by CodeRabbit

  • Improvements

    • Expanded model provider validation to accept an extended set of provider identifiers during schema validation.
  • Tests

    • Updated test cases to reflect the expanded provider validation rules, ensuring invalid providers continue to be properly rejected.

Review Change Stack

…ovider variants (#345 follow-up)
ai-gateway #345 added 11 long-tail OpenAI-adapter Provider variants
(groq, mistral, togetherai, fireworks-ai, perplexity, moonshotai,
alibaba, zhipuai, baseten, huggingface, cerebras) to the Rust enum +
Hub registrations + cp-api admission. The hardcoded JSON schema
backing `aisix-etcd::loader`'s `validate_model` runtime check at
`crates/aisix-core/src/models/schema.rs:120`, however, retained the
original 6-value allowlist.
The dashboard-side schema in `schemas/resources/model.schema.json`
was regenerated correctly by #345's `dump-schema` step — that file
IS now in sync with the enum. But the runtime validator uses a
SEPARATELY-MAINTAINED hardcoded schema at line 112-200 of
schema.rs that nobody updated. cp-api admission ✓, DP serde ✓,
runtime schema validator ✗ — a customer's groq Model resource gets
rejected at the etcd loader before deserialization with
`schema validation failed at \`/provider\`: "groq" is not one of
["openai","anthropic","google","deepseek","cohere","jina"]`.
This silently dropped EVERY long-tail Provider Model resource the
dashboard wrote. The model never appears in `/v1/models` on the
DP, and customer chat calls 404 on the alias.
Surfaced by AISIX-Cloud PR #366 e2e (D3.2 batch 1) — the groq
Model creation succeeds at cp-api but the DP never sees it. Logs
showed the schema validation rejection.
Fix
`crates/aisix-core/src/models/schema.rs:120` — extend the `provider`
enum to the full 17 values matching `Provider::as_str()` output
across every variant:
```rust
"provider": { "type": "string", "enum": [
"openai","anthropic","google","deepseek","cohere","jina",
"groq","mistral","togetherai","fireworks-ai","perplexity",
"moonshotai","alibaba","zhipuai","baseten","huggingface","cerebras"
] },
```
The existing negative-test `model_unknown_provider_value_fails`
used `"mistral"` as the "unknown value" sentinel; since mistral is
now valid, the test would have stopped catching the rejection
path. Renamed the test fixture value to `"this-is-not-a-provider-id"`
so the negative-test still pins the rejection class.
All 52 aisix-core schema tests pass; clippy clean; fmt clean.
References (per CLAUDE.md §7)
- ai-gateway#345 (merged) — Provider enum + Hub register additions
- aisix-etcd loader.rs:262 — schema-rejection log path that
surfaced the gap
CopilotAI review requested due to automatic review settings May 18, 2026 17:56
@coderabbitai

coderabbitaiBot commented May 18, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 6608819e-114c-4760-8c03-7fa8bfd7b4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d88b41 and ab76aa5.

📒 Files selected for processing (3)
  • crates/aisix-admin/src/lib.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-etcd/src/supervisor.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/aisix-etcd/src/supervisor.rs

📝 Walkthrough

Walkthrough

The PR expands the model JSON schema's provider field enum to accept a larger set of provider identifiers and updates tests/fixtures that previously used mistral to use a clearly invalid provider string so schema-rejection tests still fail.

Changes

Provider Field Allowlist Expansion

Layer / File(s)Summary
Provider field schema and core validation test
crates/aisix-core/src/models/schema.rs
The provider field enum in the model schema is expanded to accept a larger allowlist. The model_unknown_provider_value_fails test is updated to use an explicitly invalid provider string so the validation rejection path is still exercised.
Update tests and fixtures across crates
crates/aisix-admin/src/lib.rs, crates/aisix-etcd/src/loader.rs, crates/aisix-etcd/src/supervisor.rs
Tests and JSON fixtures that previously used provider: "mistral" were changed to use provider: "this-is-not-a-provider-id" (or similar) to keep negative schema-validation tests failing under the expanded provider allowlist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above.

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

…rovider sentinel
The negative-test fixtures across `aisix-admin` and `aisix-etcd`
used `"mistral"` as the "unknown provider" sentinel — a vestige
of the pre-#345 6-value allowlist. With ai-gateway#345 first-classing
11 long-tail variants (including mistral), those tests started
asserting against a now-VALID provider and FAILED.
Replaced every fixture occurrence with `"this-is-not-a-provider-id"`,
which is intentionally NOT in the post-#345 17-value enum, keeping
the schema-rejection class pinned without churn-tracking the live
provider list.
Files touched (post-#345 surgical sentinel rotation):
- `crates/aisix-admin/src/lib.rs::create_model_with_invalid_provider_prefix_is_400_schema_error`
- `crates/aisix-etcd/src/loader.rs::tests` (2 sites)
- `crates/aisix-etcd/src/supervisor.rs::tests` (1 site, drives ~6 transitive supervisor test failures via shared fixture)
All workspace tests green; clippy clean; fmt clean.
Refs ai-gateway#345 ai-gateway#346
@moonming
moonming merged commit 71ea97e into mainMay 18, 2026
8 checks passed
janiussyafiq added a commit that referenced this pull request May 20, 2026
Integrate origin/main (commit 2c1d485 = post-PR-#326 / #348 plus
#330 / #341 / #343 / #345 / #346) into this branch via `git merge
--squash` to clear PR #344's lingering `mergeable: dirty` state.
Conflict on `docs/quickstart/self-hosted.md` was a 3-way-merge-base
artifact: base (3596c0a) read `- a reachable etcd instance`, main
changed `a` → `A` (via #326), this branch additionally inserted the
glossary link. Both changes are wanted; resolution per Umar's
approved plan was `git checkout --ours`, which preserves the branch's
self-hosted.md state (already integrates capital A + glossary link
+ first-time-build paragraph + keep-running framing). Other 4
overlapping doc files auto-merged cleanly (`bootstrap-config.md`,
`core-concepts.md`, `first-model-first-key-first-request.md`,
`openai-sdk.md`). Code files all auto-merged cleanly.
Additional Copilot review (post-`167196a` cycle) addressed:
- `docs/index.md:7` — change link display text from `[data-plane]`
to `[data plane]` to match the canonical glossary term. The URL
anchor `#data-plane` stays kebab-case (matches the glossary
heading's auto-anchor); only the display text changes. Comment
id 3271145422.
- `docs/quickstart/openai-sdk.md:43` — change `All three steps below`
to `All commands below`. The Install-the-SDK section has two
command blocks (mkdir+cd, npm install), not three; the prior
wording originated from a mental model (mkdir, cd, install)
that doesn't match the typographic count of code blocks under
the heading. Comment id 3271145458.
Copilot's third comment on `docs/overview/core-concepts.md`
Observability Exporter wording (id 3271145444) auto-resolves via
this merge — main's #326 rewrite supersedes the branch's pre-#326
wording at that location ("ships per-request span telemetry…
OTLP/HTTP-compatible backend…" replaces "Use this concept when
documenting…"). No separate edit needed; the merge IS the fix.
janiussyafiq added a commit that referenced this pull request May 20, 2026
…ickstart-polish
Resolve PR #344's lingering mergeable: dirty state by linking the
branch history to origin/main (2c1d485 = post-#326 / #348 / #330 /
#341 / #343 / #345 / #346).
The squash-merge commit landed earlier (e2af197) integrated main's
content into the branch tree but did not link the histories, so
GitHub's mergeable computation still saw the 3-way-merge-base
artifact conflict on docs/quickstart/self-hosted.md (a vs A + the
glossary link / "In another terminal" vs "Keep the gateway running"
framing). This explicit merge commit ties the branch to main's
history.
Self-hosted.md conflict resolved by taking OUR side — the branch's
edits already contain main's substantive changes (capital A,
first-time-build paragraph) plus this PR's additions (glossary
link, keep-running framing, YOUR_ADMIN_KEY note, config.yaml
location anchor).
The auto-merge of first-model-first-key-first-request.md duplicated
the :::warning callout that was already integrated via the squash
commit; removed the duplicate.
@jarvis9443
jarvis9443 deleted the fix/runtime-schema-long-tail-providers branch June 25, 2026 06:26
Sign up for freeto 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.

1 participant

@moonming