Tool System
Define tools, register them, gate by permissions, bridge to AI SDK, and execute with tracking.
Overview
Tools are functions that agents can call. The tool system provides:
- Definition -- typed input schemas via Zod, execute functions, permission requirements
- Registration -- centralized tool registry with lookup by slug
- Permission gating -- tools filtered by caller's permissions before agents see them
- AI bridge -- convert platform tools to AI SDK v6 tool format
- Execution -- tracked execution with duration, errors, and output
Defining Tools
import { defineTool } from "@sprinterai/core";
import { z } from "zod";
const roiCalculator = defineTool({
slug: "roi-calculator",
name: "ROI Calculator",
description: "Calculate return on investment for a deal",
category: "finance",
icon: "calculator",
requiredPermission: "entities.team.read",
inputSchema: z.object({
investment: z.number().describe("Initial investment amount"),
returns: z.number().describe("Total returns"),
years: z.number().optional().describe("Investment period in years"),
}),
execute: async (input) => {
const { investment, returns, years } = input as {
investment: number;
returns: number;
years?: number;
};
const roi = ((returns - investment) / investment) * 100;
const annualized = years ? (Math.pow(returns / investment, 1 / years) - 1) * 100 : null;
return {
roi: `${roi.toFixed(1)}%`,
annualized: annualized ? `${annualized.toFixed(1)}%` : null,
};
},
});Tool Registry
import { ToolRegistry } from "@sprinterai/runtime";
const registry = new ToolRegistry();
registry.register(roiCalculator);
registry.register(dealScorer);
registry.register(companyLookup);
// Lookup by slug
const tool = registry.get("roi-calculator");
// List all tools
const all = registry.list();
// Filter by category
const financeTools = registry.list().filter(t => t.category === "finance");Built-in Entity Tools
The platform provides 8 entity tools out of the box:
import { createEntityTools } from "@sprinterai/runtime";
const entityTools = createEntityTools(stores.entity, userPermissions);| Tool | Required Permission |
|---|---|
searchEntities | entities.team.read |
getEntity | entities.team.read |
createEntity | entities.team.create |
updateEntity | entities.team.update |
deleteEntity | entities.team.delete |
createRelation | entities.team.update |
listEntityTypes | entities.team.read |
getEntityStats | entities.team.read |
Tool Groups
Tools are organized into groups for agent configuration:
| Group | Tools |
|---|---|
entity | searchEntities, getEntity, createEntity, updateEntity, deleteEntity, createRelation, listEntityTypes, getEntityStats |
response | submitResponse |
web | webSearch |
workflow | getWorkflowStatus, triggerWorkflow, retryNode |
context | addCorrection, addLesson, getUsageStats |
admin | 14 admin tools (entity type CRUD, view management, agent config, etc.) |
Permission Gating
Tools declare their required permissions. When resolving tools for an agent, the platform filters out tools the caller cannot use:
import { resolveAgentTools } from "@sprinterai/runtime";
// Only tools the user has permission for are included
const tools = await resolveAgentTools({
agent: agentDefinition,
stores,
permissions: userPermissions,
includeEntityTools: true,
});The agent never sees tools it cannot use. This is enforced at resolution time, not at execution time.
AI Bridge
Convert platform tools to AI SDK v6 format:
import { toAITool, toAIToolSet } from "@sprinterai/runtime";
// Single tool -> AI SDK tool
const aiTool = toAITool(roiCalculator);
// Multiple tools -> AI SDK tool set (with permission filtering)
const toolSet = toAIToolSet(allTools, userPermissions);
// Use with AI SDK streamText
import { streamText } from "ai";
const result = await streamText({
model,
tools: toolSet,
messages,
});Tool Execution
import { executeTool } from "@sprinterai/runtime";
const result = await executeTool({
tool: roiCalculator,
input: { investment: 1000000, returns: 1500000, years: 3 },
permissions: userPermissions,
});
// result.output -- the tool's return value
// result.error -- error message if failed
// result.duration -- execution time in msIf the tool declares a requiredPermission and the caller lacks it, executeTool will reject the call.
Collaborative Tools
Tools can be marked as collaborative for multi-user sessions:
const whiteboard = defineTool({
slug: "whiteboard",
name: "Whiteboard",
description: "Collaborative whiteboard",
category: "collaboration",
collaborative: true, // enables tool sessions
inputSchema: z.object({ /* ... */ }),
execute: async (input) => { /* ... */ },
});Collaborative tools support sessions (ToolSession) where multiple users interact with the tool's state over time.
Custom Tool UI
Tools can have custom input forms and output displays. Register UI components alongside the tool definition:
// features/custom/tools/roi-calculator/input-form.tsx
export function ROICalculatorInput({ onSubmit }) {
// Custom form UI
}
// features/custom/tools/roi-calculator/output-display.tsx
export function ROICalculatorOutput({ data }) {
// Custom output rendering
}Tool Types
interface ToolDefinition {
slug: string;
name: string;
description: string;
category: string;
icon?: string;
inputSchema: z.ZodType;
execute: (input: unknown) => Promise<unknown>;
collaborative?: boolean;
requiredPermission?: AppPermission;
}
interface ToolSession {
id: string;
tool_slug: string;
status: ToolSessionStatus; // "active" | "completed" | "archived"
created_by: string;
participants: string[];
metadata: Record<string, unknown>;
}
interface ToolRun {
id: string;
tool_slug: string;
session_id: string | null;
input: Record<string, unknown>;
output: Record<string, unknown> | null;
error: string | null;
duration_ms: number;
created_at: string;
}