mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 21:10:43 +00:00
fix: re-assemble when afterTurn is unavailable
- Decouple lastSeenLength advancement from afterTurn existence so engines without afterTurn still advance the fence and trigger assemble on new messages - Use hasNewMessages flag instead of didCallAfterTurn for the assemble gate - Add test verifying assemble fires on every iteration with new messages when engine lacks afterTurn
This commit is contained in:
@@ -463,6 +463,32 @@ describe("installContextEngineLoopHook", () => {
|
||||
expect(engine.assemble).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("keeps calling assemble on subsequent iterations when engine lacks afterTurn but new messages arrive", async () => {
|
||||
const agent = makeGuardableAgent();
|
||||
const engine = makeMockEngine({ omitAfterTurn: true });
|
||||
installContextEngineLoopHook({
|
||||
agent,
|
||||
contextEngine: engine,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
sessionFile,
|
||||
tokenBudget,
|
||||
modelId,
|
||||
});
|
||||
|
||||
const batch1 = [makeUser("first"), makeToolResult("call_1", "r1")];
|
||||
await callTransform(agent, batch1);
|
||||
expect(engine.assemble).toHaveBeenCalledTimes(1);
|
||||
|
||||
const batch2 = [...batch1, makeUser("second"), makeToolResult("call_2", "r2")];
|
||||
await callTransform(agent, batch2);
|
||||
expect(engine.assemble).toHaveBeenCalledTimes(2);
|
||||
|
||||
const batch3 = [...batch2, makeUser("third"), makeToolResult("call_3", "r3")];
|
||||
await callTransform(agent, batch3);
|
||||
expect(engine.assemble).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("falls through to the source messages when engine.afterTurn throws", async () => {
|
||||
const agent = makeGuardableAgent();
|
||||
const engine = makeMockEngine({
|
||||
|
||||
@@ -222,9 +222,9 @@ export function installContextEngineLoopHook(params: {
|
||||
lastSeenLength = params.getPrePromptMessageCount?.() ?? 0;
|
||||
}
|
||||
|
||||
let didCallAfterTurn = false;
|
||||
const hasNewMessages = sourceMessages.length > lastSeenLength;
|
||||
try {
|
||||
if (sourceMessages.length > lastSeenLength && typeof contextEngine.afterTurn === "function") {
|
||||
if (hasNewMessages && typeof contextEngine.afterTurn === "function") {
|
||||
const prePromptCount = lastSeenLength;
|
||||
await contextEngine.afterTurn({
|
||||
sessionId,
|
||||
@@ -234,13 +234,14 @@ export function installContextEngineLoopHook(params: {
|
||||
prePromptMessageCount: prePromptCount,
|
||||
tokenBudget,
|
||||
});
|
||||
}
|
||||
if (hasNewMessages) {
|
||||
lastSeenLength = sourceMessages.length;
|
||||
didCallAfterTurn = true;
|
||||
}
|
||||
// Skip assemble when nothing has changed since the last call AND we
|
||||
// already returned an assembled view at least once. The engine's view
|
||||
// cannot have changed without new messages arriving via afterTurn.
|
||||
if (didCallAfterTurn || !hasAssembledBefore) {
|
||||
// cannot have changed without new messages arriving.
|
||||
if (hasNewMessages || !hasAssembledBefore) {
|
||||
const assembled = await contextEngine.assemble({
|
||||
sessionId,
|
||||
sessionKey,
|
||||
|
||||
Reference in New Issue
Block a user