Behaviour for a voice agent, in the spirit of GenServer/Phoenix.LiveView:
use Guava.Agent, give it a persona, and implement only the callbacks you need.
Each call gets its own process; your callbacks thread a per-call state
value (like a LiveView socket's assigns) and return standard tuples. Use the
Guava.Call handle passed to each callback to drive the conversation
(set_task, transfer, get_field, …).
Example
defmodule MyAgent do
use Guava.Agent, name: "Nova", organization: "Acme", purpose: "Answer questions."
@impl true
def init(_call_info), do: {:ok, %{}}
@impl true
def handle_question(_call, question, state), do: {:reply, MyKB.answer(question), state}
@impl true
def handle_action("sales", call, state) do
Guava.Call.transfer(call, "+14155550100")
{:noreply, state}
end
endAttach it to a channel with Guava.Channel (see its docs) or Guava.run/1.
Callbacks
All callbacks are optional; a persona-only agent is valid. Callbacks that
produce a reply to the Dialog System return {:reply, value, state}; the rest
return {:noreply, state}.
init(call_info)→{:ok, state}— build per-call state (default%{})agent_info(call_info)→ keyword persona (defaults to theuseoptions)handle_call_received(call_info)→:accept|:decline(default:accept)handle_start(call, state)handle_caller_speech(call, event, state)/handle_agent_speech(call, event, state)handle_question(call, question, state)→{:reply, answer, state}handle_action_request(call, request, state)→{:reply, suggestion, state}where suggestion is aGuava.SuggestedAction, a list of them, ornilhandle_action(action_key, call, state)— one callback; pattern-match the keyhandle_task_complete(task_id, call, state)— one callback; pattern-match the id (areach_person/3task completes ashandle_task_complete("reach_person", …))handle_search_query(field_key, call, query, state)→{:reply, {matched, other}, state}handle_dtmf(call, event, state)/handle_escalate(call, state)handle_outbound_failed(call, event, state)/handle_session_end(call, event, state)handle_info(msg, call, state)— external mid-call messages (e.g. results of a spawned Task)terminate(reason, call, state)
Summary
Types
@type call() :: Guava.Call.t()
@type state() :: term()
Callbacks
@callback agent_info(Guava.CallInfo.t()) :: keyword()
@callback handle_action_request(call(), String.t(), state()) :: {:reply, Guava.SuggestedAction.t() | [Guava.SuggestedAction.t()] | nil, state()}
@callback handle_agent_speech(call(), Guava.Events.AgentSpeech.t(), state()) :: {:noreply, state()}
@callback handle_call_received(Guava.CallInfo.t()) :: :accept | :decline
@callback handle_caller_speech(call(), Guava.Events.CallerSpeech.t(), state()) :: {:noreply, state()}
@callback handle_dtmf(call(), Guava.Events.DTMFPressed.t(), state()) :: {:noreply, state()}
@callback handle_outbound_failed(call(), Guava.Events.OutboundCallFailed.t(), state()) :: {:noreply, state()}
@callback handle_session_end(call(), Guava.Events.BotSessionEnded.t(), state()) :: {:noreply, state()}
@callback init(Guava.CallInfo.t()) :: {:ok, state()}