Skip to content

fix(agents): surface utility-model narration failures and show the utility model in models status#104770

Merged
steipete merged 7 commits into
mainfrom
claude/status-report-display-issue-be3bf8
Jul 12, 2026
Merged

fix(agents): surface utility-model narration failures and show the utility model in models status#104770
steipete merged 7 commits into
mainfrom
claude/status-report-display-issue-be3bf8

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

Utility-model narration (#103463, #103769) fails silently when its credential is dead. Observed live on the Molty gateway: the primary model rides Codex OAuth, but the derived utility model (openai/gpt-5.6-luna) resolves the openai:api-key auth profile, which held a revoked key. Every narration call 401ed, the narrator disabled itself after 2 consecutive failures, and Discord kept showing the old raw tool lines — with zero operator-visible signal:

  • narrator failures were logVerbose-only, and the log line did not name the agent, model, or auth profile;
  • openclaw models status never mentioned the utility model, so nothing showed that narration depends on a different auth path than the primary.

Fixes #104764.

Why This Change Was Made

A dead utility credential silently degrades the product experience (narrated progress drafts fall back to raw tool lines). The failure needs to be visible at default log levels and the utility model needs to be inspectable in models status, which owns runtime auth visibility (--probe/--check).

User Impact

  • When narration disables after consecutive failures, the gateway now logs one warn per turn: narration disabled after 2 consecutive failures (openai/gpt-5.6-luna via openai:api-key): OpenAI API error (401): … — naming exactly what to repair.
  • openclaw models status shows a Utility model line (explicit config / provider default / disabled) and a utilityModel: { ref, source } field in --json.

Evidence

  • Live root-cause log (Molty gateway, 2026-07-11 22:25Z): progress-narrator: completion failed: OpenAI API error (401): 401 Incorrect API key provided: sk-proj-… repeated per turn while Discord rendered old-style tool lines; details in Utility-model narration fails silently on dead API-key profiles; models status hides the utility model #104764.
  • Testbox (blacksmith, lease tbx_01kx9pjsm0ct72rze4k3ks3zzh, run): pnpm format:check green; pnpm test src/auto-reply/reply/progress-narrator.test.ts src/commands/models/list.status.test.ts → 15 + 34 tests pass, including the new warn assertion and the new utilityModel JSON cases (explicit config and disabled).

Follow-up tracked separately in #104764: models status --probe routes api_key-profile probes through the codex app-server harness, which cannot validate an API key (needs the Codex-contract review gate).

@openclaw-barnacle openclaw-barnacle Bot added commands Command implementations size: S maintainer Maintainer-authored PR labels Jul 11, 2026

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

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5146a2d550

ℹ️ 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 on lines +216 to +217
const { provider, modelId, profileId } = prepared.selection;
utilityModelLabel = `${provider}/${modelId}${profileId ? ` via ${profileId}` : ""}`;

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.

P2 Badge Use resolved auth profile in narration warning

When the utility credential is selected by auth order/last-good rather than an explicit @profile suffix, prepared.selection.profileId is unset even though prepared.auth.profileId names the profile actually used. In that common case (for example the revoked openai:api-key profile described by the fix), the new warn omits the profile operators need to repair, so the default-level signal still does not identify the bad credential.

Useful? React with 👍 / 👎.

Comment on lines +345 to +346
const utilitySetting = readUtilityModelSetting(cfg, workspaceAgentId);
const utilityModelRef = resolveUtilityModelRefForAgent({ cfg, agentId: workspaceAgentId });

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.

P2 Badge Include utility model in auth status checks

This computes and reports utilityModelRef, but the auth/check/probe inputs below are still built only from default, fallback, image, and allowed models. With a primary like anthropic/... and a utility model like openai/..., models status --check will not put OpenAI in missingProvidersInUse and --probe will not target the utility model, so the dead utility credential this output is meant to expose remains outside the diagnostic path.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 11, 2026
@clawsweeper

clawsweeper Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 11, 2026, 8:05 PM ET / July 12, 2026, 00:05 UTC.

Summary
The branch adds default-level narration-disable warnings and extends models status with utility-model display, auth-route diagnostics, deduplicated issues, and probe selection.

PR surface: Source +90, Tests +141. Total +231 across 4 files.

Reproducibility: yes. Current-head source deterministically demonstrates the preparation-disable path, external-profile mismatch, and profile-suffix loss without requiring a speculative runtime state.

Review metrics: none identified.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #104764
Summary: This PR is the active candidate fix for the operator-visibility issue; the OpenAI auth-mode/transport mismatch remains distinct work.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix preparation warning coverage, utility-only external-profile loading, and profile-qualified route evaluation.
  • Post redacted current-head gateway warning and human/JSON models status output.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR supplies pre-fix logs and automated tests but no redacted latest-head gateway warning or terminal models status output showing the improved behavior; after adding proof, update the PR body to trigger review or ask a maintainer for @clawsweeper re-review.

Risk before merge

  • [P1] Merging now can leave preparation-time narration failures invisible and can report the wrong utility credential health for external or explicitly qualified profiles.
  • [P1] No redacted after-fix gateway warning or current-head CLI output demonstrates the changed behavior in a real setup.

Maintainer options:

  1. Fix auth parity before merge (recommended)
    Cover preparation-time warnings, utility-only external-profile loading, and profile-qualified route evaluation, then provide real current-head proof.
  2. Pause for auth-owner review
    Hold the PR if the permanent external-profile or profile-qualified diagnostic semantics require an owner decision.

Next step before merge

  • [P1] The contributor should repair the three concrete defects and add real behavior proof; the protected maintainer label then requires explicit human handling of the refreshed head.

Security
Cleared: No dependency, workflow, permission, secret-storage, or supply-chain regression is introduced; the blockers are auth-diagnostic correctness defects.

Review findings

  • [P2] Warn when preparation disables narration — src/auto-reply/reply/progress-narrator.ts:304-309
  • [P2] Load external profiles for utility-only OpenAI use — src/commands/models/list.status-command.ts:500
  • [P2] Preserve the utility model's auth-profile suffix — src/commands/models/list.status-command.ts:500
Review details

Best possible solution:

Use one canonical utility selection containing provider, model, auth profile, and preparation failure context for runtime warnings, status route analysis, and probes, while keeping the separate transport repair outside this PR.

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

Yes. Current-head source deterministically demonstrates the preparation-disable path, external-profile mismatch, and profile-suffix loss without requiring a speculative runtime state.

Is this the best way to solve the issue?

No. The operator-visibility direction is appropriate, but the current implementation does not yet cover all credential-selection and silent-disable paths central to the report.

Full review comments:

  • [P2] Warn when preparation disables narration — src/auto-reply/reply/progress-narrator.ts:304-309
    prepareNarrationModel still converts missing-auth or invalid-model preparation errors to null, and this branch immediately disables narration. That bypasses the new warning entirely, so this failure mode remains silent; carry the preparation error and available model/profile context into the one-per-turn disable warning.
    Confidence: 0.99
  • [P2] Load external profiles for utility-only OpenAI use — src/commands/models/list.status-command.ts:500
    The external-profile decision checks only the primary and fallbacks. With a non-OpenAI primary and OpenAI utility model, status loads the store without external profiles although runtime utility preparation can use the provider-scoped external Codex profile, causing --check to report missing auth for a working setup.
    Confidence: 0.99
  • [P2] Preserve the utility model's auth-profile suffix — src/commands/models/list.status-command.ts:500
    The utility ref is passed through resolveStatusModelRef, whose shared resolver strips a trailing @profile; status can consequently evaluate a healthy fallback profile while runtime remains locked to the broken explicit profile. Carry the parsed profile into route evaluation. This inline concern was already raised during the current review sequence.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.99

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 7027d2c22728.

Label changes

Label justifications:

  • P2: The PR addresses a bounded but user-visible utility narration diagnostic regression, and the remaining gaps can still hide or misreport failures.
  • merge-risk: 🚨 auth-provider: The changed status path can evaluate a different profile set or credential than utility runtime actually uses.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR supplies pre-fix logs and automated tests but no redacted latest-head gateway warning or terminal models status output showing the improved behavior; after adding proof, update the PR body to trigger review or ask a maintainer for @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +90, Tests +141. Total +231 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 113 23 +90
Tests 2 142 1 +141
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 255 24 +231

What I checked:

  • Preparation failures remain silent: Utility-model preparation errors are reduced to null; the generator immediately disables narration, bypassing the new warning that runs only after consecutive completion failures. (src/auto-reply/reply/progress-narrator.ts:212, 06c64842a81c)
  • Utility-only external profiles are excluded: External OpenAI profile loading is selected from primary and fallback text models only; the utility text model is added afterward, so a non-OpenAI primary with an OpenAI utility model uses the store without external profiles. (src/commands/models/list.status-command.ts:434, 06c64842a81c)
  • Utility profile qualification is discarded: Status sends the utility ref through resolveStatusModelRef, while resolveModelRefFromString explicitly strips the trailing auth profile before returning its model ref; route analysis can therefore evaluate a different credential than runtime. (src/agents/model-selection-shared.ts:732, 7027d2c22728)
  • Codex auth modes are distinct: Sibling Codex source handles API-key auth separately from ChatGPT auth and defines the ChatGPT Codex backend independently, supporting the need for status diagnostics to preserve the actual selected auth mode and profile. (../codex/codex-rs/login/src/auth/manager.rs:256, 4b7e19add003)
  • Feature provenance: Narrated progress drafts and derived utility-model defaults entered current main through the merged feature commits that define the affected runtime and credential path. (src/auto-reply/reply/progress-narrator.ts:161, 26d200c6a303)

Likely related people:

  • steipete: Peter Steinberger authored the merged narrated-progress and derived utility-model changes that define both affected paths. (role: introduced behavior and recent area contributor; confidence: high; commits: 26d200c6a303, 97bbbc2271f8; files: src/auto-reply/reply/progress-narrator.ts, src/agents/utility-model.ts, src/commands/models/list.status-command.ts)
  • compoodment: Recent current-main history in the model-status command includes adjacent model-selection/status maintenance. (role: recent adjacent contributor; confidence: medium; commits: 088a9dc33557; files: src/commands/models/list.status-command.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (3 earlier review cycles)
  • reviewed 2026-07-11T23:21:30.631Z sha 5146a2d :: needs real behavior proof before merge. :: [P2] Use the resolved auth profile in the warning | [P2] Add the utility model to status diagnostics
  • reviewed 2026-07-11T23:34:37.651Z sha 00c4dcb :: needs real behavior proof before merge. :: [P2] Use the resolved auth profile in the warning
  • reviewed 2026-07-11T23:57:25.329Z sha 7aa8749 :: needs real behavior proof before merge. :: [P2] Use the resolved auth profile in the warning | [P2] Warn when model preparation disables narration | [P2] Include utility-only OpenAI use in external profile loading

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

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00c4dcb145

ℹ️ 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 on lines +304 to +308
narratorLog.warn(
`narration disabled after ${consecutiveFailures} consecutive failures` +
(utilityModelLabel ? ` (${utilityModelLabel})` : "") +
(lastFailure ? `: ${lastFailure}` : ""),
);

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.

P2 Badge Warn when preparation disables narration

When the utility model cannot be prepared at all (for example missing auth, an unknown configured utility model, or provider auth setup failure), prepareNarrationModel returns null and the default generator sets disabled = true before a second failure can occur, so this newly added warning never runs. In that failure mode narration still silently falls back to raw tool lines even though the verbose-only preparation error has the exact model/auth detail operators need.

Useful? React with 👍 / 👎.

steipete added 2 commits July 11, 2026 16:33
…ility model in models status

Narration failures were verbose-only, so a dead utility-model credential
silently degraded channel progress drafts back to raw tool lines. The
narrator now warns once per turn when it disables after consecutive
failures, naming the utility model + auth profile, and openclaw models
status renders the resolved utility model (config / provider default /
disabled) in human and JSON output.

Formatting verified remotely via Testbox format:check (hook bypassed:
no node_modules in this worktree).

Fixes #104764
The utility ref was rendered but not registered as a provider use, so
missing utility-provider auth kept --check green (Codex review P2).
Utility completions ride the plain API path like image models.

Formatting verified remotely via Testbox format:check.
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 11, 2026
…viders

main's route analysis reports per-model issues; a same-provider utility
ref duplicated route reports (CI: incompatible-routes test). Shared
providers are already analyzed via their configured uses; utility-only
providers still enter the analysis so they stay visible to status.

Formatting verified remotely via Testbox format:check.
@steipete
steipete force-pushed the claude/status-report-display-issue-be3bf8 branch from 00c4dcb to 380c647 Compare July 11, 2026 23:36

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

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 380c6470d8

ℹ️ 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".

normalizedUtilityProvider &&
!providerUseRefs.some((use) => use.provider === normalizedUtilityProvider)
) {
addProviderUse(utilityModelRef, false);

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.

P2 Badge Include utility OpenAI in external profile loading

When this adds an OpenAI utility model while the primary/fallback text models are non-OpenAI, the auth store has already been selected from textUsesOpenAI using only default/fallbacks, so it is loaded via ensureAuthProfileStoreWithoutExternalProfiles. Runtime utility calls go through prepareSimpleCompletionModelForAgent/getApiKeyForModel, which scopes external CLI discovery to the actual provider, so users with only a Codex/ChatGPT external OpenAI profile can get models status --check reporting missing utility auth even though narration/titles can authenticate.

Useful? React with 👍 / 👎.

Same-provider dedupe hid the documented incident class: an OAuth-healthy
primary says nothing about the utility model's plain API route (Codex
review round 3). The openai route-test fixture now pins utilityModel off
so route tests stay focused on their configured models, and a dedicated
test covers the OAuth-primary/api-key-utility scenario.

Formatting verified remotely via Testbox format:check.
…s status

Uses without codex fallback previously skipped per-model route
resolution (image-auth scoping), so the utility ref never produced
missing-auth route issues. Route scope is now explicit: text uses get
evaluateModelAuth, image uses keep provider-wide availability.

Formatting verified remotely via Testbox format:check.
@clawsweeper clawsweeper Bot removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 11, 2026
…abels

--probe candidates now include the utility ref so utility-only providers
probe the actual configured model instead of an arbitrary catalog entry
(Codex review round 4). Inline comment records that the status resolver
never falls back to the primary, so 'provider default' labels are exact.

Formatting verified remotely via Testbox format:check.

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

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb66ac71e8

ℹ️ 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".

// their own right: an OAuth-healthy primary does not prove the utility's
// plain API path, so the ref gets full route analysis without inheriting
// the primary's codex-runtime fallback.
addProviderUse(utilityModelRef, false, "text");

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.

P2 Badge Preserve utility auth-profile suffixes

When the utility ref is profile-qualified, for example openai/gpt-5.6@openai:revoked, this new status use strips the suffix via resolveStatusModelRef/resolveModelRefFromString before building providerUseRefs, so route/auth analysis can select some other healthy OpenAI profile or env key and report models status --check as OK. Runtime utility completions still pass the suffix as selection.profileId into getApiKeyForModel, which uses that profile directly, so the narrator can keep failing on the bad suffixed credential while the diagnostic added here misses it; carry the parsed profile through as a locked/preferred profile for this utility use.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. labels Jul 11, 2026
…iagnostics

utilityModel accepts aliases, so status now reports the resolved
provider/model instead of the raw alias, and identical route issues from
overlapping primary/utility refs collapse to one entry (Codex round 5).

Formatting verified remotely via Testbox format:check.
@steipete
steipete merged commit 4e4cca2 into main Jul 12, 2026
103 checks passed
@steipete
steipete deleted the claude/status-report-display-issue-be3bf8 branch July 12, 2026 00:08
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

steipete added a commit that referenced this pull request Jul 12, 2026
…facts

discoverModels-time normalization resolves bundled provider policy surfaces;
since #104770 grew that artifact graph, loading it inside the vitest runner
hangs the openai-completions preservation test past its 120s timeout (fails
on plain main). Mock the surface module like model-selection.test.ts already
does so the discovery test stays hermetic.

(cherry picked from commit dbc176eda442be959b069e14ce6d3e93c083593e)
steipete added a commit that referenced this pull request Jul 12, 2026
…facts

discoverModels-time normalization resolves bundled provider policy surfaces;
since #104770 grew that artifact graph, loading it inside the vitest runner
hangs the openai-completions preservation test past its 120s timeout (fails
on plain main). Mock the surface module like model-selection.test.ts already
does so the discovery test stays hermetic.

(cherry picked from commit dbc176eda442be959b069e14ce6d3e93c083593e)
steipete added a commit that referenced this pull request Jul 12, 2026
…facts

discoverModels-time normalization resolves bundled provider policy surfaces;
since #104770 grew that artifact graph, loading it inside the vitest runner
hangs the openai-completions preservation test past its 120s timeout (fails
on plain main). Mock the surface module like model-selection.test.ts already
does so the discovery test stays hermetic.

(cherry picked from commit dbc176eda442be959b069e14ce6d3e93c083593e)
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 12, 2026
…ility model in models status (openclaw#104770)

* fix(agents): surface utility-model narration failures and show the utility model in models status

Narration failures were verbose-only, so a dead utility-model credential
silently degraded channel progress drafts back to raw tool lines. The
narrator now warns once per turn when it disables after consecutive
failures, naming the utility model + auth profile, and openclaw models
status renders the resolved utility model (config / provider default /
disabled) in human and JSON output.

Formatting verified remotely via Testbox format:check (hook bypassed:
no node_modules in this worktree).

Fixes openclaw#104764

* fix(models): include the utility model in models status auth analysis

The utility ref was rendered but not registered as a provider use, so
missing utility-provider auth kept --check green (Codex review P2).
Utility completions ride the plain API path like image models.

Formatting verified remotely via Testbox format:check.

* fix(models): register the utility model only for otherwise-unused providers

main's route analysis reports per-model issues; a same-provider utility
ref duplicated route reports (CI: incompatible-routes test). Shared
providers are already analyzed via their configured uses; utility-only
providers still enter the analysis so they stay visible to status.

Formatting verified remotely via Testbox format:check.

* fix(models): always analyze the utility model route in models status

Same-provider dedupe hid the documented incident class: an OAuth-healthy
primary says nothing about the utility model's plain API route (Codex
review round 3). The openai route-test fixture now pins utilityModel off
so route tests stay focused on their configured models, and a dedicated
test covers the OAuth-primary/api-key-utility scenario.

Formatting verified remotely via Testbox format:check.

* fix(models): give the utility model full text-route analysis in models status

Uses without codex fallback previously skipped per-model route
resolution (image-auth scoping), so the utility ref never produced
missing-auth route issues. Route scope is now explicit: text uses get
evaluateModelAuth, image uses keep provider-wide availability.

Formatting verified remotely via Testbox format:check.

* fix(models): probe the configured utility model and document source labels

--probe candidates now include the utility ref so utility-only providers
probe the actual configured model instead of an arbitrary catalog entry
(Codex review round 4). Inline comment records that the status resolver
never falls back to the primary, so 'provider default' labels are exact.

Formatting verified remotely via Testbox format:check.

* fix(models): canonicalize the reported utility ref and dedupe route diagnostics

utilityModel accepts aliases, so status now reports the resolved
provider/model instead of the raw alias, and identical route issues from
overlapping primary/utility refs collapse to one entry (Codex round 5).

Formatting verified remotely via Testbox format:check.
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
… gates (#104837)

* feat(gateway): propagate approvals to ancestor sessions with replay

Squash-rebased #103921 segment onto the native-clients tip on current main.
Session-scoped approval events publish sanitized pending/terminal
transitions to opted-in session audiences, with authoritative pending
replay on stream subscribe and durable-expiry reconciliation through the
owning manager. SessionApprovalEvent/Replay wire types export from the
approvals owner module; Swift models regenerated.

(cherry picked from commit 2d1dcf9747044710111d0c730fc46ba6013a165c)
(cherry picked from commit ccf88efd56b513d07599ffcee997bf0cddaf9adc)
(cherry picked from commit 8eb33f59f00ec9ee4625259b76bd7ae60d2cd480)
(cherry picked from commit c297cbc93c8401e9c79c20f242245a194f5dd236)
(cherry picked from commit 93d68f28601ff37d863da4db009504993a22533a)
(cherry picked from commit d285ccd8b2f212bb57e814107e7709c896e96b7d)
(cherry picked from commit 5c536982231402b1b58d1683794ea9948b32d077)
(cherry picked from commit 1646e5b6dc4dd20de54e10f110a5909be18d7d50)
(cherry picked from commit 35cf1b705b247fb282f4d56ffe74bd2fb238221f)
(cherry picked from commit 4f8ef36)
(cherry picked from commit 74fbdcc99d5fff062d67760a51dba4ee9e84479b)
(cherry picked from commit 222b285502681d2be14b1819798e9ee5555f431e)
(cherry picked from commit b9e744951f676b600e7c5322bfd04b0e99797c07)
(cherry picked from commit 9e904ef)
(cherry picked from commit 678f238)
(cherry picked from commit 72842e5)
(cherry picked from commit be74c25)
(cherry picked from commit 93ba8c4)
(cherry picked from commit 8f23761)

* feat(gateway): fail-closed plugin and tool approval gates

Squash-rebased #103932 segment onto the ancestor-propagation tip on
current main. Plugin node.invoke approvals claim a one-shot allow-once
decision before handing execution authority to the policy, so observation
or retry cannot replay a consumed approval; sibling tool gates bind
approval ids to their originating reviewer identity.

(cherry picked from commit 122df0d75281f572c012b6484ed5daf085d1d577)
(cherry picked from commit f23d8ac240a8dcf2a42c4daaae962263975a0ae8)
(cherry picked from commit 8632fb6436a224dac7a9a9ef0216884530de2c24)
(cherry picked from commit d9fe2dd5c53665e5732f5f3da5ed1907a686ade8)
(cherry picked from commit bb139f2c8aa36ddad70413e1ef79ff491a6f2ecd)
(cherry picked from commit 9b3e056b68ea515c7d4baef269289b6670570480)
(cherry picked from commit b11e66b59a7af1f3b08712de06864aed64d349e4)
(cherry picked from commit a12916ee592d03dfa35e86a2aaede4476a5d4e5d)
(cherry picked from commit d699de840fc8346892b9ae244fe3c3e8c4413032)
(cherry picked from commit 9b7e5a9)
(cherry picked from commit 4b507593f1b2f10b4496984c84a2803b853e5c5e)
(cherry picked from commit 56408a186733c4eeb5aa76bd5907cde7b0cd3d5b)
(cherry picked from commit a4051d6d8353d39d6fa0b5d69c36e06c3cd3e796)
(cherry picked from commit 7682980)
(cherry picked from commit a8b493f)
(cherry picked from commit aceb990)
(cherry picked from commit a29b0e7)
(cherry picked from commit 2e3be08)
(cherry picked from commit c9ae3d7)

* fix: main-gate repairs for the durable-approvals stack

- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 13, 2026
… gates (openclaw#104837)

* feat(gateway): propagate approvals to ancestor sessions with replay

Squash-rebased openclaw#103921 segment onto the native-clients tip on current main.
Session-scoped approval events publish sanitized pending/terminal
transitions to opted-in session audiences, with authoritative pending
replay on stream subscribe and durable-expiry reconciliation through the
owning manager. SessionApprovalEvent/Replay wire types export from the
approvals owner module; Swift models regenerated.

(cherry picked from commit 2d1dcf9747044710111d0c730fc46ba6013a165c)
(cherry picked from commit ccf88efd56b513d07599ffcee997bf0cddaf9adc)
(cherry picked from commit 8eb33f59f00ec9ee4625259b76bd7ae60d2cd480)
(cherry picked from commit c297cbc93c8401e9c79c20f242245a194f5dd236)
(cherry picked from commit 93d68f28601ff37d863da4db009504993a22533a)
(cherry picked from commit d285ccd8b2f212bb57e814107e7709c896e96b7d)
(cherry picked from commit 5c536982231402b1b58d1683794ea9948b32d077)
(cherry picked from commit 1646e5b6dc4dd20de54e10f110a5909be18d7d50)
(cherry picked from commit 35cf1b705b247fb282f4d56ffe74bd2fb238221f)
(cherry picked from commit 4f8ef36)
(cherry picked from commit 74fbdcc99d5fff062d67760a51dba4ee9e84479b)
(cherry picked from commit 222b285502681d2be14b1819798e9ee5555f431e)
(cherry picked from commit b9e744951f676b600e7c5322bfd04b0e99797c07)
(cherry picked from commit 9e904ef)
(cherry picked from commit 678f238)
(cherry picked from commit 72842e5)
(cherry picked from commit be74c25)
(cherry picked from commit 93ba8c4)
(cherry picked from commit 8f23761)

* feat(gateway): fail-closed plugin and tool approval gates

Squash-rebased openclaw#103932 segment onto the ancestor-propagation tip on
current main. Plugin node.invoke approvals claim a one-shot allow-once
decision before handing execution authority to the policy, so observation
or retry cannot replay a consumed approval; sibling tool gates bind
approval ids to their originating reviewer identity.

(cherry picked from commit 122df0d75281f572c012b6484ed5daf085d1d577)
(cherry picked from commit f23d8ac240a8dcf2a42c4daaae962263975a0ae8)
(cherry picked from commit 8632fb6436a224dac7a9a9ef0216884530de2c24)
(cherry picked from commit d9fe2dd5c53665e5732f5f3da5ed1907a686ade8)
(cherry picked from commit bb139f2c8aa36ddad70413e1ef79ff491a6f2ecd)
(cherry picked from commit 9b3e056b68ea515c7d4baef269289b6670570480)
(cherry picked from commit b11e66b59a7af1f3b08712de06864aed64d349e4)
(cherry picked from commit a12916ee592d03dfa35e86a2aaede4476a5d4e5d)
(cherry picked from commit d699de840fc8346892b9ae244fe3c3e8c4413032)
(cherry picked from commit 9b7e5a9)
(cherry picked from commit 4b507593f1b2f10b4496984c84a2803b853e5c5e)
(cherry picked from commit 56408a186733c4eeb5aa76bd5907cde7b0cd3d5b)
(cherry picked from commit a4051d6d8353d39d6fa0b5d69c36e06c3cd3e796)
(cherry picked from commit 7682980)
(cherry picked from commit a8b493f)
(cherry picked from commit aceb990)
(cherry picked from commit a29b0e7)
(cherry picked from commit 2e3be08)
(cherry picked from commit c9ae3d7)

* fix: main-gate repairs for the durable-approvals stack

- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (openclaw#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since openclaw#104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations maintainer Maintainer-authored PR merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Utility-model narration fails silently on dead API-key profiles; models status hides the utility model

1 participant