openclaw - ✅(Solved) Fix Control UI model switch misparses aliases like gpt-5.4 as anthropic/* [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#57917Fetched 2026-04-08 01:56:09
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Timeline (top)
cross-referenced ×1referenced ×1

Error Message

In the Control UI, manually switching models with a short alias/name like gpt-5.4 can get misparsed as if it belongs to the current/default provider. Example error shown in UI:

Root Cause

Likely Root Cause

Fix Action

Fixed

PR fix notes

PR #57966: fix: improve model alias resolution robustness and error messages

Description (problem / solution / changelog)

  • Normalize spaces and underscores to hyphens in alias key lookup
  • Add provider inference fallback from configured allowlist
  • Include available aliases hint in 'model not allowed' errors
  • Sanitize log output for inferred provider/model values
  • Add 7 new test cases covering alias normalization, cross-provider resolution, provider inference, and error message formatting

Closes #57917

Summary

  • Problem: When users type /model gpt-5.4 to switch to a model configured with alias gpt-5.4 (pointing to openai-codex/gpt-5.4), the system fails with model not allowed: anthropic/gpt 5.4 because normalizeAliasKey only applied trim().toLowerCase(), causing alias lookup to fail silently and fall back to the wrong default provider.
  • Why it matters: Users with valid model aliases configured cannot switch models via Control UI when their input contains minor formatting variations (spaces, underscores), and the error message provides no guidance on how to fix it.
  • What changed: (1) normalizeAliasKey now normalizes spaces/underscores to hyphens. (2) resolveAllowedModelRef tries provider inference from the configured allowlist before rejecting. (3) Error messages list available aliases. (4) New log line uses sanitizeForLog().
  • What did NOT change (scope boundary): No changes to parseModelRef, buildAllowedModelSet, resolveConfiguredModelRef, provider normalization, or any other model resolution paths. Alias storage format in config is unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #57917
  • Related #
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

  • Root cause: normalizeAliasKey was implemented with only trim().toLowerCase(), which is insufficient for fuzzy matching user input containing spaces or underscores. When alias lookup fails, resolveModelRefFromString silently falls back to prepending defaultProvider, producing an incorrect model ref.
  • Missing detection / guardrail: No test coverage for alias lookup with input variations (spaces, underscores). No fallback to provider inference from the allowlist when alias lookup misses.
  • Prior context: The original normalizeAliasKey was designed for exact-match alias resolution and did not anticipate UI input variations where spaces or underscores substitute for hyphens.
  • Why this regressed now: Not a regression per se — the limitation existed since alias support was added, but became user-visible as more cross-provider alias configurations were adopted.
  • If unknown, what was ruled out: N/A

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/model-selection.test.ts
  • Scenario the test should lock in: (1) Alias lookup with spaces/underscores in input resolves to the correct cross-provider model. (2) Bare model name without alias infers the unique provider from the allowlist. (3) Error messages include available aliases.
  • Why this is the smallest reliable guardrail: Unit tests on resolveAllowedModelRef and resolveModelRefFromString directly exercise the three changed code paths without requiring integration setup.
  • Existing test that already covers this (if any): None — prior tests only covered exact alias matches.
  • If no new test is added, why not: 7 new tests were added.

User-visible / Behavior Changes

  • /model gpt 5.4, /model gpt_5.4, and /model gpt-5.4 now all resolve to the same alias target.
  • When a bare model name uniquely matches a single provider in the allowlist, the correct provider is inferred automatically instead of defaulting to anthropic.
  • "model not allowed" errors now show (available aliases: gpt-5.4, sonnet) to help users self-correct.

Diagram (if applicable)

Before:
[user: /model gpt-5.4] -> normalizeAliasKey("gpt-5.4") = "gpt-5.4"
  -> alias miss (key was "gpt-5.4", matches)... BUT:
[user: /model gpt 5.4] -> normalizeAliasKey("gpt 5.4") = "gpt 5.4"
  -> alias miss -> fallback to anthropic/gpt 5.4 -> "model not allowed: anthropic/gpt 5.4"

After:
[user: /model gpt 5.4] -> normalizeAliasKey("gpt 5.4") = "gpt-5.4"
  -> alias hit -> openai-codex/gpt-5.4 ✓

[user: /model gpt-5.4 (no alias configured)]
  -> alias miss -> inferUniqueProvider -> openai-codex/gpt-5.4 ✓

[user: /model nonexistent]
  -> "model not allowed: anthropic/nonexistent (available aliases: gpt-5.4, sonnet)"

## Changed files

- `src/agents/model-selection.test.ts` (modified, +414/-0)
- `src/agents/model-selection.ts` (modified, +103/-5)
RAW_BUFFERClick to expand / collapse

Bug Description

In the Control UI, manually switching models with a short alias/name like gpt-5.4 can get misparsed as if it belongs to the current/default provider. Example error shown in UI:

Failed to set model: GatewayRequestError: model not allowed: anthropic/gpt 5.4

The backend model switch works correctly when called directly, and aliases are configured correctly in agents.defaults.models.

Expected Behavior

If the user enters gpt-5.4, the UI/runtime should resolve it to the configured alias target:

openai-codex/gpt-5.4

It should not prepend the current provider (anthropic/).

Actual Behavior

The Control UI appears to send or normalize the input in a way that causes fallback to the current/default provider, producing:

anthropic/gpt 5.4

That model is invalid, so the switch fails.

What Works

  • Direct backend switch to gpt-5.4 works
  • Full model id openai-codex/gpt-5.4 should be expected to work
  • Alias catalog entry exists and works from backend side

Likely Root Cause

The parser path used by the Control UI appears to be using a raw/display string that does not exactly match the configured alias, so runtime falls back to the current/default provider.

From runtime behavior:

  • exact alias match => correct resolution
  • no alias match => interpret as model under default/current provider

That matches the observed failure (anthropic/gpt 5.4).

Environment

  • OpenClaw: 2026.3.28
  • Gateway/UI in local control UI mode
  • Config includes alias:
    • openai-codex/gpt-5.4: { alias: "gpt-5.4" }

Requested Fix

  • Ensure the Control UI sends the exact alias or resolved provider/model id
  • Or normalize UI-entered model strings against configured aliases before provider defaulting
  • Avoid rewriting alias-like values into <current-provider>/<raw text> unless alias resolution has definitively failed on normalized input

extent analysis

Fix Plan

To resolve the issue, we need to modify the Control UI to correctly handle model aliases. Here are the steps:

  • Update the UI code to normalize user input against configured aliases before sending the request to the backend.
  • Use a function to check if the input matches any alias, and if so, send the resolved provider/model ID instead of the raw input.

Example code snippet:

function resolveModelAlias(input) {
  const aliases = getConfiguredAliases(); // assuming this function returns the alias catalog
  for (const alias in aliases) {
    if (input === aliases[alias].alias) {
      return alias; // return the resolved provider/model ID
    }
  }
  return input; // if no alias match, return the original input
}

// Before sending the request to the backend
const userInput = 'gpt-5.4';
const resolvedModelId = resolveModelAlias(userInput);
if (resolvedModelId !== userInput) {
  // Send the resolved model ID to the backend
  sendRequestToBackend(resolvedModelId);
} else {
  // Handle the case where no alias match is found
  sendRequestToBackend(userInput);
}

Verification

To verify the fix, test the following scenarios:

  • Enter a model alias (e.g., gpt-5.4) in the Control UI and check if it resolves to the correct provider/model ID (openai-codex/gpt-5.4).
  • Enter a full model ID (e.g., openai-codex/gpt-5.4) and check if it works as expected.
  • Enter an invalid model ID or alias and check if the UI handles it correctly.

Extra Tips

  • Make sure to update the alias catalog in the agents.defaults.models configuration to include all the required aliases.
  • Consider adding input validation and error handling to the resolveModelAlias function to handle edge cases.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING