Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions examples/voice_agents/sms_sender_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import logging

from dotenv import load_dotenv

from livekit.agents import Agent, AgentServer, AgentSession, JobContext, cli
from livekit.agents.beta.tools.sms import SMSToolConfig, create_sms_tool
from livekit.plugins import silero

logger = logging.getLogger("sms-agent")

load_dotenv()

RANDOM_MESSAGES = [
"Here's your daily reminder that you're awesome!",
"Hope your day is going great, consider this a little boost!",
"Just popping in to say hi from your friendly bot",
"This is a quick systems check: all vibes appear positive.",
]

IS_SIP_SESSION = True # Enables auto-detection of caller's number in SIP session
# Disable it for non-SIP sessions (e.g. console runs)

sms_tool = create_sms_tool(
SMSToolConfig(
name="send_playful_sms",
description=(
IS_SIP_SESSION
and "Send a playful SMS to the caller's phone number. "
or "Send a playful SMS to the provided `to` phone number. "
"Always include the exact message text you want to deliver."
),
auto_detect_caller=IS_SIP_SESSION,
execution_message="One moment while I send that SMS.",
)
)

instructions = (
"Keep it minimal. Immediately greet the user and tell them you are ready to send a light-hearted SMS. "
"Ask once for their mobile number with country code. "
"Do not list options or chat idly — just confirm you are waiting for the number. "
"After they provide a valid number (7-15 digits), call send_playful_sms with that number as `to` and choose any one of these messages: "
f"{'; '.join(RANDOM_MESSAGES)} "
"Send the SMS silently and then simply say “Done. Check your phone.”"
)

if IS_SIP_SESSION:
instructions = (
"Keep it minimal. Immediately greet the user and tell them you are ready to send a light-hearted SMS. "
"Ask to choose a message to send"
f"{'; '.join(RANDOM_MESSAGES)} "
"Send the SMS silently and then simply say “Done. Check your phone.”"
)


class SMSAgent(Agent):
def __init__(self) -> None:
super().__init__(instructions=instructions, tools=[sms_tool])

async def on_enter(self):
await self.session.generate_reply(
instructions=IS_SIP_SESSION
and "Warmly greet the user and ask to choose a message to send"
or "Warmly greet the user and ask for their mobile number (skip if you don't have to field in sms tool)"
)


server = AgentServer()


@server.rtc_session(agent_name="sms-sender")
async def entrypoint(ctx: JobContext):
session = AgentSession(
stt="deepgram/nova-3",
llm="openai/gpt-4o-mini",
tts="cartesia/sonic-3:a167e0f3-df7e-4d52-a9c3-f949145efdab",
vad=silero.VAD.load(),
)

await session.start(agent=SMSAgent(), room=ctx.room)
await ctx.connect()


if __name__ == "__main__":
cli.run_app(server)
77 changes: 0 additions & 77 deletions examples/voice_agents/weather_agent.py

This file was deleted.

12 changes: 12 additions & 0 deletions livekit-agents/livekit/agents/beta/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Production-ready tools for common agent operations."""

from . import sms
from .send_dtmf import send_dtmf_events
from .sms import SMSToolConfig, create_sms_tool

__all__ = [
"sms",
"send_dtmf_events",
"SMSToolConfig",
"create_sms_tool",
]
72 changes: 72 additions & 0 deletions livekit-agents/livekit/agents/beta/tools/sms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# SMS Tools

Send SMS messages from voice agents with auto-detected provider support.
Supported: Twilio, Vonage, SignalWire

## Usage

```python
from livekit.agents import Agent
from livekit.agents.beta.tools.sms import create_sms_tool, SMSToolConfig

# Default: auto-detects the caller's number from the SIP participant
# LLM only needs to provide the message text
sms_tool = create_sms_tool()

# Custom: change tool name, description, recipient, or sender
sms_tool = create_sms_tool(SMSToolConfig(
name="notify_customer", # Custom function name
description="Send confirmation", # Custom function description
to_number="+1234567890", # Send to specific number
from_number="+0987654321", # Send from specific number
auto_detect_caller=False, # Require explicit "to" argument from the LLM
execution_message="Sending a confirmation text right now.",
))

agent = Agent(
instructions="You can send SMS messages to callers",
tools=[sms_tool]
)
```

### Arguments surfaced to the LLM

`create_sms_tool` keeps the schema intentionally tiny:

- `message` — always required; this is the SMS body the LLM must supply.
- `to` — required **only** when you disable caller auto-detection _and_ don’t hardcode `to_number`. In every other configuration the tool determines the recipient on its own, so the LLM never sees or fills this field.

With `auto_detect_caller=True` (default) the tool looks up the SIP participant identity and omits the `to` argument entirely.

### Announcing executions

Set `SMSToolConfig.execution_message` when you want the agent to speak a short disclaimer before dispatching an SMS. The message is sent through `context.session.generate_reply()` with interruptions disabled so the user hears it exactly once.

## Environment Variables

**Twilio:**

```bash
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_PHONE_NUMBER=+1234567890
```

**SignalWire:**

```bash
SIGNALWIRE_PROJECT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
SIGNALWIRE_TOKEN=PTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SIGNALWIRE_SPACE_URL=example.signalwire.com
SIGNALWIRE_PHONE_NUMBER=+1234567890
```

**Vonage:**

```bash
VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret
VONAGE_PHONE_NUMBER=1234567890
```

If you supply `from_number` directly in `SMSToolConfig` it overrides the values above.
16 changes: 16 additions & 0 deletions livekit-agents/livekit/agents/beta/tools/sms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""SMS sending tools with auto-detected provider support.

Supports Twilio, SignalWire, and Vonage SMS providers.
"""

from .config import SMSResponse, SMSToolConfig, SMSToolRequest
from .provider_utils import run_sms_request
from .send_sms import create_sms_tool

__all__ = [
"SMSToolConfig",
"SMSToolRequest",
"SMSResponse",
"create_sms_tool",
"run_sms_request",
]
38 changes: 38 additions & 0 deletions livekit-agents/livekit/agents/beta/tools/sms/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass


@dataclass
class SMSResponse:
"""Structured response from SMS send operation."""

success: bool
message_id: str | None
to: str
error: str | None = None


@dataclass
class SMSToolRequest:
"""Provider configuration passed to the SMS utility."""

provider_name: str
credentials: dict[str, str]
from_number: str
timeout_ms: int = 10000


@dataclass
class SMSToolConfig:
"""Configuration for SMS tool customization."""

name: str = "send_sms"
description: str | None = None
to_number: str | None = None
from_number: str | None = None
auto_detect_caller: bool = True
timeout_ms: int = 10000
execution_message: str | None = None
output_normalizer: Callable[[SMSResponse], str | None] | None = None
Loading