fast-carpenter-5678
02/13/2026, 12:38 AMtall-airline-16756
02/13/2026, 12:39 AMtall-airline-16756
02/13/2026, 12:39 AMAgentSession (hide any secret values).
6. Any relevant environment details: SDK language/version, LiveKit server version (if known), and whether this is local dev or production.
Quick checks you can run now while you gather that info:
• Confirm each API key works directly with the provider (e.g., call Deepgram/OpenAI/Spitch APIs with the same key).
• Ensure keys are passed in the exact field/name the integration expects (for plugin-based setup the provider docs show required fields). See the STT/TTS/LLM plugin guides: Deepgram STT, Azure STT, Spitch TTS, OpenAI LLM.
• Check for common issues: typos, extra whitespace, wrong environment (using test key in prod), or missing required fields (region, model name).
Once you paste the error and a short snippet of how you configure the AgentSession, I’ll walk through targeted steps to fix it. If you prefer, include which provider to start with and we’ll debug that one first.
Sources: Deepgram STT plugin guide | LiveKit Documentation | OpenAI LLM plugin guide | LiveKit Documentation | Spitch TTS plugin guide | LiveKit Documentation | Azure Speech STT plugin guide | LiveKit Documentationfast-carpenter-5678
02/13/2026, 12:40 AMtall-airline-16756
02/13/2026, 12:40 AMinference.STT/LLM/TTS and passing provider API keys (AssemblyAI, OpenAI, Cartesia). That combination causes the 401 because LiveKit Inference expects authentication with your LiveKit credentials, not provider keys.
What’s happening (short):
• inference.* routes through LiveKit Inference (agent gateway) which authenticates with your LiveKit API key/secret.
• Passing api_key=... to inference.STT does not authenticate to the LiveKit gateway and will not forward your provider key.
• The gateway responds 401 Unauthorized during the WebSocket handshake to wss://agent-gateway.livekit.cloud/v1/stt.
Two ways to fix this (pick one depending on which billing/auth flow you want):
1) Use LiveKit Inference (recommended if you want LiveKit to manage providers)
• Remove the provider api_key arguments from the inference.* constructors.
• Ensure your LiveKit credentials are set in the environment:
◦ LIVEKIT_API_KEY
◦ LIVEKIT_API_SECRET
◦ Optionally LIVEKIT_URL if using a custom project URL
• Example change:
session = AgentSession(
userdata={},
stt=inference.STT(model="assemblyai/universal-streaming", language="en"),
llm=inference.LLM(model="openai/gpt-4.1-mini"),
tts=inference.TTS(model="cartesia/sonic-3", voice="9626c31c-bec5-4cca-baa8-f8ba9e84c8bc"),
)
• Your usage is billed through LiveKit Inference.
2) Use provider plugins (if you want to use your own provider accounts and keys directly)
• Switch from inference.* to the plugin classes for each provider so your provider API keys are used directly.
• Install/enable plugin extras if required, then use plugin constructors:
from livekit.plugins import assemblyai, openai, cartesia
session = AgentSession(
userdata={},
stt=assemblyai.STT(api_key=os.getenv("ASSEMBLYAI_API_KEY"), language="en"),
llm=openai.LLM(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4.1-mini"),
tts=cartesia.TTS(api_key=os.getenv("CARTESIA_API_KEY"), model="sonic-3",
voice="9626c31c-bec5-4cca-baa8-f8ba9e84c8bc"),
)
• This connects directly to the providers and bills those provider accounts.
Quick validation steps you can run now:
• Confirm you have valid LiveKit credentials set if you chose option 1.
• If you chose option 2, confirm each provider key works by calling the provider’s API directly.
• Remove any stray whitespace/newlines in environment values and restart your process.
If you tell me which option you want (Inference via LiveKit or direct provider plugins), I’ll give the exact code and the small env checks to run next.
Sources: How much can LiveKit scale? | LiveKit | Speech-to-text (STT) models overview | LiveKit Documentation | Models overview | LiveKit Documentationfast-carpenter-5678
02/13/2026, 12:42 AMtall-airline-16756
02/13/2026, 12:42 AMuv add "livekit-agents[assemblyai,openai,cartesia]~=1.3"
If you use pip instead:
pip install "livekit-agents[assemblyai,openai,cartesia]~=1.3"
For Node.js (pnpm):
pnpm add @livekit/agents-plugin-assemblyai@1.x @livekit/agents-plugin-openai@1.x @livekit/agents-plugin-cartesia@1.x
For Node.js (npm):
npm install @livekit/agents-plugin-assemblyai@1.x @livekit/agents-plugin-openai@1.x @livekit/agents-plugin-cartesia@1.x
After installing, update your code to use the plugin classes and pass your provider API keys (examples I showed earlier). If you want, paste your environment (Python/Node) and I’ll give the exact import lines and a minimal code snippet for your project.
Sources: Pipeline Translator Agent | LiveKit Documentation | Deepgram STT plugin guide | LiveKit Documentation | ElevenLabs STT plugin guide | LiveKit Documentation | OpenAI LLM plugin guide | LiveKit Documentationfast-carpenter-5678
02/13/2026, 12:59 AMtall-airline-16756
02/13/2026, 12:59 AMcurl -v <https://api.assemblyai.com/v2/transcript> \
-H "Authorization: YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"audio_url":"<https://cdn.simplefiles/audio/somefile.mp3>"}'
• If you get a 401 or other auth error, the key is invalid or revoked. If it succeeds, the key is good.
2) Verify network connectivity and DNS
• Test basic reachability and TLS:
curl -v <https://api.assemblyai.com/v2/>
• Test DNS resolution:
nslookup <http://api.assemblyai.com|api.assemblyai.com>
• If curl/lookup fail, check firewall, proxy, or VPC egress rules. AssemblyAI uses standard HTTPS on port 443.
3) Check for intermediate network/proxy/TLS issues
• If your host runs behind a corporate proxy or uses custom TLS inspection, that can close connections. Confirm no proxy is intercepting or blocking invites.
• Try from a different environment (your laptop or another server) to see if the problem is host-specific.
4) Confirm you’re using the plugin correctly
• Use the plugin class (no extra inference descriptors). Example:
from livekit.plugins import assemblyai
session = AgentSession(stt=assemblyai.STT(), ...)
• Do not pass an inference.STT(...) descriptor when using plugin-based API keys.
• If you prefer explicit key passing for testing, you can create the plugin with the key:
assemblyai.STT(api_key=os.getenv("ASSEMBLYAI_API_KEY"))
5) Inspect audio input and VAD / noise cancellation
• Ensure the agent is receiving audio tracks (not silent) and that VAD is configured correctly. Silent or malformed audio may make AssemblyAI drop connections.
• Disable noise-cancelling features (krisp, BVCTelephony, or other aggressive filters) temporarily to rule them out.
6) Enable more verbose logs to capture the failing requests
• Increase log level for the plugin/agent to capture raw request attempts and any underlying socket/TLS error. That often surfaces connection timeouts, TLS handshake failures, or socket resets.
• Look for underlying errno or SSL errors in the more verbose trace.
7) Retry behavior & fallback
• The plugin retries a few times (your logs show attempts 0,1,2). If this is intermittent, you can:
◦ Temporarily increase retry/backoff in your agent code (if configurable) while diagnosing.
◦ Test with a different STT provider (Deepgram) to confirm if the issue is AssemblyAI-specific.
If tests show the host cannot reach api.assemblyai.com
• Open outbound HTTPS (443) to api.assemblyai.com from the agent host (or configure an allowed egress route).
• If behind a proxy, set appropriate environment variables (HTTP(S)_PROXY) so Python & aiohttp can use it.
If the key is invalid or revoked
• Generate / use a valid AssemblyAI key and place it in the environment, then restart the agent.
If everything looks fine locally but errors continue
• Collect verbose logs (include stack traces with network/TLS details) and indicate whether the failure is consistently reproducible or intermittent.
• As a quick test, switch the STT plugin to another provider plugin (e.g., deepgram) to verify whether the issue is provider-specific.
If you’d like, I can:
• Provide the exact commands to enable more verbose aiohttp/Python logging.
• Give a minimal troubleshooting script to POST a small audio chunk to AssemblyAI to replicate the behavior.
• Help you try a different STT plugin and the import/usage snippet for that provider.
Tell me which test you want to run first (connectivity test, API-key test, or switch to another STT plugin) and I’ll give the exact commands/snippets.
Sources: AssemblyAI plugin guide | LiveKit Documentation | Troubleshooting STT not picking up utterances | LiveKit | Agents Framework | livekit/livekit_composite | DeepWikifast-carpenter-5678
02/13/2026, 1:07 AMGET /v2/ HTTP/2
Host: api.assemblyai.com
User-Agent: curl/8.7.1
Accept: /* Request completely sent off < HTTP/2 404 < server: awselb/2.0 < date: Fri, 13 Feb 2026 010553 GMT < content-type: text/plain; charset=utf-8 < content-length: 9 < * Connection #0 to host api.assemblyai.com left intact Not found%
fast-carpenter-5678
02/13/2026, 1:07 AMtall-airline-16756
02/13/2026, 1:07 AMassemblyai.STT(...), openai.LLM(...), cartesia.TTS(...).
• A raw curl to https://api.assemblyai.com/v2/ returns HTTP/2 404 (this endpoint returns 404 on GET — that’s expected; AssemblyAI’s APIs are on specific paths like /v2/transcript).
• The agent logs now show the AssemblyAI websocket being closed/reset while sending binary frames: ClientConnectionResetError: Cannot write to closing transport after prior "connection closed unexpectedly (status_code=-1)".
Let’s focus on stabilizing the AssemblyAI STT plugin (the immediate blocker). Below are precise checks and actions you can run, ordered from quickest to more involved.
1) Confirm your AssemblyAI key is being used by the plugin
• Ensure your process environment has ASSEMBLYAI_API_KEY set and the agent can read it:
◦ From the running agent host:
▪︎ echo $ASSEMBLYAI_API_KEY
◦ Or in Python:
import os
print(bool(os.getenv("ASSEMBLYAI_API_KEY")))
• Optional: pass the key explicitly when constructing the plugin to make sure the right value is used:
stt = assemblyai.STT(api_key=os.getenv("ASSEMBLYAI_API_KEY"), model="assemblyai/universal-streaming-english")
2) Validate AssemblyAI endpoints with an authenticated request
• The root /v2/ path may return 404; test a valid authenticated endpoint instead:
curl -v <https://api.assemblyai.com/v2/transcript> \
-H "Authorization: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"audio_url":"<https://cdn.simplefiles/audio/somefile.mp3>"}'
• If you get 401 → key invalid. If you get a normal JSON error/response → key & network OK.
3) Reproduce a WebSocket handshake/test outside the agent (quick network test)
• AssemblyAI’s streaming uses a WebSocket endpoint. From the agent host, run a short script or use websocat to check a raw WS connection (this helps reveal TLS/proxy resets). Example (requires websocat):
websocat -H "authorization: YOUR_KEY" <wss://api.assemblyai.com/v2/realtime/ws>
• If it immediately closes or errors, this indicates a network/proxy/TLS problem that affects WS specifically.
4) Check for proxy, firewall, or TLS interception
• Confirm the agent host can open long-lived outbound WebSocket/TCP connections to AssemblyAI. Firewalls or corporate proxies commonly allow short HTTPS GET but kill persistent WS.
• If you are behind a proxy, set HTTP(S)_PROXY for the process so aiohttp can use it:
◦ export HTTPS_PROXY="http://proxy:port"
• If your environment performs TLS inspection, ensure the inspection cert is trusted by the agent host.
5) Increase plugin logging & capture aiohttp/TCP errors
• Enable DEBUG logging for livekit.plugins.assemblyai and aiohttp to capture socket/TLS errors:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("livekit.plugins.assemblyai").setLevel(logging.DEBUG)
logging.getLogger("aiohttp").setLevel(logging.DEBUG)
• Restart the agent and paste the expanded logs if you want me to read them — look for errno (e.g., ECONNRESET) or SSL handshake errors.
6) Confirm audio frames format and rate
• The plugin sends binary frames; if audio frames are malformed, AssemblyAI server may close the connection. Check that you’re sending PCM 16-bit 16k/16kHz or the format AssemblyAI expects for streaming.
• For debugging, try sending a single small valid audio file via the REST API (transcript endpoint) to ensure AssemblyAI accepts your audio payloads.
7) Try a quick provider swap to confirm it's AssemblyAI-specific
• Temporarily switch STT to another plugin (Deepgram or Google) using your key to see if the same connection resets happen. If other providers work, the issue is AssemblyAI-specific (network, account, or endpoint). Example:
from livekit.plugins import deepgram
session = AgentSession(stt=deepgram.STT(api_key=os.getenv("DEEPGRAM_API_KEY")), ...)
8) Consider transient retries and backoff
• The plugin already retries; if this is intermittent you can:
◦ Ensure your environment allows reconnections without being rate-limited.
◦ Add longer backoff if AssemblyAI returns connection resets under high load.
Common root causes seen in these logs
• Host-level outbound WebSocket connections are being reset (proxy, firewall, TLS inspection).
• AssemblyAI key invalid/unauthorized (would show 401 on authenticated calls).
• Malformed audio frames or incompatible audio format — server closes connection.
• Provider transient outage (less common).
Next steps I can help with right away
• You already ran curl to /v2/ — run the authenticated transcript POST above and paste the response.
• If you can, enable DEBUG logs (step 5) and paste the additional trace around the WS/TLS layer.
• If you prefer, I can give a minimal Python script to open a WebSocket to AssemblyAI’s realtime endpoint with your key (safe to run locally) to reproduce the socket behavior.
Which test do you want to run next — the authenticated transcript POST, websocat/WebSocket test, or turning on DEBUG logs? Tell me which and I’ll provide the exact command/snippet.fast-carpenter-5678
02/13/2026, 1:14 AMtall-airline-16756
02/13/2026, 1:14 AMawait session.generate_reply()), before any user audio is spoken. Let’s focus on why that happens and give a concise plan to stabilize the session.
Why this can happen (short)
• The STT plugin opens a streaming connection proactively. If no audio arrives or the stream is malformed, AssemblyAI may close the connection.
• Network / WebSocket issues (proxy/firewall/TLS inspection) can cause immediate connection resets.
• Invalid or missing API key or incorrect plugin usage can cause abrupt closes (though that usually yields a 401 on REST calls).
• Aggressive VAD/voice-detection or silence being sent can cause the plugin to retry and then fail.
Immediate checks and quick fixes to try now 1) Ensure the plugin isn’t starting streaming before there’s audio
• Use VAD so the STT stream only starts when speech is detected. If you haven’t enabled VAD, enable it so the plugin waits for audio instead of opening an idle stream:
from livekit.plugins import silero
vad = silero.VAD.load()
session = AgentSession(userdata={}, stt=assemblyai.STT(api_key=..., vad=vad), ...)
• If you’re already using VAD, confirm it’s detecting non-speech vs speech correctly. For debug, temporarily require manual trigger before calling session.generate_reply().
2) Delay calling session.generate_reply() until after first audio/VAD event
• If your flow calls generate_reply() immediately, try deferring that call until after you confirm a participant has spoken (or VAD signals speech). This avoids creating a streaming session with no audio.
3) Confirm AssemblyAI key & network (quick)
• You already tested the root endpoint; run an authenticated transcript test to confirm the key:
curl -v <https://api.assemblyai.com/v2/transcript> \
-H "Authorization: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"audio_url":"<https://cdn.simplefiles/audio/somefile.mp3>"}'
• If that succeeds, the key and basic network path are fine. The issue is likely WebSocket-specific or audio-related.
4) Test WebSocket connectivity from the agent host
• A WebSocket-level test reveals proxy/firewall/TLS issues. Use websocat or a short Python snippet to open a WS to AssemblyAI’s realtime endpoint with your key. If the WS closes immediately, address proxy/firewall/TLS settings.
5) Enable debug logs for the plugin and aiohttp
• This will show underlying socket/TLS errors (ECONNRESET, SSL errors) that the high-level stack trace doesn’t reveal:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("livekit.plugins.assemblyai").setLevel(logging.DEBUG)
logging.getLogger("aiohttp").setLevel(logging.DEBUG)
6) Validate audio format / frame timing
• If your agent immediately sends empty/silent frames or sends frames at an unexpected rate/format, AssemblyAI may drop the connection. Confirm frames are PCM and match the expected sample rate and chunking for AssemblyAI streaming.
If you want, I can give exact snippets for:
• A minimal VAD + deferred generate_reply flow.
• A small Python script to open a WebSocket to AssemblyAI (to reproduce the reset).
• The authenticated curl transcript command formatted with your key (you can paste the response).
Which would you like to try first: (A) enable VAD and defer generate_reply, (B) run a WebSocket connectivity test, or (C) enable DEBUG logs and send me the expanded trace?fast-carpenter-5678
02/13/2026, 1:20 AMPOST /v2/transcript HTTP/2
Host: api.assemblyai.com
User-Agent: curl/8.7.1
Accept: /
Authorization: c9d06ced99c34148b355bb81e53d86f1
Content-Type: application/json
Content-Length: 58* upload completely sent off: 58 bytes < HTTP/2 400 < date: Fri, 13 Feb 2026 012000 GMT < content-type: application/json; charset=UTF-8 < content-length: 119 < access-control-allow-origin: * < access-control-allow-headers: Content-Type, Authorization, X-Requested-With, User-Agent, AssemblyAI-Agent < access-control-allow-methods: POST, PUT, GET, OPTIONS < strict-transport-security: max-age=31536000; includeSubDomains; preload < * Connection #0 to host api.assemblyai.com left intact {"error": "\"speech_models\" must be a non-empty list containing one or more of: \"universal-3-pro\", \"universal-2\""}%
tall-airline-16756
02/13/2026, 1:21 AMnpm install -g wscat
1. Run this (replace YOUR_KEY with the exact ASSEMBLYAI key from your env):
wscat -c "<wss://api.assemblyai.com/v2/realtime/transcribe?token=YOUR_KEY&sample_rate=16000>"
Expected outcomes:
• Success: you get a JSON welcome/connected response and the socket remains open. That means WebSocket auth & network are OK.
• Failure: immediate close or handshake error — this points to network, proxy, TLS inspection, or the token being rejected for WS.
If wscat fails, run it from a different network (your laptop/home) to check whether the agent host network blocks WS.
Step B — Confirm the key your agent process is actually using From the same host/process environment that runs the agent, verify the env variable:
# at the shell used by the agent
echo "$ASSEMBLYAI_API_KEY"
# Or inside Python REPL running in the same env:
python -c "import os; print(len(os.getenv('ASSEMBLYAI_API_KEY') or ''))"
• Confirm the key length looks like a full key (not truncated).
• Also try creating the plugin explicitly with the key to ensure no env lookup bug:
stt = assemblyai.STT(api_key=os.getenv("ASSEMBLYAI_API_KEY"), model="universal-streaming")
Step C — Short Python WebSocket test (if you prefer Python over wscat) Save and run this from the agent host (replace YOUR_KEY). It will attempt a realtime WS handshake:
import asyncio
import websockets
async def test():
url = "<wss://api.assemblyai.com/v2/realtime/transcribe?token=YOUR_KEY&sample_rate=16000>"
try:
async with websockets.connect(url) as ws:
print("Connected OK")
msg = await ws.recv()
print("Received:", msg)
except Exception as e:
print("WS error:", repr(e))
asyncio.run(test())
Step D — If WebSocket connects, run a minimal LiveKit plugin repro Use a tiny snippet that opens assemblyai.STT stream and sends one small, valid audio frame to validate the plugin’s behavior. This shows whether the plugin or audio format is causing the close.
Minimal outline (I can give a full runnable snippet if you want):
• Create assemblyai.STT(api_key=...)
• Open its streaming API
• Send one valid PCM16 frame (16kHz) and then close
• Observe whether WS is closed or you get a server response
Step E — If WebSocket fails: network and proxy checks
• Check for outbound WebSocket/TCP being blocked by firewall or cloud security group.
• If behind a corporate proxy or TLS inspection, configure HTTPS_PROXY/HTTP_PROXY for the agent process so aiohttp/WS can use the proxy.
• Try from another network to confirm host-specific blocking.
Useful quick checks you can run now and paste results of 1) wscat result output (copy/paste). 2) Result of echo "$ASSEMBLYAI_API_KEY" (showing length / masked key). 3) If you already enabled DEBUG logs for aiohttp and assemblyai plugin, paste the first few lines around the WS handshake error (the debug logs often show an underlying errno like ECONNRESET or an SSL error).
If the WS connects successfully, but the LiveKit plugin still closes when generate_reply runs:
• Paste the debug logs for the plugin around the close — I’ll look for close codes or server reasons.
• We’ll check audio format (sample rate, bit depth, frame size) that you are sending — AssemblyAI expects PCM at the given sample rate; if frames are malformed the server may reset.
Which test would you like to run right now — (1) wscat test, (2) Python WS test, or (3) run the minimal LiveKit plugin repro? I’ll provide the exact snippet for whichever you pick and help interpret the output.
Sources: AssemblyAI plugin guide | LiveKit Documentation | AssemblyAI STT | LiveKit Documentation | OpenAI STT plugin guide | LiveKit Documentationfast-carpenter-5678
02/13/2026, 1:22 AMtall-airline-16756
02/13/2026, 1:22 AMimport asyncio
import os
import struct
import math
import json
import websockets
# Config
API_KEY = os.getenv("ASSEMBLYAI_API_KEY") or "YOUR_KEY"
SAMPLE_RATE = 16000
SAMPLE_SECONDS = 1.0 # length of generated audio in seconds
if API_KEY == "YOUR_KEY":
print("Replace YOUR_KEY with your AssemblyAI API key or set ASSEMBLYAI_API_KEY in env.")
raise SystemExit(1)
# Generate a short 1-second 440Hz sine wave as PCM16 mono at 16kHz
def generate_pcm16_sine(sample_rate: int, seconds: float, freq: float = 440.0):
num_samples = int(sample_rate * seconds)
pcm = bytearray()
for n in range(num_samples):
t = n / sample_rate
# amplitude scaled to avoid clipping
sample = int(0.5 * 32767 * math.sin(2.0 * math.pi * freq * t))
pcm += struct.pack("<h", sample)
return bytes(pcm)
async def run():
url = f"<wss://api.assemblyai.com/v2/realtime/transcribe?token={API_KEY}&sample_rate={SAMPLE_RATE}>"
print("Connecting to:", url)
try:
async with websockets.connect(url, max_size=None) as ws:
print("WebSocket connected")
# Receive initial messages from server (welcome/errors)
try:
greeting = await asyncio.wait_for(ws.recv(), timeout=3.0)
print("Server greeting:", greeting)
except asyncio.TimeoutError:
print("No greeting received within timeout (this can be okay).")
# Send a init/config message if AssemblyAI expects JSON init (some realtime APIs accept JSON control msgs)
# If AssemblyAI does not expect this, the server will ignore unknown control messages.
# We include a minimal JSON to ensure we didn't need other fields.
init_msg = {"type": "input_audio_buffer.init"}
try:
await ws.send(json.dumps(init_msg))
print("Sent init/config message")
except Exception as e:
print("Init send error:", e)
# Send audio in chunks as binary frames
pcm = generate_pcm16_sine(SAMPLE_RATE, SAMPLE_SECONDS)
chunk_size = 3200 # bytes per chunk (1600 samples, 100ms at 16kHz mono PCM16)
print(f"Sending {len(pcm)} bytes of PCM audio in chunks of {chunk_size} bytes")
for i in range(0, len(pcm), chunk_size):
chunk = pcm[i : i + chunk_size]
try:
await ws.send(chunk) # binary frame
print(f"Sent chunk {i//chunk_size + 1}")
except Exception as e:
print("Error sending chunk:", repr(e))
raise
# small pause to simulate streaming timing
await asyncio.sleep(0.08)
# Optionally tell the server we're done sending audio
try:
await ws.send(json.dumps({"type": "input_audio_buffer.flush"}))
print("Sent flush")
except Exception as e:
print("Flush send error:", e)
# Read responses for a short period
try:
while True:
msg = await asyncio.wait_for(ws.recv(), timeout=5.0)
print("Received:", msg)
except asyncio.TimeoutError:
print("No more messages within timeout, closing socket normally.")
except websockets.ConnectionClosed as e:
print("Connection closed by server:", e)
except Exception as e:
print("WebSocket connection error:", repr(e))
if __name__ == "__main__":
asyncio.run(run())
Notes and what to watch for
• Successful connect: you should see "WebSocket connected" and a server greeting or server messages after sending audio. That indicates WS + auth is working.
• Immediate close or connection error: copy the printed exception (handshake error, connection reset, SSL error). That indicates a network, proxy, TLS interception, or token issue for WebSocket specifically.
• If the socket connects but the server immediately closes after you send audio: look for server response JSON giving the reason (auth, bad format, required params).
• If you see JSON errors about model names or fields, paste them and I’ll map them to the plugin config.
After you run this, share the full output. If it connects, I’ll provide the equivalent minimal LiveKit plugin snippet to send the same chunk via the plugin's streaming API for a final comparison.fast-carpenter-5678
02/13/2026, 1:43 AMtall-airline-16756
02/13/2026, 1:43 AMuniversal-streaming / universal-streaming-english or the current model name AssemblyAI expects). A wrong model name will cause immediate connection/errors.
• Verify your final STT init looks like:
stt = assemblyai.STT(api_key=os.getenv("ASSEMBLYAI_API_KEY"), model="universal-streaming")
(or the exact model name you confirmed works).
If everything’s now stable, you should no longer see the connection reset or the "connection closed unexpectedly" errors during session.generate_reply().
If you still want, I can:
• Review your final AgentSession snippet to confirm everything is configured correctly (VAD, sample rate, model names for STT/LLM/TTS).
• Provide a quick checklist for production: env vars, logging levels, retry/backoff settings, and health checks.
• Help swap to a fallback STT plugin temporarily if you want redundancy.
Would you like me to review your final code snippet to confirm it’s production-ready?