mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix(agents): await block-reply flush before tool execution starts
handleToolExecutionStart() flushed pending block replies and then called onBlockReplyFlush() as fire-and-forget (`void`). This created a race where fast tool results (especially media on Telegram) could be delivered before the text block that preceded the tool call. Await onBlockReplyFlush() so the block pipeline finishes before tool execution continues, preserving delivery order. Fixes #25267 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
Peter Steinberger
parent
4d124e4a9b
commit
99d854db82
@@ -88,6 +88,37 @@ describe("handleToolExecutionStart read path checks", () => {
|
||||
expect(warn).toHaveBeenCalledTimes(1);
|
||||
expect(String(warn.mock.calls[0]?.[0] ?? "")).toContain("read tool called without path");
|
||||
});
|
||||
|
||||
it("awaits onBlockReplyFlush before continuing tool start processing", async () => {
|
||||
const { ctx, onBlockReplyFlush } = createTestContext();
|
||||
let releaseFlush: (() => void) | undefined;
|
||||
onBlockReplyFlush.mockImplementation(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
releaseFlush = resolve;
|
||||
}),
|
||||
);
|
||||
|
||||
const evt: ToolExecutionStartEvent = {
|
||||
type: "tool_execution_start",
|
||||
toolName: "exec",
|
||||
toolCallId: "tool-await-flush",
|
||||
args: { command: "echo hi" },
|
||||
};
|
||||
|
||||
const pending = handleToolExecutionStart(ctx, evt);
|
||||
// Let the async function reach the awaited flush Promise.
|
||||
await Promise.resolve();
|
||||
|
||||
// If flush isn't awaited, tool metadata would already be recorded here.
|
||||
expect(ctx.state.toolMetaById.has("tool-await-flush")).toBe(false);
|
||||
expect(releaseFlush).toBeTypeOf("function");
|
||||
|
||||
releaseFlush?.();
|
||||
await pending;
|
||||
|
||||
expect(ctx.state.toolMetaById.has("tool-await-flush")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleToolExecutionEnd cron.add commitment tracking", () => {
|
||||
|
||||
@@ -174,7 +174,7 @@ export async function handleToolExecutionStart(
|
||||
// Flush pending block replies to preserve message boundaries before tool execution.
|
||||
ctx.flushBlockReplyBuffer();
|
||||
if (ctx.params.onBlockReplyFlush) {
|
||||
void ctx.params.onBlockReplyFlush();
|
||||
await ctx.params.onBlockReplyFlush();
|
||||
}
|
||||
|
||||
const rawToolName = String(evt.toolName);
|
||||
|
||||
Reference in New Issue
Block a user