Skip to content

Tools

tac.tools

Tools and utilities for the Twilio Agent Connect.

InjectedToolArg

Marker class for tool arguments that are injected at runtime.

Tool arguments annotated with this class are not included in the tool schema sent to language models and are instead injected during execution.

Inspired by LangChain's InjectedToolArg pattern.

Example

@function_tool() def my_tool( user_input: str, client: Annotated[MyClient, InjectedToolArg] ) -> str: # client is injected, not visible to LLM return client.process(user_input)

TACTool dataclass

TACTool(
    name: str,
    description: str,
    params_json_schema: dict[str, object],
    _raw_implementation: Callable[..., object],
)

Represents a tool/function that can be used with LLMs.

Similar to OpenAI's FuncSchema, this captures function metadata for LLM tool integration. Supports runtime injection of dependencies that are hidden from the LLM schema.

implementation property

implementation: Callable[..., Awaitable[object]]

Get a clean callable with only non-injected parameters in its signature.

This property automatically returns the right callable for LLM SDK introspection. The returned callable has only non-injected parameters in its signature while automatically handling dependency injection when called.

Returns an async callable since TAC is async-first.

Returns:

Type Description
Callable[..., Awaitable[object]]

An async callable with clean signature that can be inspected by any LLM SDK

Example
Pass to LLM SDK - it will introspect the clean signature

sdk.add_tool(tool.implementation)

configure_injection

configure_injection(**kwargs: object) -> TACTool

Configure values to be injected at runtime when the tool is called.

These values correspond to parameters marked with InjectedToolArg annotations and will be automatically supplied when the tool executes.

Validates that provided values match the expected types from the function signature using Pydantic TypeAdapter for robust validation of all Python type annotations including generics, Pydantic models, Literal types, and complex unions.

Parameters:

Name Type Description Default
**kwargs object

Mapping of parameter names to values to inject

{}

Returns:

Type Description
TACTool

Self for method chaining

Raises:

Type Description
TypeError

If a provided value doesn't match the expected type

ValueError

If an unknown parameter name is provided

Warning

Do not directly mutate _injected_args. Always use configure_injection() to ensure proper cache invalidation and type validation.

Example

tool.configure_injection(client=conversation_memory_client, config=tac_config)

to_openai_format

to_openai_format() -> dict[str, object]

Get tool schema in OpenAI function calling format.

Returns:

Type Description
dict[str, object]

Dictionary in OpenAI function format

to_anthropic_format

to_anthropic_format() -> dict[str, object]

Get tool schema in Anthropic tool calling format.

Returns:

Type Description
dict[str, object]

Dictionary in Anthropic tool format

to_openai_agents_sdk_tool

to_openai_agents_sdk_tool() -> FunctionTool

Convert this tool to an OpenAI Agents SDK FunctionTool instance.

Unlike to_openai_format and to_anthropic_format (which return plain dicts consumed by HTTP APIs), the OpenAI Agents SDK dispatches on tool class, so this returns a live FunctionTool object with an on_invoke closure that calls this tool and JSON-encodes the result.

Requires the openai-agents package:

pip install openai-agents

Returns:

Type Description
FunctionTool

A FunctionTool ready to pass to Agent(tools=[...]).

to_json

to_json() -> str

Convert tool to JSON string (OpenAI format by default).

create_tool

create_tool(
    name: str,
    description: str,
    params_json_schema: dict[str, object],
    implementation: Callable[..., object],
) -> TACTool

Create a TAC tool manually with explicit schema.

Parameters:

Name Type Description Default
name str

The name of the tool/function

required
description str

Description of what the tool does

required
params_json_schema dict[str, object]

JSON Schema for the tool's parameters

required
implementation Callable[..., object]

Function that implements the tool's logic

required

Returns:

Type Description
TACTool

TACTool instance

function_tool

function_tool(
    name: str | None = None, description: str | None = None
) -> Callable[[Callable[..., object]], TACTool]

Decorator to create a TAC tool from a function.

Similar to OpenAI's function_tool decorator approach.

Parameters:

Name Type Description Default
name str | None

Optional name override (defaults to function name)

None
description str | None

Optional description override (defaults to docstring)

None

Returns:

Type Description
Callable[[Callable[..., object]], TACTool]

Decorator function

build_handoff_payload

build_handoff_payload(
    session: ConversationSession,
    memory_store_id: str,
    attributes: dict[str, Any],
) -> HandoffPayload

Build a HandoffPayload from session context and attributes.

Useful for custom handoff tools that want TAC's payload shape without the Studio-specific delivery in post_studio_handoff.

Parameters:

Name Type Description Default
session ConversationSession

Current conversation session

required
memory_store_id str

Memory store ID (typically tac.conversation_memory_client.store_id)

required
attributes dict[str, Any]

Developer-defined attributes (including reason)

required

Returns:

Type Description
HandoffPayload

HandoffPayload with conversation context and attributes

create_studio_handoff_tool

create_studio_handoff_tool(
    tac: TAC,
    session: ConversationSession,
    attributes: dict[str, Any] | None = None,
    *,
    name: str = DEFAULT_HANDOFF_TOOL_NAME,
    description: str = DEFAULT_HANDOFF_TOOL_DESCRIPTION,
) -> TACTool

Create a handoff tool that delivers in the Twilio Studio Executions API shape.

The returned tool exposes only handoff(reason: str) to the LLM. All other dependencies are injected at runtime.

On digital channels, the tool POSTs to the Studio Flow Executions endpoint derived from tac.config.studio_handoff_flow_sid (https://studio.twilio.com/v2/Flows/{flow_sid}/Executions) using form-encoded To / From / Parameters fields with HTTP Basic auth. The Studio flow can access the handoff payload via {{flow.data.HandoffData.*}}.

For voice channels, the payload is stored on the session and the voice channel automatically sends the WS end message with handoffData after the LLM's final response is delivered.

The tool also sets the conversation to INACTIVE and clears status callbacks to prevent further webhook events from being routed to TAC.

Not available in ConversationRelay-only mode. This tool requires Conversation Orchestrator for conversation state management (setting INACTIVE status, clearing callbacks) and Conversation Memory for the handoff payload's storeId. In relay-only mode, implement a custom handoff by setting session.pending_handoff_data directly — the voice channel will send the WebSocket end message with your payload, and your <Connect action> URL handler can route the call accordingly.

Parameters:

Name Type Description Default
tac TAC

TAC instance for building payload and posting to Studio

required
session ConversationSession

Current conversation session

required
attributes dict[str, Any] | None

Static attributes to include in the handoff payload (e.g., {"department": "billing", "priority": "high"}). The LLM-provided reason is always added automatically.

None
name str

Tool name exposed to the LLM. Defaults to "handoff".

DEFAULT_HANDOFF_TOOL_NAME
description str

Tool description exposed to the LLM. Customize when the default's phrasing doesn't match your product vocabulary or escalation policy.

DEFAULT_HANDOFF_TOOL_DESCRIPTION

Returns:

Type Description
TACTool

Configured TACTool instance for handoff

Example

handoff_tool = create_studio_handoff_tool( ... tac, ... context, ... attributes={"department": "support"}, ... name="escalate_to_agent", ... description="Escalate only for billing disputes over $100.", ... )

Raises:

Type Description
ValueError

If tac.config.studio_handoff_flow_sid is unset, if Conversation Orchestrator is not configured (relay-only mode), or if no memory store ID is available.

post_studio_handoff async

post_studio_handoff(
    payload: HandoffPayload,
    session: ConversationSession,
    *,
    handoff_url: str,
    from_address: str,
    api_key: str,
    api_secret: str,
) -> None

POST a handoff payload to a Twilio Studio Flow Executions endpoint.

Emits the Twilio Studio Executions API wire format: form-encoded To / From / Parameters fields with HTTP Basic auth. Parameters is a JSON string keyed under HandoffData so Studio can reference it via {{flow.data.HandoffData.*}}.

Parameters:

Name Type Description Default
payload HandoffPayload

Structured handoff payload

required
session ConversationSession

Current conversation session (used for To address)

required
handoff_url str

Studio Flow Executions URL (https://studio.twilio.com/v2/Flows/FWxxx/Executions)

required
from_address str

Twilio phone number used as From

required
api_key str

Twilio API Key SID (Basic auth username)

required
api_secret str

Twilio API Key Secret (Basic auth password)

required

Raises:

Type Description
HTTPError

If the POST request fails

create_knowledge_tool async

create_knowledge_tool(
    knowledge_client: KnowledgeClient,
    knowledge_base_id: str,
    *,
    name: str | None = None,
    description: str | None = None,
    top_k: int = 5,
) -> TACTool

Create a knowledge search tool for the given knowledge base.

Creates a function tool that searches the specified knowledge using Twilio's Knowledge Base Search API via KnowledgeClient. The tool uses dependency injection to hide the knowledge client and knowledge ID from the LLM schema.

If both name and description are provided, uses them directly (no API call). If either is missing, fetches the knowledge base metadata to derive defaults.

Parameters:

Name Type Description Default
knowledge_client KnowledgeClient

KnowledgeClient instance for searching knowledge bases

required
knowledge_base_id str

Knowledge base ID string (e.g., "know_knowledgebase_...")

required
name str | None

Tool name exposed to the LLM. Defaults to search_<kb_display_name> (fetched from the knowledge base if unset).

None
description str | None

Tool description exposed to the LLM. Defaults to the knowledge base's description field (fetched if unset).

None
top_k int

Number of knowledge chunks to return per query. Defaults to 5.

5

Returns:

Type Description
TACTool

A configured TACTool that searches the specified knowledge with injected dependencies

Example with custom name and description (no API call): >>> tool = await create_knowledge_tool( ... knowledge_client=tac.knowledge_client, ... knowledge_base_id="know_knowledgebase_...", ... name="search_promotions", ... description="Search for promotions and discounts", ... top_k=3, ... )

Example using KB metadata as defaults (fetches KB): >>> tool = await create_knowledge_tool( ... knowledge_client=tac.knowledge_client, ... knowledge_base_id="know_knowledgebase_...", ... top_k=3, ... )

search_knowledge async

search_knowledge(
    query: str,
    knowledge_client: Annotated[
        KnowledgeClient, InjectedToolArg
    ],
    knowledge_base_id: Annotated[str, InjectedToolArg],
    top_k: Annotated[int, InjectedToolArg],
) -> list[KnowledgeChunkResult]

Search the knowledge base with the given query.

Parameters:

Name Type Description Default
query str

The search query string (max 2048 characters)

required
knowledge_client Annotated[KnowledgeClient, InjectedToolArg]

KnowledgeClient instance for API calls (injected, not visible to LLM)

required
knowledge_base_id Annotated[str, InjectedToolArg]

Knowledge base ID to search (injected, not visible to LLM)

required
top_k Annotated[int, InjectedToolArg]

Number of chunks to return (injected, not visible to LLM)

required

Returns:

Type Description
list[KnowledgeChunkResult]

List of KnowledgeChunkResult objects with content, knowledge_id, created_at, and score

create_memory_tool

create_memory_tool(
    conversation_memory_client: MemoryClient,
    session: ConversationSession,
    *,
    name: str | None = None,
    description: str | None = None,
) -> TACTool

Create memory tool with injected MemoryClient and session context.

Parameters:

Name Type Description Default
conversation_memory_client MemoryClient

MemoryClient instance for retrieving memories

required
session ConversationSession

Current session identity with profile and conversation IDs

required
name str | None

Tool name exposed to the LLM. Defaults to the function name ("retrieve_profile_memory").

None
description str | None

Tool description exposed to the LLM. Defaults to the function's docstring.

None

Returns:

Type Description
TACTool

Configured memory tool

Example

tool = create_memory_tool( ... conversation_memory_client, ... session, ... name="recall_customer_history", ... description="Recall prior preferences and complaints for this customer.", ... ) result = await tool(query="user preferences")

retrieve_profile_memory async

retrieve_profile_memory(
    query: str,
    conversation_memory_client: Annotated[
        MemoryClient, InjectedToolArg
    ],
    profile_id: Annotated[str, InjectedToolArg],
) -> dict[str, Any]

Search and retrieve relevant memories for the current profile.

Performs semantic search across the user's conversation history, observations, and stored traits to find contextually relevant information.

Parameters:

Name Type Description Default
query str

What to search for in the user's memory (e.g., "preferences about food", "previous complaints", "contact information")

required

Returns:

Type Description
dict[str, Any]

Dictionary containing relevant memories, traits, and metadata