Go SDK for Plivo Programmable Agents — build AI agents that work over voice calls programmatically.
The SDK supports every Voice AI Agent configuration. Behavior is determined by which configs you provide when creating an agent — there is no explicit mode field:
| Config provided | Pipeline | You handle |
|---|---|---|
stt + llm + tts |
Full AI — Plivo runs the entire voice agent pipeline | Tool calls and flow control |
stt + tts |
BYOLLM — Plivo handles speech, you bring your own LLM | LLM inference, stream tokens back via SendText() |
s2s |
Speech-to-speech — single provider handles STT+LLM+TTS natively | Event handling (OpenAI Realtime, Gemini Live) |
| (none) | Audio stream — Plivo is a telephony bridge | You bring and orchestrate your own STT, LLM, TTS, VAD etc. |
Inbound/Outbound Call
|
Plivo Platform
|
WebSocket ──────► Your voice.App server
| |
Audio stream app.On("tool_call", handler)
VAD / Turn app.On("prompt", handler) ← BYOLLM
STT → LLM → TTS app.On("turn.completed", handler)
| |
Caller hears session.SendToolResult()
agent speech session.Speak() / session.TransferToNumber()
session.SendText() ← stream LLM tokens
session.SendMedia() ← raw audio mode
- Tool calling — LLM invokes tools, you handle them and return results
- Mid-call model switching — swap LLM model/prompt/tools via
session.Update()for agent handoff - Multi-party conferences — add participants with
calls.Dial(), warm transfer patterns - Voicemail detection — async AMD with beep detection for outbound calls
- Background audio — ambient sounds (office, typing, call-center) mixed with agent speech
- DTMF handling — detect keypress events for IVR flows
- Interruption (barge-in) — caller can interrupt the agent mid-speech
- User idle detection — configurable reminders and auto-hangup on silence
- Per-turn metrics — latency breakdown (STT, LLM TTFT, TTS) for monitoring
- Audio streaming — raw audio relay with
SendMedia(), checkpoints, andClearAudio() - BYOK (Bring Your Own Keys) — pass API keys for Deepgram, OpenAI, ElevenLabs, Cartesia, etc.
- Idiomatic Go — sub-packages (
agent,call,voice,webhook), functional options,errorinterface - Standalone WS server —
app.Run(":9000")or integrate with anyhttp.Handler - Goroutine-safe — Session methods are safe to call from any goroutine
- Automatic retries — exponential backoff on 429 (respects
Retry-After) and 5xx - Typed events — 25 struct types for all WebSocket events (
ToolCall,TurnMetrics,StreamMedia, ...) - Per-session state —
session.Datamap persists across events within a call - Clean errors —
PlivoErrorhierarchy withStatusCode,errors.As()support - Webhook verification —
webhook.ValidateSignatureV3()for securing callbacks - Zero non-stdlib HTTP deps —
net/httpfor REST,gorilla/websocketfor WS only
go get github.com/plivo/plivo-agentstack-goRequires Go 1.21+.
Sign up at cx.plivo.com/signup to get your PLIVO_AUTH_ID and PLIVO_AUTH_TOKEN, then see the examples/ directory:
- Basic agent — tool calls, session lifecycle, error handling
- Outbound call — REST client for agent CRUD and call initiation
package main
import (
"fmt"
"log"
"github.com/plivo/plivo-agentstack-go/voice"
)
func main() {
app := voice.NewApp()
app.OnSetup(func(s *voice.Session, e *voice.AgentSessionStarted) {
fmt.Printf("Session started: %s\n", e.AgentSessionID)
})
app.OnToolCall(func(s *voice.Session, e *voice.ToolCall) {
s.SendToolResult(e.ID, map[string]any{"temperature": 72, "city": "SF"})
})
app.OnSessionEnded(func(s *voice.Session, e *voice.AgentSessionEnded) {
fmt.Printf("Session ended: %ds, %d turns\n", e.DurationSeconds, e.TurnCount)
})
log.Fatal(app.Run(":9000"))
}package main
import (
"fmt"
"log"
plivoagent "github.com/plivo/plivo-agentstack-go"
"github.com/plivo/plivo-agentstack-go/agent"
"github.com/plivo/plivo-agentstack-go/call"
)
func main() {
client := plivoagent.NewClient("YOUR_AUTH_ID", "YOUR_AUTH_TOKEN")
a, err := client.Agents.Create(agent.CreateParams{
AgentName: "Sales Agent",
WebsocketURL: "wss://your-server.com/ws",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Agent: %s\n", a.AgentUUID)
c, err := client.Calls.Initiate(call.InitiateParams{
AgentID: a.AgentUUID,
From: "+14155551234",
To: []string{"+19876543210"},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Call: %s (%s)\n", c.CallUUID, c.Status)
}git clone https://github.com/plivo/plivo-agentstack-go.git
cd plivo-agentstack-go
go build ./...
go test ./... -v # ~66 tests
go vet ./...