diff --git a/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/fixtures/background-group.json b/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/fixtures/background-group.json
new file mode 100644
index 0000000000..083e57744e
--- /dev/null
+++ b/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/fixtures/background-group.json
@@ -0,0 +1,419 @@
+{
+ "provenance": {
+ "package": "@tintinweb/pi-subagents",
+ "version": "0.19.0",
+ "sourceCommit": "4f572eaa04c09d3dbc16e4a5f13a16b295e84e14",
+ "piVersion": "0.84.4",
+ "captureDate": "2026-10-01"
+ },
+ "events": [
+ {
+ "type": "tool_execution_start",
+ "toolCallId": "call_277173",
+ "toolName": "Agent",
+ "args": {
+ "run_in_background": true,
+ "description": "Test agent 1",
+ "prompt": "reply with exactly OK",
+ "subagent_type": "general-purpose"
+ }
+ },
+ {
+ "type": "tool_execution_start",
+ "toolCallId": "call_277176",
+ "toolName": "Agent",
+ "args": {
+ "prompt": "reply with exactly OK",
+ "run_in_background": true,
+ "description": "Test agent 2",
+ "subagent_type": "general-purpose"
+ }
+ },
+ {
+ "type": "tool_execution_start",
+ "toolCallId": "call_277179",
+ "toolName": "Agent",
+ "args": {
+ "subagent_type": "general-purpose",
+ "description": "Test agent 3",
+ "prompt": "reply with exactly OK",
+ "run_in_background": true
+ }
+ },
+ {
+ "type": "tool_execution_end",
+ "toolCallId": "call_277173",
+ "toolName": "Agent",
+ "result": {
+ "content": [
+ {
+ "type": "text",
+ "text": "Agent started in background.\nAgent ID: 4b4fd01d-aaa8-46d\nType: Agent\nDescription: Test agent 1\nOutput file: /tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/4b4fd01d-aaa8-46d.output\n\nYou will be notified when this agent completes.\nUse get_subagent_result to retrieve full results, or steer_subagent to send it messages.\nDo not duplicate this agent's work."
+ }
+ ],
+ "details": {
+ "displayName": "Agent",
+ "description": "Test agent 1",
+ "subagentType": "general-purpose",
+ "modelName": "google: gemini 3.6 flash",
+ "tags": ["twin", "background"],
+ "toolUses": 0,
+ "tokens": "",
+ "durationMs": 0,
+ "status": "background",
+ "agentId": "4b4fd01d-aaa8-46d"
+ }
+ },
+ "isError": false
+ },
+ {
+ "type": "tool_execution_end",
+ "toolCallId": "call_277176",
+ "toolName": "Agent",
+ "result": {
+ "content": [
+ {
+ "type": "text",
+ "text": "Agent started in background.\nAgent ID: a92b022c-cd9e-41e\nType: Agent\nDescription: Test agent 2\nOutput file: /tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/a92b022c-cd9e-41e.output\n\nYou will be notified when this agent completes.\nUse get_subagent_result to retrieve full results, or steer_subagent to send it messages.\nDo not duplicate this agent's work."
+ }
+ ],
+ "details": {
+ "displayName": "Agent",
+ "description": "Test agent 2",
+ "subagentType": "general-purpose",
+ "modelName": "google: gemini 3.6 flash",
+ "tags": ["twin", "background"],
+ "toolUses": 0,
+ "tokens": "",
+ "durationMs": 0,
+ "status": "background",
+ "agentId": "a92b022c-cd9e-41e"
+ }
+ },
+ "isError": false
+ },
+ {
+ "type": "tool_execution_end",
+ "toolCallId": "call_277179",
+ "toolName": "Agent",
+ "result": {
+ "content": [
+ {
+ "type": "text",
+ "text": "Agent started in background.\nAgent ID: 13336b9f-79c3-49e\nType: Agent\nDescription: Test agent 3\nOutput file: /tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/13336b9f-79c3-49e.output\n\nYou will be notified when this agent completes.\nUse get_subagent_result to retrieve full results, or steer_subagent to send it messages.\nDo not duplicate this agent's work."
+ }
+ ],
+ "details": {
+ "displayName": "Agent",
+ "description": "Test agent 3",
+ "subagentType": "general-purpose",
+ "modelName": "google: gemini 3.6 flash",
+ "tags": ["twin", "background"],
+ "toolUses": 0,
+ "tokens": "",
+ "durationMs": 0,
+ "status": "background",
+ "agentId": "13336b9f-79c3-49e"
+ }
+ },
+ "isError": false
+ },
+ {
+ "type": "message_end",
+ "message": {
+ "role": "custom",
+ "customType": "subagent-notification",
+ "content": "Background agent group completed: 3 agent(s) finished\n\n\n4b4fd01d-aaa8-46d\ncall_277173\n/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/4b4fd01d-aaa8-46d.output\nDone\nAgent \"Test agent 1\" completed\nOK\n10186011054\n\n\n\na92b022c-cd9e-41e\ncall_277176\n/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/a92b022c-cd9e-41e.output\nDone\nAgent \"Test agent 2\" completed\nOK\n10186011182\n\n\n\n13336b9f-79c3-49e\ncall_277179\n/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/13336b9f-79c3-49e.output\nDone\nAgent \"Test agent 3\" completed\nOK\n10186011472\n\n\nUse get_subagent_result for full output.",
+ "display": true,
+ "details": {
+ "id": "4b4fd01d-aaa8-46d",
+ "description": "Test agent 1",
+ "status": "completed",
+ "toolUses": 0,
+ "turnCount": 0,
+ "totalTokens": 10186,
+ "totalCost": 0.007642500000000001,
+ "durationMs": 1054,
+ "outputFile": "/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/4b4fd01d-aaa8-46d.output",
+ "resultPreview": "OK",
+ "others": [
+ {
+ "id": "a92b022c-cd9e-41e",
+ "description": "Test agent 2",
+ "status": "completed",
+ "toolUses": 0,
+ "turnCount": 0,
+ "totalTokens": 10186,
+ "totalCost": 0.007642500000000001,
+ "durationMs": 1182,
+ "outputFile": "/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/a92b022c-cd9e-41e.output",
+ "resultPreview": "OK"
+ },
+ {
+ "id": "13336b9f-79c3-49e",
+ "description": "Test agent 3",
+ "status": "completed",
+ "toolUses": 0,
+ "turnCount": 0,
+ "totalTokens": 10186,
+ "totalCost": 0.007642500000000001,
+ "durationMs": 1472,
+ "outputFile": "/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/13336b9f-79c3-49e.output",
+ "resultPreview": "OK"
+ }
+ ]
+ },
+ "timestamp": 1790833737082
+ }
+ }
+ ],
+ "messages": [
+ {
+ "role": "assistant",
+ "content": [
+ {
+ "type": "thinking",
+ "thinking": "",
+ "thinkingSignature": "[{\"type\":\"reasoning.encrypted\",\"data\":\"AY89a19lxhI31c8Kjto2eEqQuEoAa1jXk+6WHw4RxcJiLq9eTkm6UtOU0r9mP+xFrs3A9GkNyIfpaIzLUGuPKjiYw648QdaOOVbR7jCqPVFA+CEYQH0V\",\"format\":\"google-gemini-v1\",\"id\":\"call_277173\",\"index\":0}]"
+ },
+ {
+ "type": "toolCall",
+ "id": "call_277173",
+ "name": "Agent",
+ "arguments": {
+ "run_in_background": true,
+ "description": "Test agent 1",
+ "prompt": "reply with exactly OK",
+ "subagent_type": "general-purpose"
+ }
+ },
+ {
+ "type": "toolCall",
+ "id": "call_277176",
+ "name": "Agent",
+ "arguments": {
+ "prompt": "reply with exactly OK",
+ "run_in_background": true,
+ "description": "Test agent 2",
+ "subagent_type": "general-purpose"
+ }
+ },
+ {
+ "type": "toolCall",
+ "id": "call_277179",
+ "name": "Agent",
+ "arguments": {
+ "subagent_type": "general-purpose",
+ "description": "Test agent 3",
+ "prompt": "reply with exactly OK",
+ "run_in_background": true
+ }
+ }
+ ],
+ "api": "openai-completions",
+ "provider": "openrouter",
+ "model": "google/gemini-3.6-flash",
+ "usage": {
+ "input": 13147,
+ "output": 135,
+ "cacheRead": 0,
+ "cacheWrite": 0,
+ "reasoning": 0,
+ "totalTokens": 13282,
+ "cost": {
+ "input": 0.009860250000000001,
+ "output": 0.00050625,
+ "cacheRead": 0,
+ "cacheWrite": 0,
+ "total": 0.0103665
+ }
+ },
+ "stopReason": "toolUse",
+ "timestamp": 1790833733536,
+ "responseId": "gen-1790833733-Qo0mjOAU6129xnYfl8rM",
+ "rawStopReason": "tool_calls"
+ },
+ {
+ "role": "toolResult",
+ "toolCallId": "call_277173",
+ "toolName": "Agent",
+ "content": [
+ {
+ "type": "text",
+ "text": "Agent started in background.\nAgent ID: 4b4fd01d-aaa8-46d\nType: Agent\nDescription: Test agent 1\nOutput file: /tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/4b4fd01d-aaa8-46d.output\n\nYou will be notified when this agent completes.\nUse get_subagent_result to retrieve full results, or steer_subagent to send it messages.\nDo not duplicate this agent's work."
+ }
+ ],
+ "details": {
+ "displayName": "Agent",
+ "description": "Test agent 1",
+ "subagentType": "general-purpose",
+ "modelName": "google: gemini 3.6 flash",
+ "tags": ["twin", "background"],
+ "toolUses": 0,
+ "tokens": "",
+ "durationMs": 0,
+ "status": "background",
+ "agentId": "4b4fd01d-aaa8-46d"
+ },
+ "isError": false,
+ "timestamp": 1790833735411
+ },
+ {
+ "role": "toolResult",
+ "toolCallId": "call_277176",
+ "toolName": "Agent",
+ "content": [
+ {
+ "type": "text",
+ "text": "Agent started in background.\nAgent ID: a92b022c-cd9e-41e\nType: Agent\nDescription: Test agent 2\nOutput file: /tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/a92b022c-cd9e-41e.output\n\nYou will be notified when this agent completes.\nUse get_subagent_result to retrieve full results, or steer_subagent to send it messages.\nDo not duplicate this agent's work."
+ }
+ ],
+ "details": {
+ "displayName": "Agent",
+ "description": "Test agent 2",
+ "subagentType": "general-purpose",
+ "modelName": "google: gemini 3.6 flash",
+ "tags": ["twin", "background"],
+ "toolUses": 0,
+ "tokens": "",
+ "durationMs": 0,
+ "status": "background",
+ "agentId": "a92b022c-cd9e-41e"
+ },
+ "isError": false,
+ "timestamp": 1790833735412
+ },
+ {
+ "role": "toolResult",
+ "toolCallId": "call_277179",
+ "toolName": "Agent",
+ "content": [
+ {
+ "type": "text",
+ "text": "Agent started in background.\nAgent ID: 13336b9f-79c3-49e\nType: Agent\nDescription: Test agent 3\nOutput file: /tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/13336b9f-79c3-49e.output\n\nYou will be notified when this agent completes.\nUse get_subagent_result to retrieve full results, or steer_subagent to send it messages.\nDo not duplicate this agent's work."
+ }
+ ],
+ "details": {
+ "displayName": "Agent",
+ "description": "Test agent 3",
+ "subagentType": "general-purpose",
+ "modelName": "google: gemini 3.6 flash",
+ "tags": ["twin", "background"],
+ "toolUses": 0,
+ "tokens": "",
+ "durationMs": 0,
+ "status": "background",
+ "agentId": "13336b9f-79c3-49e"
+ },
+ "isError": false,
+ "timestamp": 1790833735412
+ },
+ {
+ "role": "assistant",
+ "content": [
+ {
+ "type": "text",
+ "text": "I have spawned the 3 background agents and am waiting for their completion notifications."
+ }
+ ],
+ "api": "openai-completions",
+ "provider": "openrouter",
+ "model": "google/gemini-3.6-flash",
+ "usage": {
+ "input": 2004,
+ "output": 16,
+ "cacheRead": 11743,
+ "cacheWrite": 0,
+ "reasoning": 0,
+ "totalTokens": 13763,
+ "cost": {
+ "input": 0.001503,
+ "output": 6e-5,
+ "cacheRead": 0.000880725,
+ "cacheWrite": 0,
+ "total": 0.002443725
+ }
+ },
+ "stopReason": "stop",
+ "timestamp": 1790833735412,
+ "responseId": "gen-1790833735-adM3whTd4mLRXnKi2Xu0",
+ "rawStopReason": "stop"
+ },
+ {
+ "role": "custom",
+ "customType": "subagent-notification",
+ "content": "Background agent group completed: 3 agent(s) finished\n\n\n4b4fd01d-aaa8-46d\ncall_277173\n/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/4b4fd01d-aaa8-46d.output\nDone\nAgent \"Test agent 1\" completed\nOK\n10186011054\n\n\n\na92b022c-cd9e-41e\ncall_277176\n/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/a92b022c-cd9e-41e.output\nDone\nAgent \"Test agent 2\" completed\nOK\n10186011182\n\n\n\n13336b9f-79c3-49e\ncall_277179\n/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/13336b9f-79c3-49e.output\nDone\nAgent \"Test agent 3\" completed\nOK\n10186011472\n\n\nUse get_subagent_result for full output.",
+ "display": true,
+ "details": {
+ "id": "4b4fd01d-aaa8-46d",
+ "description": "Test agent 1",
+ "status": "completed",
+ "toolUses": 0,
+ "turnCount": 0,
+ "totalTokens": 10186,
+ "totalCost": 0.007642500000000001,
+ "durationMs": 1054,
+ "outputFile": "/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/4b4fd01d-aaa8-46d.output",
+ "resultPreview": "OK",
+ "others": [
+ {
+ "id": "a92b022c-cd9e-41e",
+ "description": "Test agent 2",
+ "status": "completed",
+ "toolUses": 0,
+ "turnCount": 0,
+ "totalTokens": 10186,
+ "totalCost": 0.007642500000000001,
+ "durationMs": 1182,
+ "outputFile": "/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/a92b022c-cd9e-41e.output",
+ "resultPreview": "OK"
+ },
+ {
+ "id": "13336b9f-79c3-49e",
+ "description": "Test agent 3",
+ "status": "completed",
+ "toolUses": 0,
+ "turnCount": 0,
+ "totalTokens": 10186,
+ "totalCost": 0.007642500000000001,
+ "durationMs": 1472,
+ "outputFile": "/tmp/pi-subagents-1000/tmp-paseo-pi-subagent-fixture/01a0f602-2dd3-7755-8969-96e4d126cd2e/tasks/13336b9f-79c3-49e.output",
+ "resultPreview": "OK"
+ }
+ ]
+ },
+ "timestamp": 1790833737082
+ },
+ {
+ "role": "assistant",
+ "content": [
+ {
+ "type": "text",
+ "text": "DONE"
+ }
+ ],
+ "api": "openai-completions",
+ "provider": "openrouter",
+ "model": "google/gemini-3.6-flash",
+ "usage": {
+ "input": 2740,
+ "output": 1,
+ "cacheRead": 11762,
+ "cacheWrite": 0,
+ "reasoning": 0,
+ "totalTokens": 14503,
+ "cost": {
+ "input": 0.002055,
+ "output": 3.75e-6,
+ "cacheRead": 0.00088215,
+ "cacheWrite": 0,
+ "total": 0.0029408999999999998
+ }
+ },
+ "stopReason": "stop",
+ "timestamp": 1790833737083,
+ "responseId": "gen-1790833737-3IfsB2wLuE8DMNlJMgmI",
+ "rawStopReason": "stop"
+ }
+ ]
+}
diff --git a/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.test.ts b/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.test.ts
index b464026ab1..b03c17c6ec 100644
--- a/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.test.ts
+++ b/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.test.ts
@@ -51,6 +51,20 @@ describe("@tintinweb/pi-subagents adapter", () => {
).toEqual(["running", "running", "completed"]);
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)),
+ );
+ const finalStatus = new Map();
+ for (const { event } of events) {
+ if (event.type === "upsert" && event.status) finalStatus.set(event.id, event.status);
+ }
+ expect(Object.fromEntries(finalStatus)).toEqual({
+ call_277173: "completed",
+ call_277176: "completed",
+ call_277179: "completed",
+ });
+ });
test("declines foreign Agent results", () => {
expect(
createPiExtensionHost().mapToolCall({
diff --git a/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.ts b/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.ts
index 2b06779afa..9c6ef9917e 100644
--- a/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.ts
+++ b/packages/server/src/server/agent/providers/pi/extensions/tintinweb-pi-subagents/index.ts
@@ -19,7 +19,7 @@ const Details = z
description: z.string().optional(),
})
.passthrough();
-const Notification = z
+const NotificationEntry = z
.object({
id: z.string().trim().min(1),
status: z.string(),
@@ -27,6 +27,11 @@ const Notification = z
outputFile: z.string().trim().min(1).optional(),
})
.passthrough();
+// Completions that land close together arrive as one notification: the first
+// agent at the top level and the rest in `others`.
+const Notification = NotificationEntry.extend({
+ others: z.array(NotificationEntry).optional(),
+});
const status = (value: string): "running" | "completed" | "failed" | "canceled" => {
if (value === "completed") return "completed";
if (value === "error") return "failed";
@@ -127,22 +132,25 @@ export const tintinwebPiSubagents: PiExtension = {
return undefined;
const details = Notification.safeParse(message.details);
if (!details.success) return undefined;
- const id = callsByAgent.get(details.data.id);
- if (!id) return undefined;
- const file = details.data.outputFile;
- const childSessions = file && !readSessions.has(file) ? [{ id, file }] : [];
- if (childSessions.length && file) readSessions.add(file);
- return {
- subagents: [
- {
- type: "upsert",
- id,
- description: details.data.description,
- status: status(details.data.status),
- },
- ],
- childSessions,
- };
+ const subagents = [];
+ const childSessions = [];
+ for (const entry of [details.data, ...(details.data.others ?? [])]) {
+ const id = callsByAgent.get(entry.id);
+ if (!id) continue;
+ const file = entry.outputFile;
+ if (file && !readSessions.has(file)) {
+ readSessions.add(file);
+ childSessions.push({ id, file });
+ }
+ subagents.push({
+ type: "upsert" as const,
+ id,
+ description: entry.description,
+ status: status(entry.status),
+ });
+ }
+ if (subagents.length === 0) return undefined;
+ return { subagents, childSessions };
},
};
},