import z from "zod"import { Tool } from "./tool"import DESCRIPTION from "./batch.txt" const DISALLOWED = new Set(["batch"])const FILTERED_FROM_SUGGESTIONS = new Set(["invalid", "patch", ...DISALLOWED]) export const BatchTool = Tool.define("batch", async () => { return { description: DESCRIPTION, parameters: z.object({ tool_calls: z .array( z.object({ tool: z.string().describe("The name of the tool to execute"), parameters: z.object({}).loose().describe("Parameters for the tool"), }), ) .min(1, "Provide at least one tool call") .describe("Array of tool calls to execute in parallel"), }), formatValidationError(error) { const formattedErrors = error.issues .map((issue) => { const path = issue.path.length > 0 ? issue.path.join(".") : "root" return ` - ${path}: ${issue.message}` }) .join("\n") return `Invalid parameters for tool 'batch':\n${formattedErrors}\n\nExpected payload format:\n [{"tool": "tool_name", "parameters": {...}}, {...}]` }, async execute(params, ctx) { const { Session } = await import("../session") const { Identifier } = await import("../id/id") const toolCalls = params.tool_calls.slice(0, 25) const discardedCalls = params.tool_calls.slice(25) const { ToolRegistry } = await import("./registry") const availableTools = await ToolRegistry.tools({ modelID: "", providerID: "" }) const toolMap = new Map(availableTools.map((t) => [t.id, t])) const executeCall = async (call: (typeof toolCalls)[0]) => { const callStartTime = Date.now() const partID = Identifier.ascending("part") try { if (DISALLOWED.has(call.tool)) { throw new Error( `Tool '${call.tool}' is not allowed in batch. Disallowed tools: ${Array.from(DISALLOWED).join(", ")}`, ) } const tool = toolMap.get(call.tool) if (!tool) { const availableToolsList = Array.from(toolMap.keys()).filter((name) => !FILTERED_FROM_SUGGESTIONS.has(name)) throw new Error( `Tool '${call.tool}' not in registry. External tools (MCP, environment) cannot be batched - call them directly. Available tools: ${availableToolsList.join(", ")}`, ) } const validatedParams = tool.parameters.parse(call.parameters) await Session.updatePart({ id: partID, messageID: ctx.messageID, sessionID: ctx.sessionID, type: "tool", tool: call.tool, callID: partID, state: { status: "running", input: call.parameters, time: { start: callStartTime, }, }, }) const result = await tool.execute(validatedParams, { ...ctx, callID: partID }) await Session.updatePart({ id: partID, messageID: ctx.messageID, sessionID: ctx.sessionID, type: "tool", tool: call.tool, callID: partID, state: { status: "completed", input: call.parameters, output: result.output, title: result.title, metadata: result.metadata, attachments: result.attachments, time: { start: callStartTime, end: Date.now(), }, }, }) return { success: true as const, tool: call.tool, result } } catch (error) { await Session.updatePart({ id: partID, messageID: ctx.messageID, sessionID: ctx.sessionID, type: "tool", tool: call.tool, callID: partID, state: { status: "error", input: call.parameters, error: error instanceof Error ? error.message : String(error), time: { start: callStartTime, end: Date.now(), }, }, }) return { success: false as const, tool: call.tool, error } } } const results = await Promise.all(toolCalls.map((call) => executeCall(call))) // Add discarded calls as errors const now = Date.now() for (const call of discardedCalls) { const partID = Identifier.ascending("part") await Session.updatePart({ id: partID, messageID: ctx.messageID, sessionID: ctx.sessionID, type: "tool", tool: call.tool, callID: partID, state: { status: "error", input: call.parameters, error: "Maximum of 25 tools allowed in batch", time: { start: now, end: now }, }, }) results.push({ success: false as const, tool: call.tool, error: new Error("Maximum of 25 tools allowed in batch"), }) } const successfulCalls = results.filter((r) => r.success).length const failedCalls = results.length - successfulCalls const outputMessage = failedCalls > 0 ? `Executed ${successfulCalls}/${results.length} tools successfully. ${failedCalls} failed.` : `All ${successfulCalls} tools executed successfully.\n\nKeep using the batch tool for optimal performance in your next response!` return { title: `Batch execution (${successfulCalls}/${results.length} successful)`, output: outputMessage, attachments: results.filter((result) => result.success).flatMap((r) => r.result.attachments ?? []), metadata: { totalCalls: results.length, successful: successfulCalls, failed: failedCalls, tools: params.tool_calls.map((c) => c.tool), details: results.map((r) => ({ tool: r.tool, success: r.success })), }, } }, }})
import z from "zod"
import { Tool } from "./tool"
import DESCRIPTION from "./batch.txt"
const DISALLOWED = new Set(["batch"])
const FILTERED_FROM_SUGGESTIONS = new Set(["invalid", "patch", ...DISALLOWED])
export const BatchTool = Tool.define("batch", async () => {
return {
description: DESCRIPTION,
parameters: z.object({
tool_calls: z
.array(
z.object({
tool: z.string().describe("The name of the tool to execute"),
parameters: z.object({}).loose().describe("Parameters for the tool"),
}),
)
.min(1, "Provide at least one tool call")
.describe("Array of tool calls to execute in parallel"),
}),
formatValidationError(error) {
const formattedErrors = error.issues
.map((issue) => {
const path = issue.path.length > 0 ? issue.path.join(".") : "root"
return ` - ${path}: ${issue.message}`
})
.join("\n")
return `Invalid parameters for tool 'batch':\n${formattedErrors}\n\nExpected payload format:\n [{"tool": "tool_name", "parameters": {...}}, {...}]`
},
async execute(params, ctx) {
const { Session } = await import("../session")
const { Identifier } = await import("../id/id")
const toolCalls = params.tool_calls.slice(0, 25)
const discardedCalls = params.tool_calls.slice(25)
const { ToolRegistry } = await import("./registry")
const availableTools = await ToolRegistry.tools({ modelID: "", providerID: "" })
const toolMap = new Map(availableTools.map((t) => [t.id, t]))
const executeCall = async (call: (typeof toolCalls)[0]) => {
const callStartTime = Date.now()
const partID = Identifier.ascending("part")
try {
if (DISALLOWED.has(call.tool)) {
throw new Error(
`Tool '${call.tool}' is not allowed in batch. Disallowed tools: ${Array.from(DISALLOWED).join(", ")}`,
)
}
const tool = toolMap.get(call.tool)
if (!tool) {
const availableToolsList = Array.from(toolMap.keys()).filter((name) => !FILTERED_FROM_SUGGESTIONS.has(name))
throw new Error(
`Tool '${call.tool}' not in registry. External tools (MCP, environment) cannot be batched - call them directly. Available tools: ${availableToolsList.join(", ")}`,
)
}
const validatedParams = tool.parameters.parse(call.parameters)
await Session.updatePart({
id: partID,
messageID: ctx.messageID,
sessionID: ctx.sessionID,
type: "tool",
tool: call.tool,
callID: partID,
state: {
status: "running",
input: call.parameters,
time: {
start: callStartTime,
},
},
})
const result = await tool.execute(validatedParams, { ...ctx, callID: partID })
await Session.updatePart({
id: partID,
messageID: ctx.messageID,
sessionID: ctx.sessionID,
type: "tool",
tool: call.tool,
callID: partID,
state: {
status: "completed",
input: call.parameters,
output: result.output,
title: result.title,
metadata: result.metadata,
attachments: result.attachments,
time: {
start: callStartTime,
end: Date.now(),
},
},
})
return { success: true as const, tool: call.tool, result }
} catch (error) {
await Session.updatePart({
id: partID,
messageID: ctx.messageID,
sessionID: ctx.sessionID,
type: "tool",
tool: call.tool,
callID: partID,
state: {
status: "error",
input: call.parameters,
error: error instanceof Error ? error.message : String(error),
time: {
start: callStartTime,
end: Date.now(),
},
},
})
return { success: false as const, tool: call.tool, error }
}
}
const results = await Promise.all(toolCalls.map((call) => executeCall(call)))
// Add discarded calls as errors
const now = Date.now()
for (const call of discardedCalls) {
const partID = Identifier.ascending("part")
await Session.updatePart({
id: partID,
messageID: ctx.messageID,
sessionID: ctx.sessionID,
type: "tool",
tool: call.tool,
callID: partID,
state: {
status: "error",
input: call.parameters,
error: "Maximum of 25 tools allowed in batch",
time: { start: now, end: now },
},
})
results.push({
success: false as const,
tool: call.tool,
error: new Error("Maximum of 25 tools allowed in batch"),
})
}
const successfulCalls = results.filter((r) => r.success).length
const failedCalls = results.length - successfulCalls
const outputMessage =
failedCalls > 0
? `Executed ${successfulCalls}/${results.length} tools successfully. ${failedCalls} failed.`
: `All ${successfulCalls} tools executed successfully.\n\nKeep using the batch tool for optimal performance in your next response!`
return {
title: `Batch execution (${successfulCalls}/${results.length} successful)`,
output: outputMessage,
attachments: results.filter((result) => result.success).flatMap((r) => r.result.attachments ?? []),
metadata: {
totalCalls: results.length,
successful: successfulCalls,
failed: failedCalls,
tools: params.tool_calls.map((c) => c.tool),
details: results.map((r) => ({ tool: r.tool, success: r.success })),
},
}
},
}
})