@convai/web-sdk 1.8.0-beta.4 → 1.8.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/core/CharacterVersionManager.d.ts +100 -0
- package/dist/core/CharacterVersionManager.d.ts.map +1 -0
- package/dist/core/CharacterVersionManager.js +227 -0
- package/dist/core/CharacterVersionManager.js.map +1 -0
- package/dist/core/ConvaiClient.d.ts +15 -0
- package/dist/core/ConvaiClient.d.ts.map +1 -1
- package/dist/core/ConvaiClient.js +60 -3
- package/dist/core/ConvaiClient.js.map +1 -1
- package/dist/core/characterReference.d.ts +40 -0
- package/dist/core/characterReference.d.ts.map +1 -0
- package/dist/core/characterReference.js +72 -0
- package/dist/core/characterReference.js.map +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/types.d.ts +255 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/react/hooks/useConvaiClient.d.ts.map +1 -1
- package/dist/react/hooks/useConvaiClient.js +7 -2
- package/dist/react/hooks/useConvaiClient.js.map +1 -1
- package/dist/vanilla/index.d.ts +1 -0
- package/dist/vanilla/index.d.ts.map +1 -1
- package/dist/vanilla/index.js +1 -0
- package/dist/vanilla/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAuBA;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,cAAc,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC;IACnB,kBAAkB,EAAE,CAAC;IACrB,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,CAAC;IACtB,YAAY,EAAE,CAAC;IACf,cAAc,EAAE,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;CACP,CAAC;AAEX;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAA+B;IACxE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,oBAAoB,CAAC,cAAc;YACtC,OAAO,sCAAsC,CAAC;QAChD,KAAK,oBAAoB,CAAC,gBAAgB;YACxC,OAAO,mBAAmB,CAAC;QAC7B,KAAK,oBAAoB,CAAC,kBAAkB;YAC1C,OAAO,0CAA0C,CAAC;QACpD,KAAK,oBAAoB,CAAC,eAAe;YACvC,OAAO,yBAAyB,CAAC;QACnC,KAAK,oBAAoB,CAAC,mBAAmB;YAC3C,OAAO,kCAAkC,CAAC;QAC5C,KAAK,oBAAoB,CAAC,YAAY;YACpC,OAAO,+BAA+B,CAAC;QACzC,KAAK,oBAAoB,CAAC,cAAc;YACtC,OAAO,gBAAgB,CAAC;QAC1B,KAAK,oBAAoB,CAAC,YAAY;YACpC,OAAO,gBAAgB,CAAC;QAC1B,KAAK,oBAAoB,CAAC,SAAS;YACjC,OAAO,qCAAqC,CAAC;QAC/C,KAAK,oBAAoB,CAAC,YAAY;YACpC,OAAO,0BAA0B,CAAC;QACpC;YACE,OAAO,cAAc,CAAC;IAC1B,CAAC;AACH,CAAC","sourcesContent":["import { Room, DisconnectReason as LiveKitDisconnectReason } from 'livekit-client';\nimport { BlendshapeQueue } from './BlendshapeQueue';\n\n/**\n * LiveKit disconnect reasons.\n * Helps determine why a participant was disconnected from the room.\n * \n * These values map to LiveKit's DisconnectReason enum:\n * - UNKNOWN_REASON (0): Unknown disconnect reason\n * - CLIENT_INITIATED (1): Client called disconnect() - intentional disconnect\n * - DUPLICATE_IDENTITY (2): Another client with the same identity joined the room\n * - SERVER_SHUTDOWN (3): LiveKit server is shutting down\n * - PARTICIPANT_REMOVED (4): Participant was removed by RemoveParticipant API\n * - ROOM_DELETED (5): Room was ended via DeleteRoom API\n * - STATE_MISMATCH (6): State mismatch between client and server\n * - JOIN_FAILURE (7): Failed to join the room\n * - MIGRATION (8): Participant moved to a different room\n * - SIGNAL_CLOSE (9): Signal connection was closed\n * \n * @see https://docs.livekit.io/reference/client-sdk-js/enums/DisconnectReason.html\n */\nexport type DisconnectReason = LiveKitDisconnectReason;\n\n/**\n * Export LiveKit's DisconnectReason enum values for easy access\n */\nexport const DisconnectReasonEnum = {\n UNKNOWN_REASON: 0,\n CLIENT_INITIATED: 1,\n DUPLICATE_IDENTITY: 2,\n SERVER_SHUTDOWN: 3,\n PARTICIPANT_REMOVED: 4,\n ROOM_DELETED: 5,\n STATE_MISMATCH: 6,\n JOIN_FAILURE: 7,\n MIGRATION: 8,\n SIGNAL_CLOSE: 9,\n} as const;\n\n/**\n * Get a human-readable message for a disconnect reason.\n * \n * @param reason - The disconnect reason code from LiveKit\n * @returns A human-readable message describing the disconnect reason\n * \n * @example\n * ```typescript\n * client.on('disconnect', (reason) => {\n * console.log(getDisconnectReasonMessage(reason));\n * // Output: \"User disconnected\"\n * });\n * ```\n */\nexport function getDisconnectReasonMessage(reason: DisconnectReason | null): string {\n if (reason === null) {\n return 'Connected';\n }\n\n switch (reason) {\n case DisconnectReasonEnum.UNKNOWN_REASON:\n return 'Network unavailable or unknown cause';\n case DisconnectReasonEnum.CLIENT_INITIATED:\n return 'User disconnected';\n case DisconnectReasonEnum.DUPLICATE_IDENTITY:\n return 'Another client with same identity joined';\n case DisconnectReasonEnum.SERVER_SHUTDOWN:\n return 'Server is shutting down';\n case DisconnectReasonEnum.PARTICIPANT_REMOVED:\n return 'Removed by RemoveParticipant API';\n case DisconnectReasonEnum.ROOM_DELETED:\n return 'Room ended via DeleteRoom API';\n case DisconnectReasonEnum.STATE_MISMATCH:\n return 'State mismatch';\n case DisconnectReasonEnum.JOIN_FAILURE:\n return 'Failed to join';\n case DisconnectReasonEnum.MIGRATION:\n return 'Participant moved to different room';\n case DisconnectReasonEnum.SIGNAL_CLOSE:\n return 'Signal connection closed';\n default:\n return 'Disconnected';\n }\n}\n\n/**\n * Dynamic information structure for passing real-time context to the character.\n * Pass a text description of the current dynamic context.\n * \n * @example\n * ```typescript\n * const dynamicInfo = \"Player health is low, in combat mode\";\n * ```\n */\nexport type DynamicInfo = string;\n\n/**\n * Minimal contract that ConvaiClient and AudioManager require from a WebSocket\n * session implementation. Defined here so core has zero import dependency on\n * the pipecat packages — the concrete class lives in the vanilla/websocket subpath.\n */\nexport interface IWebSocketSession {\n readonly isConnected: boolean;\n connectWithUrl(wsUrl: string): Promise<void>;\n disconnect(): Promise<void>;\n sendMessage(type: string, data: unknown): void;\n enableMic(enable: boolean): void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n on(event: string, listener: (...args: any[]) => void): () => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n off(event: string, listener: (...args: any[]) => void): void;\n}\n\n/**\n * Factory function signature used to register a WebSocket transport implementation\n * via {@link ConvaiClient.registerWebSocketTransport}. Import\n * `@convai/web-sdk/vanilla/websocket` (or `@convai/web-sdk/react/websocket`) as a\n * side-effect to register the default Pipecat-based implementation.\n */\nexport type WebSocketSessionFactory = (\n onMessage: (payload: Uint8Array) => void,\n enableMic: boolean,\n) => IWebSocketSession;\n\n/**\n * Options for {@link IConvaiClient.uploadFile}.\n *\n * Supported formats: JPEG, PNG, GIF, WebP. Maximum file size: 10 MB.\n * Files are sent as raw binary over the WebRTC byte stream — not base64 encoded.\n */\nexport interface UploadFileOptions {\n /** Server routing topic. Defaults to `'file-upload'`. */\n topic?: string;\n /**\n * Progress callback. Called with an integer percentage (0–100) as the upload proceeds.\n */\n onProgress?: (progressPercent: number) => void;\n}\n\n/**\n * Extra data returned in a server-response for specific event types.\n */\nexport interface ServerResponseExtras {\n // context-update extras\n token_count?: number;\n static_token_count?: number;\n runtime_token_count?: number;\n max_tokens?: number;\n static_max_tokens?: number;\n runtime_max_tokens?: number;\n remaining_tokens?: number;\n /** Full retained runtime dynamic context text after the update */\n content?: string;\n // tts-toggle extras\n enabled?: boolean;\n // stt-toggle extras\n muted?: boolean;\n // trigger-message extras\n trigger_name?: string;\n has_speak_tag?: boolean;\n // user_text_message extras\n text?: string;\n // kill-pipeline extras\n room_name?: string;\n // unknown-message-type error extras\n supported_types?: string[];\n // vision-status / vision-trigger extras\n vision_buffer?: VisionBufferStatus;\n requested_respond_mode?: RespondMode;\n actual_respond_mode?: RespondMode;\n requested_run_llm?: \"true\" | \"false\" | \"auto\";\n actual_run_llm?: \"true\" | \"false\" | \"auto\";\n llm_triggered?: boolean;\n downgraded?: boolean;\n downgrade_reason?: string | null;\n interrupted?: boolean;\n vision_frames_attached?: number;\n vision_image_tokens_est?: number;\n vision_detail_level?: string | null;\n vision_attach_outcome?: string;\n vision_source_participant?: string | null;\n attached_frame_pts?: number[];\n frame_binding?: string;\n frame_binding_error?: string | null;\n requested_frame_indices?: [number, number] | number[] | null;\n requested_frame_ids?: number[] | null;\n frame_indices_clamped?: boolean;\n frame_ids_stale_exempt?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Acknowledgment sent by the server for every client-to-server message.\n * Analogous to an HTTP response: use `status` to check success/failure and\n * `extras` for event-specific data such as context token counts.\n *\n * @example\n * ```typescript\n * client.on('serverResponse', (response) => {\n * if (response.event_type === 'context-update') {\n * const { remaining_tokens, max_tokens } = response.extras ?? {};\n * console.log(`Tokens remaining: ${remaining_tokens} / ${max_tokens}`);\n * }\n * if (response.status === 'error') {\n * console.error('Server error:', response.message);\n * }\n * });\n * ```\n */\nexport interface ServerResponse {\n /** The original client message type that triggered this response */\n event_type: string;\n /** Processing status */\n status: 'success' | 'error' | 'processing' | 'pending';\n /** Human-readable description of the result */\n message: string | null;\n /** Additional event-specific data */\n extras: ServerResponseExtras | null;\n}\n\n/**\n * Emitted when the server assigns an interaction ID to the session.\n * Store the interactionId for analytics or session tracking.\n */\nexport interface InteractionCreated {\n /** Unique identifier for this interaction session */\n interactionId: string;\n /** Character session identifier */\n characterSessionId: string;\n}\n\n/**\n * A single action the character performs, emitted via the `actionResponse`\n * event. When `target` is present the action is *parameterized* (the character\n * acts on a specific object/character); simple actions (e.g. `\"Wave\"`) omit it.\n */\nexport interface ConvaiAction {\n /** Base action name, e.g. `\"Move To\"`, `\"Pick Up\"`, `\"Wave\"`. */\n name: string;\n /**\n * The object or character the action targets — must match a name from\n * `actionConfig.objects[]` / `actionConfig.characters[]`. Absent for simple\n * (non-parameterized) actions.\n */\n target?: string;\n}\n\n/**\n * Payload of the `actionResponse` event. Actions execute sequentially; an\n * empty array is a valid \"no action\" turn.\n */\nexport interface ActionResponseEvent {\n actions: ConvaiAction[];\n}\n\n/**\n * Options for updating the bot's temporary runtime context.\n * Provides flexible control over how context is managed during conversation.\n * \n * @example\n * ```typescript\n * // Append to existing context\n * client.updateContext({\n * text: \"User just completed dragon quest\",\n * mode: \"append\",\n * run_llm: \"false\"\n * });\n * \n * // Replace entire context\n * client.updateContext({\n * text: \"New game state: level 5, combat mode\",\n * mode: \"replace\",\n * run_llm: \"auto\"\n * });\n * \n * // Reset/clear context\n * client.updateContext({\n * mode: \"reset\"\n * });\n * ```\n */\nexport interface ContextUpdateOptions {\n /**\n * The context text to inject.\n * Required unless mode is \"reset\" or only current_attention_object is being updated.\n */\n text?: string;\n /**\n * How to apply the context:\n * - \"append\" (default): Add text to existing ephemeral context\n * - \"replace\": Replace existing ephemeral context with new text\n * - \"reset\": Clear ephemeral context; text is optional\n */\n mode?: \"append\" | \"replace\" | \"reset\";\n /**\n * Whether to trigger LLM response:\n * - \"true\": Always trigger a response from the bot and preempt active local playback\n * - \"false\": Never trigger a response\n * - \"auto\" (default): Server decides based on context without preempting active playback\n */\n run_llm?: \"true\" | \"false\" | \"auto\";\n /**\n * Optional respond-mode alias for backends that expose unified respond modes.\n * If `run_llm` is provided, it takes precedence.\n */\n respond_mode?: RespondMode;\n /**\n * The object the character should currently focus on.\n * Must match one of action_config.objects[].name.\n * Pass an empty string to clear current attention.\n */\n current_attention_object?: string;\n}\n\nexport type RespondMode = \"must_respond\" | \"auto\" | \"silent\";\n\nexport type RespondModality =\n | \"text\"\n | \"audio\"\n | \"vision\"\n | \"context_update\"\n | \"trigger\"\n | \"scene_metadata\";\n\nexport interface RespondModesConfig {\n text?: \"must_respond\";\n audio?: \"must_respond\";\n vision?: RespondMode;\n contextUpdate?: RespondMode;\n trigger?: RespondMode;\n sceneMetadata?: RespondMode;\n}\n\nexport interface VisionSamplingWindowConfig {\n count: number;\n intervalMs: number;\n}\n\nexport interface VisionInputConfig {\n /**\n * Enable unified vision context for this session.\n *\n * Defaults to true when enableVideo is true. Set false to keep the video\n * channel available while opting out of unified vision context.\n */\n enabled?: boolean;\n sampleIntervalSecs?: number;\n framesPerTurn?: number;\n bufferFrames?: number;\n samplingWindows?: VisionSamplingWindowConfig[];\n stalenessSeconds?: number;\n maxResolution?: number | null;\n replacePreviousVisionContext?: boolean;\n}\n\nexport interface VisionBufferStatus {\n enabled?: boolean;\n first_frame_pts?: number | null;\n last_frame_pts?: number | null;\n first_frame_index?: number | null;\n retained_frames?: number;\n buffer_frames?: number;\n frames_per_turn?: number;\n replace_previous_vision_context?: boolean;\n evicted_frames?: number;\n effective_fps?: number | null;\n selected_participant?: string | null;\n frames_admitted?: number;\n frames_dropped_foreign_source?: number;\n frames_dropped_inactive_source?: number;\n frames_dropped_rate_limited?: number;\n last_attach?: {\n vision_frames_attached?: number;\n vision_image_tokens_est?: number;\n vision_detail_level?: string | null;\n vision_attach_outcome?: string;\n vision_source_participant?: string | null;\n attached_frame_pts?: number[];\n };\n}\n\nexport interface VisionStatusOptions {\n updateId?: string;\n}\n\nexport interface VisionTriggerOptions {\n updateId?: string;\n text?: string;\n respondMode?: RespondMode;\n frameIndices?: [number, number];\n frameIds?: number[];\n}\n\nexport interface RespondModeUpdateOptions {\n updateId?: string;\n modality: RespondModality;\n mode: RespondMode;\n}\n\nexport interface UpdateSceneMetadataOptions {\n respondMode?: RespondMode;\n}\n\nexport type VisionSourceKind =\n | \"webcam\"\n | \"canvas\"\n | \"screen\"\n | \"custom\"\n // Backward-compatible aliases accepted by the existing SDK surface.\n | \"camera\"\n | \"screen_share\"\n | \"unknown\";\n\nexport interface VisionSourceState {\n active: boolean;\n source: VisionSourceKind | null;\n sourceName: string | null;\n trackState: MediaStreamTrackState | null;\n transport?: \"livekit\" | \"websocket\";\n reason?: string;\n}\n\nexport interface PublishCanvasOptions {\n fps?: number;\n name?: string;\n source?: VisionSourceKind;\n stopTrackOnUnpublish?: boolean;\n}\n\nexport interface PublishVideoTrackOptions {\n name?: string;\n source?: VisionSourceKind;\n /** WebSocket transport frame publish cadence. LiveKit publishes the track continuously. */\n fps?: number;\n stopTrackOnUnpublish?: boolean;\n}\n\nexport interface VisionSourceHandle {\n track: MediaStreamTrack;\n publication?: unknown;\n transport?: \"livekit\" | \"websocket\";\n sourceName: string;\n source: VisionSourceKind;\n stopTrackOnUnpublish: boolean;\n unpublish: () => Promise<void>;\n cleanup?: () => void;\n}\n\n/**\n * Audio processing settings for the microphone input.\n * These settings help optimize the audio quality and reduce interruptions.\n * @internal - This is a fixed configuration and should not be modified by users\n */\nexport interface AudioSettings {\n /** Enable echo cancellation to prevent audio feedback (default: true) */\n echoCancellation?: boolean;\n /** Enable noise suppression to reduce background noise (default: true) */\n noiseSuppression?: boolean;\n /** Enable automatic gain control for consistent volume (default: true) */\n autoGainControl?: boolean;\n /** Audio sample rate in Hz (default: 48000) */\n sampleRate?: number;\n /** Number of audio channels, 1 for mono, 2 for stereo (default: 1) */\n channelCount?: number;\n}\n\n/**\n * Configuration object for connecting to a Convai character.\n * \n * @example\n * ```typescript\n * const config: ConvaiConfig = {\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: 'user-uuid', // Optional: enables long-term memory and analytics\n * enableVideo: false, // If false, connection_type will be \"audio\"\n * };\n * ```\n */\nexport interface ConvaiConfig {\n /** Your Convai API key or Auth Token (at least one is required) */\n apiKey?: string;\n authToken?: string;\n /** The Character ID to connect to (required) */\n characterId: string;\n /** Temporary character state of mind sent as `state_of_mind` on connect. */\n stateOfMind?: string | null;\n /**\n * Stable identifier for the end user (optional).\n *\n * Any non-empty string is accepted. Use a value that uniquely identifies the\n * user across sessions — a UUID or email address are the most common choices:\n *\n * ```ts\n * endUserId: 'a1b2c3d4-...' // UUID (preferred)\n * endUserId: 'user@example.com' // email\n * endUserId: 'device-fingerprint' // any stable unique string\n * ```\n *\n * When provided:\n * - Enables long-term memory: character remembers context from previous sessions\n * - Enables per-user analytics and engagement tracking\n *\n * When omitted the session is anonymous — no memory, no cross-session tracking.\n */\n endUserId?: string;\n /** Optional metadata object for the end user (sent as end_user_metadata to the API) */\n endUserMetadata?: Record<string, unknown>;\n /** Custom Convai API URL (optional, defaults to production endpoint) */\n url?: string;\n /** Transport layer to use. Default: \"livekit\". */\n transport?: \"livekit\" | \"websocket\" | \"sse\";\n /** SSE interaction endpoint. Supplying this also selects the SSE transport when transport is omitted. */\n interactionApiUrl?: string;\n /**\n * Character session ID (optional). Pass to resume an existing session;\n * otherwise populated from the connect API response after first connection.\n */\n characterSessionId?: string;\n /** \n * Enable video capability (default: false).\n * If true, connection_type will be \"video\" (supports audio, video, and screenshare).\n * If false, connection_type will be \"audio\" (audio only).\n */\n enableVideo?: boolean;\n /** \n * Start with video camera on when connecting (default: false).\n * Only works if enableVideo is true. If false, camera stays off until user enables it.\n */\n startWithVideoOn?: boolean;\n /** \n * Start with microphone on when connecting (default: false).\n * If false, microphone stays off until user enables it using audioControls.enableAudio().\n * Useful for text-only modes where you want to defer microphone permission until voice mode.\n */\n startWithAudioOn?: boolean;\n /**\n * Dynamic vision context controls for discrete vision-capable backends.\n * Defaults to enabled when enableVideo=true. Set\n * visionInputConfig.enabled=false to opt out while keeping the video channel.\n */\n visionInputConfig?: VisionInputConfig;\n /** Connect-time respond-mode defaults by modality. */\n respondModes?: RespondModesConfig;\n /**\n * WebRTC ICE transport policy for the LiveKit connection (default: \"relay\").\n * \"relay\" forces TURN-only (reliable against Convai's hosted LiveKit which\n * provides TURN). Set \"all\" to also allow host/srflx candidates when the\n * LiveKit has no TURN server (e.g. local dev).\n */\n iceTransportPolicy?: RTCIceTransportPolicy;\n /** Enable text-to-speech audio generation (default: true) */\n ttsEnabled?: boolean;\n /** \n * Enable lipsync/facial animation blendshapes (default: false).\n * When true, sets blendshape_provider to \"neurosync\".\n * When false, sets blendshape_provider to \"none\" (no facial animation data).\n */\n enableLipsync?: boolean;\n /** Enable emotion detection and bot-emotion updates (default: false) */\n enableEmotion?: boolean;\n /** Blendshape configuration for facial animation format */\n blendshapeConfig?: {\n /** Format of blendshapes: \"arkit\" or \"mha\" (Meta Human Animation, default: \"mha\") */\n /**\n * Blendshape stream format (default: \"mha\"). Server-verified set:\n * - \"mha\" — 251 channels (Unreal MetaHuman Animation, CTRL_expressions_*)\n * - \"arkit\" — 61 channels (Apple ARKit names)\n * - \"cc4_extended\" — 170 channels (Reallusion CC4 ExpressionPlus)\n * - \"cc5_hd\" — accepted by the server but currently delivers no frames\n * - \"visemes\" — 15 channels (OVR viseme set)\n */\n format?: \"arkit\" | \"mha\" | \"cc4_extended\" | \"cc5_hd\" | \"visemes\";\n /** \n * Custom mapper function to transform incoming blendshapes.\n * Use this to map Convai blendshapes to your character's morph targets.\n * The function receives the raw blendshape array and should return a Float32Array.\n * \n * @example\n * ```typescript\n * import { createARKitNameMapper } from '@convai/web-sdk/lipsync-helpers';\n * \n * const mapper = createARKitNameMapper({\n * 'Character__Mouth_Open': ['Jaw_Open'],\n * 'Character__EyeL_Blink': ['Eye_Blink_L'],\n * }, 'optimized');\n * \n * const config = {\n * blendshapeConfig: {\n * format: 'arkit',\n * customMapper: mapper,\n * }\n * };\n * ```\n */\n customMapper?: (input: number[] | Float32Array) => Float32Array;\n /** \n * Buffer duration for blendshape frames in seconds (default: 1).\n * Controls how much time the server should wait after generating blendshapes before playing the audio.\n */\n frames_buffer_duration?: number;\n /**\n * Enable server ahead-delivery for NeuroSync chunks (default: true).\n *\n * Defaults to `true` when `enableLipsync` is on. The server may send\n * indexed blendshape chunks before audio playback, so use the SDK\n * BlendshapeQueue/player path, which handles owner-scoped cancellation and\n * buffered-frame drops on interruption.\n *\n * Set `false` to fall back to the legacy paced delivery path.\n */\n deliver_chunks_ahead?: boolean;\n /**\n * Requested ahead-delivery blendshape timeline FPS.\n * Applies to the ahead-delivery path, where chunks carry fps\n * metadata for the SDK player. The legacy paced path keeps its fixed 90fps\n * delivery cadence for backward compatibility while SDK playback remains on\n * the normal visual timeline.\n */\n output_fps?: number;\n };\n /** Emotion configuration for character emotional state (sent to server on connect) */\n emotionConfig?:\n | {\n /** LLM-based emotion detection — infers emotion from response context (default) */\n provider: \"llm\";\n }\n | {\n /** NRCLex word-level lexicon lookup */\n provider: \"nrclex\";\n /** Minimum word threshold for emotion detection */\n min_word_threshold?: number;\n /** Low intensity threshold (0–1) */\n low_intensity_threshold?: number;\n /** High intensity threshold (0–1) */\n high_intensity_threshold?: number;\n };\n /** Configuration for character actions and environmental context */\n actionConfig?: {\n /** List of action names the character can perform */\n actions: string[];\n /** Other characters present in the scene or conversation */\n characters: Array<{\n /** Character name */\n name: string;\n /** Character biography or description */\n bio: string;\n }>;\n /** Objects available in the scene or environment */\n objects: Array<{\n /** Object name */\n name: string;\n /** Object description or properties */\n description: string;\n }>;\n /** Name of the object the character is currently focused on. Must match one of objects[].name. */\n current_attention_object?: string;\n };\n /** \n * Dynamic contextual information about the current situation.\n * This can be updated during the conversation to provide real-time context.\n * Use the DynamicInfo type to pass flexible key-value pairs with a required \"text\" field.\n */\n dynamicInfo?: DynamicInfo;\n /**\n * Template key values for Narrative Design placeholder substitution,\n * sent as `narrative_template_keys` in the /connect request.\n *\n * Narrative Design section objectives and speak tags may contain\n * placeholders such as `{player_name}` or `{quest_item}`; they are replaced\n * with these values when the section is evaluated, so one narrative graph\n * can serve many personalized sessions. Keys are case-sensitive; missing\n * keys resolve to an empty string.\n *\n * To change the keys mid-session, call `updateTemplateKeys()` — it replaces\n * this same map at runtime (before the next trigger fires).\n *\n * @example\n * ```typescript\n * const client = new ConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * narrativeTemplateKeys: {\n * player_name: 'Alex',\n * location: 'Engineering Deck',\n * quest_item: 'oxygen generator',\n * },\n * });\n * ```\n */\n narrativeTemplateKeys?: Record<string, string>;\n /**\n * Keep dynamic info in context as a static prompt (default: false).\n * \n * When true:\n * - Dynamic info behaves as a static prompt sent to the LLM for that WebRTC connection\n * - Dynamic info persists throughout the session\n * - You need to set it again after disconnecting/reconnecting\n * \n * When false:\n * - Allows resetting and updating via updateContext() or updateDynamicInfo()\n * - Dynamic info can be changed during the session\n */\n keepInContext?: boolean;\n /** \n * Enable debug mode for additional logging and diagnostics (default: false).\n */\n debug?: boolean;\n /**\n * Log decoded RTVI data messages to the browser console (default: true).\n * Set to false to silence incoming and outgoing RTVI message logs.\n */\n logRtviMessages?: boolean;\n /** \n * Metadata about the invocation source and client information.\n * Used for analytics and debugging purposes.\n */\n invocationMetadata?: {\n /** Source of the invocation (e.g., \"web\", \"mobile\", \"unity\") */\n source?: string;\n /** Client SDK version */\n clientVersion?: string;\n /** Additional custom metadata */\n extraMetadata?: Record<string, unknown>;\n };\n}\n\n/** Optional metadata for a text interaction. */\nexport interface SendUserTextMessageOptions {\n /** Stable logical-turn identity used by clients that correlate responses. */\n logicalTurnId?: string;\n /** User-selected temporary emotion to apply before processing the text. */\n stateOfMind?: string | null;\n}\n\n/**\n * The body returned by POST /connect. The embed receives this from a\n * customer-hosted proxy route rather than fetching it directly.\n */\nexport interface ConnectionData {\n /** LiveKit room URL, or the WebSocket URL when the transport is websocket. */\n room_url: string;\n /** LiveKit access token. Absent on the WebSocket transport. */\n token?: string;\n character_session_id?: string;\n end_user_id?: string;\n end_user_metadata?: Record<string, unknown>;\n}\n\n/**\n * Represents a single message in the chat conversation.\n * Different message types are used for various parts of the conversation flow.\n */\nexport interface ChatMessage {\n /** Unique identifier for the message */\n id: string;\n /** \n * Type of message:\n * - `user`: User's sent message\n * - `convai`: Character's response\n * - `user-transcription`: Real-time speech-to-text from user\n * - `bot-llm-text`: Character's LLM-generated text (token-by-token streaming)\n * - `bot-output`: Aggregated bot output (sentence/word-level chunks with spoken status)\n * - `emotion`: Character's emotional state\n * - `behavior-tree`: Behavior tree response\n * - `action`: Action execution\n * - `bot-emotion`: Bot emotional response\n * - `user-llm-text`: User text processed by LLM\n * - `interrupt-bot`: Interrupt the bot's current response\n * - `idle-warning`: Server idle-timeout warning; `content` holds remaining seconds as a numeric string (e.g. `\"45\"`)\n * - `llm-no-response`: LLM deliberately did not respond (abstain); `content` is always `\"\"`\n */\n type: 'user' | 'convai' | 'emotion' | 'behavior-tree' | 'action' | 'user-transcription' | 'bot-llm-text' | 'bot-output' | 'bot-emotion' | 'user-llm-text' | 'interrupt-bot' | 'idle-warning' | 'llm-no-response';\n /** The text content of the message */\n content: string;\n /** ISO timestamp string of when the message was created */\n timestamp: string;\n /** Whether this message is still streaming (mutable); false when finalized */\n isStreaming?: boolean;\n}\n\n/**\n * Represents a single metrics event from the server.\n * Multiple metrics may be received during a conversation.\n */\nexport interface ConvaiMetrics {\n /** Raw metrics data from the server */\n data: Record<string, unknown>;\n /** Timestamp when the metrics were received */\n timestamp: string;\n /** Unique identifier for this metrics event */\n id: string;\n}\n\n/**\n * Represents the current state of the Convai client connection and activity.\n * Use this to provide UI feedback about the conversation state.\n * \n * @example\n * ```typescript\n * const { state } = convaiClient;\n * \n * if (state.isConnected) {\n * console.log('Connected to character');\n * }\n * \n * if (state.isSpeaking) {\n * console.log('Character is speaking');\n * }\n * \n * // Or use the combined state\n * console.log(state.agentState); // 'listening' | 'thinking' | 'speaking'\n * \n * // Access end user information\n * console.log(state.endUserId); // 'user@example.com'\n * console.log(state.endUserMetadata); // { name: 'John', age: '30' }\n * \n * // Access metrics for the current conversation\n * console.log(state.metrics); // Array of metrics events\n * \n * // Check disconnect reason\n * if (state.disconnectReason !== null) {\n * console.log('Disconnected due to:', state.disconnectReason);\n * }\n * ```\n */\nexport interface ConvaiClientState {\n /** Whether the client is currently connected to Convai */\n isConnected: boolean;\n /** Whether a connection attempt is in progress */\n isConnecting: boolean;\n /** True from user-started-speaking until user-stopped-speaking (user is speaking, bot is listening). Priority below isSpeaking. */\n isListening: boolean;\n /** Whether the character is processing/thinking about a response */\n isThinking: boolean;\n /** Whether the character is currently speaking */\n isSpeaking: boolean;\n /** \n * Combined state indicator for the character's current activity.\n * Priority: speaking > listening (user speaking) > thinking > connected.\n */\n agentState: 'disconnected' | 'connected' | 'listening' | 'thinking' | 'speaking';\n /** Current bot emotion (name and optional scale). Updated when bot-emotion messages are received. */\n emotion: { emotion: string; scale?: number } | null;\n /** \n * End user ID returned from the connection response.\n * This is the actual end user ID used by the server (may differ from the one provided in config).\n */\n endUserId: string | null;\n /** \n * End user metadata returned from the connection response.\n * Contains additional information about the end user.\n */\n endUserMetadata: Record<string, unknown> | null;\n /** \n * Array of metrics events received during the current session.\n * Multiple metrics may be received per conversation.\n * Clears when resetSession() is called.\n */\n metrics: ConvaiMetrics[];\n /** \n * Disconnect reason from LiveKit when disconnected.\n * null when connected, otherwise contains the reason code.\n * Use this to differentiate between client-initiated disconnects and network/server issues.\n * \n * Notable reasons:\n * - CLIENT_INITIATED (1): User disconnected intentionally\n * - DUPLICATE_IDENTITY (2): Another client with same identity joined\n * - SERVER_SHUTDOWN (3): Server shutting down\n * - PARTICIPANT_REMOVED (4): Removed by API\n * - ROOM_DELETED (5): Room was ended\n * \n * Non-CLIENT_INITIATED reasons may indicate network disruptions where reconnection is appropriate.\n * \n * @see DisconnectReason\n */\n disconnectReason: DisconnectReason | null;\n}\n\n/**\n * Audio control interface for managing microphone\n */\nexport interface AudioControls {\n isAudioEnabled: boolean;\n isAudioMuted: boolean;\n audioLevel: number;\n enableAudio: () => Promise<void>;\n disableAudio: () => Promise<void>;\n muteAudio: () => Promise<void>;\n unmuteAudio: () => Promise<void>;\n toggleAudio: () => Promise<void>;\n setAudioDevice: (deviceId: string) => Promise<void>;\n getAudioDevices: () => Promise<MediaDeviceInfo[]>;\n startAudioLevelMonitoring: () => void;\n stopAudioLevelMonitoring: () => void;\n // EventEmitter methods for React integration\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n\n/**\n * Video control interface for managing camera\n */\nexport interface VideoControls {\n isVideoEnabled: boolean;\n isVideoHidden: boolean;\n activeVisionSource: VisionSourceHandle | null;\n hasActiveVisionSource: boolean;\n visionSourceState: VisionSourceState;\n enableVideo: () => Promise<void>;\n disableVideo: () => Promise<void>;\n hideVideo: () => Promise<void>;\n showVideo: () => Promise<void>;\n toggleVideo: () => Promise<void>;\n setVideoDevice: (deviceId: string) => Promise<void>;\n getVideoDevices: () => Promise<MediaDeviceInfo[]>;\n setVideoQuality: (quality: 'low' | 'medium' | 'high') => Promise<void>;\n publishCanvas: (\n canvas: HTMLCanvasElement,\n options?: PublishCanvasOptions,\n ) => Promise<VisionSourceHandle>;\n publishVideoTrack: (\n track: MediaStreamTrack,\n options?: PublishVideoTrackOptions,\n ) => Promise<VisionSourceHandle>;\n unpublishVisionSource: (\n source?: VisionSourceHandle | MediaStreamTrack,\n ) => Promise<void>;\n // EventEmitter methods for React integration\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n\n/**\n * Screen share control interface\n */\nexport interface ScreenShareControls {\n isScreenShareEnabled: boolean;\n isScreenShareActive: boolean;\n enableScreenShare: () => Promise<void>;\n disableScreenShare: () => Promise<void>;\n toggleScreenShare: () => Promise<void>;\n enableScreenShareWithAudio: () => Promise<void>;\n getScreenShareTracks: () => Promise<any[]>;\n // EventEmitter methods for React integration\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n\n/**\n * Main Convai client interface.\n * Provides complete control over Convai character connections and interactions.\n * \n * @example\n * ```typescript\n * import { ConvaiClient } from '@convai/web-sdk/core';\n * \n * const client = new ConvaiClient();\n * \n * // Connect to character\n * await client.connect({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: '-1' // Dev mode\n * });\n * \n * // Send a message\n * client.sendUserTextMessage('Hello!');\n * \n * // Listen for state changes\n * client.on('stateChange', (state) => {\n * console.log('State:', state);\n * });\n * \n * // Listen for messages\n * client.on('message', (message) => {\n * console.log('New message:', message);\n * });\n * ```\n */\n/**\n * Memory API Types\n * Types for Convai's long-term memory management APIs\n */\n\n/**\n * Memory object returned from the API\n */\nexport interface Memory {\n /** Unique memory identifier (UUID) */\n id: string;\n /** Memory text content */\n memory: string;\n /** ISO timestamp when the memory was created */\n created_at: string;\n /** ISO timestamp when the memory was last updated */\n updated_at: string;\n}\n\n/**\n * Memory event object from add operation\n */\nexport interface MemoryAddEvent {\n /** Memory identifier */\n id: string;\n /** Event type (always \"ADD\" for add operations) */\n event: 'ADD';\n /** Memory text content */\n memory: string;\n}\n\n/**\n * Request to add memories\n */\nexport interface MemoryAddRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Array of memory strings to add */\n memories: string[];\n}\n\n/**\n * Response from add memories operation\n */\nexport interface MemoryAddResponse {\n /** Array of added memories with their IDs */\n memories: MemoryAddEvent[];\n}\n\n/**\n * Request to list memories with pagination\n */\nexport interface MemoryListRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Page number (default: 1, clamped to 1-1000) */\n page?: number;\n /** Number of memories per page (default: 50, clamped to 1-100) */\n page_size?: number;\n}\n\n/**\n * Response from list memories operation\n */\nexport interface MemoryListResponse {\n /** Array of memories */\n memories: Memory[];\n /** Total count of memories for this character/user pair */\n total_count: number;\n /** Current page number */\n page: number;\n /** Number of memories per page */\n page_size: number;\n /** Whether there are more pages available */\n has_more: boolean;\n}\n\n/**\n * Request to get a single memory\n */\nexport interface MemoryGetRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Memory UUID to fetch */\n memory_id: string;\n}\n\n/**\n * Response from get memory operation\n */\nexport type MemoryGetResponse = Memory;\n\n/**\n * Request to delete a memory\n */\nexport interface MemoryDeleteRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Memory UUID to delete */\n memory_id: string;\n}\n\n/**\n * Response from delete memory operation\n */\nexport interface MemoryDeleteResponse {\n /** Success message */\n message: string;\n /** Memory ID that was deleted */\n memory_id: string;\n /** Whether the memory was successfully deleted */\n deleted: boolean;\n}\n\n/**\n * Request to delete all memories\n */\nexport interface MemoryDeleteAllRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n}\n\n/**\n * Response from delete all memories operation\n */\nexport interface MemoryDeleteAllResponse {\n /** Status message (deletion is asynchronous) */\n message: string;\n /** Character ID for which memories are being deleted */\n character_id: string;\n /** End user ID for which memories are being deleted */\n end_user_id: string;\n}\n\n/**\n * Error response from Memory API\n */\nexport interface MemoryError {\n /** Error message */\n ERROR: string;\n /** Transaction reference ID for debugging */\n 'Reference ID': string;\n}\n\nexport interface IConvaiClient {\n /** Current connection and activity state of the client */\n readonly state: ConvaiClientState;\n \n /** \n * Connection type: \"audio\" (audio only) or \"video\" (audio + video + screenshare).\n * Set based on enableVideo in connect config.\n */\n readonly connectionType: 'audio' | 'video' | null;\n \n /** API key used for the current connection, if apiKey was used (null otherwise) */\n readonly apiKey?: string | null;\n\n /** Auth token used for the current connection, if authToken was used (null otherwise) */\n readonly authToken?: string | null;\n\n /** Character ID used for the current connection (null if not connected) */\n readonly characterId: string | null;\n \n /** Internal LiveKit Room instance (for advanced usage) */\n readonly room: Room;\n \n /** Array of all chat messages in the current conversation */\n readonly chatMessages: ChatMessage[];\n \n /** Current real-time transcription of user speech */\n readonly userTranscription: string;\n \n /** Unique session ID for the current character conversation */\n readonly characterSessionId: string | null;\n \n /** Whether the bot is ready to receive messages (true after bot-ready message) */\n readonly isBotReady: boolean;\n \n /** Audio control methods for managing microphone mute/unmute */\n readonly audioControls: AudioControls;\n \n /** Video control methods for enabling/disabling camera */\n readonly videoControls: VideoControls;\n \n /** Screen sharing control methods */\n readonly screenShareControls: ScreenShareControls;\n \n /** Blendshape queue for time-based lipsync synchronization */\n readonly blendshapeQueue: BlendshapeQueue;\n \n /** Incremental turn session ID used by conversation events (e.g. conversationStart, turnEnd) */\n readonly conversationSessionId: number;\n \n /** \n * Memory manager for long-term memory operations.\n * Returns null if no API key or end user ID is available.\n * \n * @example\n * ```typescript\n * const memoryManager = client.memoryManager;\n * if (memoryManager) {\n * const memories = await memoryManager.listMemories();\n * }\n * ```\n */\n readonly memoryManager: import('./MemoryManager').MemoryManager | null;\n \n /** \n * Connect to a Convai character.\n */\n connect: (config?: ConvaiConfig) => Promise<void>;\n \n /**\n * Complete a connection from an already-fetched /connect response body.\n *\n * `connect()` fetches /connect and then calls this internally. Call it\n * directly when the response was obtained elsewhere — a server-side session\n * manager, or the embed's connect-proxy flow, where the API key must never\n * reach the browser.\n *\n * @example\n * // Server (customer's backend): holds the API key, calls Convai's\n * // /connect, and relays the response body verbatim.\n * // Browser: never sees the API key, only the relayed response.\n * const data = await fetch('/api/convai-connect', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ characterId: 'your-character-id' }),\n * }).then(r => r.json())\n * await client.connectWithConnectionData(data)\n */\n connectWithConnectionData: (data: ConnectionData, config?: ConvaiConfig) => Promise<void>;\n\n /** Disconnect from the current character session */\n disconnect: () => Promise<void>;\n \n /** Reconnect - disconnect and connect again using stored config */\n reconnect: () => Promise<void>;\n \n /** Reset the session ID to start a new conversation (clears history) */\n resetSession: () => void;\n \n /** Send a text message to the character */\n sendUserTextMessage: (text: string, options?: SendUserTextMessageOptions) => void;\n \n /** \n * Send a trigger message to invoke specific character actions or responses.\n * @param triggerName - Name of the trigger to invoke\n * @param triggerMessage - Optional message to accompany the trigger\n */\n sendTriggerMessage: (triggerName?: string, triggerMessage?: string) => void;\n \n /**\n * Send an interrupt message to stop the bot's current response.\n * This can be used to interrupt the bot when the user wants to speak.\n */\n sendInterruptMessage: () => void;\n\n /**\n * Reset the server-side idle timer.\n * Call this on any user activity (clicks, UI interactions, etc.) to prevent\n * the session from being disconnected due to inactivity.\n * The server sends `user-idle-warning` events (via the `idleWarning` event) before\n * disconnecting; use this method to keep the session alive.\n */\n resetIdleTimer: () => void;\n \n /**\n * Replace the Narrative Design template keys on the live session.\n *\n * These are the same keys as the `narrativeTemplateKeys` config option\n * (which seeds them at `/connect`) — this method REPLACES the entire map\n * at runtime, so include every key you still need. New values apply when\n * the next section objective or speak tag is evaluated (i.e. set them\n * before firing the next narrative trigger).\n *\n * Requires a character with Narrative Design enabled; otherwise the server\n * acks `update-template-keys` with error \"Narrative design service not\n * available\". Placeholders use single braces (`{player_name}`), keys are\n * case-sensitive, and missing keys resolve to an empty string.\n *\n * @example\n * ```typescript\n * client.updateTemplateKeys({ player_name: 'Aria', quest_item: 'lantern' });\n * client.sendTriggerMessage('QuestUpdate');\n * ```\n */\n updateTemplateKeys: (templateKeys: { [key: string]: string }) => void;\n \n /** \n * Update dynamic information about the current context.\n * This helps the character understand the current situation.\n * Pass any key-value pairs you want, but \"text\" field is required.\n */\n updateDynamicInfo: (dynamicInfo: DynamicInfo) => void;\n \n /**\n * Update the bot's temporary runtime context in a unified way.\n * Provides flexible control over ephemeral context management.\n * \n * @param options - Context update configuration\n * \n * @example\n * ```typescript\n * // Append to context\n * client.updateContext({ \n * text: \"User completed quest\", \n * mode: \"append\",\n * run_llm: \"false\"\n * });\n * \n * // Replace context\n * client.updateContext({ \n * text: \"New game state\", \n * mode: \"replace\",\n * run_llm: \"auto\"\n * });\n * \n * // Clear context\n * client.updateContext({ mode: \"reset\" });\n * ```\n */\n updateContext: (options: ContextUpdateOptions) => void;\n\n /** Request a server ack containing the current vision buffer status. */\n visionStatus: (options?: VisionStatusOptions) => string | null;\n\n /** Attach buffered frames and optionally trigger a response. */\n visionTrigger: (options?: VisionTriggerOptions) => string | null;\n\n /** Update a session respond-mode default. */\n respondModeUpdate: (options: RespondModeUpdateOptions) => string | null;\n\n /**\n * Set or clear the character's temporary state of mind without triggering a response.\n * Pass `null` (or `\"neutral\"`) to clear it.\n */\n updateEmotion: (stateOfMind: string | null) => void;\n\n /**\n * Send descriptive scene updates so the bot knows what is visible or nearby.\n * Does not modify actionConfig.\n */\n updateSceneMetadata: (\n items: Array<{ name: string; description: string }>,\n options?: UpdateSceneMetadataOptions,\n ) => void;\n\n /**\n * Toggle text-to-speech on or off.\n * When disabled, character responses won't be spoken aloud.\n */\n toggleTts: (enabled: boolean) => void;\n \n /** \n * Toggle speech-to-text on or off.\n * When enabled, user speech is transcribed to text (e.g. for dictation).\n * When disabled, STT is off.\n */\n toggleStt: (enabled: boolean) => void;\n\n /**\n * Upload a file to the character via the LiveKit byte stream transport.\n * Only works when connected with the LiveKit transport.\n *\n * @param file - The File object to send\n * @param options - Optional upload options\n * @returns Promise that resolves when the upload is complete\n *\n * @example\n * ```typescript\n * await client.uploadFile(file, {\n * topic: 'file-upload',\n * onProgress: (pct) => console.log(`${pct}% uploaded`),\n * });\n * ```\n */\n uploadFile: (file: File, options?: UploadFileOptions) => Promise<void>;\n\n /**\n * Subscribe to an event\n * @param event Event name ('stateChange', 'message', 'connect', 'disconnect', 'error')\n * @param callback Callback function\n * @returns Unsubscribe function\n */\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n \n /**\n * Unsubscribe from an event\n * @param event Event name\n * @param callback Callback function to remove\n */\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,cAAc,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC;IACnB,kBAAkB,EAAE,CAAC;IACrB,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,CAAC;IACtB,YAAY,EAAE,CAAC;IACf,cAAc,EAAE,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;CACP,CAAC;AAEX;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAA+B;IACxE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,oBAAoB,CAAC,cAAc;YACtC,OAAO,sCAAsC,CAAC;QAChD,KAAK,oBAAoB,CAAC,gBAAgB;YACxC,OAAO,mBAAmB,CAAC;QAC7B,KAAK,oBAAoB,CAAC,kBAAkB;YAC1C,OAAO,0CAA0C,CAAC;QACpD,KAAK,oBAAoB,CAAC,eAAe;YACvC,OAAO,yBAAyB,CAAC;QACnC,KAAK,oBAAoB,CAAC,mBAAmB;YAC3C,OAAO,kCAAkC,CAAC;QAC5C,KAAK,oBAAoB,CAAC,YAAY;YACpC,OAAO,+BAA+B,CAAC;QACzC,KAAK,oBAAoB,CAAC,cAAc;YACtC,OAAO,gBAAgB,CAAC;QAC1B,KAAK,oBAAoB,CAAC,YAAY;YACpC,OAAO,gBAAgB,CAAC;QAC1B,KAAK,oBAAoB,CAAC,SAAS;YACjC,OAAO,qCAAqC,CAAC;QAC/C,KAAK,oBAAoB,CAAC,YAAY;YACpC,OAAO,0BAA0B,CAAC;QACpC;YACE,OAAO,cAAc,CAAC;IAC1B,CAAC;AACH,CAAC","sourcesContent":["import { Room, DisconnectReason as LiveKitDisconnectReason } from 'livekit-client';\nimport type { CharacterVersionSelector } from \"./characterReference\";\nexport type { CharacterVersionSelector, CharacterReference } from \"./characterReference\";\nimport { BlendshapeQueue } from './BlendshapeQueue';\n\n/**\n * LiveKit disconnect reasons.\n * Helps determine why a participant was disconnected from the room.\n * \n * These values map to LiveKit's DisconnectReason enum:\n * - UNKNOWN_REASON (0): Unknown disconnect reason\n * - CLIENT_INITIATED (1): Client called disconnect() - intentional disconnect\n * - DUPLICATE_IDENTITY (2): Another client with the same identity joined the room\n * - SERVER_SHUTDOWN (3): LiveKit server is shutting down\n * - PARTICIPANT_REMOVED (4): Participant was removed by RemoveParticipant API\n * - ROOM_DELETED (5): Room was ended via DeleteRoom API\n * - STATE_MISMATCH (6): State mismatch between client and server\n * - JOIN_FAILURE (7): Failed to join the room\n * - MIGRATION (8): Participant moved to a different room\n * - SIGNAL_CLOSE (9): Signal connection was closed\n * \n * @see https://docs.livekit.io/reference/client-sdk-js/enums/DisconnectReason.html\n */\nexport type DisconnectReason = LiveKitDisconnectReason;\n\n/**\n * Export LiveKit's DisconnectReason enum values for easy access\n */\nexport const DisconnectReasonEnum = {\n UNKNOWN_REASON: 0,\n CLIENT_INITIATED: 1,\n DUPLICATE_IDENTITY: 2,\n SERVER_SHUTDOWN: 3,\n PARTICIPANT_REMOVED: 4,\n ROOM_DELETED: 5,\n STATE_MISMATCH: 6,\n JOIN_FAILURE: 7,\n MIGRATION: 8,\n SIGNAL_CLOSE: 9,\n} as const;\n\n/**\n * Get a human-readable message for a disconnect reason.\n * \n * @param reason - The disconnect reason code from LiveKit\n * @returns A human-readable message describing the disconnect reason\n * \n * @example\n * ```typescript\n * client.on('disconnect', (reason) => {\n * console.log(getDisconnectReasonMessage(reason));\n * // Output: \"User disconnected\"\n * });\n * ```\n */\nexport function getDisconnectReasonMessage(reason: DisconnectReason | null): string {\n if (reason === null) {\n return 'Connected';\n }\n\n switch (reason) {\n case DisconnectReasonEnum.UNKNOWN_REASON:\n return 'Network unavailable or unknown cause';\n case DisconnectReasonEnum.CLIENT_INITIATED:\n return 'User disconnected';\n case DisconnectReasonEnum.DUPLICATE_IDENTITY:\n return 'Another client with same identity joined';\n case DisconnectReasonEnum.SERVER_SHUTDOWN:\n return 'Server is shutting down';\n case DisconnectReasonEnum.PARTICIPANT_REMOVED:\n return 'Removed by RemoveParticipant API';\n case DisconnectReasonEnum.ROOM_DELETED:\n return 'Room ended via DeleteRoom API';\n case DisconnectReasonEnum.STATE_MISMATCH:\n return 'State mismatch';\n case DisconnectReasonEnum.JOIN_FAILURE:\n return 'Failed to join';\n case DisconnectReasonEnum.MIGRATION:\n return 'Participant moved to different room';\n case DisconnectReasonEnum.SIGNAL_CLOSE:\n return 'Signal connection closed';\n default:\n return 'Disconnected';\n }\n}\n\n/**\n * Dynamic information structure for passing real-time context to the character.\n * Pass a text description of the current dynamic context.\n * \n * @example\n * ```typescript\n * const dynamicInfo = \"Player health is low, in combat mode\";\n * ```\n */\nexport type DynamicInfo = string;\n\n/**\n * Minimal contract that ConvaiClient and AudioManager require from a WebSocket\n * session implementation. Defined here so core has zero import dependency on\n * the pipecat packages — the concrete class lives in the vanilla/websocket subpath.\n */\nexport interface IWebSocketSession {\n readonly isConnected: boolean;\n connectWithUrl(wsUrl: string): Promise<void>;\n disconnect(): Promise<void>;\n sendMessage(type: string, data: unknown): void;\n enableMic(enable: boolean): void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n on(event: string, listener: (...args: any[]) => void): () => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n off(event: string, listener: (...args: any[]) => void): void;\n}\n\n/**\n * Factory function signature used to register a WebSocket transport implementation\n * via {@link ConvaiClient.registerWebSocketTransport}. Import\n * `@convai/web-sdk/vanilla/websocket` (or `@convai/web-sdk/react/websocket`) as a\n * side-effect to register the default Pipecat-based implementation.\n */\nexport type WebSocketSessionFactory = (\n onMessage: (payload: Uint8Array) => void,\n enableMic: boolean,\n) => IWebSocketSession;\n\n/**\n * Options for {@link IConvaiClient.uploadFile}.\n *\n * Supported formats: JPEG, PNG, GIF, WebP. Maximum file size: 10 MB.\n * Files are sent as raw binary over the WebRTC byte stream — not base64 encoded.\n */\nexport interface UploadFileOptions {\n /** Server routing topic. Defaults to `'file-upload'`. */\n topic?: string;\n /**\n * Progress callback. Called with an integer percentage (0–100) as the upload proceeds.\n */\n onProgress?: (progressPercent: number) => void;\n}\n\n/**\n * Extra data returned in a server-response for specific event types.\n */\nexport interface ServerResponseExtras {\n // context-update extras\n token_count?: number;\n static_token_count?: number;\n runtime_token_count?: number;\n max_tokens?: number;\n static_max_tokens?: number;\n runtime_max_tokens?: number;\n remaining_tokens?: number;\n /** Full retained runtime dynamic context text after the update */\n content?: string;\n // tts-toggle extras\n enabled?: boolean;\n // stt-toggle extras\n muted?: boolean;\n // trigger-message extras\n trigger_name?: string;\n has_speak_tag?: boolean;\n // user_text_message extras\n text?: string;\n // kill-pipeline extras\n room_name?: string;\n // unknown-message-type error extras\n supported_types?: string[];\n // vision-status / vision-trigger extras\n vision_buffer?: VisionBufferStatus;\n requested_respond_mode?: RespondMode;\n actual_respond_mode?: RespondMode;\n requested_run_llm?: \"true\" | \"false\" | \"auto\";\n actual_run_llm?: \"true\" | \"false\" | \"auto\";\n llm_triggered?: boolean;\n downgraded?: boolean;\n downgrade_reason?: string | null;\n interrupted?: boolean;\n vision_frames_attached?: number;\n vision_image_tokens_est?: number;\n vision_detail_level?: string | null;\n vision_attach_outcome?: string;\n vision_source_participant?: string | null;\n attached_frame_pts?: number[];\n frame_binding?: string;\n frame_binding_error?: string | null;\n requested_frame_indices?: [number, number] | number[] | null;\n requested_frame_ids?: number[] | null;\n frame_indices_clamped?: boolean;\n frame_ids_stale_exempt?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Acknowledgment sent by the server for every client-to-server message.\n * Analogous to an HTTP response: use `status` to check success/failure and\n * `extras` for event-specific data such as context token counts.\n *\n * @example\n * ```typescript\n * client.on('serverResponse', (response) => {\n * if (response.event_type === 'context-update') {\n * const { remaining_tokens, max_tokens } = response.extras ?? {};\n * console.log(`Tokens remaining: ${remaining_tokens} / ${max_tokens}`);\n * }\n * if (response.status === 'error') {\n * console.error('Server error:', response.message);\n * }\n * });\n * ```\n */\nexport interface ServerResponse {\n /** The original client message type that triggered this response */\n event_type: string;\n /** Processing status */\n status: 'success' | 'error' | 'processing' | 'pending';\n /** Human-readable description of the result */\n message: string | null;\n /** Additional event-specific data */\n extras: ServerResponseExtras | null;\n}\n\n/**\n * Emitted when the server assigns an interaction ID to the session.\n * Store the interactionId for analytics or session tracking.\n */\nexport interface InteractionCreated {\n /** Unique identifier for this interaction session */\n interactionId: string;\n /** Character session identifier */\n characterSessionId: string;\n}\n\n/**\n * A single action the character performs, emitted via the `actionResponse`\n * event. When `target` is present the action is *parameterized* (the character\n * acts on a specific object/character); simple actions (e.g. `\"Wave\"`) omit it.\n */\nexport interface ConvaiAction {\n /** Base action name, e.g. `\"Move To\"`, `\"Pick Up\"`, `\"Wave\"`. */\n name: string;\n /**\n * The object or character the action targets — must match a name from\n * `actionConfig.objects[]` / `actionConfig.characters[]`. Absent for simple\n * (non-parameterized) actions.\n */\n target?: string;\n}\n\n/**\n * Payload of the `actionResponse` event. Actions execute sequentially; an\n * empty array is a valid \"no action\" turn.\n */\nexport interface ActionResponseEvent {\n actions: ConvaiAction[];\n}\n\n/**\n * Options for updating the bot's temporary runtime context.\n * Provides flexible control over how context is managed during conversation.\n * \n * @example\n * ```typescript\n * // Append to existing context\n * client.updateContext({\n * text: \"User just completed dragon quest\",\n * mode: \"append\",\n * run_llm: \"false\"\n * });\n * \n * // Replace entire context\n * client.updateContext({\n * text: \"New game state: level 5, combat mode\",\n * mode: \"replace\",\n * run_llm: \"auto\"\n * });\n * \n * // Reset/clear context\n * client.updateContext({\n * mode: \"reset\"\n * });\n * ```\n */\nexport interface ContextUpdateOptions {\n /**\n * The context text to inject.\n * Required unless mode is \"reset\" or only current_attention_object is being updated.\n */\n text?: string;\n /**\n * How to apply the context:\n * - \"append\" (default): Add text to existing ephemeral context\n * - \"replace\": Replace existing ephemeral context with new text\n * - \"reset\": Clear ephemeral context; text is optional\n */\n mode?: \"append\" | \"replace\" | \"reset\";\n /**\n * Whether to trigger LLM response:\n * - \"true\": Always trigger a response from the bot and preempt active local playback\n * - \"false\": Never trigger a response\n * - \"auto\" (default): Server decides based on context without preempting active playback\n */\n run_llm?: \"true\" | \"false\" | \"auto\";\n /**\n * Optional respond-mode alias for backends that expose unified respond modes.\n * If `run_llm` is provided, it takes precedence.\n */\n respond_mode?: RespondMode;\n /**\n * The object the character should currently focus on.\n * Must match one of action_config.objects[].name.\n * Pass an empty string to clear current attention.\n */\n current_attention_object?: string;\n}\n\nexport type RespondMode = \"must_respond\" | \"auto\" | \"silent\";\n\nexport type RespondModality =\n | \"text\"\n | \"audio\"\n | \"vision\"\n | \"context_update\"\n | \"trigger\"\n | \"scene_metadata\";\n\nexport interface RespondModesConfig {\n text?: \"must_respond\";\n audio?: \"must_respond\";\n vision?: RespondMode;\n contextUpdate?: RespondMode;\n trigger?: RespondMode;\n sceneMetadata?: RespondMode;\n}\n\nexport interface VisionSamplingWindowConfig {\n count: number;\n intervalMs: number;\n}\n\nexport interface VisionInputConfig {\n /**\n * Enable unified vision context for this session.\n *\n * Defaults to true when enableVideo is true. Set false to keep the video\n * channel available while opting out of unified vision context.\n */\n enabled?: boolean;\n sampleIntervalSecs?: number;\n framesPerTurn?: number;\n bufferFrames?: number;\n samplingWindows?: VisionSamplingWindowConfig[];\n stalenessSeconds?: number;\n maxResolution?: number | null;\n replacePreviousVisionContext?: boolean;\n}\n\nexport interface VisionBufferStatus {\n enabled?: boolean;\n first_frame_pts?: number | null;\n last_frame_pts?: number | null;\n first_frame_index?: number | null;\n retained_frames?: number;\n buffer_frames?: number;\n frames_per_turn?: number;\n replace_previous_vision_context?: boolean;\n evicted_frames?: number;\n effective_fps?: number | null;\n selected_participant?: string | null;\n frames_admitted?: number;\n frames_dropped_foreign_source?: number;\n frames_dropped_inactive_source?: number;\n frames_dropped_rate_limited?: number;\n last_attach?: {\n vision_frames_attached?: number;\n vision_image_tokens_est?: number;\n vision_detail_level?: string | null;\n vision_attach_outcome?: string;\n vision_source_participant?: string | null;\n attached_frame_pts?: number[];\n };\n}\n\nexport interface VisionStatusOptions {\n updateId?: string;\n}\n\nexport interface VisionTriggerOptions {\n updateId?: string;\n text?: string;\n respondMode?: RespondMode;\n frameIndices?: [number, number];\n frameIds?: number[];\n}\n\nexport interface RespondModeUpdateOptions {\n updateId?: string;\n modality: RespondModality;\n mode: RespondMode;\n}\n\nexport interface UpdateSceneMetadataOptions {\n respondMode?: RespondMode;\n}\n\nexport type VisionSourceKind =\n | \"webcam\"\n | \"canvas\"\n | \"screen\"\n | \"custom\"\n // Backward-compatible aliases accepted by the existing SDK surface.\n | \"camera\"\n | \"screen_share\"\n | \"unknown\";\n\nexport interface VisionSourceState {\n active: boolean;\n source: VisionSourceKind | null;\n sourceName: string | null;\n trackState: MediaStreamTrackState | null;\n transport?: \"livekit\" | \"websocket\";\n reason?: string;\n}\n\nexport interface PublishCanvasOptions {\n fps?: number;\n name?: string;\n source?: VisionSourceKind;\n stopTrackOnUnpublish?: boolean;\n}\n\nexport interface PublishVideoTrackOptions {\n name?: string;\n source?: VisionSourceKind;\n /** WebSocket transport frame publish cadence. LiveKit publishes the track continuously. */\n fps?: number;\n stopTrackOnUnpublish?: boolean;\n}\n\nexport interface VisionSourceHandle {\n track: MediaStreamTrack;\n publication?: unknown;\n transport?: \"livekit\" | \"websocket\";\n sourceName: string;\n source: VisionSourceKind;\n stopTrackOnUnpublish: boolean;\n unpublish: () => Promise<void>;\n cleanup?: () => void;\n}\n\n/**\n * Audio processing settings for the microphone input.\n * These settings help optimize the audio quality and reduce interruptions.\n * @internal - This is a fixed configuration and should not be modified by users\n */\nexport interface AudioSettings {\n /** Enable echo cancellation to prevent audio feedback (default: true) */\n echoCancellation?: boolean;\n /** Enable noise suppression to reduce background noise (default: true) */\n noiseSuppression?: boolean;\n /** Enable automatic gain control for consistent volume (default: true) */\n autoGainControl?: boolean;\n /** Audio sample rate in Hz (default: 48000) */\n sampleRate?: number;\n /** Number of audio channels, 1 for mono, 2 for stereo (default: 1) */\n channelCount?: number;\n}\n\n/**\n * Configuration object for connecting to a Convai character.\n * \n * @example\n * ```typescript\n * const config: ConvaiConfig = {\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: 'user-uuid', // Optional: enables long-term memory and analytics\n * enableVideo: false, // If false, connection_type will be \"audio\"\n * };\n * ```\n */\nexport interface ConvaiConfig {\n /** Your Convai API key or Auth Token (at least one is required) */\n apiKey?: string;\n authToken?: string;\n /**\n * The Character ID to connect to (required).\n *\n * May also carry a version selector suffix (`<uuid>-draft`, `<uuid>-latest`,\n * `<uuid>-1.2`); `characterVersion` is the clearer way to say the same thing.\n */\n characterId: string;\n /**\n * Which version of the character to run (optional).\n *\n * - `\"draft\"` — the editable draft, so you can test unreleased changes\n * - `\"latest\"` — the promoted latest release\n * - `\"1.2\"` / `\"1.2.3\"` — an immutable tagged version\n *\n * Omit it to let the runtime pick the effective latest revision, which is\n * also how characters that predate versioning behave. The selector is joined\n * to `characterId` on the wire as `<uuid>-<selector>`; `client.characterId`\n * keeps returning the bare UUID.\n *\n * @example\n * ```ts\n * const client = new ConvaiClient({\n * apiKey: 'YOUR_API_KEY',\n * characterId: 'YOUR_CHARACTER_ID',\n * characterVersion: 'draft',\n * });\n * ```\n */\n characterVersion?: CharacterVersionSelector | null;\n /**\n * Base URL of the Character REST platform used by `client.characterVersions`\n * (optional, defaults to `https://api2.convai.com`). Point it at\n * `https://api2-stg.convai.com` to author against staging.\n */\n characterApiUrl?: string;\n /** Temporary character state of mind sent as `state_of_mind` on connect. */\n stateOfMind?: string | null;\n /**\n * Stable identifier for the end user (optional).\n *\n * Any non-empty string is accepted. Use a value that uniquely identifies the\n * user across sessions — a UUID or email address are the most common choices:\n *\n * ```ts\n * endUserId: 'a1b2c3d4-...' // UUID (preferred)\n * endUserId: 'user@example.com' // email\n * endUserId: 'device-fingerprint' // any stable unique string\n * ```\n *\n * When provided:\n * - Enables long-term memory: character remembers context from previous sessions\n * - Enables per-user analytics and engagement tracking\n *\n * When omitted the session is anonymous — no memory, no cross-session tracking.\n */\n endUserId?: string;\n /** Optional metadata object for the end user (sent as end_user_metadata to the API) */\n endUserMetadata?: Record<string, unknown>;\n /** Custom Convai API URL (optional, defaults to production endpoint) */\n url?: string;\n /** Transport layer to use. Default: \"livekit\". */\n transport?: \"livekit\" | \"websocket\" | \"sse\";\n /** SSE interaction endpoint. Supplying this also selects the SSE transport when transport is omitted. */\n interactionApiUrl?: string;\n /**\n * Character session ID (optional). Pass to resume an existing session;\n * otherwise populated from the connect API response after first connection.\n */\n characterSessionId?: string;\n /** \n * Enable video capability (default: false).\n * If true, connection_type will be \"video\" (supports audio, video, and screenshare).\n * If false, connection_type will be \"audio\" (audio only).\n */\n enableVideo?: boolean;\n /** \n * Start with video camera on when connecting (default: false).\n * Only works if enableVideo is true. If false, camera stays off until user enables it.\n */\n startWithVideoOn?: boolean;\n /** \n * Start with microphone on when connecting (default: false).\n * If false, microphone stays off until user enables it using audioControls.enableAudio().\n * Useful for text-only modes where you want to defer microphone permission until voice mode.\n */\n startWithAudioOn?: boolean;\n /**\n * Dynamic vision context controls for discrete vision-capable backends.\n * Defaults to enabled when enableVideo=true. Set\n * visionInputConfig.enabled=false to opt out while keeping the video channel.\n */\n visionInputConfig?: VisionInputConfig;\n /** Connect-time respond-mode defaults by modality. */\n respondModes?: RespondModesConfig;\n /**\n * WebRTC ICE transport policy for the LiveKit connection (default: \"relay\").\n * \"relay\" forces TURN-only (reliable against Convai's hosted LiveKit which\n * provides TURN). Set \"all\" to also allow host/srflx candidates when the\n * LiveKit has no TURN server (e.g. local dev).\n */\n iceTransportPolicy?: RTCIceTransportPolicy;\n /** Enable text-to-speech audio generation (default: true) */\n ttsEnabled?: boolean;\n /** \n * Enable lipsync/facial animation blendshapes (default: false).\n * When true, sets blendshape_provider to \"neurosync\".\n * When false, sets blendshape_provider to \"none\" (no facial animation data).\n */\n enableLipsync?: boolean;\n /** Enable emotion detection and bot-emotion updates (default: false) */\n enableEmotion?: boolean;\n /** Blendshape configuration for facial animation format */\n blendshapeConfig?: {\n /** Format of blendshapes: \"arkit\" or \"mha\" (Meta Human Animation, default: \"mha\") */\n /**\n * Blendshape stream format (default: \"mha\"). Server-verified set:\n * - \"mha\" — 251 channels (Unreal MetaHuman Animation, CTRL_expressions_*)\n * - \"arkit\" — 61 channels (Apple ARKit names)\n * - \"cc4_extended\" — 170 channels (Reallusion CC4 ExpressionPlus)\n * - \"cc5_hd\" — accepted by the server but currently delivers no frames\n * - \"visemes\" — 15 channels (OVR viseme set)\n */\n format?: \"arkit\" | \"mha\" | \"cc4_extended\" | \"cc5_hd\" | \"visemes\";\n /** \n * Custom mapper function to transform incoming blendshapes.\n * Use this to map Convai blendshapes to your character's morph targets.\n * The function receives the raw blendshape array and should return a Float32Array.\n * \n * @example\n * ```typescript\n * import { createARKitNameMapper } from '@convai/web-sdk/lipsync-helpers';\n * \n * const mapper = createARKitNameMapper({\n * 'Character__Mouth_Open': ['Jaw_Open'],\n * 'Character__EyeL_Blink': ['Eye_Blink_L'],\n * }, 'optimized');\n * \n * const config = {\n * blendshapeConfig: {\n * format: 'arkit',\n * customMapper: mapper,\n * }\n * };\n * ```\n */\n customMapper?: (input: number[] | Float32Array) => Float32Array;\n /** \n * Buffer duration for blendshape frames in seconds (default: 1).\n * Controls how much time the server should wait after generating blendshapes before playing the audio.\n */\n frames_buffer_duration?: number;\n /**\n * Enable server ahead-delivery for NeuroSync chunks (default: true).\n *\n * Defaults to `true` when `enableLipsync` is on. The server may send\n * indexed blendshape chunks before audio playback, so use the SDK\n * BlendshapeQueue/player path, which handles owner-scoped cancellation and\n * buffered-frame drops on interruption.\n *\n * Set `false` to fall back to the legacy paced delivery path.\n */\n deliver_chunks_ahead?: boolean;\n /**\n * Requested ahead-delivery blendshape timeline FPS.\n * Applies to the ahead-delivery path, where chunks carry fps\n * metadata for the SDK player. The legacy paced path keeps its fixed 90fps\n * delivery cadence for backward compatibility while SDK playback remains on\n * the normal visual timeline.\n */\n output_fps?: number;\n };\n /** Emotion configuration for character emotional state (sent to server on connect) */\n emotionConfig?:\n | {\n /** LLM-based emotion detection — infers emotion from response context (default) */\n provider: \"llm\";\n }\n | {\n /** NRCLex word-level lexicon lookup */\n provider: \"nrclex\";\n /** Minimum word threshold for emotion detection */\n min_word_threshold?: number;\n /** Low intensity threshold (0–1) */\n low_intensity_threshold?: number;\n /** High intensity threshold (0–1) */\n high_intensity_threshold?: number;\n };\n /** Configuration for character actions and environmental context */\n actionConfig?: {\n /** List of action names the character can perform */\n actions: string[];\n /** Other characters present in the scene or conversation */\n characters: Array<{\n /** Character name */\n name: string;\n /** Character biography or description */\n bio: string;\n }>;\n /** Objects available in the scene or environment */\n objects: Array<{\n /** Object name */\n name: string;\n /** Object description or properties */\n description: string;\n }>;\n /** Name of the object the character is currently focused on. Must match one of objects[].name. */\n current_attention_object?: string;\n };\n /** \n * Dynamic contextual information about the current situation.\n * This can be updated during the conversation to provide real-time context.\n * Use the DynamicInfo type to pass flexible key-value pairs with a required \"text\" field.\n */\n dynamicInfo?: DynamicInfo;\n /**\n * Template key values for Narrative Design placeholder substitution,\n * sent as `narrative_template_keys` in the /connect request.\n *\n * Narrative Design section objectives and speak tags may contain\n * placeholders such as `{player_name}` or `{quest_item}`; they are replaced\n * with these values when the section is evaluated, so one narrative graph\n * can serve many personalized sessions. Keys are case-sensitive; missing\n * keys resolve to an empty string.\n *\n * To change the keys mid-session, call `updateTemplateKeys()` — it replaces\n * this same map at runtime (before the next trigger fires).\n *\n * @example\n * ```typescript\n * const client = new ConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * narrativeTemplateKeys: {\n * player_name: 'Alex',\n * location: 'Engineering Deck',\n * quest_item: 'oxygen generator',\n * },\n * });\n * ```\n */\n narrativeTemplateKeys?: Record<string, string>;\n /**\n * Keep dynamic info in context as a static prompt (default: false).\n * \n * When true:\n * - Dynamic info behaves as a static prompt sent to the LLM for that WebRTC connection\n * - Dynamic info persists throughout the session\n * - You need to set it again after disconnecting/reconnecting\n * \n * When false:\n * - Allows resetting and updating via updateContext() or updateDynamicInfo()\n * - Dynamic info can be changed during the session\n */\n keepInContext?: boolean;\n /** \n * Enable debug mode for additional logging and diagnostics (default: false).\n */\n debug?: boolean;\n /**\n * Log decoded RTVI data messages to the browser console (default: true).\n * Set to false to silence incoming and outgoing RTVI message logs.\n */\n logRtviMessages?: boolean;\n /** \n * Metadata about the invocation source and client information.\n * Used for analytics and debugging purposes.\n */\n invocationMetadata?: {\n /** Source of the invocation (e.g., \"web\", \"mobile\", \"unity\") */\n source?: string;\n /** Client SDK version */\n clientVersion?: string;\n /** Additional custom metadata */\n extraMetadata?: Record<string, unknown>;\n };\n}\n\n/** Optional metadata for a text interaction. */\nexport interface SendUserTextMessageOptions {\n /** Stable logical-turn identity used by clients that correlate responses. */\n logicalTurnId?: string;\n /** User-selected temporary emotion to apply before processing the text. */\n stateOfMind?: string | null;\n}\n\n/**\n * The body returned by POST /connect. The embed receives this from a\n * customer-hosted proxy route rather than fetching it directly.\n */\nexport interface ConnectionData {\n /** LiveKit room URL, or the WebSocket URL when the transport is websocket. */\n room_url: string;\n /** LiveKit access token. Absent on the WebSocket transport. */\n token?: string;\n character_session_id?: string;\n end_user_id?: string;\n end_user_metadata?: Record<string, unknown>;\n}\n\n/**\n * Represents a single message in the chat conversation.\n * Different message types are used for various parts of the conversation flow.\n */\nexport interface ChatMessage {\n /** Unique identifier for the message */\n id: string;\n /** \n * Type of message:\n * - `user`: User's sent message\n * - `convai`: Character's response\n * - `user-transcription`: Real-time speech-to-text from user\n * - `bot-llm-text`: Character's LLM-generated text (token-by-token streaming)\n * - `bot-output`: Aggregated bot output (sentence/word-level chunks with spoken status)\n * - `emotion`: Character's emotional state\n * - `behavior-tree`: Behavior tree response\n * - `action`: Action execution\n * - `bot-emotion`: Bot emotional response\n * - `user-llm-text`: User text processed by LLM\n * - `interrupt-bot`: Interrupt the bot's current response\n * - `idle-warning`: Server idle-timeout warning; `content` holds remaining seconds as a numeric string (e.g. `\"45\"`)\n * - `llm-no-response`: LLM deliberately did not respond (abstain); `content` is always `\"\"`\n */\n type: 'user' | 'convai' | 'emotion' | 'behavior-tree' | 'action' | 'user-transcription' | 'bot-llm-text' | 'bot-output' | 'bot-emotion' | 'user-llm-text' | 'interrupt-bot' | 'idle-warning' | 'llm-no-response';\n /** The text content of the message */\n content: string;\n /** ISO timestamp string of when the message was created */\n timestamp: string;\n /** Whether this message is still streaming (mutable); false when finalized */\n isStreaming?: boolean;\n}\n\n/**\n * Represents a single metrics event from the server.\n * Multiple metrics may be received during a conversation.\n */\nexport interface ConvaiMetrics {\n /** Raw metrics data from the server */\n data: Record<string, unknown>;\n /** Timestamp when the metrics were received */\n timestamp: string;\n /** Unique identifier for this metrics event */\n id: string;\n}\n\n/**\n * Represents the current state of the Convai client connection and activity.\n * Use this to provide UI feedback about the conversation state.\n * \n * @example\n * ```typescript\n * const { state } = convaiClient;\n * \n * if (state.isConnected) {\n * console.log('Connected to character');\n * }\n * \n * if (state.isSpeaking) {\n * console.log('Character is speaking');\n * }\n * \n * // Or use the combined state\n * console.log(state.agentState); // 'listening' | 'thinking' | 'speaking'\n * \n * // Access end user information\n * console.log(state.endUserId); // 'user@example.com'\n * console.log(state.endUserMetadata); // { name: 'John', age: '30' }\n * \n * // Access metrics for the current conversation\n * console.log(state.metrics); // Array of metrics events\n * \n * // Check disconnect reason\n * if (state.disconnectReason !== null) {\n * console.log('Disconnected due to:', state.disconnectReason);\n * }\n * ```\n */\nexport interface ConvaiClientState {\n /** Whether the client is currently connected to Convai */\n isConnected: boolean;\n /** Whether a connection attempt is in progress */\n isConnecting: boolean;\n /** True from user-started-speaking until user-stopped-speaking (user is speaking, bot is listening). Priority below isSpeaking. */\n isListening: boolean;\n /** Whether the character is processing/thinking about a response */\n isThinking: boolean;\n /** Whether the character is currently speaking */\n isSpeaking: boolean;\n /** \n * Combined state indicator for the character's current activity.\n * Priority: speaking > listening (user speaking) > thinking > connected.\n */\n agentState: 'disconnected' | 'connected' | 'listening' | 'thinking' | 'speaking';\n /** Current bot emotion (name and optional scale). Updated when bot-emotion messages are received. */\n emotion: { emotion: string; scale?: number } | null;\n /** \n * End user ID returned from the connection response.\n * This is the actual end user ID used by the server (may differ from the one provided in config).\n */\n endUserId: string | null;\n /** \n * End user metadata returned from the connection response.\n * Contains additional information about the end user.\n */\n endUserMetadata: Record<string, unknown> | null;\n /** \n * Array of metrics events received during the current session.\n * Multiple metrics may be received per conversation.\n * Clears when resetSession() is called.\n */\n metrics: ConvaiMetrics[];\n /** \n * Disconnect reason from LiveKit when disconnected.\n * null when connected, otherwise contains the reason code.\n * Use this to differentiate between client-initiated disconnects and network/server issues.\n * \n * Notable reasons:\n * - CLIENT_INITIATED (1): User disconnected intentionally\n * - DUPLICATE_IDENTITY (2): Another client with same identity joined\n * - SERVER_SHUTDOWN (3): Server shutting down\n * - PARTICIPANT_REMOVED (4): Removed by API\n * - ROOM_DELETED (5): Room was ended\n * \n * Non-CLIENT_INITIATED reasons may indicate network disruptions where reconnection is appropriate.\n * \n * @see DisconnectReason\n */\n disconnectReason: DisconnectReason | null;\n}\n\n/**\n * Audio control interface for managing microphone\n */\nexport interface AudioControls {\n isAudioEnabled: boolean;\n isAudioMuted: boolean;\n audioLevel: number;\n enableAudio: () => Promise<void>;\n disableAudio: () => Promise<void>;\n muteAudio: () => Promise<void>;\n unmuteAudio: () => Promise<void>;\n toggleAudio: () => Promise<void>;\n setAudioDevice: (deviceId: string) => Promise<void>;\n getAudioDevices: () => Promise<MediaDeviceInfo[]>;\n startAudioLevelMonitoring: () => void;\n stopAudioLevelMonitoring: () => void;\n // EventEmitter methods for React integration\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n\n/**\n * Video control interface for managing camera\n */\nexport interface VideoControls {\n isVideoEnabled: boolean;\n isVideoHidden: boolean;\n activeVisionSource: VisionSourceHandle | null;\n hasActiveVisionSource: boolean;\n visionSourceState: VisionSourceState;\n enableVideo: () => Promise<void>;\n disableVideo: () => Promise<void>;\n hideVideo: () => Promise<void>;\n showVideo: () => Promise<void>;\n toggleVideo: () => Promise<void>;\n setVideoDevice: (deviceId: string) => Promise<void>;\n getVideoDevices: () => Promise<MediaDeviceInfo[]>;\n setVideoQuality: (quality: 'low' | 'medium' | 'high') => Promise<void>;\n publishCanvas: (\n canvas: HTMLCanvasElement,\n options?: PublishCanvasOptions,\n ) => Promise<VisionSourceHandle>;\n publishVideoTrack: (\n track: MediaStreamTrack,\n options?: PublishVideoTrackOptions,\n ) => Promise<VisionSourceHandle>;\n unpublishVisionSource: (\n source?: VisionSourceHandle | MediaStreamTrack,\n ) => Promise<void>;\n // EventEmitter methods for React integration\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n\n/**\n * Screen share control interface\n */\nexport interface ScreenShareControls {\n isScreenShareEnabled: boolean;\n isScreenShareActive: boolean;\n enableScreenShare: () => Promise<void>;\n disableScreenShare: () => Promise<void>;\n toggleScreenShare: () => Promise<void>;\n enableScreenShareWithAudio: () => Promise<void>;\n getScreenShareTracks: () => Promise<any[]>;\n // EventEmitter methods for React integration\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n\n/**\n * Main Convai client interface.\n * Provides complete control over Convai character connections and interactions.\n * \n * @example\n * ```typescript\n * import { ConvaiClient } from '@convai/web-sdk/core';\n * \n * const client = new ConvaiClient();\n * \n * // Connect to character\n * await client.connect({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: '-1' // Dev mode\n * });\n * \n * // Send a message\n * client.sendUserTextMessage('Hello!');\n * \n * // Listen for state changes\n * client.on('stateChange', (state) => {\n * console.log('State:', state);\n * });\n * \n * // Listen for messages\n * client.on('message', (message) => {\n * console.log('New message:', message);\n * });\n * ```\n */\n/**\n * Character Versioning API Types\n *\n * Shapes returned by the Character REST platform's `/character/versions/*`\n * routes. Field names are kept as the API sends them.\n */\n\n/** One immutable, tagged character version. */\nexport interface CharacterVersionInfo {\n /** Semantic tag, e.g. `\"1.2\"` or `\"1.2.3\"` */\n version: string;\n /** Immutable revision backing this tag */\n revision_id: string;\n /** Whether `latest` currently points at this tag */\n is_latest: boolean;\n created_by: string;\n /** ISO-8601 timestamp */\n created_at: string;\n is_deprecated: boolean;\n /** ISO-8601 timestamp, or null when not deprecated */\n deprecated_at: string | null;\n}\n\n/** Response from `CharacterVersionManager.list()`. */\nexport interface CharacterVersionList {\n /** Released versions, newest first as returned by the API */\n items: CharacterVersionInfo[];\n /** Revision `latest` resolves to, or null before any release */\n latest_revision_id: string | null;\n /** Tag `latest` points at, or null when latest is an unpromoted revision */\n latest_version: string | null;\n /** Editable draft revision, or null for a legacy character that has not been bootstrapped */\n draft_revision_id: string | null;\n /** Released revision the draft was branched from */\n draft_parent_revision_id: string | null;\n draft_parent_version: string | null;\n /** True when the draft differs from its released parent */\n has_unpublished_changes: boolean;\n /** True when `latest` points at a tagged version rather than a loose revision */\n latest_is_promoted: boolean;\n}\n\n/** Voice details attached to a resolved version when `includeRuntimeSettings` is set. */\nexport interface CharacterRuntimeVoice {\n voice_value: string;\n voice_name: string;\n provider: string;\n lang_codes: string[] | null;\n accessibility: string | null;\n gender: string | null;\n voice_data: Record<string, unknown> | null;\n}\n\n/** Live (unversioned) runtime settings returned alongside a resolved version. */\nexport interface CharacterRuntimeSettings {\n schema_version: 1;\n stt_provider: string | null;\n voice: CharacterRuntimeVoice | null;\n}\n\n/** Response from `CharacterVersionManager.resolve()`. */\nexport interface ResolvedCharacterVersion {\n character_id: string;\n /** The reference that was resolved, e.g. `<uuid>-draft` */\n requested_reference: string;\n /** Immutable revision, or null for a legacy character with no revision yet */\n revision_id: string | null;\n /** Tag when the reference resolved to a tagged version */\n version: string | null;\n is_latest: boolean;\n /** The full character configuration snapshot */\n payload: Record<string, unknown>;\n runtime_settings?: CharacterRuntimeSettings | null;\n}\n\n/** Options for `CharacterVersionManager.resolve()`. */\nexport interface ResolveCharacterVersionOptions {\n /**\n * Also return the live voice and STT settings (default: false).\n * Only a trusted service identity may ask for these; an API key is\n * answered with `403 Runtime settings require a trusted service identity`.\n */\n includeRuntimeSettings?: boolean;\n}\n\n/** Response from `CharacterVersionManager.bootstrap()`. */\nexport interface CharacterDraftBootstrapResult {\n character_id: string;\n draft_revision_id: string;\n /** False when the character already had a draft */\n created: boolean;\n}\n\n/** One side of a version comparison. */\nexport interface CharacterVersionDiffSide {\n /** The selector that was compared: `draft`, `latest`, or a tag */\n selector: string;\n revision_id: string | null;\n version: string | null;\n is_latest: boolean;\n}\n\n/** One field-level change in a raw diff. */\nexport interface CharacterVersionRawChange {\n /** JSON path into the character payload */\n path: string;\n change_type: \"added\" | \"removed\" | \"modified\";\n before?: unknown;\n after?: unknown;\n}\n\n/** One human-labelled change in a semantic diff; revertable one at a time. */\nexport interface CharacterVersionSemanticChange {\n change_id: string;\n semantic_key: string;\n label: string;\n category: string;\n change_type: \"added\" | \"removed\" | \"modified\";\n before?: unknown;\n after?: unknown;\n source_paths: string[];\n can_revert: boolean;\n revert_disabled_reason?: string | null;\n integrity_warning?: string | null;\n}\n\n/** Response from `CharacterVersionManager.diff()` with `view: \"raw\"` (the default). */\nexport interface CharacterVersionRawDiff {\n view?: \"raw\";\n character_id: string;\n from: CharacterVersionDiffSide;\n to: CharacterVersionDiffSide;\n change_count: number;\n changes: CharacterVersionRawChange[];\n}\n\n/** Response from `CharacterVersionManager.diff()` with `view: \"semantic\"`. */\nexport interface CharacterVersionSemanticDiff {\n view: \"semantic\";\n semantic_schema_version: number;\n character_id: string;\n from: CharacterVersionDiffSide;\n to: CharacterVersionDiffSide;\n draft_revision_id: string | null;\n change_count: number;\n changes: CharacterVersionSemanticChange[];\n}\n\nexport type CharacterVersionDiff = CharacterVersionRawDiff | CharacterVersionSemanticDiff;\n\n/** Options for `CharacterVersionManager.diff()`. */\nexport interface CharacterVersionDiffOptions {\n /** `\"raw\"` lists JSON paths; `\"semantic\"` groups them into labelled, revertable changes. Default `\"raw\"`. */\n view?: \"raw\" | \"semantic\";\n}\n\n/** Options for `CharacterVersionManager.create()`. */\nexport interface CreateCharacterVersionOptions {\n /** Point `latest` at the new version immediately (default: false) */\n makeLatest?: boolean;\n}\n\n/** Options for `CharacterVersionManager.revert()`. */\nexport interface RevertCharacterChangeOptions {\n /** Version the draft is being compared against — the change is reverted to this side */\n from: string;\n /** `change_id` from a semantic diff */\n changeId: string;\n /** Draft revision the caller last saw; the request fails if the draft moved */\n expectedDraftRevisionId: string;\n}\n\n/** Response from `CharacterVersionManager.revert()`. */\nexport interface RevertCharacterChangeResult {\n character_id: string;\n reverted_change_id: string;\n previous_draft_revision_id: string;\n /** The new draft revision after the revert */\n draft_revision_id: string;\n /** Semantic diff between `from` and the new draft */\n diff: CharacterVersionSemanticDiff;\n}\n\n/** Response from `CharacterVersionManager.discardDraft()`. */\nexport interface DiscardCharacterDraftResult {\n character_id: string;\n previous_draft_revision_id: string;\n /** The fresh draft, restored from its released parent */\n draft_revision_id: string;\n draft_parent_revision_id: string;\n draft_parent_version: string;\n}\n\n/** Response from `CharacterVersionManager.fork()`. */\nexport interface ForkCharacterVersionResult {\n character_id: string;\n /** Tag the draft was replaced with */\n source_version: string;\n draft_revision_id: string;\n latest_revision_id: string | null;\n has_unpublished_changes: boolean;\n}\n\n/** Options for constructing a `CharacterVersionManager` directly. */\nexport interface CharacterVersionManagerOptions {\n /** Bare character UUID (a suffixed reference is accepted and stripped) */\n characterId: string;\n /** Convai API key, sent as `CONVAI-API-KEY` */\n apiKey?: string;\n /** Convai personal access token, sent as `Authorization: Bearer` (alternative to `apiKey`) */\n personalAccessToken?: string;\n /** Character REST platform origin (default: `https://api2.convai.com`) */\n baseUrl?: string;\n /** Workspace scope, forwarded as `workspace_id` on every call */\n workspaceId?: string;\n}\n\n/**\n * Memory API Types\n * Types for Convai's long-term memory management APIs\n */\n\n/**\n * Memory object returned from the API\n */\nexport interface Memory {\n /** Unique memory identifier (UUID) */\n id: string;\n /** Memory text content */\n memory: string;\n /** ISO timestamp when the memory was created */\n created_at: string;\n /** ISO timestamp when the memory was last updated */\n updated_at: string;\n}\n\n/**\n * Memory event object from add operation\n */\nexport interface MemoryAddEvent {\n /** Memory identifier */\n id: string;\n /** Event type (always \"ADD\" for add operations) */\n event: 'ADD';\n /** Memory text content */\n memory: string;\n}\n\n/**\n * Request to add memories\n */\nexport interface MemoryAddRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Array of memory strings to add */\n memories: string[];\n}\n\n/**\n * Response from add memories operation\n */\nexport interface MemoryAddResponse {\n /** Array of added memories with their IDs */\n memories: MemoryAddEvent[];\n}\n\n/**\n * Request to list memories with pagination\n */\nexport interface MemoryListRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Page number (default: 1, clamped to 1-1000) */\n page?: number;\n /** Number of memories per page (default: 50, clamped to 1-100) */\n page_size?: number;\n}\n\n/**\n * Response from list memories operation\n */\nexport interface MemoryListResponse {\n /** Array of memories */\n memories: Memory[];\n /** Total count of memories for this character/user pair */\n total_count: number;\n /** Current page number */\n page: number;\n /** Number of memories per page */\n page_size: number;\n /** Whether there are more pages available */\n has_more: boolean;\n}\n\n/**\n * Request to get a single memory\n */\nexport interface MemoryGetRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Memory UUID to fetch */\n memory_id: string;\n}\n\n/**\n * Response from get memory operation\n */\nexport type MemoryGetResponse = Memory;\n\n/**\n * Request to delete a memory\n */\nexport interface MemoryDeleteRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n /** Memory UUID to delete */\n memory_id: string;\n}\n\n/**\n * Response from delete memory operation\n */\nexport interface MemoryDeleteResponse {\n /** Success message */\n message: string;\n /** Memory ID that was deleted */\n memory_id: string;\n /** Whether the memory was successfully deleted */\n deleted: boolean;\n}\n\n/**\n * Request to delete all memories\n */\nexport interface MemoryDeleteAllRequest {\n /** Character UUID */\n character_id: string;\n /** End user identifier */\n end_user_id: string;\n}\n\n/**\n * Response from delete all memories operation\n */\nexport interface MemoryDeleteAllResponse {\n /** Status message (deletion is asynchronous) */\n message: string;\n /** Character ID for which memories are being deleted */\n character_id: string;\n /** End user ID for which memories are being deleted */\n end_user_id: string;\n}\n\n/**\n * Error response from Memory API\n */\nexport interface MemoryError {\n /** Error message */\n ERROR: string;\n /** Transaction reference ID for debugging */\n 'Reference ID': string;\n}\n\nexport interface IConvaiClient {\n /** Current connection and activity state of the client */\n readonly state: ConvaiClientState;\n \n /** \n * Connection type: \"audio\" (audio only) or \"video\" (audio + video + screenshare).\n * Set based on enableVideo in connect config.\n */\n readonly connectionType: 'audio' | 'video' | null;\n \n /** API key used for the current connection, if apiKey was used (null otherwise) */\n readonly apiKey?: string | null;\n\n /** Auth token used for the current connection, if authToken was used (null otherwise) */\n readonly authToken?: string | null;\n\n /** Bare character UUID used for the current connection (null if not connected) */\n readonly characterId: string | null;\n\n /** Version selector in effect for the current connection (`draft`, `latest`, or a tag); null when unversioned or not connected */\n readonly characterVersion: CharacterVersionSelector | null;\n\n /** The reference sent to the runtime: `characterId` joined with `characterVersion` (null if not connected) */\n readonly characterReference: string | null;\n \n /** Internal LiveKit Room instance (for advanced usage) */\n readonly room: Room;\n \n /** Array of all chat messages in the current conversation */\n readonly chatMessages: ChatMessage[];\n \n /** Current real-time transcription of user speech */\n readonly userTranscription: string;\n \n /** Unique session ID for the current character conversation */\n readonly characterSessionId: string | null;\n \n /** Whether the bot is ready to receive messages (true after bot-ready message) */\n readonly isBotReady: boolean;\n \n /** Audio control methods for managing microphone mute/unmute */\n readonly audioControls: AudioControls;\n \n /** Video control methods for enabling/disabling camera */\n readonly videoControls: VideoControls;\n \n /** Screen sharing control methods */\n readonly screenShareControls: ScreenShareControls;\n \n /** Blendshape queue for time-based lipsync synchronization */\n readonly blendshapeQueue: BlendshapeQueue;\n \n /** Incremental turn session ID used by conversation events (e.g. conversationStart, turnEnd) */\n readonly conversationSessionId: number;\n \n /** \n * Memory manager for long-term memory operations.\n * Returns null if no API key or end user ID is available.\n * \n * @example\n * ```typescript\n * const memoryManager = client.memoryManager;\n * if (memoryManager) {\n * const memories = await memoryManager.listMemories();\n * }\n * ```\n */\n readonly memoryManager: import('./MemoryManager').MemoryManager | null;\n\n /**\n * Character version manager for the configured character.\n *\n * Lists, compares, releases, promotes and discards character versions\n * through the Character REST platform. Available as soon as the client has\n * an `apiKey` and `characterId` — before connecting, so an app can pick a\n * version and then connect to it. Null without an API key.\n *\n * @example\n * ```typescript\n * const versions = client.characterVersions;\n * if (versions) {\n * const { items, draft_revision_id } = await versions.list();\n * await versions.create('1.0', { makeLatest: true });\n * }\n * ```\n */\n readonly characterVersions: import('./CharacterVersionManager').CharacterVersionManager | null;\n \n /** \n * Connect to a Convai character.\n */\n connect: (config?: ConvaiConfig) => Promise<void>;\n \n /**\n * Complete a connection from an already-fetched /connect response body.\n *\n * `connect()` fetches /connect and then calls this internally. Call it\n * directly when the response was obtained elsewhere — a server-side session\n * manager, or the embed's connect-proxy flow, where the API key must never\n * reach the browser.\n *\n * @example\n * // Server (customer's backend): holds the API key, calls Convai's\n * // /connect, and relays the response body verbatim.\n * // Browser: never sees the API key, only the relayed response.\n * const data = await fetch('/api/convai-connect', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ characterId: 'your-character-id' }),\n * }).then(r => r.json())\n * await client.connectWithConnectionData(data)\n */\n connectWithConnectionData: (data: ConnectionData, config?: ConvaiConfig) => Promise<void>;\n\n /** Disconnect from the current character session */\n disconnect: () => Promise<void>;\n \n /** Reconnect - disconnect and connect again using stored config */\n reconnect: () => Promise<void>;\n \n /** Reset the session ID to start a new conversation (clears history) */\n resetSession: () => void;\n \n /** Send a text message to the character */\n sendUserTextMessage: (text: string, options?: SendUserTextMessageOptions) => void;\n \n /** \n * Send a trigger message to invoke specific character actions or responses.\n * @param triggerName - Name of the trigger to invoke\n * @param triggerMessage - Optional message to accompany the trigger\n */\n sendTriggerMessage: (triggerName?: string, triggerMessage?: string) => void;\n \n /**\n * Send an interrupt message to stop the bot's current response.\n * This can be used to interrupt the bot when the user wants to speak.\n */\n sendInterruptMessage: () => void;\n\n /**\n * Reset the server-side idle timer.\n * Call this on any user activity (clicks, UI interactions, etc.) to prevent\n * the session from being disconnected due to inactivity.\n * The server sends `user-idle-warning` events (via the `idleWarning` event) before\n * disconnecting; use this method to keep the session alive.\n */\n resetIdleTimer: () => void;\n \n /**\n * Replace the Narrative Design template keys on the live session.\n *\n * These are the same keys as the `narrativeTemplateKeys` config option\n * (which seeds them at `/connect`) — this method REPLACES the entire map\n * at runtime, so include every key you still need. New values apply when\n * the next section objective or speak tag is evaluated (i.e. set them\n * before firing the next narrative trigger).\n *\n * Requires a character with Narrative Design enabled; otherwise the server\n * acks `update-template-keys` with error \"Narrative design service not\n * available\". Placeholders use single braces (`{player_name}`), keys are\n * case-sensitive, and missing keys resolve to an empty string.\n *\n * @example\n * ```typescript\n * client.updateTemplateKeys({ player_name: 'Aria', quest_item: 'lantern' });\n * client.sendTriggerMessage('QuestUpdate');\n * ```\n */\n updateTemplateKeys: (templateKeys: { [key: string]: string }) => void;\n \n /** \n * Update dynamic information about the current context.\n * This helps the character understand the current situation.\n * Pass any key-value pairs you want, but \"text\" field is required.\n */\n updateDynamicInfo: (dynamicInfo: DynamicInfo) => void;\n \n /**\n * Update the bot's temporary runtime context in a unified way.\n * Provides flexible control over ephemeral context management.\n * \n * @param options - Context update configuration\n * \n * @example\n * ```typescript\n * // Append to context\n * client.updateContext({ \n * text: \"User completed quest\", \n * mode: \"append\",\n * run_llm: \"false\"\n * });\n * \n * // Replace context\n * client.updateContext({ \n * text: \"New game state\", \n * mode: \"replace\",\n * run_llm: \"auto\"\n * });\n * \n * // Clear context\n * client.updateContext({ mode: \"reset\" });\n * ```\n */\n updateContext: (options: ContextUpdateOptions) => void;\n\n /** Request a server ack containing the current vision buffer status. */\n visionStatus: (options?: VisionStatusOptions) => string | null;\n\n /** Attach buffered frames and optionally trigger a response. */\n visionTrigger: (options?: VisionTriggerOptions) => string | null;\n\n /** Update a session respond-mode default. */\n respondModeUpdate: (options: RespondModeUpdateOptions) => string | null;\n\n /**\n * Set or clear the character's temporary state of mind without triggering a response.\n * Pass `null` (or `\"neutral\"`) to clear it.\n */\n updateEmotion: (stateOfMind: string | null) => void;\n\n /**\n * Send descriptive scene updates so the bot knows what is visible or nearby.\n * Does not modify actionConfig.\n */\n updateSceneMetadata: (\n items: Array<{ name: string; description: string }>,\n options?: UpdateSceneMetadataOptions,\n ) => void;\n\n /**\n * Toggle text-to-speech on or off.\n * When disabled, character responses won't be spoken aloud.\n */\n toggleTts: (enabled: boolean) => void;\n \n /** \n * Toggle speech-to-text on or off.\n * When enabled, user speech is transcribed to text (e.g. for dictation).\n * When disabled, STT is off.\n */\n toggleStt: (enabled: boolean) => void;\n\n /**\n * Upload a file to the character via the LiveKit byte stream transport.\n * Only works when connected with the LiveKit transport.\n *\n * @param file - The File object to send\n * @param options - Optional upload options\n * @returns Promise that resolves when the upload is complete\n *\n * @example\n * ```typescript\n * await client.uploadFile(file, {\n * topic: 'file-upload',\n * onProgress: (pct) => console.log(`${pct}% uploaded`),\n * });\n * ```\n */\n uploadFile: (file: File, options?: UploadFileOptions) => Promise<void>;\n\n /**\n * Subscribe to an event\n * @param event Event name ('stateChange', 'message', 'connect', 'disconnect', 'error')\n * @param callback Callback function\n * @returns Unsubscribe function\n */\n on: (event: string, callback: (...args: any[]) => void) => () => void;\n \n /**\n * Unsubscribe from an event\n * @param event Event name\n * @param callback Callback function to remove\n */\n off: (event: string, callback: (...args: any[]) => void) => void;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConvaiClient.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,GAC1B,SAAS,YAAY,KACpB,aAAa,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useConvaiClient.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,GAC1B,SAAS,YAAY,KACpB,aAAa,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;CAgO9B,CAAC"}
|
|
@@ -27,8 +27,10 @@ import { ConvaiClient as CoreConvaiClient } from "../../core/index.js";
|
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
export const useConvaiClient = (config) => {
|
|
30
|
-
// Create client instance once
|
|
31
|
-
|
|
30
|
+
// Create client instance once. The config is handed to the client as well
|
|
31
|
+
// as kept in the hook, so config-derived surfaces such as
|
|
32
|
+
// `characterVersions` are usable before the first connect().
|
|
33
|
+
const [client] = useState(() => new CoreConvaiClient(config));
|
|
32
34
|
// React state for UI updates
|
|
33
35
|
const [state, setState] = useState(client.state);
|
|
34
36
|
const [activity, setActivity] = useState("Idle");
|
|
@@ -166,6 +168,8 @@ export const useConvaiClient = (config) => {
|
|
|
166
168
|
...(client.apiKey && { apiKey: client.apiKey }),
|
|
167
169
|
...(client.authToken && { authToken: client.authToken }),
|
|
168
170
|
characterId: client.characterId,
|
|
171
|
+
characterVersion: client.characterVersion,
|
|
172
|
+
characterReference: client.characterReference,
|
|
169
173
|
connect,
|
|
170
174
|
connectWithConnectionData: client.connectWithConnectionData.bind(client),
|
|
171
175
|
disconnect: client.disconnect.bind(client),
|
|
@@ -195,6 +199,7 @@ export const useConvaiClient = (config) => {
|
|
|
195
199
|
blendshapeQueue: client.blendshapeQueue,
|
|
196
200
|
conversationSessionId: client.conversationSessionId,
|
|
197
201
|
memoryManager: client.memoryManager,
|
|
202
|
+
characterVersions: client.characterVersions,
|
|
198
203
|
toggleTts: client.toggleTts.bind(client),
|
|
199
204
|
toggleStt: client.toggleStt.bind(client),
|
|
200
205
|
uploadFile: client.uploadFile.bind(client),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConvaiClient.js","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { ConvaiClient as CoreConvaiClient } from \"../../core\";\nimport type {\n ConvaiConfig,\n IConvaiClient,\n ChatMessage,\n} from \"../../core/types\";\n\n/**\n * React hook wrapper for ConvaiClient\n * Main hook for managing Convai client connection and functionality.\n *\n * Provides a complete interface for connecting to Convai's AI-powered voice assistants,\n * managing real-time audio/video conversations, and handling various message types.\n *\n * @param config - Optional configuration to store for later connection\n * @returns {ConvaiClient & { activity: string; chatMessages: ChatMessage[] }} Complete client interface with connection state, methods, and message history\n *\n * @example\n * ```tsx\n * function App() {\n * const convaiClient = useConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: 'user-uuid', // Optional: enables memory & analytics\n * enableVideo: true,\n * });\n *\n * return (\n * <ConvaiWidget convaiClient={convaiClient} />\n * );\n * }\n * ```\n */\nexport const useConvaiClient = (\n config?: ConvaiConfig,\n): IConvaiClient & {\n activity: string;\n chatMessages: ChatMessage[];\n isAudioMuted: boolean;\n isVideoEnabled: boolean;\n isScreenShareActive: boolean;\n} => {\n // Create client instance once\n const [client] = useState(() => new CoreConvaiClient());\n\n // React state for UI updates\n const [state, setState] = useState(client.state);\n const [activity, setActivity] = useState<string>(\"Idle\");\n const [chatMessages, setChatMessages] = useState<ChatMessage[]>(\n client.chatMessages,\n );\n const [userTranscription, setUserTranscription] = useState<string>(\n client.userTranscription,\n );\n const [isSpeaking, setIsSpeaking] = useState<boolean>(false);\n const [isBotReady, setIsBotReady] = useState<boolean>(client.isBotReady);\n \n // Reactive states for control managers\n const [isAudioMuted, setIsAudioMuted] = useState<boolean>(\n client.audioControls.isAudioMuted\n );\n const [isVideoEnabled, setIsVideoEnabled] = useState<boolean>(\n client.videoControls.isVideoEnabled\n );\n const [isScreenShareActive, setIsScreenShareActive] = useState<boolean>(\n client.screenShareControls.isScreenShareActive\n );\n\n // Store config if provided\n const [storedConfig] = useState<ConvaiConfig | undefined>(config);\n\n // Setup event listeners\n useEffect(() => {\n // State change listener\n const unsubStateChange = client.on(\"stateChange\", (newState) => {\n setState(newState);\n\n // Update activity based on state (priority: speaking > listening > thinking > connected)\n if (!newState.isConnected) {\n setActivity(\"Disconnected\");\n } else if (newState.isConnecting) {\n setActivity(\"Connecting...\");\n } else if (newState.isSpeaking) {\n setActivity(\"Speaking\");\n } else if (newState.isListening) {\n setActivity(\"Listening\");\n } else if (newState.isThinking) {\n setActivity(\"Thinking\");\n } else {\n setActivity(\"Connected\");\n }\n });\n\n // Messages change listener\n const unsubMessagesChange = client.on(\"messagesChange\", (messages) => {\n setChatMessages([...messages]);\n });\n\n // User transcription change listener\n const unsubUserTranscription = client.on(\n \"userTranscriptionChange\",\n (transcription) => {\n setUserTranscription(transcription);\n },\n );\n\n // Speaking change listener\n const unsubSpeaking = client.on(\"speakingChange\", (speaking) => {\n setIsSpeaking(speaking);\n });\n\n // Bot ready listener\n const unsubBotReady = client.on(\"botReady\", () => {\n setIsBotReady(true);\n setActivity(\"Connected\");\n });\n\n // Connect listener\n const unsubConnect = client.on(\"connect\", () => {\n setState(client.state);\n });\n\n // Disconnect listener\n const unsubDisconnect = client.on(\"disconnect\", () => {\n setIsBotReady(false);\n setState(client.state);\n setActivity(\"Disconnected\");\n setChatMessages([]);\n // Reset control states on disconnect\n setIsAudioMuted(true);\n setIsVideoEnabled(false);\n setIsScreenShareActive(false);\n });\n\n // WebSocket transport: play bot audio track via a hidden <audio> element\n const wsAudioEl = document.createElement(\"audio\");\n wsAudioEl.autoplay = true;\n wsAudioEl.dataset.convaiWs = \"true\";\n document.body.appendChild(wsAudioEl);\n\n const unsubBotAudioTrack = client.on(\n \"botAudioTrack\",\n (track: MediaStreamTrack) => {\n wsAudioEl.srcObject = new MediaStream([track]);\n },\n );\n\n // Disconnect listener also clears WS audio\n const unsubDisconnectWsAudio = client.on(\"disconnect\", () => {\n wsAudioEl.srcObject = null;\n });\n\n // Audio controls state change listener\n const unsubAudioState = client.audioControls.on(\"audioStateChange\", (audioState: any) => {\n if (audioState.isAudioMuted !== undefined) {\n setIsAudioMuted(audioState.isAudioMuted);\n }\n });\n\n // Video controls state change listener\n const unsubVideoState = client.videoControls.on(\"videoStateChange\", (videoState: any) => {\n if (videoState.isVideoEnabled !== undefined) {\n setIsVideoEnabled(videoState.isVideoEnabled);\n }\n });\n\n // Screen share controls state change listener\n const unsubScreenShareState = client.screenShareControls.on(\"screenShareStateChange\", (screenShareState: any) => {\n if (screenShareState.isScreenShareActive !== undefined) {\n setIsScreenShareActive(screenShareState.isScreenShareActive);\n }\n });\n\n // Cleanup listeners on unmount\n return () => {\n unsubStateChange();\n unsubMessagesChange();\n unsubUserTranscription();\n unsubSpeaking();\n unsubBotReady();\n unsubConnect();\n unsubDisconnect();\n unsubBotAudioTrack();\n unsubDisconnectWsAudio();\n unsubAudioState();\n unsubVideoState();\n unsubScreenShareState();\n wsAudioEl.srcObject = null;\n wsAudioEl.remove();\n };\n }, [client]);\n\n // Create enhanced connect function that can use stored config\n const connect = useCallback(\n async (configOverride?: ConvaiConfig) => {\n const finalConfig = configOverride || storedConfig;\n\n if (!finalConfig) {\n throw new Error(\n \"No configuration provided. Pass config to useConvaiClient() or to connect()\",\n );\n }\n\n await client.connect(finalConfig);\n },\n [client, storedConfig],\n );\n\n // Create reconnect function wrapper\n const reconnect = useCallback(async () => {\n await client.reconnect();\n }, [client]);\n\n // Return client interface with React-friendly additions\n return {\n state,\n connectionType: client.connectionType,\n ...(client.apiKey && { apiKey: client.apiKey }),\n ...(client.authToken && { authToken: client.authToken }),\n characterId: client.characterId,\n connect,\n connectWithConnectionData: client.connectWithConnectionData.bind(client),\n disconnect: client.disconnect.bind(client),\n reconnect,\n resetSession: client.resetSession.bind(client),\n room: client.room,\n sendUserTextMessage: client.sendUserTextMessage.bind(client),\n sendTriggerMessage: client.sendTriggerMessage.bind(client),\n sendInterruptMessage: client.sendInterruptMessage.bind(client),\n resetIdleTimer: client.resetIdleTimer.bind(client),\n updateTemplateKeys: client.updateTemplateKeys.bind(client),\n updateDynamicInfo: client.updateDynamicInfo.bind(client),\n updateContext: client.updateContext.bind(client),\n updateEmotion: client.updateEmotion.bind(client),\n visionStatus: client.visionStatus.bind(client),\n visionTrigger: client.visionTrigger.bind(client),\n respondModeUpdate: client.respondModeUpdate.bind(client),\n updateSceneMetadata: client.updateSceneMetadata.bind(client),\n activity,\n chatMessages,\n userTranscription,\n characterSessionId: client.characterSessionId,\n isBotReady,\n audioControls: client.audioControls,\n videoControls: client.videoControls,\n screenShareControls: client.screenShareControls,\n blendshapeQueue: client.blendshapeQueue,\n conversationSessionId: client.conversationSessionId,\n memoryManager: client.memoryManager,\n toggleTts: client.toggleTts.bind(client),\n toggleStt: client.toggleStt.bind(client),\n uploadFile: client.uploadFile.bind(client),\n on: client.on.bind(client),\n off: client.off.bind(client),\n // Reactive control states\n isAudioMuted,\n isVideoEnabled,\n isScreenShareActive,\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"useConvaiClient.js","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { ConvaiClient as CoreConvaiClient } from \"../../core\";\nimport type {\n ConvaiConfig,\n IConvaiClient,\n ChatMessage,\n} from \"../../core/types\";\n\n/**\n * React hook wrapper for ConvaiClient\n * Main hook for managing Convai client connection and functionality.\n *\n * Provides a complete interface for connecting to Convai's AI-powered voice assistants,\n * managing real-time audio/video conversations, and handling various message types.\n *\n * @param config - Optional configuration to store for later connection\n * @returns {ConvaiClient & { activity: string; chatMessages: ChatMessage[] }} Complete client interface with connection state, methods, and message history\n *\n * @example\n * ```tsx\n * function App() {\n * const convaiClient = useConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: 'user-uuid', // Optional: enables memory & analytics\n * enableVideo: true,\n * });\n *\n * return (\n * <ConvaiWidget convaiClient={convaiClient} />\n * );\n * }\n * ```\n */\nexport const useConvaiClient = (\n config?: ConvaiConfig,\n): IConvaiClient & {\n activity: string;\n chatMessages: ChatMessage[];\n isAudioMuted: boolean;\n isVideoEnabled: boolean;\n isScreenShareActive: boolean;\n} => {\n // Create client instance once. The config is handed to the client as well\n // as kept in the hook, so config-derived surfaces such as\n // `characterVersions` are usable before the first connect().\n const [client] = useState(() => new CoreConvaiClient(config));\n\n // React state for UI updates\n const [state, setState] = useState(client.state);\n const [activity, setActivity] = useState<string>(\"Idle\");\n const [chatMessages, setChatMessages] = useState<ChatMessage[]>(\n client.chatMessages,\n );\n const [userTranscription, setUserTranscription] = useState<string>(\n client.userTranscription,\n );\n const [isSpeaking, setIsSpeaking] = useState<boolean>(false);\n const [isBotReady, setIsBotReady] = useState<boolean>(client.isBotReady);\n \n // Reactive states for control managers\n const [isAudioMuted, setIsAudioMuted] = useState<boolean>(\n client.audioControls.isAudioMuted\n );\n const [isVideoEnabled, setIsVideoEnabled] = useState<boolean>(\n client.videoControls.isVideoEnabled\n );\n const [isScreenShareActive, setIsScreenShareActive] = useState<boolean>(\n client.screenShareControls.isScreenShareActive\n );\n\n // Store config if provided\n const [storedConfig] = useState<ConvaiConfig | undefined>(config);\n\n // Setup event listeners\n useEffect(() => {\n // State change listener\n const unsubStateChange = client.on(\"stateChange\", (newState) => {\n setState(newState);\n\n // Update activity based on state (priority: speaking > listening > thinking > connected)\n if (!newState.isConnected) {\n setActivity(\"Disconnected\");\n } else if (newState.isConnecting) {\n setActivity(\"Connecting...\");\n } else if (newState.isSpeaking) {\n setActivity(\"Speaking\");\n } else if (newState.isListening) {\n setActivity(\"Listening\");\n } else if (newState.isThinking) {\n setActivity(\"Thinking\");\n } else {\n setActivity(\"Connected\");\n }\n });\n\n // Messages change listener\n const unsubMessagesChange = client.on(\"messagesChange\", (messages) => {\n setChatMessages([...messages]);\n });\n\n // User transcription change listener\n const unsubUserTranscription = client.on(\n \"userTranscriptionChange\",\n (transcription) => {\n setUserTranscription(transcription);\n },\n );\n\n // Speaking change listener\n const unsubSpeaking = client.on(\"speakingChange\", (speaking) => {\n setIsSpeaking(speaking);\n });\n\n // Bot ready listener\n const unsubBotReady = client.on(\"botReady\", () => {\n setIsBotReady(true);\n setActivity(\"Connected\");\n });\n\n // Connect listener\n const unsubConnect = client.on(\"connect\", () => {\n setState(client.state);\n });\n\n // Disconnect listener\n const unsubDisconnect = client.on(\"disconnect\", () => {\n setIsBotReady(false);\n setState(client.state);\n setActivity(\"Disconnected\");\n setChatMessages([]);\n // Reset control states on disconnect\n setIsAudioMuted(true);\n setIsVideoEnabled(false);\n setIsScreenShareActive(false);\n });\n\n // WebSocket transport: play bot audio track via a hidden <audio> element\n const wsAudioEl = document.createElement(\"audio\");\n wsAudioEl.autoplay = true;\n wsAudioEl.dataset.convaiWs = \"true\";\n document.body.appendChild(wsAudioEl);\n\n const unsubBotAudioTrack = client.on(\n \"botAudioTrack\",\n (track: MediaStreamTrack) => {\n wsAudioEl.srcObject = new MediaStream([track]);\n },\n );\n\n // Disconnect listener also clears WS audio\n const unsubDisconnectWsAudio = client.on(\"disconnect\", () => {\n wsAudioEl.srcObject = null;\n });\n\n // Audio controls state change listener\n const unsubAudioState = client.audioControls.on(\"audioStateChange\", (audioState: any) => {\n if (audioState.isAudioMuted !== undefined) {\n setIsAudioMuted(audioState.isAudioMuted);\n }\n });\n\n // Video controls state change listener\n const unsubVideoState = client.videoControls.on(\"videoStateChange\", (videoState: any) => {\n if (videoState.isVideoEnabled !== undefined) {\n setIsVideoEnabled(videoState.isVideoEnabled);\n }\n });\n\n // Screen share controls state change listener\n const unsubScreenShareState = client.screenShareControls.on(\"screenShareStateChange\", (screenShareState: any) => {\n if (screenShareState.isScreenShareActive !== undefined) {\n setIsScreenShareActive(screenShareState.isScreenShareActive);\n }\n });\n\n // Cleanup listeners on unmount\n return () => {\n unsubStateChange();\n unsubMessagesChange();\n unsubUserTranscription();\n unsubSpeaking();\n unsubBotReady();\n unsubConnect();\n unsubDisconnect();\n unsubBotAudioTrack();\n unsubDisconnectWsAudio();\n unsubAudioState();\n unsubVideoState();\n unsubScreenShareState();\n wsAudioEl.srcObject = null;\n wsAudioEl.remove();\n };\n }, [client]);\n\n // Create enhanced connect function that can use stored config\n const connect = useCallback(\n async (configOverride?: ConvaiConfig) => {\n const finalConfig = configOverride || storedConfig;\n\n if (!finalConfig) {\n throw new Error(\n \"No configuration provided. Pass config to useConvaiClient() or to connect()\",\n );\n }\n\n await client.connect(finalConfig);\n },\n [client, storedConfig],\n );\n\n // Create reconnect function wrapper\n const reconnect = useCallback(async () => {\n await client.reconnect();\n }, [client]);\n\n // Return client interface with React-friendly additions\n return {\n state,\n connectionType: client.connectionType,\n ...(client.apiKey && { apiKey: client.apiKey }),\n ...(client.authToken && { authToken: client.authToken }),\n characterId: client.characterId,\n characterVersion: client.characterVersion,\n characterReference: client.characterReference,\n connect,\n connectWithConnectionData: client.connectWithConnectionData.bind(client),\n disconnect: client.disconnect.bind(client),\n reconnect,\n resetSession: client.resetSession.bind(client),\n room: client.room,\n sendUserTextMessage: client.sendUserTextMessage.bind(client),\n sendTriggerMessage: client.sendTriggerMessage.bind(client),\n sendInterruptMessage: client.sendInterruptMessage.bind(client),\n resetIdleTimer: client.resetIdleTimer.bind(client),\n updateTemplateKeys: client.updateTemplateKeys.bind(client),\n updateDynamicInfo: client.updateDynamicInfo.bind(client),\n updateContext: client.updateContext.bind(client),\n updateEmotion: client.updateEmotion.bind(client),\n visionStatus: client.visionStatus.bind(client),\n visionTrigger: client.visionTrigger.bind(client),\n respondModeUpdate: client.respondModeUpdate.bind(client),\n updateSceneMetadata: client.updateSceneMetadata.bind(client),\n activity,\n chatMessages,\n userTranscription,\n characterSessionId: client.characterSessionId,\n isBotReady,\n audioControls: client.audioControls,\n videoControls: client.videoControls,\n screenShareControls: client.screenShareControls,\n blendshapeQueue: client.blendshapeQueue,\n conversationSessionId: client.conversationSessionId,\n memoryManager: client.memoryManager,\n characterVersions: client.characterVersions,\n toggleTts: client.toggleTts.bind(client),\n toggleStt: client.toggleStt.bind(client),\n uploadFile: client.uploadFile.bind(client),\n on: client.on.bind(client),\n off: client.off.bind(client),\n // Reactive control states\n isAudioMuted,\n isVideoEnabled,\n isScreenShareActive,\n };\n};\n"]}
|
package/dist/vanilla/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
31
|
export { ConvaiClient } from '../core/ConvaiClient.js';
|
|
32
|
+
export { CharacterVersionManager, CharacterApiError } from '../core/CharacterVersionManager.js';
|
|
32
33
|
export { AudioRenderer } from './AudioRenderer.js';
|
|
33
34
|
export { createConvaiWidget, destroyConvaiWidget } from './ConvaiWidget.js';
|
|
34
35
|
export * from '../core/types.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vanilla/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vanilla/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAG7F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGzE,cAAc,eAAe,CAAC;AAG9B,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,eAAe,GAChB,MAAM,SAAS,CAAC"}
|
package/dist/vanilla/index.js
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
// Main client for managing connections
|
|
32
32
|
export { ConvaiClient } from '../core/ConvaiClient.js';
|
|
33
|
+
export { CharacterVersionManager, CharacterApiError } from '../core/CharacterVersionManager.js';
|
|
33
34
|
// AudioRenderer for custom UI builders (handles audio playback)
|
|
34
35
|
export { AudioRenderer } from './AudioRenderer.js';
|
|
35
36
|
// Vanilla widget - complete UI solution
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vanilla/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,uCAAuC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vanilla/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,uCAAuC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE7F,gEAAgE;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,wCAAwC;AACxC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,0DAA0D;AAC1D,cAAc,eAAe,CAAC","sourcesContent":["/**\n * Convai Web SDK - Vanilla JavaScript/TypeScript Export\n * \n * This module provides vanilla JS/TS exports for the Convai SDK.\n * Use this for non-React applications.\n * \n * @example\n * ```typescript\n * import { ConvaiClient, createConvaiWidget } from '@convai/web-sdk/vanilla';\n * \n * // Pass config to constructor (same pattern as React's useConvaiClient)\n * const client = new ConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * enableVideo: true,\n * });\n * \n * // Create widget - auto-connects on first click\n * const widget = createConvaiWidget(document.body, {\n * convaiClient: client\n * });\n * \n * // Client has all functions for advanced usage:\n * // - client.connect() - manual connection\n * // - client.disconnect() - disconnect\n * // - client.reconnect() - reconnect\n * // - client.sendUserTextMessage() - send messages\n * // - client.audioControls, videoControls, etc.\n * ```\n */\n\n// Main client for managing connections\nexport { ConvaiClient } from '../core/ConvaiClient';\nexport { CharacterVersionManager, CharacterApiError } from '../core/CharacterVersionManager';\n\n// AudioRenderer for custom UI builders (handles audio playback)\nexport { AudioRenderer } from './AudioRenderer';\n\n// Vanilla widget - complete UI solution\nexport { createConvaiWidget, destroyConvaiWidget } from './ConvaiWidget';\n\n// Re-export ALL core types for complete parity with React\nexport * from '../core/types';\n\n// Widget-specific types\nexport type {\n VanillaWidget,\n VanillaWidgetOptions,\n WidgetPlacement,\n} from './types';\n\n\n"]}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "1.8.0-beta.
|
|
1
|
+
export declare const SDK_VERSION = "1.8.0-beta.5";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,gDAAgD;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC","sourcesContent":["// GENERATED by scripts/sync-version.mjs — do not edit by hand.\n// Regenerated from package.json on every build.\nexport const SDK_VERSION = \"1.8.0-beta.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,gDAAgD;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC","sourcesContent":["// GENERATED by scripts/sync-version.mjs — do not edit by hand.\n// Regenerated from package.json on every build.\nexport const SDK_VERSION = \"1.8.0-beta.5\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@convai/web-sdk",
|
|
3
|
-
"version": "1.8.0-beta.
|
|
3
|
+
"version": "1.8.0-beta.5",
|
|
4
4
|
"description": "Build web apps with lifelike AI characters. The Convai Web SDK gives you real-time voice, lipsync, emotions, and dynamic context — with first-class support for React and vanilla TypeScript.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|