Skip to content

feat(sdk): align with @deepgram/sdk 5.9 - #71

Merged
GregHolmes merged 3 commits into
mainfrom
gh/update-agents-sdk-5.9
Sep 3, 2026
Merged

feat(sdk): align with @deepgram/sdk 5.9#71
GregHolmes merged 3 commits into
mainfrom
gh/update-agents-sdk-5.9

Conversation

@GregHolmes

Copy link
Copy Markdown
Contributor

Summary

  • Upgrade @deepgram/agents from @deepgram/sdk 5.1.0 to 5.9.0.
  • Preserve SDK 5.9 WebSocket ordering while normalizing binary Blob messages to the documented ArrayBuffer audio event.
  • Fix the immediate-Welcome race, make Agents the sole reconnect owner, replay runtime settings before buffered audio, and preserve inline conversation/function-call context.
  • Add current listen, latency, history, injection, and function-response types/events.
  • Pin TypeScript 5.9.3 to match API Extractor and correct stale VAD/configuration documentation.

Compatibility

Validation

  • bun install --frozen-lockfile
  • bun run typecheck
  • bun run build
  • bun run test: 112 Agents tests and 29 Widget tests pass
  • Live production smoke on commit d08b6df: Welcome and Settings applied, one conversation message, 190 ordered audio frames / 182,400 bytes
  • Packed-stack checks: React, UI, and Widget typecheck/build/tests pass
  • Application checks: Voice Heist build passes; Voice-enabled Browser typecheck/build plus 27 tests pass; Restaurants typecheck plus 68 tests pass when Agents and direct SDK are upgraded together

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this PR does. Upgrades @deepgram/agents from @deepgram/sdk 5.1.0 to 5.9.0 and rewrites the session lifecycle around SDK 5.9's runtime behavior: binary audio now arrives from the SDK as Blob, and this library converts it to the documented ArrayBuffer through one ordered queue so a later message can never overtake an earlier audio frame. The SDK's transport reconnect is disabled and AgentSession owns reconnection, refreshing auth, replaying runtime setting updates, and restoring inline conversation context before buffered audio resumes.

What I checked.

  • Frame ordering under slow Blob conversion: the serialized drain queue plus the new tests cover the failure mode where AgentAudioDone overtakes the final audio chunk. Verified against the test suite, not just the PR description.
  • Full gate in a clean container (oven/bun:1.3.13, CI order: install → build → typecheck → test): all pass, 112 Agents + 29 Widget tests, matching the PR body's counts.
  • SDK 5.9 types: Welcome carries request_id (getId() returned null before this PR because the code read session_id, which the server never sent); the injectAgentMessage behaviors default/queue/interrupt match the SDK's Behavior consts exactly.
  • All three README config examples compile against the built package with zero errors, including the listen provider with version 'v1' + nova-3.
  • Not re-run: the live production smoke and the restaurants-web / Voice Heist / browser-app checks are author-attested.

One should-fix before or shortly after merge. Every updatePrompt/updateListen/updateSpeak/updateThink call is appended to runtimeUpdates (agent-session.ts:474) and the array is cleared only by a fresh connect(). An app that updates its prompt every conversation turn holds every update in memory for the session's life and replays the entire history — hundreds of stale prompts — over the new socket before queued audio flushes on reconnect. Since each update type fully replaces its target server-side, compacting to the latest update per type (preserving the relative order of the survivors) caps both memory and the replay burst at four messages.

Nits.

  • types/config.ts:48 — "Max consecutive attempts before SettingsApplied resets the counter" reads as if SettingsApplied triggers the give-up; suggest: "Max consecutive failed attempts before giving up. The counter resets once a connection reaches SettingsApplied."
  • agent-session.ts:160 — a synchronous send failure wipes the incoming-message queue, discarding server messages still waiting behind an in-flight Blob conversion, while the close path deliberately drains them first; the two failure paths could share the drain-first behavior.

Merge ordering. This supersedes #67 (close it once this lands) and overlaps #69's README edits (whichever lands second takes the conflict).

@GregHolmes

Copy link
Copy Markdown
Contributor Author

Addressed Corey’s review in 33d2480:

  • Compact reconnect replay state to the latest value per update type, preserving the relative order of the surviving updates.
  • Route synchronous media, keepalive, injection, function-response, and runtime-update write failures through the same drain-first failure queue.
  • Clarify reconnect attempt semantics and replay behavior in the docs.
  • Add regressions for update compaction and in-flight Blob ordering during synchronous send failure.

Local gate passes: 114 Agents tests, 29 Widget tests, both typechecks and production builds.

Merge ordering remains: merge #71 first, then close #67 as superseded and rebase #69 onto main.

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 33d2480 against the approved base d08b6df. All three earlier findings are resolved:

  • Replay history: each runtime setting type now keeps only its latest value, so a reconnect sends at most four update messages in last-set order. Traced the ordering and the new test asserts it.
  • maxAttempts doc-comment: now states it is consecutive failed attempts before giving up, with the counter resetting at SettingsApplied.
  • Synchronous send failure: every sync write (media, keepalive, inject, function response, runtime update) now goes through one wrapper that queues the failure behind any in-flight Blob conversion, so the frame being converted is still delivered before teardown. New test covers audio → sdk-error → reconnecting. Side benefit: SDK 5.9 send methods throw "Socket is not open." synchronously, and the keepalive timer previously had no catch around that call.

Gate in oven/bun:1.3.13: frozen install, build, typecheck, test — 114 Agents + 29 Widget pass. CI green. Release-please config confirms a feat commit yields 0.1.2.

Two small fixes before merge so the follow-up is complete on its own terms:

  1. packages/sdk/src/agent-session.ts:610-619 — the audio flush inside the SettingsApplied handler is the one write path still calling _handleSocketFailure directly. Every other synchronous write now goes through _writeToSocket, so a flush failure here is the only case that still discards server messages already queued behind SettingsApplied instead of dispatching them first. Wrap socket.sendMedia(this.audioQueue[index]) in _writeToSocket, and on false do this.audioQueue = this.audioQueue.slice(index); return;.

  2. packages/sdk/README.md:152 — the replay sentence parses as if "after SettingsApplied" modifies "updated". Suggested replacement:

    After SettingsApplied, the latest value of each runtime setting (prompt, listen, speak, think) is replayed, ordered by when each setting was last updated, before audio queued during reconnect is flushed.

Merge ordering as you stated: #71 first, close #67 as superseded, rebase #69.

@GregHolmes

Copy link
Copy Markdown
Contributor Author

Addressed the re-review in 7f76952:

  • The SettingsApplied audio flush now uses _writeToSocket; a failed frame remains queued and failure handling drains previously accepted inbound messages first.
  • The initial sendSettings write now uses the same wrapper as well, removing the last unguarded protocol write.
  • Replaced the reconnect replay sentence with the suggested unambiguous wording.
  • Added a delayed-Blob + SettingsApplied flush-failure regression proving audio → warning → sdk-error → reconnecting order.

Package gate passes with 115 Agents tests.

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 7f76952 against 33d2480. Both requested fixes are in and I'm approving.

What changed. The audio flush inside the SettingsApplied handler now goes through _writeToSocket, so a failed flush queues the failure behind server messages already received instead of discarding them, and the unsent frames stay in audioQueue for the next connection. The README replay sentence is replaced with the suggested wording. The initial sendSettings on Welcome is also wrapped now; before that, a throw there escaped the drain loop as an unhandled rejection with no teardown, so that is a real improvement.

What I checked.

  • Traced the new test by hand: pending Blob, then SettingsApplied, then a Warning, then sendMedia throws. The code emits audio, warning, sdk-error, reconnecting in that order, matching the assertion, and the failed frame is retained.
  • The failure queued from inside the handler cannot deadlock the drain: the nested drain call returns immediately and the outer loop handles the failure item next iteration.
  • Gate in oven/bun:1.3.13: frozen install, build, typecheck, test. 115 Agents + 29 Widget pass, 0 fail. CI green on 7f76952, branch current with main.

One follow-up, not a merge hold. packages/sdk/src/agent-session.ts:596-600: the new sendSettings failure path has no test. A case that makes mockSocket.sendSettings throw and asserts sdk-error then reconnecting with no welcome event would close it.

Merge ordering as you stated: #71 first, close #67 as superseded, rebase #69.

@GregHolmes
GregHolmes merged commit 5a63c41 into main Sep 3, 2026
2 checks passed
@GregHolmes
GregHolmes deleted the gh/update-agents-sdk-5.9 branch September 3, 2026 12:35
GregHolmes added a commit that referenced this pull request Sep 4, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.2](agents-v0.1.1...agents-v0.1.2)
(2026-09-03)


### Features

* **sdk:** upgrade the underlying Agent transport from `@deepgram/sdk`
5.1 to 5.9 and align settings, binary-message, and request-ID handling
with the current Agent v1 socket
([#71](#71))
([5a63c41](5a63c41))
* **sdk:** expose `updateListen`, injection behavior,
conversation-history clearing, and typed `ListenUpdated`,
`LatencyReport`, `History`, and `FunctionCallResponse` events
([d08b6df](d08b6df))


### Bug Fixes

* **sdk:** serialize Blob audio, JSON messages, and synchronous socket
failures so accepted messages are emitted in wire order before reconnect
teardown
([7f76952](7f76952))
* **sdk:** refresh credentials on each reconnect attempt, restore inline
conversation and completed function-call context, and retain queued
audio until the replacement connection receives `SettingsApplied`
([d08b6df](d08b6df))
* **sdk:** compact reconnect replay to the latest prompt, listen, speak,
and think updates in last-set order, and reset the consecutive-attempt
counter only after `SettingsApplied`
([33d2480](33d2480))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
GregHolmes added a commit that referenced this pull request Sep 4, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.8](agents-widget-v0.1.7...agents-widget-v0.1.8)
(2026-09-04)


### Features

* **widget:** ship the `@deepgram/agents` 0.1.2 runtime in the
self-contained ESM and UMD bundles, updating the underlying Agent
transport from `@deepgram/sdk` 5.1 to 5.9
([#71](#71))
([5a63c41](5a63c41))


### Bug Fixes

* **widget:** refresh credentials on reconnect, retain queued audio
until `SettingsApplied`, and restore inline conversation and completed
function-call context
([d08b6df](d08b6df))
* **widget:** replay only the latest prompt, listen, speak, and think
updates after reconnect, in the order each setting was last changed
([33d2480](33d2480))
* **widget:** preserve wire order across Blob audio, JSON messages, and
synchronous socket failures so accepted audio is delivered before
reconnect teardown
([7f76952](7f76952))
* **widget:** require `@deepgram/agents` 0.1.2 for matching public types
and correct the OpenAI model placement in the ESM, UMD, and API examples
([f114af8](f114af8))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants