Skip to content

fix(agent): stale replies after queued user turns#90759

Merged
obviyus merged 10 commits into
openclaw:mainfrom
zhangguiping-xydt:feat/issue-76888
Jul 11, 2026
Merged

fix(agent): stale replies after queued user turns#90759
obviyus merged 10 commits into
openclaw:mainfrom
zhangguiping-xydt:feat/issue-76888

Conversation

@zhangguiping-xydt

@zhangguiping-xydt zhangguiping-xydt commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where users in channel-backed embedded-agent sessions could receive a visible reply to an older queued user message after sending a newer active prompt.

Closes #76888

The failure shape is that orphan repair only checked the current session leaf. Real sessions can append non-message metadata entries such as thinking/model snapshots after the orphaned user message before prompt submission, which hid the older user message from repair and left it eligible as an active instruction.

Why This Change Was Made

The embedded runner now looks past trailing non-message metadata that does not contribute LLM content, repairs the older user turn as context-only prompt material, branches away from that orphaned user entry, replays the skipped state entries, and keeps the already-sanitized active session messages for provider submission.

This keeps the fix scoped to the embedded-agent/session/provider boundary. It does not change Discord delivery, queue semantics, provider routing, model selection, public config/schema/protocol, API keys/auth, storage format migrations, or session persistence format. The remaining maintainer-owned decision is whether this preserve-as-context strategy should be canonical versus the alternative candidate in #96533, which uses different stale-prompt semantics.

User Impact

When an active channel prompt follows an orphaned queued user turn, the older turn is preserved only as prior-turn context and the latest active prompt remains the answer target. Users should no longer see the assistant answer the stale queued turn in this session-state shape.

The highest-risk area is embedded-runner session-state/prompt-shape compatibility. The mitigation is focused coverage for the metadata-skipping repair, state replay, label target remap, provider-seam prompt order, and the shared queued-user marker contract. Exact marker wording and final cross-PR session-state semantics remain maintainer review decisions.

Evidence

Current HEAD validation:

Validation `plugin-sdk-dts-after-dangling-label-commit` (pass, exit_code=0):
node scripts/run-tsgo.mjs -p tsconfig.plugin-sdk.dts.json --declaration true

Validation `orphan-repair-label-focused-after-dangling-label-commit` (pass, exit_code=0):
pnpm exec vitest run src/agents/embedded-agent-runner/run/attempt.spawn-workspace.context-engine.test.ts -t "repairs an orphaned user message behind non-message session metadata before the provider|does not abort orphan repair for a dangling trailing label"

Focused result: 2 files passed, 4 tests passed, 144 skipped.

The current focused regressions prove the issue-specific provider-boundary behavior:

olderPrompt = OLD_TURN_76888: answer the orphaned queued turn
latestPrompt = LATEST_TURN_76888: answer only the active channel prompt
provider prompt = queued-context-marker + OLD_TURN_76888 + LATEST_TURN_76888
assistant content = stub-provider-target=LATEST_TURN_76888
branch target = parent-leaf
replayed entries = thinking:high -> model:deepseek/deepseek-chat -> custom:model-snapshot -> label:replayed-custom/model snapshot
dangling trailing label = skipped when original target is absent; orphan repair still branches to parent-leaf and provider receives LATEST_TURN_76888

Reviewer-visible live behavior proof previously recorded for this PR:

Validation `live-orphaned-user-proof-local-provider` (pass, exit_code=0, 232638ms):

[agent/embedded] Merged and removed orphaned user message to prevent consecutive user turns. runId=issue-76888-live-proof sessionId=issue-76888-live-proof trigger=user
runtime=production runEmbeddedAgent
agent_harness=openclaw
channel_metadata=messageChannel:discord messageProvider:discord trigger:user
provider_model=[redacted configured OpenAI-compatible provider]
model_prompt_trace=prompt:before
prompt_trace_count=1
prompt_trace_match_index=0
model_prompt_order=queued-context-marker -> OLD_TURN_76888 -> LATEST_TURN_76888
visible_reply=LATEST_TURN_TARGET_76888
assert_latest_target_present=true
assert_old_target_absent=true
post_run_leaf_role=assistant
payload_count=1

Additional validation already recorded on this PR:

focused-agent-tests-after-orphan-history-filter: pass, 2 Vitest shards passed.
changed-tests-after-orphan-history-filter: pass, changed test selection completed successfully.
plugin-sdk-dts-after-session-entry-alias: pass.
orphan-repair-focused-after-session-entry-alias: pass.

What was not tested: I did not send an actual Discord message through the live Discord transport, and I did not reproduce the original stochastic production stale reply end to end. The live proof used production runEmbeddedAgent with Discord channel metadata, a real JSONL session fixture, and a configured provider; the post-sync current-head follow-up reran the focused embedded-runner/provider-seam regressions and the plugin SDK declaration shard after rebasing onto current main and after the dangling-label replay guard.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 5, 2026
@clawsweeper

clawsweeper Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Codex review: stale review; fresh review needed.

Summary
The latest durable ClawSweeper review was for head 014239a8a19dcefa355c81467c3598b9ea0526f5, but the PR head is now 492dd34deb25a4f6665a15e4eb63d30e5a53c704. Its old verdict and PR readiness labels are no longer current.

Next step
Run or wait for a fresh ClawSweeper review on the current PR head.

Review history (5 earlier review cycles)
  • reviewed 2026-07-01T18:52:17.934Z sha 3d218c6 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-08T07:27:28.490Z sha 3d218c6 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-08T09:13:01.019Z sha 5b3fa1b :: needs maintainer review before merge. :: none
  • reviewed 2026-07-08T09:19:52.811Z sha 5b3fa1b :: needs maintainer review before merge. :: none
  • reviewed 2026-07-11T04:13:37.741Z sha 014239a :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jun 5, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: M and removed size: XS proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 8, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 8, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 8, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 8, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 9, 2026
@clawsweeper clawsweeper Bot added the status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. label Jul 1, 2026

Copy link
Copy Markdown
Contributor

After comparing this with #96533 against the exact #76888 failure shape, I think #90759 is the stronger landing candidate.

The main reason is that #76888 is not only about how an orphaned user leaf is merged once found. The reported root cause is that the orphaned user message can be hidden behind later non-message session metadata, so the runner never repairs the right leaf in the first place. #90759 fixes that at the embedded-runner/session boundary by walking back to the trailing message entry, replaying skipped state entries, and removing the repaired orphan from provider history.

It also includes stronger end-to-end proof: the PR body has redacted production runEmbeddedAgent evidence, and the added tests cover the metadata-hidden orphan path plus replayed state/label behavior.

If maintainers prefer the stale-internal-drop semantics from #96533, that is a valid product decision. But for the exact #76888 reproduction, #90759 looks closer to the root cause and more complete as a fix.

@zhangguiping-xydt zhangguiping-xydt changed the title fix #76888: [Bug]: Queued/orphaned user-message merge can produce stale reply fix(agent): stale replies after queued user turns Jul 8, 2026
@obviyus obviyus self-assigned this Jul 11, 2026
@obviyus
obviyus force-pushed the feat/issue-76888 branch 2 times, most recently from a173364 to 014239a Compare July 11, 2026 04:05
@obviyus

obviyus commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Maintainer follow-up pushed in 014239a.

  • Repairs persisted/active orphan history before context-engine assembly.
  • Uses the same repaired prompt for assembly budgeting and provider submission.
  • Removes content-equality rediscovery.
  • Preserves user-directed inter-session input while dropping stale internal handoffs.
  • Autoreview: clean.

Exact-head CI: 43 jobs green, including build, prod/test types, lint, guards, and all Node test shards. The two QA smoke failures are unrelated packaging failures: this older branch lacks the CHANGELOG.md release section for 2026.7.2.

CI: https://github.com/openclaw/openclaw/actions/runs/29139037364

@obviyus
obviyus force-pushed the feat/issue-76888 branch from 014239a to 492dd34 Compare July 11, 2026 04:19
@clawsweeper clawsweeper Bot removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 11, 2026
@obviyus

obviyus commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Landed via squash onto main.

The two QA smoke failures were unrelated release packaging checks: the branch lacked the release-owned CHANGELOG.md section for 2026.7.2.

@obviyus
obviyus merged commit e009a41 into openclaw:main Jul 11, 2026
101 of 107 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 11, 2026
…0759)

* fix(agent): keep orphaned user turns contextual
* test(agent): prove orphan repair targets active prompt
* fix(agent): repair orphaned user behind session metadata
* fix(agent): satisfy orphan repair CI types
* fix(agent): preserve orphan repair state entries
* fix(agent): filter repaired orphan from assembled history
* fix(embedded-agent): repair orphan session entry types
* fix(embedded-agent): remap replayed metadata labels
* fix(embedded-agent): skip dangling replay labels
* fix(agents): repair orphan history before assembly

---------

Co-authored-by: 张贵萍0668001030 <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Queued/orphaned user-message merge can produce stale reply

3 participants