fix: address codex review findings
This commit is contained in:
@@ -147,6 +147,9 @@ describe('codexWebsocketRuntime', () => {
|
||||
id: 'resp-incomplete',
|
||||
model: parsed.model || 'gpt-5.4',
|
||||
status: 'incomplete',
|
||||
incomplete_details: {
|
||||
reason: 'max_output_tokens',
|
||||
},
|
||||
},
|
||||
}));
|
||||
};
|
||||
@@ -154,18 +157,34 @@ describe('codexWebsocketRuntime', () => {
|
||||
const { createCodexWebsocketRuntime, CodexWebsocketRuntimeError } = await import('./codexWebsocketRuntime.js');
|
||||
const runtime = createCodexWebsocketRuntime();
|
||||
|
||||
await expect(runtime.sendRequest({
|
||||
sessionId: 'exec-session-incomplete',
|
||||
requestUrl: upstreamWsUrl,
|
||||
headers: {
|
||||
Authorization: 'Bearer oauth-access-token',
|
||||
'OpenAI-Beta': 'responses_websockets=2026-02-06',
|
||||
},
|
||||
body: {
|
||||
model: 'gpt-5.4',
|
||||
input: [],
|
||||
},
|
||||
})).rejects.toBeInstanceOf(CodexWebsocketRuntimeError);
|
||||
let error: unknown;
|
||||
try {
|
||||
await runtime.sendRequest({
|
||||
sessionId: 'exec-session-incomplete',
|
||||
requestUrl: upstreamWsUrl,
|
||||
headers: {
|
||||
Authorization: 'Bearer oauth-access-token',
|
||||
'OpenAI-Beta': 'responses_websockets=2026-02-06',
|
||||
},
|
||||
body: {
|
||||
model: 'gpt-5.4',
|
||||
input: [],
|
||||
},
|
||||
});
|
||||
} catch (caught) {
|
||||
error = caught;
|
||||
}
|
||||
|
||||
expect(error).toBeInstanceOf(CodexWebsocketRuntimeError);
|
||||
expect(error).toMatchObject({
|
||||
message: 'max_output_tokens',
|
||||
status: 502,
|
||||
});
|
||||
expect((error as CodexWebsocketRuntimeError).events).toEqual([
|
||||
expect.objectContaining({
|
||||
type: 'response.incomplete',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('treats top-level error frames as terminal websocket failures', async () => {
|
||||
@@ -182,17 +201,36 @@ describe('codexWebsocketRuntime', () => {
|
||||
const { createCodexWebsocketRuntime, CodexWebsocketRuntimeError } = await import('./codexWebsocketRuntime.js');
|
||||
const runtime = createCodexWebsocketRuntime();
|
||||
|
||||
await expect(runtime.sendRequest({
|
||||
sessionId: 'exec-session-error',
|
||||
requestUrl: upstreamWsUrl,
|
||||
headers: {
|
||||
Authorization: 'Bearer oauth-access-token',
|
||||
'OpenAI-Beta': 'responses_websockets=2026-02-06',
|
||||
},
|
||||
body: {
|
||||
model: 'gpt-5.4',
|
||||
input: [],
|
||||
},
|
||||
})).rejects.toBeInstanceOf(CodexWebsocketRuntimeError);
|
||||
let error: unknown;
|
||||
try {
|
||||
await runtime.sendRequest({
|
||||
sessionId: 'exec-session-error',
|
||||
requestUrl: upstreamWsUrl,
|
||||
headers: {
|
||||
Authorization: 'Bearer oauth-access-token',
|
||||
'OpenAI-Beta': 'responses_websockets=2026-02-06',
|
||||
},
|
||||
body: {
|
||||
model: 'gpt-5.4',
|
||||
input: [],
|
||||
},
|
||||
});
|
||||
} catch (caught) {
|
||||
error = caught;
|
||||
}
|
||||
|
||||
expect(error).toBeInstanceOf(CodexWebsocketRuntimeError);
|
||||
expect(error).toMatchObject({
|
||||
message: 'account mismatch',
|
||||
status: 502,
|
||||
});
|
||||
expect((error as CodexWebsocketRuntimeError).events).toEqual([
|
||||
expect.objectContaining({
|
||||
type: 'error',
|
||||
error: expect.objectContaining({
|
||||
message: 'account mismatch',
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,6 +34,32 @@ function isFailureTerminalEvent(payload: Record<string, unknown>): boolean {
|
||||
return type === 'response.failed' || type === 'response.incomplete' || type === 'error';
|
||||
}
|
||||
|
||||
function asFiniteNumber(value: unknown): number | undefined {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
||||
}
|
||||
|
||||
function extractFailureTerminalStatus(payload: Record<string, unknown>): number {
|
||||
const response = isRecord(payload.response) ? payload.response : null;
|
||||
const responseError = response && isRecord(response.error) ? response.error : null;
|
||||
const topLevelError = isRecord(payload.error) ? payload.error : null;
|
||||
const candidates = [
|
||||
payload.status,
|
||||
payload.statusCode,
|
||||
payload.code,
|
||||
topLevelError?.status,
|
||||
topLevelError?.statusCode,
|
||||
topLevelError?.code,
|
||||
responseError?.status,
|
||||
responseError?.statusCode,
|
||||
responseError?.code,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
const status = asFiniteNumber(candidate);
|
||||
if (status !== undefined) return status;
|
||||
}
|
||||
return 502;
|
||||
}
|
||||
|
||||
function extractTerminalErrorMessage(payload: Record<string, unknown>): string {
|
||||
const type = asTrimmedString(payload.type);
|
||||
if (type === 'error' && isRecord(payload.error)) {
|
||||
@@ -243,7 +269,7 @@ async function sendSessionRequest(
|
||||
void closeSocket(socket);
|
||||
reject(new CodexWebsocketRuntimeError(extractTerminalErrorMessage(parsed), {
|
||||
events: [...events],
|
||||
status: typeof parsed.status === 'number' && Number.isFinite(parsed.status) ? parsed.status : undefined,
|
||||
status: extractFailureTerminalStatus(parsed),
|
||||
payload: parsed,
|
||||
}));
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user