@polyweave/deepgram (1.0.9)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/deepgram@1.0.9"@polyweave/deepgram": "1.0.9"About this package
@polyweave/deepgram
Deepgram multi-modal adapter for the Polyweave platform. Supports Speech-to-Text (HTTP batch and WebSocket streaming) and Text-to-Speech (HTTP REST and WebSocket streaming) via Polyweave frame protocol.
Published as @polyweave/deepgram.
Synopsis
import { createDeepgramAdapter } from '@polyweave/deepgram';
const adapter = createDeepgramAdapter({
apiKey: process.env.DEEPGRAM_API_KEY,
timeout: 30000
});
// STT: send AUDIO frames, receive TEXT frames
adapter.source.pipe(mySink);
adapter.sink.write({
type: 'AUDIO',
streamId: 'stt-1',
content: { data: audioBuffer, encoding: 'linear16', sampleRate: 16000 }
});
// TTS: send TEXT frames, receive AUDIO frames
adapter.sink.write({
type: 'PARAM',
content: { key: 'task', value: 'tts' }
});
adapter.sink.write({
type: 'TEXT',
streamId: 'tts-1',
content: { text: 'Hello, world!' }
});
Install
npm install @polyweave/deepgram
Why
Speech is the highest-bandwidth human–AI channel — and latency kills immersion. This adapter provides realtime streaming STT via Deepgram's WebSocket API with interim_results for sub-300ms Time-To-First-Partial, plus streaming TTS via WebSocket for incremental audio output. Both streaming and batch (HTTP) modes are available, with TTS supporting 12 Aura English voices. All modes emit Polyweave RECEIPT frames for cost tracking.
API
createDeepgramAdapter(config)
Creates a Deepgram adapter as a Polyweave frame duplex { source, sink }. Frames are routed to STT or TTS handlers based on frame type and the task parameter.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
config.apiKey |
string |
No | process.env.DEEPGRAM_API_KEY |
Deepgram API key. Can also be set after creation via PARAM { key: 'apiKey' } frame or adapter.setReady(key). |
config.timeout |
number |
No | 30000 |
Request timeout in milliseconds. |
config.name |
string |
No | null |
Human-readable name exposed on adapter.name. |
Returns: IFrameDuplex { source, sink, setReady, ready, apiKey, name }
Additional properties on the returned duplex:
| Property | Type | Description |
|---|---|---|
setReady(key) |
function |
Set the API key post-creation. Processes any buffered frames. |
ready |
boolean (getter) |
Whether the adapter has an API key and is accepting frames. |
apiKey |
string (getter) |
The current API key (or null). |
name |
string | null |
Adapter name from config. |
PARAM keys recognized by the sink:
| Key | Default | Description |
|---|---|---|
apiKey |
— | Triggers setReady(). |
model |
"nova-3" |
STT model. |
language |
"en" |
ISO 639-1 language code. |
punctuate |
true |
Add punctuation to transcripts. |
smart_format |
true |
Smart formatting (dates, numbers, etc.). |
diarize |
false |
Speaker diarization. |
diarize_version |
undefined |
Diarization model version. |
multichannel |
false |
Multi-channel audio input. |
alternatives |
1 |
Number of transcription alternatives. |
numerals |
true |
Convert numerals to digits. |
profanity_filter |
false |
Filter profanity. |
redact |
undefined |
Array of redaction types ("pci", "numbers", "ssn"). |
replace |
undefined |
Find-and-replace term mappings. |
search |
undefined |
Search for specific terms. |
keywords |
undefined |
Array of keywords to boost. |
filler_words |
false |
Include filler words in transcript. |
paragraphs |
false |
Paragraph segmentation. |
utterances |
false |
Utterance segmentation. |
utt_split |
0.8 |
Utterance split threshold in seconds. |
interim_results |
true |
Stream interim (partial) results for low-latency STT. |
endpointing |
300 |
Milliseconds of silence before finalizing an utterance. |
vad_events |
false |
Emit voice activity detection events. |
encoding |
"linear16" |
Audio encoding: linear16, flac, mulaw, opus, etc. |
sample_rate |
16000 |
Audio sample rate in Hz. |
channels |
1 |
Number of audio channels. |
tts_model |
"aura-asteria-en" |
TTS voice model. |
streaming_stt |
true |
Use WebSocket streaming STT. Set false for HTTP batch. |
streaming_tts |
false |
Use WebSocket streaming TTS. |
task |
undefined |
Routes frames: "tts" / "t2a" / "text_to_speech" for TTS; default is TTS (TEXT frames always route to TTS, AUDIO frames always route to STT regardless of task). |
receipt_mode |
"final" |
When receipts are emitted. |
receipt_interval |
50 |
Token/chunk interval for progressive receipts. |
Frame protocol:
| Input frame type | Action |
|---|---|
TEXT |
Routes to TTS handler. Emits AUDIO (audio buffer) → RECEIPT → END. |
AUDIO |
Routes to realtime STT (WebSocket, if streaming_stt is true) or HTTP batch STT. Emits TEXT (transcript, possibly multiple for interim results) → RECEIPT → END. |
PARAM |
Accumulates configuration. key: "apiKey" triggers setReady(). |
START |
Ignored (passthrough). |
END |
For streaming STT: signals session close. |
TOPOLOGY_SCAN |
Responds with TOPOLOGY_REPORT containing adapter metadata and state. |
TEST_INJECT |
Injects frame arrays for testing. |
TEST_SNAPSHOT |
Returns adapter paused state for testing. |
Output frame types emitted:
| Frame type | Content |
|---|---|
TEXT |
Transcript text. Metadata includes partial (boolean), committed, streaming, speechFinal, confidence, words, ttft (time-to-first-text in ms). |
AUDIO |
TTS audio buffer. Metadata includes format (mp3, pcm, opus, flac, aac, mulaw), mimeType, sampleRate, ttfb (time-to-first-byte), streaming, chunkIndex, ttfa (time-to-first-audio). |
RECEIPT |
Cost information: inputCost, outputCost, totalCost, audioSeconds, characters, audioChunksSent. |
ERROR |
Maps Deepgram errors to ErrorCode values (see error mapping below). Always followed by an END frame with metadata.error: true. |
END |
Marks stream completion. Metadata includes timing and audio statistics. |
TOPOLOGY_REPORT / TEST_SNAPSHOT |
Protocol frames for topology scanning and testing. |
Error mapping (from utils/errorMapper.js):
| Error pattern | Mapped ErrorCode | Retryable |
|---|---|---|
401 / Unauthorized / Invalid API key |
AUTHENTICATION_ERROR |
No |
402 / Payment Required / quota |
QUOTA_EXCEEDED |
No |
429 / rate limit / Too Many Requests |
RATE_LIMIT_EXCEEDED |
Yes |
400 / Bad Request / Invalid |
INVALID_INPUT |
No |
500 / 503 / Server Error |
PROVIDER_ERROR |
Yes |
timeout / ETIMEDOUT / ECONNRESET |
QUEUE_TIMEOUT |
Yes |
WebSocket / connection |
PROTOCOL_ERROR |
Yes |
| All other errors | PROVIDER_ERROR |
No |
Runtime errors (thrown synchronously by routeFrame):
| Frame type | Error |
|---|---|
| Unsupported frame type (not TEXT, AUDIO, or END) | "Unsupported frame type: {type}. Supported types: TEXT, AUDIO" |
This throw is caught by the sink.write try/catch and converted to an ERROR + END frame pair.
Ready-state buffering:
If no apiKey is provided at creation time, all incoming frames are buffered until a PARAM { key: 'apiKey', value: '...' } frame or setReady(key) call provides the key. Buffered frames are then replayed through the sink.
Cleanup on end:
duplex.sink.end() destroys all active HTTP requests and closes all WebSocket sessions (STT + TTS) before calling the original end handler.
handleTtsHttp(frame, duplex, params, sharedState) (exported from src/handlers/ttsHttp.js)
HTTP TTS handler. Sends text to POST https://api.deepgram.com/v1/speak, receives audio buffer, emits AUDIO + RECEIPT + END frames. Not part of the public API — used internally by routeFrame.
handleSttRealtime(frame, duplex, params, sharedState) (exported from src/handlers/sttRealtime.js)
WebSocket streaming STT handler. Creates persistent sessions per streamId. Opens a WebSocket to wss://api.deepgram.com/v1/listen, sends audio chunks as binary frames, receives Results JSON with interim/final transcripts. Emits TEXT frames for each result. Tracks TTFP (time-to-first-partial) and accumulated audio duration.
handleTtsWebSocket(frame, duplex, params, sharedState) (exported from src/handlers/ttsWebSocket.js)
WebSocket streaming TTS handler. Creates sessions per streamId. Opens a WebSocket to wss://api.deepgram.com/v1/speak, sends {"type":"Speak","text":"..."} JSON frames, receives binary audio chunks. Sends {"type":"Close"} to flush and close. Tracks TTFA (time-to-first-audio) and total characters sent.
AURA_VOICES (exported from src/handlers/ttsHttp.js)
Named map of supported Deepgram Aura English voices:
| Key | Description |
|---|---|
aura-asteria-en |
Asteria (English, Female) |
aura-luna-en |
Luna (English, Female) |
aura-stella-en |
Stella (English, Female) |
aura-athena-en |
Athena (English, Female) |
aura-hera-en |
Hera (English, Female) |
aura-orion-en |
Orion (English, Male) |
aura-arcas-en |
Arcas (English, Male) |
aura-perseus-en |
Perseus (English, Male) |
aura-angus-en |
Angus (English, Male) |
aura-orpheus-en |
Orpheus (English, Male) |
aura-helios-en |
Helios (English, Male) |
aura-zeus-en |
Zeus (English, Male) |
Cost functions (exported from src/costs.js)
getModelCost(model)
Returns the cost object for a given model name, or null if unknown.
| Model | Per-minute cost |
|---|---|
nova-2 |
$0.0043 |
nova |
$0.0059 |
enhanced |
$0.0145 |
base |
$0.0125 |
calculateCost(model, minutes)
Returns total cost: minutes * getModelCost(model).perMinute. Returns 0 if the model is unknown or has no perMinute property.
mapDeepgramError(error, frame) (exported from src/utils/errorMapper.js)
Maps a DeepgramError to a Polyweave error frame with the appropriate ErrorCode, retryable flag, and provider metadata.
Tests
npm test
Runs node --test test/deepgram.test.js test/rigor.test.js. Covering: adapter creation with and without API key, ready-state buffering, PARAM accumulation, STT and TTS frame routing, error mapping for all error patterns, cost calculation, topology scan, and test injection/snapshot frames.
Requirements
- Node.js >= 22.0.0
- ESM only
- Runtime dependencies:
@polyweave/push-websocket,ws(^8.19.0) - Peer dependencies:
@polyweave/core,@polyweave/errors— must be installed alongside. - Deepgram API key (set via
DEEPGRAM_API_KEYenv var, config option, or PARAM frame).
Caveats
- The default
streaming_sttistrue. Set it tofalsevia PARAM to use HTTP batch STT (higher latency, but works without persistent WebSocket connections). - The default
streaming_ttsisfalse. Set it totruevia PARAM to enable WebSocket TTS for lower time-to-first-audio at the cost of a persistent connection. - WebSocket sessions are created lazily on the first AUDIO (STT) or TEXT (TTS) frame. Audio/text sent before the WebSocket connects is queued and flushed on open.
- TTS pricing uses a hardcoded $0.015/1000 characters estimate. STT pricing uses a hardcoded $0.0043/minute (Nova-3) rate. Check
src/costs.jsfor the latest values. - HTTP TTS supports the following output encodings:
linear16(PCM),mp3,opus,flac,aac,mulaw. Unrecognized encodings default tomp3. - HTTP STT auto-detects audio format from magic bytes (RIFF/WAV, MP3, FLAC) if
encodingis not one of the recognized values.
Dependencies
Dependencies
| ID | Version |
|---|---|
| @polyweave/push-websocket | * |
| ws | ^8.19.0 |
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |
Peer Dependencies
| ID | Version |
|---|---|
| @polyweave/core | * |
| @polyweave/costs | * |
| @polyweave/errors | * |