






















@@ -370,6 +370,79 @@ describe("runCodexAppServerAttempt", () => {
370370expect(onTimeout).toHaveBeenCalledTimes(1);
371371});
372372373+it("releases the session when Codex never completes after a dynamic tool response", async () => {
374+let handleRequest:
375+| ((request: { id: string; method: string; params?: unknown }) => Promise<unknown>)
376+| undefined;
377+const request = vi.fn(async (method: string) => {
378+if (method === "thread/start") {
379+return threadStartResult("thread-1");
380+}
381+if (method === "turn/start") {
382+return turnStartResult("turn-1", "inProgress");
383+}
384+return {};
385+});
386+__testing.setCodexAppServerClientFactoryForTests(
387+async () =>
388+({
389+ request,
390+addNotificationHandler: () => () => undefined,
391+addRequestHandler: (
392+handler: (request: {
393+id: string;
394+method: string;
395+params?: unknown;
396+}) => Promise<unknown>,
397+) => {
398+handleRequest = handler;
399+return () => undefined;
400+},
401+}) as never,
402+);
403+const params = createParams(
404+path.join(tempDir, "session.jsonl"),
405+path.join(tempDir, "workspace"),
406+);
407+params.timeoutMs = 60_000;
408+409+const run = runCodexAppServerAttempt(params, { turnCompletionIdleTimeoutMs: 5 });
410+await vi.waitFor(() => expect(handleRequest).toBeTypeOf("function"), { interval: 1 });
411+412+await expect(
413+handleRequest?.({
414+id: "request-tool-1",
415+method: "item/tool/call",
416+params: {
417+threadId: "thread-1",
418+turnId: "turn-1",
419+callId: "call-1",
420+namespace: null,
421+tool: "message",
422+arguments: { action: "send", text: "already sent" },
423+},
424+}),
425+).resolves.toMatchObject({
426+success: false,
427+contentItems: [{ type: "inputText", text: "Unknown OpenClaw tool: message" }],
428+});
429+430+await expect(run).resolves.toMatchObject({
431+aborted: true,
432+timedOut: true,
433+promptError: "codex app-server turn idle timed out waiting for turn/completed",
434+});
435+await vi.waitFor(
436+() =>
437+expect(request).toHaveBeenCalledWith("turn/interrupt", {
438+threadId: "thread-1",
439+turnId: "turn-1",
440+}),
441+{ interval: 1 },
442+);
443+expect(queueAgentHarnessMessage("session-1", "after timeout")).toBe(false);
444+});
445+373446it("applies before_prompt_build to Codex developer instructions and turn input", async () => {
374447const beforePromptBuild = vi.fn(async () => ({
375448systemPrompt: "custom codex system",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。