Skip to main content
@lokutor/sdk latest: 1.9.0 · lokutor (Python) latest: 1.6.0 JS 1.5.0, 1.5.1 and 1.6.1 were JavaScript-only releases; Python went from 1.4.1 to 1.5.0 alongside JS 1.6.0.

Changelog

JS 1.9.0 (2026-10-26)

  • language: 'auto' (or '') on VoiceAgentClient, ConversationalPanel and updateLanguage() sends {"type": "language", "data": ""}, so the agent follows the caller’s language (Voice chat). Before, the client and the panel turned an empty language into 'en'. Omitting language is unchanged. New exports: AUTO_LANGUAGE, LanguageOption, languageToWire(). client.language can now be ''.

JS 1.8.0 · Python 1.6.0 (2026-10-21)

  • Custom vocabulary: keyterms on STTClient.transcribe() and SpeechToTextClient, the names, brands and terms to write your way when what is heard is close (up to 100; send language too). See Custom vocabulary. No other changes.

JS 1.7.1 (2026-10-20)

  • ConversationalPanel draws its own orb (PixelOrb) when no visualizer is passed. 1.7.0 carried the same code and was never made public.

JS 1.6.1

  • JS: the microphone is low-passed before it is downsampled to 16 kHz for recognition. StreamResampler (which BrowserAudioManager uses) applies a 63-tap windowed-sinc filter at 0.45 × the output rate (7.2 kHz for 16 kHz) before interpolating. Without it, sound between 8 and 24 kHz folded back into the speech band. A 12 kHz tone used to come through at 4 kHz at full level and is now 85 dB down. Speech up to about 6 kHz keeps its level (−0.4 dB at 6 kHz, −4 dB at 7 kHz).
  • JS: from 44.1 kHz microphones, the resampled audio no longer depends on how it was split into blocks. The resampler lost part of a sample’s timing at every block and ran slightly fast.
  • JS: StreamResampler.process(chunk, true) (flush) ends the stream when downsampling: it drains the filter, returns the remaining audio, and starts over. Upsampling is unchanged. No API changes.

Game engines (preview), 2026-10-19

  • New: Unity and Godot SDKs. A character with a Lokutor Agent listens through the microphone, answers in its own voice from its position in the world, moves its mouth, and calls game functions as actions. Unity: com.lokutor.voice-agents (git URL install). Godot: the addons/lokutor addon. Both in the lokutor-sdk repository; @lokutor/sdk and the Python SDK are unchanged.

JS 1.6.0 / Python 1.5.0

  • JS: tool_call fires once, with { name, arguments, call_id }; pass call_id to submitToolResult(call_id, result). It used to fire twice, the first time without call_id, so handlers ran each tool twice.
  • JS: constructor callbacks fire once, and connection errors and status changes reach both the constructor callbacks and on('error') / on('status') listeners.
  • JS: interim user text arrives as the new transcription_partial event and is no longer stored in getTranscript(), which holds final lines only.
  • JS: new auth: () => string | Promise<string> option, called before every connect and reconnect, to fetch a fresh wst_ ticket from your backend (Secure browser setup). apiKey is optional when auth is given.
  • JS: with agentId, prompt is optional and voice, language and prompt are sent only if you set them, so the dashboard agent’s own settings are no longer overwritten.
  • JS: TTSClient.synthesize() resolves when the server ends the stream and rejects with a LokutorError on server errors or stalls (it used to resolve after 2 s without audio). It sends speed and steps only if you set them.
  • JS: discovery helpers call https://api.lokutor.com/voices etc. (they requested a path that did not exist); fetchHealth() calls GET /ready. SpeechToTextClient.connect() rejects when the microphone fails. New error codes in ErrorCode: billing.insufficient_balance, billing.topup_required, billing.limit_reached, billing.account_disputed, agent.not_found. Node.js use needs Node 22+ (global WebSocket).
  • Python: on_tool_call(name, arguments, call_id) receives call_id. Works on Python 3.8+. PyAudio is only needed for local audio (pip install "lokutor[audio]"). Plain strings are accepted for voice and language.

1.5.1

  • JS: new requestMicrophone(), to call inside the tap or click that starts a call; pass its result to BrowserAudioManager as microphone. The call then uses that stream instead of asking for the microphone after the connection opens, which iOS Safari could refuse without showing its prompt (the agent spoke and nothing the caller said reached it). It also moves an iOS audio session left in 'playback' back to 'auto', since iOS refuses the microphone in playback mode.
  • JS: when the microphone cannot start, connect() now rejects with the new code audio.microphone_unavailable (not retryable) and closes the session. Previously connect() stayed pending while the session kept talking.
  • JS: BrowserAudioManager.cleanup() closes its AudioContext; init() no longer waits indefinitely on AudioContext.resume(). Server errors reach onError once (they were delivered twice).

1.5.0

  • JS: the voice-agent client reconnects only after the connection drops or the server goes away (close codes 1001, 1006, 1011–1014). When the server ends the session on purpose (1000, 1008, 4xxx) it stays closed, fires error with code session.ended and the server’s reason, status disconnected, and a new ended event — previously it reconnected into a fresh session.
  • JS: a reconnection reuses the running microphone (it used to start a second capture, doubling and scrambling the caller’s audio) and resets the response generation counter (it used to discard every response of the new session as stale, so the agent answered and nothing was heard).
  • JS: new session_limit event when the server announces a session’s remaining time; ConversationalPanel shows it as a countdown, says “Reconnecting…” while the client retries, ends the call visibly when the connection is gone, shows the server’s reason, and adds onEnded(message).
  • JS: BrowserAudioManager keeps the screen awake while the microphone is live (keepAwake, default true) and resumes audio when the page returns to the foreground.

1.4.1

  • Python: pyaudio (needed only for local mic/speaker convenience — VoiceAgentClient’s live audio loop, and TTSClient/STTClient’s optional local playback/capture helpers) is now an optional audio extra (pip install lokutor[audio]) instead of a hard dependency. It needs PortAudio’s C library, which doesn’t compile on a clean machine without the system package — previously this broke pip install lokutor outright, and blocked even TTSClient/STTClient usage that never touches local audio hardware.

1.4.0

  • JS: the voice-agent panel’s “listening” curtain is now the agent’s own accent color with a grain texture, replacing a fixed stock-photo background
  • JS: removed a leftover pulse animation and an opacity dim on the visualizer that were never updated for the current binary (agent/user, no idle) visualizer state
  • Backend: a false-positive barge-in that resumes playback now tells the client — previously the client was left showing listening while the bot was audibly still speaking (see WebSocket Protocol → Barge-in)
  • Backend: /ws/agent’s voice and language messages now reject an unrecognised value the same way POST /tts/synthesize and /ws/tts already did, instead of silently applying a fallback

1.3.0

  • Nine supported languages, Versa 2.0 voice ids
  • Wire vocabulary canonicalized to voice/language (the older voice_id/lang names remain accepted as deprecated aliases)

1.2.1

Point release on top of 1.2.0.

1.2.0

  • Standalone speech-to-text: STTClient for one-shot transcription of a complete audio clip (POST /stt/transcribe), SpeechToTextClient for continuous/live transcription over WS /ws/stt — neither requires the full voice-agent (LLM + TTS) pipeline
  • simpleTranscribe() convenience function

1.1.43

  • Tool calling improvements: submitToolResult() method, call_id in tool_call events
  • Conversation panel UI component
  • Python SDK: update_prompt(), get_transcript(), get_transcript_text()
  • Python SDK: on() event listener pattern

1.1.17

  • Initial stable release
  • VoiceAgentClient for real-time conversations
  • TTSClient for standalone text-to-speech
  • BrowserAudioManager for Web Audio API
  • LokutorError with typed error codes
  • WebSocket reconnection with exponential backoff
  • Viseme streaming support
  • 10 voices; language count at the time isn’t preserved accurately in this entry — see Voices, Languages & Models for the current count (nine)

Versioning policy

  • MAJOR — Breaking API changes
  • MINOR — New features, backwards compatible
  • PATCH — Bug fixes, backwards compatible