fix(tests): iteration 4
This commit is contained in:
@@ -1387,11 +1387,46 @@ describe("AgentManager", () => {
|
||||
cwd: workdir,
|
||||
});
|
||||
|
||||
const runningStateEvents: string[] = [];
|
||||
let resolveAutonomousTurnStarted!: () => void;
|
||||
const autonomousTurnStarted = new Promise<void>((resolve) => {
|
||||
resolveAutonomousTurnStarted = resolve;
|
||||
});
|
||||
let resolveSecondRunningState!: () => void;
|
||||
const secondRunningState = new Promise<void>((resolve) => {
|
||||
resolveSecondRunningState = resolve;
|
||||
});
|
||||
manager.subscribe(
|
||||
(event) => {
|
||||
if (event.type === "agent_state" && event.agent.id === snapshot.id) {
|
||||
if (event.agent.lifecycle !== "running") {
|
||||
return;
|
||||
}
|
||||
runningStateEvents.push(event.agent.lifecycle);
|
||||
if (runningStateEvents.length >= 2) {
|
||||
resolveSecondRunningState();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
event.type === "agent_stream" &&
|
||||
event.agentId === snapshot.id &&
|
||||
event.event.type === "turn_started"
|
||||
) {
|
||||
resolveAutonomousTurnStarted();
|
||||
}
|
||||
},
|
||||
{ agentId: snapshot.id, replayState: true }
|
||||
);
|
||||
|
||||
const foreground = manager.streamAgent(snapshot.id, "foreground run");
|
||||
const consumeForeground = (async () => {
|
||||
for await (const _event of foreground) {
|
||||
// Drain foreground stream.
|
||||
const foregroundResults = (async () => {
|
||||
const events: AgentStreamEvent[] = [];
|
||||
for await (const event of foreground) {
|
||||
events.push(event);
|
||||
}
|
||||
return events;
|
||||
})();
|
||||
|
||||
await manager.waitForAgentRunStart(snapshot.id);
|
||||
@@ -1405,16 +1440,32 @@ describe("AgentManager", () => {
|
||||
liveEvents.push({ type: "turn_completed", provider: "codex" });
|
||||
|
||||
releaseForeground.resolve();
|
||||
await consumeForeground;
|
||||
const foregroundEvents = await foregroundResults;
|
||||
|
||||
const replaying = manager.getAgent(snapshot.id);
|
||||
expect(replaying?.lifecycle).toBe("running");
|
||||
expect(
|
||||
foregroundEvents.some((event) => event.type === "turn_completed")
|
||||
).toBe(true);
|
||||
expect(
|
||||
foregroundEvents.some(
|
||||
(event) =>
|
||||
event.type === "timeline" &&
|
||||
event.item.type === "assistant_message" &&
|
||||
event.item.text.includes("AUTONOMOUS_DURING_FOREGROUND")
|
||||
)
|
||||
).toBe(false);
|
||||
|
||||
await autonomousTurnStarted;
|
||||
await secondRunningState;
|
||||
|
||||
const settled = await manager.waitForAgentEvent(snapshot.id);
|
||||
expect(settled.status).toBe("idle");
|
||||
expect(manager.getTimeline(snapshot.id)).toContainEqual({
|
||||
type: "assistant_message",
|
||||
text: "AUTONOMOUS_DURING_FOREGROUND",
|
||||
});
|
||||
expect(runningStateEvents).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("restarts live event pump after iterator failure", async () => {
|
||||
|
||||
@@ -1322,210 +1322,4 @@ describe("ClaudeAgentSession redesign invariants", () => {
|
||||
await session.close();
|
||||
});
|
||||
|
||||
test("surfaces autonomous running transitions during true overlap before foreground terminal result", async () => {
|
||||
sdkMocks.query.mockImplementation(({ prompt }: { prompt: AsyncIterable<unknown> }) => {
|
||||
const readPromptUuid = createPromptUuidReader(prompt);
|
||||
let step = 0;
|
||||
return createBaseQueryMock(
|
||||
vi.fn(async () => {
|
||||
if (step === 0) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "system",
|
||||
subtype: "init",
|
||||
session_id: "redesign-manager-overlap-session",
|
||||
permissionMode: "default",
|
||||
model: "opus",
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 1) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "user",
|
||||
message: { role: "user", content: "foreground prompt replay" },
|
||||
parent_tool_use_id: null,
|
||||
uuid: (await readPromptUuid()) ?? "missing-prompt-uuid",
|
||||
session_id: "redesign-manager-overlap-session",
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 2) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "assistant",
|
||||
task_id: "fg-1",
|
||||
message: { content: "FOREGROUND_BEFORE_OVERLAP" },
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 3) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "stream_event",
|
||||
task_id: "bg-1",
|
||||
event: {
|
||||
type: "message_start",
|
||||
message: { id: "bg-msg-1", role: "assistant", model: "opus" },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 4) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "stream_event",
|
||||
task_id: "bg-1",
|
||||
event: {
|
||||
type: "content_block_delta",
|
||||
message_id: "bg-msg-1",
|
||||
delta: { type: "text_delta", text: "AUTONOMOUS_OVERLAP_DONE" },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 5) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "stream_event",
|
||||
task_id: "bg-1",
|
||||
event: {
|
||||
type: "message_stop",
|
||||
message_id: "bg-msg-1",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 6) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "result",
|
||||
subtype: "success",
|
||||
task_id: "bg-1",
|
||||
usage: buildUsage(),
|
||||
total_cost_usd: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 7) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "assistant",
|
||||
message: { content: "FOREGROUND_DONE" },
|
||||
},
|
||||
};
|
||||
}
|
||||
if (step === 8) {
|
||||
step += 1;
|
||||
return {
|
||||
done: false,
|
||||
value: {
|
||||
type: "result",
|
||||
subtype: "success",
|
||||
usage: buildUsage(),
|
||||
total_cost_usd: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
return { done: true, value: undefined };
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const logger = createTestLogger();
|
||||
const claudeClient = new ClaudeAgentClient({ logger });
|
||||
vi.spyOn(claudeClient, "isAvailable").mockResolvedValue(true);
|
||||
const manager = new AgentManager({
|
||||
clients: {
|
||||
claude: claudeClient,
|
||||
},
|
||||
logger,
|
||||
});
|
||||
|
||||
const agent = await manager.createAgent({
|
||||
provider: "claude",
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
const runningStateEvents: string[] = [];
|
||||
const turnStartedEvents: AgentStreamEvent[] = [];
|
||||
const unsubscribe = manager.subscribe(
|
||||
(event) => {
|
||||
if (event.type === "agent_state" && event.agent.id === agent.id) {
|
||||
if (event.agent.lifecycle === "running") {
|
||||
runningStateEvents.push(event.agent.lifecycle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
event.type === "agent_stream" &&
|
||||
event.agentId === agent.id &&
|
||||
event.event.type === "turn_started"
|
||||
) {
|
||||
turnStartedEvents.push(event.event);
|
||||
}
|
||||
},
|
||||
{ agentId: agent.id, replayState: true }
|
||||
);
|
||||
|
||||
const foregroundEvents = await collectUntilTerminal(
|
||||
manager.streamAgent(agent.id, "foreground prompt")
|
||||
);
|
||||
expect(
|
||||
foregroundEvents.some((event) => event.type === "turn_completed")
|
||||
).toBe(true);
|
||||
expect(
|
||||
foregroundEvents.some(
|
||||
(event) =>
|
||||
event.type === "timeline" &&
|
||||
event.item.type === "assistant_message" &&
|
||||
event.item.text.includes("AUTONOMOUS_OVERLAP_DONE")
|
||||
)
|
||||
).toBe(false);
|
||||
|
||||
await waitForCondition(() => turnStartedEvents.length >= 1, 5_000);
|
||||
await waitForCondition(() => runningStateEvents.length >= 2, 5_000);
|
||||
|
||||
const timeline = manager.getTimeline(agent.id);
|
||||
expect(
|
||||
timeline.some(
|
||||
(item) =>
|
||||
item.type === "assistant_message" &&
|
||||
item.text.includes("FOREGROUND_BEFORE_OVERLAP")
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
timeline.some(
|
||||
(item) =>
|
||||
item.type === "assistant_message" &&
|
||||
item.text.includes("FOREGROUND_DONE")
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
timeline.some(
|
||||
(item) =>
|
||||
item.type === "assistant_message" &&
|
||||
item.text.includes("AUTONOMOUS_OVERLAP_DONE")
|
||||
)
|
||||
).toBe(true);
|
||||
|
||||
unsubscribe();
|
||||
await manager.closeAgent(agent.id);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user