feat(sdk): align with @deepgram/sdk 5.9 - #71
Conversation
dg-coreylweathers
left a comment
There was a problem hiding this comment.
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).
|
Addressed Corey’s review in
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 |
dg-coreylweathers
left a comment
There was a problem hiding this comment.
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.
maxAttemptsdoc-comment: now states it is consecutive failed attempts before giving up, with the counter resetting atSettingsApplied.- 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:
-
packages/sdk/src/agent-session.ts:610-619— the audio flush inside theSettingsAppliedhandler is the one write path still calling_handleSocketFailuredirectly. Every other synchronous write now goes through_writeToSocket, so a flush failure here is the only case that still discards server messages already queued behindSettingsAppliedinstead of dispatching them first. Wrapsocket.sendMedia(this.audioQueue[index])in_writeToSocket, and onfalsedothis.audioQueue = this.audioQueue.slice(index); return;. -
packages/sdk/README.md:152— the replay sentence parses as if "afterSettingsApplied" 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.
|
Addressed the re-review in
Package gate passes with 115 Agents tests. |
dg-coreylweathers
left a comment
There was a problem hiding this comment.
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 aWarning, thensendMediathrows. The code emitsaudio,warning,sdk-error,reconnectingin 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.
🤖 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).
🤖 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).
Summary
@deepgram/agentsfrom@deepgram/sdk5.1.0 to 5.9.0.Blobmessages to the documentedArrayBufferaudio event.Compatibility
@deepgram/sdk5.1 and exchange SDK-derived types with Agents must upgrade both together.restaurants-webwas verified successfully with both packages on SDK 5.9; its exact 0.1.1 pin prevents an accidental update.Validation
bun install --frozen-lockfilebun run typecheckbun run buildbun run test: 112 Agents tests and 29 Widget tests passd08b6df: Welcome and Settings applied, one conversation message, 190 ordered audio frames / 182,400 bytes