|
|
@@ -35,17 +35,13 @@ async function flushChildIdleReconcile(): Promise<void> {
|
|
|
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
|
}
|
|
|
|
|
|
-function createHook(options?: {
|
|
|
+type HookOptions = {
|
|
|
shouldManageSession?: (sessionID: string) => boolean;
|
|
|
registerSessionAsOrchestrator?: (sessionID: string) => void;
|
|
|
readContextMinLines?: number;
|
|
|
readContextMaxFiles?: number;
|
|
|
strategy?: 'latest' | 'checkpoint-compatible';
|
|
|
maxRetainedSnapshots?: number;
|
|
|
- /**
|
|
|
- * Keeps continuation behavior tests focused on the opt-in beta path;
|
|
|
- * production defaults are exercised by the direct factory test below.
|
|
|
- */
|
|
|
continueOnIdle?: boolean;
|
|
|
backgroundJobBoard?: BackgroundJobBoard;
|
|
|
sessionStatus?: unknown;
|
|
|
@@ -53,7 +49,9 @@ function createHook(options?: {
|
|
|
idleReconcileDelayMs?: number;
|
|
|
isFallbackInProgress?: (sessionID: string) => boolean;
|
|
|
coordinator?: SessionLifecycle;
|
|
|
-}) {
|
|
|
+};
|
|
|
+
|
|
|
+function createHook(options?: HookOptions) {
|
|
|
const hook = createTaskSessionManagerHook(
|
|
|
{
|
|
|
client: {
|
|
|
@@ -72,7 +70,7 @@ function createHook(options?: {
|
|
|
strategy: options?.strategy,
|
|
|
readContextMinLines: options?.readContextMinLines,
|
|
|
readContextMaxFiles: options?.readContextMaxFiles,
|
|
|
- continueOnIdle: options?.continueOnIdle ?? true,
|
|
|
+ continueOnIdle: options?.continueOnIdle ?? false,
|
|
|
backgroundJobBoard: options?.backgroundJobBoard,
|
|
|
shouldManageSession: options?.shouldManageSession ?? (() => true),
|
|
|
registerSessionAsOrchestrator: options?.registerSessionAsOrchestrator,
|
|
|
@@ -85,6 +83,13 @@ function createHook(options?: {
|
|
|
return { hook };
|
|
|
}
|
|
|
|
|
|
+function createContinuationHook(options?: HookOptions) {
|
|
|
+ return createHook({
|
|
|
+ ...options,
|
|
|
+ continueOnIdle: options?.continueOnIdle ?? true,
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
function createMessages(sessionID: string, text = 'user message') {
|
|
|
return {
|
|
|
messages: [
|
|
|
@@ -3555,7 +3560,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('nudges once for incomplete todos when parent and children are inactive', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
continueOnIdle: true,
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
@@ -3583,7 +3588,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('paired idle events submit at most one continuation', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -3720,7 +3725,7 @@ describe('task-session-manager hook', () => {
|
|
|
resolvePrompt = resolve;
|
|
|
}),
|
|
|
);
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -3744,7 +3749,7 @@ describe('task-session-manager hook', () => {
|
|
|
expect(promptAsync).toHaveBeenCalledTimes(1);
|
|
|
|
|
|
await hook.event({ event: { type: 'server.instance.disposed' } });
|
|
|
- const { hook: nextHook } = createHook({
|
|
|
+ const { hook: nextHook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -3768,7 +3773,7 @@ describe('task-session-manager hook', () => {
|
|
|
const promptAsync = mock(async () => {
|
|
|
throw new Error('prompt rejected');
|
|
|
});
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -3808,7 +3813,7 @@ describe('task-session-manager hook', () => {
|
|
|
}),
|
|
|
);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -3916,7 +3921,7 @@ describe('task-session-manager hook', () => {
|
|
|
promptAsync,
|
|
|
};
|
|
|
let fallbackInProgress = false;
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
isFallbackInProgress: () => fallbackInProgress,
|
|
|
sessionClient,
|
|
|
@@ -3955,7 +3960,7 @@ describe('task-session-manager hook', () => {
|
|
|
if (todoCalls === 1) return { data: undefined };
|
|
|
return { data: [{ status: 'pending' }] };
|
|
|
});
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -3989,7 +3994,7 @@ describe('task-session-manager hook', () => {
|
|
|
}
|
|
|
return { data: {} };
|
|
|
});
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4015,7 +4020,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('does not evaluate or nudge while a question or permission waits', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4049,7 +4054,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('does not evaluate or nudge after wait_for_user requests text-only HITL', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4071,7 +4076,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('a distinct external user message releases wait_for_user', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4104,7 +4109,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('a duplicate external message cannot clear a newer user wait', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4146,7 +4151,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('synthetic and internal messages do not clear wait_for_user', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4183,7 +4188,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('a foreground-fallback replay marker does not clear wait_for_user', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4222,7 +4227,7 @@ describe('task-session-manager hook', () => {
|
|
|
const children = mock(async () => ({ data: [] }));
|
|
|
const status = mock(async () => ({ data: {} }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: { todo, children, status, promptAsync },
|
|
|
});
|
|
|
@@ -4248,7 +4253,7 @@ describe('task-session-manager hook', () => {
|
|
|
}),
|
|
|
);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4286,11 +4291,11 @@ describe('task-session-manager hook', () => {
|
|
|
status: mock(async () => ({ data: {} })),
|
|
|
promptAsync,
|
|
|
};
|
|
|
- const owner = createHook({
|
|
|
+ const owner = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient,
|
|
|
}).hook;
|
|
|
- const waiter = createHook({
|
|
|
+ const waiter = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient,
|
|
|
}).hook;
|
|
|
@@ -4310,7 +4315,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('external user input clears only the explicit wait while a question remains', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4367,7 +4372,7 @@ describe('task-session-manager hook', () => {
|
|
|
promptAsync,
|
|
|
};
|
|
|
const makeHook = () =>
|
|
|
- createHook({ idleReconcileDelayMs: 0, sessionClient }).hook;
|
|
|
+ createContinuationHook({ idleReconcileDelayMs: 0, sessionClient }).hook;
|
|
|
const owner = makeHook();
|
|
|
|
|
|
owner.beginUserWait('parent-1');
|
|
|
@@ -4395,7 +4400,7 @@ describe('task-session-manager hook', () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
let fallbackInProgress = true;
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
isFallbackInProgress: () => fallbackInProgress,
|
|
|
sessionClient: {
|
|
|
@@ -4425,7 +4430,7 @@ describe('task-session-manager hook', () => {
|
|
|
const children = mock(async () => ({ data: [] }));
|
|
|
const status = mock(async () => ({ data: {} }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: { todo, children, status, promptAsync },
|
|
|
});
|
|
|
@@ -4450,7 +4455,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('fails closed when an id-less ask races a scheduled continuation', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4491,7 +4496,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('clears only the resolved input wait and resumes on a later idle', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4566,7 +4571,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('resumes on a later idle after a question rejection', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4609,7 +4614,7 @@ describe('task-session-manager hook', () => {
|
|
|
}),
|
|
|
);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4640,7 +4645,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('internal and synthetic messages do not clear an input wait', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4682,7 +4687,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('retains input waits across a session error', async () => {
|
|
|
const todo = mock(async () => ({ data: [{ status: 'pending' }] }));
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -4727,7 +4732,7 @@ describe('task-session-manager hook', () => {
|
|
|
},
|
|
|
] as const) {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4756,7 +4761,7 @@ describe('task-session-manager hook', () => {
|
|
|
test('coalesces paired idle events and suppresses active children', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
const children = mock(async () => ({ data: [{ id: 'child-1' }] }));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4783,7 +4788,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('runtime-shaped external messages rearm a consumed nudge', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4818,7 +4823,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('output.message.id rearms when input.messageID is missing', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4854,7 +4859,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('ID-less output.message object identity rearms once', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4946,7 +4951,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('distinct ID-less message objects each open a new epoch', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -4992,7 +4997,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('missing id and output.message fails closed without rearm', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5153,7 +5158,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('file-only external messages rearm a consumed nudge', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5188,7 +5193,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('synthetic completion messages do not rearm a consumed nudge', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5229,7 +5234,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('nudge busy-to-idle cycle does not send a second unchanged nudge', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5266,7 +5271,7 @@ describe('task-session-manager hook', () => {
|
|
|
}),
|
|
|
);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo,
|
|
|
@@ -5298,7 +5303,7 @@ describe('task-session-manager hook', () => {
|
|
|
const board = new BackgroundJobBoard();
|
|
|
setupCompletedJob(board);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
backgroundJobBoard: board,
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
@@ -5323,7 +5328,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('missing SDK response data fails closed without nudging', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: undefined })),
|
|
|
@@ -5343,7 +5348,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('does not nudge when todos are completed or cancelled only', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({
|
|
|
@@ -5365,7 +5370,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('does not nudge while the parent is active', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5385,7 +5390,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('does not nudge while a child is retrying', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5407,7 +5412,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('does not rearm a consumed nudge for its actual internal part', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5444,7 +5449,7 @@ describe('task-session-manager hook', () => {
|
|
|
const promptAsync = mock(async () => {
|
|
|
throw new Error('prompt failed');
|
|
|
});
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5468,7 +5473,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('keeps a failed prompt response consumed', async () => {
|
|
|
const promptAsync = mock(async () => ({ error: 'prompt failed' }));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => ({ data: [{ status: 'pending' }] })),
|
|
|
@@ -5492,12 +5497,12 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('fails closed for missing or throwing SDK endpoints', async () => {
|
|
|
const missingPrompt = mock(async () => ({}));
|
|
|
- const { hook: missingHook } = createHook({
|
|
|
+ const { hook: missingHook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: { promptAsync: missingPrompt },
|
|
|
});
|
|
|
const throwingPrompt = mock(async () => ({}));
|
|
|
- const { hook: throwingHook } = createHook({
|
|
|
+ const { hook: throwingHook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => {
|
|
|
@@ -5522,7 +5527,7 @@ describe('task-session-manager hook', () => {
|
|
|
|
|
|
test('does not nudge when fallback is already in progress', async () => {
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
isFallbackInProgress: () => true,
|
|
|
sessionClient: {
|
|
|
@@ -5550,7 +5555,7 @@ describe('task-session-manager hook', () => {
|
|
|
},
|
|
|
);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
isFallbackInProgress: () => fallbackInProgress,
|
|
|
sessionClient: {
|
|
|
@@ -5580,7 +5585,7 @@ describe('task-session-manager hook', () => {
|
|
|
releaseLatestChildren = () => resolve({ data: [] });
|
|
|
});
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
backgroundJobBoard: board,
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
@@ -5613,7 +5618,7 @@ describe('task-session-manager hook', () => {
|
|
|
},
|
|
|
);
|
|
|
const promptAsync = mock(async () => ({}));
|
|
|
- const { hook } = createHook({
|
|
|
+ const { hook } = createContinuationHook({
|
|
|
idleReconcileDelayMs: 0,
|
|
|
sessionClient: {
|
|
|
todo: mock(async () => todos),
|