Merge pull request #167 from phj1081/codex/owner/ejclaw
fix: persist queued cursors after turn completion
This commit is contained in:
@@ -144,7 +144,7 @@ describe('message-runtime queued cursor handling', () => {
|
|||||||
expect(outcome).toBe(false);
|
expect(outcome).toBe(false);
|
||||||
expect(executeTurn).toHaveBeenCalledTimes(1);
|
expect(executeTurn).toHaveBeenCalledTimes(1);
|
||||||
expect(lastAgentTimestamps).toEqual({});
|
expect(lastAgentTimestamps).toEqual({});
|
||||||
expect(saveState).toHaveBeenCalledTimes(2);
|
expect(saveState).not.toHaveBeenCalled();
|
||||||
expect(logMocks.warn).toHaveBeenCalledWith(
|
expect(logMocks.warn).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
messageSeqStart: 48,
|
messageSeqStart: 48,
|
||||||
@@ -183,4 +183,69 @@ describe('message-runtime queued cursor handling', () => {
|
|||||||
expect(lastAgentTimestamps).toEqual({ 'group@test': '48' });
|
expect(lastAgentTimestamps).toEqual({ 'group@test': '48' });
|
||||||
expect(saveState).toHaveBeenCalledTimes(1);
|
expect(saveState).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not advance the queued human cursor before the owner turn finishes', async () => {
|
||||||
|
const task = makeTask({
|
||||||
|
owner_service_id: 'codex',
|
||||||
|
owner_agent_type: 'codex',
|
||||||
|
});
|
||||||
|
createPairedTask(task);
|
||||||
|
const lastAgentTimestamps: Record<string, string> = {};
|
||||||
|
const saveState = vi.fn(() => undefined);
|
||||||
|
const executeTurn: RunQueuedGroupTurnArgs['executeTurn'] = vi.fn(
|
||||||
|
async () => {
|
||||||
|
expect(lastAgentTimestamps).toEqual({});
|
||||||
|
expect(saveState).not.toHaveBeenCalled();
|
||||||
|
return {
|
||||||
|
outputStatus: 'success' as const,
|
||||||
|
deliverySucceeded: true,
|
||||||
|
visiblePhase: 'final',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const outcome = await runQueuedGroupTurn(
|
||||||
|
makeQueuedTurnArgs({
|
||||||
|
task,
|
||||||
|
executeTurn,
|
||||||
|
lastAgentTimestamps,
|
||||||
|
saveState,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(outcome).toBe(true);
|
||||||
|
expect(executeTurn).toHaveBeenCalledTimes(1);
|
||||||
|
expect(lastAgentTimestamps).toEqual({ 'group@test': '48' });
|
||||||
|
expect(saveState).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps the queued human cursor when the owner turn aborts before completion', async () => {
|
||||||
|
const task = makeTask({
|
||||||
|
owner_service_id: 'codex',
|
||||||
|
owner_agent_type: 'codex',
|
||||||
|
});
|
||||||
|
createPairedTask(task);
|
||||||
|
const executeTurn: RunQueuedGroupTurnArgs['executeTurn'] = vi.fn(
|
||||||
|
async () => {
|
||||||
|
throw new Error('process terminated during restart');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const lastAgentTimestamps: Record<string, string> = {};
|
||||||
|
const saveState = vi.fn(() => undefined);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
runQueuedGroupTurn(
|
||||||
|
makeQueuedTurnArgs({
|
||||||
|
task,
|
||||||
|
executeTurn,
|
||||||
|
lastAgentTimestamps,
|
||||||
|
saveState,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).rejects.toThrow('process terminated during restart');
|
||||||
|
|
||||||
|
expect(executeTurn).toHaveBeenCalledTimes(1);
|
||||||
|
expect(lastAgentTimestamps).toEqual({});
|
||||||
|
expect(saveState).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -379,17 +379,7 @@ export async function runQueuedGroupTurn(args: {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousCursor = args.lastAgentTimestamps[cursorKey];
|
|
||||||
const cursorAdvanced = endSeq !== null;
|
const cursorAdvanced = endSeq !== null;
|
||||||
if (cursorAdvanced) {
|
|
||||||
advanceLastAgentCursor(
|
|
||||||
args.lastAgentTimestamps,
|
|
||||||
args.saveState,
|
|
||||||
chatJid,
|
|
||||||
endSeq,
|
|
||||||
cursorKey,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { outputStatus, deliverySucceeded, visiblePhase } =
|
const { outputStatus, deliverySucceeded, visiblePhase } =
|
||||||
await args.executeTurn({
|
await args.executeTurn({
|
||||||
@@ -416,17 +406,22 @@ export async function runQueuedGroupTurn(args: {
|
|||||||
hasHumanMsg &&
|
hasHumanMsg &&
|
||||||
turnRole === 'owner' &&
|
turnRole === 'owner' &&
|
||||||
currentTask?.owner_agent_type === 'codex',
|
currentTask?.owner_agent_type === 'codex',
|
||||||
cursorAdvanced,
|
|
||||||
previousCursor,
|
|
||||||
lastAgentTimestamps: args.lastAgentTimestamps,
|
|
||||||
saveState: args.saveState,
|
|
||||||
cursorKey,
|
|
||||||
log,
|
log,
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cursorAdvanced) {
|
||||||
|
advanceLastAgentCursor(
|
||||||
|
args.lastAgentTimestamps,
|
||||||
|
args.saveState,
|
||||||
|
chatJid,
|
||||||
|
endSeq,
|
||||||
|
cursorKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!deliverySucceeded) {
|
if (!deliverySucceeded) {
|
||||||
log.warn(
|
log.warn(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ export function finalizeQueuedRunCursor(args: {
|
|||||||
startSeq: number | null;
|
startSeq: number | null;
|
||||||
endSeq: number | null;
|
endSeq: number | null;
|
||||||
rollbackOnSilentError: boolean;
|
rollbackOnSilentError: boolean;
|
||||||
cursorAdvanced: boolean;
|
|
||||||
previousCursor: string | undefined;
|
|
||||||
lastAgentTimestamps: Record<string, string>;
|
|
||||||
saveState: () => void;
|
|
||||||
cursorKey: string;
|
|
||||||
log: {
|
log: {
|
||||||
warn: (bindings: Record<string, unknown>, message: string) => void;
|
warn: (bindings: Record<string, unknown>, message: string) => void;
|
||||||
};
|
};
|
||||||
@@ -66,14 +61,6 @@ export function finalizeQueuedRunCursor(args: {
|
|||||||
args.outputStatus === 'error' &&
|
args.outputStatus === 'error' &&
|
||||||
args.visiblePhase === 'silent'
|
args.visiblePhase === 'silent'
|
||||||
) {
|
) {
|
||||||
if (args.cursorAdvanced) {
|
|
||||||
if (args.previousCursor === undefined) {
|
|
||||||
delete args.lastAgentTimestamps[args.cursorKey];
|
|
||||||
} else {
|
|
||||||
args.lastAgentTimestamps[args.cursorKey] = args.previousCursor;
|
|
||||||
}
|
|
||||||
args.saveState();
|
|
||||||
}
|
|
||||||
args.log.warn(
|
args.log.warn(
|
||||||
{
|
{
|
||||||
messageSeqStart: args.startSeq,
|
messageSeqStart: args.startSeq,
|
||||||
|
|||||||
Reference in New Issue
Block a user