fix(runner): buffer pre-accept Codex items

This commit is contained in:
Dotta committed 2026-08-21 10:02:53 -05:00
1 parent 380e9f3aae
commit da934b6d3d
3 files changed
+21 -3

No files matched your search

@@ -1218,11 +1218,16 @@ describe("Codex app-server Codex driver", () => {
normalizedSessionId: "normalized-implicit-item-turn",
workingDirectory: "/workspace",
});
const turn = await session.startTurn({ message: { role: "user", text: "Complete." } });
let resolveTurnStart!: (value: Record<string, unknown>) => void;
transport.turnStartResponse = new Promise((resolve) => { resolveTurnStart = resolve; });
const starting = session.startTurn({ message: { role: "user", text: "Complete." } });
while (!transport.calls.some((call) => call.method === "turn/start")) await Promise.resolve();
transport.push("item/completed", {
threadId: "thread-1",
item: { id: "answer-implicit", type: "agentMessage", text: JSON.stringify(result) },
});
resolveTurnStart({ turn: { id: "turn-1", status: "inProgress", items: [] } });
const turn = await starting;
transport.push("turn/completed", {
threadId: "thread-1",
turn: { id: turn.turnId, status: "completed", items: [] },
@@ -663,6 +663,7 @@ class CodexHarnessSession implements HarnessSession {
#resultCallId: string | null = null;
#resultTurnId: string | null = null;
#turnStartPending = false;
readonly #pendingTurnNotifications: CodexRpcNotification[] = [];
#protocolFailed = false;
#protocolFailureCode: string | null = null;
#protocolFailureMessage: string | null = null;
@@ -822,6 +823,8 @@ class CodexHarnessSession implements HarnessSession {
}
this.#activeTurnId ??= turnId;
this.#emit("turn.accepted", { turnId }, { turnId });
const pendingTurnNotifications = this.#pendingTurnNotifications.splice(0);
for (const notification of pendingTurnNotifications) this.#mapNotification(notification);
if (this.#interruptQueued) {
this.#interruptQueued = false;
await this.#sendInterrupt(turnId, "queued_before_start");
@@ -1125,6 +1128,15 @@ class CodexHarnessSession implements HarnessSession {
const item = itemFromParams(params);
const threadId = text(params.threadId);
const explicitTurnId = text(params.turnId, text(turn.id));
if (
explicitTurnId.length === 0
&& this.#turnStartPending
&& this.#activeTurnId === null
&& (notification.method.startsWith("item/") || notification.method === "thread/tokenUsage/updated")
) {
this.#pendingTurnNotifications.push(structuredClone(notification));
return;
}
// Current Codex app-server builds omit turnId from some item notifications. This driver
// permits only one active turn, so a same-thread item can be bound to that turn without
// ambiguity. Pre-turn, cross-thread, stale, and post-terminal notifications still fail closed.
+3 -2
View File
@@ -1,4 +1,5 @@
// Development and test builds resolve the workspace package here. The server
// build replaces this compiled shim with the package's built distribution so
// Development and test builds resolve the workspace package here. Rebuild the package and restart
// the server after changing runner internals; the workspace export resolves through dist. The
// server build replaces this compiled shim with the package's built distribution so
// published server installs do not need a separate paperclip-runner npm bootstrap.
export * from "@paperclipai/paperclip-runner";