Tools & Agents

Enable LLMs to call functions during generation. Define tools with Zod schemas.

import.ts
import { defineTool, executeToolCall } from "@tryhamster/gerbil";

Quick Start

Create a tool file in .gerbil/tools/:

.gerbil/tools/weather.tool.ts
01// .gerbil/tools/weather.tool.ts
02export default {
03 name: "get_weather",
04 description: "Get current weather for a city",
05 execute: async (params, ctx) => {
06 const { city } = params;
07 // Your implementation
08 return `Weather in ${city}: 72°F, sunny`;
09 },
10};

No imports needed! Tools are automatically discovered from .gerbil/tools/.

Built-in Tools

gerbil_docs

Search Gerbil documentation for any topic.

docs-tool.ts
import { docsTool } from "@tryhamster/gerbil";
const result = await docsTool({ query: "streaming" });
// Returns documentation about streaming responses

Available topics:

  • quickstart, generate, stream, json, thinking, embed
  • models, load, ai-sdk, next, express, react, hono
  • langchain, mcp, skills, define-skill, cli, tools

run_skill

Execute any Gerbil skill.

skills-tool.ts
import { skillsTool } from "@tryhamster/gerbil";
const result = await skillsTool({
skill: "summarize",
input: "Long article text..."
});

Defining Custom Tools

Simple Format (Recommended)

Tools use a simple export format with no imports required:

.gerbil/tools/calculator.tool.ts
01// .gerbil/tools/calculator.tool.ts
02export default {
03 name: "calculator",
04 description: "Perform basic math calculations",
05 execute: async (params, ctx) => {
06 const { expression } = params;
07 try {
08 const result = eval(expression);
09 return `${expression} = ${result}`;
10 } catch {
11 return `Error: Invalid expression`;
12 }
13 },
14};

Tool Context

Tools receive a context object with access to the LLM:

.gerbil/tools/generate_joke.tool.ts
01// .gerbil/tools/generate_joke.tool.ts
02export default {
03 name: "generate_joke",
04 description: "Generate a joke about a topic",
05 execute: async (params, ctx) => {
06 const { topic } = params;
07
08 // Use ctx.generate() to call the LLM!
09 if (ctx?.generate) {
10 const joke = await ctx.generate(`Tell me a short joke about ${topic}`);
11 return joke;
12 }
13
14 return "Could not generate joke";
15 },
16};

Create Tool Wizard

The REPL includes a 4-step guided wizard to create tools:

  1. Name — Tool name (snake_case)
  2. Description — What the tool does
  3. Parameters — Inputs (optional, press Enter to skip)
  4. Logic — What to return

The wizard uses AI to generate the execute function body, then saves to .gerbil/tools/.

Tool Registry

Tools are automatically registered when defined:

registry.ts
01import {
02 defineTool,
03 getTool,
04 listTools,
05 getToolDefinitions
06} from "@tryhamster/gerbil";
07
08// Define registers automatically
09const myTool = defineTool({ ... });
10
11// Get by name
12const tool = getTool("my-tool");
13
14// List all tools
15console.log(listTools());
16// ["gerbil_docs", "run_skill", "my-tool"]
17
18// Get all definitions (for prompt injection)
19const definitions = getToolDefinitions();

Using Tools

REPL Tools View

Manage tools in the REPL (press 3 or navigate to Tools):

Terminal
gerbil repl
# Press 3 for Tools view
  • x — Execute tool directly
  • c — Create a new tool (guided wizard)
  • o — Open tool file in VS Code
  • Enter — Expand tool details

Tools are shown with badges: [builtin], [project], or [error].

REPL Agent Mode

Use tools automatically in Chat with Agent mode:

Terminal
gerbil repl
# In Chat view: press ⌘A to toggle Agent mode
# Or Tab to cycle modes → select "Agent"

In Agent mode, the model can see available tools, call them by outputting JSON, and receive tool results to synthesize a response.

Programmatic Usage

programmatic.ts
01import {
02 formatToolsForPrompt,
03 parseToolCall,
04 executeToolCall,
05 getToolDefinitions
06} from "@tryhamster/gerbil";
07
08// Add tools to system prompt
09const tools = getToolDefinitions();
10const systemPrompt = `You are a helpful assistant.
11
12${formatToolsForPrompt(tools)}`;
13
14// Generate response
15const response = await gerbil.generate(userQuery, {
16 system: systemPrompt
17});
18
19// Check for tool calls
20const toolCall = parseToolCall(response.text);
21if (toolCall) {
22 const result = await executeToolCall(toolCall.tool, toolCall.params);
23 // Continue conversation with tool result
24}

Tool Call Format

Gerbil uses a simple JSON format for tool calls:

format.json
{
"tool": "tool_name",
"params": {
"param1": "value1",
"param2": "value2"
}
}

The model is prompted to output this format when it wants to use a tool.

Connecting Skills as Tools

Skills and tools share similar structures. Expose skills as tools:

skills-as-tools.ts
01import { useSkill, defineTool } from "@tryhamster/gerbil";
02import { z } from "zod";
03
04// Get a skill
05const summarizeSkill = useSkill("summarize");
06
07// Wrap as tool
08const summarizeTool = defineTool({
09 name: "summarize",
10 description: "Summarize text content",
11 parameters: z.object({
12 content: z.string(),
13 length: z.enum(["short", "medium", "long"]).default("short"),
14 }),
15 execute: async ({ content, length }) => {
16 const result = await summarizeSkill({ content, length });
17 return result;
18 },
19});

API Reference

ToolDefinition

ToolDefinition.ts
interface ToolDefinition<TParams = unknown> {
/** Tool name (function name) */
name: string;
/** Description for the LLM */
description: string;
/** Zod schema for parameters */
parameters?: z.ZodType<TParams>;
/** The function to execute */
execute: (params: TParams) => Promise<string>;
}

Functions

functions.ts
// Define a tool (auto-registers)
defineTool(definition: ToolDefinition): Tool
// Get tool by name
getTool(name: string): Tool | undefined
// List all tool names
listTools(): string[]
// Get all definitions for prompt injection
getToolDefinitions(): ToolDefinition[]
// Format tools for system prompt
formatToolsForPrompt(tools: ToolDefinition[]): string
// Parse tool call from LLM response
parseToolCall(response: string): { tool: string; params: any } | null
// Execute a tool call
executeToolCall(name: string, params: any): Promise<string>

Model Compatibility

Tool calling works best with:

  • Qwen3-0.6B — Excellent tool calling support
  • Qwen2.5 models — Good support
  • ~Phi-3 — Moderate support
  • SmolLM2 — May struggle with consistent formatting

Best Practices

  • 1.Clear descriptions — The model uses descriptions to decide when to call tools
  • 2.Simple parameters — Use basic types when possible
  • 3.Helpful errors — Return clear error messages
  • 4.Validate inputs — Zod schemas validate before execution
  • 5.Keep responses concise — Long tool outputs consume context