CrewAI integration

View as Markdown

dial-crewai packages Dial’s operations as CrewAI tools, so a multi-agent crew can send messages, receive OTP codes, and place calls as part of its work. It’s the CrewAI sibling of the LangChain integration: each tool is a crewai.tools.BaseTool subclass wrapping the Python SDK client — it adds nothing to the REST contract, it just shapes Dial’s operations into CrewAI tools.

Install

pip install dial-crewai

This pulls in dial-sdk and crewai.

Give the tools to a crew

Build one DialClient, pass it to dial_tools, and hand the list to an agent. Every tool shares that one client — a single connection pool for the whole crew:

from crewai import Agent
from dial_sdk import DialClient, DialConfig
from dial_crewai import dial_tools
dial = DialClient(DialConfig(api_key="sk_live_..."))
phone_agent = Agent(
role="Phone identity agent",
goal="Send and receive SMS so the crew can complete phone-verified signups",
backstory="You operate the crew's Dial phone number.",
tools=dial_tools(dial),
)

dial_tools returns the full set, all sharing your client — the analog of LangChain’s DialToolkit.get_tools(). CrewAI agents take a plain tools=[...] list.

Available tools

Each tool takes your shared DialClient (client=):

ToolAction
ListNumbersToolList your phone numbers
PurchaseNumberToolProvision a new number (billable)
SetNumberPropertiesToolUpdate a number’s nickname or inbound instruction
SendMessageToolSend an SMS
ReplyToMessageToolReply or react to a message
StartTypingToolShow a typing indicator (iMessage numbers; SMS numbers ignore it)
StopTypingToolClear a typing indicator
ListMessagesToolList recent messages
MakeCallToolPlace an AI voice call
ListCallsToolList recent calls
GetCallToolFetch one call by id
GetBillingToolCredit balance, subscription, per-number mode
WaitForMessageToolBlock until the next inbound SMS arrives, or time out

Or pick individual tools

from dial_crewai import SendMessageTool, WaitForMessageTool
tools = [
SendMessageTool(client=dial),
WaitForMessageTool(client=dial),
]

Handling OTP

The reason a crew needs phone identity: receive a verification code and act on it. WaitForMessageTool blocks until the next inbound SMS arrives, so an agent can trigger a signup that texts a code to your Dial number, read the code, and enter it back into the form.

from crewai import Agent, Crew, Task
from dial_sdk import DialClient, DialConfig
from dial_crewai import SendMessageTool, WaitForMessageTool
dial = DialClient(DialConfig(api_key="sk_live_..."))
signup_agent = Agent(
role="Signup agent",
goal="Complete a phone-verified signup by reading the OTP sent to our Dial number",
backstory="You wait for verification codes on the crew's Dial number and read them back.",
tools=[SendMessageTool(client=dial), WaitForMessageTool(client=dial)],
)
wait_for_otp = Task(
description="Wait up to 120 seconds for the inbound verification code on our Dial number, then report it.",
expected_output="The verification code that was texted to our number.",
agent=signup_agent,
)
Crew(agents=[signup_agent], tasks=[wait_for_otp]).kickoff()

A full runnable example is in examples/signup_crew.py.

The dial-sdk client is async; these tools are sync-first (_run) with an async→sync bridge, and also expose _arun for async crews. SendMessageTool is a write action and isn’t idempotent — a re-invoke after a failure can send a duplicate. MakeCallTool accepts an idempotency_key. See Retries and idempotency.

Receiving events beyond a single wait

WaitForMessageTool is a one-shot wait, backed by a presence-based stream (not at-least-once — missed events replay only on reconnect within ~2 minutes). To react to inbound SMS or completed calls durably, use the Python SDK’s new_events_connection() directly, or register a webhook (signed and retried at-least-once), and feed events into your crew however suits your app.