Skip to content

feat: add pluggable transport interface for sagemaker support#492

Merged
GregHolmes merged 2 commits into
mainfrom
gh/pluggable-transport-sagemaker
Jun 1, 2026
Merged

feat: add pluggable transport interface for sagemaker support#492
GregHolmes merged 2 commits into
mainfrom
gh/pluggable-transport-sagemaker

Conversation

@GregHolmes

@GregHolmes GregHolmes commented May 1, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

Adds a pluggable streaming-transport interface so the JS SDK can route listen.v1, listen.v2, speak.v1, and agent.v1 connections through a custom transport instead of the default WebSocket. Also adds a reconnect parity flag for clean handoff of retry responsibility to custom transports.

This is the JS half of the cross-SDK pluggable-transport work that's also landed in Python and Java for SageMaker support.

What's new

  1. DeepgramTransport / DeepgramTransportFactory interface (src/transport.ts)

    • Hand-maintained type surface that custom transports implement
    • Same factory(url, headers, request) shape as the Python/Java equivalents, with JS-specific request metadata as a third argument
  2. transportFactory option on DeepgramClient (wired in src/CustomClient.ts)

    • When set, listen.v1 / listen.v2 / speak.v1 / agent.v1 createConnection paths build a TransportWebSocketAdapter that exposes the SDK's expected ReconnectingWebSocket surface but delegates to the custom transport underneath
    • REST behaviour stays unchanged; only the streaming connection layer is pluggable
  3. reconnect flag with auto-disable (commit b82d30b)

    • New reconnect?: boolean option on DeepgramClient
    • Default is true (SDK manages reconnects, current behaviour)
    • When transportFactory is set, auto-disabled to false — the custom transport owns its retry/reconnect lifecycle; double-stacking the SDK's wrapper retries on top would cause storm-on-storm under burst load
    • Callers can still opt back in with explicit reconnect: true
    • Exposed read-only as client.reconnect

Context

  • This is the SDK seam that @deepgram/sagemaker (deepgram-js-sdk-transport-sagemaker) plugs into. That package's createSageMakerTransportFactory returns a DeepgramTransportFactory matching this interface.
  • The reconnect flag mirrors the same parity work in:
    • deepgram-java-sdk
    • deepgram-python-sdk #720
  • The JS half of this work has been validated end-to-end against three live SageMaker endpoints (Nova-3 STT, Flux, Aura TTS), including a 400-concurrent-connection burst against Nova-3 with mean WER 0.10% — matching Java's reference test.

Testing

  • pnpm build
  • pnpm vitest run tests/unit/transport-factory.test.ts — adapter-path unit coverage including reconnect-flag defaults, explicit reconnect: false, transportFactory auto-disable, and explicit reconnect: true override
  • pnpm vitest run tests/unit/custom-client.test.ts
  • End-to-end validation against live SageMaker endpoints (Nova-3 STT, Flux, Aura TTS); see the @deepgram/sagemaker package for the transport implementation those tests exercise

Types of changes

  • New feature (non-breaking change which adds functionality)

Release impact

  • feat: per commit message → minor version bump per release-please
  • Fully backwards-compatible — both transportFactory and reconnect are optional kwargs with sensible defaults; existing callers need no code changes
  • Hand-maintained files added to .fernignore so Fern regen doesn't overwrite them

Companion packages

This PR provides the SDK-side interface. The first consumer is:

  • @deepgram/sagemaker (repo: deepgram-js-sdk-transport-sagemaker) — SageMaker bidirectional HTTP/2 transport, validated end-to-end at 400 concurrent connections

Checklist

  • I have read the CONTRIBUTING doc
  • I have lint'ed all of my code using repo standards
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

@GregHolmes GregHolmes requested a review from lukeocodes as a code owner May 1, 2026 10:19
@GregHolmes GregHolmes self-assigned this May 1, 2026
@GregHolmes GregHolmes force-pushed the gh/pluggable-transport-sagemaker branch from 85b06a8 to b82d30b Compare May 26, 2026 09:58
@GregHolmes GregHolmes changed the title feat: add pluggable transport interface for SageMaker support feat: add pluggable transport interface for sagemaker support May 27, 2026
CustomDeepgramClientOptions now accepts a `reconnect?: boolean` that
controls whether the SDK retries streaming connections at the wrapper
level after a transport-side failure. Defaults to `true`. When a
`transportFactory` is supplied, `reconnect` is auto-set to `false` so
self-retrying transports (e.g. SageMaker) aren't double-stacked with
a second retry layer — wrapping a self-retrying transport caused
storm-on-storm behavior under burst load. Pass `reconnect: true` with
`transportFactory` to opt back into wrapper-level retries.

TransportWebSocketAdapter honors the flag by short-circuiting its
retry loop after the first attempt when reconnect is disabled, so
transport-side errors surface to the application instead of being
absorbed into another reconnect cycle.
@GregHolmes GregHolmes force-pushed the gh/pluggable-transport-sagemaker branch from b82d30b to 8dec8c9 Compare June 1, 2026 10:01
@GregHolmes GregHolmes merged commit 4d43b1b into main Jun 1, 2026
8 checks passed
@GregHolmes GregHolmes deleted the gh/pluggable-transport-sagemaker branch June 1, 2026 10:10
GregHolmes added a commit that referenced this pull request Jun 1, 2026
🤖 I have created a release *beep* *boop*
---


##
[5.4.0](v5.3.0...v5.4.0)
(2026-06-01)

Adds a pluggable streaming-transport layer (the JS side of the cross-SDK
SageMaker work) and fixes the TypeScript types exposed for the WebSocket
helper clients. Fully backwards-compatible — every new option is
optional with existing defaults, so current callers need no code
changes.

### Features

* **Pluggable transport interface for SageMaker support**
([#492](#492))
([4d43b1b](4d43b1b))

Adds a `DeepgramTransport` / `DeepgramTransportFactory` interface
(`src/transport.ts`) and a `transportFactory` option on
`DeepgramClient`. When set, the `listen.v1`, `listen.v2`, `speak.v1`,
and `agent.v1` `createConnection` paths route through a custom transport
via a `TransportWebSocketAdapter` instead of the default WebSocket; REST
behaviour is unchanged. This is the seam the `@deepgram/sagemaker`
package plugs into, validated end-to-end against live Nova-3 STT, Flux,
and Aura TTS endpoints (including a 400-concurrent-connection burst).
Mirrors the same work in the Python and Java SDKs.

* **`reconnect` flag with auto-disable for custom transports**
([8dec8c9](8dec8c9))

New optional `reconnect?: boolean` on `DeepgramClient` (default `true`,
exposed read-only as `client.reconnect`) controlling wrapper-level retry
of streaming connections. Auto-disabled to `false` when a
`transportFactory` is supplied, so self-retrying transports aren't
double-stacked with a second retry layer (which caused storm-on-storm
behaviour under burst load). Opt back in with an explicit `reconnect:
true`.

### Bug Fixes

* **Expose WebSocket helper types**
([#501](#501))
([ac71def](ac71def))
— thanks @asim48-ctrl

The `agent` / `listen` / `speak` getters were typed against the
generated client, which hid the wrapper's `createConnection()` method
and typed `Authorization` as required. They now expose typed WebSocket
wrapper clients, so `client.listen.v1.createConnection({ model: "nova-3"
})` type-checks and `Authorization` is optional. Runtime behaviour is
unchanged — this is a types-only fix. Fixes #489.

---
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 to deepgram/deepgram-python-sdk that referenced this pull request Jun 1, 2026
🤖 I have created a release *beep* *boop*
---


##
[7.3.0](v7.2.0...v7.3.0)
(2026-06-01)


### Features

* **client:** add a declarative `reconnect` flag with transport-factory
auto-disable. `DeepgramClient` / `AsyncDeepgramClient` now accept
`reconnect: bool = True` (exposed read-only as `client.reconnect`). When
a custom `transport_factory` is supplied, `reconnect` auto-sets to
`False` to signal that the transport owns its own retry/reconnect
lifecycle — e.g. the SageMaker transport's jittered backoff + replay
buffers — so SDK-level retries don't stack on top and cause
storm-on-storm under burst load. Pass `reconnect=True` explicitly to opt
back in. Declarative only for now (the Python SDK has no wrapper
reconnect layer; `websockets` doesn't auto-reconnect), fully
backwards-compatible, and parity with the same flag in the JS
([#492](deepgram/deepgram-js-sdk#492)) and
Java SDKs
([#720](#720))
([b5d5905](b5d5905))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Greg Holmes <greg.holmes@deepgram.com>
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