Compare commits

...
Author SHA1 Message Date
paseo-bot[bot] dcf6d0ac71 style: format reproduction test 2026-10-07 05:49:32 +02:00
paseo-bot[bot] 292d864f0e test(pi): reproduce empty Tintinweb foreground subagent transcript (#5828)
Failing reproduction only. The captured @tintinweb/pi-subagents 0.19.0
foreground Agent result has no Output file line, so the adapter hands
Paseo no child transcript to read.
2026-10-07 05:49:28 +02:00
@@ -1,7 +1,10 @@
import { describe, expect, test } from "vitest";
import { fileURLToPath } from "node:url";
import { createPiExtensionHost } from "../index.js";
import { readSubagentFixture, verifySubagentFixture } from "../subagent-fixture-test.js";
import {
readSubagentFixture,
verifySubagentFixture,
} from "../subagent-fixture-test.js";
describe("@tintinweb/pi-subagents adapter", () => {
test("exposes the background output file while the child is running", () => {
@@ -13,51 +16,105 @@ describe("@tintinweb/pi-subagents adapter", () => {
result: {
details: { agentId: "native-1", status: "background" },
content: [
{ type: "text", text: "Agent started in background.\nOutput file: /tmp/child.output\n" },
{
type: "text",
text: "Agent started in background.\nOutput file: /tmp/child.output\n",
},
],
},
});
expect(mapping?.subagents).toEqual([
expect.objectContaining({ id: "call-1", status: "running" }),
]);
expect(mapping?.childSessions).toEqual([{ id: "call-1", file: "/tmp/child.output" }]);
expect(mapping?.childSessions).toEqual([
{ id: "call-1", file: "/tmp/child.output" },
]);
});
test("maps captured foreground lifecycle live and on replay", async () => {
const events = await verifySubagentFixture(
readSubagentFixture(new URL("./fixtures/foreground.json", import.meta.url)),
readSubagentFixture(
new URL("./fixtures/foreground.json", import.meta.url)
)
);
expect(
events
.filter((event) => event.event.type === "upsert")
.map((event) => (event.event.type === "upsert" ? event.event.status : null)),
.map((event) =>
event.event.type === "upsert" ? event.event.status : null
)
).toEqual(["running", "completed"]);
});
// #5828: the extension writes a transcript for foreground agents too, but its
// foreground result carries no `Output file:` line, so the child opens empty.
test("exposes the foreground child's transcript when it completes", () => {
const fixture = readSubagentFixture(
new URL("./fixtures/foreground.json", import.meta.url)
);
const end = fixture.events.find(
(event) => event.type === "tool_execution_end"
) as {
toolCallId: string;
result: Parameters<
ReturnType<typeof createPiExtensionHost>["mapToolCall"]
>[0]["result"];
};
const mapping = createPiExtensionHost().mapToolCall({
callId: end.toolCallId,
toolName: "Agent",
args: {
subagent_type: "general-purpose",
prompt: "list the files in this empty workspace",
},
status: "completed",
result: end.result,
});
expect(mapping?.subagents).toEqual([
expect.objectContaining({ id: end.toolCallId, status: "completed" }),
]);
expect(mapping?.childSessions).toEqual([
{ id: end.toolCallId, file: expect.any(String) },
]);
});
test("uses a structured notification to complete a background child", async () => {
const source = readSubagentFixture(new URL("./fixtures/background.json", import.meta.url));
const source = readSubagentFixture(
new URL("./fixtures/background.json", import.meta.url)
);
const file = (
source.messages.find((message) => message.role === "custom") as {
details: { outputFile: string };
}
).details.outputFile;
const fixture = readSubagentFixture(new URL("./fixtures/background.json", import.meta.url), {
from: file,
to: fileURLToPath(new URL("./fixtures/child-session.jsonl", import.meta.url)),
});
const fixture = readSubagentFixture(
new URL("./fixtures/background.json", import.meta.url),
{
from: file,
to: fileURLToPath(
new URL("./fixtures/child-session.jsonl", import.meta.url)
),
}
);
const events = await verifySubagentFixture(fixture);
expect(
events
.filter((event) => event.event.type === "upsert")
.map((event) => (event.event.type === "upsert" ? event.event.status : null)),
.map((event) =>
event.event.type === "upsert" ? event.event.status : null
)
).toEqual(["running", "running", "completed"]);
expect(events.filter((event) => event.event.type === "timeline").length).toBeGreaterThan(0);
expect(
events.filter((event) => event.event.type === "timeline").length
).toBeGreaterThan(0);
});
test("completes every background child in a grouped notification", async () => {
const events = await verifySubagentFixture(
readSubagentFixture(new URL("./fixtures/background-group.json", import.meta.url)),
readSubagentFixture(
new URL("./fixtures/background-group.json", import.meta.url)
)
);
const finalStatus = new Map<string, string>();
for (const { event } of events) {
if (event.type === "upsert" && event.status) finalStatus.set(event.id, event.status);
if (event.type === "upsert" && event.status)
finalStatus.set(event.id, event.status);
}
expect(Object.fromEntries(finalStatus)).toEqual({
call_277173: "completed",
@@ -73,7 +130,7 @@ describe("@tintinweb/pi-subagents adapter", () => {
args: { prompt: "foo" },
status: "completed",
result: { details: { agentId: "other", status: "completed" } },
}),
})
).toBeUndefined();
});
});