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.

json
{ "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.

json
{ "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:

json
{
  "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:

  1. Typed objects ({ type: "action" | "workflow" }): preferred format. Resolved via batched DB queries (max 2 queries regardless of tool count).
  2. Legacy strings ("action_name"): still supported. Treated as { type: "action", name: "..." } internally.
  3. Legacy inline objects ({ name, action, description, parameters }): still supported. Routed as custom tool definitions with full parameter specs.
  4. 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:

json
{
  "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:

json
{
  "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:

json
{
  "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.

### Mixing Formats

All three formats can coexist in the same tools array:

json
{
  "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