Skip to navigation

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

from dial_sdk import DialClient, DialConfig
from dial_langchain import DialToolkit
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent
model = init_chat_model("claude-sonnet-4-6", model_provider="anthropic")
dial = DialClient(DialConfig(api_key="sk_live_..."))
toolkit = DialToolkit(client=dial)
agent = 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:

from dial_sdk import DialClient, DialConfig
from dial_langchain import ListNumbersTool, SendMessageTool, MakeCallTool
dial = DialClient(DialConfig(api_key="sk_live_..."))
tools = [
ListNumbersTool(client=dial),
SendMessageTool(client=dial),
MakeCallTool(client=dial),
]
# Bind to any tool-calling model or agent
llm_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:

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