FrostAgent’s tool system gives the LLM a structured way to take actions in the world — sending messages, spawning subagents, fetching weather data, and querying game versions. Every tool is a self-contained Go struct with a JSON Schema definition that the Engine forwards to the LLM so the model knows exactly what arguments each tool accepts. When the LLM requests a tool call, the Engine looks up the tool in the registry, invokes itsDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/GuaiZai233/FrostAgent/llms.txt
Use this file to discover all available pages before exploring further.
Execute function with the JSON arguments, and feeds the result back into the conversation.
Tool Interface
Each tool ininternal/tools/tools.go is a Tool struct with four methods that satisfy the llm.ToolExecutor interface expected by the Engine:
| Method | Returns | Purpose |
|---|---|---|
Name() | string | Unique identifier used to register the tool and match LLM tool-call requests. |
Description() | string | Human-readable description sent to the LLM to help it decide when to call this tool. |
Parameters() | map[string]any | A JSON Schema object definition. The Engine sends this alongside Name and Description in every ChatRequest. |
Execute(args string) | (string, error) | Called by the Engine with the JSON-encoded arguments the LLM produced. Returns a plain-text or JSON result that is appended as a role: "tool" message. |
args is always a raw JSON string produced by the LLM. Your Execute implementation should unmarshal it with json.Unmarshal and validate required fields before acting on them.Tool Registry
Registry (in internal/tools/registry.go) stores tool metadata and executor functions in two parallel maps, allowing fast lookup by name.
NewRegistry() *Registry
Creates an empty registry with pre-allocated maps.
Register(t Tool)
Adds a tool to both internal maps. Calling Register with a name that already exists silently overwrites the previous entry.
GetTool(name string) (Tool, bool)
Returns the full Tool struct (including its schema) for a given name, or false if not found.
GetExecutor(name string) (func(args string) (string, error), bool)
Returns just the executor closure for a given tool name. Useful when you want to call a tool programmatically without going through the full registry.
ListTools() []Tool
Returns all registered tool definitions as a slice. Order is non-deterministic (Go map iteration). The Engine uses this to build the Tools array on every ChatRequest.
Execute(name, args string) (string, error)
Looks up the executor by name and calls it with args. Returns "tool not found" (not an error) if the name is unknown.
Built-In Tools
FrostAgent ships with four tools registered at startup incmd/app/main.go.
1. send_message
Delivers a rich message to the user over the active OneBot connection. The Engine fires SendHook when this tool executes, causing the adapter to send the message immediately rather than waiting for the LLM’s final turn.
| Parameter | Type | Required | Description |
|---|---|---|---|
messages | array | ✅ | Sequence of message payload objects. |
messages[].type | string | ✅ | plain, image, record, video, file, mention_user, or quote. |
messages[].text | string | For plain | The text string to send. |
messages[].path | string | For media types | Local file path (prefixed file:// by the adapter). |
messages[].url | string | For media types | Remote URL for the media file. |
messages[].mention_user_id | string | For mention_user | QQ user ID to @-mention. |
messages[].message_id | string | For quote | ID of the message to quote/reply to. |
session | string | ❌ | Override the target session (platform_id:message_type:session_id). Defaults to the active session. |
2. use_subagent
Dispatches a task to a named subagent. Currently supports the Coder subagent, which is specialised for code generation tasks.
| Parameter | Type | Required | Description |
|---|---|---|---|
subagent_name | string | ✅ | Name of the subagent to call. Currently "Coder". |
content | string | ✅ | The task description or code snippet to send to the subagent. |
The
use_subagent tool expects send_message to be called first to inform the user that the subagent has been dispatched. This is enforced through the tool’s description prompt.3. get_weather
Returns current weather information for a named city.
| Parameter | Type | Required | Description |
|---|---|---|---|
city | string | ✅ | The name of the city to query. |
execute closure with a call to your preferred weather API to make it live.
4. get_game_version
Returns the latest version string for a named game.
| Parameter | Type | Required | Description |
|---|---|---|---|
game | string | ✅ | The name of the game to query. |
get_weather, this tool returns a mocked response (V1.14.51) by default and is intended to be extended with a real data source.
Registering Tools in main.go
Tools are registered incmd/app/main.go during the init() function. The current setup uses the Engine’s internal map[string]ToolExecutor directly:
Tool Execution Flow
The following describes exactly how the Engine processes a tool call once the LLM returns a response:LLM returns tool_calls
The
Provider.Chat response includes one or more ToolCall entries. Each has an ID, a Type (always "function"), and a Function with a Name and JSON-encoded Arguments string.Engine iterates tool calls
runLoop iterates responseMsg.ToolCalls. For each entry it looks up the tool in ToolRegistry by tc.Function.Name.Execute is called
tool.Execute(tc.Function.Arguments) is called with the raw JSON arguments string. The tool’s closure unmarshals the arguments, validates them, and returns a result string or an error.SendHook fires for send_message
If the tool name is
"send_message" and engine.SendHook != nil, the Engine calls SendHook(toolResult) immediately. The adapter parses the JSON result and writes a fully-formed OneBot action frame to the WebSocket. The Engine then replaces toolResult with "消息已发送" before continuing.Tool result appended
A new
ChatMessage with Role: "tool", Content: toolResult, and ToolCallID: tc.ID is appended to the message slice so the LLM knows what each tool returned.