Current section
Files
Jump to
Current section
Files
CHANGELOG.md
# Changelog
The package version mirrors the Python `guava-sdk` version this port is reconciled
to, so it may skip Python versions. See [PARITY.md](PARITY.md) for the deviations
that are deliberate.
## 0.36.0
Tracks Python `guava-sdk` 0.36.0.
### Breaking
- **Campaigns are identified by code, not id.** `%Guava.Campaign{}` carries `:code`
and `:name`; `:id` remains only for the endpoints still keyed on it and is
documented as internal. No `Guava.Campaigns` function takes an id — pass a code or
a `%Guava.Campaign{}`. The campaign `update` function is gone, having been deleted
upstream. Single-field results are unwrapped: `upload_contacts` returns a count and
`status` a counts map.
- **`Guava.Usage` is removed** and `config :guava, usage_telemetry:` is now an ignored
key. The uploader was a faithful port but nothing ever fed it, so enabling it
uploaded nothing. The SDK's `:telemetry` spans are unaffected. See PARITY.md for why
the feed was not ported.
### Changed — may affect a working deployment
- **HTTP redirects are no longer followed.** A 3xx now raises `%Guava.Error{type:
:http}` carrying the status, matching `httpx`, which defaults to
`follow_redirects=False`. Req had been following up to 10 redirects and rewriting
POST to GET for 301–303, dropping the JSON body — so a redirected `send_sms!/4`
could return `:ok` for a message that was never sent. If your base URL is fronted
by something that redirects API paths, point it at the final URL.
- **The per-attempt HTTP timeout is 5s, connect and receive alike**, matching
`httpx`'s `Timeout(5.0)`. It was Req's 15s receive default with connect left on
Mint's 30s. Retries are unchanged, so a hung host now costs ~27s across four
attempts rather than ~127s. RAG and LLM calls keep their own longer budgets.
### Added
- **Graceful shutdown.** `Guava.drain/1` closes listener sockets and waits out
in-flight calls, wired to the application's `prep_stop` callback so a `SIGTERM` during a rolling
deploy no longer drops live calls.
- **`Guava.ready?/0`** for a readiness probe you mount yourself; the SDK does not
serve HTTP. It reflects intake channels only, so placing an outbound call cannot
make a node report unready.
### Fixed
Reliability work driven by repeated absolute-parity audits against the Python SDK.
Each fix has a regression test confirmed to fail when that fix alone is reverted.
- Multiple `Guava.Channel` children in one supervisor collided on child id, so the
documented multi-channel example could not boot. Ids are now derived from the mode.
- `Guava.run([])` hung forever instead of returning.
- Call runtimes and finished outbound channels were `:permanent`, so completed calls
were restarted and a supervised outbound channel re-dialled the callee indefinitely.
- Sockets: the failure counter reset on WebSocket upgrade rather than on open-ack, so
backoff never escalated and `reconnection-failed` was never reported; a failed
connect was counted twice; open-ack timers were orphaned; `conn_ready` survived a
monitored drop, letting a command precede the handshake.
- A silently half-open connection went unnoticed for ~15 minutes; a keepalive is now
answered for or the connection is replaced.
- The opening handshake had no overall deadline, so a peer trickling upgrade bytes
could wedge a socket indefinitely — and with it `Guava.drain/1`.
- A socket outlived its owner, and a transport could outlive its socket, leaking a
process and a server-side connection per call.
- A stray `open-ack` mid-session re-ran the handshake, retransmitting buffered
messages and silently clearing the reconnect budget.
- Auth headers are recomputed per connection attempt, so a token that expires
mid-call can still reconnect.
- A CLI OAuth refresh that failed produced an empty bearer token and re-issued the
failing request on every subsequent call; it now raises with the real status.
- Handlers: exiting, throwing, returning an unexpected shape, or returning a value
the wire cannot carry all killed the call; each now logs and answers with the
fallback. Expert-error wording matches upstream exactly, since the model reads it.
- Handler commands were cast to the runtime's own mailbox, inverting wire order and
dropping anything queued at session end.
- A raising `handle_call_received/1` took the listener down; a dead socket left a
channel reporting ready; a slow agent `init/1` stalled other ringing calls.
- Outbound variables are validated before dialling. A searchable field with no
handler reports an expert error rather than "no matches".
- `handle_session_end/3` is reachable under `Guava.Testing`, and a crashing agent
under test no longer takes the test process down.
- An unparseable `Retry-After` no longer masks the real HTTP status.