بنقرة واحدة
create-local-tool
// Scaffold a new local tool for the voice agent pipeline with capability-based registration, executor function, ToolDefinition, and tests
// Scaffold a new local tool for the voice agent pipeline with capability-based registration, executor function, ToolDefinition, and tests
Scaffold a new A2A capability agent with Python application, Dockerfile, requirements.txt, and CDK stack following the project's established patterns
Run an ECS scaling validation test with parallel monitoring, baseline enforcement, and automated result documentation
Sets up Daily.co phone number and webhook for PSTN dial-in. Guides through API key verification, phone number purchase, pinless dial-in configuration, and secrets sync. Use after deploying infrastructure, when setting up a phone number, or when configuring dial-in.
Scaffolds a new A2A capability agent with Python application, Dockerfile, requirements.txt, and CDK stack. Use when adding a new remote tool or service that the voice agent discovers via CloudMap.
Scaffolds a new local tool for the voice agent pipeline with capability-based registration, executor function, and tests. Use when adding a tool that runs inside the voice agent container and may need transport or SIP session access.
Deploys optional A2A capability agents (Knowledge Base, CRM) that extend the voice agent with new skills. Explains the A2A architecture, enables the capability registry, deploys agent stacks, and verifies discovery. Use after the core deployment and Daily setup are complete.
| name | create-local-tool |
| description | Scaffold a new local tool for the voice agent pipeline with capability-based registration, executor function, ToolDefinition, and tests |
Scaffold all the files needed for a new local tool in the voice agent pipeline. This includes:
backend/voice-agent/app/tools/builtin/{name}_tool.py)ALL_LOCAL_TOOLS in catalog.py)backend/voice-agent/tests/test_{name}_tool.py)No pipeline code or CDK changes are needed -- the capability system handles registration automatically.
Use this skill when you need to create a new tool that runs inside the voice agent container and may need access to pipeline internals (transport, SIP session, DTMF, recording control). For remote tools that run as separate services, use the create-capability-agent skill instead.
Read docs/guides/adding-a-local-tool.md for the complete developer guide. Templates below are derived from that guide and the shipped time_tool and transfer_tool implementations.
Ask the user for:
hangup_call). This becomes the function name the LLM sees.description field, which is critical for LLM tool selection.Check existing tool names to avoid conflicts:
| Name | Source | Agent |
|---|---|---|
get_current_time | Local | Voice Agent |
hangup_call | Local | Voice Agent |
transfer_to_agent | Local | Voice Agent |
search_knowledge_base | A2A | KB Agent (backend/agents/knowledge-base-agent/) |
lookup_customer | A2A | CRM Agent (backend/agents/crm-agent/) |
create_support_case | A2A | CRM Agent |
add_case_note | A2A | CRM Agent |
verify_account_number | A2A | CRM Agent |
verify_recent_transaction | A2A | CRM Agent |
Create backend/voice-agent/app/tools/builtin/{name}_tool.py:
"""Description of this tool.
Capability requirements:
- List each capability and why it's needed
"""
from typing import Any, Dict
from ..capabilities import PipelineCapability
from ..context import ToolContext
from ..result import ToolResult, success_result, error_result
from ..schema import ToolCategory, ToolDefinition, ToolParameter
async def {name}_executor(
arguments: Dict[str, Any],
context: ToolContext,
) -> ToolResult:
"""Execute the tool.
Args:
arguments: Validated parameters from the LLM
context: ToolContext with call_id, session_id, transport, etc.
Returns:
ToolResult via success_result() or error_result()
"""
# Tool logic here
return success_result({"key": "value"})
{name}_tool = ToolDefinition(
name="{tool_name}",
description="...",
category=ToolCategory.SYSTEM,
parameters=[...],
executor={name}_executor,
timeout_seconds=5.0,
requires=frozenset({PipelineCapability.BASIC}),
)
Key requirements:
async defToolResult via success_result() or error_result()description -- the LLM uses this to decide when to call the toolrequires to the minimum set of capabilities neededcontext.transportcontext.sip_session_idEdit backend/voice-agent/app/tools/builtin/catalog.py:
from .{name}_tool import {name}_tool
ALL_LOCAL_TOOLS: List[ToolDefinition] = [
time_tool,
transfer_tool,
hangup_tool,
{name}_tool, # <-- add here
]
Create backend/voice-agent/tests/test_{name}_tool.py:
"""Tests for {name}_tool."""
import pytest
from app.tools.builtin.{name}_tool import {name}_tool, {name}_executor
from app.tools.capabilities import PipelineCapability
from app.tools.context import ToolContext
class TestToolDefinition:
def test_name(self):
assert {name}_tool.name == "{tool_name}"
def test_requires(self):
assert {name}_tool.requires == frozenset({PipelineCapability.BASIC})
def test_in_catalog(self):
from app.tools.builtin.catalog import ALL_LOCAL_TOOLS
assert {name}_tool in ALL_LOCAL_TOOLS
class TestToolExecutor:
@pytest.fixture
def context(self):
return ToolContext(call_id="test-call", session_id="test-session")
@pytest.mark.asyncio
async def test_basic_execution(self, context):
result = await {name}_executor({}, context)
assert result.success is True
cd backend/voice-agent && .venv/bin/python -m pytest tests/test_{name}_tool.py -v
Also run the full suite to verify no regressions:
cd backend/voice-agent && .venv/bin/python -m pytest tests/ -v
Before finishing, verify:
async def and returns ToolResultrequires declares the minimum capabilities neededdescription is specific enough for the LLM to know when to use itALL_LOCAL_TOOLS in catalog.pypytest tests/test_{name}_tool.py -v