All fields are required
LiveKit closed state management as 'Not Planned.' SignalWire built it in. The gap between idea and working agent should be code, not workarounds.
LiveKit requires all tools to be defined as Python functions. Developers who want to define tools using JSON Schema (the format LLMs use natively) cannot. The request was closed as 'Not Planned' (GitHub #1966).
No built-in way to persist conversation state across turns, transfers, or steps. Developers build custom state layers from scratch for every project.
livekit-agents, livekit, livekit-api, livekit-protocol, plus plugins for each STT, TTS, and turn detection provider. Version mismatches cause silent failures.
Developers see APIConnectionError with body: null when they hit STT quotas. A LiveKit team member acknowledged the error message is poor. Debugging requires guessing.
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult
class SupportAgent(AgentBase):
def __init__(self):
super().__init__(name="Support Agent", route="/support")
self.prompt_add_section("Instructions",
body="You are a customer support agent. "
"Greet the caller and resolve their issue.")
self.add_language("English", "en-US", "rime.spore:mistv2")
@AgentBase.tool(name="check_order")
def check_order(self, order_id: str):
"""Check the status of a customer order.
Args:
order_id: The order ID to look up
"""
return SwaigFunctionResult(f"Order {order_id}: shipped, ETA April 2nd")
agent = SupportAgent()
agent.run()
Language models use JSON Schema, MCP uses JSON Schema, OpenAPI uses JSON Schema, but livekit uses python functions.
Store account numbers, auth tokens, and PII accessible to tool functions but invisible to the language model. No prompt leakage of sensitive data.
State persists automatically across conversation turns, agent transfers, and step transitions. No external database required.
Trigger end-of-conversation summaries, CRM updates, and ticket creation through built-in post-prompt hooks. No webhook gymnastics.
Tool function responses include state updates that persist automatically and are available to subsequent turns without manual save and restore.
| Aspect | LiveKit | SignalWire |
|---|---|---|
| Tool definition | Python function introspection | JSON Schema + decorator (LLM-native) |
| Serverless data integration | Not available | Serverless API integration connects to any endpoint |
| State management | Manual (closed as 'Not Planned') | Built-in shared data layer and session |
| Package count | 8+ coordinated packages | 1 package |
| Version coordination | Required; silent failures on mismatch | Not needed |
| Error messages | Quota limits appear as connection errors | Standard HTTP status codes |
| Model compatibility | Plugin-dependent (documented Gemini issues) | Platform-level, model-agnostic |
| Post-call actions | DIY webhook integration | Built-in post-prompts |
| Deployment | LiveKit-specific worker process | Any Python host (server, Lambda, Cloud Functions) |
pip install signalwire-agents. One package, one version.
Inherit AgentBase, set a prompt, add skills. Under 15 lines for a working agent.
Decorate Python functions with @agent.tool or define them in YAML. JSON Schema generated automatically.
Call agent.run(). Same code deploys to a server, Lambda, or Cloud Functions. No platform-specific worker process.
Yes. STT, TTS, and LLM providers are configured at the platform level. You bring your own API keys or use SignalWire's integrated providers.
Tools are defined as JSON Schema. Model compatibility is handled at the platform level, not in client-side plugins. The same tool definition works across providers.
Session state, metadata, and conversation context transfer automatically. The receiving agent inherits the full conversation history.
No. SignalWire agents are standard Python HTTP servers. Run locally with python your_agent.py, test with any HTTP client, deploy anywhere.
Trusted by 2,000+ companies
One package, one install. The same code deploys to a server, Lambda, or Cloud Functions.