mirror of https://github.com/openclaw/openclaw.git
fix(agents): resolve compaction wait before channel flush (#59308)
Merged via squash.
Prepared head SHA: bf17502df8
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
parent
326490ab76
commit
32fa5c3be5
|
|
@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Exec approvals: route Slack, Discord, and Telegram approvals through the shared channel approval-capability path so native approval auth, delivery, and `/approve` handling stay aligned across channels while preserving Telegram session-key agent filtering. (#58634) thanks @gumadeiras
|
||||
- Matrix/runtime: resolve the verification/bootstrap runtime from a distinct packaged Matrix entry so global npm installs stop failing on crypto bootstrap with missing-module or recursive runtime alias errors. (#59249) Thanks @gumadeiras.
|
||||
- Matrix/streaming: preserve ordered block flushes before tool, message, and agent boundaries, add explicit `channels.matrix.blockStreaming` opt-in so Matrix `streaming: "off"` stays final-only by default, and move MiniMax plain-text final handling into the MiniMax provider runtime instead of the shared core heuristic. (#59266) thanks @gumadeiras
|
||||
- Agents/compaction: resolve compaction wait before final reply/channel flush completion so slow end-of-run delivery drains no longer delay compaction completion. (#59308) thanks @gumadeiras
|
||||
|
||||
## 2026.4.2
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ vi.mock("../infra/agent-events.js", () => ({
|
|||
|
||||
function createContext(
|
||||
lastAssistant: unknown,
|
||||
overrides?: { onAgentEvent?: (event: unknown) => void },
|
||||
overrides?: {
|
||||
onAgentEvent?: (event: unknown) => void;
|
||||
onBlockReplyFlush?: () => void | Promise<void>;
|
||||
},
|
||||
): EmbeddedPiSubscribeContext {
|
||||
const onBlockReply = vi.fn();
|
||||
return {
|
||||
|
|
@ -19,6 +22,7 @@ function createContext(
|
|||
sessionKey: "agent:main:main",
|
||||
onAgentEvent: overrides?.onAgentEvent,
|
||||
onBlockReply,
|
||||
onBlockReplyFlush: overrides?.onBlockReplyFlush,
|
||||
},
|
||||
state: {
|
||||
lastAssistant: lastAssistant as EmbeddedPiSubscribeContext["state"]["lastAssistant"],
|
||||
|
|
@ -179,4 +183,45 @@ describe("handleAgentEnd", () => {
|
|||
expect(ctx.state.pendingToolMediaUrls).toEqual([]);
|
||||
expect(ctx.state.pendingToolAudioAsVoice).toBe(false);
|
||||
});
|
||||
|
||||
it("resolves compaction wait before awaiting an async block reply flush", async () => {
|
||||
let resolveFlush: (() => void) | undefined;
|
||||
const ctx = createContext(undefined);
|
||||
ctx.flushBlockReplyBuffer = vi
|
||||
.fn()
|
||||
.mockImplementationOnce(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
resolveFlush = resolve;
|
||||
}),
|
||||
)
|
||||
.mockImplementation(() => {});
|
||||
|
||||
const endPromise = handleAgentEnd(ctx);
|
||||
|
||||
expect(ctx.maybeResolveCompactionWait).toHaveBeenCalledTimes(1);
|
||||
expect(ctx.resolveCompactionRetry).not.toHaveBeenCalled();
|
||||
|
||||
resolveFlush?.();
|
||||
await endPromise;
|
||||
});
|
||||
|
||||
it("resolves compaction wait before awaiting an async channel flush", async () => {
|
||||
let resolveChannelFlush: (() => void) | undefined;
|
||||
const onBlockReplyFlush = vi.fn(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
resolveChannelFlush = resolve;
|
||||
}),
|
||||
);
|
||||
const ctx = createContext(undefined, { onBlockReplyFlush });
|
||||
|
||||
const endPromise = handleAgentEnd(ctx);
|
||||
|
||||
expect(ctx.maybeResolveCompactionWait).toHaveBeenCalledTimes(1);
|
||||
expect(onBlockReplyFlush).toHaveBeenCalledTimes(1);
|
||||
|
||||
resolveChannelFlush?.();
|
||||
await endPromise;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -136,20 +136,13 @@ export function handleAgentEnd(ctx: EmbeddedPiSubscribeContext) {
|
|||
};
|
||||
|
||||
const flushBlockReplyBufferResult = ctx.flushBlockReplyBuffer();
|
||||
finalizeAgentEnd();
|
||||
if (isPromiseLike<void>(flushBlockReplyBufferResult)) {
|
||||
return flushBlockReplyBufferResult
|
||||
.then(() => flushPendingMediaAndChannel())
|
||||
.finally(() => {
|
||||
finalizeAgentEnd();
|
||||
});
|
||||
return flushBlockReplyBufferResult.then(() => flushPendingMediaAndChannel());
|
||||
}
|
||||
|
||||
const flushPendingMediaAndChannelResult = flushPendingMediaAndChannel();
|
||||
if (isPromiseLike<void>(flushPendingMediaAndChannelResult)) {
|
||||
return flushPendingMediaAndChannelResult.finally(() => {
|
||||
finalizeAgentEnd();
|
||||
});
|
||||
return flushPendingMediaAndChannelResult;
|
||||
}
|
||||
|
||||
finalizeAgentEnd();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue