openclaw - 💡(How to fix) Fix Feature: Inter-session progress streaming for sessions_send (ACP/long-running session support) [1 comments, 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#54895Fetched 2026-04-08 01:34:44
View on GitHub
Comments
1
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
commented ×1

When sessions_send targets a long-running session (e.g. an ACP/Codex binding session), the caller receives a timeout status even though the message was successfully delivered and the target session is actively working. The caller has no visibility into the target session's progress (tool calls, assistant deltas, etc.) until the run completes and the announce flow posts a final summary.

This is a fundamental gap in the inter-session messaging model: it currently only supports send → wait → done, with no send → subscribe → stream progress → done pattern.

Error Message

| lifecycle (end/error) | broadcast("agent") + cleanup | ❌ Caller is not a websocket client |

Root Cause

When sessions_send targets a long-running session (e.g. an ACP/Codex binding session), the caller receives a timeout status even though the message was successfully delivered and the target session is actively working. The caller has no visibility into the target session's progress (tool calls, assistant deltas, etc.) until the run completes and the announce flow posts a final summary.

This is a fundamental gap in the inter-session messaging model: it currently only supports send → wait → done, with no send → subscribe → stream progress → done pattern.

Fix Action

Fix / Workaround

sessions_send dispatches the agent run via callGateway({ method: "agent" }) (succeeds immediately with accepted), then synchronously waits via callGateway({ method: "agent.wait" }) with a default timeout of 30 seconds.

  1. After startAgentRun, subscribe to onAgentEvent for the dispatched runId
  2. On tool:start events, forward a progress message to the caller session's channel via callGateway({ method: "send" })
  3. On lifecycle:end, proceed with the existing final announce

When streamProgress is true:

  1. Dispatch the run as normal
  2. Instead of agent.wait, subscribe to onAgentEvent(runId)
  3. Forward tool events and assistant deltas back to the caller
  4. Return a structured result including progress items and final reply

Code Example

{
  "sessionKey": "...",
  "message": "...",
  "streamProgress": true
}

---

sessions_subscribe(sessionKey, runId, { events: ["tool", "assistant"] })
RAW_BUFFERClick to expand / collapse

Summary

When sessions_send targets a long-running session (e.g. an ACP/Codex binding session), the caller receives a timeout status even though the message was successfully delivered and the target session is actively working. The caller has no visibility into the target session's progress (tool calls, assistant deltas, etc.) until the run completes and the announce flow posts a final summary.

This is a fundamental gap in the inter-session messaging model: it currently only supports send → wait → done, with no send → subscribe → stream progress → done pattern.

Problem

1. Timeout misreports delivery status

sessions_send dispatches the agent run via callGateway({ method: "agent" }) (succeeds immediately with accepted), then synchronously waits via callGateway({ method: "agent.wait" }) with a default timeout of 30 seconds.

For ACP/Codex sessions that routinely take 1–5+ minutes, agent.wait times out. The tool returns { status: "timeout" }, which the caller interprets as failure — even though the message was already delivered and the target session is actively processing.

2. No progress visibility for inter-session runs

The gateway event system routes events as follows:

Event typeRoutingVisible to caller session?
tool (start/end)toolEventRecipients.get(runId) → registered websocket connIds only❌ No registration
assistant (text delta)broadcast("agent") + nodeSendToSession(targetSessionKey)❌ Sent to target session only
lifecycle (end/error)broadcast("agent") + cleanup❌ Caller is not a websocket client
chat (delta/final)broadcast("chat") + nodeSendToSession(targetSessionKey)❌ Sent to target session only

When sessions_send triggers a run, the caller agent uses internal RPC (callGateway), not a websocket connection. There is no connId to register for tool event receipts. All events are routed to the target session's key, never back to the originating caller session.

3. Announce flow is final-only

The startA2AFlow / runSessionsSendA2AFlow path is:

  • Fire-and-forget (not awaited before returning the tool result)
  • Only runs after the target run completes
  • Posts a single final summary to the target channel
  • Does not stream intermediate progress (tool calls, partial results, etc.)

Impact

  • Users sending work to ACP/Codex sessions via sessions_send see timeout and have no way to know the session is actively working
  • No real-time visibility into tool calls, file operations, or other progress
  • Users must manually poll with sessions_history or re-ping the session to discover status
  • Particularly impactful for Telegram topic-bound sessions where the expected UX is live progress updates

Proposed solution

Option A: Event forwarding in announce flow (incremental)

Modify runSessionsSendA2AFlow (or add a parallel progress reporter) to:

  1. After startAgentRun, subscribe to onAgentEvent for the dispatched runId
  2. On tool:start events, forward a progress message to the caller session's channel via callGateway({ method: "send" })
  3. On lifecycle:end, proceed with the existing final announce

This keeps the current architecture intact while adding a progress bridge.

Option B: sessions_send with internalEvents subscription

Allow sessions_send to opt into an event stream:

{
  "sessionKey": "...",
  "message": "...",
  "streamProgress": true
}

When streamProgress is true:

  1. Dispatch the run as normal
  2. Instead of agent.wait, subscribe to onAgentEvent(runId)
  3. Forward tool events and assistant deltas back to the caller
  4. Return a structured result including progress items and final reply

Option C: New sessions_subscribe tool

Add a dedicated tool that lets an agent subscribe to another session's run events:

sessions_subscribe(sessionKey, runId, { events: ["tool", "assistant"] })

This would provide real-time visibility without modifying sessions_send.

Reproduction

  1. Configure an ACP binding session (e.g. Codex via acpx)
  2. From a main agent session (e.g. Telegram topic), use sessions_send to send a task to the ACP session
  3. Observe: sessions_send returns timeout after 30 seconds
  4. The ACP session is actively working (verifiable via sessions_history later)
  5. No progress is visible in the caller session until the ACP run finishes and announce fires

Environment

  • OpenClaw version: latest (2026.3.x)
  • Channel: Telegram (group forum with topic-bound sessions)
  • ACP backend: acpx (Codex)

Relevant code paths

  • createSessionsSendTool — tool entry point, default 30s timeout
  • startAgentRuncallGateway({ method: "agent" }) — 10s dispatch
  • agent.wait handler — races lifecycle + dedupe, returns timeout if neither resolves
  • runSessionsSendA2AFlow — fire-and-forget announce, final-only
  • createAgentEventHandler — event routing, tool events only to registered connIds
  • toolEventRecipients — connId-based registry, no inter-session support

extent analysis

Fix Plan

To address the issue of sessions_send timing out for long-running sessions and lacking visibility into the target session's progress, we will implement Option B: sessions_send with internalEvents subscription. This approach allows the caller to opt into an event stream, providing real-time progress updates.

Steps:

  1. Modify createSessionsSendTool to accept an optional streamProgress parameter:
{
  "sessionKey": "...",
  "message": "...",
  "streamProgress": true
}
  1. Implement event subscription:
if (streamProgress) {
  const runId = await startAgentRun(sessionKey, message);
  const eventHandler = createAgentEventHandler(runId);
  eventHandler.on('tool:start', (event) => {
    // Forward tool event to caller session
    callGateway({ method: "send", sessionKey: callerSessionKey, message: event });
  });
  eventHandler.on('assistant', (event) => {
    // Forward assistant delta to caller session
    callGateway({ method: "send", sessionKey: callerSessionKey, message: event });
  });
  eventHandler.on('lifecycle:end', () => {
    // Return final result to caller
    return { status: 'done', result: '...' };
  });
} else {
  // Existing implementation with default timeout
}
  1. Update callGateway to handle event forwarding:
if (method === 'send' && streamProgress) {
  // Handle event forwarding to caller session
  const callerSessionKey = ...;
  const message = ...;
  // Forward event to caller session
}
  1. Test the implementation with a sample ACP binding session and verify that the caller session receives progress updates in real-time.

Verification

To verify the fix, follow these steps:

  1. Configure an ACP binding session (e.g., Codex via acpx).
  2. From a main agent session (e.g., Telegram topic), use sessions_send with streamProgress set to true.
  3. Observe that the caller session receives progress updates in real-time.
  4. Verify that the final result is returned to the caller session after the target session completes.

Extra Tips

  • Consider adding error handling for cases where the event subscription fails or the target session terminates unexpectedly.
  • You may want to implement a timeout for the event subscription to prevent indefinite waiting.
  • Review the existing createAgentEventHandler and toolEventRecipients implementations to ensure they are compatible with the new event subscription mechanism.

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 - 💡(How to fix) Fix Feature: Inter-session progress streaming for sessions_send (ACP/long-running session support) [1 comments, 1 participants]