Skip to content

fix(status): use resolved model when raw default references removed provider#39646

Open
gambletan wants to merge 4 commits intoopenclaw:mainfrom
gambletan:fix/stale-default-model-status
Open

fix(status): use resolved model when raw default references removed provider#39646
gambletan wants to merge 4 commits intoopenclaw:mainfrom
gambletan:fix/stale-default-model-status

Conversation

@gambletan
Copy link
Copy Markdown
Contributor

Summary

  • Validate that the provider referenced in the raw default model string exists before using it in status output
  • Fall back to the properly resolved model label when the provider has been removed from config
  • Prevents stale provider/model names from appearing in openclaw status and models status --json

Fixes #38880

Test plan

  • Remove a provider from config, verify openclaw status shows the resolved model
  • Verify models status --json uses resolved model when provider is removed
  • Verify normal operation unchanged when provider exists

Generated with Claude Code

gambletan and others added 4 commits March 7, 2026 23:18
The OPENCLAW_GATEWAY_BIND setting in .env was being ignored because
GATEWAY_BIND was evaluated before the .env file was sourced. This
caused the gateway to always start with --bind loopback regardless
of the user's configuration.

Fix: Move .env sourcing to happen before GATEWAY_BIND evaluation.

Closes openclaw#38810
Issue openclaw#38830

The legacy-param detection incorrectly treats empty strings like
to: '' or channelId: '' as legacy-param usage. Some tool wrappers
populate optional fields with empty-string defaults, causing valid
calls using target to fail.

Changed checks to require non-empty strings:
- typeof params.args.to === 'string' && params.args.to.trim().length > 0
- typeof params.args.channelId === 'string' && params.args.channelId.trim().length > 0
- Add AWS Bedrock 'too many tokens per day' pattern to rate limit detection
- Add 'tokens per day' and 'too many tokens' to failover-matches.ts
- Add patterns to errors.ts, timer.ts, and manager-embedding-ops.ts

Fixes openclaw#38822
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui scripts Repository scripts commands Command implementations agents Agent runtime and tooling size: M labels Mar 8, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 8, 2026

Greptile Summary

This PR bundles several independent fixes: the core change validates that a raw default model's provider still exists in config before using it as the display label in models status --json and openclaw status, preventing stale provider names from leaking through after a provider is removed. It also broadens rate-limit error detection across multiple subsystems ("too many tokens" / "tokens per day"), fixes empty-string channel-target detection, moves .env sourcing earlier in the Podman script so OPENCLAW_GATEWAY_BIND overrides take effect, and adds a slash-command autocomplete dropdown to the chat UI.

Key findings:

  • The provider-validation fix in list.status-command.ts is incomplete in two places: displayDefault (line 402) still interpolates the raw stale provider string for rich terminal output, and rawCandidates (line 231) still passes the unvalidated rawModel to the auth-probe pipeline instead of the validated defaultLabel.
  • The autocomplete dropdown in chat.ts renders an empty styled container when no commands match the current input (e.g. /xyz), producing a visible empty box.
  • The ArrowDown/ArrowUp/Tab keydown handler comments say "let the autocomplete dropdown handle these", but no such handler is wired to the dropdown buttons — keyboard navigation is effectively a no-op stub.
  • The idx map parameter on line 496 of chat.ts is unused.

Confidence Score: 3/5

  • Safe to merge for most subsystems, but the status fix is partially incomplete and the autocomplete has functional gaps.
  • The rate-limit pattern expansions, channel-target fix, embedding-ops retry fix, and shell-script ordering change are all clean and low-risk. The core status fix in list.status-command.ts correctly gates defaultLabel, but leaves displayDefault and rawCandidates using the unvalidated raw value — meaning the PR doesn't fully achieve its stated goal for rich terminal output or auth probing. The autocomplete feature works for mouse-only interaction but has a visible empty-box bug and a misleadingly commented keyboard-navigation stub that does nothing.
  • src/commands/models/list.status-command.ts (incomplete fix for displayDefault and rawCandidates) and ui/src/ui/views/chat.ts (empty dropdown rendering + non-functional keyboard navigation stub)

Comments Outside Diff (2)

  1. src/commands/models/list.status-command.ts, line 401-402 (link)

    Stale provider still visible in rich terminal output

    The displayDefault variable on line 402 still concatenates rawModel directly, meaning that when a provider has been removed from config, openclaw status (non-JSON rich output) will still show something like:

    Default: resolvedProvider/model (from removed-provider/old-model)
    

    This contradicts the PR's stated goal of preventing stale provider/model names from appearing in openclaw status. The same validation logic applied to defaultLabel should be reused here:

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/commands/models/list.status-command.ts
    Line: 401-402
    
    Comment:
    **Stale provider still visible in rich terminal output**
    
    The `displayDefault` variable on line 402 still concatenates `rawModel` directly, meaning that when a provider has been removed from config, `openclaw status` (non-JSON rich output) will still show something like:
    
    ```
    Default: resolvedProvider/model (from removed-provider/old-model)
    ```
    
    This contradicts the PR's stated goal of preventing stale provider/model names from appearing in `openclaw status`. The same validation logic applied to `defaultLabel` should be reused here:
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. src/commands/models/list.status-command.ts, line 230-236 (link)

    Stale provider can still reach probe candidates

    rawCandidates uses rawModel || resolvedLabel directly rather than the newly computed defaultLabel. When a provider has been removed from config, the stale rawModel value is still passed through to resolveModelRefFromString and ends up in modelCandidates for auth probing. This means auth probes could attempt to test a provider that no longer exists in config, potentially producing misleading probe errors.

    Using defaultLabel here keeps the probe candidate list consistent with the display fix:

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/commands/models/list.status-command.ts
    Line: 230-236
    
    Comment:
    **Stale provider can still reach probe candidates**
    
    `rawCandidates` uses `rawModel || resolvedLabel` directly rather than the newly computed `defaultLabel`. When a provider has been removed from config, the stale `rawModel` value is still passed through to `resolveModelRefFromString` and ends up in `modelCandidates` for auth probing. This means auth probes could attempt to test a provider that no longer exists in config, potentially producing misleading probe errors.
    
    Using `defaultLabel` here keeps the probe candidate list consistent with the display fix:
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: b052e24

Comment thread ui/src/ui/views/chat.ts
></textarea>
</label>
${
props.draft.startsWith("/") && props.connected
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.

Empty autocomplete dropdown rendered when no commands match

The autocomplete <div> is rendered whenever props.draft.startsWith("/") && props.connected, regardless of whether getMatchingCommands() returns any results. When the user types something like /xyz, getMatchingCommands returns [], but the styled dropdown container (with border, box-shadow, background) is still mounted — producing a small, empty box above the compose area.

The condition should also check that there are matching commands:

Suggested change
props.draft.startsWith("/") && props.connected
${
props.draft.startsWith("/") && props.connected && getMatchingCommands(props.draft).length > 0
? html`
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/views/chat.ts
Line: 491

Comment:
**Empty autocomplete dropdown rendered when no commands match**

The autocomplete `<div>` is rendered whenever `props.draft.startsWith("/") && props.connected`, regardless of whether `getMatchingCommands()` returns any results. When the user types something like `/xyz`, `getMatchingCommands` returns `[]`, but the styled dropdown container (with `border`, `box-shadow`, `background`) is still mounted — producing a small, empty box above the compose area.

The condition should also check that there are matching commands:

```suggestion
          ${
            props.draft.startsWith("/") && props.connected && getMatchingCommands(props.draft).length > 0
              ? html`
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread ui/src/ui/views/chat.ts
Comment on lines +461 to 463
if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Tab") {
// Let the autocomplete dropdown handle these
return;
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.

Keyboard navigation for autocomplete is not implemented

The comment "Let the autocomplete dropdown handle these" is misleading — the dropdown buttons have no keyboard event listeners and no focused state is tracked. Pressing ArrowDown/ArrowUp simply moves the cursor within the <textarea>, and Tab moves focus away from the compose field entirely without selecting a command.

As-is, the autocomplete is only usable via mouse click. If keyboard navigation is intended (which the comment implies), a selectedIndex state variable and proper focus()/keydown dispatch on the button elements would need to be wired up. If keyboard navigation is intentionally deferred, the comment should reflect that to avoid confusion.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/views/chat.ts
Line: 461-463

Comment:
**Keyboard navigation for autocomplete is not implemented**

The comment "Let the autocomplete dropdown handle these" is misleading — the dropdown buttons have no keyboard event listeners and no focused state is tracked. Pressing ArrowDown/ArrowUp simply moves the cursor within the `<textarea>`, and Tab moves focus away from the compose field entirely without selecting a command.

As-is, the autocomplete is only usable via mouse click. If keyboard navigation is intended (which the comment implies), a `selectedIndex` state variable and proper `focus()`/`keydown` dispatch on the button elements would need to be wired up. If keyboard navigation is intentionally deferred, the comment should reflect that to avoid confusion.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread ui/src/ui/views/chat.ts
Comment on lines +495 to +496
${getMatchingCommands(props.draft).map(
(cmd, idx) => html`
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.

Unused idx parameter in map callback

The idx parameter is declared but never referenced in the template body. This will likely generate a TypeScript/lint warning and can be removed:

Suggested change
${getMatchingCommands(props.draft).map(
(cmd, idx) => html`
${getMatchingCommands(props.draft).map(
(cmd) => html`
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/views/chat.ts
Line: 495-496

Comment:
**Unused `idx` parameter in map callback**

The `idx` parameter is declared but never referenced in the template body. This will likely generate a TypeScript/lint warning and can be removed:

```suggestion
                      ${getMatchingCommands(props.draft).map(
                        (cmd) => html`
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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: b052e246d4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ui/src/ui/views/chat.ts
Comment on lines +500 to +502
@click=${() => {
props.onDraftChange(cmd.usage + " ");
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return focus to composer after slash command selection

Clicking an autocomplete item updates the draft but leaves focus on the clicked <button>, so the next keystrokes no longer go into the message box; this is especially disruptive for /model because users must immediately continue typing an argument. In the current handler there is no focus handoff back to the textarea, so mouse selection breaks the compose flow until users manually re-focus the input.

Useful? React with 👍 / 👎.

@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Apr 24, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 26, 2026

Codex review: needs changes before merge.

Summary
The branch validates the raw default model provider in model status output, expands several rate-limit matchers, treats empty legacy channel targets as absent, moves Podman env-file sourcing earlier, and adds WebChat slash-command autocomplete.

Reproducibility: yes. Source inspection of current main shows a provider-qualified raw default is parsed before configured-provider fallback, then reused by JSON status output, probe candidates, rich terminal output, and the status summary path.

Next step before merge
Queue a focused replacement or repair because the bug is valid, the branch is incomplete and broad, and the implementation boundary is clear.

Security
Needs attention: The diff has no dependency or secret-permission change, but it mixes a gateway bind-behavior change into an unrelated status fix.

Review findings

  • [P2] Use a provider-valid default for every status consumer — src/commands/models/list.status-command.ts:109
  • [P3] Hide the autocomplete when no commands match — ui/src/ui/views/chat.ts:491
  • [P3] Wire the swallowed navigation keys to the menu — ui/src/ui/views/chat.ts:461-463
Review details

Best possible solution:

Create a focused status-model resolver repair that feeds one provider-valid effective default into models status JSON, rich output, auth probes, and the openclaw status summary, with regression coverage and a changelog entry.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection of current main shows a provider-qualified raw default is parsed before configured-provider fallback, then reused by JSON status output, probe candidates, rich terminal output, and the status summary path.

Is this the best way to solve the issue?

No. The PR validates only defaultLabel and falls back to resolvedLabel, which can already be derived from the stale raw default; the narrower maintainable fix is a shared provider-valid effective default for every status consumer.

Full review comments:

  • [P2] Use a provider-valid default for every status consumer — src/commands/models/list.status-command.ts:109
    The new validation only changes defaultLabel, but resolvedLabel is computed before the provider-existence check and can already reflect the removed provider. rawCandidates, rich displayDefault, and the separate status summary resolver also keep consuming raw or stale values, so the PR does not fully prevent removed-provider names from being shown or probed.
    Confidence: 0.93
  • [P3] Hide the autocomplete when no commands match — ui/src/ui/views/chat.ts:491
    The dropdown renders whenever the draft starts with /, even when getMatchingCommands() returns an empty list. Typing an unknown command such as /xyz leaves a visible empty menu above the composer.
    Confidence: 0.88
  • [P3] Wire the swallowed navigation keys to the menu — ui/src/ui/views/chat.ts:461-463
    The key handler returns for ArrowUp, ArrowDown, and Tab with a comment that the dropdown will handle them, but the added dropdown has no selected state or keyboard handler. Keyboard completion/navigation is therefore non-functional.
    Confidence: 0.84
  • [P3] Return focus to the composer after command selection — ui/src/ui/views/chat.ts:501-503
    Clicking a command suggestion updates the draft but leaves focus on the clicked button, so users cannot continue typing command arguments from the keyboard until they manually focus the textarea again.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.9

Security concerns:

  • [low] Review the Podman bind change separately — scripts/run-openclaw-podman.sh:77
    Moving .env sourcing before GATEWAY_BIND lets env-file values affect gateway bind behavior in this PR. Because non-loopback binds change network exposure and current main now has a hardened safelisted loader, this should be split or rebased rather than bundled with model status output changes.
    Confidence: 0.78

Acceptance criteria:

  • pnpm test src/commands/models/list.status.test.ts src/commands/status.summary.runtime.test.ts src/commands/status.test.ts
  • pnpm exec oxfmt --check --threads=1 src/commands/models/list.status-command.ts src/commands/models/list.status.test.ts src/commands/status.summary.runtime.ts src/commands/status.summary.runtime.test.ts src/commands/status.test.ts CHANGELOG.md
  • pnpm check:changed in Testbox before handoff

What I checked:

  • Current main still serializes the raw default label: modelsStatusCommand computes defaultLabel as rawModel || resolvedLabel and writes it as defaultModel, so a removed provider in the raw config remains user-visible. (src/commands/models/list.status-command.ts:212, e8d0cf75ea0e)
  • Current main still probes raw candidates: Auth probe candidates start with rawModel || resolvedLabel, so a stale provider-qualified default can still enter probe resolution. (src/commands/models/list.status-command.ts:375, e8d0cf75ea0e)
  • Rich output still includes stale raw source: Rich models status formats resolvedLabel (from rawModel) whenever the labels differ, preserving the stale provider/model text in terminal output. (src/commands/models/list.status-command.ts:548, e8d0cf75ea0e)
  • Status summary parses raw defaults before fallback: resolveConfiguredStatusModelRef parses agents.defaults.model.primary before using configured-provider fallback, so openclaw status can keep resolving the removed provider. (src/commands/status.summary.runtime.ts:69, e8d0cf75ea0e)
  • PR status fix is incomplete: The PR adds validation only around defaultLabel; it does not make the resolved default, auth probe candidates, rich output, or status summary share one provider-valid effective default. (src/commands/models/list.status-command.ts:109, b052e246d4b2)
  • PR bundles unrelated surfaces: The PR changes nine files across Podman launch scripts, agent failover, cron retry classification, outbound channel targets, memory embedding retry policy, model status, and WebChat UI. (b052e246d4b2)

Likely related people:

  • steipete: Most recent and repeated commits in the model status and status summary paths, including model run fallback metadata, plugin-normalization avoidance, selected session model resolution, and provider policy refactors. (role: recent maintainer; confidence: high; commits: db06fcd990ff, ea1a0277d53b, e61eba11e671; files: src/commands/models/list.status-command.ts, src/commands/status.summary.runtime.ts)
  • shakkernerd: Recent model status work reused provider auth lookup maps and aligned auth evidence/display paths in the same command file. (role: adjacent owner; confidence: medium; commits: 6662dcf20992, 4109446c2f54, b4ecc814c5b8; files: src/commands/models/list.status-command.ts)
  • Takhoffman: Recent commits touched the same status/model resolution area by normalizing status summary provider lookup and deduping canonical providers in models status. (role: adjacent owner; confidence: medium; commits: 2877a7d8b2f6, 392c15aa73b2; files: src/commands/status.summary.runtime.ts, src/commands/models/list.status-command.ts)
  • BunsDev: Recent WebChat work includes slash menu accessibility and chat UI fixes, relevant to the autocomplete hunks bundled into this PR. (role: UI adjacent owner; confidence: medium; commits: 20cbc1f21683, 05c9492bff0f, 2810f1219a62; files: ui/src/ui/views/chat.ts)

Remaining risk / open question:

  • The branch is materially stale versus current main; several unrelated hunks overlap areas that now have newer implementations.
  • The Podman env-file bind change affects gateway exposure semantics and should be reviewed separately from the model-status bug.

Codex review notes: model gpt-5.5, reasoning high; reviewed against e8d0cf75ea0e.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: web-ui App: web-ui commands Command implementations scripts Repository scripts size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: openclaw status / openclaw models status --json report stale default model from removed provider

1 participant