mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 20:22:45 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcf6d0ac71 | ||
|
|
292d864f0e |
+72
-15
@@ -1,7 +1,10 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { createPiExtensionHost } from "../index.js";
|
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", () => {
|
describe("@tintinweb/pi-subagents adapter", () => {
|
||||||
test("exposes the background output file while the child is running", () => {
|
test("exposes the background output file while the child is running", () => {
|
||||||
@@ -13,51 +16,105 @@ describe("@tintinweb/pi-subagents adapter", () => {
|
|||||||
result: {
|
result: {
|
||||||
details: { agentId: "native-1", status: "background" },
|
details: { agentId: "native-1", status: "background" },
|
||||||
content: [
|
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(mapping?.subagents).toEqual([
|
||||||
expect.objectContaining({ id: "call-1", status: "running" }),
|
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 () => {
|
test("maps captured foreground lifecycle live and on replay", async () => {
|
||||||
const events = await verifySubagentFixture(
|
const events = await verifySubagentFixture(
|
||||||
readSubagentFixture(new URL("./fixtures/foreground.json", import.meta.url)),
|
readSubagentFixture(
|
||||||
|
new URL("./fixtures/foreground.json", import.meta.url)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
events
|
events
|
||||||
.filter((event) => event.event.type === "upsert")
|
.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"]);
|
).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 () => {
|
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 = (
|
const file = (
|
||||||
source.messages.find((message) => message.role === "custom") as {
|
source.messages.find((message) => message.role === "custom") as {
|
||||||
details: { outputFile: string };
|
details: { outputFile: string };
|
||||||
}
|
}
|
||||||
).details.outputFile;
|
).details.outputFile;
|
||||||
const fixture = readSubagentFixture(new URL("./fixtures/background.json", import.meta.url), {
|
const fixture = readSubagentFixture(
|
||||||
from: file,
|
new URL("./fixtures/background.json", import.meta.url),
|
||||||
to: fileURLToPath(new URL("./fixtures/child-session.jsonl", import.meta.url)),
|
{
|
||||||
});
|
from: file,
|
||||||
|
to: fileURLToPath(
|
||||||
|
new URL("./fixtures/child-session.jsonl", import.meta.url)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
const events = await verifySubagentFixture(fixture);
|
const events = await verifySubagentFixture(fixture);
|
||||||
expect(
|
expect(
|
||||||
events
|
events
|
||||||
.filter((event) => event.event.type === "upsert")
|
.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"]);
|
).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 () => {
|
test("completes every background child in a grouped notification", async () => {
|
||||||
const events = await verifySubagentFixture(
|
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>();
|
const finalStatus = new Map<string, string>();
|
||||||
for (const { event } of events) {
|
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({
|
expect(Object.fromEntries(finalStatus)).toEqual({
|
||||||
call_277173: "completed",
|
call_277173: "completed",
|
||||||
@@ -73,7 +130,7 @@ describe("@tintinweb/pi-subagents adapter", () => {
|
|||||||
args: { prompt: "foo" },
|
args: { prompt: "foo" },
|
||||||
status: "completed",
|
status: "completed",
|
||||||
result: { details: { agentId: "other", status: "completed" } },
|
result: { details: { agentId: "other", status: "completed" } },
|
||||||
}),
|
})
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user