mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-07 00:44:49 +00:00
fix(subagents): retain history across hydration
This commit is contained in:
@@ -2885,6 +2885,11 @@ test("archiveFinishedSubagents archives managed children and keeps dismissed pro
|
||||
workspaceId: undefined,
|
||||
},
|
||||
);
|
||||
const managedWithRunningProviderDescendant = await manager.createAgent(
|
||||
{ provider: "codex", cwd: workdir },
|
||||
undefined,
|
||||
{ labels: { [PARENT_AGENT_ID_LABEL]: parent.id }, workspaceId: undefined },
|
||||
);
|
||||
client.sessions[3]?.pushEvent({
|
||||
type: "turn_started",
|
||||
provider: "codex",
|
||||
@@ -2893,6 +2898,19 @@ test("archiveFinishedSubagents archives managed children and keeps dismissed pro
|
||||
await vi.waitFor(() => {
|
||||
expect(manager.getAgent(runningGrandchild.id)?.lifecycle).toBe("running");
|
||||
});
|
||||
client.sessions[4]?.pushEvent({
|
||||
type: "provider_subagent",
|
||||
provider: "codex",
|
||||
event: { type: "upsert", id: "running-provider-grandchild", status: "running" },
|
||||
});
|
||||
await vi.waitFor(() => {
|
||||
expect(
|
||||
manager.getProviderSubagent(
|
||||
managedWithRunningProviderDescendant.id,
|
||||
"running-provider-grandchild",
|
||||
)?.status,
|
||||
).toBe("running");
|
||||
});
|
||||
await manager.hydrateTimelineFromProvider(parent.id);
|
||||
|
||||
const result = await manager.archiveFinishedSubagents(parent.id);
|
||||
@@ -2903,6 +2921,7 @@ test("archiveFinishedSubagents archives managed children and keeps dismissed pro
|
||||
});
|
||||
expectArchivedAgentRecord(await storage.get(managedFinished.id), "closed");
|
||||
expect((await storage.get(managedWithRunningDescendant.id))?.archivedAt).toBeFalsy();
|
||||
expect((await storage.get(managedWithRunningProviderDescendant.id))?.archivedAt).toBeFalsy();
|
||||
expect(manager.getAgent(runningGrandchild.id)?.lifecycle).toBe("running");
|
||||
expect(manager.listProviderSubagents(parent.id).map((subagent) => subagent.id)).toEqual([
|
||||
"native-running",
|
||||
@@ -2927,6 +2946,11 @@ test("archiveFinishedSubagents archives managed children and keeps dismissed pro
|
||||
expect(manager.listProviderSubagents(parent.id).map((subagent) => subagent.id)).toEqual([
|
||||
"native-running",
|
||||
]);
|
||||
expect(manager.getProviderSubagent(parent.id, "native-finished")).toMatchObject({
|
||||
id: "native-finished",
|
||||
status: "completed",
|
||||
});
|
||||
expect(() => manager.fetchProviderSubagentTimeline(parent.id, "native-finished")).not.toThrow();
|
||||
});
|
||||
|
||||
test("force provider hydration removes children absent from current history", async () => {
|
||||
|
||||
@@ -985,6 +985,9 @@ export class AgentManager {
|
||||
const hasBusyDescendant = (agentId: string, visited = new Set<string>()): boolean => {
|
||||
if (visited.has(agentId)) return true;
|
||||
visited.add(agentId);
|
||||
if (this.providerSubagents.list(agentId).some((subagent) => subagent.status === "running")) {
|
||||
return true;
|
||||
}
|
||||
for (const child of recordsByParentId.get(agentId) ?? []) {
|
||||
const liveChild = this.agents.get(child.id);
|
||||
if (
|
||||
@@ -2980,8 +2983,9 @@ export class AgentManager {
|
||||
private applyProviderSubagentEvent(
|
||||
agent: ManagedAgent,
|
||||
event: Extract<AgentStreamEvent, { type: "provider_subagent" }>,
|
||||
options?: { includeDismissed?: boolean },
|
||||
): ProviderSubagentStoreEvent | null {
|
||||
if (agent.dismissedProviderSubagentIds.has(event.event.id)) {
|
||||
if (!options?.includeDismissed && agent.dismissedProviderSubagentIds.has(event.event.id)) {
|
||||
return null;
|
||||
}
|
||||
return this.providerSubagents.apply(agent.id, event.provider, event.event);
|
||||
@@ -3120,12 +3124,18 @@ export class AgentManager {
|
||||
|
||||
for (const event of this.providerSubagents.deleteParent(agent.id)) {
|
||||
if (broadcast) {
|
||||
this.dispatch({ type: "provider_subagent", event });
|
||||
this.dispatch({
|
||||
type: "provider_subagent",
|
||||
event: agent.dismissedProviderSubagentIds.has(event.subagentId)
|
||||
? { ...event, retainTimeline: true }
|
||||
: event,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const event of providerSubagentEvents) {
|
||||
const update = this.applyProviderSubagentEvent(agent, event);
|
||||
if (broadcast && update) {
|
||||
const dismissed = agent.dismissedProviderSubagentIds.has(event.event.id);
|
||||
const update = this.applyProviderSubagentEvent(agent, event, { includeDismissed: true });
|
||||
if (broadcast && update && !dismissed) {
|
||||
this.dispatch({ type: "provider_subagent", event: update });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +160,8 @@ export class ProviderSubagentStore {
|
||||
};
|
||||
}
|
||||
|
||||
deleteParent(parentAgentId: string): ProviderSubagentStoreEvent[] {
|
||||
const events: ProviderSubagentStoreEvent[] = [];
|
||||
deleteParent(parentAgentId: string): Extract<ProviderSubagentStoreEvent, { type: "remove" }>[] {
|
||||
const events: Extract<ProviderSubagentStoreEvent, { type: "remove" }>[] = [];
|
||||
for (const subagent of this.list(parentAgentId)) {
|
||||
const key = storeKey(parentAgentId, subagent.id);
|
||||
this.descriptors.delete(key);
|
||||
|
||||
@@ -246,7 +246,7 @@ describe("codex tool-call mapper", () => {
|
||||
detail: {
|
||||
type: "sub_agent",
|
||||
subAgentType: "research/investigator",
|
||||
description: "/root/research/investigator",
|
||||
description: "research/investigator",
|
||||
log: "",
|
||||
actions: [],
|
||||
},
|
||||
@@ -280,7 +280,7 @@ describe("codex tool-call mapper", () => {
|
||||
detail: {
|
||||
type: "sub_agent",
|
||||
subAgentType: "investigator",
|
||||
description: "/tmp/native/investigator",
|
||||
description: "investigator",
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -298,7 +298,7 @@ describe("codex tool-call mapper", () => {
|
||||
detail: {
|
||||
type: "sub_agent",
|
||||
subAgentType: "investigator",
|
||||
description: "C:\\Users\\dev\\agents\\investigator",
|
||||
description: "investigator",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1003,6 +1003,7 @@ function mapSubAgentActivityItem(
|
||||
Math.max(nativeName.lastIndexOf("/"), nativeName.lastIndexOf("\\")) + 1,
|
||||
);
|
||||
}
|
||||
const description = nativeName;
|
||||
nativeName ||= "Sub-agent";
|
||||
return {
|
||||
type: "tool_call",
|
||||
@@ -1013,7 +1014,7 @@ function mapSubAgentActivityItem(
|
||||
detail: {
|
||||
type: "sub_agent",
|
||||
subAgentType: nativeName,
|
||||
description: item.agentPath,
|
||||
description,
|
||||
log: "",
|
||||
actions: [],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user