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:

1from crewai import Agent
2from dial_sdk import DialClient, DialConfig
3from dial_crewai import dial_tools
4
5dial = DialClient(DialConfig(api_key="sk_live_..."))
6
7phone_agent = Agent(
8 role="Phone identity agent",
9 goal="Send and receive SMS so the crew can complete phone-verified signups",
10 backstory="You operate the crew's Dial phone number.",
11 tools=dial_tools(dial),
12)

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
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

1from dial_crewai import SendMessageTool, WaitForMessageTool
2
3tools = [
4 SendMessageTool(client=dial),
5 WaitForMessageTool(client=dial),
6]

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.

1from crewai import Agent, Crew, Task
2from dial_sdk import DialClient, DialConfig
3from dial_crewai import SendMessageTool, WaitForMessageTool
4
5dial = DialClient(DialConfig(api_key="sk_live_..."))
6
7signup_agent = Agent(
8 role="Signup agent",
9 goal="Complete a phone-verified signup by reading the OTP sent to our Dial number",
10 backstory="You wait for verification codes on the crew's Dial number and read them back.",
11 tools=[SendMessageTool(client=dial), WaitForMessageTool(client=dial)],
12)
13
14wait_for_otp = Task(
15 description="Wait up to 120 seconds for the inbound verification code on our Dial number, then report it.",
16 expected_output="The verification code that was texted to our number.",
17 agent=signup_agent,
18)
19
20Crew(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.