> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fibonacci.today/llms.txt
> Use this file to discover all available pages before exploring further.

# ToolNode

> Node for executing external tool and API integrations

The `ToolNode` class runs a Fibonacci platform tool — connecting workflows to services like Google Sheets, Slack, databases, and HTTP APIs.

## Constructor

```python theme={null}
from fibonacci import ToolNode

node = ToolNode(
    id="fetch_data",
    name="Fetch Sheet Data",
    tool="google_sheets_read",
    params={
        "spreadsheet_id": "{{input.sheet_id}}",
        "range": "A1:D100"
    }
)
```

### Parameters

| Parameter      | Type        | Default  | Description                                                               |
| -------------- | ----------- | -------- | ------------------------------------------------------------------------- |
| `id`           | `str`       | Required | Unique node identifier (lowercase letters, numbers, underscores, hyphens) |
| `name`         | `str`       | Required | Human-readable node name                                                  |
| `tool`         | `str`       | Required | Tool name (e.g., `"google_sheets_read"`, `"slack_send_message"`)          |
| `params`       | `dict`      | Required | Input parameters for the tool — supports `{{variable}}` template syntax   |
| `timeout`      | `int`       | `30`     | Execution timeout in seconds                                              |
| `dependencies` | `list[str]` | `[]`     | Node IDs this node waits for before running                               |
| `enable_retry` | `bool`      | `False`  | Retry on failure                                                          |
| `max_retries`  | `int`       | `3`      | Maximum retry attempts (used when `enable_retry=True`)                    |
| `retry_delay`  | `float`     | `1.0`    | Initial delay in seconds between retries                                  |

<Note>
  Tool names use **underscore format** (e.g., `google_sheets_read`, `slack_send_message`). Use `list_tools()` or `print_tool_info()` to see available tools and their exact names.
</Note>

## Template Variables in Params

Any value in `params` can reference dynamic data:

```python theme={null}
node = ToolNode(
    id="notify",
    name="Send Notification",
    tool="slack_send_message",
    params={
        "channel": "#{{input.team}}",
        "message": "Analysis complete: {{analyze_data}}"
    }
)
```

| Syntax              | Source                                   |
| ------------------- | ---------------------------------------- |
| `{{input.field}}`   | Workflow input data                      |
| `{{node_id}}`       | Full output of another node              |
| `{{node_id.field}}` | Specific field from a node's JSON output |

## Tool Categories

### Google Workspace

```python theme={null}
# Read from Google Sheets
read_sheet = ToolNode(
    id="read_sheet",
    name="Read Sheet",
    tool="google_sheets_read",
    params={
        "spreadsheet_id": "{{input.sheet_id}}",
        "range": "Sheet1!A1:D100"
    }
)

# Write to Google Sheets
write_sheet = ToolNode(
    id="write_sheet",
    name="Write Results",
    tool="google_sheets_write",
    params={
        "spreadsheet_id": "{{input.sheet_id}}",
        "range": "Results!A1",
        "values": [["Name", "Score"], ["Alice", "95"]]
    }
)

# Append rows
append_row = ToolNode(
    id="append_row",
    name="Append Log Row",
    tool="google_sheets_append",
    params={
        "spreadsheet_id": "{{input.sheet_id}}",
        "range": "Log!A:D",
        "values": [["{{input.id}}", "{{analyze_data}}"]]
    }
)

# Read a Google Doc
read_doc = ToolNode(
    id="read_doc",
    name="Read Document",
    tool="google_docs_read",
    params={
        "document_id": "{{input.doc_id}}"
    }
)

# Create a Google Doc
create_doc = ToolNode(
    id="create_doc",
    name="Create Document",
    tool="google_docs_create",
    params={
        "title": "{{input.title}}",
        "content": "{{generate_report}}"
    }
)

# Send email via Gmail
send_email = ToolNode(
    id="send_email",
    name="Send Email",
    tool="gmail_send",
    params={
        "to": "recipient@example.com",
        "subject": "Your Report is Ready",
        "body": "{{executive_summary}}"
    }
)

# Create a Google Calendar event
create_event = ToolNode(
    id="create_event",
    name="Schedule Meeting",
    tool="google_calendar_create_event",
    params={
        "summary": "Follow-up Meeting",
        "start": "2025-06-01T10:00:00",
        "end": "2025-06-01T11:00:00",
        "attendees": ["team@company.com"]
    }
)
```

### Communication

```python theme={null}
# Slack — send a message
slack_msg = ToolNode(
    id="notify_team",
    name="Notify Team",
    tool="slack_send_message",
    params={
        "channel": "#team-updates",
        "message": "Report ready: {{executive_summary}}"
    }
)

# Slack — DM a user
slack_dm = ToolNode(
    id="dm_user",
    name="DM User",
    tool="slack_send_message",
    params={
        "channel": "@john.doe",
        "message": "Your task is complete."
    }
)
```

### HTTP & APIs

```python theme={null}
# Generic HTTP request
api_call = ToolNode(
    id="call_api",
    name="Call External API",
    tool="http_request",
    params={
        "method": "POST",
        "url": "https://api.example.com/data",
        "headers": {
            "Authorization": "Bearer {{input.api_token}}",
            "Content-Type": "application/json"
        },
        "body": {
            "query": "{{input.search_term}}"
        }
    }
)

# Webhook
webhook = ToolNode(
    id="trigger_webhook",
    name="Trigger Webhook",
    tool="webhook_call",
    params={
        "url": "https://hooks.zapier.com/hooks/catch/123/abc",
        "payload": {
            "event": "report_generated",
            "data": "{{report_data}}"
        }
    }
)
```

### Databases

```python theme={null}
query = ToolNode(
    id="query_db",
    name="Query Database",
    tool="database_query",
    params={
        "connection_string": "{{secrets.DATABASE_URL}}",
        "query": """
            SELECT customer_id, SUM(amount) AS total
            FROM orders
            WHERE date >= '{{input.start_date}}'
            GROUP BY customer_id
            ORDER BY total DESC
            LIMIT 10
        """
    }
)
```

<Warning>
  Never hardcode database credentials. Use the `secrets` parameter in `wf.run()` or the Fibonacci secrets manager.
</Warning>

### Cloud Storage

```python theme={null}
# Upload to S3
s3_upload = ToolNode(
    id="upload_s3",
    name="Upload to S3",
    tool="s3_upload",
    params={
        "bucket": "my-reports",
        "key": "reports/{{input.report_id}}.pdf",
        "content": "{{report_pdf}}",
        "content_type": "application/pdf"
    }
)

# Download from S3
s3_download = ToolNode(
    id="download_s3",
    name="Download from S3",
    tool="s3_download",
    params={
        "bucket": "my-data",
        "key": "data/{{input.file_name}}"
    }
)
```

### CRM & Business

```python theme={null}
# Create a Salesforce lead
create_lead = ToolNode(
    id="create_lead",
    name="Create Salesforce Lead",
    tool="salesforce_create",
    params={
        "object": "Lead",
        "data": {
            "FirstName": "{{input.first_name}}",
            "LastName": "{{input.last_name}}",
            "Email": "{{input.email}}",
            "Company": "{{input.company}}"
        }
    }
)

# Update a HubSpot contact
hubspot_contact = ToolNode(
    id="update_contact",
    name="Update HubSpot Contact",
    tool="hubspot_update_contact",
    params={
        "email": "{{input.email}}",
        "properties": {
            "lead_score": "{{score_lead}}"
        }
    }
)

# Create a Notion page
notion_page = ToolNode(
    id="create_notion",
    name="Create Notion Page",
    tool="notion_create_page",
    params={
        "database_id": "{{input.database_id}}",
        "properties": {
            "Name": "{{input.title}}",
            "Status": "Ready"
        },
        "content": "{{generate_notes}}"
    }
)
```

## Tool Discovery

### List Available Tools

```python theme={null}
from fibonacci import list_tools, list_tool_categories

# All tools
tools = list_tools()
for tool in tools:
    print(f"{tool['name']}: {tool['description']}")

# By category
categories = list_tool_categories()
for cat in categories:
    print(f"{cat['name']}: {cat['count']} tools")
```

### Search Tools

```python theme={null}
from fibonacci import search_tools

results = search_tools("slack")
for tool in results:
    print(f"{tool['name']}: {tool['description']}")
```

### Inspect a Tool

```python theme={null}
from fibonacci import print_tool_info

print_tool_info("google_sheets_read")
```

Output:

```
======================================================================
🔧 google_sheets_read
======================================================================
Category: google_workspace
Description: Read data from a Google Sheets spreadsheet

📥 Input Parameters:
  • spreadsheet_id (string) - required
  • range (string) - required
    A1 notation range (e.g., "Sheet1!A1:D10")

📖 Examples:
  1. Read sales data
     Params: {"spreadsheet_id": "abc123", "range": "Sales!A1:E100"}
======================================================================
```

### Find the Right Tool

```python theme={null}
from fibonacci import find_tool_for_task

tool = find_tool_for_task("send a message to slack")
print(tool)  # "slack_send_message"

tool = find_tool_for_task("read data from google sheets")
print(tool)  # "google_sheets_read"
```

## Dependencies

```python theme={null}
# Read data
read = ToolNode(
    id="read_source",
    name="Read Source Sheet",
    tool="google_sheets_read",
    params={"spreadsheet_id": "...", "range": "A1:Z100"}
)

# Write results (waits for read to finish)
write = ToolNode(
    id="write_dest",
    name="Write Destination Sheet",
    tool="google_sheets_write",
    params={
        "spreadsheet_id": "...",
        "range": "A1",
        "values": "{{read_source}}"
    },
    dependencies=["read_source"]
)
```

## Timeout Configuration

```python theme={null}
slow_api = ToolNode(
    id="slow_api",
    name="Long-Running API",
    tool="http_request",
    params={"url": "https://api.example.com/slow-endpoint"},
    timeout=120   # override the 30s default
)
```

## Retry Configuration

```python theme={null}
# Via constructor
api_call = ToolNode(
    id="api_call",
    name="Reliable API Call",
    tool="http_request",
    params={"url": "https://api.example.com"},
    enable_retry=True,
    max_retries=5,
    retry_delay=2.0
)

# Via fluent method
api_call = ToolNode(
    id="api_call",
    name="Reliable API Call",
    tool="http_request",
    params={"url": "https://api.example.com"}
).with_retry(max_retries=5, delay=2.0)
```

## Conditional Execution

```python theme={null}
notify_urgent = ToolNode(
    id="notify_urgent",
    name="Notify Urgent",
    tool="slack_send_message",
    params={
        "channel": "#urgent",
        "message": "Urgent issue: {{analyzer}}"
    }
).with_condition(
    left_value="{{analyzer_urgency}}",
    operator="equals",
    right_value="high"
)
```

## YAML Configuration

```yaml theme={null}
nodes:
  - id: notify
    name: Notify Team
    type: tool
    tool_name: slack_send_message
    tool_params:
      channel: "#analytics"
      message: "Analysis complete: {{analyze}}"
    dependencies:
      - analyze
```

## Complete Example

```python theme={null}
from fibonacci import Workflow, LLMNode, ToolNode

wf = Workflow(name="data-pipeline")

# Fetch data
fetch = ToolNode(
    id="fetch_data",
    name="Read Sheet",
    tool="google_sheets_read",
    params={
        "spreadsheet_id": "{{input.sheet_id}}",
        "range": "Data!A1:Z1000"
    }
)

# Analyze with LLM
analyze = LLMNode(
    id="analyze",
    name="Analyze Data",
    instruction="Analyze this data and find key insights: {{fetch_data}}",
    model="claude-sonnet-4-6",
    dependencies=["fetch_data"]
)

# Notify via Slack
notify = ToolNode(
    id="notify",
    name="Send Report",
    tool="slack_send_message",
    params={
        "channel": "#analytics",
        "message": "Analysis complete for {{input.sheet_id}}:\n{{analyze}}"
    },
    dependencies=["analyze"]
)

wf.add_nodes([fetch, analyze, notify])

result = wf.run(input_data={"sheet_id": "abc123"})
print(result.output_data)
```
