Skip to content

v0.36.0

Latest

Choose a tag to compare

@griffin-goguava-ai griffin-goguava-ai released this 30 Jul 02:04

Syncs the Elixir port to Python guava-sdk 0.36.0.

Most of this release is reliability work found by repeatedly auditing the port against
the Python SDK with no version baseline. Every fix carries a regression test confirmed
to fail when that fix alone is reverted.

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.

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.

New public API

  • 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

Highlights — see CHANGELOG.md for the full list.

  • Multiple Guava.Channel children in one supervisor collided on child id, so the documented multi-channel example could not boot.
  • Completed calls were restarted, and a supervised outbound channel re-dialled the callee indefinitely.
  • Sockets: the reconnect budget never escalated or reported failure; a silently half-open connection went unnoticed for ~15 minutes; the opening handshake had no overall deadline, so a stalling peer could wedge a socket and with it Guava.drain/1; a socket could outlive its owner, leaking a server-side connection per call.
  • Handlers that exited, threw, returned an unexpected shape, or returned 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.
  • A failed CLI OAuth refresh produced an empty bearer token and re-issued the failing request on every subsequent call.

Wire protocol

  • No changes. All 87 wire fixtures regenerate byte-identically from upstream 0.36.0's own pydantic models, and the port emits and matches all 38 command_type/event_type discriminators with none extra.

Housekeeping

  • CI added (GitHub Actions): a test matrix over Elixir 1.15/1.17/1.18 — which validates the ~> 1.15 floor mix.exs claims — plus format, credo and a docs build that fails on warnings.
  • CHANGELOG.md added. PARITY.md records the deliberate deviations, including several where upstream's behaviour was rejected on the merits rather than copied. See PARITY.md.

Install:

{:guava, "~> 0.36"}