Tool Declarations
Tools give ReAct agents the ability to take actions. Hyphen uses a typed tool declaration system: you declare what tools are available, and the resolver handles the rest.
The Two Tool Types
Action Tools
Reference any registered action by name. The resolver automatically fetches the action's description, parameters, and kind from the database.
{ "type": "action", "name": "classify_document" }
That's it. The resolver looks up classify_document in your registered actions, builds parameter hints from its kind and properties, and presents a fully enriched tool definition to the LLM. You don't need to repeat the description or parameters.
Workflow Tools
Reference a workflow by ID. Hyphen resolves it into a callable workflow tool during execution.
{ "type": "workflow", "id": "wfl-123e4567-e89b-12d3-a456-426614174000" }
The resolver fetches the workflow's name and description, then presents it to the LLM by its human-readable name. When the agent invokes the tool, Hyphen executes the workflow as a sub-process through the typed workflow declaration.
Complete Example
An agent that researches companies, enriches data through a pipeline, and sends outreach:
{
"type": "loop",
"properties": {
"mode": "react",
"objective": "Research Acme Corporation and draft an outreach email for review.",
"tools": [
{ "type": "action", "name": "search_company" },
{ "type": "action", "name": "search_news" },
{ "type": "action", "name": "gmail_send" },
{ "type": "workflow", "id": "wfl-123e4567-e89b-12d3-a456-426614174000" }
],
"model": "gpt-4",
"max_iterations": 10,
"on_stuck": { "iterations": 3, "action": "escalate" },
"result_key": "agentResult"
}
}
The agent gets four tools (search_company, search_news, gmail_send, and the enrichment workflow) plus all implicit tools: without any inline descriptions or parameter specs.
Implicit Tools (Always Available)
These tools are automatically injected into every ReAct agent. You never need to declare them:
| Tool | Purpose |
|---|---|
__complete__ |
Signal task completion with answer and confidence |
__pause_for_human__ |
Pause and request human input |
__store_memory__ |
Store data for later retrieval within the session |
__retrieve_memory__ |
Retrieve previously stored data |
__log_progress__ |
Record milestones for observability |
See Built-in Tools for the full parameter reference.
Tool Resolution Order
The resolver processes the tools array in this order:
- Typed objects (
{ type: "action" | "workflow" }): preferred format. Resolved via batched DB queries (max 2 queries regardless of tool count). - Legacy strings (
"action_name"): still supported. Treated as{ type: "action", name: "..." }internally. - Legacy inline objects (
{ name, action, description, parameters }): still supported. Routed as custom tool definitions with full parameter specs. - Implicit tools: always auto-injected after all declared tools are resolved.
Outside this page, prefer typed declarations in examples even though legacy strings remain supported for backward compatibility.
Unresolved actions (not found in registered actions or built-in OAuth actions) are still added to the tool set: the agent receives feedback if it tries to use an unknown tool.
Structural Permissioning
The tools array is an architectural constraint, not a policy layer. The agent cannot discover, invent, or access capabilities beyond what you've declared:
{
"tools": [
{ "type": "action", "name": "block_ip" },
{ "type": "action", "name": "isolate_host" }
]
}
This agent can block IPs and isolate hosts. It cannot delete firewall rules, shut down servers, or take any other action: even if those actions are registered in your org. The tool list defines the boundary.
This is what makes governed autonomy possible. The agent reasons freely within the boundary. The boundary itself is structural.
Legacy Formats (Backward Compatible)
String References
The simplest legacy format. Still fully supported and will remain so indefinitely:
{
"tools": ["lookup_customer", "gmail_send"]
}
Internally converted to { type: "action", name: "lookup_customer" }.
Inline Object Definitions
Full control over what the agent sees. Still supported for backward compatibility, but not recommended for new workflows:
{
"tools": [
{
"name": "calculate_discount",
"action": "discount_calculator",
"description": "Calculate discount based on customer tier and order value",
"parameters": {
"customer_tier": {
"type": "string",
"required": true,
"description": "Customer tier: bronze, silver, gold, platinum"
},
"order_value": {
"type": "number",
"required": true,
"description": "Total order value in USD"
}
}
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Tool name the agent uses in the action field |
action |
string | Yes | Registered action this tool maps to |
description |
string | Yes | What the tool does: shown to the agent in its prompt |
parameters |
object | Yes | Parameter definitions with type, required, description, enum |
The inline object format may be deprecated in a future version. New workflows should use typed declarations exclusively.
All three formats can coexist in the same tools array:
{
"tools": [
{ "type": "action", "name": "search_company" },
"gmail_send",
{
"name": "custom_scorer",
"action": "lead_scoring_api",
"description": "Score a lead based on engagement data",
"parameters": { "lead_id": { "type": "string", "required": true } }
}
]
}
The resolver handles each format appropriately. However, for consistency and maintainability, prefer typed declarations for all new work.
When to Use Each Format
| Format | When to Use |
|---|---|
Typed action { type: "action" } |
Default for all new workflows. Let the resolver pull metadata from the action registration. |
Typed workflow { type: "workflow" } |
When the agent needs to trigger sub-workflows (Pattern B or C). |
Legacy string "name" |
Quick prototyping, or when migrating existing workflows that already use strings. |
| Legacy inline object | Only when you need to override the registered action's description or expose a subset of parameters to the agent. |
Tips for Effective Tool Sets
Fewer tools = better agent performance. Agents reason more effectively with 3-7 tools than with 15. Scope the tool set to what the specific task requires.
Action descriptions matter. The resolver pulls descriptions from your registered actions. Write good action descriptions at registration time, and every agent that references the action benefits.
Use workflow tools for complex sub-processes. Instead of giving the agent 10 granular tools, consider wrapping related steps into a workflow and giving the agent one workflow tool.
Test with reasoning traces. After executing an agent, inspect the reasoning trace at GET /agents/:id/trace. If the agent is misusing tools, the trace shows exactly where the confusion occurs: usually a description problem.
ā Next: Stuck Detection