@oyasmi/pipiclaw 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +67 -9
- package/dist/agent.js.map +1 -1
- package/dist/dingtalk.d.ts +1 -1
- package/dist/dingtalk.d.ts.map +1 -1
- package/dist/dingtalk.js +26 -4
- package/dist/dingtalk.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +11 -0
- package/dist/events.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +106 -39
- package/dist/main.js.map +1 -1
- package/dist/paths.d.ts +2 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +2 -0
- package/dist/paths.js.map +1 -1
- package/dist/prompt-builder.d.ts +4 -1
- package/dist/prompt-builder.d.ts.map +1 -1
- package/dist/prompt-builder.js +30 -1
- package/dist/prompt-builder.js.map +1 -1
- package/dist/sandbox.d.ts +1 -0
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +56 -13
- package/dist/sandbox.js.map +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +47 -7
- package/dist/store.js.map +1 -1
- package/dist/sub-agents.d.ts +47 -0
- package/dist/sub-agents.d.ts.map +1 -0
- package/dist/sub-agents.js +228 -0
- package/dist/sub-agents.js.map +1 -0
- package/dist/tools/bash.d.ts +4 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +3 -2
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +2 -6
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts +10 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +15 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/subagent.d.ts +52 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +245 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/write-content.d.ts +5 -0
- package/dist/tools/write-content.d.ts.map +1 -0
- package/dist/tools/write-content.js +30 -0
- package/dist/tools/write-content.js.map +1 -0
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +2 -10
- package/dist/tools/write.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Agent } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import { convertToLlm } from "@mariozechner/pi-coding-agent";
|
|
3
|
+
import { Type } from "@sinclair/typebox";
|
|
4
|
+
import { formatModelReference } from "../model-utils.js";
|
|
5
|
+
import { discoverSubAgents, formatSubAgentList, resolveSubAgentConfig, validateSubAgentTask, } from "../sub-agents.js";
|
|
6
|
+
import { createBashTool } from "./bash.js";
|
|
7
|
+
import { createEditTool } from "./edit.js";
|
|
8
|
+
import { createReadTool } from "./read.js";
|
|
9
|
+
import { createWriteTool } from "./write.js";
|
|
10
|
+
const subagentSchema = Type.Object({
|
|
11
|
+
label: Type.String({ description: "Brief description of what this sub-agent task does (shown to user)" }),
|
|
12
|
+
agent: Type.Optional(Type.String({ description: "Name of a predefined sub-agent from workspaceDir/sub-agents/" })),
|
|
13
|
+
name: Type.Optional(Type.String({ description: "Optional display name for an inline sub-agent" })),
|
|
14
|
+
task: Type.String({ description: "Complete task description for the sub-agent" }),
|
|
15
|
+
systemPrompt: Type.Optional(Type.String({
|
|
16
|
+
description: "Optional inline system prompt for a temporary sub-agent. Use when no predefined agent fits.",
|
|
17
|
+
})),
|
|
18
|
+
tools: Type.Optional(Type.Array(Type.String(), { description: "Optional tool whitelist for the sub-agent" })),
|
|
19
|
+
model: Type.Optional(Type.String({ description: "Optional exact model reference. Defaults to the parent's current model." })),
|
|
20
|
+
maxTurns: Type.Optional(Type.Number({ description: "Optional maximum assistant turns for this sub-agent" })),
|
|
21
|
+
maxToolCalls: Type.Optional(Type.Number({ description: "Optional maximum tool calls for this sub-agent" })),
|
|
22
|
+
maxWallTimeSec: Type.Optional(Type.Number({ description: "Optional wall time budget in seconds for this sub-agent" })),
|
|
23
|
+
bashTimeoutSec: Type.Optional(Type.Number({ description: "Optional default timeout in seconds for bash commands inside this sub-agent" })),
|
|
24
|
+
});
|
|
25
|
+
function createEmptyUsageTotals() {
|
|
26
|
+
return {
|
|
27
|
+
input: 0,
|
|
28
|
+
output: 0,
|
|
29
|
+
cacheRead: 0,
|
|
30
|
+
cacheWrite: 0,
|
|
31
|
+
total: 0,
|
|
32
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function isAssistantMessage(message) {
|
|
36
|
+
return typeof message === "object" && message !== null && "role" in message && message.role === "assistant";
|
|
37
|
+
}
|
|
38
|
+
function extractAssistantText(message) {
|
|
39
|
+
return message.content
|
|
40
|
+
.filter((part) => part.type === "text")
|
|
41
|
+
.map((part) => part.text)
|
|
42
|
+
.join("\n")
|
|
43
|
+
.trim();
|
|
44
|
+
}
|
|
45
|
+
function getLastAssistantMessage(messages) {
|
|
46
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
47
|
+
const message = messages[i];
|
|
48
|
+
if (isAssistantMessage(message)) {
|
|
49
|
+
return message;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function extractLabelFromArgs(args) {
|
|
55
|
+
if (!args || typeof args !== "object" || !("label" in args)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const label = args.label;
|
|
59
|
+
return typeof label === "string" && label.trim() ? label.trim() : null;
|
|
60
|
+
}
|
|
61
|
+
function formatStatus(agentName, text) {
|
|
62
|
+
return `Subagent ${agentName}: ${text}`;
|
|
63
|
+
}
|
|
64
|
+
function buildFailureText(config, reason, lastAssistantText) {
|
|
65
|
+
const trimmedLastText = lastAssistantText.trim();
|
|
66
|
+
if (!trimmedLastText) {
|
|
67
|
+
return `Sub-agent ${config.name} failed: ${reason}`;
|
|
68
|
+
}
|
|
69
|
+
return `Sub-agent ${config.name} failed: ${reason}\n\nLast output:\n${trimmedLastText}`;
|
|
70
|
+
}
|
|
71
|
+
function createToolSet(executor, bashTimeoutSec) {
|
|
72
|
+
return [
|
|
73
|
+
createReadTool(executor),
|
|
74
|
+
createBashTool(executor, { defaultTimeoutSeconds: bashTimeoutSec }),
|
|
75
|
+
createEditTool(executor),
|
|
76
|
+
createWriteTool(executor),
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
function filterToolsByName(allTools, names) {
|
|
80
|
+
const allowed = new Set(names);
|
|
81
|
+
return allTools.filter((tool) => allowed.has(tool.name));
|
|
82
|
+
}
|
|
83
|
+
function createDetails(config, usage, turns, toolCalls, durationMs, failed, failureReason) {
|
|
84
|
+
return {
|
|
85
|
+
agent: config.name,
|
|
86
|
+
source: config.source,
|
|
87
|
+
model: formatModelReference(config.model),
|
|
88
|
+
tools: [...config.tools],
|
|
89
|
+
turns,
|
|
90
|
+
toolCalls,
|
|
91
|
+
durationMs,
|
|
92
|
+
failed,
|
|
93
|
+
failureReason,
|
|
94
|
+
usage: {
|
|
95
|
+
...usage,
|
|
96
|
+
cost: { ...usage.cost },
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function linkAbortSignals(parentSignal, childController) {
|
|
101
|
+
if (!parentSignal) {
|
|
102
|
+
return () => { };
|
|
103
|
+
}
|
|
104
|
+
const abortChild = () => childController.abort(parentSignal.reason);
|
|
105
|
+
if (parentSignal.aborted) {
|
|
106
|
+
abortChild();
|
|
107
|
+
return () => { };
|
|
108
|
+
}
|
|
109
|
+
parentSignal.addEventListener("abort", abortChild, { once: true });
|
|
110
|
+
return () => parentSignal.removeEventListener("abort", abortChild);
|
|
111
|
+
}
|
|
112
|
+
export function createSubAgentTool(options) {
|
|
113
|
+
return {
|
|
114
|
+
name: "subagent",
|
|
115
|
+
label: "subagent",
|
|
116
|
+
description: "Delegate a task to a sub-agent with an isolated context. You may use a predefined sub-agent from workspaceDir/sub-agents/ or define a temporary inline sub-agent by providing systemPrompt/tools/model parameters. Sub-agents never receive the subagent tool, so they cannot create nested agents.",
|
|
117
|
+
parameters: subagentSchema,
|
|
118
|
+
execute: async (_toolCallId, params, signal, onUpdate) => {
|
|
119
|
+
const availableModels = options.getAvailableModels();
|
|
120
|
+
const discovery = discoverSubAgents(options.workspaceDir, availableModels);
|
|
121
|
+
const currentModel = options.getCurrentModel();
|
|
122
|
+
const taskLengthError = validateSubAgentTask(params.task);
|
|
123
|
+
if (taskLengthError) {
|
|
124
|
+
throw new Error(taskLengthError);
|
|
125
|
+
}
|
|
126
|
+
const invocation = resolveSubAgentConfig(availableModels, currentModel, discovery.agents, params);
|
|
127
|
+
if (!invocation.config) {
|
|
128
|
+
throw new Error(`${invocation.error}\n\nAvailable predefined sub-agents:\n${formatSubAgentList(discovery.agents)}`);
|
|
129
|
+
}
|
|
130
|
+
const config = invocation.config;
|
|
131
|
+
const apiKey = await options.resolveApiKey(config.model);
|
|
132
|
+
const startedAt = Date.now();
|
|
133
|
+
const usage = createEmptyUsageTotals();
|
|
134
|
+
let assistantTurns = 0;
|
|
135
|
+
let toolCalls = 0;
|
|
136
|
+
let failureReason;
|
|
137
|
+
let lastUpdateText = "";
|
|
138
|
+
const emitUpdate = (text) => {
|
|
139
|
+
const nextText = text.trim();
|
|
140
|
+
if (!nextText || nextText === lastUpdateText) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
lastUpdateText = nextText;
|
|
144
|
+
onUpdate?.({
|
|
145
|
+
content: [{ type: "text", text: nextText }],
|
|
146
|
+
details: createDetails(config, usage, assistantTurns, toolCalls, Date.now() - startedAt, Boolean(failureReason), failureReason),
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
const worker = new Agent({
|
|
150
|
+
initialState: {
|
|
151
|
+
systemPrompt: config.systemPrompt,
|
|
152
|
+
model: config.model,
|
|
153
|
+
thinkingLevel: "off",
|
|
154
|
+
tools: filterToolsByName(createToolSet(options.executor, config.bashTimeoutSec), config.tools),
|
|
155
|
+
},
|
|
156
|
+
convertToLlm,
|
|
157
|
+
getApiKey: async () => apiKey,
|
|
158
|
+
});
|
|
159
|
+
const childController = new AbortController();
|
|
160
|
+
const unlinkAbortSignals = linkAbortSignals(signal, childController);
|
|
161
|
+
const wallClockTimer = setTimeout(() => {
|
|
162
|
+
failureReason = `Wall time budget exceeded (${config.maxWallTimeSec}s)`;
|
|
163
|
+
worker.abort();
|
|
164
|
+
}, config.maxWallTimeSec * 1000);
|
|
165
|
+
const unsubscribe = worker.subscribe((event) => {
|
|
166
|
+
if (event.type === "message_end" && isAssistantMessage(event.message)) {
|
|
167
|
+
assistantTurns++;
|
|
168
|
+
const messageUsage = event.message.usage;
|
|
169
|
+
usage.input += messageUsage.input;
|
|
170
|
+
usage.output += messageUsage.output;
|
|
171
|
+
usage.cacheRead += messageUsage.cacheRead;
|
|
172
|
+
usage.cacheWrite += messageUsage.cacheWrite;
|
|
173
|
+
usage.total += messageUsage.totalTokens;
|
|
174
|
+
usage.cost.input += messageUsage.cost.input;
|
|
175
|
+
usage.cost.output += messageUsage.cost.output;
|
|
176
|
+
usage.cost.cacheRead += messageUsage.cost.cacheRead;
|
|
177
|
+
usage.cost.cacheWrite += messageUsage.cost.cacheWrite;
|
|
178
|
+
usage.cost.total += messageUsage.cost.total;
|
|
179
|
+
}
|
|
180
|
+
if (event.type === "tool_execution_start") {
|
|
181
|
+
toolCalls++;
|
|
182
|
+
const label = extractLabelFromArgs(event.args) || event.toolName;
|
|
183
|
+
emitUpdate(formatStatus(config.name, label));
|
|
184
|
+
if (toolCalls > config.maxToolCalls) {
|
|
185
|
+
failureReason = `Tool call budget exceeded (${config.maxToolCalls})`;
|
|
186
|
+
emitUpdate(formatStatus(config.name, "tool budget reached"));
|
|
187
|
+
worker.abort();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (event.type === "turn_end" &&
|
|
191
|
+
isAssistantMessage(event.message) &&
|
|
192
|
+
event.toolResults.length > 0 &&
|
|
193
|
+
assistantTurns >= config.maxTurns) {
|
|
194
|
+
failureReason = `Turn budget exceeded (${config.maxTurns})`;
|
|
195
|
+
emitUpdate(formatStatus(config.name, "turn budget reached"));
|
|
196
|
+
worker.abort();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
emitUpdate(formatStatus(config.name, "started"));
|
|
200
|
+
try {
|
|
201
|
+
if (childController.signal.aborted) {
|
|
202
|
+
throw new Error("Sub-agent aborted");
|
|
203
|
+
}
|
|
204
|
+
const abortWorker = () => worker.abort();
|
|
205
|
+
childController.signal.addEventListener("abort", abortWorker, { once: true });
|
|
206
|
+
try {
|
|
207
|
+
await worker.prompt(params.task);
|
|
208
|
+
await worker.waitForIdle();
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
childController.signal.removeEventListener("abort", abortWorker);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
unsubscribe();
|
|
216
|
+
unlinkAbortSignals();
|
|
217
|
+
clearTimeout(wallClockTimer);
|
|
218
|
+
}
|
|
219
|
+
if (signal?.aborted) {
|
|
220
|
+
throw new Error("Sub-agent aborted");
|
|
221
|
+
}
|
|
222
|
+
const lastAssistantMessage = getLastAssistantMessage(worker.state.messages);
|
|
223
|
+
const durationMs = Date.now() - startedAt;
|
|
224
|
+
if (!lastAssistantMessage) {
|
|
225
|
+
failureReason = failureReason || "Sub-agent returned no assistant message";
|
|
226
|
+
emitUpdate(formatStatus(config.name, "failed"));
|
|
227
|
+
throw new Error(`Sub-agent ${config.name} failed: ${failureReason}`);
|
|
228
|
+
}
|
|
229
|
+
const finalText = extractAssistantText(lastAssistantMessage);
|
|
230
|
+
const effectiveFailureReason = failureReason ||
|
|
231
|
+
(lastAssistantMessage.stopReason === "error" || lastAssistantMessage.stopReason === "aborted"
|
|
232
|
+
? lastAssistantMessage.errorMessage || `Sub-agent stopped with ${lastAssistantMessage.stopReason}`
|
|
233
|
+
: undefined);
|
|
234
|
+
if (effectiveFailureReason) {
|
|
235
|
+
emitUpdate(formatStatus(config.name, "failed"));
|
|
236
|
+
throw new Error(buildFailureText(config, effectiveFailureReason, finalText));
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
content: [{ type: "text", text: finalText || `(Sub-agent ${config.name} completed with no text output)` }],
|
|
240
|
+
details: createDetails(config, usage, assistantTurns, toolCalls, durationMs, false),
|
|
241
|
+
};
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=subagent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent.js","sourceRoot":"","sources":["../../src/tools/subagent.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, type AgentEvent, type AgentMessage, type AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { Api, AssistantMessage, Model, TextContent } from \"@mariozechner/pi-ai\";\nimport { convertToLlm } from \"@mariozechner/pi-coding-agent\";\nimport { Type } from \"@sinclair/typebox\";\nimport { formatModelReference } from \"../model-utils.js\";\nimport type { Executor } from \"../sandbox.js\";\nimport {\n\tdiscoverSubAgents,\n\tformatSubAgentList,\n\tresolveSubAgentConfig,\n\ttype SubAgentConfig,\n\tvalidateSubAgentTask,\n} from \"../sub-agents.js\";\nimport { createBashTool } from \"./bash.js\";\nimport { createEditTool } from \"./edit.js\";\nimport { createReadTool } from \"./read.js\";\nimport { createWriteTool } from \"./write.js\";\n\nconst subagentSchema = Type.Object({\n\tlabel: Type.String({ description: \"Brief description of what this sub-agent task does (shown to user)\" }),\n\tagent: Type.Optional(Type.String({ description: \"Name of a predefined sub-agent from workspaceDir/sub-agents/\" })),\n\tname: Type.Optional(Type.String({ description: \"Optional display name for an inline sub-agent\" })),\n\ttask: Type.String({ description: \"Complete task description for the sub-agent\" }),\n\tsystemPrompt: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Optional inline system prompt for a temporary sub-agent. Use when no predefined agent fits.\",\n\t\t}),\n\t),\n\ttools: Type.Optional(Type.Array(Type.String(), { description: \"Optional tool whitelist for the sub-agent\" })),\n\tmodel: Type.Optional(\n\t\tType.String({ description: \"Optional exact model reference. Defaults to the parent's current model.\" }),\n\t),\n\tmaxTurns: Type.Optional(Type.Number({ description: \"Optional maximum assistant turns for this sub-agent\" })),\n\tmaxToolCalls: Type.Optional(Type.Number({ description: \"Optional maximum tool calls for this sub-agent\" })),\n\tmaxWallTimeSec: Type.Optional(\n\t\tType.Number({ description: \"Optional wall time budget in seconds for this sub-agent\" }),\n\t),\n\tbashTimeoutSec: Type.Optional(\n\t\tType.Number({ description: \"Optional default timeout in seconds for bash commands inside this sub-agent\" }),\n\t),\n});\n\ninterface UsageTotals {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotal: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport interface SubAgentToolDetails {\n\tagent: string;\n\tsource: \"predefined\" | \"inline\";\n\tmodel: string;\n\ttools: string[];\n\tturns: number;\n\ttoolCalls: number;\n\tdurationMs: number;\n\tfailed: boolean;\n\tfailureReason?: string;\n\tusage: UsageTotals;\n}\n\nexport interface SubAgentToolOptions {\n\texecutor: Executor;\n\tgetCurrentModel: () => Model<Api>;\n\tgetAvailableModels: () => Model<Api>[];\n\tresolveApiKey: (model: Model<Api>) => Promise<string>;\n\tworkspaceDir: string;\n}\n\nfunction createEmptyUsageTotals(): UsageTotals {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotal: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction isAssistantMessage(message: AgentMessage): message is AssistantMessage {\n\treturn typeof message === \"object\" && message !== null && \"role\" in message && message.role === \"assistant\";\n}\n\nfunction extractAssistantText(message: AssistantMessage): string {\n\treturn message.content\n\t\t.filter((part): part is Extract<AssistantMessage[\"content\"][number], TextContent> => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\")\n\t\t.trim();\n}\n\nfunction getLastAssistantMessage(messages: AgentMessage[]): AssistantMessage | null {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (isAssistantMessage(message)) {\n\t\t\treturn message;\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction extractLabelFromArgs(args: unknown): string | null {\n\tif (!args || typeof args !== \"object\" || !(\"label\" in args)) {\n\t\treturn null;\n\t}\n\tconst label = (args as { label?: unknown }).label;\n\treturn typeof label === \"string\" && label.trim() ? label.trim() : null;\n}\n\nfunction formatStatus(agentName: string, text: string): string {\n\treturn `Subagent ${agentName}: ${text}`;\n}\n\nfunction buildFailureText(config: SubAgentConfig, reason: string, lastAssistantText: string): string {\n\tconst trimmedLastText = lastAssistantText.trim();\n\tif (!trimmedLastText) {\n\t\treturn `Sub-agent ${config.name} failed: ${reason}`;\n\t}\n\treturn `Sub-agent ${config.name} failed: ${reason}\\n\\nLast output:\\n${trimmedLastText}`;\n}\n\nfunction createToolSet(executor: Executor, bashTimeoutSec: number): AgentTool<any>[] {\n\treturn [\n\t\tcreateReadTool(executor),\n\t\tcreateBashTool(executor, { defaultTimeoutSeconds: bashTimeoutSec }),\n\t\tcreateEditTool(executor),\n\t\tcreateWriteTool(executor),\n\t];\n}\n\nfunction filterToolsByName(allTools: AgentTool<any>[], names: string[]): AgentTool<any>[] {\n\tconst allowed = new Set(names);\n\treturn allTools.filter((tool) => allowed.has(tool.name));\n}\n\nfunction createDetails(\n\tconfig: SubAgentConfig,\n\tusage: UsageTotals,\n\tturns: number,\n\ttoolCalls: number,\n\tdurationMs: number,\n\tfailed: boolean,\n\tfailureReason?: string,\n): SubAgentToolDetails {\n\treturn {\n\t\tagent: config.name,\n\t\tsource: config.source,\n\t\tmodel: formatModelReference(config.model!),\n\t\ttools: [...config.tools],\n\t\tturns,\n\t\ttoolCalls,\n\t\tdurationMs,\n\t\tfailed,\n\t\tfailureReason,\n\t\tusage: {\n\t\t\t...usage,\n\t\t\tcost: { ...usage.cost },\n\t\t},\n\t};\n}\n\nfunction linkAbortSignals(parentSignal: AbortSignal | undefined, childController: AbortController): () => void {\n\tif (!parentSignal) {\n\t\treturn () => {};\n\t}\n\n\tconst abortChild = () => childController.abort(parentSignal.reason);\n\tif (parentSignal.aborted) {\n\t\tabortChild();\n\t\treturn () => {};\n\t}\n\n\tparentSignal.addEventListener(\"abort\", abortChild, { once: true });\n\treturn () => parentSignal.removeEventListener(\"abort\", abortChild);\n}\n\nexport function createSubAgentTool(\n\toptions: SubAgentToolOptions,\n): AgentTool<typeof subagentSchema, SubAgentToolDetails> {\n\treturn {\n\t\tname: \"subagent\",\n\t\tlabel: \"subagent\",\n\t\tdescription:\n\t\t\t\"Delegate a task to a sub-agent with an isolated context. You may use a predefined sub-agent from workspaceDir/sub-agents/ or define a temporary inline sub-agent by providing systemPrompt/tools/model parameters. Sub-agents never receive the subagent tool, so they cannot create nested agents.\",\n\t\tparameters: subagentSchema,\n\t\texecute: async (_toolCallId, params, signal, onUpdate) => {\n\t\t\tconst availableModels = options.getAvailableModels();\n\t\t\tconst discovery = discoverSubAgents(options.workspaceDir, availableModels);\n\t\t\tconst currentModel = options.getCurrentModel();\n\t\t\tconst taskLengthError = validateSubAgentTask(params.task);\n\t\t\tif (taskLengthError) {\n\t\t\t\tthrow new Error(taskLengthError);\n\t\t\t}\n\t\t\tconst invocation = resolveSubAgentConfig(availableModels, currentModel, discovery.agents, params);\n\t\t\tif (!invocation.config) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${invocation.error}\\n\\nAvailable predefined sub-agents:\\n${formatSubAgentList(discovery.agents)}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst config = invocation.config;\n\t\t\tconst apiKey = await options.resolveApiKey(config.model!);\n\t\t\tconst startedAt = Date.now();\n\t\t\tconst usage = createEmptyUsageTotals();\n\t\t\tlet assistantTurns = 0;\n\t\t\tlet toolCalls = 0;\n\t\t\tlet failureReason: string | undefined;\n\t\t\tlet lastUpdateText = \"\";\n\n\t\t\tconst emitUpdate = (text: string) => {\n\t\t\t\tconst nextText = text.trim();\n\t\t\t\tif (!nextText || nextText === lastUpdateText) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlastUpdateText = nextText;\n\t\t\t\tonUpdate?.({\n\t\t\t\t\tcontent: [{ type: \"text\", text: nextText }],\n\t\t\t\t\tdetails: createDetails(\n\t\t\t\t\t\tconfig,\n\t\t\t\t\t\tusage,\n\t\t\t\t\t\tassistantTurns,\n\t\t\t\t\t\ttoolCalls,\n\t\t\t\t\t\tDate.now() - startedAt,\n\t\t\t\t\t\tBoolean(failureReason),\n\t\t\t\t\t\tfailureReason,\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst worker = new Agent({\n\t\t\t\tinitialState: {\n\t\t\t\t\tsystemPrompt: config.systemPrompt,\n\t\t\t\t\tmodel: config.model!,\n\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\ttools: filterToolsByName(createToolSet(options.executor, config.bashTimeoutSec), config.tools),\n\t\t\t\t},\n\t\t\t\tconvertToLlm,\n\t\t\t\tgetApiKey: async () => apiKey,\n\t\t\t});\n\n\t\t\tconst childController = new AbortController();\n\t\t\tconst unlinkAbortSignals = linkAbortSignals(signal, childController);\n\t\t\tconst wallClockTimer = setTimeout(() => {\n\t\t\t\tfailureReason = `Wall time budget exceeded (${config.maxWallTimeSec}s)`;\n\t\t\t\tworker.abort();\n\t\t\t}, config.maxWallTimeSec * 1000);\n\n\t\t\tconst unsubscribe = worker.subscribe((event: AgentEvent) => {\n\t\t\t\tif (event.type === \"message_end\" && isAssistantMessage(event.message)) {\n\t\t\t\t\tassistantTurns++;\n\t\t\t\t\tconst messageUsage = event.message.usage;\n\t\t\t\t\tusage.input += messageUsage.input;\n\t\t\t\t\tusage.output += messageUsage.output;\n\t\t\t\t\tusage.cacheRead += messageUsage.cacheRead;\n\t\t\t\t\tusage.cacheWrite += messageUsage.cacheWrite;\n\t\t\t\t\tusage.total += messageUsage.totalTokens;\n\t\t\t\t\tusage.cost.input += messageUsage.cost.input;\n\t\t\t\t\tusage.cost.output += messageUsage.cost.output;\n\t\t\t\t\tusage.cost.cacheRead += messageUsage.cost.cacheRead;\n\t\t\t\t\tusage.cost.cacheWrite += messageUsage.cost.cacheWrite;\n\t\t\t\t\tusage.cost.total += messageUsage.cost.total;\n\t\t\t\t}\n\n\t\t\t\tif (event.type === \"tool_execution_start\") {\n\t\t\t\t\ttoolCalls++;\n\t\t\t\t\tconst label = extractLabelFromArgs(event.args) || event.toolName;\n\t\t\t\t\temitUpdate(formatStatus(config.name, label));\n\t\t\t\t\tif (toolCalls > config.maxToolCalls) {\n\t\t\t\t\t\tfailureReason = `Tool call budget exceeded (${config.maxToolCalls})`;\n\t\t\t\t\t\temitUpdate(formatStatus(config.name, \"tool budget reached\"));\n\t\t\t\t\t\tworker.abort();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tevent.type === \"turn_end\" &&\n\t\t\t\t\tisAssistantMessage(event.message) &&\n\t\t\t\t\tevent.toolResults.length > 0 &&\n\t\t\t\t\tassistantTurns >= config.maxTurns\n\t\t\t\t) {\n\t\t\t\t\tfailureReason = `Turn budget exceeded (${config.maxTurns})`;\n\t\t\t\t\temitUpdate(formatStatus(config.name, \"turn budget reached\"));\n\t\t\t\t\tworker.abort();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\temitUpdate(formatStatus(config.name, \"started\"));\n\n\t\t\ttry {\n\t\t\t\tif (childController.signal.aborted) {\n\t\t\t\t\tthrow new Error(\"Sub-agent aborted\");\n\t\t\t\t}\n\n\t\t\t\tconst abortWorker = () => worker.abort();\n\t\t\t\tchildController.signal.addEventListener(\"abort\", abortWorker, { once: true });\n\t\t\t\ttry {\n\t\t\t\t\tawait worker.prompt(params.task);\n\t\t\t\t\tawait worker.waitForIdle();\n\t\t\t\t} finally {\n\t\t\t\t\tchildController.signal.removeEventListener(\"abort\", abortWorker);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tunsubscribe();\n\t\t\t\tunlinkAbortSignals();\n\t\t\t\tclearTimeout(wallClockTimer);\n\t\t\t}\n\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"Sub-agent aborted\");\n\t\t\t}\n\n\t\t\tconst lastAssistantMessage = getLastAssistantMessage(worker.state.messages);\n\t\t\tconst durationMs = Date.now() - startedAt;\n\t\t\tif (!lastAssistantMessage) {\n\t\t\t\tfailureReason = failureReason || \"Sub-agent returned no assistant message\";\n\t\t\t\temitUpdate(formatStatus(config.name, \"failed\"));\n\t\t\t\tthrow new Error(`Sub-agent ${config.name} failed: ${failureReason}`);\n\t\t\t}\n\n\t\t\tconst finalText = extractAssistantText(lastAssistantMessage);\n\t\t\tconst effectiveFailureReason =\n\t\t\t\tfailureReason ||\n\t\t\t\t(lastAssistantMessage.stopReason === \"error\" || lastAssistantMessage.stopReason === \"aborted\"\n\t\t\t\t\t? lastAssistantMessage.errorMessage || `Sub-agent stopped with ${lastAssistantMessage.stopReason}`\n\t\t\t\t\t: undefined);\n\n\t\t\tif (effectiveFailureReason) {\n\t\t\t\temitUpdate(formatStatus(config.name, \"failed\"));\n\t\t\t\tthrow new Error(buildFailureText(config, effectiveFailureReason, finalText));\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: finalText || `(Sub-agent ${config.name} completed with no text output)` }],\n\t\t\t\tdetails: createDetails(config, usage, assistantTurns, toolCalls, durationMs, false),\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Executor } from "../sandbox.js";
|
|
2
|
+
export declare function writeContent(executor: Executor, path: string, content: string, signal: AbortSignal | undefined, options?: {
|
|
3
|
+
createParentDir?: boolean;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=write-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-content.d.ts","sourceRoot":"","sources":["../../src/tools/write-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,QAAQ,EAAE,MAAM,eAAe,CAAC;AAmB1D,wBAAsB,YAAY,CACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACrC,OAAO,CAAC,IAAI,CAAC,CAiBf","sourcesContent":["import type { ExecResult, Executor } from \"../sandbox.js\";\nimport { shellEscape } from \"../shell-escape.js\";\n\nconst INLINE_WRITE_MAX_BYTES = 64 * 1024;\n\nfunction getDir(path: string): string {\n\treturn path.includes(\"/\") ? path.substring(0, path.lastIndexOf(\"/\")) : \".\";\n}\n\nfunction isInlineSafe(content: string): boolean {\n\treturn Buffer.byteLength(content, \"utf-8\") <= INLINE_WRITE_MAX_BYTES;\n}\n\nfunction ensureSuccess(result: ExecResult, path: string): void {\n\tif (result.code !== 0) {\n\t\tthrow new Error(result.stderr || `Failed to write file: ${path}`);\n\t}\n}\n\nexport async function writeContent(\n\texecutor: Executor,\n\tpath: string,\n\tcontent: string,\n\tsignal: AbortSignal | undefined,\n\toptions?: { createParentDir?: boolean },\n): Promise<void> {\n\tconst createParentDir = options?.createParentDir ?? false;\n\tconst dirPrefix = createParentDir ? `mkdir -p ${shellEscape(getDir(path))} && ` : \"\";\n\n\tif (isInlineSafe(content)) {\n\t\tconst result = await executor.exec(`${dirPrefix}printf '%s' ${shellEscape(content)} > ${shellEscape(path)}`, {\n\t\t\tsignal,\n\t\t});\n\t\tensureSuccess(result, path);\n\t\treturn;\n\t}\n\n\tconst result = await executor.exec(`${dirPrefix}cat > ${shellEscape(path)}`, {\n\t\tsignal,\n\t\tstdin: content,\n\t});\n\tensureSuccess(result, path);\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { shellEscape } from "../shell-escape.js";
|
|
2
|
+
const INLINE_WRITE_MAX_BYTES = 64 * 1024;
|
|
3
|
+
function getDir(path) {
|
|
4
|
+
return path.includes("/") ? path.substring(0, path.lastIndexOf("/")) : ".";
|
|
5
|
+
}
|
|
6
|
+
function isInlineSafe(content) {
|
|
7
|
+
return Buffer.byteLength(content, "utf-8") <= INLINE_WRITE_MAX_BYTES;
|
|
8
|
+
}
|
|
9
|
+
function ensureSuccess(result, path) {
|
|
10
|
+
if (result.code !== 0) {
|
|
11
|
+
throw new Error(result.stderr || `Failed to write file: ${path}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function writeContent(executor, path, content, signal, options) {
|
|
15
|
+
const createParentDir = options?.createParentDir ?? false;
|
|
16
|
+
const dirPrefix = createParentDir ? `mkdir -p ${shellEscape(getDir(path))} && ` : "";
|
|
17
|
+
if (isInlineSafe(content)) {
|
|
18
|
+
const result = await executor.exec(`${dirPrefix}printf '%s' ${shellEscape(content)} > ${shellEscape(path)}`, {
|
|
19
|
+
signal,
|
|
20
|
+
});
|
|
21
|
+
ensureSuccess(result, path);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const result = await executor.exec(`${dirPrefix}cat > ${shellEscape(path)}`, {
|
|
25
|
+
signal,
|
|
26
|
+
stdin: content,
|
|
27
|
+
});
|
|
28
|
+
ensureSuccess(result, path);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=write-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-content.js","sourceRoot":"","sources":["../../src/tools/write-content.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzC,SAAS,MAAM,CAAC,IAAY,EAAU;IACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAAA,CAC3E;AAED,SAAS,YAAY,CAAC,OAAe,EAAW;IAC/C,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,sBAAsB,CAAC;AAAA,CACrE;AAED,SAAS,aAAa,CAAC,MAAkB,EAAE,IAAY,EAAQ;IAC9D,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,yBAAyB,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;AAAA,CACD;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,QAAkB,EAClB,IAAY,EACZ,OAAe,EACf,MAA+B,EAC/B,OAAuC,EACvB;IAChB,MAAM,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,KAAK,CAAC;IAC1D,MAAM,SAAS,GAAG,eAAe,CAAC,CAAC,CAAC,YAAY,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAErF,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,eAAe,WAAW,CAAC,OAAO,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE;YAC5G,MAAM;SACN,CAAC,CAAC;QACH,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC5B,OAAO;IACR,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,SAAS,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE;QAC5E,MAAM;QACN,KAAK,EAAE,OAAO;KACd,CAAC,CAAC;IACH,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAAA,CAC5B","sourcesContent":["import type { ExecResult, Executor } from \"../sandbox.js\";\nimport { shellEscape } from \"../shell-escape.js\";\n\nconst INLINE_WRITE_MAX_BYTES = 64 * 1024;\n\nfunction getDir(path: string): string {\n\treturn path.includes(\"/\") ? path.substring(0, path.lastIndexOf(\"/\")) : \".\";\n}\n\nfunction isInlineSafe(content: string): boolean {\n\treturn Buffer.byteLength(content, \"utf-8\") <= INLINE_WRITE_MAX_BYTES;\n}\n\nfunction ensureSuccess(result: ExecResult, path: string): void {\n\tif (result.code !== 0) {\n\t\tthrow new Error(result.stderr || `Failed to write file: ${path}`);\n\t}\n}\n\nexport async function writeContent(\n\texecutor: Executor,\n\tpath: string,\n\tcontent: string,\n\tsignal: AbortSignal | undefined,\n\toptions?: { createParentDir?: boolean },\n): Promise<void> {\n\tconst createParentDir = options?.createParentDir ?? false;\n\tconst dirPrefix = createParentDir ? `mkdir -p ${shellEscape(getDir(path))} && ` : \"\";\n\n\tif (isInlineSafe(content)) {\n\t\tconst result = await executor.exec(`${dirPrefix}printf '%s' ${shellEscape(content)} > ${shellEscape(path)}`, {\n\t\t\tsignal,\n\t\t});\n\t\tensureSuccess(result, path);\n\t\treturn;\n\t}\n\n\tconst result = await executor.exec(`${dirPrefix}cat > ${shellEscape(path)}`, {\n\t\tsignal,\n\t\tstdin: content,\n\t});\n\tensureSuccess(result, path);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG9C,QAAA,MAAM,WAAW;;;;EAIf,CAAC;AAEH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG9C,QAAA,MAAM,WAAW;;;;EAIf,CAAC;AAEH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAoBjF","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { Executor } from \"../sandbox.js\";\nimport { writeContent } from \"./write-content.js\";\n\nconst writeSchema = Type.Object({\n\tlabel: Type.String({ description: \"Brief description of what you're writing (shown to user)\" }),\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport function createWriteTool(executor: Executor): AgentTool<typeof writeSchema> {\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tparameters: writeSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\t{ path, content }: { label: string; path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t) => {\n\t\t\tawait writeContent(executor, path, content, signal, { createParentDir: true });\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|
package/dist/tools/write.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import {
|
|
2
|
+
import { writeContent } from "./write-content.js";
|
|
3
3
|
const writeSchema = Type.Object({
|
|
4
4
|
label: Type.String({ description: "Brief description of what you're writing (shown to user)" }),
|
|
5
5
|
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
|
@@ -12,15 +12,7 @@ export function createWriteTool(executor) {
|
|
|
12
12
|
description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
|
|
13
13
|
parameters: writeSchema,
|
|
14
14
|
execute: async (_toolCallId, { path, content }, signal) => {
|
|
15
|
-
|
|
16
|
-
const dir = path.includes("/") ? path.substring(0, path.lastIndexOf("/")) : ".";
|
|
17
|
-
// Use printf to handle content with special characters, pipe to file
|
|
18
|
-
// This avoids issues with heredoc and special characters
|
|
19
|
-
const cmd = `mkdir -p ${shellEscape(dir)} && printf '%s' ${shellEscape(content)} > ${shellEscape(path)}`;
|
|
20
|
-
const result = await executor.exec(cmd, { signal });
|
|
21
|
-
if (result.code !== 0) {
|
|
22
|
-
throw new Error(result.stderr || `Failed to write file: ${path}`);
|
|
23
|
-
}
|
|
15
|
+
await writeContent(executor, path, content, signal, { createParentDir: true });
|
|
24
16
|
return {
|
|
25
17
|
content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }],
|
|
26
18
|
details: undefined,
|
package/dist/tools/write.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,0DAA0D,EAAE,CAAC;IAC/F,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;IACtF,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;CACrE,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,QAAkB,EAAiC;IAClF,OAAO;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EACV,iIAAiI;QAClI,UAAU,EAAE,WAAW;QACvB,OAAO,EAAE,KAAK,EACb,WAAmB,EACnB,EAAE,IAAI,EAAE,OAAO,EAAoD,EACnE,MAAoB,EACnB,EAAE,CAAC;YACJ,MAAM,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;YAE/E,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,OAAO,CAAC,MAAM,aAAa,IAAI,EAAE,EAAE,CAAC;gBAC1F,OAAO,EAAE,SAAS;aAClB,CAAC;QAAA,CACF;KACD,CAAC;AAAA,CACF","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { Executor } from \"../sandbox.js\";\nimport { writeContent } from \"./write-content.js\";\n\nconst writeSchema = Type.Object({\n\tlabel: Type.String({ description: \"Brief description of what you're writing (shown to user)\" }),\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport function createWriteTool(executor: Executor): AgentTool<typeof writeSchema> {\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tparameters: writeSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\t{ path, content }: { label: string; path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t) => {\n\t\t\tawait writeContent(executor, path, content, signal, { createParentDir: true });\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|