@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'') onVoiceAgentClient,ConversationalPanelandupdateLanguage()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'. Omittinglanguageis unchanged. New exports:AUTO_LANGUAGE,LanguageOption,languageToWire().client.languagecan now be''.
JS 1.8.0 · Python 1.6.0 (2026-10-21)
- Custom vocabulary:
keytermsonSTTClient.transcribe()andSpeechToTextClient, the names, brands and terms to write your way when what is heard is close (up to 100; sendlanguagetoo). See Custom vocabulary. No other changes.
JS 1.7.1 (2026-10-20)
ConversationalPaneldraws 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(whichBrowserAudioManageruses) 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: theaddons/lokutoraddon. Both in thelokutor-sdkrepository;@lokutor/sdkand the Python SDK are unchanged.
JS 1.6.0 / Python 1.5.0
- JS:
tool_callfires once, with{ name, arguments, call_id }; passcall_idtosubmitToolResult(call_id, result). It used to fire twice, the first time withoutcall_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_partialevent and is no longer stored ingetTranscript(), which holds final lines only. - JS: new
auth: () => string | Promise<string>option, called before every connect and reconnect, to fetch a freshwst_ticket from your backend (Secure browser setup).apiKeyis optional whenauthis given. - JS: with
agentId,promptis optional andvoice,languageandpromptare 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 aLokutorErroron server errors or stalls (it used to resolve after 2 s without audio). It sendsspeedandstepsonly if you set them. - JS: discovery helpers call
https://api.lokutor.com/voicesetc. (they requested a path that did not exist);fetchHealth()callsGET /ready.SpeechToTextClient.connect()rejects when the microphone fails. New error codes inErrorCode:billing.insufficient_balance,billing.topup_required,billing.limit_reached,billing.account_disputed,agent.not_found. Node.js use needs Node 22+ (globalWebSocket). - Python:
on_tool_call(name, arguments, call_id)receivescall_id. Works on Python 3.8+. PyAudio is only needed for local audio (pip install "lokutor[audio]"). Plain strings are accepted forvoiceandlanguage.
1.5.1
- JS: new
requestMicrophone(), to call inside the tap or click that starts a call; pass its result toBrowserAudioManagerasmicrophone. 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 codeaudio.microphone_unavailable(not retryable) and closes the session. Previouslyconnect()stayed pending while the session kept talking. - JS:
BrowserAudioManager.cleanup()closes its AudioContext;init()no longer waits indefinitely onAudioContext.resume(). Server errors reachonErroronce (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
errorwith codesession.endedand the server’s reason, statusdisconnected, and a newendedevent — 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_limitevent when the server announces a session’s remaining time;ConversationalPanelshows 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 addsonEnded(message). - JS:
BrowserAudioManagerkeeps the screen awake while the microphone is live (keepAwake, defaulttrue) 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, andTTSClient/STTClient’s optional local playback/capture helpers) is now an optionalaudioextra (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 brokepip install lokutoroutright, and blocked evenTTSClient/STTClientusage 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
listeningwhile the bot was audibly still speaking (see WebSocket Protocol → Barge-in) - Backend:
/ws/agent’svoiceandlanguagemessages now reject an unrecognised value the same wayPOST /tts/synthesizeand/ws/ttsalready 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 oldervoice_id/langnames remain accepted as deprecated aliases)
1.2.1
Point release on top of 1.2.0.1.2.0
- Standalone speech-to-text:
STTClientfor one-shot transcription of a complete audio clip (POST /stt/transcribe),SpeechToTextClientfor continuous/live transcription overWS /ws/stt— neither requires the full voice-agent (LLM + TTS) pipeline simpleTranscribe()convenience function
1.1.43
- Tool calling improvements:
submitToolResult()method,call_idin 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
VoiceAgentClientfor real-time conversationsTTSClientfor standalone text-to-speechBrowserAudioManagerfor Web Audio APILokutorErrorwith 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