[codex] Recover Codex context overflow sessions

This commit is contained in:
Eyejoker
2026-05-19 21:52:54 +09:00
committed by GitHub
parent 59c7318833
commit f240cf7820
4 changed files with 46 additions and 33 deletions

View File

@@ -21,6 +21,23 @@ import { getErrorMessage } from './utils.js';
type AttemptResult = 'success' | 'error';
function isRetryableCodexSessionFailureAttempt(args: {
provider: 'claude' | 'codex';
attempt: MessageAgentAttempt;
}): boolean {
const { provider, attempt } = args;
if (provider !== 'codex' || attempt.sawOutput) return false;
if (attempt.retryableSessionFailureDetected === true) return true;
if (attempt.output != null)
return shouldRetryFreshCodexSessionOnAgentFailure(attempt.output);
return attempt.error == null
? false
: shouldRetryFreshCodexSessionOnAgentFailure({
result: null,
error: getErrorMessage(attempt.error),
});
}
export async function executeMessageAgentAttemptLifecycle(args: {
provider: 'claude' | 'codex';
runAttempt: (provider: 'claude' | 'codex') => Promise<MessageAgentAttempt>;
@@ -212,34 +229,13 @@ export async function executeMessageAgentAttemptLifecycle(args: {
};
};
const isRetryableCodexSessionFailure = (
attempt: MessageAgentAttempt,
): boolean => {
if (provider !== 'codex' || attempt.sawOutput) {
return false;
}
if (attempt.retryableSessionFailureDetected === true) {
return true;
}
if (attempt.error == null) {
return false;
}
return shouldRetryFreshCodexSessionOnAgentFailure({
result: null,
error: getErrorMessage(attempt.error),
});
};
const recoverRetryableCodexSessionFailure = async (
attempt: MessageAgentAttempt,
): Promise<{
attempt: MessageAgentAttempt;
resolved: AttemptResult | null;
}> => {
if (!isRetryableCodexSessionFailure(attempt)) {
if (!isRetryableCodexSessionFailureAttempt({ provider, attempt })) {
return { attempt, resolved: null };
}
@@ -250,7 +246,12 @@ export async function executeMessageAgentAttemptLifecycle(args: {
);
const freshAttempt = await runTrackedAttempt('codex');
if (!isRetryableCodexSessionFailure(freshAttempt)) {
if (
!isRetryableCodexSessionFailureAttempt({
provider,
attempt: freshAttempt,
})
) {
return { attempt: freshAttempt, resolved: null };
}

View File

@@ -3461,7 +3461,7 @@ describe('runAgentForGroup Claude rotation', () => {
expect(deps.clearSession).toHaveBeenCalledWith('test-claude');
});
it('drops a poisoned Codex session id before retrying a fresh session after remote compaction failure', async () => {
it('drops a poisoned Codex session id before retrying after context-window overflow', async () => {
const group = {
...makeGroup(),
folder: 'test-codex',
@@ -3494,20 +3494,19 @@ describe('runAgentForGroup Claude rotation', () => {
vi.mocked(agentRunner.runAgentProcess)
.mockImplementationOnce(async (_group, input) => {
expect(input.sessionId).toBe('stale-codex-session-id');
throw new Error(
"Error running remote compact task: Unknown parameter: 'prompt_cache_retention'",
);
return {
status: 'error',
result: null,
error: "Codex ran out of room in the model's context window.",
newSessionId: 'stale-codex-session-id',
};
})
.mockImplementationOnce(async (_group, input, _onProcess, onOutput) => {
expect(input.sessionId).toBeUndefined();
await onOutput?.({
status: 'success',
phase: 'final',
result: 'fresh Codex retry success',
});
await onOutput?.({ status: 'success', phase: 'final', result: 'ok' });
return {
status: 'success',
result: 'fresh Codex retry success',
result: 'ok',
newSessionId: 'fresh-codex-session-id',
};
});

View File

@@ -135,6 +135,17 @@ describe('shouldRetryFreshCodexSessionOnAgentFailure', () => {
).toBe(true);
});
it('retries Codex context-window overflow with a fresh session', () => {
const output = {
result: null,
error:
"Codex ran out of room in the model's context window.\nStart a new thread or clear earlier history before retrying.",
};
expect(shouldResetCodexSessionOnAgentFailure(output)).toBe(true);
expect(shouldRetryFreshCodexSessionOnAgentFailure(output)).toBe(true);
});
it('does not retry generic Codex Bad Request signals during observation-only rollout', () => {
const output = {
result: null,

View File

@@ -20,6 +20,8 @@ const SESSION_RETRY_PATTERNS = [
const CODEX_SESSION_RESET_PATTERNS = [
/Error running remote compact task/i,
/Codex ran out of room in the model's context window/i,
/Start a new thread or clear earlier history before retrying/i,
/prompt_cache_retention/i,
];