Tools
Purpose and Scope
Tools are the application-capability layer for Flue agents. They let an agent look up information, call services, or perform controlled changes while it is working, without giving the model unrestricted access to the rest of the application. The Tools guide frames common examples as order lookup, ticket creation, and approval requests, which are operations where the model needs fresh or privileged application data to complete a user-facing task. A tool is not just a prompt hint; it is executable TypeScript that Flue can validate, run, and return to the model as structured context.
Sources: apps/docs/src/content/docs/guide/tools.md
The guide also draws an important boundary between tools, skills, and sandboxes. A skill is reusable instructional content that changes how the agent reasons or follows a procedure. A tool executes application code. Filesystem and command access are not modeled as custom application tools in the guide; those capabilities come from the agent sandbox. This distinction helps authors decide whether they are giving the agent knowledge, a callable business operation, or an execution environment. Keeping those concerns separate makes permission review easier and reduces the temptation to expose broad internal APIs as one oversized tool.
Sources: apps/docs/src/content/docs/guide/tools.md
Relevant Source Files
- apps/docs/src/content/docs/guide/tools.md — First-party guide page defining what tools are for, how to create a custom tool with Valibot schemas, how to attach tools to agents, and how to think about authorization-sensitive inputs.
Core Primitives
The central primitive is the custom tool defined with defineTool(...). A tool has a model-facing name, a natural-language description, optional input and output schemas, and a run function. The name is what the model calls, so it should be clear, action-oriented, and unique among tools available during the same operation. The description is model guidance: it tells the agent when the capability is appropriate. The schema fields define the structured contract between the model and application code, while the run function performs the actual work under application control.
Sources: apps/docs/src/content/docs/guide/tools.md
Input and output validation are part of the authoring model rather than a separate afterthought. The guide uses Valibot for a top-level object input schema and explains that Flue validates model-supplied input before invoking the run function. If validation fails, the model receives a tool error and can try again with corrected arguments. Output schemas provide the opposite side of the contract: Flue validates the returned value, snapshots it as JSON-compatible data, and stringifies it for the model. When no output schema is supplied, authors should still return JSON-compatible data, and an undefined result is sent as null.
Sources: apps/docs/src/content/docs/guide/tools.md
Defining a Custom Tool
A typical tool module lives in shared application code and exports one or more named capabilities. The guide’s order-status example keeps a small order-status map in the same file, defines an input object with an order identifier, declares an output object with a nullable status, and implements an asynchronous run function. That example is intentionally narrow: the tool does one thing, accepts only the information needed for that thing, and returns a small structured answer. This shape is a good default for production tools because it is easy for the model to select and easy for the application to audit.
import { defineTool } from '@flue/runtime';
import * as v from 'valibot';
export const lookupOrderStatus = defineTool({
name: 'lookup_order_status',
description: 'Look up the current fulfillment status for one order ID.',
input: v.object({
orderId: v.pipe(v.string(), v.description('Order ID in the form order_1234')),
}),
output: v.object({
status: v.nullable(v.string()),
}),
async run({ input, signal }) {
return { status: null };
},
});The signal passed to the run function is also part of the operational contract. It lets downstream work respond to cancellation, which matters when a user disconnects, a durable operation is interrupted, or a request no longer needs an external API call. Tool authors should propagate that signal into fetch calls or other cancellable operations where possible. The guide’s example does not need cancellation for an in-memory lookup, but the parameter is visible in the signature so authors design long-running or network-backed tools with cancellation from the beginning.
Sources: apps/docs/src/content/docs/guide/tools.md
Attaching Tools to Agents
Tools become available to an agent through the agent configuration. The guide attaches the exported order-status tool in the tools array returned from defineAgent(...), alongside the model and instructions. When the agent receives a request, the model can decide whether it needs the current order status before answering. The tool call and returned text become part of the session context, so the agent can continue reasoning with the result. This makes tools suitable for stable capabilities that belong to the agent’s ordinary job, such as a customer support assistant checking orders.
import { defineAgent } from '@flue/runtime';
import { lookupOrderStatus } from '../shared/order-tools.ts';
export default defineAgent(() => ({
model: 'anthropic/claude-haiku-4-5',
instructions: 'Help customers check the status of their orders.',
tools: [lookupOrderStatus],
}));The guide also supports a more bounded pattern: instead of configuring a tool as a permanent agent capability, callers can provide tools for a single operation through agent session options such as prompting, skills, or task delegation. Use the stable configuration path when the tool is part of the agent’s identity and should be available whenever it works. Use the per-operation path when the capability is temporary, request-specific, or should not be present in unrelated conversations. This distinction helps reduce accidental tool exposure while still letting a workflow or route provide focused capabilities for one unit of work.
Sources: apps/docs/src/content/docs/guide/tools.md
Protecting Access and Approval-Sensitive Operations
The most important security guidance in the Tools guide is that model-selected parameters are not an authorization boundary. A model can choose values for a tool input, but the application must decide which account, customer, repository, credential, or resource scope the tool is allowed to touch. For an addressable customer-support agent, the guide recommends deriving the accessible customer from the selected agent instance, then allowing the model to choose only values within that already-authorized boundary. In practice, this means tool code should combine model arguments with trusted application context rather than accepting all authority from the input object.
Sources: apps/docs/src/content/docs/guide/tools.md
This access model is especially important for approval-sensitive operations such as creating tickets, approving requests, changing records, or calling third-party services. A well-designed tool should expose the smallest useful action, validate arguments, and enforce application policy before performing side effects. If a capability needs human approval, tenant checks, credential selection, or rate limits, those controls belong in the surrounding application code and in the run function, not in the model prompt alone. The model can propose an action, but the application remains responsible for deciding whether that action is permitted and how it is executed.
Sources: apps/docs/src/content/docs/guide/tools.md
API Shape Reference
| Component | Purpose | Authoring guidance |
|---|---|---|
defineTool(...) | Creates a custom tool that can be attached to an agent or supplied for a bounded operation. | Keep tools narrow, named clearly, and focused on one application capability. |
name | Model-facing tool identifier. | Use action-oriented names such as lookup_order_status; names available together must be distinct. |
description | Guidance that helps the model decide when to call the tool. | Describe the capability and its intended use, not hidden policy. |
input | Optional Valibot object schema for model-supplied arguments. | Validate before work runs; return tool errors to allow model retries. |
output | Optional Valibot schema for structured results. | Return JSON-compatible data; Flue snapshots and stringifies validated output. |
run({ input, signal }) | Application-controlled implementation. | Enforce authorization and propagate cancellation to downstream work. |
Next Steps
After defining a first custom tool, review the agent configuration that will expose it and decide whether it should be a stable capability or a per-operation capability. Then audit the run function for trusted context, tenant scoping, validation, cancellation, and side-effect policy. If the agent also needs reusable operating procedures, read the Skills guide; if it needs filesystem or command execution, read the Sandboxes guide; if it needs delegated specialist work, read the Subagents guide. For public method details around prompt, skill, and task options, continue to the Agent API reference.