Skip to content

fix(auto-reply): preserve session model display for heartbeat usage#82267

Merged
giodl73-repo merged 3 commits into
openclaw:mainfrom
giodl73-repo:fix-heartbeat-preserve-session-model-62954
May 16, 2026
Merged

fix(auto-reply): preserve session model display for heartbeat usage#82267
giodl73-repo merged 3 commits into
openclaw:mainfrom
giodl73-repo:fix-heartbeat-preserve-session-model-62954

Conversation

@giodl73-repo

@giodl73-repo giodl73-repo commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • preserve the stored session model / modelProvider display fields when a heartbeat run persists usage for a different heartbeat model
  • keep heartbeat usage, cache counters, context totals, cost snapshots, system prompt reports, and CLI binding persistence intact
  • thread the existing heartbeat run flag into the shared usage persistence path

Fixes #62954.

Tests

  • CI=1 node scripts/run-vitest.mjs src/auto-reply/reply/session.test.ts src/auto-reply/reply/followup-runner.test.ts
  • pnpm exec oxfmt --check --threads=1 src/auto-reply/reply/session-usage.ts src/auto-reply/reply/session-run-accounting.ts src/auto-reply/reply/agent-runner.ts src/auto-reply/reply/followup-runner.ts src/auto-reply/reply/session.test.ts src/auto-reply/reply/followup-runner.test.ts
  • pnpm check:changed

Real behavior proof

Behavior or issue addressed: heartbeat turns using agents.defaults.heartbeat.model could overwrite a session's persisted display model / modelProvider, making UI/history show the heartbeat model until the next user turn.

Real environment tested: local OpenClaw checkout on Ubuntu 24.04 under WSL, exercising the real session usage persistence path used after agent runs.

Exact steps or command run after this patch: CI=1 node scripts/run-vitest.mjs src/auto-reply/reply/session.test.ts src/auto-reply/reply/followup-runner.test.ts.

Evidence after fix: before/after proof bundle published via Crabbox artifacts:

heartbeat-session-model-display-before-after-proof.png

Observed result after fix: origin/main plus only the new regression spec fails because heartbeat usage overwrites the stored display model; this PR branch passes the same focused shard and preserves model / modelProvider while usage/cache/token fields update.

What was not tested: a live heartbeat tick in the control UI; this PR validates the source-level persistence path that caused the stale UI model.

@openclaw-barnacle openclaw-barnacle Bot added size: S maintainer Maintainer-authored PR labels May 15, 2026
@clawsweeper

clawsweeper Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR threads heartbeat state into auto-reply session usage persistence so heartbeat runs preserve stored session model and modelProvider display fields while usage data still updates.

Reproducibility: yes. Source inspection shows current main receives heartbeat state but persists the heartbeat modelUsed/providerUsed into the fields that display resolution prefers, and the posted before artifact fails the focused regression with the heartbeat model displayed.

Real behavior proof
Needs real behavior proof before merge: The PR body and artifacts show focused Vitest/Crabbox logs and a before/after test screenshot, but no real heartbeat/control UI, chat.history, terminal live output, or runtime log proof after the fix; contributor should add redacted real proof before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, ask a maintainer to comment @clawsweeper re-review.

Next step before merge
Human handling is required because the PR has the protected maintainer label and the external-contributor real behavior proof gate is still mock-only; there is no narrow code defect for an automated repair job.

Security
Cleared: The diff is limited to auto-reply TypeScript persistence code and a focused test, with no concrete security or supply-chain concern found.

Review details

Best possible solution:

Land the narrow heartbeat-aware persistence fix after redacted real runtime proof is added and protected-label handling clears; keep heartbeat cost attribution and CLI binding policy questions separate.

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

Yes. Source inspection shows current main receives heartbeat state but persists the heartbeat modelUsed/providerUsed into the fields that display resolution prefers, and the posted before artifact fails the focused regression with the heartbeat model displayed.

Is this the best way to solve the issue?

Yes for the code shape. Passing the existing heartbeat flag into the shared persistence boundary is the narrow maintainable fix because it preserves display identity only for heartbeat runs while leaving usage, cost, context, and normal model updates unchanged.

Acceptance criteria:

  • CI=1 node scripts/run-vitest.mjs src/auto-reply/reply/session.test.ts src/auto-reply/reply/followup-runner.test.ts
  • pnpm exec oxfmt --check --threads=1 src/auto-reply/reply/session-usage.ts src/auto-reply/reply/session-run-accounting.ts src/auto-reply/reply/agent-runner.ts src/auto-reply/reply/followup-runner.ts src/auto-reply/reply/session.test.ts src/auto-reply/reply/followup-runner.test.ts
  • pnpm check:changed
  • Redacted real heartbeat/control UI, chat.history, terminal live output, or runtime log proof showing the displayed session model stays on the non-heartbeat model after a heartbeat run.

What I checked:

  • Current main persistence gap: persistSessionUsageUpdate on current main accepts runtime model/provider values but no heartbeat discriminator, then writes params.providerUsed and params.modelUsed into the session entry in the usage branch. (src/auto-reply/reply/session-usage.ts:71, 16e5d6692dcc)
  • Model/context-only branch has the same gap: The no-usage model/context update branch also writes the just-used provider/model into modelProvider and model, so the branch would need the same heartbeat preservation rule. (src/auto-reply/reply/session-usage.ts:176, 16e5d6692dcc)
  • Main reply runner knows heartbeat state: runReplyAgent derives isHeartbeat, but the current-main persistRunSessionUsage call passes modelUsed and providerUsed without that state. (src/auto-reply/reply/agent-runner.ts:1099, 16e5d6692dcc)
  • Follow-up runner has the same omission: createFollowupRunner already passes heartbeat state to preflight compaction, but its usage persistence call currently omits opts?.isHeartbeat === true. (src/auto-reply/reply/followup-runner.ts:266, 16e5d6692dcc)
  • Display resolver consumes persisted fields: resolveSessionModelRef returns persisted entry.modelProvider and entry.model before falling back to configured defaults, so polluted persistence changes displayed session identity. (src/gateway/session-utils.ts:1412, 16e5d6692dcc)
  • Existing shipped partial fix confirms intended behavior: Current main already has a separate preserveRuntimeModel path for agent-command heartbeat runs, and the docs/changelog state that heartbeats should preserve the shared session runtime model; this PR addresses the remaining auto-reply usage persistence path. (src/agents/command/session-store.ts:61, 16e5d6692dcc)

Likely related people:

  • @zhangguiping-xydt: Commit 2c272e2 added the heartbeat preserveRuntimeModel behavior for the agent-command session-store path, establishing the same intended preservation behavior this PR extends to auto-reply persistence. (role: adjacent partial-fix author; confidence: high; commits: 2c272e271a3d; files: src/agents/agent-command.ts, src/agents/command/session-store.ts, src/agents/command/session-store.test.ts)
  • @clay-datacurve: Commit 7b61ca1 substantially touched the central session management/dashboard files involved here, including auto-reply usage, main/follow-up runners, and gateway display utilities. (role: session management feature contributor; confidence: medium; commits: 7b61ca1b0615; files: src/auto-reply/reply/session-usage.ts, src/auto-reply/reply/agent-runner.ts, src/auto-reply/reply/followup-runner.ts)
  • @steipete: Current-main blame/log for the central session persistence and display files points through recent Peter Steinberger commits, including the current checkout snapshot around these files. (role: recent area contributor; confidence: medium; commits: b5ba210fd5c6, 16e5d6692dcc; files: src/auto-reply/reply/session-usage.ts, src/auto-reply/reply/agent-runner.ts, src/auto-reply/reply/followup-runner.ts)
  • @MrMiaigi: Commit 47bb5dd changed the same persistSessionUsageUpdate area and tests for cost snapshot semantics, which are intentionally preserved by this PR. (role: adjacent persistence-path contributor; confidence: medium; commits: 47bb5ddece21; files: src/auto-reply/reply/session-usage.ts, src/auto-reply/reply/session.test.ts, src/agents/command/session-store.ts)

Remaining risk / open question:

  • The posted after-fix proof is still focused test/log evidence only; no real heartbeat run, control UI, chat.history, terminal live output, or runtime log shows the fixed behavior after the patch.
  • One GitHub Actions check run was still in progress at inspection time, although the relevant completed checks shown by the API were successful.

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

Re-review progress:

@giodl73-repo

Copy link
Copy Markdown
Contributor Author

OpenClaw QA Artifacts

Summary

Heartbeat session model display proof for PR #82267.

  • Before: origin/main 4e10969 with only the new regression spec fails because heartbeat usage for a different model overwrites the persisted session display model.
  • After: PR branch 9fcafd8 passes the same focused shard and preserves the existing display model while usage/cache/token fields update.
  • Artifact image: heartbeat-session-model-display-before-after-proof.png
  • Logs: before-origin-main-with-regression-test.log, after-pr-82267.log

Evidence

@giodl73-repo giodl73-repo changed the title Preserve session model display for heartbeat usage fix(auto-reply): preserve session model display for heartbeat usage May 15, 2026
@giodl73-repo
giodl73-repo force-pushed the fix-heartbeat-preserve-session-model-62954 branch 9 times, most recently from 00e8977 to 4e85f6d Compare May 16, 2026 14:38
@giodl73-repo
giodl73-repo force-pushed the fix-heartbeat-preserve-session-model-62954 branch from c61c83d to 1420f5f Compare May 16, 2026 15:02
@giodl73-repo
giodl73-repo merged commit 0eca3a9 into openclaw:main May 16, 2026
113 checks passed
galiniliev pushed a commit to galiniliev/openclaw that referenced this pull request May 20, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
galiniliev pushed a commit to galiniliev/openclaw that referenced this pull request May 25, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
qiaokuan1992 pushed a commit to qiaokuan1992/openclaw that referenced this pull request Jun 2, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
…penclaw#82267)

* Preserve session model display for heartbeat usage
* Refresh checks after proof update
* chore: refresh CI after main repairs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Heartbeat turn overwrites session's persisted model/modelProvider, leaving stale model in UI display

1 participant