





















@@ -273,6 +273,134 @@ describe("CodexNativeSubagentTaskMirror", () => {
273273});
274274});
275275276+it("finalizes stale collab agent state from the blocked tool call status", () => {
277+const runtime = createRuntime();
278+const mirror = new CodexNativeSubagentTaskMirror(
279+{
280+parentThreadId: "parent-thread",
281+requesterSessionKey: "agent:main:main",
282+now: () => 45_000,
283+},
284+runtime,
285+);
286+287+mirror.handleNotification({
288+method: "item/completed",
289+params: {
290+item: {
291+type: "collabAgentToolCall",
292+tool: "spawnAgent",
293+status: "blocked",
294+senderThreadId: "parent-thread",
295+receiverThreadIds: ["child-thread"],
296+prompt: "read cwd",
297+agentsStates: {
298+"child-thread": {
299+status: "pendingInit",
300+message: "Native hook relay unavailable",
301+},
302+},
303+},
304+},
305+});
306+307+expect(runtime.recordTaskRunProgressByRunId).not.toHaveBeenCalledWith({
308+runId: "codex-thread:child-thread",
309+runtime: "subagent",
310+lastEventAt: 45_000,
311+progressSummary: "Native hook relay unavailable",
312+});
313+expect(runtime.finalizeTaskRunByRunId).toHaveBeenCalledWith({
314+runId: "codex-thread:child-thread",
315+runtime: "subagent",
316+status: "succeeded",
317+endedAt: 45_000,
318+lastEventAt: 45_000,
319+progressSummary: "Native hook relay unavailable",
320+terminalSummary: "Native hook relay unavailable",
321+terminalOutcome: "blocked",
322+});
323+});
324+325+it("does not treat completed tool calls as completed subagents", () => {
326+const runtime = createRuntime();
327+const mirror = new CodexNativeSubagentTaskMirror(
328+{
329+parentThreadId: "parent-thread",
330+requesterSessionKey: "agent:main:main",
331+now: () => 46_000,
332+},
333+runtime,
334+);
335+336+mirror.handleNotification({
337+method: "item/completed",
338+params: {
339+item: {
340+type: "collabAgentToolCall",
341+tool: "spawnAgent",
342+status: "completed",
343+senderThreadId: "parent-thread",
344+receiverThreadIds: ["child-thread"],
345+prompt: "read cwd",
346+agentsStates: {
347+"child-thread": {
348+status: "pendingInit",
349+message: null,
350+},
351+},
352+},
353+},
354+});
355+356+expect(runtime.recordTaskRunProgressByRunId).toHaveBeenCalledWith({
357+runId: "codex-thread:child-thread",
358+runtime: "subagent",
359+lastEventAt: 46_000,
360+progressSummary: "Codex native subagent is initializing.",
361+});
362+expect(runtime.finalizeTaskRunByRunId).not.toHaveBeenCalled();
363+});
364+365+it("does not treat failed non-spawn tool calls as failed subagents", () => {
366+const runtime = createRuntime();
367+const mirror = new CodexNativeSubagentTaskMirror(
368+{
369+parentThreadId: "parent-thread",
370+requesterSessionKey: "agent:main:main",
371+now: () => 47_000,
372+},
373+runtime,
374+);
375+376+mirror.handleNotification({
377+method: "item/completed",
378+params: {
379+item: {
380+type: "collabAgentToolCall",
381+tool: "wait",
382+status: "failed",
383+senderThreadId: "parent-thread",
384+receiverThreadIds: [],
385+agentsStates: {
386+"child-thread": {
387+status: "running",
388+message: "wait timed out",
389+},
390+},
391+},
392+},
393+});
394+395+expect(runtime.recordTaskRunProgressByRunId).toHaveBeenCalledWith({
396+runId: "codex-thread:child-thread",
397+runtime: "subagent",
398+lastEventAt: 47_000,
399+progressSummary: "wait timed out",
400+});
401+expect(runtime.finalizeTaskRunByRunId).not.toHaveBeenCalled();
402+});
403+276404it("preserves a completed collab agent message when the thread later goes idle", () => {
277405const runtime = createRuntime();
278406const mirror = new CodexNativeSubagentTaskMirror(
@@ -322,6 +450,65 @@ describe("CodexNativeSubagentTaskMirror", () => {
322450});
323451});
324452453+it("lets terminal collab agent state correct an earlier idle thread status", () => {
454+const runtime = createRuntime();
455+const mirror = new CodexNativeSubagentTaskMirror(
456+{
457+parentThreadId: "parent-thread",
458+requesterSessionKey: "agent:main:main",
459+now: () => 55_000,
460+},
461+runtime,
462+);
463+464+mirror.handleNotification({
465+method: "thread/status/changed",
466+params: {
467+threadId: "child-thread",
468+status: { type: "idle" },
469+},
470+});
471+mirror.handleNotification({
472+method: "item/completed",
473+params: {
474+item: {
475+type: "collabAgentToolCall",
476+tool: "spawnAgent",
477+status: "failed",
478+senderThreadId: "parent-thread",
479+receiverThreadIds: ["child-thread"],
480+prompt: "read cwd",
481+agentsStates: {
482+"child-thread": {
483+status: "pendingInit",
484+message: "Native hook relay unavailable",
485+},
486+},
487+},
488+},
489+});
490+491+expect(runtime.finalizeTaskRunByRunId).toHaveBeenNthCalledWith(1, {
492+runId: "codex-thread:child-thread",
493+runtime: "subagent",
494+status: "succeeded",
495+endedAt: 55_000,
496+lastEventAt: 55_000,
497+progressSummary: "Codex native subagent is idle.",
498+terminalSummary: "Codex native subagent finished.",
499+});
500+expect(runtime.finalizeTaskRunByRunId).toHaveBeenNthCalledWith(2, {
501+runId: "codex-thread:child-thread",
502+runtime: "subagent",
503+status: "failed",
504+endedAt: 55_000,
505+lastEventAt: 55_000,
506+error: "Native hook relay unavailable",
507+progressSummary: "Native hook relay unavailable",
508+terminalSummary: "Native hook relay unavailable",
509+});
510+});
511+325512it("normalizes collab agent status spelling from alternate event surfaces", () => {
326513const runtime = createRuntime();
327514const mirror = new CodexNativeSubagentTaskMirror(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。