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

></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 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 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 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 👍 / 👎.

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