Skip to content

Commit b31b22e

Browse files
committed
fix: ignore prefixed reconnect advisories
1 parent b7e3e54 commit b31b22e

4 files changed

Lines changed: 18 additions & 2 deletions

File tree

adapters/codex-exec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import os from "node:os";
44
import path from "node:path";
55
import type { AgentAdapter, AdapterResult, AdapterRuntime, NormalizedAgentOpts } from "./types.ts";
66
import type { EngineConfig, Usage } from "../engine/types.ts";
7+
import { isReconnectAdvisory } from "./stream-errors.ts";
78

89
export class CodexExecAdapter implements AgentAdapter {
910
readonly name = "codex-exec";
@@ -57,7 +58,7 @@ export class CodexExecAdapter implements AgentAdapter {
5758
if (event.type === "turn.failed") fatalMessage = event.error?.message ?? "codex exec turn failed";
5859
if (event.type === "error") {
5960
const message = String(event.message ?? event.error?.message ?? "");
60-
if (!/^Reconnecting/i.test(message)) fatalMessage = message;
61+
if (!isReconnectAdvisory(message)) fatalMessage = message;
6162
}
6263
}
6364
});

adapters/codex-sdk.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { AgentAdapter, AdapterResult, AdapterRuntime, NormalizedAgentOpts } from "./types.ts";
22
import type { EngineConfig, Usage } from "../engine/types.ts";
3+
import { isReconnectAdvisory } from "./stream-errors.ts";
34

45
export class CodexSdkAdapter implements AgentAdapter {
56
readonly name = "codex-sdk";
@@ -31,7 +32,7 @@ export class CodexSdkAdapter implements AgentAdapter {
3132
if (event.type === "turn.failed") throw new Error(event.error?.message ?? "codex turn failed");
3233
if (event.type === "error") {
3334
const message = String(event.message ?? event.error?.message ?? "");
34-
if (!/^Reconnecting/i.test(message)) throw new Error(message || "codex stream error");
35+
if (!isReconnectAdvisory(message)) throw new Error(message || "codex stream error");
3536
}
3637
}
3738
return { finalResponse, usage, threadId: thread.id ?? undefined };

adapters/stream-errors.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const RECONNECTING_ADVISORY_RE = /^\s*(?:(?:\[[^\]\n]+]|\w[\w.-]*:)\s*)*Reconnecting\b/i;
2+
3+
export function isReconnectAdvisory(message: string): boolean {
4+
return RECONNECTING_ADVISORY_RE.test(message);
5+
}

tests/engine.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Semaphore } from "../engine/semaphore.ts";
1010
import { normalizeSchema, parseAndValidate } from "../engine/schema.ts";
1111
import { resolveBackend } from "../adapters/registry.ts";
1212
import { OpenAIResponsesAdapter } from "../adapters/openai-responses.ts";
13+
import { isReconnectAdvisory } from "../adapters/stream-errors.ts";
1314

1415
async function tempDir(): Promise<string> {
1516
return mkdtemp(path.join(tmpdir(), "codex-workflow-test-"));
@@ -548,6 +549,14 @@ describe("dynamic workflow engine", () => {
548549
await rm(dir, { recursive: true, force: true });
549550
});
550551

552+
it("treats prefixed Reconnecting stream messages as advisory", () => {
553+
assert.equal(isReconnectAdvisory("Reconnecting... 1/5"), true);
554+
assert.equal(isReconnectAdvisory("error: Reconnecting... 1/5"), true);
555+
assert.equal(isReconnectAdvisory("[warn] Reconnecting... 1/5"), true);
556+
assert.equal(isReconnectAdvisory("fatal reconnecting failed"), false);
557+
assert.equal(isReconnectAdvisory("error: authentication failed"), false);
558+
});
559+
551560
it("retries transient adapter errors without consuming schema repair attempts", async () => {
552561
const dir = await tempDir();
553562
const journalPath = path.join(dir, "journal.jsonl");

0 commit comments

Comments
 (0)