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 |
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 |
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 |
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., |
None
|
name
|
str
|
Tool name exposed to the LLM. Defaults to |
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 |
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 |
required |
handoff_url
|
str
|
Studio Flow Executions URL
( |
required |
from_address
|
str
|
Twilio phone number used as |
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 |
None
|
description
|
str | None
|
Tool description exposed to the LLM. Defaults to the knowledge
base's |
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
( |
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 |