Skip to content

fix #75452: Heartbeat per-turn model override persists after turn completes#75567

Closed
zhangguiping-xydt wants to merge 2 commits intoopenclaw:mainfrom
zhangguiping-xydt:feat/issue-75452-v2
Closed

fix #75452: Heartbeat per-turn model override persists after turn completes#75567
zhangguiping-xydt wants to merge 2 commits intoopenclaw:mainfrom
zhangguiping-xydt:feat/issue-75452-v2

Conversation

@zhangguiping-xydt
Copy link
Copy Markdown
Contributor

Summary

Fixes #75452

Heartbeat turns that use a per-turn model override (e.g., a lightweight ollama model) were persisting that override into the shared session state after the turn completed. Subsequent normal turns would then incorrectly see the heartbeat model instead of the originally configured model.

Changes

  • Add preserveRuntimeModel flag to updateSessionStoreAfterAgentRun that preserves pre-existing model, modelProvider, and contextTokens when set
  • Wire the flag for heartbeat turns (bootstrapContextRunKind === "heartbeat") in agent-command.ts
  • Add 4 test cases covering: normal preserve, missing contextTokens guard, new-session fallback, and default (non-preserve) behavior
  • Update CHANGELOG

Test plan

  • Unit tests pass for session-store.test.ts
  • 4 new test cases cover all preservation edge cases
  • Default behavior unchanged (non-heartbeat turns still overwrite runtime model)

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: M labels May 1, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

Codex review: needs changes before merge.

What this changes:

The PR adds a preserveRuntimeModel option to session-store persistence, wires it for heartbeat runs, adds session-store regression tests, and adds a changelog entry for the heartbeat model override bleed fix.

Required change before merge:

The remaining work is narrow and file-local on the PR branch: repair the preserve branch for model-only session entries and update the changelog line to satisfy the gate.

Security review:

Security review cleared: Cleared: the diff changes session metadata persistence, focused tests, and changelog text only, with no dependency, CI, secret, install, publish, or code-download surface.

Review findings:

  • [P2] Avoid pairing legacy models with the heartbeat provider — src/agents/command/session-store.ts:134-135
  • [P2] Fix the changelog line for PR gates — CHANGELOG.md:20
Review details

Best possible solution:

Land a corrected narrow patch that keeps heartbeat model overrides scoped to heartbeat runs, preserves only valid pre-existing runtime model identity, covers legacy model-only session entries, leaves non-heartbeat persistence unchanged, and satisfies the active changelog gate.

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

Yes. The linked issue gives a concrete config and before/after session_status evidence; current main also reproduces at code level because heartbeat run metadata is unconditionally written back into the shared session entry.

Is this the best way to solve the issue?

No, not as currently written. The preserveRuntimeModel direction is maintainable, but the preserve branch must not pair a preserved model with the heartbeat provider, and the changelog line must pass the repository PR gate.

Full review comments:

  • [P2] Avoid pairing legacy models with the heartbeat provider — src/agents/command/session-store.ts:134-135
    When a stored entry has model but no modelProvider, this branch preserves the old model while falling back to the heartbeat providerUsed. That can persist pairs like ollama/claude-opus-4-6 instead of preserving the legacy model under its existing semantics; add a model-only regression and avoid borrowing the heartbeat provider for preserved models.
    Confidence: 0.9
  • [P2] Fix the changelog line for PR gates — CHANGELOG.md:20
    The added changelog line references only the fixed issue, thanks a different handle, and is inserted above existing Fixes entries. The PR gate requires the current PR reference, Thanks @zhangguiping-xydt, and section-tail placement before this can merge.
    Confidence: 0.96

Overall correctness: patch is incorrect
Overall confidence: 0.88

Acceptance criteria:

  • pnpm test src/agents/command/session-store.test.ts
  • pnpm exec oxfmt --check --threads=1 src/agents/command/session-store.ts src/agents/command/session-store.test.ts CHANGELOG.md
  • pnpm check:changed in Testbox before handoff if promoted

What I checked:

  • Current main persistence path: Current main derives modelUsed and providerUsed from the completed run result and then writes contextTokens plus setSessionRuntimeModel(next, { provider: providerUsed, model: modelUsed }) for every persisted run, with no heartbeat-specific preservation branch. (src/agents/command/session-store.ts:78, e0cc374b07c1)
  • Heartbeat caller on main: The current heartbeat caller only suppresses lastInteractionAt freshness for cron/heartbeat runs; it does not preserve or restore the prior runtime model metadata after a heartbeat turn. (src/agents/agent-command.ts:1158, e0cc374b07c1)
  • PR preserve branch defect: The PR preserve branch uses entry.modelProvider ?? providerUsed with entry.model ?? modelUsed, so a legacy entry with only model can be paired with the heartbeat provider from the just-finished run. (src/agents/command/session-store.ts:134, 13e9461223e0)
  • Model-only entries are valid state: Current session normalization keeps a runtime model even when modelProvider is absent, and merge logic explicitly deletes a stale provider when a model is patched without a provider, so model-only entries need a safe preserve path. (src/config/sessions/types.ts:376, e0cc374b07c1)
  • Changelog gate mismatch: The PR changelog gate requires the added line to reference the current PR, be appended at the section tail, and include Thanks @<contrib>; the PR line references only the fixed issue, thanks @zhang-guiping, and is inserted above existing section entries. (scripts/pr-lib/changelog.sh:177, e0cc374b07c1)
  • Related discussion: The linked issue provides concrete heartbeat-vs-primary model setup and before/after status output; the existing ClawSweeper comment on this PR already flagged the same two narrow blockers.

Likely related people:

  • steipete: Recent commit history and local blame show repeated maintenance of session-store, agent-command, runtime status metadata, session reset behavior, and model/runtime persistence near this path. (role: recent maintainer; confidence: high; commits: e5dc0e6d15ea, 566d2d73a323, 5f81147c4d0c; files: src/agents/command/session-store.ts, src/agents/agent-command.ts, src/config/sessions/types.ts)
  • jalehman: Recent work in agent-command.ts added compaction model fallback handling and preserved fallback metadata, which is adjacent to per-run model metadata and persistence semantics. (role: adjacent owner; confidence: medium; commits: c09884614864; files: src/agents/agent-command.ts)
  • vincentkoc: Recent model runtime normalization work touched provider/runtime selection and status labeling, which overlaps the provider/model identity contract involved in this PR. (role: adjacent owner; confidence: medium; commits: aa27e27f3606; files: src/config/sessions/types.ts, src/agents/agent-command.ts)

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

BunsDev pushed a commit that referenced this pull request May 2, 2026
Fixes #75452.

Heartbeat runs can use a per-turn model override via agents.defaults.heartbeat.model. Before this change, the run metadata was written back to the shared session store, so the next normal turn could inherit the heartbeat provider/model and a smaller context window.

This lands the contributor fix plus maintainer polish:
- preserve existing session runtime model/provider/context metadata when persisting heartbeat turns
- avoid creating invalid provider/model pairs for legacy model-only session entries
- leave empty prior runtime state unset for heartbeat-only turns
- keep normal non-heartbeat runtime persistence unchanged
- add focused regression coverage for the session-store edge cases
- refresh heartbeat docs and changelog attribution

Validation:
- pnpm test src/agents/command/session-store.test.ts src/agents/openclaw-tools.session-status.test.ts
- pnpm exec oxfmt --check --threads=1 src/agents/agent-command.ts src/agents/command/session-store.ts src/agents/command/session-store.test.ts CHANGELOG.md docs/gateway/heartbeat.md
- git diff --check
- GitHub checks on 42a00dc: clean; no active checks and no relevant failures

Duplicate PR #75567 was already closed; #75557 is the canonical fix.
lxe pushed a commit to lxe/openclaw that referenced this pull request May 6, 2026
Fixes openclaw#75452.

Heartbeat runs can use a per-turn model override via agents.defaults.heartbeat.model. Before this change, the run metadata was written back to the shared session store, so the next normal turn could inherit the heartbeat provider/model and a smaller context window.

This lands the contributor fix plus maintainer polish:
- preserve existing session runtime model/provider/context metadata when persisting heartbeat turns
- avoid creating invalid provider/model pairs for legacy model-only session entries
- leave empty prior runtime state unset for heartbeat-only turns
- keep normal non-heartbeat runtime persistence unchanged
- add focused regression coverage for the session-store edge cases
- refresh heartbeat docs and changelog attribution

Validation:
- pnpm test src/agents/command/session-store.test.ts src/agents/openclaw-tools.session-status.test.ts
- pnpm exec oxfmt --check --threads=1 src/agents/agent-command.ts src/agents/command/session-store.ts src/agents/command/session-store.test.ts CHANGELOG.md docs/gateway/heartbeat.md
- git diff --check
- GitHub checks on 42a00dc: clean; no active checks and no relevant failures

Duplicate PR openclaw#75567 was already closed; openclaw#75557 is the canonical fix.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
Fixes openclaw#75452.

Heartbeat runs can use a per-turn model override via agents.defaults.heartbeat.model. Before this change, the run metadata was written back to the shared session store, so the next normal turn could inherit the heartbeat provider/model and a smaller context window.

This lands the contributor fix plus maintainer polish:
- preserve existing session runtime model/provider/context metadata when persisting heartbeat turns
- avoid creating invalid provider/model pairs for legacy model-only session entries
- leave empty prior runtime state unset for heartbeat-only turns
- keep normal non-heartbeat runtime persistence unchanged
- add focused regression coverage for the session-store edge cases
- refresh heartbeat docs and changelog attribution

Validation:
- pnpm test src/agents/command/session-store.test.ts src/agents/openclaw-tools.session-status.test.ts
- pnpm exec oxfmt --check --threads=1 src/agents/agent-command.ts src/agents/command/session-store.ts src/agents/command/session-store.test.ts CHANGELOG.md docs/gateway/heartbeat.md
- git diff --check
- GitHub checks on 42a00dc: clean; no active checks and no relevant failures

Duplicate PR openclaw#75567 was already closed; openclaw#75557 is the canonical fix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Heartbeat per-turn model override persists after turn completes (2026.4.29)

1 participant