workflows

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package workflows contains reusable, context-first agent workflows.

Index

Constants

View Source
const (
	HumanAgentIdentity                  = "human-agent-sip"
	DefaultCallerHangupNoticeTimeout    = 30 * time.Second
	DefaultCallerHangupCleanupTimeout   = 10 * time.Second
	DefaultWarmTransferCleanupTimeout   = 10 * time.Second
	DefaultWarmTransferMergeTimeout     = 30 * time.Second
	DefaultWarmTransferDialDrainTimeout = 10 * time.Second
	BuiltinHoldMusic                    = "hold_music"
)
View Source
const CallerHangupInstruction = `` /* 156-byte string literal not displayed */
View Source
const DefaultTaskGroupMaxExecutions = 1024
View Source
const WarmTransferInstructionsTemplate = `{persona}

# Context

In the conversation, user refers to the human agent, caller refers to the person who's transcript is included.
Remember, you are not speaking to the caller right now, you are speaking to the human agent.

## Conversation history with caller
{_conversation_history}
## End of conversation history with caller

Once the human agent has confirmed, you should call the tool ` + "`connect_to_caller`" + ` to connect them to the caller.

You are talking to the human agent now, start by giving them a summary of the conversation so far, and answer any questions they might have.

{extra}
`
View Source
const WarmTransferPersona = `` /* 376-byte string literal not displayed */

Variables

View Source
var (
	ErrTaskGroupAlreadyStarted   = errors.New("workflows: task group has already started")
	ErrTaskGroupNotComplete      = errors.New("workflows: task group is not complete")
	ErrTaskGroupExecutionLimit   = errors.New("workflows: task group execution limit exceeded")
	ErrTaskGroupSummarizerNeeded = errors.New("workflows: summarizeChatCtx requires a standard LLM or summarizer")
)
View Source
var (
	ErrWarmTransferAlreadyStarted = errors.New("workflows: warm transfer has already started")
	ErrWarmTransferNotStarted     = errors.New("workflows: warm transfer has not started")
	ErrWarmTransferAlreadyDone    = errors.New("workflows: warm transfer is already complete")
	ErrWarmTransferNotReady       = errors.New("workflows: warm transfer is not ready to merge")
	ErrWarmTransferCallerGone     = errors.New("workflows: caller hung up before the transfer completed")
	ErrWarmTransferVoicemail      = errors.New("workflows: voicemail detected")
	ErrWarmTransferDeclined       = errors.New("workflows: human agent declined to connect")
	ErrWarmTransferRoomClosed     = errors.New("workflows: human agent room closed")
)

Functions

func CreateCallerHangupSpeech

func CreateCallerHangupSpeech(ctx context.Context, session WarmTransferSession, speech WarmTransferSpeech, instruction *string) (*voice.SpeechHandle, error)

func CreateWarmTransferSpeech

func CreateWarmTransferSpeech(ctx context.Context, session WarmTransferSession, speech WarmTransferSpeech, options voice.SayOptions) (*voice.SpeechHandle, error)

func FormatWarmTransferConversation

func FormatWarmTransferConversation(chat *llm.ChatContext) string

func ResolveHumanAgentRoomName

func ResolveHumanAgentRoomName(callerRoomName string, override *string) (string, error)

func ResolveWarmTransferInstructions

func ResolveWarmTransferInstructions(config WarmTransferInstructionConfig, chat *llm.ChatContext) string

ResolveWarmTransferInstructions renders the pinned agents-js prompt. A full string bypasses templating; unset parts preserve defaults and explicit empty parts remove their section.

func SummarizeChatContext

func SummarizeChatContext(ctx context.Context, model llm.LLM, chat *llm.ChatContext) (*llm.ChatContext, error)

SummarizeChatContext applies the same keepLastTurns=0 summarization used by agents-js TaskGroup. The source context is never mutated.

Types

type AgentTaskAdapter

type AgentTaskAdapter[Result, UserData any] struct {
	// contains filtered or unexported fields
}

AgentTaskAdapter erases a voice task's result type without erasing errors or its chat/tool context.

func AdaptAgentTask

func AdaptAgentTask[Result, UserData any](task *voice.AgentTask[Result, UserData], runner TaskRunner[Result, UserData]) (*AgentTaskAdapter[Result, UserData], error)

AdaptAgentTask wraps a typed voice.AgentTask for TaskGroup. If runner is nil, Run waits on task.Run; callers that need the group to perform the foreground handoff should supply their session's task runner.

func (*AgentTaskAdapter[Result, UserData]) AgentTask

func (a *AgentTaskAdapter[Result, UserData]) AgentTask() *voice.AgentTask[Result, UserData]

func (*AgentTaskAdapter[Result, UserData]) ChatContext

func (a *AgentTaskAdapter[Result, UserData]) ChatContext() *llm.ChatContext

func (*AgentTaskAdapter[Result, UserData]) Run

func (a *AgentTaskAdapter[Result, UserData]) Run(ctx context.Context) (any, error)

func (*AgentTaskAdapter[Result, UserData]) ToolContext

func (a *AgentTaskAdapter[Result, UserData]) ToolContext() *llm.Context

func (*AgentTaskAdapter[Result, UserData]) UpdateChatContext

func (a *AgentTaskAdapter[Result, UserData]) UpdateChatContext(ctx context.Context, chat *llm.ChatContext) error

func (*AgentTaskAdapter[Result, UserData]) UpdateTools

func (a *AgentTaskAdapter[Result, UserData]) UpdateTools(ctx context.Context, tools *llm.Context) error

type ChatSummarizer

type ChatSummarizer interface {
	SummarizeChatContext(context.Context, *llm.ChatContext) (*llm.ChatContext, error)
}

ChatSummarizer replaces a chat history with its bounded summary.

type ChatSummarizerFunc

type ChatSummarizerFunc func(context.Context, *llm.ChatContext) (*llm.ChatContext, error)

ChatSummarizerFunc adapts a function to ChatSummarizer.

func (ChatSummarizerFunc) SummarizeChatContext

func (f ChatSummarizerFunc) SummarizeChatContext(ctx context.Context, chat *llm.ChatContext) (*llm.ChatContext, error)

type InstructionPart

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

InstructionPart is one replaceable section of a built-in workflow prompt. TextInstruction is the convenient form for ordinary text; ModalInstruction preserves separate audio and text instructions.

func InstructionPartPtr

func InstructionPartPtr(value InstructionPart) *InstructionPart

InstructionPartPtr is a convenience for struct literals.

func ModalInstruction

func ModalInstruction(value llm.Instructions) InstructionPart

ModalInstruction constructs a workflow instruction section from LiveKit's modality-aware Instructions value.

func TextInstruction

func TextInstruction(value string) InstructionPart

TextInstruction constructs a workflow instruction section from plain text.

func (InstructionPart) Instructions

func (p InstructionPart) Instructions() llm.Instructions

Instructions returns the modality-aware instruction value.

func (InstructionPart) Value

func (p InstructionPart) Value() string

Value returns the audio/default representation of the instruction section.

type InstructionParts

type InstructionParts struct {
	Persona *InstructionPart
	Extra   *InstructionPart
}

InstructionParts customizes sections of built-in workflow prompts. Nil preserves the workflow default; a pointer to TextInstruction("") removes the section. This distinction matches agents-js and agents-python.

type Task

type Task interface {
	Run(context.Context) (any, error)
	ChatContext() *llm.ChatContext
	UpdateChatContext(context.Context, *llm.ChatContext) error
	ToolContext() *llm.Context
	UpdateTools(context.Context, *llm.Context) error
}

Task is the small surface TaskGroup needs from an agent task. The adapter returned by AdaptAgentTask makes every *voice.AgentTask usable here while a custom implementation is useful for non-voice or deterministic tasks.

type TaskCompletedEvent

type TaskCompletedEvent struct {
	AgentTask Task
	TaskID    string
	Result    any
}

TaskCompletedEvent is emitted after a child completes and its chat context has been merged into the group.

type TaskFactory

type TaskFactory func() Task

type TaskGroup

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

TaskGroup runs registered tasks sequentially and lets later tasks regress to already-visited tasks through a generated out_of_scope tool. It is one-shot.

func MustTaskGroup

func MustTaskGroup(options TaskGroupOptions) *TaskGroup

func NewTaskGroup

func NewTaskGroup(options TaskGroupOptions) (*TaskGroup, error)

func (*TaskGroup) Add

func (g *TaskGroup) Add(factory TaskFactory, registration TaskRegistration) *TaskGroup

Add registers or replaces a task and returns the group for fluent setup. As in JavaScript Map.set, replacing an ID preserves its original ordering. Bad registrations are reported by Run; AddTask is the eager-validation variant.

func (*TaskGroup) AddTask

func (g *TaskGroup) AddTask(factory TaskFactory, registration TaskRegistration) error

func (*TaskGroup) ChatContext

func (g *TaskGroup) ChatContext() *llm.ChatContext

func (*TaskGroup) Done

func (g *TaskGroup) Done() bool

func (*TaskGroup) PreserveFunctionCallHistory

func (g *TaskGroup) PreserveFunctionCallHistory() bool

func (*TaskGroup) Result

func (g *TaskGroup) Result() (TaskGroupResult, error)

func (*TaskGroup) Run

type TaskGroupOptions

type TaskGroupOptions struct {
	// Nil preserves the agents-js default (true).
	SummarizeChatCtx *bool
	ReturnExceptions bool
	ChatCtx          *llm.ChatContext
	OnTaskCompleted  func(context.Context, TaskCompletedEvent) error
	// PreserveFunctionCallHistory is exposed for parity with AgentTask even
	// though TaskGroup always retains tool results until optional summarization.
	PreserveFunctionCallHistory bool

	// LLM supplies the agents-js standard-LLM summarizer. Summarizer overrides
	// LLM and is useful for custom/realtime model stacks.
	LLM        llm.LLM
	Summarizer ChatSummarizer

	// MaxExecutions bounds regressions caused by out_of_scope. Zero selects
	// DefaultTaskGroupMaxExecutions.
	MaxExecutions int
}

type TaskGroupResult

type TaskGroupResult struct {
	TaskResults map[string]any `json:"taskResults"`
}

TaskGroupResult contains the last successful/error value for every completed task ID. A fresh map is returned to every observer.

type TaskRegistration

type TaskRegistration struct {
	ID          string
	Description string
}

type TaskRunner

type TaskRunner[Result, UserData any] func(context.Context, *voice.AgentTask[Result, UserData]) (Result, error)

TaskRunner starts a voice task in its owning session and waits for its typed result. It is separate from voice.AgentTask.Run because the latter only waits for completion; the session/runtime owns the foreground handoff.

type WarmTransferBackend

type WarmTransferBackend interface {
	CallerRoomName(context.Context) (string, error)
	CallerLocalIdentity(context.Context) (string, error)
	CallerPresent(context.Context) (bool, error)
	CallerDisconnected() <-chan WarmTransferParticipantEvent

	CaptureCallerIO(context.Context) (WarmTransferIOState, error)
	SetCallerIO(context.Context, WarmTransferIOState) error
	StartHold(context.Context, WarmTransferHoldAudio) (WarmTransferHold, error)

	Dial(context.Context, WarmTransferDialRequest) (WarmTransferConsultation, error)
	MoveParticipant(context.Context, string, string, string) error
	RemoveParticipant(context.Context, string, string) error
	DeleteRoom(context.Context, string) error
}

WarmTransferBackend isolates RTC/SIP ownership from the deterministic workflow state machine. Methods that may block are context-first. The caller event stream must be bounded by the implementation and must never be closed while Run is active without first carrying the terminal disconnect event.

type WarmTransferBackendFuncs

type WarmTransferBackendFuncs struct {
	CallerRoomNameFunc      func(context.Context) (string, error)
	CallerLocalIdentityFunc func(context.Context) (string, error)
	CallerPresentFunc       func(context.Context) (bool, error)
	CallerDisconnectedChan  <-chan WarmTransferParticipantEvent
	CaptureCallerIOFunc     func(context.Context) (WarmTransferIOState, error)
	SetCallerIOFunc         func(context.Context, WarmTransferIOState) error
	StartHoldFunc           func(context.Context, WarmTransferHoldAudio) (WarmTransferHold, error)
	DialFunc                func(context.Context, WarmTransferDialRequest) (WarmTransferConsultation, error)
	MoveParticipantFunc     func(context.Context, string, string, string) error
	RemoveParticipantFunc   func(context.Context, string, string) error
	DeleteRoomFunc          func(context.Context, string) error
	PostMergeCleanupFunc    func(context.Context, string) error
}

WarmTransferBackendFuncs is a zero-allocation adapter for applications that already own RTC callbacks, RoomIO, or a custom consultation session.

func (WarmTransferBackendFuncs) CallerDisconnected

func (b WarmTransferBackendFuncs) CallerDisconnected() <-chan WarmTransferParticipantEvent

func (WarmTransferBackendFuncs) CallerLocalIdentity

func (b WarmTransferBackendFuncs) CallerLocalIdentity(ctx context.Context) (string, error)

func (WarmTransferBackendFuncs) CallerPresent

func (b WarmTransferBackendFuncs) CallerPresent(ctx context.Context) (bool, error)

func (WarmTransferBackendFuncs) CallerRoomName

func (b WarmTransferBackendFuncs) CallerRoomName(ctx context.Context) (string, error)

func (WarmTransferBackendFuncs) CaptureCallerIO

func (WarmTransferBackendFuncs) DeleteCallerRoomOnDisconnect

func (b WarmTransferBackendFuncs) DeleteCallerRoomOnDisconnect(ctx context.Context, room string) error

func (WarmTransferBackendFuncs) DeleteRoom

func (b WarmTransferBackendFuncs) DeleteRoom(ctx context.Context, room string) error

func (WarmTransferBackendFuncs) Dial

func (WarmTransferBackendFuncs) MoveParticipant

func (b WarmTransferBackendFuncs) MoveParticipant(ctx context.Context, from, identity, to string) error

func (WarmTransferBackendFuncs) RemoveParticipant

func (b WarmTransferBackendFuncs) RemoveParticipant(ctx context.Context, room, identity string) error

func (WarmTransferBackendFuncs) SetCallerIO

func (WarmTransferBackendFuncs) StartHold

type WarmTransferConsultation

type WarmTransferConsultation interface {
	RoomName() string
	Session() WarmTransferSession
	Disconnected() <-chan error
	Close(context.Context) error
}

WarmTransferConsultation owns the private human-agent room and its session. Disconnected must return a stable, close-only/read-only channel; a nil value is rejected so room failures cannot be silently missed.

type WarmTransferDialRequest

type WarmTransferDialRequest struct {
	CallerRoomName     string
	CallerIdentity     string
	HumanRoomName      string
	HumanIdentity      string
	SIPCallTo          string
	SIPTrunkID         string
	SIPConnection      *livekit.SIPOutboundConfig
	SIPNumber          string
	SIPHeaders         map[string]string
	DTMF               *string
	RingingTimeout     *time.Duration
	Instructions       llm.Instructions
	ChatContext        *llm.ChatContext
	Tools              *llm.Context
	AllowInterruptions *bool
	STT                agents.Override[stt.STT]
	VAD                agents.Override[vad.VAD]
	LLM                agents.Override[llm.LLM]
	TTS                agents.Override[tts.TTS]
	TurnHandling       *voice.TurnHandlingOptions
}

func (WarmTransferDialRequest) Clone

type WarmTransferHold

type WarmTransferHold interface {
	Stop(context.Context) error
}

WarmTransferHold is owned by the backend and stopped exactly once.

type WarmTransferHoldAudio

type WarmTransferHoldAudio struct {
	Source string
	Volume float64
}

type WarmTransferIOState

type WarmTransferIOState struct {
	AudioInput          bool
	AudioOutput         bool
	TranscriptionOutput bool
}

type WarmTransferInstructionConfig

type WarmTransferInstructionConfig struct {
	Full  *string
	Parts *InstructionParts
}

WarmTransferInstructionConfig models the string | InstructionParts union. Full replaces the prompt; Parts retains the template. Both nil selects the built-in prompt.

func FullWarmTransferInstructions

func FullWarmTransferInstructions(value string) WarmTransferInstructionConfig

func PartialWarmTransferInstructions

func PartialWarmTransferInstructions(value InstructionParts) WarmTransferInstructionConfig

type WarmTransferParticipantEvent

type WarmTransferParticipantEvent struct {
	Identity string
	Kind     livekit.ParticipantInfo_Kind
}

type WarmTransferPostMergeBackend

type WarmTransferPostMergeBackend interface {
	DeleteCallerRoomOnDisconnect(context.Context, string) error
}

WarmTransferPostMergeBackend optionally installs the caller-room cleanup listener after a successful merge. Ownership moves to the backend because the foreground task is about to return.

type WarmTransferResult

type WarmTransferResult struct {
	HumanAgentIdentity string `json:"humanAgentIdentity"`
}

type WarmTransferSession

type WarmTransferSession interface {
	Say(context.Context, string, voice.SayOptions) (*voice.SpeechHandle, error)
	GenerateReply(context.Context, voice.GenerateReplyOptions) (*voice.SpeechHandle, error)
	Interrupt(context.Context, bool) error
	Close(context.Context, ...voice.CloseOptions) error
}

WarmTransferSession is the consultation surface used by the workflow. Every *voice.AgentSession[T] satisfies it.

type WarmTransferSpeech

type WarmTransferSpeech struct {
	Text  *string
	Start func(context.Context, WarmTransferSession) (*voice.SpeechHandle, error)
}

WarmTransferSpeech is exact text or a callback that starts speech in the consultation session. Its zero value means no speech.

func TextSpeech

func TextSpeech(text string) WarmTransferSpeech

type WarmTransferTask

type WarmTransferTask[UserData any] struct {
	// contains filtered or unexported fields
}

func CreateWarmTransferTask

func CreateWarmTransferTask[UserData any](options WarmTransferTaskOptions[UserData]) (*WarmTransferTask[UserData], error)

CreateWarmTransferTask is the functional constructor name used by agents-js. Go returns validation errors instead of throwing.

func MustWarmTransferTask

func MustWarmTransferTask[UserData any](options WarmTransferTaskOptions[UserData]) *WarmTransferTask[UserData]

func NewWarmTransferTask

func NewWarmTransferTask[UserData any](options WarmTransferTaskOptions[UserData]) (*WarmTransferTask[UserData], error)

func (*WarmTransferTask[UserData]) Instructions

func (t *WarmTransferTask[UserData]) Instructions() llm.Instructions

func (*WarmTransferTask[UserData]) Run

func (t *WarmTransferTask[UserData]) Run(ctx context.Context) (result WarmTransferResult, runErr error)

func (*WarmTransferTask[UserData]) ToolContext

func (t *WarmTransferTask[UserData]) ToolContext() *llm.Context

func (*WarmTransferTask[UserData]) VoiceTask

func (t *WarmTransferTask[UserData]) VoiceTask() *voice.AgentTask[WarmTransferResult, UserData]

func (*WarmTransferTask[UserData]) WaitReady

func (t *WarmTransferTask[UserData]) WaitReady(ctx context.Context) error

WaitReady waits until the outbound call has answered and the consultation tools may be invoked.

type WarmTransferTaskOptions

type WarmTransferTaskOptions[UserData any] struct {
	AbortContext context.Context
	Backend      WarmTransferBackend

	SIPCallTo      string
	SIPTrunkID     agents.Override[string]
	SIPConnection  *livekit.SIPOutboundConfig
	SIPNumber      string
	SIPHeaders     map[string]string
	DTMF           *string
	RingingTimeout *time.Duration
	RoomName       *string

	// Zero inherits the agents-js default hold music at volume 0.8. Use
	// agents.Disable[WarmTransferHoldAudio]() for holdAudio: null.
	HoldAudio agents.Override[WarmTransferHoldAudio]

	GreetingSpeech          WarmTransferSpeech
	CallerHangupSpeech      WarmTransferSpeech
	CallerHangupInstruction *string // Deprecated: prefer CallerHangupSpeech.
	Instructions            WarmTransferInstructionConfig
	ChatCtx                 *llm.ChatContext
	Tools                   *llm.Context
	STT                     agents.Override[stt.STT]
	VAD                     agents.Override[vad.VAD]
	LLM                     agents.Override[llm.LLM]
	TTS                     agents.Override[tts.TTS]
	TurnHandling            *voice.TurnHandlingOptions
	AllowInterruptions      *bool

	CallerHangupNoticeTimeout  time.Duration
	CallerHangupCleanupTimeout time.Duration
	CleanupTimeout             time.Duration
	MergeTimeout               time.Duration
	DialDrainTimeout           time.Duration
	OnError                    func(error)
}

Directories

Path Synopsis
Package livekit provides the optional server-sdk-go/RoomIO backend for the stable warm-transfer workflow.
Package livekit provides the optional server-sdk-go/RoomIO backend for the stable warm-transfer workflow.

Jump to

Keyboard shortcuts

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