—— SYSTEM-DIRECTED AI

AI agents that answer to your code

AI agents that answer to your code

Your code holds the authority. The platform owns the state. The model runs inside the call and never knows the rules exist.

Your code holds the authority. The platform owns the state. The model runs inside the call and never knows the rules exist.

redirect.py — live call, owned by the platform

copy

01

02

03

04

05

06

07

08

09

10

11

12

@AgentBase.tool(name="refund")
def refund(self, amount: float, raw_data=None):
    """Issue a refund the caller asked for."""
    limit = raw_data["global_data"]["refund_limit"]  # the model never sees this
    if amount <= limit:
        return FunctionResult(f"Approved, ${amount:.2f} refunded.")
    return FunctionResult("Let me get a manager to approve that.")

redirect.py

copy

01

02

03

04

05

06

07

08

09

10

11

12

@AgentBase.tool(name="refund")
def refund(self, amount: float, raw_data=None):
    """Issue a refund the caller asked for."""
    limit = raw_data["global_data"]["refund_limit"]  # the model never sees this
    if amount <= limit:
        return FunctionResult(f"Approved, ${amount:.2f} refunded.")
    return FunctionResult("Let me get a manager to approve that.")

redirect.py — live call, owned by the platform

copy

01

02

03

04

05

06

07

08

09

10

11

12

@AgentBase.tool(name="refund")
def refund(self, amount: float, raw_data=None):
    """Issue a refund the caller asked for."""
    limit = raw_data["global_data"]["refund_limit"]  # the model never sees this
    if amount <= limit:
        return FunctionResult(f"Approved, ${amount:.2f} refunded.")
    return FunctionResult("Let me get a manager to approve that.")
Bottom Linear Gradient  Lines image

Voice AI in production at

OVERVIEW

Where AI runs decides what breaks

When the AI runs inside of the call instead of across five vendors, you get clean logs, real control, and low latency.

Prompt governs everything

Code Governs

Debugging across 5 vendors

One event stream

Behavior drifts under load

Your code controls behavior

Network hops add latency

Low latency from in-engine AI kernel

Telephony is a separate vendor

Native PSTN, SIP, and WebRTC

Prompt governs everything

Debugging across 5 vendors

Behavior drifts under load

Network hops add latency

Telephony is a separate vendor

Code Governs

One event stream

Your code controls behavior

Low latency from in-engine AI kernel

Native PSTN, SIP, and WebRTC

OBSERVABILITY

You build agent behavior.


The platform handles the rest.

The platform handles state, timing, coordination, and infrastructure. You build AI agents and call flows without ever touching infrastructure complexity.

01 Stateful Call Context

The call's context, history, and transfer state live on one UUID and persist for the whole call, through every step and transfer.

02 Tool Governance

When the model requests a tool, your handler applies your rules and returns the result. The model can't act on anything your code didn't clear.

03 Sub-second Latency

Speech, model, and voice run in the media engine, not across separate vendors. Full turns land near 1.2s, 600ms with speech-to-speech.

04 One Platform

The call and the AI kernel run as one system. State, transfers, and tool calls happen in one place instead of syncing across vendors.

Real-time Voice AI Logs

copy


Native Observability

01 Stateful Call Context

The call's context, history, and transfer state live on one UUID and persist for the whole call, through every step and transfer.

02 Tool Governance

When the model requests a tool, your handler applies your rules and returns the result. The model can't act on anything your code didn't clear.

03 Sub-second Latency

Speech, model, and voice run in the media engine, not across separate vendors. Full turns land near 1.2s, 600ms with speech-to-speech.

04 One Platform

The call and the AI kernel run as one system. State, transfers, and tool calls happen in one place instead of syncing across vendors.

Real-time Voice AI Logs

copy


Native Observability

01 Stateful Call Context

The call's context, history, and transfer state live on one UUID and persist for the whole call, through every step and transfer.

02 Tool Governance

When the model requests a tool, your handler applies your rules and returns the result. The model can't act on anything your code didn't clear.

03 Sub-second Latency

Speech, model, and voice run in the media engine, not across separate vendors. Full turns land near 1.2s, 600ms with speech-to-speech.

04 One Platform

The call and the AI kernel run as one system. State, transfers, and tool calls happen in one place instead of syncing across vendors.

Real-time Voice AI Logs

copy


Native Observability

Performance Analysis

Voice AI performance is fundamentally an infrastructure problem

Voice AI performance is fundamentally an infrastructure problem

Architectural design decisions materially affect conversational responsiveness. No model quality advantage can fully compensate for a poorly orchestrated pipeline. This report benchmarks three leading Voice AI platforms by implementing the same Smart Appointment Assistant across each system, measuring conversational latency, tool call latency, and development complexity under identical conditions.

Architectural design decisions materially affect conversational responsiveness. No model quality advantage can fully compensate for a poorly orchestrated pipeline. This report benchmarks three leading Voice AI platforms by implementing the same Smart Appointment Assistant across each system, measuring conversational latency, tool call latency, and development complexity under identical conditions.

Conversational turn latency

SignalWire (avg of 5 configs)

range: 1.09-1.46s

1.24s

Vapi

1% faster thank LK baseline

1.85s

LiveKit (baseline)

0.89s spread

1.87s

Livekit (tuned)

0.38s spread

1.75s

Developer Toolkit

Everything you need to build smarter voice systems.

Every application you build runs on the same engine, keeps its own call state, and stays under your code's control.

Inbound & outbound agents

Answer incoming calls or place them at scale. The same agent code handles both directions, so you write the behavior once.

AI-to-human handoff

Escalate to a live rep with the full call context intact. The agent transfers the transcript, state, and caller details, so no one starts over.

Real-time translation

Translate both sides of a live call as it happens. Each party hears their own language with sub-second turns, on one connection.

SEE IT IN PRODUCTION

Steer the AI mid-call

Talk to Sigmond on the left. On the right is what controlling a live AI session looks like on the platform Sigmond runs on.

Talk to Sigmond

A voice AI that answers questions about SignalWire over WebRTC

Tap to talk to a live agent

AI_Message - Python relay SDK

copy

01

02

03

04

05

06

07

08

09

10

11

12

# pip install signalwire-sdk   →   python sigmond.py
# Sigmond: a voice AI that answers questions about SignalWire.
# His persona is a prompt. His knowledge is a tool he calls. Your code owns both.

from signalwire import AgentBase, FunctionResult

# A tiny stand-in knowledge base so this runs with zero setup. In production you
# swap this for the native_vector_search skill (see the note at the bottom).
DOCS = {
    "swaig": "SWAIG is SignalWire's AI Gateway, the tool-calling system that lets the AI in.",
    "latency": "Conversational turns land around 1.2 seconds because the AI kernel runs inside the media engine.",
    "puc": "Programmable Unified Communications: the platform owns the call and your code programs it.",
}


class Sigmond(AgentBase):
    def __init__(self):
        super().__init__(name="sigmond", route="/sigmond")
        self.add_language(name="English", code="en-US", voice="inworld.Mark")

        # Persona: who Sigmond is. The prompt is the ONE place the model gets latitude.
        self.prompt_add_section("Personality", body="You are Sigmond, a warm, concise voice guide to SignalWire.")
        self.prompt_add_section("Goal", body="Answer the caller's SignalWire questions accurately.")
        self.prompt_add_section("Rules", bullets=[
            "Call search_docs before you state a fact.",
            "If the docs do not cover it, say so. Never invent product details.",
        ])

    # A SWAIG function is a tool the AI calls mid-call. It runs on YOUR server.
    # The model decides WHEN to search; your code decides WHAT comes back.
    # The type hint (query: str) becomes the tool's schema. No JSON to hand-write.
    @AgentBase.tool(name="search_docs")
    def search_docs(self, query: str, raw_data=None):
        """Search SignalWire documentation to answer a caller's question."""
        for key, fact in DOCS.items():
            if key in query.lower():
                return FunctionResult(fact)
        return FunctionResult("I don't have that in the docs, but I can connect you with someone who does.")


# In production, delete the tool above and let the built-in skill do real vector
# search over an index you build from your docs with the sw-search CLI.
# (Needs the search extras: pip install "signalwire-sdk[search-queryonly]")
#
#   self.add_skill("native_vector_search", {
#       "tool_name": "search_docs",
#       "description": "Search SignalWire documentation.",
#       "index_file": "./signalwire-docs.swsearch",
#   })

# To talk to Sigmond from a browser, a separate @signalwire/js front-end dials his address (WebRTC). Not shown here.

if __name__ == "__main__":
    Sigmond().run()   # serve it, then route a phone number or browser (WebRTC) call to Sig

AI_Message - Python relay SDK

copy

01

02

03

04

05

06

07

08

09

10

11

12

# pip install signalwire-sdk   →   python sigmond.py
# Sigmond: a voice AI that answers questions about SignalWire.
# His persona is a prompt. His knowledge is a tool he calls. Your code owns both.

from signalwire import AgentBase, FunctionResult

# A tiny stand-in knowledge base so this runs with zero setup. In production you
# swap this for the native_vector_search skill (see the note at the bottom).
DOCS = {
    "swaig": "SWAIG is SignalWire's AI Gateway, the tool-calling system that lets the AI in.",
    "latency": "Conversational turns land around 1.2 seconds because the AI kernel runs inside the media engine.",
    "puc": "Programmable Unified Communications: the platform owns the call and your code programs it.",
}


class Sigmond(AgentBase):
    def __init__(self):
        super().__init__(name="sigmond", route="/sigmond")
        self.add_language(name="English", code="en-US", voice="inworld.Mark")

        # Persona: who Sigmond is. The prompt is the ONE place the model gets latitude.
        self.prompt_add_section("Personality", body="You are Sigmond, a warm, concise voice guide to SignalWire.")
        self.prompt_add_section("Goal", body="Answer the caller's SignalWire questions accurately.")
        self.prompt_add_section("Rules", bullets=[
            "Call search_docs before you state a fact.",
            "If the docs do not cover it, say so. Never invent product details.",
        ])

    # A SWAIG function is a tool the AI calls mid-call. It runs on YOUR server.
    # The model decides WHEN to search; your code decides WHAT comes back.
    # The type hint (query: str) becomes the tool's schema. No JSON to hand-write.
    @AgentBase.tool(name="search_docs")
    def search_docs(self, query: str, raw_data=None):
        """Search SignalWire documentation to answer a caller's question."""
        for key, fact in DOCS.items():
            if key in query.lower():
                return FunctionResult(fact)
        return FunctionResult("I don't have that in the docs, but I can connect you with someone who does.")


# In production, delete the tool above and let the built-in skill do real vector
# search over an index you build from your docs with the sw-search CLI.
# (Needs the search extras: pip install "signalwire-sdk[search-queryonly]")
#
#   self.add_skill("native_vector_search", {
#       "tool_name": "search_docs",
#       "description": "Search SignalWire documentation.",
#       "index_file": "./signalwire-docs.swsearch",
#   })

# To talk to Sigmond from a browser, a separate @signalwire/js front-end dials his address (WebRTC). Not shown here.

if __name__ == "__main__":
    Sigmond().run()   # serve it, then route a phone number or browser (WebRTC) call to Sig

AI_Message - Python relay SDK

copy

01

02

03

04

05

06

07

08

09

10

11

12

# pip install signalwire-sdk   →   python sigmond.py
# Sigmond: a voice AI that answers questions about SignalWire.
# His persona is a prompt. His knowledge is a tool he calls. Your code owns both.

from signalwire import AgentBase, FunctionResult

# A tiny stand-in knowledge base so this runs with zero setup. In production you
# swap this for the native_vector_search skill (see the note at the bottom).
DOCS = {
    "swaig": "SWAIG is SignalWire's AI Gateway, the tool-calling system that lets the AI in.",
    "latency": "Conversational turns land around 1.2 seconds because the AI kernel runs inside the media engine.",
    "puc": "Programmable Unified Communications: the platform owns the call and your code programs it.",
}


class Sigmond(AgentBase):
    def __init__(self):
        super().__init__(name="sigmond", route="/sigmond")
        self.add_language(name="English", code="en-US", voice="inworld.Mark")

        # Persona: who Sigmond is. The prompt is the ONE place the model gets latitude.
        self.prompt_add_section("Personality", body="You are Sigmond, a warm, concise voice guide to SignalWire.")
        self.prompt_add_section("Goal", body="Answer the caller's SignalWire questions accurately.")
        self.prompt_add_section("Rules", bullets=[
            "Call search_docs before you state a fact.",
            "If the docs do not cover it, say so. Never invent product details.",
        ])

    # A SWAIG function is a tool the AI calls mid-call. It runs on YOUR server.
    # The model decides WHEN to search; your code decides WHAT comes back.
    # The type hint (query: str) becomes the tool's schema. No JSON to hand-write.
    @AgentBase.tool(name="search_docs")
    def search_docs(self, query: str, raw_data=None):
        """Search SignalWire documentation to answer a caller's question."""
        for key, fact in DOCS.items():
            if key in query.lower():
                return FunctionResult(fact)
        return FunctionResult("I don't have that in the docs, but I can connect you with someone who does.")


# In production, delete the tool above and let the built-in skill do real vector
# search over an index you build from your docs with the sw-search CLI.
# (Needs the search extras: pip install "signalwire-sdk[search-queryonly]")
#
#   self.add_skill("native_vector_search", {
#       "tool_name": "search_docs",
#       "description": "Search SignalWire documentation.",
#       "index_file": "./signalwire-docs.swsearch",
#   })

# To talk to Sigmond from a browser, a separate @signalwire/js front-end dials his address (WebRTC). Not shown here.

if __name__ == "__main__":
    Sigmond().run()   # serve it, then route a phone number or browser (WebRTC) call to Sig

2000+

Customers

2.7B

Annual minutes & messages

~1200ms

AVG AI turn

~800ms

Optimized Stack

Bottom Linear Gradient  Lines image
Top Linear Gradient  Lines image

FAQS

Frequently asked questions

Frequently asked questions

What to know about the architecture behind System-Directed AI, from latency to compliance.

What to know about the architecture behind System-Directed AI, from latency to compliance.

What's the difference between SignalWire's voice AI and Vapi or Retell?

Vapi and Retell are orchestration layers on top of four other vendors — Twilio for telephony, Deepgram for STT, OpenAI for the LLM, ElevenLabs for TTS. Their per-minute fee is on top of the underlying vendor costs. SignalWire owns the media stack, the AI kernel, and the carrier relationships in one platform. One bill, one operator, one place to call when something breaks.

Why is SignalWire's latency lower?

The AI kernel runs inside the same media stack the call lives in. STT, LLM inference, and TTS execute in the substrate, not over external HTTP round trips. The architecture eliminates the inter-system relay that adds 800-2000ms on bolt-on platforms. Measured turn latency averages ~1,200ms across tested configurations.

What does System-directed AI actually prevent?

Hallucinated actions the backend cannot honor. Unauthorized state transitions. Tool calls outside the current step's scope. Model access to data it was never meant to see. The governance is structural — the model doesn't know other tools exist, doesn't see the data layer, and can't override decisions enforced in code.

Can I use my own LLM?

Yes. The AI kernel is model-agnostic. OpenAI, Claude, open-source models on dedicated infrastructure, and native speech-to-speech models all run through the same interfaces. Switch models without rewriting the application.

What about speech-to-speech models like Nova Sonic and OpenAI Realtime?

Supported through the same kernel. New modalities arrive as configuration choices, not code changes. SignalWire's architecture was designed to absorb model evolution.

How does pricing work?

$0.16/min for the AI runtime, which includes speech-to-text, language model inference, text-to-speech, orchestration, state management, and governance. Transport (PSTN, SIP, WebRTC) is billed separately at carrier rates. No setup fees, no monthly minimums, no per-seat licenses.

Is the AI agent compliant for regulated industries?

The platform is SOC 2 Type II, HIPAA-eligible with a BAA, and supports PCI DSS controls. The hidden data layer keeps sensitive fields out of model context structurally, not by prompt instruction. Compliance is enforced at the platform level.

How do I migrate from a Twilio + Vapi or Twilio + Retell stack?

SignalWire's cXML compatibility layer runs existing TwiML inside the control plane, so Twilio voice flows can migrate without rewrite. The voice AI portion replaces the middleware vendor. Migrate incrementally; new agent code uses the SignalWire Agents SDK.

Build your first governed AI Voice Agent

The quickstart takes about 15 minutes. You will have a working agent on a real phone number before you close the tab

Build your first governed AI Voice Agent

The quickstart takes about 15 minutes. You will have a working agent on a real phone number before you close the tab

Build your first governed AI Voice Agent

The quickstart takes about 15 minutes. You will have a working agent on a real phone number before you close the tab

Build your first governed AI Voice Agent

The quickstart takes about 15 minutes. You will have a working agent on a real phone number before you close the tab