openclaw - ✅(Solved) Fix [Bug]: sessions_send misclassifies first agent.wait timeout as hard send failure [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#68065Fetched 2026-04-18 05:54:08
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×3referenced ×2

Error Message

| Run not found / session invisible | error | error (unchanged) | | Hard error (policy deny, invalid params) | error | error (unchanged) |

Root Cause

In src/agents/tools/sessions-send-tool.ts, the timeout path immediately returns { status: "timeout" } without checking whether the run was actually accepted and whether a reply materialized after the wait window.

Fix Action

Workaround

We're currently running a local patched tarball (2026.4.15-patch.sessions-send.1) with a carry-forward script at scripts/patch-installed-package.py that re-applies the fix after each openclaw update.

PR fix notes

PR #68075: fix(agents): post-timeout compensation in sessions_send (closes #68065)

Description (problem / solution / changelog)

Summary

sessions_send with a non-zero timeoutSeconds misclassified first agent.wait timeout as a hard send failure. When the target session accepted the message and started processing, but the reply was not ready within the wait window, the tool returned status: "timeout" — indistinguishable from actual delivery failure.

This caused false failure noise for subagent dispatch chains, cross-session delegation, and any workflow that relies on sessions_send with a wait timeout.

Changes

src/agents/run-wait.ts: Add compensateAfterWaitTimeout() — after a wait timeout, reads the latest assistant snapshot and checks whether a new reply materialized since the pre-send baseline. Returns { newReply?, accepted, delivery }.

src/agents/tools/sessions-send-tool.ts: Replace the bare status: timeout return with post-timeout compensation:

  • New reply found after timeout `-> status: ok with the reply
  • Run accepted, no reply yet `-> status: accepted
  • Hard timeout (run never accepted) `-> status: timeout (unchanged)

Behavior Contract

ScenarioBeforeAfter
Run accepted, reply ready within timeoutokok
Run accepted, reply NOT ready within timeouttimeoutaccepted
Run accepted, reply arrives just after timeouttimeoutok
Run not found / session invisibleerrorerror
timeoutSeconds = 0 (fire-and-forget)acceptedaccepted

Closes

Closes #68065


Author: WadeY [email protected]

Changed files

  • extensions/memory-core/src/dreaming-narrative.ts (modified, +8/-3)
  • src/agents/pi-embedded-runner/run/incomplete-turn.ts (modified, +2/-1)
  • src/agents/run-wait.ts (modified, +48/-0)
  • src/agents/tools/sessions-send-tool.ts (modified, +29/-0)
  • src/cli/plugins-update-selection.ts (modified, +5/-0)
  • src/logging/subsystem.ts (modified, +2/-2)

PR #68196: fix(agents): post-timeout compensation in sessions_send

Description (problem / solution / changelog)

Fixes #68065

sessions_send with a non-zero timeout previously returned status=timeout whenever the wait window expired, even when the target agent had already accepted the message and produced a reply after the window closed.

Behavior contract

ScenarioBeforeAfter
Reply arrives just after the timeout windowstatus: "timeout"status: "ok" with the late reply
Run accepted but no new reply within windowstatus: "timeout"status: "accepted"
Run truly stalled / not acceptedstatus: "timeout"status: "timeout" (unchanged)
Fire-and-forget (timeoutSeconds: 0)status: "accepted"status: "accepted" (unchanged)

Implementation

Adds compensateAfterWaitTimeout() in src/agents/run-wait.ts that reads the latest assistant reply snapshot after a timeout and checks whether a new reply materialized since the pre-send baseline. The timeout handler in sessions-send-tool.ts now calls this before returning a hard timeout.

Test coverage

  • src/agents/run-wait.test.ts — 3 new tests in a compensateAfterWaitTimeout describe block:
    • new reply found after timeout → returns accepted with reply
    • no new reply but run accepted → returns accepted without reply
    • compensation itself fails → falls back to hard timeout
  • src/agents/tools/sessions.test.ts — 1 new test: fire-and-forget (timeoutSeconds=0) stays on the accepted path without triggering compensation or agent.wait
  • All 42 tests in the targeted test files pass (16 in run-wait, 26 in sessions)

Production provenance

We have been running this fix as a dist-level patch in production. This PR is the source-level equivalent, adapted to the current upstream main branch. Reference third-party implementation: wade-microblueworld/openclaw@bfe3a59

Note on full test suite

The full pnpm test run has 2 pre-existing failures on upstream main that are unrelated to this change (src/plugins/bundle-commands.test.ts, src/commands/gateway-status/helpers.test.ts). All files touched by this PR pass cleanly.

Changed files

  • src/agents/run-wait.test.ts (modified, +84/-0)
  • src/agents/run-wait.ts (modified, +50/-0)
  • src/agents/tools/sessions-send-tool.ts (modified, +26/-0)
  • src/agents/tools/sessions.test.ts (modified, +33/-0)

Code Example

// On first wait timeout, check if the run was accepted and reply exists
const compensation = await compensateAfterWaitTimeout({
  sessionKey,
  runId: result.runId,
  snapshotBefore: snapshotBeforeWait,
});

if (compensation.newReply) {
  return { status: "ok", reply: compensation.newReply, delivery: compensation.delivery };
}
if (compensation.accepted) {
  return { status: "accepted", delivery: { status: "accepted", note: "..." } };
}
// Only then return hard timeout
return { status: "timeout" };
RAW_BUFFERClick to expand / collapse

Problem

sessions_send with non-zero timeoutSeconds misclassifies first agent.wait timeout as a hard send failure. When the target session accepts the message and starts processing, but the reply isn't ready within the wait window, the tool returns status: "timeout" — indistinguishable from actual delivery failure.

This causes false failure noise for subagent dispatch chains, cross-session delegation, and any workflow that relies on sessions_send with a wait timeout.

Root Cause

In src/agents/tools/sessions-send-tool.ts, the timeout path immediately returns { status: "timeout" } without checking whether the run was actually accepted and whether a reply materialized after the wait window.

Proposed Fix

Add post-timeout compensation in sessions-send-tool.ts:

// On first wait timeout, check if the run was accepted and reply exists
const compensation = await compensateAfterWaitTimeout({
  sessionKey,
  runId: result.runId,
  snapshotBefore: snapshotBeforeWait,
});

if (compensation.newReply) {
  return { status: "ok", reply: compensation.newReply, delivery: compensation.delivery };
}
if (compensation.accepted) {
  return { status: "accepted", delivery: { status: "accepted", note: "..." } };
}
// Only then return hard timeout
return { status: "timeout" };

Helper compensateAfterWaitTimeout in src/agents/run-wait.ts:

  • Reads latest assistant reply snapshot
  • Compares with pre-wait snapshot
  • Returns { newReply?, accepted?, delivery }

Behavior Contract

ScenarioBeforeAfter
Run accepted, reply ready within timeoutokok (unchanged)
Run accepted, reply NOT ready within timeouttimeoutaccepted
Run accepted, reply arrives just after timeouttimeoutok
Run not found / session invisibleerrorerror (unchanged)
timeoutSeconds = 0 (fire-and-forget)acceptedaccepted (unchanged)
Hard error (policy deny, invalid params)errorerror (unchanged)

Existing Test Coverage

The fix has been running in our local patched build with 55 source-tree tests passing:

  • src/agents/run-wait.test.ts: 16 tests (including 3 new compensation tests)
  • src/agents/tools/sessions.test.ts: 27 tests (including fire-and-forget regression)
  • src/gateway/server.sessions-send.test.ts: 2 tests
  • src/agents/run-wait.test.ts compensation describe block covers: new reply found, no new reply but run accepted, compensation itself fails (fallback to hard timeout)

Workaround

We're currently running a local patched tarball (2026.4.15-patch.sessions-send.1) with a carry-forward script at scripts/patch-installed-package.py that re-applies the fix after each openclaw update.

extent analysis

TL;DR

Apply the proposed fix in sessions-send-tool.ts to add post-timeout compensation and correctly handle sessions_send with non-zero timeoutSeconds.

Guidance

  • Review the compensateAfterWaitTimeout function in src/agents/run-wait.ts to ensure it correctly reads the latest assistant reply snapshot and compares it with the pre-wait snapshot.
  • Verify that the compensation object is properly handled in sessions-send-tool.ts to return the correct status and reply.
  • Test the fix with the provided test coverage, including the 55 source-tree tests, to ensure the desired behavior contract is met.
  • Consider applying the workaround by running a local patched tarball (2026.4.15-patch.sessions-send.1) and using the scripts/patch-installed-package.py script to re-apply the fix after each openclaw update.

Example

const compensation = await compensateAfterWaitTimeout({
  sessionKey,
  runId: result.runId,
  snapshotBefore: snapshotBeforeWait,
});

if (compensation.newReply) {
  return { status: "ok", reply: compensation.newReply, delivery: compensation.delivery };
}
if (compensation.accepted) {
  return { status: "accepted", delivery: { status: "accepted", note: "..." } };
}

Notes

The proposed fix and test coverage seem comprehensive, but it's essential to thoroughly review and test the changes to ensure they meet the desired behavior contract.

Recommendation

Apply the workaround by running a local patched tarball (2026.4.15-patch.sessions-send.1) and using the scripts/patch-installed-package.py script to re-apply the fix after each openclaw update, as this provides a temporary solution until the fix is officially released.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: sessions_send misclassifies first agent.wait timeout as hard send failure [2 pull requests, 1 participants]