Skip to content

08.3 Integration Tools

Nikolay Vyahhi edited this page Feb 19, 2026 · 3 revisions

Integration Tools

Relevant source files

The following files were used as context for generating this wiki page:

Integration Tools enable ZeroClaw agents to interact with external services and orchestrate multi-agent workflows. This page covers tools that connect to third-party platforms (Composio), delegate work to specialized sub-agents (Delegate), and send notifications (Pushover).

For core file and system operations, see Core Tools. For browser automation and HTTP requests, see Browser and HTTP Tools. For hardware interaction, see Hardware Tools.


Overview

Integration tools extend agent capabilities beyond local execution by:

  • Composio Integration: Access 200+ third-party applications (Gmail, GitHub, Notion, Slack) without managing OAuth tokens locally
  • Agent Delegation: Orchestrate multi-agent workflows where specialized sub-agents handle specific subtasks
  • Notification Services: Send alerts and notifications to external platforms

These tools are conditionally enabled based on configuration and follow the same security model as core tools, enforcing autonomy levels, rate limiting, and action recording.

Sources: src/tools/mod.rs:1-238, src/tools/composio.rs:1-27, src/tools/delegate.rs:1-27


Tool Registry Integration

Integration tools are registered in the all_tools factory function, which conditionally adds them based on configuration:

Tool Enabled When Configuration Source
composio composio_key parameter is non-empty config.composio.api_key
delegate agents map is non-empty config.agents.*
pushover Always available Credentials in .env file
graph TB
    allTools["all_tools()<br/>(mod.rs:89-238)"]
    composioKey["composio_key:<br/>Option&lt;&str&gt;"]
    agentsMap["agents:<br/>HashMap&lt;String, DelegateAgentConfig&gt;"]
    
    allTools -->|"if composio_key.is_some()"| ComposioTool["ComposioTool::new()<br/>(composio.rs:30-40)"]
    allTools -->|"if !agents.is_empty()"| DelegateTool["DelegateTool::new()<br/>(delegate.rs:29-40)"]
    allTools -->|"always"| PushoverTool["PushoverTool::new()<br/>(pushover.rs:17-22)"]
    
    composioKey --> ComposioTool
    agentsMap --> DelegateTool
    
    ComposioTool --> toolVec["Vec&lt;Box&lt;dyn Tool&gt;&gt;"]
    DelegateTool --> toolVec
    PushoverTool --> toolVec
Loading

Sources: src/tools/mod.rs:210-235, src/config/mod.rs:1-17


Composio Integration

Architecture

ComposioTool provides a unified interface to execute actions on 200+ third-party applications through Composio's managed OAuth platform. It supports both v2 and v3 API endpoints with automatic fallback, enabling compatibility across API versions.

graph LR
    subgraph "ComposioTool Structure"
        Tool["ComposioTool"]
        apiKey["api_key: String"]
        entityId["default_entity_id: String"]
        security["security: Arc&lt;SecurityPolicy&gt;"]
        
        Tool --> apiKey
        Tool --> entityId
        Tool --> security
    end
    
    subgraph "API Endpoints"
        v3["V3 API<br/>backend.composio.dev/api/v3"]
        v2["V2 API<br/>backend.composio.dev/api/v2"]
    end
    
    subgraph "Operations"
        listActions["list_actions()<br/>(composio.rs:46-65)"]
        executeAction["execute_action()<br/>(composio.rs:114-138)"]
        getConnectionUrl["get_connection_url()<br/>(composio.rs:236-264)"]
    end
    
    Tool --> listActions
    Tool --> executeAction
    Tool --> getConnectionUrl
    
    listActions -->|"try v3 first"| v3
    listActions -->|"fallback on error"| v2
    
    executeAction -->|"try v3 first"| v3
    executeAction -->|"fallback on error"| v2
    
    getConnectionUrl -->|"try v3 first"| v3
    getConnectionUrl -->|"fallback on error"| v2
Loading

Sources: src/tools/composio.rs:19-27, src/tools/composio.rs:46-138

Tool Parameters

The composio tool accepts three action types through its parameters schema:

Action Required Parameters Optional Parameters Description
list action app List available actions, optionally filtered by app/toolkit
execute action, action_name or tool_slug, params entity_id, connected_account_id Execute a specific action with parameters
connect action app, auth_config_id, entity_id Get OAuth connection URL for an app

Example parameter schema:

{
  "type": "object",
  "properties": {
    "action": {
      "type": "string",
      "enum": ["list", "execute", "connect"]
    },
    "tool_slug": {
      "type": "string",
      "description": "Preferred v3 tool slug (e.g., 'gmail-send-email')"
    },
    "action_name": {
      "type": "string", 
      "description": "Legacy v2 action name (e.g., 'GMAIL_SEND_EMAIL')"
    },
    "connected_account_id": {
      "type": "string",
      "description": "Specific connected account for multi-account scenarios"
    }
  },
  "required": ["action"]
}

Sources: src/tools/composio.rs:396-436

API Version Fallback

All Composio operations attempt v3 API first, then fall back to v2 on error:

sequenceDiagram
    participant Agent
    participant ComposioTool
    participant V3["Composio V3 API"]
    participant V2["Composio V2 API"]
    
    Agent->>ComposioTool: execute_action(action_name, params)
    ComposioTool->>ComposioTool: normalize_tool_slug()<br/>(composio.rs:595-597)
    
    ComposioTool->>V3: POST /api/v3/tools/{slug}/execute
    
    alt V3 Success
        V3-->>ComposioTool: Result JSON
        ComposioTool-->>Agent: ToolResult(success=true)
    else V3 Error
        V3-->>ComposioTool: Error
        ComposioTool->>V2: POST /api/v2/actions/{name}/execute
        
        alt V2 Success
            V2-->>ComposioTool: Result JSON
            ComposioTool-->>Agent: ToolResult(success=true)
        else V2 Error
            V2-->>ComposioTool: Error
            ComposioTool-->>Agent: ToolResult(success=false)<br/>Combined error message
        end
    end
Loading

Sources: src/tools/composio.rs:114-138, src/tools/composio.rs:166-198, src/tools/composio.rs:200-234

Entity ID Management

Composio uses entity IDs to scope OAuth connections in multi-user setups:

  • Default Entity: Set via default_entity_id parameter in ComposioTool::new(), typically from config.composio.entity_id
  • Per-Request Override: Can be specified in the entity_id parameter of action execution
  • Normalization: Empty or whitespace-only entity IDs fall back to "default"

Entity ID flows through v3 API as user_id and v2 API as entityId.

Sources: src/tools/composio.rs:30-40, src/tools/composio.rs:586-593, src/tools/composio.rs:446-448

Security Integration

ComposioTool enforces security checks before executing actions or initiating OAuth flows:

graph TB
    execute["Tool.execute(args)"]
    parseAction["Parse 'action' parameter"]
    
    execute --> parseAction
    
    parseAction -->|"action='execute'"| checkAct["security.enforce_tool_operation(<br/>ToolOperation::Act,<br/>'composio.execute')"]
    parseAction -->|"action='connect'"| checkConnect["security.enforce_tool_operation(<br/>ToolOperation::Act,<br/>'composio.connect')"]
    parseAction -->|"action='list'"| performList["Perform list operation<br/>(read-only, no check)"]
    
    checkAct -->|"ReadOnly mode"| denyAct["Return error:<br/>'read-only mode'"]
    checkAct -->|"Rate limited"| denyRate["Return error:<br/>'Rate limit exceeded'"]
    checkAct -->|"Approved"| performExecute["Execute action via API"]
    
    checkConnect -->|"Denied"| denyConnect["Return error message"]
    checkConnect -->|"Approved"| performConnect["Get OAuth URL via API"]
Loading

Sources: src/tools/composio.rs:490-500, src/tools/composio.rs:535-545

Tool Slug Normalization

The v3 API uses kebab-case slugs (e.g., gmail-send-email) while v2 uses UPPER_SNAKE_CASE (e.g., GMAIL_SEND_EMAIL). The tool normalizes action names by:

  1. Trimming whitespace
  2. Replacing underscores with hyphens
  3. Converting to lowercase

This allows agents to use either format, which the tool automatically converts to v3 format before attempting the v3 endpoint.

Sources: src/tools/composio.rs:595-597


Delegate Tool

Multi-Agent Orchestration

DelegateTool enables hierarchical agent workflows where a primary agent can delegate specialized subtasks to secondary agents with different provider/model configurations. This supports patterns like:

  • Research + Execution: Primary agent uses a fast model, delegates deep research to a specialized reasoning model
  • Code Generation: Primary agent delegates code tasks to a code-optimized model
  • Summarization: Primary agent delegates long-context summarization to a model with large context windows
graph TB
    subgraph "DelegateTool Structure"
        Tool["DelegateTool"]
        agents["agents: Arc&lt;HashMap&lt;String, DelegateAgentConfig&gt;&gt;"]
        security["security: Arc&lt;SecurityPolicy&gt;"]
        fallback["fallback_credential: Option&lt;String&gt;"]
        depth["depth: u32"]
        
        Tool --> agents
        Tool --> security
        Tool --> fallback
        Tool --> depth
    end
    
    subgraph "DelegateAgentConfig"
        config["DelegateAgentConfig"]
        provider["provider: String"]
        model["model: String"]
        systemPrompt["system_prompt: Option&lt;String&gt;"]
        apiKey["api_key: Option&lt;String&gt;"]
        maxDepth["max_depth: u32"]
        
        config --> provider
        config --> model
        config --> systemPrompt
        config --> apiKey
        config --> maxDepth
    end
    
    agents -.contains.-> config
Loading

Sources: src/tools/delegate.rs:19-58, src/config/mod.rs:7-9

Delegation Flow

sequenceDiagram
    participant Primary as Primary Agent
    participant DelegateTool
    participant Security as SecurityPolicy
    participant Provider as Sub-Agent Provider
    participant SubAgent as Sub-Agent LLM
    
    Primary->>DelegateTool: execute({"agent": "researcher", "prompt": "..."})
    
    DelegateTool->>DelegateTool: Validate parameters<br/>(delegate.rs:105-138)
    DelegateTool->>DelegateTool: Look up agent config
    
    DelegateTool->>DelegateTool: Check depth >= max_depth
    alt Depth Limit Exceeded
        DelegateTool-->>Primary: ToolResult(error: "depth limit reached")
    end
    
    DelegateTool->>Security: enforce_tool_operation(Act, "delegate")
    alt Security Check Failed
        Security-->>DelegateTool: Error
        DelegateTool-->>Primary: ToolResult(error: security message)
    end
    
    DelegateTool->>DelegateTool: Resolve API key<br/>(agent.api_key OR fallback_credential)
    DelegateTool->>Provider: create_provider(provider, credential)
    
    DelegateTool->>DelegateTool: Build prompt with optional context
    DelegateTool->>Provider: timeout(120s,<br/>chat_with_system(system_prompt, prompt, model, temp))
    
    Provider->>SubAgent: LLM Request
    SubAgent-->>Provider: Response
    Provider-->>DelegateTool: Result
    
    DelegateTool-->>Primary: ToolResult(output: "[Agent 'researcher'...]\n{response}")
Loading

Sources: src/tools/delegate.rs:104-265

Depth Limiting

Delegation depth prevents infinite recursion when agents delegate to each other:

  • Depth Tracking: Each DelegateTool instance has an immutable depth field set at construction
  • Per-Agent Limit: Each agent config specifies max_depth (default: 3)
  • Check Logic: self.depth >= agent_config.max_depth rejects the delegation
  • Sub-Agent Construction: When sub-agents get their own tool registries, their DelegateTool must be created via DelegateTool::with_depth(agents, credential, security, parent.depth + 1)
graph TD
    Primary["Primary Agent<br/>depth=0"]
    Researcher["Researcher Sub-Agent<br/>depth=1<br/>max_depth=3"]
    Coder["Coder Sub-Agent<br/>depth=2<br/>max_depth=2"]
    Blocked["Delegation Blocked<br/>depth=2 >= max_depth=2"]
    
    Primary -->|"delegate to researcher"| Researcher
    Researcher -->|"delegate to coder"| Coder
    Coder -.->|"attempts delegation"| Blocked
    
    style Blocked fill:#ffcccc
Loading

Sources: src/tools/delegate.rs:43-57, src/tools/delegate.rs:160-172

Credential Resolution

API keys for sub-agent providers follow a two-tier resolution:

  1. Agent-Specific Key: agent_config.api_key if set
  2. Fallback Credential: self.fallback_credential (typically from root config.api_key)

This allows per-agent credentials for specialized provider access while defaulting to a shared credential for consistency.

Sources: src/tools/delegate.rs:186-192

Timeout Protection

All sub-agent provider calls are wrapped in a 120-second timeout to prevent indefinite blocking:

tokio::time::timeout(
    Duration::from_secs(DELEGATE_TIMEOUT_SECS),
    provider.chat_with_system(...)
)

Timeout expiration returns a ToolResult with success=false and an error message indicating the agent timed out.

Sources: src/tools/delegate.rs:12-13, src/tools/delegate.rs:218-240

Context Parameter

The context parameter allows the primary agent to provide background information to the sub-agent:

  • Optional: Can be omitted or empty
  • Formatting: When non-empty, prepended to prompt as [Context]\n{context}\n\n[Task]\n{prompt}
  • Use Cases: Passing relevant code snippets, prior findings, or domain-specific knowledge

Sources: src/tools/delegate.rs:133-137, src/tools/delegate.rs:209-213


Pushover Notification Tool

Overview

PushoverTool sends push notifications to devices via the Pushover API. It reads credentials from the workspace .env file and supports priority levels and sound customization.

graph LR
    subgraph "PushoverTool"
        Tool["PushoverTool"]
        security["security: Arc&lt;SecurityPolicy&gt;"]
        workspace["workspace_dir: PathBuf"]
        
        Tool --> security
        Tool --> workspace
    end
    
    subgraph "Credential Storage"
        envFile[".env file<br/>in workspace_dir"]
        token["PUSHOVER_TOKEN"]
        userKey["PUSHOVER_USER_KEY"]
        
        envFile --> token
        envFile --> userKey
    end
    
    subgraph "Pushover API"
        endpoint["POST https://api.pushover.net/1/messages.json"]
        form["multipart/form-data:<br/>token, user, message,<br/>title, priority, sound"]
        
        endpoint --> form
    end
    
    Tool -->|"get_credentials()"| envFile
    Tool -->|"execute()"| endpoint
Loading

Sources: src/tools/pushover.rs:11-23, src/tools/pushover.rs:8-9

Parameter Schema

Parameter Type Required Description
message string Yes Notification message content
title string No Notification title (defaults to app name)
priority integer No Priority level: -2 (silent), -1 (low), 0 (normal), 1 (high), 2 (emergency)
sound string No Notification sound override (e.g., 'pushover', 'bike', 'bugle')

Priority validation enforces range -2..=2 and rejects values outside this range with an error.

Sources: src/tools/pushover.rs:88-112, src/tools/pushover.rs:141-153

Credential Parsing

Credentials are parsed from .env with support for:

  • Comments: Lines starting with # are ignored
  • Export Prefix: export VAR=value syntax supported
  • Quoted Values: Single and double quotes are stripped
  • Inline Comments: Values can have trailing comments (e.g., KEY=value # comment)
flowchart TD
    readEnv["Read .env file<br/>(pushover.rs:46-47)"]
    parseLine["For each line"]
    checkComment{{"Line starts with #<br/>or is empty?"}}
    stripExport["Strip 'export ' prefix"]
    splitKV["Split on '='"]
    parseValue["parse_env_value()<br/>(pushover.rs:24-42)"]
    checkKey{{"Key is PUSHOVER_TOKEN<br/>or PUSHOVER_USER_KEY?"}}
    store["Store credential"]
    
    readEnv --> parseLine
    parseLine --> checkComment
    checkComment -->|"Yes"| parseLine
    checkComment -->|"No"| stripExport
    stripExport --> splitKV
    splitKV --> parseValue
    parseValue --> checkKey
    checkKey -->|"Yes"| store
    checkKey -->|"No"| parseLine
    store --> parseLine
Loading

Sources: src/tools/pushover.rs:44-75, src/tools/pushover.rs:24-42

Security Enforcement

Before sending notifications, the tool enforces two security checks:

  1. Autonomy Check: security.can_act() returns false in ReadOnly mode
  2. Rate Limiting: security.record_action() returns false when rate limit exceeded

Both checks return a ToolResult with success=false and an appropriate error message.

Sources: src/tools/pushover.rs:115-129

API Request Flow

sequenceDiagram
    participant Agent
    participant PushoverTool
    participant EnvFile as .env File
    participant Client as HTTP Client
    participant API as Pushover API
    
    Agent->>PushoverTool: execute({"message": "...", "priority": 1})
    
    PushoverTool->>PushoverTool: Security checks (can_act, record_action)
    
    PushoverTool->>EnvFile: get_credentials()
    EnvFile-->>PushoverTool: (token, user_key)
    
    PushoverTool->>PushoverTool: Build multipart form
    PushoverTool->>Client: build_runtime_proxy_client_with_timeouts<br/>("tool.pushover", 15, 10)
    
    PushoverTool->>API: POST /1/messages.json<br/>multipart form
    
    API-->>PushoverTool: HTTP response + JSON body
    
    PushoverTool->>PushoverTool: Check status.is_success()<br/>Check json["status"] == 1
    
    alt Success (status=1)
        PushoverTool-->>Agent: ToolResult(success=true, output="sent successfully")
    else API Error
        PushoverTool-->>Agent: ToolResult(success=false, error="API error")
    end
Loading

Sources: src/tools/pushover.rs:114-214


Configuration

Composio Configuration

Composio tool requires API key configuration in config.toml:

[composio]
api_key = "sk_composio_..."
entity_id = "default"  # Optional, defaults to "default"

The API key is stored in the encrypted secret store when secrets.encrypt = true.

Sources: src/config/mod.rs:8-9

Delegate Agent Configuration

Delegate agents are configured in the [agents.*] section:

[agents.researcher]
provider = "ollama"
model = "llama3"
system_prompt = "You are a research assistant."
temperature = 0.3
max_depth = 3

[agents.coder]
provider = "openrouter"
model = "anthropic/claude-sonnet-4-20250514"
api_key = "sk_or_..."  # Optional, falls back to config.api_key
max_depth = 2

Each agent configuration becomes a DelegateAgentConfig in the tools registry.

Sources: src/config/mod.rs:9, src/tools/mod.rs:222-234

Pushover Configuration

Pushover credentials are stored in the workspace .env file (not in config.toml):

# .env in workspace directory
PUSHOVER_TOKEN=azGDORePK8gMaC0QOYAMyEEuzyh
PUSHOVER_USER_KEY=uQiRzpo4DXghDmr9QzzfQu27cmVRsG

This keeps notification credentials separate from the main configuration and allows per-workspace notification settings.

Sources: src/tools/pushover.rs:44-75


Testing Integration Tools

Test Coverage

Integration tools have comprehensive test coverage:

Tool Test Count Coverage Areas
ComposioTool 30+ tests Parameter validation, API versioning, error handling, security enforcement
DelegateTool 20+ tests Depth limiting, credential resolution, parameter validation, security
PushoverTool 15+ tests Credential parsing, priority validation, security checks

Sources: src/tools/composio.rs:763-1110, src/tools/delegate.rs:268-577, src/tools/pushover.rs:217-433

Mocking External Services

Integration tool tests avoid real external API calls by:

  • Composio: Testing internal logic (normalization, schema validation, error message sanitization) without network calls
  • Delegate: Using invalid provider names that fail at provider creation, not network layer
  • Pushover: Testing credential parsing and schema validation without API calls

Tests that would require external services return predictable errors at the provider/client creation stage.

Sources: src/tools/composio.rs:812-839, src/tools/delegate.rs:395-415


Error Handling Patterns

API Version Fallback Error Messages

When both v3 and v2 API calls fail, Composio tool generates combined error messages:

anyhow::bail!(
    "Composio execute failed on v3 ({v3_err}) and v2 fallback ({v2_err})"
)

This provides visibility into both failure modes for debugging.

Sources: src/tools/composio.rs:132-136

Timeout Error Messages

Delegate tool generates timeout-specific errors with the agent name and duration:

format!("Agent '{agent_name}' timed out after {DELEGATE_TIMEOUT_SECS}s")

Sources: src/tools/delegate.rs:235-238

Credential Error Messages

Pushover tool provides specific error messages for missing credentials:

  • "PUSHOVER_TOKEN not found in .env"
  • "PUSHOVER_USER_KEY not found in .env"
  • "Failed to read {path}: {error}"

Sources: src/tools/pushover.rs:70-72


Security Considerations

Tool Operation Enforcement

Integration tools that perform actions (not read-only queries) enforce ToolOperation::Act:

  • Composio execute/connect: Enforces before API calls
  • Delegate: Enforces before provider creation
  • Pushover: Uses can_act() and record_action() directly

Sources: src/tools/composio.rs:491-500, src/tools/delegate.rs:174-183, src/tools/pushover.rs:115-129

Credential Isolation

Different credential storage mechanisms provide defense-in-depth:

  • Composio: API key in encrypted secret store, entity IDs separate user contexts
  • Delegate: Per-agent API keys support least-privilege access to providers
  • Pushover: Workspace-scoped .env file prevents cross-workspace credential leakage

Sources: src/tools/composio.rs:24, src/tools/delegate.rs:186-192, src/tools/pushover.rs:44-75

Error Message Sanitization

Composio tool sanitizes error messages to prevent credential leakage:

for marker in [
    "connected_account_id", "connectedAccountId",
    "entity_id", "entityId",
    "user_id", "userId",
] {
    sanitized = sanitized.replace(marker, "[redacted]");
}

Sources: src/tools/composio.rs:652-675


Clone this wiki locally