Metadata-Version: 2.5
Name: langchain-plivo-tools
Version: 0.2.0
Summary: Send SMS and place voice calls from LangChain agents through Plivo
Project-URL: Homepage, https://github.com/plivo-dev/langchain-plivo-tools
Project-URL: Repository, https://github.com/plivo-dev/langchain-plivo-tools
Project-URL: Documentation, https://github.com/plivo-dev/langchain-plivo-tools
Project-URL: Bug Tracker, https://github.com/plivo-dev/langchain-plivo-tools/issues
Project-URL: Release Notes, https://github.com/plivo-dev/langchain-plivo-tools/releases
Author-email: Plivo <oss@plivo.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,calls,langchain,langchain-tools,messaging,plivo,sms,telephony,toolkit,voice
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Telephony
Requires-Python: >=3.10
Requires-Dist: langchain-core<2,>=0.3
Requires-Dist: plivo<5,>=4.60
Description-Content-Type: text/markdown

# langchain-plivo-tools

[![PyPI version](https://img.shields.io/pypi/v/langchain-plivo-tools.svg)](https://pypi.org/project/langchain-plivo-tools/)
[![Python versions](https://img.shields.io/pypi/pyversions/langchain-plivo-tools.svg)](https://pypi.org/project/langchain-plivo-tools/)
[![License MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![CI](https://github.com/plivo-dev/langchain-plivo-tools/actions/workflows/ci.yml/badge.svg)](https://github.com/plivo-dev/langchain-plivo-tools/actions/workflows/ci.yml)

Plivo SMS and voice tools for [LangChain](https://python.langchain.com) agents. An agent
sends text messages and places phone calls through
[Plivo](https://cx.plivo.com/?utm_source=github&utm_medium=oss&utm_campaign=langchain-plivo-tools).

| Capability | Detail |
|---|---|
| Send SMS | An agent sends a text message and receives the Plivo message UUID |
| Place calls | An agent dials a number, with optional text spoken when the call connects |
| Toolkit | `PlivoToolkit` returns every tool the current configuration supports |
| Credentials | Read from the environment or passed to the constructor, held as `SecretStr` |

## Requirements

| Requirement | Detail |
|---|---|
| Python | 3.10 or later |
| Plivo account | Auth ID and Auth Token from the [Plivo console](https://cx.plivo.com/?utm_source=github&utm_medium=oss&utm_campaign=langchain-plivo-tools) |
| Plivo number | In E.164 format, enabled for SMS, voice, or both |
| Answer URL | Required by `PlivoMakeCall` only. An endpoint returning Plivo XML, described under [The Answer URL contract](#the-answer-url-contract) |

## Installation

```bash
pip install langchain-plivo-tools
```

### Upgrading from 0.1.0

The two tool classes lost their `Tool` suffix in 0.2.0 to match the naming used
across LangChain tool packages.

| 0.1.0 | 0.2.0 |
| --- | --- |
| `PlivoSendMessageTool` | `PlivoSendMessage` |
| `PlivoMakeCallTool` | `PlivoMakeCall` |

The old names still import and resolve to the renamed classes, raising a
`DeprecationWarning`. They are scheduled for removal in 0.3.0. The tool names
the model sees, `plivo_send_message` and `plivo_make_call`, are unchanged, so
agent behaviour does not shift on upgrade.

## Setup

Set the Plivo credentials as environment variables, or pass them to the tool directly.

```bash
export PLIVO_AUTH_ID="your-auth-id"
export PLIVO_AUTH_TOKEN="your-auth-token"
export PLIVO_FROM_NUMBER="+14155551234"
```

The Auth ID and Auth Token are on the [Plivo console](https://cx.plivo.com/?utm_source=github&utm_medium=oss&utm_campaign=langchain-plivo-tools) dashboard. The from number must be a Plivo phone number in E.164 format, enabled for SMS, voice, or both.

## Send an SMS

```python
from langchain_plivo_tools import PlivoSendMessage

tool = PlivoSendMessage()

tool.invoke({"body": "Your order has shipped.", "to": "+14155551234"})
```

Credentials can also be passed in code instead of the environment.

```python
tool = PlivoSendMessage(
    auth_id="your-auth-id",
    auth_token="your-auth-token",
    from_number="+14155551234",
)
```

The tool returns the Plivo message UUID on success. Numbers use E.164 format.

## Make a call

`PlivoMakeCall` places a phone call. Plivo answers the call by fetching an **Answer URL** that returns Plivo XML, so that endpoint has to be hosted separately. Its address goes in `PLIVO_ANSWER_URL`, alongside the credentials above, or is passed as `answer_url` to the tool.

```python
from langchain_plivo_tools import PlivoMakeCall

tool = PlivoMakeCall()

tool.invoke({"to": "+14155551234", "message": "Your monitor is down."})
```

### The Answer URL contract

When the call connects, Plivo fetches the Answer URL and expects a Plivo XML document in response. The URL is fetched with **GET** by default, because the optional `message` argument is appended to it as a `message` query parameter. The endpoint reads that parameter and returns XML that speaks it. A minimal response looks like this.

```xml
<Response><Speak>{message}</Speak></Response>
```

Invoking the tool with `message="Your monitor is down."` makes Plivo request the Answer URL with `?message=Your+monitor+is+down.`, and the endpoint returns this.

```xml
<Response><Speak>Your monitor is down.</Speak></Response>
```

To receive the parameters as a POST body instead, set the answer method to `POST`, either through the environment or on the tool.

```bash
export PLIVO_ANSWER_METHOD="POST"
```

```python
tool = PlivoMakeCall(answer_method="POST")
```

The tool returns the Plivo request UUID on success.

## Configuration

Every setting reads from an environment variable, and any of them can be overridden by passing the matching argument to the tool constructor.

| Environment variable | Constructor argument | Used by | Purpose |
| --- | --- | --- | --- |
| `PLIVO_AUTH_ID` | `auth_id` | both tools | Plivo account Auth ID |
| `PLIVO_AUTH_TOKEN` | `auth_token` | both tools | Plivo account Auth Token |
| `PLIVO_FROM_NUMBER` | `from_number` | both tools | Plivo number that sends the SMS or places the call |
| `PLIVO_ANSWER_URL` | `answer_url` | `PlivoMakeCall` | Endpoint that returns Plivo XML when the call connects |
| `PLIVO_ANSWER_METHOD` | `answer_method` | `PlivoMakeCall` | HTTP method Plivo uses to fetch the Answer URL, defaults to `GET` |

## Using the tools with a LangChain agent

Both tools are standard LangChain tools, so they can be bound to a chat model or handed to an agent.

```python
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent

from langchain_plivo_tools import PlivoMakeCall, PlivoSendMessage

tools = [PlivoSendMessage(), PlivoMakeCall()]

model = init_chat_model("claude-sonnet-4-5-20250929", model_provider="anthropic")
agent = create_react_agent(model, tools)

result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "Text +14155551234 to let them know their order shipped.",
            }
        ]
    }
)
print(result["messages"][-1].content)
```

### Every tool at once with the toolkit

`PlivoToolkit` hands an agent all of the Plivo tools in one call, which keeps the
agent setup unchanged as more tools are added to the package.

```python
from langchain_plivo_tools import PlivoToolkit

agent = create_react_agent(model, PlivoToolkit().get_tools())
```

The toolkit reads the same environment variables as the individual tools, and any
argument passed to it is forwarded to every tool that accepts one.

```python
toolkit = PlivoToolkit(
    auth_id="your-auth-id",
    auth_token="your-auth-token",
    from_number="+14155551234",
    answer_url="https://example.com/answer",
)
```

A tool whose configuration is incomplete is left out of the returned list rather
than raising, because an account that only sends SMS has no reason to set an
Answer URL. Each omission raises a warning naming the missing setting, so a tool
absent from an agent stays traceable. Nothing being configurable is an error.

```python
# With credentials set but no PLIVO_ANSWER_URL:
PlivoToolkit().get_tools()
# UserWarning: Some Plivo tools are missing from the toolkit.
# PlivoMakeCall (Missing Plivo settings: PLIVO_ANSWER_URL. ...)
# -> [PlivoSendMessage()]
```

## Security

- The Auth Token is held as a `SecretStr`, keeping it out of `repr()` and log output
- Credentials are read from the environment or passed to the constructor, and this package
  writes neither to disk
- Both tools perform billable actions against a number the model supplies. No destination
  allowlist or rate limit is applied here, so those controls belong in the host application
  or in Plivo spend limits
- The `message` argument reaches the Answer URL as a query parameter. An endpoint placing it
  into XML has to escape it first, because unescaped input can alter the XML document

## Limitations

- SMS only. MMS and WhatsApp are not covered
- Number lookup and Verify are not included
- `PlivoMakeCall` needs a separately hosted Answer URL, because Plivo does not speak text
  handed straight to the call API

## Development

```bash
make install
make test
make lint
```

Integration tests place a real API call and run only when `PLIVO_AUTH_ID`, `PLIVO_AUTH_TOKEN`, `PLIVO_FROM_NUMBER` and `PLIVO_TO_NUMBER` are set. Calls also need `PLIVO_ANSWER_URL`.

```bash
make integration_test
```

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
