Help us shape the future of Go! Take the 2026 Go Developer Survey

voiceagents

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

README

Sent Voice Agents for Go

An AI agent that takes and places phone calls through Sent, on the Sent Voice Agents protocol 0.2.0, for Go 1.23 and later.

Status: Preview, with the protocol. Generated and rendered by sent-dm-sdk-pipeline from the protocol at v0.2.0; every release passes the protocol's conformance scenarios in CI.

Read the Voice Agents docs to get started.

Install

go get github.com/sentdm/sent-dm-voice-agents-go

Go 1.23 or later. The one dependency is github.com/coder/websocket, which depends on nothing.

Quickstart

package main

import (
	"context"
	"os"
	"strings"

	voiceagents "github.com/sentdm/sent-dm-voice-agents-go"
)

type support struct{ voiceagents.BaseHandler }

func (support) OnSessionStart(ctx context.Context, session *voiceagents.Session) {
	session.Say("Hi, this is Acme support. How can I help?")
}

func (support) OnUserSaid(ctx context.Context, session *voiceagents.Session, said *voiceagents.UserSaid) {
	if strings.Contains(said.Text, "person") {
		session.Say("Transferring you now.")
		session.TransferNumber(ctx, "+14155550100")
	} else {
		session.Say("You said " + said.Text)
	}
}

func main() {
	agent := voiceagents.New(voiceagents.Options{
		APIKey:  os.Getenv("SENT_API_KEY"),
		AgentID: "agent_...",
		Handler: support{},
	})
	if err := agent.Serve(); err != nil {
		panic(err)
	}
}

Serve() connects to Sent with the account API key and serves calls until SIGINT or SIGTERM; Run(ctx) does the same until ctx ends or Stop() is called. Each session's handlers run in order on their own goroutine, so sessions never wait for one another. The runtime answers heartbeats, opens a new connection when one drains or is lost, and resumes the sessions that can move; the handlers only see calls.

Handler When
OnSessionStart(ctx, session) A call reached the agent. In a text session, Say to speak
OnUserSaid(ctx, session, said) Text sessions: the caller said something; said.Correction means it replaces the previous one
OnAudio(ctx, session, samples) Audio sessions: the caller's audio, 16-bit mono PCM at session.SampleRate
OnToolResult(ctx, session, result) Sent answered a tool call; the waiting Tool call gets the same result
OnSessionEnd(ctx, session, end) The call left the agent; end.Reason says why
OnSessionLost(ctx, session) The connection was lost and the session could not be resumed

On a Session: Say(text, Last(false), Interruptible(false)), Clear(), SendAudio(samples), and the tools Transfer(ctx, party), TransferNumber(ctx, number), Hangup(ctx), SendDTMF(ctx, digits), Hold(ctx, held), each returning Sent's ToolResult. session.From, To, Direction, SessionType, Language, Context, SampleRate carry what session.start said.

frames.go holds every frame as a type, with Decode and Encode that check the protocol's rules; it is generated from the protocol and not edited by hand.

Develop

gofmt -l . && go vet ./... && go test ./...     # formatting, vet, the tests against the protocol's fixtures
go build -o bin/conformance ./cmd/conformance   # the conformance agent the protocol's action runs in CI

Releases are cut by release-please from main; the release tag on this public repository is the release, and the publish workflow asks the Go module proxy for it so it is indexed at once.

Documentation

Index

Constants

View Source
const ConformanceGreeting = "Hello from the conformance agent."

ConformanceGreeting is what the conformance agent says first in a text session.

View Source
const ConnectPath = "/v1/agents/connect"
View Source
const DefaultURL = "wss://" + Host + ConnectPath

DefaultURL is where the agent connects when Options.URL is empty.

View Source
const HeaderBytes = 2

HeaderBytes is the size of the stream number before the samples.

View Source
const Host = "voice.sent.dm"
View Source
const ProtocolVersion = "0.2.0"
View Source
const RetainedFrames = 32

RetainedFrames is how many of its latest counted frames each side keeps per session, to send again on a resume.

View Source
const Subprotocol = "sent.voice.v1"
View Source
const Version = "0.1.0" // x-release-please-version

Version is this package's own version.

Variables

View Source
var ErrSessionEnded = errors.New("the session has ended")

ErrSessionEnded is returned once the call has left the agent: session.end arrived, or the session was lost.

View Source
var ErrTextSession = errors.New("the session is a text session")

ErrTextSession is returned by SendAudio on a text session.

View Source
var FromAgent = map[string]struct{}{"agent.say": {}, "tool.call": {}, "agent.clear": {}, "session.resume": {}, "pong": {}}
View Source
var FromSent = map[string]struct{}{"connection.ready": {}, "connection.draining": {}, "ping": {}, "error": {}, "session.start": {}, "user.said": {}, "tool.result": {}, "session.end": {}, "session.resumed": {}}

FromSent is who sends what: a frame from the other side on the wrong direction is a protocol error.

View Source
var PartyKinds = []string{"user", "number", "conference", "agent", "anonymous"}

PartyKinds is the values Sent lists today; it may add more, so a runtime treats others as it would the fallback.

View Source
var SessionEndReasons = []string{"caller_hung_up", "agent_hung_up", "transferred", "max_duration", "agent_unreachable", "balance_exhausted", "voice_disabled", "failed"}

SessionEndReasons is the values Sent lists today; it may add more, so a runtime treats others as it would the fallback.

View Source
var SessionScoped = map[string]struct{}{"session.start": {}, "user.said": {}, "tool.result": {}, "session.end": {}, "session.resumed": {}, "agent.say": {}, "tool.call": {}, "agent.clear": {}, "session.resume": {}}

SessionScoped is the frames that belong to a session: they carry session_id.

View Source
var SessionTypes = map[string][]string{
	"session.start":   {"text", "audio"},
	"user.said":       {"text"},
	"tool.result":     {"text", "audio"},
	"session.end":     {"text", "audio"},
	"session.resumed": {"text", "audio"},
	"agent.say":       {"text"},
	"tool.call":       {"text", "audio"},
	"agent.clear":     {"text", "audio"},
	"session.resume":  {"text", "audio"},
}

SessionTypes is which session types allow each session frame.

View Source
var Uncounted = map[string]struct{}{"error": {}, "session.start": {}, "session.resumed": {}, "session.resume": {}, "audio": {}}

Uncounted is the frames that do not count towards `received`, whatever they carry; every other frame with a session_id counts, also one of an unknown type.

Functions

func AudioFrame

func AudioFrame(stream int, samples []byte) ([]byte, error)

AudioFrame is a frame carrying samples for stream.

func BytesPerFrame

func BytesPerFrame(sampleRate, milliseconds int) int

BytesPerFrame is how many bytes of samples carry milliseconds of audio at sampleRate: 640 for 20 ms at 16000 Hz.

func Encode

func Encode(frame Frame) ([]byte, error)

Encode is the JSON to send for a frame, type first. It returns a *FrameError when the frame breaks the protocol.

func SamplesOf

func SamplesOf(frame []byte) []byte

SamplesOf is the samples of a frame, as 16-bit little-endian mono PCM.

func StreamOf

func StreamOf(frame []byte) int

StreamOf is the stream a frame belongs to: the session whose stream it is, on this connection.

Types

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent serves calls. Its Handler's methods run on the session's own goroutine, in order.

func New

func New(options Options) *Agent

New is an agent for the options. It connects when Run or Serve is called.

func (*Agent) Run

func (a *Agent) Run(ctx context.Context) error

Run serves calls until Stop is called or ctx ends. It returns a *Refused when Sent refuses the connection for a reason that needs a person, and nil otherwise.

func (*Agent) Serve

func (a *Agent) Serve() error

Serve runs the agent until SIGINT or SIGTERM. For a program whose main is the agent.

func (*Agent) Sessions

func (a *Agent) Sessions() []*Session

Sessions is every live session.

func (*Agent) Stop

func (a *Agent) Stop()

Stop stops serving: every connection closes with 1000, so the calls on them follow the agent's fallback at once.

type AgentClear

type AgentClear struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`
}

AgentClear: Drop the speech or audio the agent sent that Sent has not played yet.

func (AgentClear) MarshalJSON

func (f AgentClear) MarshalJSON() ([]byte, error)

func (*AgentClear) Session

func (f *AgentClear) Session() string

func (*AgentClear) Type

func (*AgentClear) Type() string

Type is the wire type of AgentClear: agent.clear.

type AgentSay

type AgentSay struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	Text string `json:"text"`

	// Interruptible: Whether the caller speaking stops this speech.
	Interruptible *bool `json:"interruptible,omitempty"`

	// Last: false when more text for the same utterance follows.
	Last *bool `json:"last,omitempty"`
}

AgentSay: Text sessions: speak this to the caller.

func (AgentSay) MarshalJSON

func (f AgentSay) MarshalJSON() ([]byte, error)

func (*AgentSay) Session

func (f *AgentSay) Session() string

func (*AgentSay) Type

func (*AgentSay) Type() string

Type is the wire type of AgentSay: agent.say.

type BaseHandler

type BaseHandler struct{}

BaseHandler does nothing on every event. Embed it and override the methods you need.

func (BaseHandler) OnAudio

func (BaseHandler) OnAudio(context.Context, *Session, []byte)

func (BaseHandler) OnConnected

func (BaseHandler) OnConnected(context.Context, *ConnectionReady)

func (BaseHandler) OnError

func (BaseHandler) OnFrame

func (BaseHandler) OnSessionEnd

func (BaseHandler) OnSessionEnd(context.Context, *Session, *SessionEnd)

func (BaseHandler) OnSessionLost

func (BaseHandler) OnSessionLost(context.Context, *Session)

func (BaseHandler) OnSessionStart

func (BaseHandler) OnSessionStart(context.Context, *Session)

func (BaseHandler) OnToolResult

func (BaseHandler) OnToolResult(context.Context, *Session, *ToolResult)

func (BaseHandler) OnUserSaid

func (BaseHandler) OnUserSaid(context.Context, *Session, *UserSaid)

type ConformanceHandler

type ConformanceHandler struct{ BaseHandler }

ConformanceHandler is the conformance agent's behaviour.

func (ConformanceHandler) OnAudio

func (ConformanceHandler) OnAudio(_ context.Context, session *Session, samples []byte)

func (ConformanceHandler) OnSessionStart

func (ConformanceHandler) OnSessionStart(_ context.Context, session *Session)

func (ConformanceHandler) OnToolResult

func (ConformanceHandler) OnToolResult(_ context.Context, session *Session, result *ToolResult)

func (ConformanceHandler) OnUserSaid

func (ConformanceHandler) OnUserSaid(ctx context.Context, session *Session, said *UserSaid)

type ConformanceStep

type ConformanceStep struct {
	// Action is say or tool.
	Action    string
	Text      string
	Last      *bool
	Name      string
	Arguments map[string]any
}

ConformanceStep is one action the conformance agent performs for a user.said.

func Decide

func Decide(text string) []ConformanceStep

Decide is what a user.said asks for: the actions the agent performs in order. A command is the text up to the first space; stream takes the next word as the first piece.

type ConnectionDraining

type ConnectionDraining struct {
}

ConnectionDraining: No new sessions will start on this connection. Open a new one now, while sessions already on this one go on.

func (ConnectionDraining) MarshalJSON

func (f ConnectionDraining) MarshalJSON() ([]byte, error)

func (*ConnectionDraining) Type

func (*ConnectionDraining) Type() string

Type is the wire type of ConnectionDraining: connection.draining.

type ConnectionReady

type ConnectionReady struct {
	// ProtocolVersion: The version of this protocol Sent speaks on the connection.
	ProtocolVersion string `json:"protocol_version"`

	// HeartbeatIntervalMs: How often Sent sends ping on the connection.
	HeartbeatIntervalMs int64 `json:"heartbeat_interval_ms"`

	// MaxSessions: The most sessions Sent puts on the connection at once.
	MaxSessions int64 `json:"max_sessions"`
}

ConnectionReady: First on a connection the agent opened: it is authenticated, and sessions will follow.

func (ConnectionReady) MarshalJSON

func (f ConnectionReady) MarshalJSON() ([]byte, error)

func (*ConnectionReady) Type

func (*ConnectionReady) Type() string

Type is the wire type of ConnectionReady: connection.ready.

type ErrorFrame

type ErrorFrame struct {
	Error *ErrorInfo `json:"error"`

	// SessionID: The session: one call while one agent is on it.
	SessionID *string `json:"session_id,omitempty"`

	// FrameType: The type of the frame that was not accepted, when it had one.
	FrameType *string `json:"frame_type,omitempty"`
}

ErrorFrame: A frame the agent sent was not accepted and had no effect. The connection stays open.

func (ErrorFrame) MarshalJSON

func (f ErrorFrame) MarshalJSON() ([]byte, error)

func (*ErrorFrame) Type

func (*ErrorFrame) Type() string

Type is the wire type of ErrorFrame: error.

type ErrorInfo

type ErrorInfo struct {
	// Code: Stable and machine-readable. Sent may add codes.
	Code string `json:"code"`

	// Message: For people. It may change without notice.
	Message string `json:"message"`
}

ErrorInfo is the ErrorInfo object.

type Frame

type Frame interface {
	Type() string
}

Frame is one frame of the protocol; Type is its wire `type`.

func Decode

func Decode(data []byte) (Frame, error)

Decode is the frame a JSON text carries. It returns a *FrameError when the text is not a JSON object with a string type, or when the frame breaks the protocol.

type FrameError

type FrameError struct {
	Message string
}

FrameError is a frame that does not fit the protocol.

func (*FrameError) Error

func (e *FrameError) Error() string

type Handler

type Handler interface {
	// OnConnected: a connection to Sent is ready for sessions.
	OnConnected(ctx context.Context, ready *ConnectionReady)
	// OnSessionStart: a call reached the agent. In a text session, Say to speak; an audio session waits for audio.
	OnSessionStart(ctx context.Context, session *Session)
	// OnUserSaid: text sessions, the caller said something. With Correction true it replaces the previous one.
	OnUserSaid(ctx context.Context, session *Session, said *UserSaid)
	// OnAudio: audio sessions, the caller's audio, 16-bit little-endian mono PCM at session.SampleRate.
	OnAudio(ctx context.Context, session *Session, samples []byte)
	// OnToolResult: Sent answered a tool call. The call's waiting Tool gets the same result.
	OnToolResult(ctx context.Context, session *Session, result *ToolResult)
	// OnFrame: a session frame this SDK version does not know. It was counted; nothing else is needed.
	OnFrame(ctx context.Context, session *Session, frame *UnknownFrame)
	// OnSessionEnd: the call left the agent. end.Reason says why.
	OnSessionEnd(ctx context.Context, session *Session, end *SessionEnd)
	// OnSessionLost: the session's connection was lost and it could not be resumed. Sent ends the call with
	// agent_unreachable; no session.end follows.
	OnSessionLost(ctx context.Context, session *Session)
	// OnError: Sent refused a frame; the connection stays open.
	OnError(ctx context.Context, err *ErrorFrame)
}

Handler is what an agent does on its calls. Embed BaseHandler and override what you need.

type Options

type Options struct {
	// APIKey is the account API key. Keep it on the server the agent runs on.
	APIKey string
	// AgentID is the agent, as POST /v3/voice/agents created it.
	AgentID string
	// URL is where to connect. Empty means Sent.
	URL string
	// Handler is what the agent does on its calls.
	Handler Handler
	// Logger is where the runtime's log lines go. Nil means slog's default; tokens never appear in them.
	Logger *slog.Logger
}

Options is what an agent needs.

type Party

type Party struct {
	// Kind: user, number, conference, agent or anonymous. Sent may add kinds.
	Kind string `json:"kind"`

	// Value: The app user's identity, the E.164 number, the room name or the agent id. Absent for anonymous.
	Value *string `json:"value,omitempty"`
}

Party: One end of a call, in the shape of the REST API's call parties.

type Ping

type Ping struct {
	// Ts: Milliseconds since the Unix epoch.
	Ts int64 `json:"ts"`
}

Ping: Sent's heartbeat on a connection. Answer with pong carrying the same ts.

func (Ping) MarshalJSON

func (f Ping) MarshalJSON() ([]byte, error)

func (*Ping) Type

func (*Ping) Type() string

Type is the wire type of Ping: ping.

type Pong

type Pong struct {
	// Ts: Milliseconds since the Unix epoch.
	Ts int64 `json:"ts"`
}

Pong: The answer to ping, with the same ts.

func (Pong) MarshalJSON

func (f Pong) MarshalJSON() ([]byte, error)

func (*Pong) Type

func (*Pong) Type() string

Type is the wire type of Pong: pong.

type Refused

type Refused struct {
	Status int
	Reason string
}

Refused is the error Run returns when Sent refused the connection for a reason that needs a person.

func (*Refused) Error

func (r *Refused) Error() string

type Resume

type Resume struct {
	// Token: A secret that moves one session to a new connection, once. Opaque: keep it out of URLs and logs.
	Token string `json:"token"`

	// WindowMs: How long Sent keeps the session for a resume after its connection is lost, or after it ends.
	WindowMs int64 `json:"window_ms"`
}

Resume: How to resume the session on a new connection. See Resuming sessions in docs/protocol.md.

type SayOption

type SayOption func(*AgentSay)

SayOption changes how a Say is spoken.

func Interruptible

func Interruptible(interruptible bool) SayOption

Interruptible is whether the caller speaking stops this speech.

func Last

func Last(last bool) SayOption

Last marks a piece of a reply: send pieces with Last(false) and finish with Last(true); they are spoken as one utterance.

type Session

type Session struct {
	ID        string
	CallID    string
	AgentID   string
	Direction string
	From      *Party
	To        *Party
	// SessionType is text or audio.
	SessionType string
	Language    string
	Context     map[string]any
	StartedAt   string
	// SampleRate is the Hz of the session's 16-bit mono PCM, both ways, in an audio session.
	SampleRate int
	// Start is what session.start said about the call.
	Start *SessionStart
	// contains filtered or unexported fields
}

Session is the call the agent is on, and the ways to act on it. The agent creates it; its handlers run in order.

func (*Session) Clear

func (s *Session) Clear() error

Clear drops the speech or audio the agent sent that Sent has not played yet.

func (*Session) End

func (s *Session) End() *SessionEnd

End is session.end, once it arrived.

func (*Session) Ended

func (s *Session) Ended() bool

Ended is whether the call has left the agent: session.end arrived, or the session was lost.

func (*Session) Hangup

func (s *Session) Hangup(ctx context.Context) (*ToolResult, error)

Hangup ends the call, after the speech the agent queued before it.

func (*Session) Hold

func (s *Session) Hold(ctx context.Context, held bool) (*ToolResult, error)

Hold puts the caller on hold, or takes them off it.

func (*Session) Lost

func (s *Session) Lost() bool

Lost is whether the connection was lost and the session could not be resumed: Sent ends the call without a session.end.

func (*Session) Received

func (s *Session) Received() int64

Received is how many of Sent's counted frames for the session the agent has read: the received of a resume.

func (*Session) Resumable

func (s *Session) Resumable() bool

Resumable is whether the session survives a lost connection: it has a resume token.

func (*Session) Say

func (s *Session) Say(text string, options ...SayOption) error

Say speaks text to the caller of a text session.

func (*Session) SendAudio

func (s *Session) SendAudio(samples []byte) error

SendAudio plays samples, 16-bit little-endian mono PCM at the session's sample rate, in an audio session. Send 20 ms per call, and no more than 200 ms. It returns ErrSessionEnded once the call has left the agent.

func (*Session) SendDTMF

func (s *Session) SendDTMF(ctx context.Context, digits string) (*ToolResult, error)

SendDTMF plays digits on the call: 0 to 9, *, #, A to D, and w to wait half a second.

func (*Session) Sent

func (s *Session) Sent() int64

Sent is how many counted frames the agent has sent for the session.

func (*Session) Stream

func (s *Session) Stream() (int, bool)

Stream is the number in the header of the session's binary audio frames on its current connection.

func (*Session) Token

func (s *Session) Token() (string, bool)

Token is the latest resume token, when the session can be resumed. Keep it out of logs.

func (*Session) Tool

func (s *Session) Tool(ctx context.Context, name string, arguments map[string]any) (*ToolResult, error)

Tool calls a tool by name and waits for its tool.result. It returns ErrSessionEnded if the session ends first, and ctx's error if ctx ends first.

func (*Session) Transfer

func (s *Session) Transfer(ctx context.Context, to *Party) (*ToolResult, error)

Transfer moves the call to another party. On success the session then ends with transferred.

func (*Session) TransferNumber

func (s *Session) TransferNumber(ctx context.Context, number string) (*ToolResult, error)

TransferNumber moves the call to an E.164 number.

func (*Session) WindowMs

func (s *Session) WindowMs() int64

WindowMs is how long Sent keeps the session for a resume after its connection is lost.

type SessionEnd

type SessionEnd struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	// Reason: Why the call left the agent. Sent may add reasons, so treat one you do not know as failed.
	Reason string `json:"reason"`

	DurationMs int64 `json:"duration_ms"`
}

SessionEnd: Last for every session: the call has left the agent.

func (SessionEnd) MarshalJSON

func (f SessionEnd) MarshalJSON() ([]byte, error)

func (*SessionEnd) Session

func (f *SessionEnd) Session() string

func (*SessionEnd) Type

func (*SessionEnd) Type() string

Type is the wire type of SessionEnd: session.end.

type SessionFrame

type SessionFrame interface {
	Frame
	Session() string
}

SessionFrame is a frame that belongs to a session: it carries session_id.

type SessionResume

type SessionResume struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	// Token: A secret that moves one session to a new connection, once. Opaque: keep it out of URLs and logs.
	Token string `json:"token"`

	// Received: How many of the other side's frames for the session were read. Resuming sessions in docs/protocol.md says which frames count.
	Received int64 `json:"received"`
}

SessionResume: Move a session to this connection, after its connection was lost or while it drains.

func (SessionResume) MarshalJSON

func (f SessionResume) MarshalJSON() ([]byte, error)

func (*SessionResume) Session

func (f *SessionResume) Session() string

func (*SessionResume) Type

func (*SessionResume) Type() string

Type is the wire type of SessionResume: session.resume.

type SessionResumed

type SessionResumed struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	// Received: How many of the other side's frames for the session were read. Resuming sessions in docs/protocol.md says which frames count.
	Received int64 `json:"received"`

	// Resume: How to resume the session on a new connection. See Resuming sessions in docs/protocol.md.
	Resume *Resume `json:"resume,omitempty"`

	// Audio: Present on an audio session that is still live: its stream on this connection, which can differ from the one before. Its sample rate does not change.
	Audio *SessionResumedAudio `json:"audio,omitempty"`
}

SessionResumed: The session is on this connection now. Sent's frames the agent did not read follow, in order.

func (SessionResumed) MarshalJSON

func (f SessionResumed) MarshalJSON() ([]byte, error)

func (*SessionResumed) Session

func (f *SessionResumed) Session() string

func (*SessionResumed) Type

func (*SessionResumed) Type() string

Type is the wire type of SessionResumed: session.resumed.

type SessionResumedAudio

type SessionResumedAudio struct {
	// Stream: The number in the header of the session's binary audio frames, unique among the sessions open on the connection.
	Stream int64 `json:"stream"`
}

SessionResumedAudio: Present on an audio session that is still live: its stream on this connection, which can differ from the one before. Its sample rate does not change.

type SessionStart

type SessionStart struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	// CallID: The call, as the REST API's /v3/voice/calls knows it. It stays the same when the call moves to a person.
	CallID string `json:"call_id"`

	// AgentID: The agent, as the REST API's /v3/voice/agents knows it.
	AgentID string `json:"agent_id"`

	Direction string `json:"direction"`

	// From: One end of a call, in the shape of the REST API's call parties.
	From *Party `json:"from"`

	// To: One end of a call, in the shape of the REST API's call parties.
	To *Party `json:"to"`

	SessionType string `json:"session_type"`

	// Language: The caller's language as a BCP 47 tag, from the agent's speech settings.
	Language *string `json:"language,omitempty"`

	// Audio: Present on audio sessions.
	Audio *SessionStartAudio `json:"audio,omitempty"`

	// MaxDurationMs: When Sent ends the session with reason max_duration, counted from started_at.
	MaxDurationMs *int64 `json:"max_duration_ms,omitempty"`

	// Context: What the customer's backend passed when it started an outbound call. At most 4 KB as JSON.
	Context map[string]any `json:"context,omitempty"`

	// Resume: How to resume the session on a new connection. See Resuming sessions in docs/protocol.md.
	Resume *Resume `json:"resume,omitempty"`

	// StartedAt: When the session started, in ISO 8601, as the REST API writes times.
	StartedAt string `json:"started_at"`
}

SessionStart: First for every session: a call has reached the agent.

func (SessionStart) MarshalJSON

func (f SessionStart) MarshalJSON() ([]byte, error)

func (*SessionStart) Session

func (f *SessionStart) Session() string

func (*SessionStart) Type

func (*SessionStart) Type() string

Type is the wire type of SessionStart: session.start.

type SessionStartAudio

type SessionStartAudio struct {
	// Stream: The number in the header of the session's binary audio frames, unique among the sessions open on the connection.
	Stream int64 `json:"stream"`

	// SampleRate: Hz of the session's 16-bit mono PCM, both ways.
	SampleRate *int64 `json:"sample_rate,omitempty"`
}

SessionStartAudio: Present on audio sessions.

type ToolCall

type ToolCall struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	// CallRef: Chosen by the agent for a tool.call, unique within the session, and repeated in its tool.result.
	CallRef string `json:"call_ref"`

	Name string `json:"name"`

	Arguments map[string]any `json:"arguments,omitempty"`
}

ToolCall: Act on the call with a built-in tool. Sent answers with exactly one tool.result.

func (ToolCall) MarshalJSON

func (f ToolCall) MarshalJSON() ([]byte, error)

func (*ToolCall) Session

func (f *ToolCall) Session() string

func (*ToolCall) Type

func (*ToolCall) Type() string

Type is the wire type of ToolCall: tool.call.

type ToolResult

type ToolResult struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	// CallRef: Chosen by the agent for a tool.call, unique within the session, and repeated in its tool.result.
	CallRef string `json:"call_ref"`

	Ok bool `json:"ok"`

	Error *ErrorInfo `json:"error,omitempty"`
}

ToolResult: The outcome of one tool.call, with its call_ref.

func (ToolResult) MarshalJSON

func (f ToolResult) MarshalJSON() ([]byte, error)

func (*ToolResult) Session

func (f *ToolResult) Session() string

func (*ToolResult) Type

func (*ToolResult) Type() string

Type is the wire type of ToolResult: tool.result.

type UnknownFrame

type UnknownFrame struct {

	// SessionID is the session the frame names, or empty.
	SessionID string

	// Fields is the frame as it arrived, every field included.
	Fields map[string]any
	// contains filtered or unexported fields
}

UnknownFrame is a frame of a type this version does not know. Ignore it; count it when it names a session.

func NewUnknownFrame

func NewUnknownFrame(fields map[string]any) *UnknownFrame

NewUnknownFrame is a frame of a type this version does not know, as its fields, type included.

func (UnknownFrame) MarshalJSON

func (f UnknownFrame) MarshalJSON() ([]byte, error)

func (*UnknownFrame) Session

func (f *UnknownFrame) Session() string

func (*UnknownFrame) Type

func (f *UnknownFrame) Type() string

type UserSaid

type UserSaid struct {
	// SessionID: The session: one call while one agent is on it.
	SessionID string `json:"session_id"`

	Text string `json:"text"`

	// Correction: true when this replaces the session's previous user.said.
	Correction bool `json:"correction"`
}

UserSaid: Text sessions: one complete utterance from the caller.

func (UserSaid) MarshalJSON

func (f UserSaid) MarshalJSON() ([]byte, error)

func (*UserSaid) Session

func (f *UserSaid) Session() string

func (*UserSaid) Type

func (*UserSaid) Type() string

Type is the wire type of UserSaid: user.said.

Directories

Path Synopsis
cmd
conformance command
The conformance agent of sent-dm-voice-protocol, as a program: the protocol's harness runs it with SENT_CONFORMANCE_URL set, in CI before every release, and by hand against a harness on localhost.
The conformance agent of sent-dm-voice-protocol, as a program: the protocol's harness runs it with SENT_CONFORMANCE_URL set, in CI before every release, and by hand against a harness on localhost.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL