Showing the changes to apps/server/src/provider/codex (2 of 5 files). Show all
Unified · Split
| @@ -171,6 +171,27 @@ describe("isRecoverableThreadResumeError", () => { · 170 unmodified lines | ||
| 171 | 171 | false, |
| 172 | 172 | ); |
| 173 | 173 | }); |
| 174 | + | |
| 175 | + it("ignores unrelated missing-resource errors that do not mention threads", () => { | |
| 176 | + assert.equal( | |
| 177 | + isRecoverableThreadResumeError( | |
| 178 | + new CodexErrors.CodexAppServerRequestError({ | |
| 179 | + code: -32603, | |
| 180 | + errorMessage: "Config file not found", | |
| 181 | + }), | |
| 182 | + ), | |
| 183 | + false, | |
| 184 | + ); | |
| 185 | + assert.equal( | |
| 186 | + isRecoverableThreadResumeError( | |
| 187 | + new CodexErrors.CodexAppServerRequestError({ | |
| 188 | + code: -32603, | |
| 189 | + errorMessage: "Model does not exist", | |
| 190 | + }), | |
| 191 | + ), | |
| 192 | + false, | |
| 193 | + ); | |
| 194 | + }); | |
| 174 | 195 | }); |
| 175 | 196 | |
| 176 | 197 | describe("openCodexThread", () => { |
| @@ -383,6 +383,9 @@ function classifyCodexStderrLine(rawLine: string): { readonly message: string } · 382 unmodified lines | ||
| 383 | 383 | |
| 384 | 384 | export function isRecoverableThreadResumeError(error: unknown): boolean { |
| 385 | 385 | const message = (error instanceof Error ? error.message : String(error)).toLowerCase(); |
| 386 | + if (!message.includes("thread")) { | |
| 387 | + return false; | |
| 388 | + } | |
| 386 | 389 | return RECOVERABLE_THREAD_RESUME_ERROR_SNIPPETS.some((snippet) => message.includes(snippet)); |
| 387 | 390 | } |
| 388 | 391 | |
| @@ -390,8 +393,17 @@ type CodexThreadOpenResponse = · 1 unmodified line | ||
| 390 | 393 | | CodexRpc.ClientRequestResponsesByMethod["thread/start"] |
| 391 | 394 | | CodexRpc.ClientRequestResponsesByMethod["thread/resume"]; |
| 392 | 395 | |
| 396 | +type CodexThreadOpenMethod = "thread/start" | "thread/resume"; | |
| 397 | + | |
| 398 | +interface CodexThreadOpenClient { | |
| 399 | + readonly request: <M extends CodexThreadOpenMethod>( | |
| 400 | + method: M, | |
| 401 | + payload: CodexRpc.ClientRequestParamsByMethod[M], | |
| 402 | + ) => Effect.Effect<CodexRpc.ClientRequestResponsesByMethod[M], CodexErrors.CodexAppServerError>; | |
| 403 | +} | |
| 404 | + | |
| 393 | 405 | export const openCodexThread = (input: { |
| 394 | − readonly client: CodexClient.CodexAppServerClientShape; | |
| 406 | + readonly client: CodexThreadOpenClient; | |
| 395 | 407 | readonly threadId: ThreadId; |
| 396 | 408 | readonly runtimeMode: RuntimeMode; |
| 397 | 409 | readonly cwd: string; |
| @@ -1288,6 +1300,7 @@ export const makeCodexSessionRuntime = ( · 890 unmodified lines | ||
| 1288 | 1300 | requestId, |
| 1289 | 1301 | }); |
| 1290 | 1302 | } |
| 1303 | + const codexAnswers = yield* toCodexUserInputAnswers(answers); | |
| 1291 | 1304 | yield* Ref.update(pendingUserInputsRef, (current) => { |
| 1292 | 1305 | const next = new Map(current); |
| 1293 | 1306 | next.delete(requestId); |
| @@ -1302,7 +1315,7 @@ export const makeCodexSessionRuntime = ( · 8 unmodified lines | ||
| 1302 | 1315 | ...(pending.turnId ? { turnId: pending.turnId } : {}), |
| 1303 | 1316 | ...(pending.itemId ? { itemId: pending.itemId } : {}), |
| 1304 | 1317 | payload: { |
| 1305 | − answers: yield* toCodexUserInputAnswers(answers), | |
| 1318 | + answers: codexAnswers, | |
| 1306 | 1319 | }, |
| 1307 | 1320 | }); |
| 1308 | 1321 | }), |