

















@@ -5618,6 +5618,70 @@ describe("runCodexAppServerAttempt", () => {
56185618await expect(run).resolves.toMatchObject({ aborted: false, timedOut: false });
56195619});
562056205621+it("does not idle-timeout when terminal completion queues behind projection", async () => {
5622+const harness = createStartedThreadHarness();
5623+const params = createParams(
5624+path.join(tempDir, "session.jsonl"),
5625+path.join(tempDir, "workspace"),
5626+);
5627+params.timeoutMs = 120;
5628+const turnStartProgressEvents: DiagnosticEventPayload[] = [];
5629+const stopDiagnostics = onInternalDiagnosticEvent((event) => {
5630+if (event.type === "run.progress" && event.reason === "codex_app_server:turn:start") {
5631+turnStartProgressEvents.push(event);
5632+}
5633+});
5634+let resolveReasoningStarted!: () => void;
5635+const reasoningStarted = new Promise<void>((resolve) => {
5636+resolveReasoningStarted = resolve;
5637+});
5638+let releaseProjection!: () => void;
5639+const projectionGate = new Promise<void>((resolve) => {
5640+releaseProjection = resolve;
5641+});
5642+params.onReasoningStream = async () => {
5643+resolveReasoningStarted();
5644+await projectionGate;
5645+};
5646+5647+let settled = false;
5648+const run = runCodexAppServerAttempt(params, {
5649+turnCompletionIdleTimeoutMs: 5,
5650+turnTerminalIdleTimeoutMs: 5,
5651+}).finally(() => {
5652+settled = true;
5653+});
5654+await harness.waitForMethod("turn/start");
5655+await vi.waitFor(() => expect(turnStartProgressEvents).toHaveLength(2), { interval: 1 });
5656+stopDiagnostics();
5657+5658+const blockedProjection = harness.notify({
5659+method: "item/reasoning/textDelta",
5660+params: {
5661+threadId: "thread-1",
5662+turnId: "turn-1",
5663+itemId: "reasoning-1",
5664+delta: "thinking",
5665+},
5666+});
5667+void blockedProjection.catch(() => undefined);
5668+await reasoningStarted;
5669+5670+const queuedTerminal = harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
5671+void queuedTerminal.catch(() => undefined);
5672+await new Promise((resolve) => setTimeout(resolve, 30));
5673+5674+expect(settled).toBe(false);
5675+expect(harness.request.mock.calls.some(([method]) => method === "turn/interrupt")).toBe(false);
5676+5677+releaseProjection();
5678+await queuedTerminal;
5679+const result = await run;
5680+expect(result.aborted).toBe(false);
5681+expect(result.timedOut).toBe(false);
5682+expect(result.promptError).toBeNull();
5683+});
5684+56215685it("releases the session when a completed agent message item goes quiet", async () => {
56225686let notify: (notification: CodexServerNotification) => Promise<void> = async () => undefined;
56235687const request = vi.fn(async (method: string) => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。