> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getdial.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server.

# Microsoft Agent Framework integration

> Give a Microsoft Agent Framework agent Dial tools for SMS, OTP, and voice calls — phone identity for production Azure AI agents.

`dial-agentframework` packages Dial's operations as [Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/)
tools, so an `Agent` can send messages, receive OTP codes, and place calls as part of its work.
The Agent Framework is Microsoft's production successor to AutoGen and Semantic Kernel — the path
for new Azure / enterprise agent builds. It's a sibling of the
[LangChain integration](/documentation/sdks/langchain): each tool is an `agent_framework.FunctionTool`
wrapping the [Python SDK](/documentation/sdks/python) client — it adds nothing to the REST contract,
it just shapes Dial's operations into Agent Framework tools.

Already on the original **AutoGen** (`autogen-agentchat`)? Use
[`dial-autogen`](/documentation/sdks/autogen). Both expose the same Dial tools.

## Install

```bash
pip install dial-agentframework
```

This pulls in `dial-sdk` and `agent-framework-core`. The Agent Framework keeps each model
provider in its own package, so also install a chat client for your provider — for example
`agent-framework-openai`, or the framework's Azure integration for Azure OpenAI.

## Give the tools to an agent

Build one [`DialClient`](/documentation/sdks/python), 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 agent session — and you own its lifecycle (`await client.close()` when done):

```python
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient  # pip install agent-framework-openai
from dial_sdk import DialClient, DialConfig
from dial_agentframework import dial_tools

dial = DialClient(DialConfig(api_key="sk_live_..."))  # close with `await dial.close()`

agent = Agent(
    OpenAIChatClient(),  # Azure OpenAI builds: swap in the Azure integration's chat client
    name="phone_agent",
    instructions="You operate the team's Dial phone number for SMS, OTP, and voice calls.",
    tools=dial_tools(dial),
)

result = await agent.run("Text +14155550123 from pn_abc saying our table is ready.")
print(result.text)
```

`dial_tools` returns the full set, all sharing your client — the analog of LangChain's
`DialToolkit.get_tools()`. The Agent Framework runs tools in an async loop, so the Dial
tools are **async-native** — no async→sync bridge. The Dial tools themselves are identical
regardless of which model provider (Azure OpenAI, OpenAI, …) drives the agent.

## Available tools

Each builder takes your shared `DialClient` and returns one `FunctionTool`:

| Builder                      | Tool name               | Action                                                |
| ---------------------------- | ----------------------- | ----------------------------------------------------- |
| `list_numbers_tool`          | `list_numbers`          | List your phone numbers                               |
| `purchase_number_tool`       | `purchase_number`       | Provision a new number (billable)                     |
| `set_number_properties_tool` | `set_number_properties` | Update a number's nickname or inbound instruction     |
| `send_message_tool`          | `send_message`          | Send an SMS                                           |
| `list_messages_tool`         | `list_messages`         | List recent messages                                  |
| `make_call_tool`             | `make_call`             | Place an AI voice call                                |
| `list_calls_tool`            | `list_calls`            | List recent calls                                     |
| `get_call_tool`              | `get_call`              | Fetch one call by id                                  |
| `get_billing_tool`           | `get_billing`           | Credit balance, subscription, per-number mode         |
| `wait_for_message_tool`      | `wait_for_message`      | Block until the next inbound SMS arrives, or time out |

### Or pick individual tools

```python
from dial_agentframework import send_message_tool, wait_for_message_tool

tools = [
    send_message_tool(dial),
    wait_for_message_tool(dial),
]
```

## Handling OTP

The reason an agent needs phone identity: receive a verification code and act on it.
`wait_for_message` 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.

```python
result = await agent.run(
    "Wait up to 120 seconds for the inbound verification code on our Dial number, then report it."
)
print(result.text)
```

A full runnable example is in [`examples/signup_agentframework.ipynb`](https://github.com/GENWAY-AI/dial/blob/main/sdk-agentframework/examples/signup_agentframework.ipynb).

`send_message` is a write action and **isn't idempotent** — a re-invoke after a failure can
send a duplicate. `make_call` accepts an `idempotency_key`. See
[Retries and idempotency](/documentation/reference/errors#retries-and-idempotency).

## Receiving events beyond a single wait

`wait_for_message` 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](/documentation/sdks/python)
`new_events_connection()` directly, or register a [webhook](/documentation/platform/webhooks)
(signed and retried at-least-once), and feed events into your agent however suits your app.