1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
import { z } from "zod";
import type { ToolDefinition } from "../types/index.js";
export interface SummonCallbacks {
spawn(options: { task: string; tools: string[]; workingDirectory?: string }): Promise<string>;
getResult(
agentId: string,
): Promise<{ status: "done"; result: string } | { status: "error"; error: string }>;
}
export function createSummonTool(
defaultWorkingDirectory: string,
callbacks: SummonCallbacks,
): ToolDefinition {
return {
name: "summon",
description: [
"Spawn a new child agent to work on a task independently.",
"",
"By default, blocks until the child agent finishes and returns the result directly.",
"Set background=true to return immediately with an agent_id instead — use retrieve to collect the result later.",
"",
"The child agent runs in its own tab visible to the user. Use the 'retrieve' tool with the returned agent_id to get the result when needed.",
"",
"Pattern for parallel work:",
" 1. Call summon multiple times with background=true to start several agents",
" 2. Do your own work or wait",
" 3. Call retrieve for each agent_id to collect results",
"",
"The 'tools' parameter controls what the child can do. Available tool names:",
" - read_file: Read file contents",
" - list_files: List files and directories",
" - write_file: Write/edit files",
" - run_shell: Execute shell commands",
" - todo: Track work items",
" - summon: Spawn its own child agents (enables nesting)",
" - retrieve: Collect results from its children (required if summon is given)",
" - web_search: Search the web",
" - youtube_transcribe: Fetch YouTube video transcripts",
"",
"If tools is omitted, the child gets read_file, list_files, and todo only (read-only by default).",
].join("\n"),
parameters: z.object({
task: z
.string()
.describe(
"Detailed instructions for the child agent. Be specific about what it should do and what it should return.",
),
tools: z
.array(
z.enum([
"read_file",
"list_files",
"write_file",
"run_shell",
"todo",
"summon",
"retrieve",
"web_search",
"youtube_transcribe",
]),
)
.optional()
.describe(
'Tool names to give the child. Defaults to ["read_file", "list_files", "todo"]. Include "summon" and "retrieve" to allow nesting.',
),
working_directory: z
.string()
.optional()
.describe(
"Absolute path for the child to work in. Defaults to the current working directory.",
),
background: z
.boolean()
.optional()
.describe(
"If true, returns immediately with an agent_id for later retrieval. If false (default), blocks until the child agent finishes and returns the result directly.",
),
}),
execute: async (args: Record<string, unknown>): Promise<string> => {
const task = args.task as string;
const tools = (args.tools as string[] | undefined) ?? ["read_file", "list_files", "todo"];
const workingDirectory =
(args.working_directory as string | undefined) ?? defaultWorkingDirectory;
const background = (args.background as boolean | undefined) ?? false;
try {
const agentId = await callbacks.spawn({
task,
tools,
workingDirectory,
});
if (!background) {
// Block until the child agent completes
const result = await callbacks.getResult(agentId);
if (result.status === "done") {
return result.result;
}
return `Error from child agent: ${result.error}`;
}
return [
`Agent spawned successfully.`,
`agent_id: ${agentId}`,
``,
`The child agent is now working on the task in its own tab.`,
`Use the retrieve tool with this agent_id to get the result when ready.`,
].join("\n");
} catch (err) {
return `Error spawning agent: ${err instanceof Error ? err.message : String(err)}`;
}
},
};
}
|