Skip to content

feat(models): add Alibaba EU (Frankfurt) region - #3525

Merged
steebchen merged 3 commits into
mainfrom
port-vila
Aug 10, 2026
Merged

steebchen merged 3 commits into
mainfrom
port-vila

Conversation

@steebchen

@steebchen steebchen commented Aug 10, 2026 •

Copy link
Copy Markdown
Member

Adds Alibaba Cloud's EU (Frankfurt) region (eu-frankfurt).

Why this needs more than an endpointMap entry

Frankfurt is the one Model Studio region with no shared DashScope domain — dashscope-eu, dashscope-de and eu-central-1.dashscope do not resolve at all. It is reachable two ways, both verified live against a real Frankfurt key:

Host Works Notes
{WorkspaceId}.eu-central-1.maas.aliyuncs.com ✅ Per-credential; full rate limits and SLA
trial.eu-central-1.maas.aliyuncs.com ✅ Shared; resolves the workspace from the API key
any other label (foo., dashscope., api., …) ❌ Workspace endpoint is invalid
plain DashScope hosts ❌ Frankfurt has none

An earlier attempt (48d088f, never merged) pointed frankfurt at dashscope-intl, which silently executed EU-designated traffic in Singapore. This does not alias any host.

Design

The workspace ID is optional. Without one, Frankfurt uses the shared entry point, so an API key alone keeps working. With one, requests go to the credential's own endpoint — Alibaba caps the shared host at 1000 RPM with no SLA and documents it as "not recommended for production environments".

  • endpointMap entries may carry a {workspaceId} placeholder; endpointFallbackMap supplies the shared host to use when no ID is configured.
  • Resolution order: managed credential → provider-key option → LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT → base var → shared host. The ID is validated as a bare hostname label before interpolation.
  • Regional env lookups honour the __ENTERPRISE__/__PLANS__ variant names and comma-separated configIndex selection.
  • Only a region with no fallback is gated out of routing, so an unbuildable endpoint is never selected.
  • The dialog shows an optional Workspace ID field for regions that use one.

Other regions are untouched: they keep their plain DashScope hosts, which accept both legacy and workspace-scoped (sk-ws-…) keys.

Pricing

Alibaba's published Frankfurt (Global-scope) list prices; all three models are Global-scope only there, so there is no deployment-scope ambiguity. Cache rates follow the documented model-level ratios (implicit 20%, explicit hit 10%, write 125%), which are region-independent.

Model Input Output
qwen3.7-max $1.65 $4.951
qwen3.7-plus $0.276 / $0.826 (>256K) $1.101 / $3.301
qwen3.6-plus $0.276 $1.651

qwen3.8-max is not offered in Frankfurt and is excluded.

Testing

Real e2e against Frankfurt, both endpoint paths, 144 passed / 0 failed each:

TEST_MODELS="alibaba/qwen3.7-max:eu-frankfurt,alibaba/qwen3.7-plus:eu-frankfurt,alibaba/qwen3.6-plus:eu-frankfurt" FULL_MODE=true pnpm test:e2e

27 named :eu-frankfurt cases ran (reasoning efforts none→max, reasoning + streaming) with requestedRegion: "eu-frankfurt".

Provider-key registration verified through the real POST /keys/provider route with live keys: legacy key on a shared-host region, workspace-scoped key with its workspace ID, workspace-scoped key without one, and an invalid workspace ID rejected.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Alibaba Cloud EU (Frankfurt) region support.
    • Added optional workspace ID configuration for account-specific Alibaba endpoints.
    • Added workspace ID validation, endpoint guidance, and display in provider key management.
    • Added shared-endpoint fallback where supported.
    • Added Frankfurt pricing for supported Qwen models.
  • Documentation

    • Documented regional endpoint routing, workspace ID requirements, and shared endpoint availability.

Frankfurt is the one Model Studio region without a shared DashScope
domain: neither dashscope-eu nor dashscope-de resolves, and it is served
only by the workspace-dedicated {WorkspaceId}.eu-central-1.maas host.
Region endpoints can therefore carry a {workspaceId} placeholder that the
credential fills in, supplied per provider key or via
LLM_ALIBABA_WORKSPACE_ID(__EU_FRANKFURT).

A region that needs a workspace id is not routable from an API key
alone, so platform-credential availability requires both before the
gateway will select it, and the workspace id is validated as a bare
hostname label before it is interpolated.

Adds Frankfurt mappings with Alibaba's published Frankfurt prices for
qwen3.7-max, qwen3.7-plus and qwen3.6-plus.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 10, 2026 19:45
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ce6960e-85c3-4a66-96d3-332fb744857b

📥 Commits

Reviewing files that changed from the base of the PR and between 58c28a7 and cd028f7.

📒 Files selected for processing (1)
  • packages/models/src/providers.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/models/src/providers.ts

Walkthrough

This change adds Alibaba Cloud EU Frankfurt support with workspace-specific endpoints. Provider schemas, environment resolution, endpoint construction, model metadata, tests, and provider-key UI configuration now support alibaba_workspace_id.

Changes

Alibaba workspace routing

Layer / File(s) Summary
Provider contracts and Frankfurt metadata
packages/models/src/providers.ts, packages/db/src/schema.ts, packages/models/src/models/alibaba.ts
Alibaba definitions add the Frankfurt workspace endpoint, workspace credential, fallback endpoint, region detection, provider-key option, and regional pricing.
Regional environment resolution and availability
packages/models/src/provider.ts, packages/models/src/provider.spec.ts, apps/api/src/routes/admin-provider-credentials.spec.ts
Environment helpers resolve regional settings and indexed values. Workspace-scoped regions require regional workspace configuration before credentials are considered available.
Workspace endpoint construction and routing
packages/actions/src/get-provider-endpoint.ts, packages/actions/src/get-provider-endpoint.spec.ts
Endpoint resolution validates workspace IDs, substitutes them into Frankfurt hosts, applies fallbacks, and tests credential, provider-option, and environment-variable sources.
Provider-key configuration and validation
apps/api/src/routes/keys-provider.ts, apps/ui/src/components/provider-keys/create-provider-key-dialog.tsx, apps/ui/src/components/provider-keys/provider-keys-list.tsx, apps/api/src/routes/keys-provider.spec.ts, apps/api/src/routes/keys-provider.e2e.ts, apps/docs/content/features/routing.mdx, apps/gateway/src/chat-helpers.e2e.ts
Provider-key schemas, API validation, UI validation, option labels, reset behavior, test fixtures, and routing documentation support workspace IDs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant ProviderKeyDialog
  participant API
  participant getProviderEndpoint
  participant Alibaba
  Admin->>ProviderKeyDialog: Select Alibaba EU Frankfurt
  ProviderKeyDialog->>ProviderKeyDialog: Validate workspace ID
  ProviderKeyDialog->>API: Submit region and workspace ID
  API->>getProviderEndpoint: Resolve provider endpoint
  getProviderEndpoint->>Alibaba: Build workspace-specific URL
  Alibaba-->>getProviderEndpoint: Return routed endpoint
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding Alibaba Cloud's EU (Frankfurt) region to the models and routing configuration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch port-vila

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/routes/keys-provider.ts`:
- Around line 337-340: Update the create-request schema containing
alibaba_region and alibaba_workspace_id with a conditional refinement that
requires a workspace ID when the region is eu-frankfurt and validates it as 1–64
alphanumeric-or-hyphen characters. Add create-route tests covering a missing
workspace ID and an invalid workspace ID, while preserving existing validation
for other regions.

In `@packages/models/src/provider.ts`:
- Around line 380-389: Update the regional lookup in the provider
environment-value resolver to generate variant-specific names using variant and
region, then apply the same comma-separated list selection by configIndex as
getProviderEnvValue before returning. Preserve fallback to getProviderEnvValue
when no matching regional value exists, and add endpoint tests covering
variant-specific and indexed regional workspace IDs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2475ecb4-ae89-4cd4-af93-8548f83f7697

📥 Commits

Reviewing files that changed from the base of the PR and between a6eb013 and c794ee5.

📒 Files selected for processing (12)
  • apps/api/src/routes/admin-provider-credentials.spec.ts
  • apps/api/src/routes/keys-provider.ts
  • apps/docs/content/features/routing.mdx
  • apps/ui/src/components/provider-keys/create-provider-key-dialog.tsx
  • apps/ui/src/components/provider-keys/provider-keys-list.tsx
  • packages/actions/src/get-provider-endpoint.spec.ts
  • packages/actions/src/get-provider-endpoint.ts
  • packages/db/src/schema.ts
  • packages/models/src/models/alibaba.ts
  • packages/models/src/provider.spec.ts
  • packages/models/src/provider.ts
  • packages/models/src/providers.ts

Comment thread apps/api/src/routes/keys-provider.ts Outdated
Comment thread packages/models/src/provider.ts Outdated
@vicovaro

Copy link
Copy Markdown
Contributor

add qwen3.7-flash and qwen3.6-flash too for eu-frankfurt.

Also, qwen3.7-flash got a price decrease on non-Singapore region to 0.028$/m in and 0.11$/m out.
qwen3.7-plus also got a price decrease on non-Singapore region.
But that's worth for another PR as fix(models) Qwen models price decrease like so

@smakosh smakosh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🚀

Frankfurt is the one Model Studio region with no shared DashScope domain.
It is served by the workspace-dedicated
`{WorkspaceId}.eu-central-1.maas.aliyuncs.com` host, and by a shared entry
point that resolves the workspace from the API key.

The workspace id is therefore optional: without one the region falls back to
the shared host, so an API key alone keeps working. Alibaba caps that host at
1000 RPM with no SLA and advises against production use, so a credential that
supplies a workspace id gets its own endpoint instead.

Also addresses review feedback: regional env lookups now honour the
`__ENTERPRISE__`/`__PLANS__` variant names and comma-separated configIndex
selection, and the workspace id is format-validated server-side rather than
in the dialog alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/routes/keys-provider.spec.ts`:
- Around line 260-263: Update the acceptance tests for both shared-host Alibaba
regions, including the test around postAlibabaKey for eu-frankfurt and the
corresponding test near it, to assert an exact 200 response instead of merely
checking the status is not 400. Preserve the existing request setup and region
coverage.

In `@apps/gateway/src/chat-helpers.e2e.ts`:
- Around line 1275-1285: Update the Alibaba branch in the credential-seeding
helper to read the Frankfurt-specific value via
getRegionSpecificEnvValue("alibaba", "eu-frankfurt") while retaining the generic
LLM_ALIBABA_API_KEY token flow. When the workspace is available, persist
alibaba_region as "eu-frankfurt" together with alibaba_workspace_id; preserve
the undefined result when no workspace is configured.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f7bf337-14df-4f15-9801-e28f9b254894

📥 Commits

Reviewing files that changed from the base of the PR and between c794ee5 and 58c28a7.

📒 Files selected for processing (12)
  • apps/api/src/routes/keys-provider.e2e.ts
  • apps/api/src/routes/keys-provider.spec.ts
  • apps/api/src/routes/keys-provider.ts
  • apps/docs/content/features/routing.mdx
  • apps/gateway/src/chat-helpers.e2e.ts
  • apps/ui/src/components/provider-keys/create-provider-key-dialog.tsx
  • packages/actions/src/get-provider-endpoint.spec.ts
  • packages/actions/src/get-provider-endpoint.ts
  • packages/models/src/models/alibaba.ts
  • packages/models/src/provider.spec.ts
  • packages/models/src/provider.ts
  • packages/models/src/providers.ts
💤 Files with no reviewable changes (1)
  • packages/models/src/models/alibaba.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/docs/content/features/routing.mdx
  • packages/models/src/provider.spec.ts
  • packages/actions/src/get-provider-endpoint.spec.ts
  • packages/actions/src/get-provider-endpoint.ts
  • packages/models/src/provider.ts
  • apps/ui/src/components/provider-keys/create-provider-key-dialog.tsx

Comment on lines +260 to +263
test("accepts eu-frankfurt without a workspace id", async () => {
const res = await postAlibabaKey({ alibaba_region: "eu-frankfurt" });
expect(res.status).not.toBe(400);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert successful creation in the acceptance tests.

A 401, 403, or 500 response satisfies not.toBe(400). The tests can therefore pass when provider-key creation fails. Assert 200 for both shared-host regions.

Proposed assertion fix
-			expect(res.status).not.toBe(400);
+			expect(res.status).toBe(200);

Also applies to: 273-276

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/routes/keys-provider.spec.ts` around lines 260 - 263, Update the
acceptance tests for both shared-host Alibaba regions, including the test around
postAlibabaKey for eu-frankfurt and the corresponding test near it, to assert an
exact 200 response instead of merely checking the status is not 400. Preserve
the existing request setup and region coverage.

Comment on lines +1275 to +1285
if (providerId === "alibaba") {
// BYOK keys never read env vars at request time, so a workspace-scoped
// region (Frankfurt) is only reachable when the seeded key carries the
// workspace id the way a real credential would.
const workspaceId = getRegionScopedProviderEnvValue(
"alibaba",
"workspaceId",
"eu-frankfurt",
);
return workspaceId ? { alibaba_workspace_id: workspaceId } : undefined;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline apps/gateway/src/chat-helpers.e2e.ts --items all

rg -n -C 8 'createProviderKey\s*\(' apps/gateway/src/chat-helpers.e2e.ts
rg -n -C 8 'alibaba_region|alibaba_workspace_id|getRegionScopedProviderEnvValue' \
  apps/gateway/src/chat-helpers.e2e.ts \
  packages/actions/src/get-provider-endpoint.ts

Repository: theopenco/llmgateway

Length of output: 10132


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- createProviderKey implementation ---'
sed -n '1121,1155p' apps/gateway/src/chat-helpers.e2e.ts

printf '%s\n' '--- Alibaba endpoint resolution context ---'
sed -n '360,465p' packages/actions/src/get-provider-endpoint.ts

printf '%s\n' '--- Alibaba option/type and region definitions ---'
rg -n -C 5 'alibaba_region|alibaba_workspace_id|workspaceId|region.*alibaba|alibaba.*region' \
  packages apps -g '*.ts' -g '*.tsx' | head -n 260

printf '%s\n' '--- changed-file summary and Qwen references ---'
git diff --stat
rg -n -C 3 'qwen|Qwen|TEST_MODELS' apps/gateway packages -g '*.e2e.ts' -g '*.ts' | head -n 260

Repository: theopenco/llmgateway

Length of output: 41562


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- endpoint function signature and region selection ---'
rg -n -C 12 'export (async )?function getProviderEndpoint|function getProviderEndpoint|regionBaseUrl|const region =' \
  packages/actions/src/get-provider-endpoint.ts | head -n 220

printf '%s\n' '--- Alibaba provider catalogue and environment configuration ---'
rg -n -C 12 'id: "alibaba"|workspaceId|apiKey|LLM_ALIBABA|eu-frankfurt|qwen' \
  packages/models apps/gateway/src/chat-helpers.e2e.ts \
  -g '*.ts' -g '*.tsx' | head -n 320

printf '%s\n' '--- provider-key options at all Alibaba call sites ---'
rg -n -C 10 'providerKeyOptions|credentialConfig|createProviderKey\(' \
  packages/actions/src apps/gateway/src -g '*.ts' | head -n 320

printf '%s\n' '--- repository state ---'
git status --short
git diff --name-only

Repository: theopenco/llmgateway

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Alibaba provider definition ---'
line=$(rg -n '^(\s*)id: "alibaba"' packages/models/src/providers.ts | cut -d: -f1 | head -n1)
echo "line=$line"
sed -n "$((line-8)),$((line+70))p" packages/models/src/providers.ts

printf '%s\n' '--- Alibaba environment helper implementation ---'
rg -n -C 8 'function getRegionScopedProviderEnvValue|export function getRegionScopedProviderEnvValue|getRegionEnvVarSuffix' \
  packages/models/src -g '*.ts'

printf '%s\n' '--- Alibaba region mappings and Qwen model entries ---'
rg -n -C 8 'providerId: "alibaba"|provider: "alibaba"|eu-frankfurt|qwen' \
  packages/models/src -g '*.ts' | grep -E -B8 -A8 'alibaba|eu-frankfurt|qwen' | head -n 260

printf '%s\n' '--- Runtime uses of alibaba_region ---'
rg -n -C 5 'alibaba_region' packages apps -g '*.ts' -g '*.tsx'

Repository: theopenco/llmgateway

Length of output: 26796


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- provider environment filtering ---'
sed -n '140,185p' apps/gateway/src/chat-helpers.e2e.ts
sed -n '430,490p' packages/models/src/provider.ts

printf '%s\n' '--- Alibaba Qwen model mappings ---'
rg -n -C 12 'providerId: "alibaba"|regions:|qwen' packages/models/src/models -g '*.ts' \
  | awk 'BEGIN{p=0} /qwen|Qwen/{p=1} p{print} p&&NR>0{c++} c>220{exit}'

printf '%s\n' '--- regional API-key helper and provider-key seeding helpers ---'
rg -n -C 10 'getRegionSpecificEnvValue|getRegionSpecificEnvVarName|getProviderEnvVar\(|hasAllRequiredProviderEnvVars|providerEnvOptionsForTests|beforeAllHook' \
  packages/models/src apps/gateway/src/chat-helpers.e2e.ts -g '*.ts'

printf '%s\n' '--- E2E scripts and model-selection documentation ---'
rg -n -C 4 'TEST_MODELS|vitest.*e2e|gateway.*e2e' package.json apps/gateway/package.json README.md .github -g '*.json' -g '*.md' -g '*.yml' -g '*.yaml' 2>/dev/null | head -n 220

Repository: theopenco/llmgateway

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- request call sites that supply the Alibaba region ---'
rg -n -C 14 'getProviderEndpoint\(' packages apps -g '*.ts' | grep -E -B14 -A14 'getProviderEndpoint|region' | head -n 360

printf '%s\n' '--- endpoint fallback implementation ---'
sed -n '49,90p' packages/actions/src/get-provider-endpoint.ts
rg -n -C 8 'regionConfig\.optionsKey|optionsKey|providerKeyOptions.*options|options.*providerKey' \
  packages apps -g '*.ts' | head -n 240

printf '%s\n' '--- read-only behavioral verifier ---'
python3 - <<'PY'
from pathlib import Path
import re

helper = Path("apps/gateway/src/chat-helpers.e2e.ts").read_text()
endpoint = Path("packages/actions/src/get-provider-endpoint.ts").read_text()
provider = Path("packages/models/src/providers.ts").read_text()
models = Path("packages/models/src/provider.ts").read_text()

before_all = helper[helper.index("export async function beforeAllHook"):helper.index("function providerEnvOptionsForTests")]
options_fn = helper[helper.index("function providerEnvOptionsForTests"):helper.index("export async function beforeEachHook")]
create_fn = helper[helper.index("export async function createProviderKey"):helper.index("export function validateResponse")]

assert 'const envVarName = getProviderEnvVar(provider.id);' in before_all
assert 'getRegionSpecificEnvValue(' not in before_all
assert 'getRegionScopedProviderEnvValue(' in options_fn
assert 'alibaba_workspace_id: workspaceId' in options_fn
assert 'alibaba_region' not in options_fn
assert re.search(r'options,', create_fn)
assert 'providerKeyOptions?.alibaba_workspace_id' in endpoint
assert 'getRegionScopedProviderEnvValue(' in endpoint
assert '"eu-frankfurt": `https://${REGION_WORKSPACE_ID_PLACEHOLDER}.eu-central-1.maas.aliyuncs.com`' in provider
assert '"eu-frankfurt": "https://trial.eu-central-1.maas.aliyuncs.com"' in provider

# Emulate the relevant credential selection:
def seeded_token(env):
    return env.get("LLM_ALIBABA_API_KEY")

def seeded_options(env):
    ws = env.get("LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT")
    return {"alibaba_workspace_id": ws} if ws else None

env = {
    "LLM_ALIBABA_API_KEY": "generic-token",
    "LLM_ALIBABA_API_KEY__EU_FRANKFURT": "frankfurt-token",
    "LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT": "workspace-id",
}
assert seeded_token(env) == "generic-token"
assert seeded_options(env) == {"alibaba_workspace_id": "workspace-id"}
assert "alibaba_region" not in seeded_options(env)

print("beforeAllHook seeds the base Alibaba token, not the regional token.")
print("providerEnvOptionsForTests carries the Frankfurt workspace ID only.")
print("Alibaba endpoint routing receives region separately and uses the workspace option for Frankfurt host construction.")
print("The original concern about missing alibaba_region is not supported by the endpoint call shape.")
PY

Repository: theopenco/llmgateway

Length of output: 29696


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- selected-region resolver ---'
rg -n -C 18 'function resolveSelectedRegion|export function resolveSelectedRegion|resolveSelectedRegion\(' \
  packages/actions/src apps -g '*.ts' | head -n 220

printf '%s\n' '--- non-validation gateway endpoint calls with region ---'
rg -l 'getProviderEndpoint\(' apps/gateway packages/actions/src -g '*.ts' \
  | while read -r file; do
    if [ "$file" != "packages/actions/src/get-provider-endpoint.ts" ] &&
       [ "$file" != "packages/actions/src/validate-provider-key.ts" ]; then
      echo "--- $file"
      rg -n -A 28 -B 5 'getProviderEndpoint\(' "$file" | head -n 90
    fi
  done

printf '%s\n' '--- focused behavioral verifier ---'
python3 - <<'PY'
from pathlib import Path
import re

helper = Path("apps/gateway/src/chat-helpers.e2e.ts").read_text()
endpoint = Path("packages/actions/src/get-provider-endpoint.ts").read_text()
provider = Path("packages/models/src/providers.ts").read_text()

before_all = helper[helper.index("export async function beforeAllHook"):helper.index("function providerEnvOptionsForTests")]
options_fn = helper[helper.index("function providerEnvOptionsForTests"):helper.index("export async function beforeEachHook")]
create_fn = helper[helper.index("export async function createProviderKey"):helper.index("export function validateResponse")]

checks = {
    "beforeAllHook reads only the base API-key env name": 'const envVarName = getProviderEnvVar(provider.id);' in before_all,
    "beforeAllHook does not read a regional API key": 'getRegionSpecificEnvValue(' not in before_all,
    "Alibaba options include the workspace ID": 'alibaba_workspace_id: workspaceId' in options_fn,
    "Alibaba options omit the region": 'alibaba_region' not in options_fn,
    "createProviderKey persists the options argument": bool(re.search(r'options,', create_fn)),
    "endpoint uses the separately supplied region": 'region?: string' in endpoint,
    "endpoint uses the workspace option": 'providerKeyOptions?.alibaba_workspace_id' in endpoint,
    "Frankfurt has a workspace endpoint": '"eu-frankfurt": `https://${REGION_WORKSPACE_ID_PLACEHOLDER}.eu-central-1.maas.aliyuncs.com`' in provider,
}
for name, ok in checks.items():
    print(f"{'PASS' if ok else 'FAIL'}: {name}")
assert all(checks.values())

def seeded_credential(env):
    # This mirrors beforeAllHook's two relevant assignments.
    token = env.get("LLM_ALIBABA_API_KEY")
    workspace = env.get("LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT")
    options = {"alibaba_workspace_id": workspace} if workspace else None
    return token, options

env = {
    "LLM_ALIBABA_API_KEY": "generic-token",
    "LLM_ALIBABA_API_KEY__EU_FRANKFURT": "frankfurt-token",
    "LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT": "workspace-id",
}
token, options = seeded_credential(env)
assert token == "generic-token"
assert options == {"alibaba_workspace_id": "workspace-id"}
assert "alibaba_region" not in options
print("PASS: regional API-key env is present but is not selected by beforeAllHook.")
print("PASS: Frankfurt routing metadata is supplied through the request region plus workspace option, not alibaba_region.")
PY

Repository: theopenco/llmgateway

Length of output: 17892


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

helper = Path("apps/gateway/src/chat-helpers.e2e.ts").read_text()
endpoint = Path("packages/actions/src/get-provider-endpoint.ts").read_text()
provider = Path("packages/models/src/providers.ts").read_text()
validator = Path("packages/actions/src/validate-provider-key.ts").read_text()

before_all = helper[helper.index("export async function beforeAllHook"):helper.index("function providerEnvOptionsForTests")]
options_fn = helper[helper.index("function providerEnvOptionsForTests"):helper.index("export async function beforeEachHook")]
create_fn = helper[helper.index("export async function createProviderKey"):helper.index("export function validateResponse")]

checks = {
    "beforeAllHook reads the base Alibaba API-key env name": 'const envVarName = getProviderEnvVar(provider.id);' in before_all,
    "beforeAllHook does not read a regional Alibaba API key": 'getRegionSpecificEnvValue(' not in before_all,
    "Alibaba test options include the Frankfurt workspace ID": 'alibaba_workspace_id: workspaceId' in options_fn,
    "Alibaba test options omit alibaba_region": 'alibaba_region' not in options_fn,
    "createProviderKey persists its options argument": bool(re.search(r'options,', create_fn)),
    "request endpoint accepts region separately": 'region?: string' in endpoint,
    "Alibaba endpoint uses the workspace option": 'providerKeyOptions?.alibaba_workspace_id' in endpoint,
    "provider validation resolves alibaba_region from key options": 'regionKey = providerDef?.regionConfig?.optionsKey' in validator,
}
for name, ok in checks.items():
    print(f"{'PASS' if ok else 'FAIL'}: {name}")
assert all(checks.values())

env = {
    "LLM_ALIBABA_API_KEY": "generic-token",
    "LLM_ALIBABA_API_KEY__EU_FRANKFURT": "frankfurt-token",
    "LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT": "workspace-id",
}
# Model the assignments made by beforeAllHook/providerEnvOptionsForTests.
seeded_token = env["LLM_ALIBABA_API_KEY"]
seeded_options = {"alibaba_workspace_id": env["LLM_ALIBABA_WORKSPACE_ID__EU_FRANKFURT"]}
assert seeded_token == "generic-token"
assert seeded_options == {"alibaba_workspace_id": "workspace-id"}
assert "alibaba_region" not in seeded_options
print("PASS: with both keys configured, the seeded Alibaba credential uses the generic token.")
print("PASS: the seeded options contain the Frankfurt workspace but no alibaba_region.")
print("PASS: the endpoint region is a separate request argument; alibaba_region is used by provider-key validation.")
PY

Repository: theopenco/llmgateway

Length of output: 883


Seed the Frankfurt Alibaba credential. beforeAllHook always reads LLM_ALIBABA_API_KEY, so it can combine the generic token with the Frankfurt workspace. Read LLM_ALIBABA_API_KEY__EU_FRANKFURT through getRegionSpecificEnvValue("alibaba", "eu-frankfurt") and persist alibaba_region: "eu-frankfurt" with alibaba_workspace_id. Run the complete filtered E2E suite with TEST_MODELS set to the changed Qwen models.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/gateway/src/chat-helpers.e2e.ts` around lines 1275 - 1285, Update the
Alibaba branch in the credential-seeding helper to read the Frankfurt-specific
value via getRegionSpecificEnvValue("alibaba", "eu-frankfurt") while retaining
the generic LLM_ALIBABA_API_KEY token flow. When the workspace is available,
persist alibaba_region as "eu-frankfurt" together with alibaba_workspace_id;
preserve the undefined result when no workspace is configured.

Source: Coding guidelines

LLM_ALIBABA_REGION had no reader anywhere: the region comes from the
model's `:region` suffix or the credential's own region binding. Declaring
it only rendered a dead text field on the managed-credential form, next to
the workspace id field that does matter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@steebchen
steebchen enabled auto-merge (squash) August 10, 2026 21:35
@steebchen
steebchen merged commit bff2367 into main Aug 10, 2026
12 checks passed
@steebchen
steebchen deleted the port-vila branch August 10, 2026 21:53
steebchen added a commit that referenced this pull request Aug 11, 2026
## Problem

`qwen3.8-max` had no `regions` array at all, so the only reachable
Alibaba endpoint for it was the default Singapore one — even though
Model Studio serves it from every region, including Frankfurt (which
#3525 just wired up). `qwen3.7-flash` was likewise limited to Singapore
and Beijing.

## Change

Both mappings now declare all four regions: `singapore`, `eu-frankfurt`,
`us-virginia`, `cn-beijing`. `qwen3.7-max` and `qwen3.7-plus` already
had all four, so the Qwen 3.7/3.8 line is now uniform.

Availability was established by probing every model in the Alibaba
catalogue against all four regional endpoints with that region's real
key, not from the docs — the OpenAI-compatible `/models` listing is
unreliable here (it omits `qwen3.8-max` in *every* region, including
Singapore where it demonstrably works).

## Pricing

The new region entries inherit the mapping's global (Singapore) prices,
matching how every other unverified Alibaba region entry in the
catalogue is expressed (e.g. `qwen3.7-max:us-virginia`,
`qwen3.7-plus:cn-beijing`). Alibaba's regional list prices are never
*above* the global one, so no entry can bill below cost; the effect is
that cheapest-region routing simply won't prefer these regions over
Singapore until real regional prices are filled in.

## Verification

`pnpm format`, `pnpm build`, and the models/pricing unit specs (304
tests) pass.

Real e2e per region — the seeded BYOK provider key always takes its
token from `LLM_ALIBABA_API_KEY`, so one run can only exercise one
region's credentials; the suite was run four times, each with that
variable pointed at the corresponding regional key:

| region | qwen 3.7/3.8 e2e cases |
| --- | --- |
| `singapore` | 68 passed / 0 failed |
| `eu-frankfurt` | 68 passed / 0 failed |
| `us-virginia` | 68 passed / 0 failed |
| `cn-beijing` | 68 passed / 0 failed |

Each run covers `qwen3.7-max`, `qwen3.7-plus`, `qwen3.7-flash` and
`qwen3.8-max` pinned to that region, across basic completion, streaming,
reasoning (all seven efforts), reasoning + streaming, JSON output, and
tool calls.

The remaining red in those runs is unrelated to this change: six
provider-key registration cases for providers with no local key
(AtlasCloud, AWS Mantle, Azure, Azure AI Foundry, ElevenLabs, Sakana
AI), plus — in the three non-Singapore runs — the two Alibaba
key-registration cases, which validate `LLM_ALIBABA_API_KEY` against the
Singapore host and therefore fail while that variable holds another
region's key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Expanded regional availability for the `qwen3.7-flash` model to
include Singapore, Frankfurt, Virginia, and Beijing.
  * Added support for the same regions to the `qwen3.8-max` model.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants