Skip to content

fix: route embedded tool calls through in-process dispatch (#40237)#394

Open
BingqingLyu wants to merge 2 commits intomainfrom
fork-pr-42497-fix-ws-self-contention-local-dispatch
Open

fix: route embedded tool calls through in-process dispatch (#40237)#394
BingqingLyu wants to merge 2 commits intomainfrom
fork-pr-42497-fix-ws-self-contention-local-dispatch

Conversation

@BingqingLyu
Copy link
Copy Markdown
Owner

@BingqingLyu BingqingLyu commented Apr 27, 2026

Summary

Fixes openclaw#40237 (also resolves openclaw#5703 and openclaw#6508 which were circular-duped shut).

When agent tools like cron.run, cron.list, cron.add are called from within an active LLM session, callGatewayTool opens a new WebSocket connection to the same gateway. Because the gateway's Node.js event loop is busy processing the current LLM turn, the second WS connection sits in queue and times out after 10s.

This PR routes embedded tool calls through the existing in-process dispatch path (dispatchGatewayMethod) when running inside the gateway process, bypassing WS entirely. External CLI tool calls continue to use WS unchanged.

Changes

  • src/gateway/local-dispatch.ts (new): lightweight registry that the gateway server populates at startup. Exposes tryLocalGatewayDispatch which returns a promise when in-process dispatch is available, or undefined when running outside the gateway (e.g. CLI).

  • src/gateway/server-plugins.ts: registers dispatchGatewayMethod as the local dispatcher when setFallbackGatewayContext is called during gateway startup.

  • src/agents/tools/gateway.ts: callGatewayTool now checks tryLocalGatewayDispatch first. If available (inside gateway), dispatches in-process with zero WS overhead. Otherwise falls through to the existing WS path.

How it works

CLI tool call (external):
  callGatewayTool → tryLocalGatewayDispatch returns undefined → WS path (unchanged)

Embedded tool call (inside gateway LLM session):
  callGatewayTool → tryLocalGatewayDispatch returns Promise → dispatchGatewayMethod
    → handleGatewayRequest (in-process, no WS) → immediate response

The dispatchGatewayMethod function already exists and is battle-tested — it's used by plugin subagent runtime for sessions, agent dispatch, etc. This PR simply makes it available to agent tools via the registry pattern.

Test plan

  • Unit tests for local-dispatch.ts (registry behavior, reset, error propagation)
  • Integration tests in gateway.test.ts verifying:
    • Embedded tool calls use in-process dispatch (no WS callGateway mock called)
    • External tool calls fall back to WS when no dispatcher registered
    • undefined params correctly normalized to {}
  • Existing server-plugins.test.ts tests pass (5/5)
  • Type check clean (pnpm tsgo)
  • Lint/format clean (pnpm check)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants