LangChain integration

View as Markdown

dial-langchain packages Dial’s operations as LangChain tools, so an agent can send messages and place calls as part of its reasoning.

Install

$pip install dial-langchain

This pulls in dial-sdk and langchain-core.

Available tools

Each tool takes your shared DialClient (client=):

ToolAction
ListNumbersToolList your phone numbers
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
MakeCallToolPlace an AI voice call
ListMessagesToolList recent messages
ListCallsToolList recent calls

Give the tools to an agent

Build one DialClient, hand it to DialToolkit, and call get_tools() to give the agent the full set, no per-tool imports. Every tool shares that one client (a single connection pool):

1from dial_sdk import DialClient, DialConfig
2from dial_langchain import DialToolkit
3from langchain.chat_models import init_chat_model
4from langgraph.prebuilt import create_react_agent
5
6model = init_chat_model("claude-sonnet-4-6", model_provider="anthropic")
7
8dial = DialClient(DialConfig(api_key="sk_live_..."))
9toolkit = DialToolkit(client=dial)
10agent = create_react_agent(model, toolkit.get_tools())

DialToolkit is a standard LangChain BaseToolkit, so get_tools() works anywhere a list of tools is expected.

Or pick individual tools

When you only want a subset, import the tools directly and pass them the same client:

1from dial_sdk import DialClient, DialConfig
2from dial_langchain import ListNumbersTool, SendMessageTool, MakeCallTool
3
4dial = DialClient(DialConfig(api_key="sk_live_..."))
5tools = [
6 ListNumbersTool(client=dial),
7 SendMessageTool(client=dial),
8 MakeCallTool(client=dial),
9]
10
11# Bind to any tool-calling model or agent
12llm_with_tools = llm.bind_tools(tools)

The tools are async — LangChain calls them via ainvoke. SendMessageTool expects to, a from-number (from_number — ID, owned E.164, or nickname — or the legacy from_number_id), and body; MakeCallTool expects to, a from-number, outbound_instruction, and optionally language and idempotency_key.

SendMessageTool is a write action and isn’t idempotent — if your agent re-invokes it after a failure, it can send a duplicate message. MakeCallTool accepts an optional idempotency_key: a re-invoke with the same key returns the already-placed call instead of placing a duplicate. See Retries and idempotency.

Receiving events

Inbound events aren’t a tool — they’re an ingress stream, not something the agent “calls.” To react to inbound SMS or completed calls, use the Python SDK’s new_events_connection() directly — a presence-based stream (not at-least-once — for durable delivery, register a webhook) — and feed events into your agent however suits your app:

1from dial_sdk import DialClient, DialConfig
2
3dial = DialClient(DialConfig(api_key="sk_live_..."))
4async with dial.new_events_connection() as conn:
5 async for event in conn:
6 ... # route the event into your agent