Skip to content

fix(providers): honor saved baseUrl for alibaba-token-plan via override + choices#459

Closed
alexanderxcmo wants to merge 1 commit into
lidge-jun:devfrom
alexanderxcmo:fix/alibaba-token-plan-base-url-override
Closed

fix(providers): honor saved baseUrl for alibaba-token-plan via override + choices#459
alexanderxcmo wants to merge 1 commit into
lidge-jun:devfrom
alexanderxcmo:fix/alibaba-token-plan-base-url-override

Conversation

@alexanderxcmo

Copy link
Copy Markdown
Contributor

Fixes #457

Problem

The alibaba-token-plan registry entry (Beijing) lacks allowBaseUrlOverride, so the router silently discards any user-saved baseUrl and forces the Beijing endpoint (router.ts: registry URL wins unless the entry is a template or opts into override).

After the July provider migration merged user configs into the id alibaba-token-plan, configs holding an international (ap-southeast-1) baseUrl are still routed to cn-beijingall requests fail with 401, with no warning that the saved URL was ignored.

Fix

Mirror the existing qwen-cloud pattern:

  • src/providers/base-url-choices.ts: add ALIBABA_TOKEN_PLAN_BEIJING_BASE_URL, ALIBABA_TOKEN_PLAN_INTL_BASE_URL, and ALIBABA_TOKEN_PLAN_BASE_URL_CHOICES (beijing / intl / custom).
  • src/providers/registry.ts: alibaba-token-plan gets allowBaseUrlOverride: true + baseUrlChoices, and uses the Beijing constant (value unchanged).

Default resolution is unchanged when no user baseUrl is set — only configs with a saved URL now have it honored, and the GUI can offer the region choice.

Tests

  • New tests/alibaba-token-plan-endpoints.test.ts mirrors the qwen-cloud endpoint tests (registry shape, presets projection, matchBaseUrlChoice mapping).
  • Updated the override allowlist assertion in tests/provider-registry-parity.test.ts.
  • tsc --noEmit clean, full suite: 3231 pass / 0 fail, privacy scan passed.

Notes

…de + choices

The alibaba-token-plan registry entry (Beijing) lacked allowBaseUrlOverride,
so the router silently discarded any user-saved baseUrl and forced the
Beijing endpoint. Configs migrated to this id with an international
(ap-southeast-1) baseUrl were routed to cn-beijing and failed with 401.

Give the entry allowBaseUrlOverride + baseUrlChoices (beijing default,
intl/Singapore, custom), mirroring the existing qwen-cloud pattern.
Default resolution is unchanged when no user baseUrl is set.

Fixes lidge-jun#457
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dd8b5d09-9d0e-4a25-95a8-e4c76d766e00

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added the bug Something isn't working label Jul 25, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64a8753ef5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/providers/registry.ts
adapter: "openai-chat",
authKind: "key",
allowBaseUrlOverride: true,
baseUrlChoices: ALIBABA_TOKEN_PLAN_BASE_URL_CHOICES,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Separate the international product metadata

When the new intl choice is selected, this entry still projects the Beijing Personal Edition dashboardUrl, note, default/static model list, and liveModels: false. AddProviderModal.tsx uses that dashboard URL unconditionally for setup, while gatherRoutedModels enriches the saved provider from this entry and fetchProviderModels immediately returns its static models when live discovery is disabled. Consequently, a new Singapore/Team configuration is directed to the Beijing console and advertised only the Personal Edition catalog despite routing requests internationally; represent the editions separately or make the dashboard and catalog metadata endpoint-specific.

Useful? React with 👍 / 👎.

Comment thread src/providers/registry.ts
baseUrl: ALIBABA_TOKEN_PLAN_BEIJING_BASE_URL,
adapter: "openai-chat",
authKind: "key",
allowBaseUrlOverride: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Normalize overridden URLs before appending request paths

For a migrated configuration whose saved baseUrl ends in /—a representation the new matching test explicitly accepts—this opt-in makes routedProviderConfig preserve the URL verbatim. The openai-chat adapter then builds ${provider.baseUrl}/chat/completions, producing a path such as /compatible-mode/v1//chat/completions; upstreams that do not normalize double slashes will reject every request. Strip trailing slashes from the accepted override, or join the request path safely, before routing.

Useful? React with 👍 / 👎.

@Wibias
Wibias marked this pull request as draft July 25, 2026 19:48
@snowyukitty

Copy link
Copy Markdown
Contributor

Thanks for chasing this down — the 401 is real, and the router analysis in #457 is spot on. While reading the same code I ran into two bits of history that are easy to miss, and I think they change what this PR should do. Sharing them here rather than in the issue so they're next to the diff.

allowBaseUrlOverride on alibaba-token-plan already shipped once, and was backed out

Author dates are misleading here — the branch was rebased, and a9b9048a carries an author date 25 minutes earlier than the commit it reverts. This ordering is from git merge-base --is-ancestor on dev:

Commit What
9b412d8e cherry-pick of #189 — adds allowBaseUrlOverride: true to alibaba-token-plan
a9b9048a Revert "fix: preserve configured Alibaba Token Plan base URL (#189)"
7e63d2e0 feat: add alibaba-token-plan-intl provider for international token plan

The revert carries no stated reason, but what replaced it is legible in the code: region became a separate registry id. alibaba-token-plan stays pinned to Beijing with no override, and alibaba-token-plan-intl is the entry that carries allowBaseUrlOverride — with ALIBABA_INTL_BASE_URL_CHOICES offering plan type within one region (token-plan / payg / custom), mirroring QWEN_CLOUD_BASE_URL_CHOICES rather than crossing regions.

This PR's beijing / intl / custom set puts both regions back under one id, which is the shape the revert removed. @lidge-jun is the only one who knows whether that revert was deliberate policy or a rollback for an unrelated reason, and the answer decides the whole PR — probably worth a word before investing more in it.

Also worth noting: your own confirmed workaround in #457 — renaming the id to alibaba-token-plan-intl — is exactly what the post-revert design expects.

On the migration: I couldn't find it, and I'd genuinely like to be wrong

The premise that a shipped migration merged user providers into alibaba-token-plan is what makes re-adding the override look necessary, so I tried to confirm it. Searching v2.7.36, v2.7.37, v2.7.38-preview.20260724, v2.7.39, v2.7.40 and dev:

  • no hits for bak-before, provider-rename, alibaba-token-plan-1, or renameProviderId;
  • alibaba appears only in src/providers/registry.ts, src/providers/base-url-choices.ts, src/usage/expected-prices.ts, src/generated/jawcode-model-metadata.ts and gui/src/provider-icons.ts — no id-rewriting code;
  • the only config-backup names this codebase can produce are <config>.pre-openai-tiers-v2.bak, <config>.pre-openai-tiers-v1-rollback.<ts>.bak and <config>.invalid-<iso>, none of which match .bak-before-<name>-<timestamp>.

You clearly saw that file, so the likeliest explanation is that I'm searching for the wrong thing. If you still have config.json.bak-before-alibaba-provider-rename-* on disk, its mtime and the ocx version that wrote it would settle this in a minute.

The part that seems unambiguous either way

Independent of how region ends up being modelled: src/router.ts:162 discards a saved, well-formed baseUrl with no diagnostic at all, so the only thing a user ever sees is a 401 from an endpoint they never configured. That's your suggested fix 2, which you deliberately kept out of this PR — and I think you were right to, because it's design-neutral: it holds for every pinned registry entry, whichever way the Alibaba question goes. There's a precedent for the shape at src/config.ts:714, where an invalid streamMode warns before falling back.

I'm happy to put that up as a small separate PR so it doesn't tangle with the policy question here — but it's your finding and your issue, so just say if you'd rather own it and I'll stay out of the way.

@lidge-jun

Copy link
Copy Markdown
Owner

🔒 Under maintainer review — detailed feedback incoming

@lidge-jun (maintainer) has this PR in an active review pass. Please do not merge, rebase, or
close it
until the detailed review lands; a full comment with specific file:line findings,
failure modes, and suggested fixes is being prepared.

This is a claim marker so two maintainers do not review or land the same PR at once. If you are a
maintainer and need this PR urgently, please reply here first instead of merging.

Baseline for this pass: dev is at bef0dfbe (yesterday's integration batch ebc62d1f plus
#458, #456, #391, #392, #463, #465). If this PR touches the same files, the upcoming review will
name the exact overlapping paths so you only have to rebase once.

No action needed from you until then. Thanks for the contribution and for your patience.

Review tracker: devlog/_plan/260726_pr_review_pass · marker posted by the maintainer review pass

@lidge-jun

Copy link
Copy Markdown
Owner

Thanks for chasing down the Alibaba endpoint problem. The underlying complaint is legitimate, but the approach here conflicts with a design decision that has since landed on dev, so this needs a rework rather than a rebase.

High — this restores a single-provider cross-region model that current dev deliberately replaced. The PR adds allowBaseUrlOverride and an international choice to the Beijing entry (src/providers/registry.ts:691-703, src/providers/base-url-choices.ts:24-39). Current dev at src/providers/registry.ts:813-875 instead gives the international Team Edition its own alibaba-token-plan-intl provider with its own model list, modality map, context windows, and reasoning metadata.

The concrete failure: a user picks the Singapore URL through your intl choice but keeps provider id alibaba-token-plan. Requests then go to the international endpoint while routing and catalog metadata still describe Beijing Personal Edition — its dashboard link, its note, its default model, its model and capability maps. A URL override cannot carry all of those contracts across, so the user gets a working endpoint attached to wrong metadata.

If stale configuration is the real bug you're solving, the right shape is an explicit migration: detect a recognized Singapore URL saved under alibaba-token-plan and move it to alibaba-token-plan-intl, preserving credentials and user-owned fields, idempotently.

Medium — the tests don't exercise the behavior in the title. tests/alibaba-token-plan-endpoints.test.ts:11-34 checks constants, preset projection, and matchBaseUrlChoice, but never calls routeModel. It would not catch a failure to honor the saved URL, nor the endpoint/metadata mismatch above.

Exact conflicts against dev bef0dfbe (merge base 3cc1b6f7):

CONFLICT (content): src/providers/base-url-choices.ts
CONFLICT (content): src/providers/registry.ts
CONFLICT (content): tests/provider-registry-parity.test.ts

All three are semantic, not textual noise: dev added ALIBABA_INTL_* choices scoped to the international provider, registered alibaba-token-plan-intl, and expects that id in the override allowlist; this PR puts the Beijing provider in each of those positions instead.

Rebase instruction:

git fetch origin
git rebase origin/dev

When resolving, please keep the current ALIBABA_INTL_* constants and the token-plan / payg / custom choices, keep alibaba-token-plan pinned to Beijing, keep alibaba-token-plan-intl as the override-capable provider, and keep alibaba-token-plan-intl (not Beijing) in the parity allowlist. Then replace the current test with migration plus end-to-end routing coverage if stale configs still need repair.

Also relevant: #464 adds a warning for exactly this situation — a pinned provider discarding a configured baseUrl — and documents the Beijing/international split as the resolution. If this PR landed as written, that warning would stop firing for alibaba-token-plan and its documentation would become false. My recommendation is that #464 lands first and this one is reframed as a migration.

Test gap: no routeModel assertion, no stale-config migration test, no proof that a Singapore endpoint receives the international provider's model and capability metadata. The conflicting head also hasn't run full cross-platform CI against current dev.


Reviewed as part of a maintainer review pass against dev at bef0dfbe, at head 64a8753e. All four changed files reviewed.

@lidge-jun

Copy link
Copy Markdown
Owner

Closing this without merging. The bug you reported is real — a saved baseUrl being silently discarded and turning into a 401 is genuinely bad, and #464 exists because of your report. But this particular fix can't land as written, and I want to be specific about why rather than leave you guessing.

Current dev deliberately models Beijing and International as separate providers. alibaba-token-plan is pinned to the Beijing Personal Edition, while alibaba-token-plan-intl owns the Singapore/international endpoints with its own model list, modality map, context windows, and reasoning metadata. Adding allowBaseUrlOverride to the Beijing entry collapses that split back together: you'd get the international endpoint while routing and the catalog still describe the provider as Beijing Personal Edition — its dashboard link, its note, its default model, its capability maps. A URL override can't carry those contracts across, so the result is a working endpoint wearing the wrong identity. Worse, that provider's API key would then be sendable to whatever destination happens to be saved.

The PR is also stale against dev now, with semantic conflicts in src/providers/base-url-choices.ts, src/providers/registry.ts, and tests/provider-registry-parity.test.tsdev added ALIBABA_INTL_* choices scoped to the international provider and expects that id in the override allowlist, where this PR puts Beijing in each of those positions.

On the underlying problem. If the real issue is that an unattended rename or merge left your config pointing alibaba-token-plan at a Singapore URL, that deserves a fix — but it's a migration, not an override flag. A safe one has to move the API key, defaultProvider, routed model references, disabledModels, providerContextCaps, and any key pools atomically, and decide what happens when an alibaba-token-plan-intl entry already exists. I looked for the rename path described in #457 (config.json.bak-before-alibaba-provider-rename-*) and it isn't in this repository, so I can't write that migration responsibly without knowing what produced those backups.

Issue #457 stays open. This PR's body says Fixes #457, but closing this must not close the issue — the underlying recovery path is still unresolved and worth tracking. In the meantime, #464 adds the diagnostic so a discarded baseUrl produces a named warning instead of a bare 401, which at least turns your silent failure into a visible one.

If you can share what performed the rename — a version, a command, or the backup file's contents with credentials stripped — that would move #457 forward considerably. Thanks for reporting it; the silent-discard behavior was worth surfacing.


Reviewed as part of a maintainer PABCD pass against dev. Plan unit: devlog/_plan/260726_pr_close_rework/090_wp9_security_hold_and_close_459.md.

@lidge-jun lidge-jun closed this Jul 26, 2026
lidge-jun added a commit that referenced this pull request Jul 26, 2026
통합(dev push 완료): #437 803807a, #460 74ddd96, #431 82a47db,
#405 be16c1d, #468 후속 테스트 bcaf029.

close: 통합 4건 + 통합 없이 1건(#459, 설계 충돌). #457은 OPEN 유지.
이슈 close 0건 — dev에서 고쳐졌는데 안 닫힌 이슈가 없었다.

무효화: WP4(#466)와 WP6(#467)은 동료가 직접 머지했고, 우리 분석이
지적한 결함을 동료 커밋이 같은 방향으로 해소했다.

보안 보류 5건에 신규 발견 게시: #429 재분류, #355 OAuth 토큰 목적지,
#424 유료 브리지 기본 ON, #408 설치 락 해제, #403 4분할 요청.

A-gate는 사이클마다 3~5라운드를 돌았다. 반복된 원인은 계획서에
테스트나 코드를 적으면서 실물 소스를 확인하지 않은 것이었다.
lidge-jun added a commit that referenced this pull request Jul 26, 2026
… at diff level

Two issues reproduce against current dev and get implementation phases; the
rest are recorded with why they are not code fixes this unit can close.

The roadmap went through six adversarial audit rounds before any code, and two
findings changed the shape of the work rather than its details:

- #477's suggested fix (delete the early return in writeJournal) would snapshot
  an already-injected config as the user's original, making opencodex routing
  survive 'ocx stop'. The guard is load-bearing; ownership is now checked from
  the bytes being journaled instead of trusted from the caller.
- #457's obvious fix (allowBaseUrlOverride on the Beijing entry) shipped once,
  was reverted twice, and was refused again when PR #459 closed on 2026-07-26.
  Beijing and International are deliberately separate providers, so the repair
  is a config migration, not an override flag.

The migration is split: the provider-id reference rewriter is its own phase,
because a missed reference silently orphans a setting or invalidates a combo
target, which makes loadConfig discard the whole config.

Also recorded: an integrity rule added under audit pressure would have thrown
out of startServer and refused to boot the proxy after a legitimate config
edit. It was removed in favour of copy-verify-link publication.
lidge-jun added a commit that referenced this pull request Jul 26, 2026
Closes #457.

A provider rename left users with `alibaba-token-plan` holding an international
(ap-southeast-1) endpoint. That entry is pinned to cn-beijing and takes no
baseUrl override, so the router discards the saved URL and sends an
international key to Beijing: 401 on every request. #464 made the discard
visible; this makes it recoverable.

The obvious fix is not available. Giving the Beijing entry
`allowBaseUrlOverride` shipped once, was backed out twice, and was refused again
when PR #459 closed on 2026-07-26: `alibaba-token-plan` and
`alibaba-token-plan-intl` are deliberately separate products with different
model lists, context windows, modality maps and dashboards. A URL override
carries none of that, so the endpoint would work while the catalog described the
wrong product — and the provider's key would become sendable to whatever
destination happened to be saved. The maintainer named the right shape when
closing that PR: a migration, not a flag.

So the entry moves to the id whose registry entry actually serves its endpoint.
The destination is built with `providerConfigSeed`, the same function
`ocx provider add` uses, so the migrated row is indistinguishable from one
created against the international provider directly; only credentials and
genuinely user-owned fields are overlaid. A user-chosen `defaultModel` survives
only if the destination can serve it.

Every reference to the old id is re-pointed through `rewriteProviderReferences`.
The migration refuses rather than guesses in two cases: when the destination
provider row already exists, and when the rewrite reports an occupied
destination key. Merging two credential sets or two context caps is a user
decision.

A pre-migration snapshot is taken first. Relying on the OpenAI tier backup was
considered and rejected: it only writes when its own projection changes, which
is not the common path, so a config already at tier v2 would migrate with no
rollback point at all. The snapshot is copy-verify-link — exclusive creation
alone would let a crash mid-copy leave a truncated file that the next run
accepts as valid. An existing snapshot is reused as-is rather than validated
against the current config: that check would refuse to boot the proxy after a
legitimate edit following an aborted run, and a safety net must not become the
thing that stops the product.

Fail-closed on a backup write failure: no rollback point, no credential rewrite.

15 tests across three files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants