Guava (Guava v0.36.0)

Copy Markdown View Source

The Elixir SDK for the Guava voice-agent platform.

Two layers:

  • Guava.Client — account-level HTTP operations (phone numbers, SMS, outbound-call creation, campaigns).
  • Guava.Agent — a behaviour for handling live voice calls. Define an agent module, then attach it to a channel with Guava.Channel (supervised) or the blocking helpers here (listen_phone/3, call_phone/5, …) for scripts.

See the README and the guides under docs/.

Summary

Types

An E.164 formatted phone number, e.g. "+14155550123".

Functions

Serve an outbound campaign by code. Blocks.

Place an outbound call and handle it with agent. Blocks until the call ends.

Stop accepting new calls and wait for the calls in progress to finish.

Listen for inbound phone calls on agent_number. Blocks.

Listen for inbound SIP calls on sip_code. Blocks.

Listen for inbound WebRTC calls (creates a code when nil). Blocks.

Whether every channel on this node has started listening and none is draining.

Start one or more Guava.Channel child specs under a supervisor and block until they stop. For scripts/mix run; in an app, add the child specs to your own supervision tree instead.

Types

phone_number()

@type phone_number() :: String.t()

An E.164 formatted phone number, e.g. "+14155550123".

Functions

attach_campaign(agent, campaign_code, opts \\ [])

@spec attach_campaign(module(), String.t(), keyword()) :: :ok

Serve an outbound campaign by code. Blocks.

call_phone(agent, from_number, to_number, variables \\ %{}, opts \\ [])

@spec call_phone(module(), phone_number(), phone_number(), map(), keyword()) :: :ok

Place an outbound call and handle it with agent. Blocks until the call ends.

drain(opts \\ [])

@spec drain(keyword()) :: :ok | {:timeout, pos_integer()}

Stop accepting new calls and wait for the calls in progress to finish.

Every channel closes its listener socket, so the server stops assigning work to this node; calls already running are untouched, since each owns a separate socket. Returns :ok once the last call ends, or {:timeout, n} with the number still running when the budget ran out.

This runs automatically when the :guava application stops, so a SIGTERM during a rolling deploy no longer drops live calls. Call it yourself to drain early — from a Kubernetes preStop hook, say.

The budget defaults to config :guava, drain_timeout: 30_000 and can be overridden per call with :timeout. Keep it comfortably below your orchestrator's kill deadline (terminationGracePeriodSeconds on Kubernetes), which bounds the whole shutdown regardless.

listen_phone(agent, agent_number, opts \\ [])

@spec listen_phone(module(), phone_number(), keyword()) :: :ok

Listen for inbound phone calls on agent_number. Blocks.

listen_sip(agent, sip_code, opts \\ [])

@spec listen_sip(module(), String.t(), keyword()) :: :ok

Listen for inbound SIP calls on sip_code. Blocks.

listen_webrtc(agent, webrtc_code \\ nil, opts \\ [])

@spec listen_webrtc(module(), String.t() | nil, keyword()) :: :ok

Listen for inbound WebRTC calls (creates a code when nil). Blocks.

ready?()

@spec ready?() :: boolean()

Whether every channel on this node has started listening and none is draining.

Intended for a readiness probe — wire it into your own endpoint, e.g. a Plug returning 200 when this is true and 503 otherwise. The SDK doesn't serve HTTP itself; see the deployment guide.

This is a startup and rollout gate, not a liveness signal: it stays true across transient reconnects, which the socket layer handles with buffering, so a network blip doesn't pull the node out of rotation.

run(children)

@spec run(Supervisor.child_spec() | [Supervisor.child_spec()]) :: :ok

Start one or more Guava.Channel child specs under a supervisor and block until they stop. For scripts/mix run; in an app, add the child specs to your own supervision tree instead.

Guava.run({Guava.Channel, agent: MyAgent, listen: {:phone, "+14155550123"}})

This is for channels that run indefinitely — listeners and campaigns. It waits on the supervisor it creates, which stays up even after a finite channel has finished, so it does not return when an outbound: channel's call ends. Use call_phone/5 to place one outbound call and block until it finishes.