mirror of
https://github.com/wu736139669/hapi.git
synced 2026-11-07 01:21:37 +00:00
fix(codex): wait for manual compaction to finish (#1038)
* test: reproduce issue #982 * fix: wait for Codex manual compaction (closes #982) * test: cover Codex compaction turn completion
This commit is contained in:
@@ -39,6 +39,7 @@ const harness = vi.hoisted(() => ({
|
||||
failResumeThreadIds: [] as string[],
|
||||
nextThreadSystemErrorMessage: null as string | null,
|
||||
failNextCompact: false,
|
||||
deferCompactCompletion: false,
|
||||
deferThreadStatusNotifications: false,
|
||||
emitChildThreadEvents: false,
|
||||
emitChildUsageEvents: false,
|
||||
@@ -131,6 +132,9 @@ vi.mock('./codexAppServerClient', () => {
|
||||
harness.failNextCompact = false;
|
||||
throw new Error('compact failed');
|
||||
}
|
||||
if (harness.deferCompactCompletion) {
|
||||
return {};
|
||||
}
|
||||
const compacted = { threadId, turnId: `compact-${harness.compactThreadIds.length}` };
|
||||
harness.notifications.push({ method: 'thread/compacted', params: compacted });
|
||||
this.notificationHandler?.('thread/compacted', compacted);
|
||||
@@ -908,10 +912,16 @@ function createMode(): EnhancedMode {
|
||||
};
|
||||
}
|
||||
|
||||
function createSessionStub(messages = ['hello from launcher test'], mode = createMode()) {
|
||||
function createSessionStub(
|
||||
messages = ['hello from launcher test'],
|
||||
mode = createMode(),
|
||||
isolateMessages = false
|
||||
) {
|
||||
const queue = new MessageQueue2<EnhancedMode>((mode) => JSON.stringify(mode));
|
||||
messages.forEach((message, index) => {
|
||||
if (index === 0 && messages.length > 1) {
|
||||
if (isolateMessages) {
|
||||
queue.pushIsolated(message, mode);
|
||||
} else if (index === 0 && messages.length > 1) {
|
||||
queue.pushIsolateAndClear(message, mode);
|
||||
} else {
|
||||
queue.push(message, mode);
|
||||
@@ -1066,6 +1076,7 @@ describe('codexRemoteLauncher', () => {
|
||||
harness.remainingThreadSystemErrors = 0;
|
||||
harness.nextThreadSystemErrorMessage = null;
|
||||
harness.failNextCompact = false;
|
||||
harness.deferCompactCompletion = false;
|
||||
harness.deferThreadStatusNotifications = false;
|
||||
harness.emitChildThreadEvents = false;
|
||||
harness.emitChildUsageEvents = false;
|
||||
@@ -2684,6 +2695,45 @@ describe('codexRemoteLauncher', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('does not start the next turn until manual compaction finishes', async () => {
|
||||
harness.deferCompactCompletion = true;
|
||||
const { session, sessionEvents } = createSessionStub([
|
||||
'first message',
|
||||
'/compact',
|
||||
'after compact'
|
||||
], createMode(), true);
|
||||
|
||||
const running = codexRemoteLauncher(session as never);
|
||||
await vi.waitFor(() => {
|
||||
expect(harness.compactThreadIds).toEqual(['thread-1']);
|
||||
});
|
||||
|
||||
expect(harness.startTurnMessages).toEqual(['first message']);
|
||||
expect(sessionEvents).not.toContainEqual({
|
||||
type: 'message',
|
||||
message: 'Compaction completed'
|
||||
});
|
||||
|
||||
harness.dispatchNotification?.('item/completed', {
|
||||
threadId: 'thread-1',
|
||||
turnId: 'compact-1',
|
||||
item: { id: 'compact-item-1', type: 'contextCompaction' }
|
||||
});
|
||||
harness.dispatchNotification?.('turn/completed', {
|
||||
threadId: 'thread-1',
|
||||
turn: { id: 'compact-1', status: 'completed' }
|
||||
});
|
||||
|
||||
const exitReason = await running;
|
||||
|
||||
expect(exitReason).toBe('exit');
|
||||
expect(harness.startTurnMessages).toEqual(['first message', 'after compact']);
|
||||
expect(sessionEvents).toContainEqual({
|
||||
type: 'message',
|
||||
message: 'Compaction completed'
|
||||
});
|
||||
});
|
||||
|
||||
it('interrupts an in-flight turn before compacting the current thread', async () => {
|
||||
harness.suppressTurnCompletion = true;
|
||||
const { session, sessionEvents } = createSessionStub(['first message', '/compact']);
|
||||
|
||||
Reference in New Issue
Block a user