




















@@ -6064,6 +6064,92 @@ describe("runCodexAppServerAttempt", () => {
60646064expect(agentEndContext.sessionId).toBe("session-1");
60656065});
606660666067+it("waits for agent_end hooks before resolving local codex turns", async () => {
6068+let releaseAgentEnd: () => void = () => undefined;
6069+const agentEndSettled = new Promise<void>((resolve) => {
6070+releaseAgentEnd = resolve;
6071+});
6072+const agentEnd = vi.fn(() => agentEndSettled);
6073+initializeGlobalHookRunner(
6074+createMockPluginRegistry([{ hookName: "agent_end", handler: agentEnd }]),
6075+);
6076+const sessionFile = path.join(tempDir, "session.jsonl");
6077+const workspaceDir = path.join(tempDir, "workspace");
6078+const harness = createStartedThreadHarness();
6079+const run = runCodexAppServerAttempt(createParams(sessionFile, workspaceDir));
6080+let settled = false;
6081+void run.then(() => {
6082+settled = true;
6083+});
6084+6085+await harness.waitForMethod("turn/start");
6086+await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
6087+6088+await vi.waitFor(() => expect(agentEnd).toHaveBeenCalledTimes(1), fastWait);
6089+expect(settled).toBe(false);
6090+releaseAgentEnd();
6091+await expect(run).resolves.toMatchObject({ promptError: null });
6092+expect(settled).toBe(true);
6093+});
6094+6095+it("does not wait for agent_end hooks before resolving channel-backed codex turns", async () => {
6096+let releaseAgentEnd: () => void = () => undefined;
6097+const agentEndSettled = new Promise<void>((resolve) => {
6098+releaseAgentEnd = resolve;
6099+});
6100+const agentEnd = vi.fn(() => agentEndSettled);
6101+initializeGlobalHookRunner(
6102+createMockPluginRegistry([{ hookName: "agent_end", handler: agentEnd }]),
6103+);
6104+const sessionFile = path.join(tempDir, "session.jsonl");
6105+const workspaceDir = path.join(tempDir, "workspace");
6106+const harness = createStartedThreadHarness();
6107+const params = createParams(sessionFile, workspaceDir);
6108+params.messageChannel = "discord";
6109+params.messageProvider = "discord";
6110+const run = runCodexAppServerAttempt(params);
6111+6112+await harness.waitForMethod("turn/start");
6113+await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
6114+const result = await run;
6115+6116+expect(result.promptError).toBeNull();
6117+expect(agentEnd).toHaveBeenCalledTimes(1);
6118+releaseAgentEnd();
6119+});
6120+6121+it("waits for agent_end hooks before rejecting local codex turn-start failures", async () => {
6122+let releaseAgentEnd: () => void = () => undefined;
6123+const agentEndSettled = new Promise<void>((resolve) => {
6124+releaseAgentEnd = resolve;
6125+});
6126+const agentEnd = vi.fn(() => agentEndSettled);
6127+initializeGlobalHookRunner(
6128+createMockPluginRegistry([{ hookName: "agent_end", handler: agentEnd }]),
6129+);
6130+const sessionFile = path.join(tempDir, "session.jsonl");
6131+const workspaceDir = path.join(tempDir, "workspace");
6132+createStartedThreadHarness(async (method) => {
6133+if (method === "turn/start") {
6134+throw new Error("turn start exploded");
6135+}
6136+return undefined;
6137+});
6138+const run = runCodexAppServerAttempt(createParams(sessionFile, workspaceDir));
6139+let rejected = false;
6140+void run.catch(() => {
6141+rejected = true;
6142+});
6143+6144+await vi.waitFor(() => expect(agentEnd).toHaveBeenCalledTimes(1), fastWait);
6145+await new Promise<void>((resolve) => setImmediate(resolve));
6146+6147+expect(rejected).toBe(false);
6148+releaseAgentEnd();
6149+await expect(run).rejects.toThrow("turn start exploded");
6150+expect(rejected).toBe(true);
6151+});
6152+60676153it("forwards Codex app-server verbose tool summaries and completed output", async () => {
60686154const onToolResult = vi.fn();
60696155const sessionFile = path.join(tempDir, "session.jsonl");
@@ -6663,6 +6749,7 @@ describe("runCodexAppServerAttempt", () => {
66636749expect(harness.requests.map((request) => request.method)).toEqual([
66646750"thread/start",
66656751"turn/start",
6752+"thread/unsubscribe",
66666753]);
66676754const binding = await readCodexAppServerBinding(sessionFile);
66686755expect(binding?.threadId).toBe("thread-existing");
@@ -6689,6 +6776,7 @@ describe("runCodexAppServerAttempt", () => {
66896776expect(harness.requests.map((request) => request.method)).toEqual([
66906777"thread/resume",
66916778"turn/start",
6779+"thread/unsubscribe",
66926780]);
66936781const binding = await readCodexAppServerBinding(sessionFile);
66946782expect(binding?.threadId).toBe("thread-existing");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。