openclaw - ✅(Solved) Fix Bug: TUI mid-session model switch passes raw alias instead of resolved model ID [1 pull requests, 1 comments, 2 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#75163Fetched 2026-05-01 05:37:27
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
2
Timeline (top)
commented ×1cross-referenced ×1

When switching models in the OpenClaw TUI (web dashboard), the model selector writes the display alias (e.g. "MoE", "Dense") directly into the session config without resolving it to a canonical model ID. LM Studio then rejects it with HTTP 400: Invalid model identifier. Telegram works fine because each message creates a fresh session routed through the gateway layer, which resolves aliases before hitting the provider.

Root Cause

Summary

When switching models in the OpenClaw TUI (web dashboard), the model selector writes the display alias (e.g. "MoE", "Dense") directly into the session config without resolving it to a canonical model ID. LM Studio then rejects it with HTTP 400: Invalid model identifier. Telegram works fine because each message creates a fresh session routed through the gateway layer, which resolves aliases before hitting the provider.

Fix Action

Fix / Workaround

Root Cause Analysis (Per Qwen 3.6)

The TUI model switcher writes the display name/alias directly into session.model without going through OpenClaw's model resolution layer. Telegram avoids this because each inbound message creates a fresh session that passes through the gateway, which resolves aliases before dispatching to the provider runtime. TUI reuses existing sessions and the mid-session model change bypasses alias resolution entirely.

Severity (Per Qwen 3.6)

Medium — breaks model switching in TUI entirely; Telegram and CLI unaffected. Workaround: use full canonical model IDs (e.g., qwen3.6-27b-claude-opus-reasoning-distill-v2@q4_k_m) instead of aliases in the TUI switcher.

PR fix notes

PR #75198: fix(models): resolve provider-qualified aliases in session switches

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem: Control UI/TUI session model switching could pass a provider-qualified display alias like lmstudio-moe/MoE through sessions.patch, which let the provider receive MoE instead of the canonical local model id.
  • Why it matters: LM Studio and other local providers reject display aliases as invalid model identifiers, breaking user-selected mid-session model switches.
  • What changed: Shared model selection now resolves provider/Alias through the configured alias index when the provider matches the alias target, before existing allowlist/catalog validation and persistence.
  • What did NOT change (scope boundary): No fallback behavior, provider-specific LM Studio logic, Telegram behavior, or broad Control UI state handling changed.

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 #75163
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: resolveModelRefFromString resolved aliases only when the entire raw model string matched a configured alias. Bare MoE resolved, but lmstudio-moe/MoE was parsed as provider lmstudio-moe and model MoE.
  • Missing detection / guardrail: Existing tests covered bare aliases and slash-form aliases, but not provider-qualified display aliases emitted by session/model selection paths.
  • Contributing context (if known): Control UI/TUI session state can combine a server-reported model alias with its provider into provider/Alias, then send that value through sessions.patch.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • 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, src/gateway/sessions- patch.test.ts
    • Scenario the test should lock in: lmstudio-moe/MoE resolves and persists as lmstudio-moe/ qwen3.6-35b-a3b when MoE is configured as that model’s alias.
    • Why this is the smallest reliable guardrail: The resolver test locks the shared canonicalization rule; the Gateway patch test proves the user session persistence boundary stores the canonical override.
    • Existing test that already covers this (if any): Existing tests covered bare aliases and explicit provider/model refs, but not provider-qualified aliases.
    • If no new test is added, why not: N/A

User-visible / Behavior Changes

Users can switch to configured aliased local/provider models from Control UI/TUI without the provider receiving the display alias as the model id.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

  Before:
  [model switch: lmstudio-moe/MoE] -> [sessions.patch stores/parses MoE as model] -> [provider
  rejects invalid model id]

  After:
  [model switch: lmstudio-moe/MoE] -> [shared alias resolver maps to qwen3.6-35b-a3b] ->
  [sessions.patch persists canonical override]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS local dev environment
  • Runtime/container: Node/pnpm workspace
  • Model/provider: LM Studio-style local provider alias (lmstudio-moe/MoE) covered by regression tests
  • Integration/channel (if any): Control UI/TUI session model switching via sessions.patch
  • Relevant config (redacted): agents.defaults.models["lmstudio-moe/qwen3.6-35b-a3b"].alias = "MoE"

Steps

  1. Configure an allowed model with alias MoE for canonical ref lmstudio-moe/qwen3.6-35b-a3b.
  2. Send sessions.patch with model lmstudio-moe/MoE.
  3. Inspect the persisted session override.

Expected

  • Session override persists provider lmstudio-moe and model qwen3.6-35b-a3b.

Actual

  • Before this PR, lmstudio-moe/MoE was treated as direct model MoE, causing an invalid model identifier path.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • pnpm test src/agents/model-selection.test.ts
    • pnpm test src/gateway/sessions-patch.test.ts
    • pnpm test src/agents/model-selection.test.ts src/gateway/sessions-patch.test.ts ui/src/ui/ chat-model-ref.test.ts ui/src/ui/chat-model-select-state.test.ts ui/src/ui/views/ chat.test.ts
    • pnpm exec oxfmt --check --threads=1 src/agents/model-selection-shared.ts src/agents/model-selection.test.ts src/gateway/sessions-patch.test.ts ui/src/ui/chat-model-ref.ts ui/src/ui/chat-model-ref.test.ts ui/src/ui/chat-model-select-state.test.ts
    • pnpm build
    • git diff --check
    • pnpm dlx codex review --base origin/main
  • Edge cases checked: Existing slash-form alias coverage still passes; explicit allowlisted provider/model refs still pass; provider-qualified alias only resolves when the provider matches the alias target.
  • What you did not verify: Live LM Studio server behavior; Testbox pnpm check:changed was blocked because Blacksmith CLI was not authenticated and no BLACKSMITH_ORG was configured.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: A provider/Alias string could be mistaken for a real provider/model ref.
    • Mitigation: The new resolution only applies when the suffix matches a configured alias and the prefix provider matches the alias target provider; otherwise existing parsing and allowlist validation are preserved.

Built with Codex

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/model-selection-shared.ts (modified, +11/-0)
  • src/agents/model-selection.test.ts (modified, +38/-0)
  • src/gateway/sessions-patch.test.ts (modified, +25/-0)

Code Example

HTTP 400: Invalid model identifier "MoE". Please specify a valid downloaded model (e.g., draftthinking_qwen3_4b@q2_k, ...)

---

{ 
  "event": "model_fallback_decision", 
  "requestedProvider": "lmstudio-moe", 
  "requestedModel": "MoE", 
  "candidateProvider": "lmstudio-moe", 
  "candidateModel": "MoE", 
  "reason": "model_not_found", 
  "status": 404, 
  "errorPreview": "400 Invalid model identifier \"MoE\"", 
  "fallbackConfigured": false, 
  "fallbackStepFinalOutcome": "chain_exhausted" 
}
RAW_BUFFERClick to expand / collapse

:label: Labels to add: bug, tui

Bug: TUI mid-session model switch passes raw alias instead of resolved model ID

Summary

When switching models in the OpenClaw TUI (web dashboard), the model selector writes the display alias (e.g. "MoE", "Dense") directly into the session config without resolving it to a canonical model ID. LM Studio then rejects it with HTTP 400: Invalid model identifier. Telegram works fine because each message creates a fresh session routed through the gateway layer, which resolves aliases before hitting the provider.

Expected Behavior

Model switching in TUI should resolve display names/aliases to their canonical IDs (e.g. "MoE""qwen3.6-35b-a3b") before persisting to the session, matching how Telegram creates fresh sessions.

Actual Behavior

TUI writes raw alias strings into the session model field. On next request:

HTTP 400: Invalid model identifier "MoE". Please specify a valid downloaded model (e.g., draftthinking_qwen3_4b@q2_k, ...)

The gateway's model-fallback/decision subsystem sees the failure but has no fallback configured for this path (fallbackConfigured: false), so it fails completely.

Steps to Reproduce

  1. Configure models with aliases in openclaw.json
  2. Open the TUI (web dashboard) and start a session.
  3. Use the model switcher to select an aliased model (e.g., "MoE" or "Dense").
  4. Send a message — observe HTTP 400: Invalid model identifier.

Environment

-OpenClaw version: 2026.4.27 (cbc2ba0) -OS: Linux 6.8.0-110-generic (x64), node v22.22.2 -Gateway mode: local, bind: lan, port 18789 -Provider: LM Studio via OpenAI-compatible API (api: openai-completions) -Primary model alias: lmstudio-moe/qwen3.6-35b-a3b (Qwen 3.6 35B A3B MoE) -Fallback model alias: lmstudio-dense/qwen3.6-27b-claude-opus-reasoning-distill-v2@q4_k_m

Relevant Log Lines

{ 
  "event": "model_fallback_decision", 
  "requestedProvider": "lmstudio-moe", 
  "requestedModel": "MoE", 
  "candidateProvider": "lmstudio-moe", 
  "candidateModel": "MoE", 
  "reason": "model_not_found", 
  "status": 404, 
  "errorPreview": "400 Invalid model identifier \"MoE\"", 
  "fallbackConfigured": false, 
  "fallbackStepFinalOutcome": "chain_exhausted" 
}

Session affected: agent:main:tui-ebe784d0-ca99-4c57-b341-16003430878b (model field set to "MoE").

Root Cause Analysis (Per Qwen 3.6)

The TUI model switcher writes the display name/alias directly into session.model without going through OpenClaw's model resolution layer. Telegram avoids this because each inbound message creates a fresh session that passes through the gateway, which resolves aliases before dispatching to the provider runtime. TUI reuses existing sessions and the mid-session model change bypasses alias resolution entirely.

Suggested Fix (Per Qwen 3.6)

In the TUI model switch handler (likely in the embedded agent or dashboard route), resolve display names/aliases to canonical IDs using the same lookup logic that gateway uses for fresh session creation before persisting to the session store. Alternatively, add a pre-flight resolution step when writing session.model from user input.

Severity (Per Qwen 3.6)

Medium — breaks model switching in TUI entirely; Telegram and CLI unaffected. Workaround: use full canonical model IDs (e.g., qwen3.6-27b-claude-opus-reasoning-distill-v2@q4_k_m) instead of aliases in the TUI switcher.

extent analysis

TL;DR

Resolve display names/aliases to canonical IDs in the TUI model switch handler before persisting to the session store.

Guidance

  • Identify the TUI model switch handler code and modify it to use the same lookup logic as the gateway for fresh session creation to resolve aliases.
  • Add a pre-flight resolution step when writing session.model from user input to ensure canonical IDs are used.
  • Verify that the session.model field is being updated correctly by checking the session store or relevant logs.
  • Test model switching in the TUI with both alias and canonical ID inputs to ensure the fix works as expected.

Example

No code example is provided as the issue does not include specific code snippets, but the fix should involve modifying the TUI model switch handler to resolve aliases using the gateway's lookup logic.

Notes

The fix assumes that the gateway's lookup logic is accessible and can be reused in the TUI model switch handler. If this is not the case, an alternative approach may be needed.

Recommendation

Apply workaround: use full canonical model IDs instead of aliases in the TUI switcher until the root cause is fixed, as this provides a temporary solution to the issue.

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

openclaw - ✅(Solved) Fix Bug: TUI mid-session model switch passes raw alias instead of resolved model ID [1 pull requests, 1 comments, 2 participants]