Skip to main content

EstuaryClient

The main class for interacting with the Estuary platform. Manages the WebSocket connection, voice sessions, and provides access to the memory API.

import { EstuaryClient } from '@estuary-ai/sdk';

const client = new EstuaryClient(config);

Constructor​

new EstuaryClient(config)​

Creates a new client instance. Either apiKey or sessionToken must be provided in the config.

ParameterTypeDescription
configEstuaryConfigClient configuration

Throws: EstuaryError with code AUTH_FAILED if neither apiKey nor sessionToken is provided.

const client = new EstuaryClient({
serverUrl: 'https://api.estuary-ai.com',
apiKey: 'est_your_api_key',
characterId: 'your-character-uuid',
playerId: 'user-123',
});

Static Methods​

EstuaryClient.openShare(serverUrl, shareId)​

Opens a permanent share link. Calls the backend's share endpoint to mint a fresh session token and resolve character metadata. Use the returned fields to construct an EstuaryClient with sessionToken auth.

ParameterTypeDescription
serverUrlstringBase URL of the Estuary server
shareIdstringThe share link identifier

Returns: Promise<ShareOpenResponse>

Throws: EstuaryError with code REST_ERROR if the share open request fails.

import { EstuaryClient } from '@estuary-ai/sdk';

const share = await EstuaryClient.openShare(
'https://api.estuary-ai.com',
'share-abc-123',
);

const client = new EstuaryClient({
serverUrl: share.serverUrl,
sessionToken: share.sessionToken,
characterId: share.characterId,
playerId: share.playerId,
});

await client.connect();

See ShareOpenResponse for the full response shape.


Connection​

connect()​

Connects to the Estuary server and authenticates with the configured apiKey (or sessionToken). Returns a promise that resolves with session info on success.

Returns: Promise<SessionInfo>

Throws: EstuaryError with code CONNECTION_FAILED or AUTH_FAILED

const session = await client.connect();
console.log('Session ID:', session.sessionId);

disconnect()​

Disconnects from the server. Stops any active voice session, clears audio playback, and cleans up resources. Awaits stopVoice() internally, so it returns a promise.

Returns: Promise<void>

await client.disconnect();

isConnected​

Whether the client is currently connected and authenticated.

Type: boolean (read-only)

if (client.isConnected) {
client.sendText('Hello!');
}

connectionState​

The current connection state.

Type: ConnectionState (read-only)

console.log(client.connectionState); // 'connected', 'connecting', etc.

Text​

sendText(text, textOnly?)​

Sends a text message to the character.

ParameterTypeDefaultDescription
textstring--The message text
textOnlybooleantrueIf true, suppresses voice response (text only). Pass false to receive voice audio.

Throws: EstuaryError with code NOT_CONNECTED

client.sendText('Hello!'); // text only (default)
client.sendText('Tell me a story', false); // also stream voice audio

sayLine(text, textOnly?)​

Scripts the character to say a specific prewritten line via TTS. Skips the LLM entirely -- the text is fed directly to TTS and saved to chat history as a normal assistant message. Any in-progress response is interrupted before the line is spoken.

ParameterTypeDefaultDescription
textstring--The line to speak. Empty/whitespace strings are ignored.
textOnlybooleanfalseIf true, only botResponse is emitted (no audio).

Throws: EstuaryError with code NOT_CONNECTED

client.sayLine('Welcome back, traveler.');
client.sayLine('System message', true); // text only, no TTS

The response uses the same botResponse and botVoice events as a normal reply; isInterjection will be false.

interrupt(messageId?)​

Interrupts the current bot response and clears queued audio.

ParameterTypeDescription
messageIdstring (optional)Specific message to interrupt

Throws: EstuaryError with code NOT_CONNECTED

client.interrupt();
client.interrupt('msg-123');

Voice​

startVoice()​

Starts a voice session and requests microphone permission. With voiceMode: 'continuous' (default), audio streams immediately. With 'push_to_talk', the microphone is prepared with transmission off until a press.

The voice transport used depends on the voiceTransport config option:

  • 'websocket' -- Streams PCM audio over WebSocket
  • 'livekit' -- Connects via LiveKit WebRTC (requires livekit-client)
  • 'auto' (default) -- Uses LiveKit if available, otherwise WebSocket

Returns: Promise<void>

Throws:

  • EstuaryError with code NOT_CONNECTED if not connected
  • EstuaryError with code VOICE_ALREADY_ACTIVE if voice is already started
  • EstuaryError with code VOICE_NOT_SUPPORTED if no transport is available
  • EstuaryError with code MICROPHONE_DENIED if microphone permission is denied
await client.startVoice();

stopVoice()​

Stops the active voice session. Releases the microphone and cleans up the voice manager. No-op if voice is not active.

Returns: Promise<void>

await client.stopVoice();

beginPushToTalk()​

Presses talk in a prepared voiceMode: 'push_to_talk' session. Await the promise before prompting the user to speak. Pauses while held do not submit the turn. Repeated presses while already held share the pending operation.

Returns: Promise<void>

Throws: NOT_CONNECTED before connect; VOICE_NOT_ACTIVE before startVoice(); VOICE_MODE_MISMATCH in continuous mode; CONNECTION_FAILED on a voice provider failure; CONNECTION_TIMEOUT if readiness times out. Reconnect before retrying a timed-out command.

endPushToTalk()​

Releases talk and finalizes the turn, keeping voice prepared for another press. Safe to call while a press is pending, when already released, or after teardown. Bind this to release/cancel/blur events so the button cannot remain held. Await it before the next turn; a rapid LiveKit re-press can merge with the previous turn during the release grace period. It does not end the LiveKit call.

Returns: Promise<void>

Throws: VOICE_MODE_MISMATCH in continuous mode; connection errors if the release signal fails. On a command timeout, reconnect before retrying.

isPushToTalkActive​

Whether the talk button is held, including while press readiness is pending. It resets on release, voice teardown, and disconnect. Reconnection does not resume an old press. User mute and playback suppression can still block transmission while this property is true; isMuted reports the separate user mute toggle.

Type: boolean (read-only)

See Push-to-talk for usage.

toggleMute()​

Toggles the microphone mute state.

Throws: EstuaryError with code VOICE_NOT_ACTIVE if no voice session is active

Returns: void

client.toggleMute();

isMuted​

Whether the microphone is currently muted.

Type: boolean (read-only)

console.log('Muted:', client.isMuted);

isVoiceActive​

Whether a voice session is currently active.

Type: boolean (read-only)

if (client.isVoiceActive) {
await client.stopVoice();
}

Camera​

sendCameraImage(imageBase64, mimeType, requestId?, text?)​

Sends a camera image for vision-language model processing.

ParameterTypeDescription
imageBase64stringBase64-encoded image data
mimeTypestringImage MIME type (e.g., 'image/jpeg')
requestIdstring (optional)Request ID (if responding to a cameraCaptureRequest)
textstring (optional)Text to accompany the image

Throws: EstuaryError with code NOT_CONNECTED

client.sendCameraImage(base64Data, 'image/jpeg', requestId, 'What is this?');

updatePreferences(preferences)​

Updates session-level preferences.

ParameterTypeDescription
preferencesobjectPreferences to update
preferences.enableVisionAcknowledgmentboolean (optional)Whether the character acknowledges before analyzing images

Throws: EstuaryError with code NOT_CONNECTED

client.updatePreferences({ enableVisionAcknowledgment: false });

Audio​

notifyAudioPlaybackComplete(messageId?)​

Notifies the server that audio playback has completed for a message. This is called automatically:

  • WebSocket transport: by the built-in AudioPlayer when its drain callback fires.
  • LiveKit transport: when the bot's speaking state transitions from speaking to silent (via the LiveKit speaking-state callback).

You only need to call this manually if you implement a custom audio playback path (for example, intercepting botVoice events and rendering audio yourself).

ParameterTypeDescription
messageIdstring (optional)The message whose audio finished playing

Throws: EstuaryError with code NOT_CONNECTED

client.notifyAudioPlaybackComplete('msg-123');

Character​

getCharacter(characterId?)​

Fetches character details (3D model URL, avatar, tagline, etc.) from the REST API.

ParameterTypeDescription
characterIdstring (optional)Character to fetch. Defaults to the characterId configured on the client.

Returns: Promise<CharacterInfo> -- see CharacterInfo.

Throws: EstuaryError with code NOT_CONNECTED if the client was constructed with a sessionToken instead of an apiKey (REST is not available with session-token auth -- use a server-side proxy in that case).

const character = await client.getCharacter();
console.log('3D model URL:', character.modelUrl);

// Or explicitly fetch a different character
const other = await client.getCharacter('character-uuid-2');

Properties​

memory​

The memory API client for querying memories, knowledge graphs, and facts.

Type: MemoryClient (read-only)

Throws: EstuaryError with code NOT_CONNECTED when accessed if the client was constructed with a sessionToken (REST is not available with session-token auth).

const facts = await client.memory.getCoreFacts();

See Memory & Knowledge Graph for usage details.

session​

The current session info. null if not connected.

Type: SessionInfo | null (read-only)

if (client.session) {
console.log('Conversation:', client.session.conversationId);
}

Event Methods​

EstuaryClient extends TypedEventEmitter and provides typed event subscription:

on(event, listener)​

Subscribe to an event. See Events and Types for the full event map.

client.on('botResponse', (response) => { /* ... */ });

off(event, listener)​

Remove an event listener.

client.off('botResponse', handler);

once(event, listener)​

Subscribe to an event for a single invocation.

client.once('connected', (session) => { /* ... */ });