/** * protocol.ts * ----------- * The native wire contract: every type that must stay in sync with the React * Native host. If the native side changes, this is the file that changes with * it. Nothing here has runtime behaviour — it's pure types plus the one global * declaration for the bridge channel. * * Adding a one-shot endpoint touches this file in two spots: a command in * `LaylaApiRequest` and a response in `LaylaApiEvent`. */ declare global { interface Window { /** Injected by the React Native when its `onMessage` prop is set. */ ReactNativeWebView?: { postMessage: (message: string) => void; }; } } type LaylaChatRole = 'system' | 'user' | 'assistant'; /** An OpenAI-style chat message. */ interface LaylaChatMessage { role: LaylaChatRole; content: string | null; name?: string; } interface LaylaChatHistoryEntry extends LaylaChatMessage { id: number; character_id: string; session_id: string; timestamp: number; } interface LaylaScheduledChatMessage { id: number; character_id: string; session_id: string | null; timestamp: number; message: string; } interface LaylaCharacter { id: string; data: TavernCardV2; } interface LaylaMemory { id: number; character_id: string; session_id: string; rawText: string; timestamp: number; summary: string | null; knowledgeGraphJSON: string | null; } interface LaylaPersona { name: string; description: string; } interface LaylaTTSVoice { id: string; type: string; tags: string[]; name: string; } declare const SENTIMENT_THRESHOLDS: { admiration: number; amusement: number; anger: number; annoyance: number; approval: number; caring: number; confusion: number; curiosity: number; desire: number; disappointment: number; disapproval: number; disgust: number; embarrassment: number; excitement: number; fear: number; gratitude: number; grief: number; joy: number; love: number; nervousness: number; optimism: number; pride: number; realization: number; relief: number; remorse: number; sadness: number; surprise: number; neutral: number; }; type SentimentValues = typeof SENTIMENT_THRESHOLDS; /** * A character card following the Character Card V2 spec (`chara_card_v2`), as * returned by the host's `get_characters` handler. If your app already exports * its own `TavernCardV2`, prefer importing that — they describe the same shape. */ interface TavernCardV2 { spec: 'chara_card_v2'; spec_version: '2.0'; data: { name: string; description: string; personality: string; scenario: string; first_mes: string; mes_example: string; creator_notes: string; system_prompt: string; post_history_instructions: string; alternate_greetings: string[]; character_book?: TavernCharacterBook; tags: string[]; creator: string; character_version: string; extensions: Record; }; } interface TavernCharacterBook { name?: string; description?: string; scan_depth?: number; token_budget?: number; recursive_scanning?: boolean; extensions: Record; entries: Array<{ keys: string[]; content: string; extensions: Record; enabled: boolean; insertion_order: number; case_sensitive?: boolean; name?: string; priority?: number; id?: number; comment?: string; selective?: boolean; secondary_keys?: string[]; constant?: boolean; position?: 'before_char' | 'after_char'; }>; } interface LaylaExecutionContext { character: LaylaCharacter | null; session_id: string | null; } /** Send a conversation for completion (a streaming request). */ interface LaylaApiSendMessage { cmd: 'send_message'; data: LaylaChatMessage[]; } /** Ask the host for the list of available character cards (a one-shot request). */ interface LaylaApiGetCharacters { cmd: 'get_characters'; data: { offset: number; limit: number; }; } /** Ask the host for a character image identified by . */ interface LaylaApiGetCharacterImage { cmd: 'get_character_image'; data: { character_id: string; }; } /** * Stop the in-flight generation. * * Native contract: on receiving this, the host MUST stop the current * generation and then emit a normal `on_message_end` (or `on_error`) for that * request. That terminating event is the acknowledgement the SDK waits for * before starting the next queued request, so it must always be sent — even * when generation was cut short. Tokens already posted before the host * processes the cancel are harmless; the SDK swallows them. */ interface LaylaApiCancel { cmd: 'cancel'; } /** * Ask the host to generate an image based on the provided prompt. The host should respond with an `on_generate_image_response` event containing the generated image encoded in base64 (including the data URI prefix). */ interface LaylaApiGenerateImage { cmd: 'generate_image'; data: { prompt: string; img2img_base64?: string; model_id?: string; }; } /** * Ask the host for the list of available image generation models. The host should respond with an `on_get_image_generation_models_response` event containing an array of model names. * The host will only return image models that are immediately available for use (so this will not include models that are not downloaded) */ interface LaylaApiGetImageGenerationModels { cmd: 'get_image_generation_models'; data: null; } /** * Ask the host to update a character's data. The host should update the character identified by `character_id` with the provided `character_data`. * If the character ID does not exist, the host will create a new character. * You can include an "image" field in character_data.data.extensions to update the character's image. The "image" field should contain the new image data encoded in base64 (including the data URI prefix). * The host should respond with an `on_update_character_response` event containing the updated character id after the update is applied. */ interface LaylaApiUpdateCharacter { cmd: 'update_character'; data: { character_id: string; character_data: TavernCardV2; }; } /** * Ask the host for the chat history associated with a specific session ID. * The host should respond with an `on_get_chat_history_response` event containing an array of chat messages, each including the role, content, character ID, and timestamp. * The messages should be returned in reverse chronological order (newest to oldest). */ interface LaylaApiGetChatHistory { cmd: 'get_chat_history'; data: { session_id: string; offset: number; limit: number; }; } /** * Ask the host to analyze the sentiment of the provided text. * The host should respond with an `on_get_sentiment_response` event containing the sentiment values for each emotion category defined in `SentimentValues`. * Each sentiment value should be a number between 0 and 1, representing the intensity of that emotion in the input text. */ interface LaylaApiGetSentiment { cmd: 'get_sentiment'; data: { text: string; }; } /** * Ask the host for the chat sessions associated with a specific character ID. * The host should respond with an `on_get_chat_sessions_response` event containing an array of chat sessions, including the session ID, last message timestamp, and the last message content */ interface LaylaApiGetChatSessions { cmd: 'get_chat_sessions'; data: { character_id: string; offset: number; limit: number; }; } /** * Ask the host to save a chat message to the history of a specific session. * A new session will be created if the provided `session_id` does not exist. * If provided id <= 0, a new chat message will be created. Otherwise, the existing chat message with the provided id will be updated. * The host should respond with an `on_save_chat_message_response` event containing the saved chat message. */ interface LaylaApiSaveChatMessage { cmd: 'save_chat_message'; data: LaylaChatHistoryEntry; } /** * Ask the host to save a file with the given filename and content. The host should handle the file saving process (e.g., by storing it locally) * The host should respond with an `on_save_file_response` event indicating whether the file was saved successfully */ interface LaylaApiSaveFile { cmd: 'save_file'; data: { filename: string; content_base64: string; share: boolean; }; } /** * Asks the host to read the contents of a file with the given filename + extension. Only reads files in your app's private directory. * The host will respond with an `on_read_file_response` event containing the file content encoded in base64 (including the data URI prefix). */ interface LaylaApiReadFile { cmd: 'read_file'; data: { filename: string; }; } /** * Ask the host for the memories associated with a specific character ID. * The host should respond with an `on_get_memories_response` event containing an array of memories, each including the content, timestamp, and any additional metadata. * The memories should be returned in reverse chronological order (newest to oldest). */ interface LaylaApiGetMemories { cmd: 'get_memories'; data: { character_id: string; offset: number; limit: number; min_timestamp?: number; max_timestamp?: number; }; } /** * Ask the host for the top memories associated with a specific character ID. This heuristic is determined by the host. * The host should respond with an `on_get_top_memories_response` event containing an array of the top memories, each including the content, timestamp, and any additional metadata. * The memories are returned in reverse chronological order (newest to oldest) and should include the content, timestamp, and any additional metadata. */ interface LaylaApiGetTopMemories { cmd: 'get_top_memories'; data: { character_id: string; limit: number; }; } /** * Ask the host to create a new memory or update existing memories * If `memory.id` is <= 0, a new memory will be created. Otherwise, the existing memory with the provided id will be updated. * The host should respond with an `on_create_or_update_memories_response` event containing the created or updated memories after the operation is applied. */ interface LaylaApiCreateOrUpdateMemories { cmd: 'create_or_update_memories'; data: LaylaMemory[]; } /** * Ask the host to schedule a chat message to be sent at a specific timestamp (in the future). * The host should store the scheduled message and send it at the specified time for the given character and optional session. * The host should respond with an `on_scheduled_chat_message` event containing the scheduled chat message details, including the id, character_id, session_id, timestamp, and message content. */ interface LaylaApiScheduledChatMessage { cmd: 'scheduled_chat_message'; data: LaylaScheduledChatMessage; } /** * Ask the host for the list of scheduled chat messages. * The host should respond with an `on_scheduled_chat_message` event containing an array of scheduled messages, each containing the scheduled chat message details, including the id, character_id, session_id, timestamp, and message content. * Note: this API will return ALL scheduled messages. Layla is not designed to handle a large number of scheduled messages, so this API does not support pagination or filtering. The host should return all scheduled messages in a single response and the client should handle any necessary filtering or pagination on its own. */ interface LaylaApiGetScheduledChatMessages { cmd: 'get_scheduled_chat_messages'; data: null; } /** * Ask the host to cancel a previously scheduled chat message by its ID. * The host should remove the scheduled message from its storage and prevent it from being sent at the specified time. * The host should respond with an `on_cancel_scheduled_chat_message` event indicating whether the cancellation was successful or if the scheduled message was not found. */ interface LaylaApiCancelScheduledChatMessage { cmd: 'cancel_scheduled_chat_message'; data: { id: number; }; } /** * Ask the host for the default persona or a specific character's persona. * The host should respond with an `on_get_persona_response` event containing the requested persona data. * If `character_id` is null, the host should return the default persona. */ interface LaylaApiGetPersona { cmd: 'get_persona'; data: { character_id: string | null; }; } /** * Ask the host for the list of available TTS voices installed in Layla. * The host should respond with an `on_get_tts_voices` event containing an array of TTS voices. */ interface LaylaApiGetTTSVoices { cmd: 'get_tts_voices'; data: null; } /** * Ask the host to generate voice audio for the provided text using the specified TTS voice. * The host will generate the audio and automatically play it on device. The host will emit an `on_finished_speaking` event when the playback has finished. * Developer note: * - the host handles queuing of multiple `generate_voice` requests WITH THE SAME `ttsVoiceId`, so the client does not need to manage queuing or waiting for playback to finish before sending the next request. The host will ensure that each request is processed in order and that the `on_finished_speaking` event is emitted after each playback completes. * - if a different `ttsVoiceId` is used in a subsequent request, this incurs a small performance penalty as the host needs to swap TTS models. Additionally, currently queued voices will be cancelled and playback stopped. */ interface LaylaApiGenerateVoice { cmd: 'generate_voice'; data: { ttsVoiceId: string | null; text: string; }; } /** * Ask the host to generate voice audio for the provided text using the specified TTS voice and save it to a file. * The host will generate the audio and save it to a .wav or .mp3 file. The host will respond with `on_generate_voice_to_file_response` event containing the base64-encoded audio data (including the data URI prefix) if the generation was successful, or an error message if there was an error during the generation process. */ interface LaylaApiGenerateVoiceToFile { cmd: 'generate_voice_to_file'; data: { ttsVoiceId: string | null; text: string; save: boolean; }; } /** * Ask the host to stop any in-progress voice audio playback. * The host will immediately stop the playback and emit an `on_finished_speaking` event to indicate that the playback has been stopped. */ interface LaylaApiStopSpeaking { cmd: 'stop_speaking'; data: null; } /** * Ask the host for the list of available inference engines. * The host should respond with an `on_get_inference_engines_response` event containing an array of inference engines names. * These names can be used to set the inference engine before calling `send_message` to generate a response. */ interface LaylaApiGetInferenceEngines { cmd: 'get_inference_engines'; data: null; } /** * Ask the host to set the inference engine to use for subsequent `send_message` requests. * The host should respond with an `on_set_inference_engine_response` event indicating whether the inference engine was set successfully or if the specified engine name was not found. * If the engine is not found, the host should reset to the default inference engine. * If `engineName` is null, the host should reset to the default inference engine. */ interface LaylaApiSetInferenceEngine { cmd: 'set_inference_engine'; data: { engineName: string | null; }; } /** * Ask the host for the current execution context. * The execution context can include information about the current state of the host, such as current character, session, or other relevant data. * The execution context can also be null, which means the mini-app is running standalone as a top-level mini-app, without any character or session context. * The host should respond with an `on_get_execution_context_response` event containing the current execution context. */ interface LaylaApiGetExecutionContext { cmd: 'get_execution_context'; data: null; } /** * Ask the host to start the background audio player and queue the provided audio files for playback. * There is no response event for this request. The host should start the background audio player and queue the provided audio files for playback in the order they are provided. * Starting the player while another queue is already playing replaces that queue entirely. */ interface LaylaApiStartBackgroundAudioPlayer { cmd: 'start_background_audio_player'; data: { queueAudioFiles: string[]; metadata?: { title?: string; artist?: string; albumTitle?: string; artworkUrl?: string; }; }; } /** * Ask the host to stop the background audio player, clear the queue and release the player. * There is no response event for this request. Playback cannot be resumed after this; use pause_background_audio_player if playback should continue later. */ interface LaylaApiStopBackgroundAudioPlayer { cmd: 'stop_background_audio_player'; data: null; } /** * Ask the host to pause the background audio player at its current position. * There is no response event for this request. The queue and playback position are retained. Does nothing if no player is active. */ interface LaylaApiPauseBackgroundAudioPlayer { cmd: 'pause_background_audio_player'; data: null; } /** * Ask the host to resume the background audio player from its current position. * There is no response event for this request. Does nothing if no player is active. */ interface LaylaApiResumeBackgroundAudioPlayer { cmd: 'resume_background_audio_player'; data: null; } /** * Ask the host to skip to another track in the background audio player queue. * There is no response event for this request, but the host emits a background_audio_track_changed event once the track changes. * If index is omitted the host advances to the next track; at the end of the queue this does nothing. Does nothing if no player is active. */ interface LaylaApiSkipBackgroundAudioTrack { cmd: 'skip_background_audio_track'; data: { index?: number; }; } /** * A request command (anything that opens a job and expects events back). * Add new one-shot commands here. `cancel` is not a request — it's a control * signal for an already-open job — so it lives outside this union. */ type LaylaApiRequest = LaylaApiSendMessage | LaylaApiGetCharacters | LaylaApiGetCharacterImage | LaylaApiCancel | LaylaApiGenerateImage | LaylaApiUpdateCharacter | LaylaApiGetChatHistory | LaylaApiGetSentiment | LaylaApiGetChatSessions | LaylaApiSaveChatMessage | LaylaApiSaveFile | LaylaApiReadFile | LaylaApiGetMemories | LaylaApiGetTopMemories | LaylaApiCreateOrUpdateMemories | LaylaApiScheduledChatMessage | LaylaApiCancelScheduledChatMessage | LaylaApiGetScheduledChatMessages | LaylaApiGetPersona | LaylaApiGetTTSVoices | LaylaApiGenerateVoice | LaylaApiStopSpeaking | LaylaApiGetInferenceEngines | LaylaApiSetInferenceEngine | LaylaApiGetExecutionContext | LaylaApiGenerateVoiceToFile | LaylaApiStartBackgroundAudioPlayer | LaylaApiStopBackgroundAudioPlayer | LaylaApiPauseBackgroundAudioPlayer | LaylaApiResumeBackgroundAudioPlayer | LaylaApiSkipBackgroundAudioTrack | LaylaApiGetImageGenerationModels; /** A streamed token. `msg` is the full snapshot, `delta` is new. */ interface LaylaApiEvent_onMsg { event: 'on_message'; data: { msg: string; delta: string; }; } /** Stream finished. */ interface LaylaApiEvent_onMsgEnd { event: 'on_message_end'; } /** Error. Terminates whatever request is in flight, of any kind. */ interface LaylaApiEvent_onError { event: 'on_error'; data: { message: string; }; } /** The character card list for a `get_characters` request. */ interface LaylaApiEvent_onGetCharactersResponse { event: 'on_get_characters_response'; data: LaylaCharacter[]; } /** The character image for a `get_character_image` request, encoded in base64 (includes the data URI prefix) */ interface LaylaApiEvent_onGetCharacterImageResponse { event: 'on_get_character_image_response'; data: { character_id: string; image_data_base64: string | null; } | null; } /** * The generated image for a `generate_image` request, encoded in base64 (includes the data URI prefix). If `image_data_base64` is null, it indicates that there was an error during image generation. */ interface LaylaApiEvent_onGenerateImageResponse { event: 'on_generate_image_response'; data: { image_data_base64: string | null; } | null; } /** * Progress update for a `generate_image` request. The host can emit multiple progress events during the image generation process, providing updates on the current status and progress of the generation. */ interface LaylaApiEvent_onGenerateImageProgress { event: 'on_generate_image_progress'; data: { status: string; steps: number; total_steps: number; }; } /** * The response for an `update_character` request, containing the updated character id after the update is applied. * Note: the ID may not be the same as the one in the request if a new character was created (i.e., if the provided `character_id` did not exist before). In that case, the response will contain the new character ID assigned by the host. */ interface LaylaApiEvent_onUpdateCharacterResponse { event: 'on_update_character_response'; data: { character_id: string; }; } /** * The chat history for a `get_chat_history` request, containing an array of chat messages associated with the specified session ID. * Each message includes the role, content, session ID, and timestamp. The host should return the messages in reverse chronological order (newest to oldest). */ interface LaylaApiEvent_onGetChatHistoryResponse { event: 'on_get_chat_history_response'; data: { session_id: string; messages: LaylaChatHistoryEntry[]; }; } /** * The sentiment analysis results for a `get_sentiment` request, containing the sentiment values for each emotion category defined in `SentimentValues`. * Each sentiment value is a number between 0 and 1, representing the intensity of that emotion in the input text. */ interface LaylaApiEvent_onGetSentimentResponse { event: 'on_get_sentiment_response'; data: { sentiment_values: SentimentValues; }; } /** * The chat sessions for a `get_chat_sessions` request, containing an array of chat sessions associated with the specified character ID. * Each session includes the session ID, last message timestamp, and the last message content. */ interface LaylaApiEvent_onGetChatSessionsResponse { event: 'on_get_chat_sessions_response'; data: { character_id: string; sessions: Array<{ session_id: string; last_message_timestamp: number; last_message_content: string; }>; }; } /** * The response for a `save_chat_message` request, containing the updated chat message after the save is applied. * Note: if the provided `id` in the request was <= 0, this indicates that a new chat message was created. In that case, the response will contain the new chat message with its assigned ID and other details. * If the provided `id` in the request was > 0, this indicates that an existing chat message was updated. In that case, the response will contain the updated chat message with the same ID and updated details. */ interface LaylaApiEvent_onSaveChatMessageResponse { event: 'on_save_chat_message_response'; data: LaylaChatHistoryEntry; } /** * The response for a `save_file` request, indicating whether the file was saved successfully and providing an optional message with additional information about the save operation (e.g., error details if the save was not successful). */ interface LaylaApiEvent_onSaveFileResponse { event: 'on_save_file_response'; data: { filename: string; success: boolean; message?: string; }; } /** * The response for a `read_file` request, containing the file content encoded in base64 (including the data URI prefix) if the read operation was successful. * If there was an error reading the file (e.g., file not found, access denied, etc.), `content_base64` will be null, and an optional message may be provided with additional information about the read operation (e.g., error details). */ interface LaylaApiEvent_onReadFileResponse { event: 'on_read_file_response'; data: { filename: string; content_base64: string | null; message?: string; }; } /** * The response for a `get_memories` request, containing an array of memories associated with the specified character ID in reverse chronological order (newest to oldest). */ interface LaylaApiEvent_onGetMemoriesResponse { event: 'on_get_memories_response'; data: { character_id: string; memories: LaylaMemory[]; }; } /** * The response for a `create_or_update_memories` request, containing the created or updated memories after the operation is applied. */ interface LaylaApiEvent_onCreateOrUpdateMemoriesResponse { event: 'on_create_or_update_memories_response'; data: { character_id: string; memories: LaylaMemory[]; }; } /** * The response for a `get_top_memories` request, containing an array of the top memories associated with the specified character ID in reverse chronological order (newest to oldest). */ interface LaylaApiEvent_onGetTopMemoriesResponse { event: 'on_get_top_memories_response'; data: { character_id: string; memories: LaylaMemory[]; }; } /** * The response for a `scheduled_chat_message` request, containing the scheduled chat message details, including the id, character_id, session_id, timestamp, and message content. * This event is emitted by the host after successfully scheduling a chat message to be sent at a specific timestamp (in the future). */ interface LaylaApiEvent_onScheduledChatMessage { event: 'on_scheduled_chat_message'; data: LaylaScheduledChatMessage; } /** * The response for a `cancel_scheduled_chat_message` request, indicating whether the cancellation was successful or if the scheduled message was not found. * This event is emitted by the host after attempting to cancel a previously scheduled chat message by its ID. */ interface LaylaApiEvent_onCancelScheduledChatMessage { event: 'on_cancel_scheduled_chat_message'; data: { id: number; success: boolean; message?: string; }; } /** * The response for a `get_scheduled_chat_messages` request, containing an array of all scheduled chat messages, each including the id, character_id, session_id, timestamp, and message content. * This event is emitted by the host after successfully retrieving the list of scheduled chat messages. */ interface LaylaApiEvent_onGetScheduledChatMessagesResponse { event: 'on_get_scheduled_chat_messages_response'; data: { scheduled_messages: LaylaScheduledChatMessage[]; }; } /** * The response for a `get_persona` request, containing the requested persona data for a specific character or the default persona if `character_id` is null. * This event is emitted by the host after successfully retrieving the persona data. */ interface LaylaApiEvent_onGetPersonaResponse { event: 'on_get_persona_response'; data: { character_id: string | null; persona: LaylaPersona; }; } /** * The response for a `get_tts_voices` request, containing an array of all available TTS voices installed in Layla. * This event is emitted by the host after successfully retrieving the list of TTS voices. */ interface LaylaApiEvent_onGetTTSVoicesResponse { event: 'on_get_tts_voices_response'; data: { voices: LaylaTTSVoice[]; }; } /** * The response for a `generate_voice` request, indicating that the voice audio playback has finished. * This event is emitted by the host after successfully generating and playing the voice audio for the provided text using the specified TTS voice. * Note: this event is emitted AFTER the playback has completely finished, so the client can use this event to trigger any follow-up actions or UI updates after the voice playback is done. */ interface LaylaApiEvent_onFinishedSpeaking { event: 'on_finished_speaking'; data: null; } interface LaylaApiEvent_onGenerateVoiceToFileResponse { event: 'on_generate_voice_to_file_response'; data: { success: boolean; audio_data_base64: string | null; filename: string | null; message?: string; }; } /** * The response for a `get_inference_engines` request, containing an array of all available inference engine names. * This event is emitted by the host after successfully retrieving the list of inference engines. */ interface LaylaApiEvent_onGetInferenceEnginesResponse { event: 'on_get_inference_engines_response'; data: { engines: string[]; }; } /** * The response for a `set_inference_engine` request, indicating whether the specified inference engine was set successfully. * This event is emitted by the host after attempting to set the inference engine. */ interface LaylaApiEvent_onSetInferenceEngineResponse { event: 'on_set_inference_engine_response'; data: { success: boolean; engineName: string | null; }; } /** * The response for a `get_execution_context` request, containing the current execution context of the mini-app. * The execution context can include information about the current state of the host, such as current character, session, or other relevant data. * If the mini-app is running standalone as a top-level mini-app without any character or session context, the `data` field will be null. */ interface LaylaApiEvent_onGetExecutionContextResponse { event: 'on_get_execution_context_response'; data: LaylaExecutionContext | null; } /** * The contextual event emitted by the host when a new chat message is added to the chat context (e.g., when a user sends a message or when the assistant generates a response). * This event is only emitted by the host when the mini-app is running in a character chat context. * It provides the new chat message along with the associated character ID, session ID, and timestamp. */ interface LaylaApiEvent_onChatContextNewMessage { event: 'on_chat_context_new_message'; data: { message: LaylaChatMessage; character_id: string; session_id: string; timestamp: number; }; } /** * The contextual event emitted by the host when the active sentiment changes in the surrounding character chat. * This event is only emitted by the host when the mini-app is running in a character chat context. * It provides the sentiment category currently selected by the host. */ interface LaylaApiEvent_onChatContextSentimentUpdate { event: 'on_chat_context_sentiment_update'; data: { sentiment: keyof SentimentValues; }; } /** * The contextual event emitted by the host when the character starts speaking in the surrounding character chat. * This event is only emitted by the host when the mini-app is running in a character chat context. */ interface LaylaApiEvent_onChatContextStartedSpeaking { event: 'on_chat_context_started_speaking'; data: null; } /** * The contextual event emitted by the host when the character finishes speaking in the surrounding character chat. * This event uses the same `on_finished_speaking` event name as TTS playback completion and is included separately here to describe its character chat context. */ interface LaylaApiEvent_onChatContextFinishedSpeaking { event: 'on_finished_speaking'; data: null; } /** * The contextual event emitted by the host when the character starts thinking in the surrounding character chat. * This event is only emitted by the host when the mini-app is running in a character chat context. */ interface LaylaApiEvent_onChatContextStartedThinking { event: 'on_chat_context_started_thinking'; data: null; } /** * The event emitted by the host when the background audio player moves to a different track, * either because the previous track finished or because of a skip_background_audio_track request. */ interface LaylaApiEvent_onBackgroundAudioTrackChanged { event: 'on_background_audio_track_changed'; data: { currentIndex: number; previousIndex: number; }; } /** * The event emitted by the host at a regular interval (roughly once per second) while the background audio player is active. * Note that these updates are throttled or suspended entirely while the app is backgrounded, so they must not be used to drive queue logic. */ interface LaylaApiEvent_onBackgroundAudioStatus { event: 'on_background_audio_status'; data: { playing: boolean; currentIndex: number; currentTime: number; duration: number; isLoaded: boolean; }; } /** * The event emitted by the host when the last track in the queue finishes playing. * The player is released at this point, so playback must be restarted with start_background_audio_player. */ interface LaylaApiEvent_onBackgroundAudioFinished { event: 'on_background_audio_finished'; data: null; } interface LaylaApiEvent_onGetImageGenerationModelsResponse { event: 'on_get_image_generation_models_response'; data: { id: string; name: string; description: string; }[]; } type LaylaApiEvent = LaylaApiEvent_onMsg | LaylaApiEvent_onMsgEnd | LaylaApiEvent_onError | LaylaApiEvent_onGetCharactersResponse | LaylaApiEvent_onGetCharacterImageResponse | LaylaApiEvent_onGenerateImageResponse | LaylaApiEvent_onGenerateImageProgress | LaylaApiEvent_onUpdateCharacterResponse | LaylaApiEvent_onGetChatHistoryResponse | LaylaApiEvent_onGetSentimentResponse | LaylaApiEvent_onGetChatSessionsResponse | LaylaApiEvent_onSaveChatMessageResponse | LaylaApiEvent_onSaveFileResponse | LaylaApiEvent_onReadFileResponse | LaylaApiEvent_onGetMemoriesResponse | LaylaApiEvent_onGetTopMemoriesResponse | LaylaApiEvent_onCreateOrUpdateMemoriesResponse | LaylaApiEvent_onScheduledChatMessage | LaylaApiEvent_onCancelScheduledChatMessage | LaylaApiEvent_onGetScheduledChatMessagesResponse | LaylaApiEvent_onGetPersonaResponse | LaylaApiEvent_onGetTTSVoicesResponse | LaylaApiEvent_onGetInferenceEnginesResponse | LaylaApiEvent_onSetInferenceEngineResponse | LaylaApiEvent_onFinishedSpeaking | LaylaApiEvent_onGetExecutionContextResponse | LaylaApiEvent_onChatContextNewMessage | LaylaApiEvent_onChatContextSentimentUpdate | LaylaApiEvent_onChatContextStartedSpeaking | LaylaApiEvent_onChatContextStartedThinking | LaylaApiEvent_onChatContextFinishedSpeaking | LaylaApiEvent_onGenerateVoiceToFileResponse | LaylaApiEvent_onBackgroundAudioTrackChanged | LaylaApiEvent_onBackgroundAudioStatus | LaylaApiEvent_onBackgroundAudioFinished | LaylaApiEvent_onGetImageGenerationModelsResponse; /** * errors.ts * --------- * The error hierarchy. Everything the SDK throws or rejects with extends * `LaylaError`, so consumers can `catch (e) { if (e instanceof LaylaError) ... }`. */ declare class LaylaError extends Error { constructor(message: string); } declare class LaylaAbortError extends LaylaError { constructor(message?: string); } declare class LaylaBridgeUnavailableError extends LaylaError { constructor(); } /** * internal/one-shot.ts * -------------------- * The reusable primitive for every request/response endpoint. * * `OneShotRequest` is a Deferred wearing the BridgeSink interface: you give it * the command to send, the name of the event that answers it, and how to pull * the result out of that event. It resolves on the response event and rejects * on error/abort. The `oneShot` helper wires up the AbortSignal and enqueues. * Adding a new endpoint needs neither a new class here nor any bridge change. */ /** Shared options for one-shot requests. */ interface RequestOptions { /** Abort the request from the consumer side. */ signal?: AbortSignal; } /** * internal/bridge.ts * ------------------ * The single low-level transport over the WebView message channel. * * Owns one global `message` listener and serialises requests, because the * current protocol has no request id to correlate concurrent jobs. Every job — * chat completions and one-shot requests alike — flows through the same queue * and single active slot, so a one-shot waits behind an in-flight generation * rather than racing it. * * The bridge is intentionally event-agnostic: it routes every parsed event to * the active job's sink and lets the sink say when it's done. The only event it * special-cases is `on_error`, which terminates any job. New request/response * shapes therefore need NO changes here. If you add an `id` field to both * `LaylaApiMessage` and `LaylaApiEvent`, this is the one place that would change * to support true concurrency. */ /** * Everything the bridge needs from a job. A sink consumes the inbound event * stream for the active request and reports when the request is complete. */ interface BridgeSink { /** * Handle one parsed RN->web event (never `on_error`; the bridge routes that * to `fail`). Return `true` when this event terminates the request, so the * bridge can free the active slot and pump the next job. Return `false` for * events that are not yours or that don't end the request. */ accept(event: LaylaApiEvent): boolean; /** Terminate the request with an error (host error, abort, missing bridge). */ fail(err: Error): void; isClosed(): boolean; /** * Optional: the message to post to the host if this request is cancelled * while in flight. Streaming generation returns `{ cmd: 'cancel' }`; one-shot * requests return nothing (there's no generation to stop — they just close * locally and the host's eventual response frees the slot). */ cancelMessage?(): LaylaApiRequest | null; } /** * resources/chat/types.ts * ----------------------- * The OpenAI-shaped output and parameter types for chat completions. These are * the SDK's public surface for chat, not the native wire protocol. */ interface ChatCompletionChunk { id: string; object: 'chat.completion.chunk'; created: number; model: string; choices: Array<{ index: number; delta: { role?: 'assistant'; content?: string; reasoning?: string; }; finish_reason: 'stop' | null; }>; } interface ChatCompletion { id: string; object: 'chat.completion'; created: number; model: string; choices: Array<{ index: number; message: { role: 'assistant'; content: string; reasoning?: string; }; finish_reason: 'stop'; }>; } interface ChatCompletionCreateParamsBase { messages: LaylaChatMessage[]; /** * Accepted for OpenAI compatibility. The Layla host currently picks the * model itself, so this is only used to populate the `model` field on the * returned objects unless you extend the `send_message` protocol. */ model?: string; stream?: boolean; /** Abort the request from the consumer side. */ signal?: AbortSignal; } interface ChatCompletionCreateParamsNonStreaming extends ChatCompletionCreateParamsBase { stream?: false; } interface ChatCompletionCreateParamsStreaming extends ChatCompletionCreateParamsBase { stream: true; } /** * resources/chat/stream.ts * ------------------------ * ChatCompletionStream: the user-facing streaming object. * * - Async-iterable of ChatCompletionChunk (the OpenAI `for await` pattern) * - Event emitter: 'content' | 'chunk' | 'end' | 'error' * - Convenience: finalContent(), finalChatCompletion() * * Implements BridgeSink so the bridge can drive it from `on_message*` events. */ type Listener = (...args: any[]) => void; declare class ChatCompletionStream implements BridgeSink, AsyncIterable { private readonly id; private readonly created; private readonly model; private buffer; private resolvers; private rejectors; private rawSnapshot; private contentSnapshot; private reasoningSnapshot; private pendingTag; private inReasoning; private ended; private closed; private failure; private listeners; private finalDeferred; constructor(model: string); on(event: 'content', listener: (delta: string, snapshot: string) => void): this; on(event: 'reasoning', listener: (delta: string, snapshot: string) => void): this; on(event: 'chunk', listener: (chunk: ChatCompletionChunk) => void): this; on(event: 'end', listener: () => void): this; on(event: 'error', listener: (err: Error) => void): this; off(event: string, listener: Listener): this; private emit; accept(event: LaylaApiEvent): boolean; fail(err: Error): void; isClosed(): boolean; cancelMessage(): LaylaApiCancel; /** Abort from the consumer side. */ abort(reason?: unknown): void; private handleDelta; private handleEnd; next(): Promise>; /** Breaking out of `for await` aborts the request, like the OpenAI SDK. */ return(): Promise>; [Symbol.asyncIterator](): AsyncIterator; finalChatCompletion(): Promise; finalContent(): Promise; private pushChunk; private drainDone; private drainError; private resolveRawDelta; private parseTaggedDelta; private flushPendingTag; private makeChunk; private buildCompletion; } /** * resources/chat/index.ts * ----------------------- * The chat resource: completions, session/history reads, and message saves. * Completions mirror the OpenAI SDK shape. Re-exports the public chat types * and the stream class for the package barrel. */ declare class Completions { create(body: ChatCompletionCreateParamsNonStreaming): Promise; create(body: ChatCompletionCreateParamsStreaming): Promise; /** * OpenAI-style helper: returns the live stream object synchronously (not a * promise), so you can attach `.on(...)` listeners before any token arrives. */ stream(body: Omit): ChatCompletionStream; private startStream; } declare class Chat { readonly completions: Completions; /** * Fetch the inference engines available for subsequent chat completions. */ getInferenceEngines(options?: RequestOptions): Promise; /** * Select the inference engine used for subsequent chat completions. * Pass `null` to reset to the host's default engine. */ setInferenceEngine(engineName: string | null, options?: RequestOptions): Promise; /** * Ask the native host for a character's chat history. Resolves once with the host's `on_get_chat_history_response` payload, or rejects on error/abort. * Results are in reverse chronological order (newest first). Use `offset` and `range` to page through the history if needed. * @param sessionId The ID of the session whose chat history is being requested. * @param offset The starting point for the chat history results. * @param range The number of chat history entries to retrieve. * @param options Additional request options. * @returns A promise that resolves to an array of chat history entries. */ getChatHistory(sessionId: string, offset?: number, range?: number, options?: RequestOptions): Promise; /** * Ask the native host for a character's chat sessions. Resolves once with the host's `on_get_chat_sessions_response` payload, or rejects on error/abort. * Results are in reverse chronological order (newest first). Use `offset` and `range` to page through the sessions if needed. * @param characterId The ID of the character whose chat sessions are being requested. * @param offset The starting point for the chat sessions results. * @param range The number of chat sessions to retrieve. * @param options Additional request options. * @returns A promise that resolves to an object containing the chat sessions. */ getChatSessions(characterId: string, offset?: number, range?: number, options?: RequestOptions): Promise; /** * Create or update a chat history entry. Pass an id less than or equal to * zero to create a message, or an existing positive id to update it. * @param message The complete chat history entry to save. * @param options Additional request options. * @returns A promise that resolves to the saved entry, including its assigned id. */ saveChatMessage(message: LaylaChatHistoryEntry, options?: RequestOptions): Promise; /** * Schedule a chat message to be sent by the host at a future timestamp. * Pass `id <= 0` when creating a new scheduled message; the host returns the * saved message with its assigned id. */ scheduleChatMessage(message: LaylaScheduledChatMessage, options?: RequestOptions): Promise; /** * Fetch all scheduled chat messages known to the host. * * The host API is intentionally unpaged; callers should filter locally when * they only need scheduled messages for one character or session. */ getScheduledChatMessages(options?: RequestOptions): Promise; /** * Cancel a scheduled chat message by id. */ cancelScheduledChatMessage(id: number, options?: RequestOptions): Promise; } /** * resources/images.ts * ----------------------- * The images resource: `layla.images.generateImage()`. * */ /** A single image generation model available on the host. */ type LaylaImageGenerationModel = LaylaApiEvent_onGetImageGenerationModelsResponse['data'][number]; declare class Images { /** * Ask the native host for the list of image generation models that are * immediately available for use. Models that are not downloaded are omitted. * * Pass a returned model's `id` as the `modelId` argument to * {@link Images.generateImage} to generate with that specific model. */ getImageGenerationModels(options?: RequestOptions): Promise; /** * Ask the native host to generate an image. Resolves to a ready-to-use base64 image src string, or null if the character has no image * * Pass `modelId` to generate with a specific image model (one of the `id`s * returned by {@link Images.getImageGenerationModels}). When omitted, the host * uses its default image model. */ generateImage(prompt: string, onProgress: (status: string, step: number, total_step: number) => void, img2img_base64?: string, modelId?: string, options?: RequestOptions): Promise; } /** * Utility APIs that do not belong to a domain-specific resource. */ type SaveFileResult = LaylaApiEvent_onSaveFileResponse['data']; type ReadFileResult = LaylaApiEvent_onReadFileResponse['data']; declare class Utils { /** * Ask the native host to save base64-encoded file content. * * `contentBase64` must not include a data URI prefix. */ saveFile(filename: string, contentBase64: string, share?: boolean, options?: RequestOptions): Promise; /** * Ask the native host to read file content from the app's private directory. * * The returned `content_base64` includes a data URI prefix when available. */ readFile(filename: string, options?: RequestOptions): Promise; } /** * resources/memories.ts * --------------------- * Memory CRUD-ish helpers backed by the host's memory protocol endpoints. */ interface MemoryListOptions extends RequestOptions { /** Only return memories created after this timestamp. */ minTimestamp?: number; /** Only return memories created before this timestamp. */ maxTimestamp?: number; } declare class Memories { /** * Ask the native host for memories attached to a character. * Results are returned newest first. */ list(characterId: string, offset?: number, range?: number, options?: MemoryListOptions): Promise; /** * Ask the native host for the top memories attached to a character. * The host determines the ranking heuristic. */ getTopMemories(characterId: string, limit?: number, options?: RequestOptions): Promise; /** * Create or update memories. Pass `id <= 0` to create a new memory, or an * existing positive id to update it. */ createOrUpdate(memories: LaylaMemory[], options?: RequestOptions): Promise; } /** * resources/personas.ts * --------------------- * Persona helpers backed by the host's persona protocol endpoint. */ declare class Personas { /** * Ask the native host for the default persona, or a character-specific * persona when a character id is provided. */ get(characterId?: string | null, options?: RequestOptions): Promise; } /** * resources/tts.ts * ---------------- * Text-to-speech helpers backed by the host's TTS protocol endpoints. */ type GenerateVoiceToFileResult = LaylaApiEvent_onGenerateVoiceToFileResponse['data']; declare class TTS { /** * Ask the native host for all available TTS voices installed in Layla. */ getVoices(options?: RequestOptions): Promise; /** * Ask the native host to generate and play voice audio for the provided text. * Pass `null` to use the global default TTS voice. * * Resolves after the host emits `on_finished_speaking`, which indicates that * audio playback has completed. */ generateVoice(ttsVoiceId: string | null, text: string, options?: RequestOptions): Promise; /** * Generate voice audio without playing it. * * When `save` is false, the result contains `audio_data_base64` including * its data URI prefix. When true, the host saves the audio and returns its * `filename` instead. */ generateVoiceToFile(ttsVoiceId: string | null, text: string, save?: boolean, options?: RequestOptions): Promise; /** * Ask the native host to stop any in-progress voice playback. * * This control message bypasses the normal request queue so it can interrupt * an active `generateVoice(...)` call. */ stopSpeaking(options?: RequestOptions): Promise; } /** * Background audio player controls and events. * * Control methods are fire-and-forget at the host protocol level. Their * promises resolve once the command has been posted to the Layla WebView * bridge; player state is reported through this resource's events. */ type BackgroundAudioMetadata = NonNullable; type BackgroundAudioTrackChanged = LaylaApiEvent_onBackgroundAudioTrackChanged['data']; type BackgroundAudioStatus = LaylaApiEvent_onBackgroundAudioStatus['data']; type BackgroundAudioFinished = LaylaApiEvent_onBackgroundAudioFinished['data']; type BackgroundAudioTrackChangedListener = (data: BackgroundAudioTrackChanged) => void; type BackgroundAudioStatusListener = (data: BackgroundAudioStatus) => void; type BackgroundAudioFinishedListener = (data: BackgroundAudioFinished) => void; declare class BackgroundAudio { private readonly trackChangedListeners; private readonly statusListeners; private readonly finishedListeners; private listening; /** Start playback, replacing any existing background-audio queue. */ start(queueAudioFiles: string[], metadata?: BackgroundAudioMetadata): Promise; /** Stop playback, clear the queue, and release the player. */ stop(): Promise; /** Pause playback while retaining the queue and current position. */ pause(): Promise; /** Resume a paused player from its current position. */ resume(): Promise; /** Skip to a zero-based queue index, or to the next track when omitted. */ skip(index?: number): Promise; on(event: 'trackChanged', listener: BackgroundAudioTrackChangedListener): this; on(event: 'status', listener: BackgroundAudioStatusListener): this; on(event: 'finished', listener: BackgroundAudioFinishedListener): this; off(event: 'trackChanged', listener: BackgroundAudioTrackChangedListener): this; off(event: 'status', listener: BackgroundAudioStatusListener): this; off(event: 'finished', listener: BackgroundAudioFinishedListener): this; private post; private hasListeners; private ensureListening; private stopListening; private onWindowMessage; private emit; } /** * resources/contextual.ts * ----------------------- * Helpers for mini-apps launched inside a character chat context. */ type ChatContextNewMessage = LaylaApiEvent_onChatContextNewMessage['data']; type ChatContextNewMessageListener = (data: ChatContextNewMessage) => void; type ChatContextSentimentUpdate = LaylaApiEvent_onChatContextSentimentUpdate['data']; type ChatContextSentimentUpdateListener = (data: ChatContextSentimentUpdate) => void; type ChatContextStartedSpeaking = LaylaApiEvent_onChatContextStartedSpeaking['data']; type ChatContextStartedSpeakingListener = (data: ChatContextStartedSpeaking) => void; type ChatContextFinishedSpeaking = LaylaApiEvent_onChatContextFinishedSpeaking['data']; type ChatContextFinishedSpeakingListener = (data: ChatContextFinishedSpeaking) => void; type ChatContextStartedThinking = LaylaApiEvent_onChatContextStartedThinking['data']; type ChatContextStartedThinkingListener = (data: ChatContextStartedThinking) => void; declare class Contextual { private readonly chatContextNewMessageListeners; private readonly chatContextSentimentUpdateListeners; private readonly chatContextStartedSpeakingListeners; private readonly chatContextFinishedSpeakingListeners; private readonly chatContextStartedThinkingListeners; private listening; /** * Ask the native host for the context in which this mini-app is running. * Returns `null` for a standalone top-level mini-app. */ getExecutionContext(options?: RequestOptions): Promise; /** Listen for activity in the surrounding character chat. */ on(event: 'chatContextNewMessage', listener: ChatContextNewMessageListener): this; on(event: 'chatContextSentimentUpdate', listener: ChatContextSentimentUpdateListener): this; on(event: 'chatContextStartedSpeaking', listener: ChatContextStartedSpeakingListener): this; on(event: 'chatContextFinishedSpeaking', listener: ChatContextFinishedSpeakingListener): this; on(event: 'chatContextStartedThinking', listener: ChatContextStartedThinkingListener): this; /** Stop listening for activity in the surrounding character chat. */ off(event: 'chatContextNewMessage', listener: ChatContextNewMessageListener): this; off(event: 'chatContextSentimentUpdate', listener: ChatContextSentimentUpdateListener): this; off(event: 'chatContextStartedSpeaking', listener: ChatContextStartedSpeakingListener): this; off(event: 'chatContextFinishedSpeaking', listener: ChatContextFinishedSpeakingListener): this; off(event: 'chatContextStartedThinking', listener: ChatContextStartedThinkingListener): this; private hasListeners; private ensureListening; private stopListening; private onWindowMessage; private emit; } /** * resources/characters.ts * ----------------------- * The characters resource: `layla.characters.list()`. * * This is the template for any one-shot endpoint — a single `oneShot(...)` call * giving the command, the response event name, and how to read the payload. * Copy this file to add a new resource (e.g. `settings.ts` -> `Settings.get`). */ declare class Characters { /** * Ask the native host for the available character cards. Resolves once with * the host's `on_get_characters_response` payload, or rejects on error/abort. */ list(offset?: number, range?: number, options?: RequestOptions): Promise; /** * Ask the native host for a character portrait. Resolves to a ready-to-use * image src string, or null when the character has no image. */ getImage(characterId: string, options?: RequestOptions): Promise; /** * Ask the native host to update a character's data. Resolves once the update is successful, with the character ID. Rejects on error/abort. */ update(char: LaylaCharacter, options?: RequestOptions): Promise; } /** * resources/classifier.ts * ----------------------- * The classifier resource: `layla.classifier.getSentiment()`. * * This is the template for any one-shot endpoint — a single `oneShot(...)` call * giving the command, the response event name, and how to read the payload. * Copy this file to add a new resource (e.g. `settings.ts` -> `Settings.get`). */ declare class Classifier { /** * Ask the native host for the sentiment of a given text. Resolves once with the host's `on_get_sentiment_response` payload, or rejects on error/abort. * @param text The text to analyze for sentiment. * @param options Additional request options. * @returns A promise that resolves to the sentiment analysis result. */ getSentiment(text: string, options?: RequestOptions): Promise; } /** * client.ts * --------- * The top-level client. Composes the resources into the object users interact * with. Add a new resource by importing it and assigning it a readonly field. */ interface LaylaSDKOptions { /** Reserved for future use (e.g. default model). */ model?: string; } declare class LaylaSDK { readonly chat: Chat; readonly characters: Characters; readonly images: Images; readonly classifier: Classifier; readonly utils: Utils; readonly memories: Memories; readonly personas: Personas; readonly tts: TTS; readonly contextual: Contextual; readonly backgroundAudio: BackgroundAudio; constructor(_options?: LaylaSDKOptions); } /** * mock.ts * ------- * A fake Layla native host for running the SDK OUTSIDE the app (Vite dev server, * Storybook, a browser test, etc.). It installs a stand-in * `window.ReactNativeWebView` and answers the web->RN commands by dispatching the * same `MessageEvent`s the real host would, so the SDK's bridge, queue, * streaming, and cancel paths all run for real against it. * * Usage (Vite — install in dev before you use the SDK): * * // main.ts * if (import.meta.env.DEV) { * const { installLaylaMock } = await import('layla-sdk/mock'); * installLaylaMock({ debug: true }); * } * * Install BEFORE the SDK posts its first message; otherwise the bridge sees no * host and rejects with LaylaBridgeUnavailableError. */ type MockReply = string | string[] | Iterable | AsyncIterable; type MockChatHistorySource = LaylaChatHistoryEntry[] | Record; type MockMemorySource = LaylaMemory[] | Record; type MockPersonaSource = Record; type MockFileSource = Record; type MockScheduledChatMessageSource = LaylaScheduledChatMessage[]; type MockImageGenerationModel = LaylaApiEvent_onGetImageGenerationModelsResponse['data'][number]; interface LaylaMockOptions { /** * Produce the assistant reply for a `send_message`. Return a string (which the * mock tokenises and streams), an array of pre-split tokens, or an * (async) iterable of tokens for full control over timing/content. May be * async. Defaults to a canned reply that echoes the last user message. */ respond?: (messages: LaylaChatMessage[]) => MockReply | Promise; /** Cards returned by `get_characters`. Defaults to two sample cards. */ characters?: LaylaCharacter[]; /** * Initial messages used by chat session/history reads and message saves. * Pass an array of all messages, or a record of message arrays keyed by * session id, character id, or any app-specific label. */ chatHistory?: MockChatHistorySource; /** * Initial memories used by memory list and create/update calls. * Pass an array of all memories, or a record of memory arrays keyed by * character id or any app-specific label. */ memories?: MockMemorySource; /** Default persona returned by `get_persona` when no character id is passed. */ persona?: LaylaPersona; /** Character-specific personas keyed by character id. */ personas?: MockPersonaSource; /** * Initial private app files used by `utils.readFile`. * Values may be raw base64 strings or ready-to-use data URIs. */ files?: MockFileSource; /** * Initial scheduled chat messages used by scheduled-message APIs. */ scheduledChatMessages?: MockScheduledChatMessageSource; /** * Inference engines returned by `chat.getInferenceEngines()`. * Defaults to three sample engines. */ inferenceEngines?: string[]; /** * Context returned by `contextual.getExecutionContext()`. * Defaults to `null`, matching a standalone top-level mini-app. */ executionContext?: LaylaExecutionContext | null; /** TTS voices returned by `tts.getVoices()`. Defaults to two sample voices. */ ttsVoices?: LaylaTTSVoice[]; /** * Image generation models returned by `images.getImageGenerationModels()`. * Defaults to two sample models. */ imageGenerationModels?: MockImageGenerationModel[]; /** Delay before the first event of a response (simulated latency). Default 150ms. */ latencyMs?: number; /** Delay between streamed tokens. Default 40ms. */ tokenDelayMs?: number; /** 0..1 probability that a request fails with on_error, for testing error paths. Default 0. */ errorRate?: number; /** Log every web->RN command and RN->web event to the console. */ debug?: boolean; } interface LaylaMockHandle { /** Emit a background-audio track change for listener testing. */ emitBackgroundAudioTrackChanged(data: LaylaApiEvent_onBackgroundAudioTrackChanged['data']): void; /** Emit a background-audio status update for listener testing. */ emitBackgroundAudioStatus(data: LaylaApiEvent_onBackgroundAudioStatus['data']): void; /** Emit background-audio completion for listener testing. */ emitBackgroundAudioFinished(): void; /** Emit a host-pushed message event for contextual listener testing. */ emitChatContextNewMessage(data: LaylaApiEvent_onChatContextNewMessage['data']): void; /** Emit a host-pushed sentiment update for contextual listener testing. */ emitChatContextSentimentUpdate(data: LaylaApiEvent_onChatContextSentimentUpdate['data']): void; /** Emit a host-pushed speaking-start event for contextual listener testing. */ emitChatContextStartedSpeaking(): void; /** Emit a host-pushed speaking-finished event for contextual listener testing. */ emitChatContextFinishedSpeaking(): void; /** Emit a host-pushed thinking-start event for contextual listener testing. */ emitChatContextStartedThinking(): void; /** Remove the fake bridge and restore whatever was there before. */ uninstall(): void; } /** Build a valid Character Card V2 with sensible mock defaults. */ declare function makeMockCharacter(name: string, overrides?: Partial): LaylaCharacter; declare function installLaylaMock(options?: LaylaMockOptions): LaylaMockHandle; export { BackgroundAudio, type BackgroundAudioFinished, type BackgroundAudioFinishedListener, type BackgroundAudioMetadata, type BackgroundAudioStatus, type BackgroundAudioStatusListener, type BackgroundAudioTrackChanged, type BackgroundAudioTrackChangedListener, type ChatCompletion, type ChatCompletionChunk, type ChatCompletionCreateParamsBase, type ChatCompletionCreateParamsNonStreaming, type ChatCompletionCreateParamsStreaming, ChatCompletionStream, type ChatContextFinishedSpeaking, type ChatContextFinishedSpeakingListener, type ChatContextNewMessage, type ChatContextNewMessageListener, type ChatContextSentimentUpdate, type ChatContextSentimentUpdateListener, type ChatContextStartedSpeaking, type ChatContextStartedSpeakingListener, type ChatContextStartedThinking, type ChatContextStartedThinkingListener, Contextual, type GenerateVoiceToFileResult, Images, LaylaSDK as Layla, LaylaAbortError, type LaylaApiCancel, type LaylaApiCancelScheduledChatMessage, type LaylaApiCreateOrUpdateMemories, type LaylaApiEvent, type LaylaApiEvent_onBackgroundAudioFinished, type LaylaApiEvent_onBackgroundAudioStatus, type LaylaApiEvent_onBackgroundAudioTrackChanged, type LaylaApiEvent_onCancelScheduledChatMessage, type LaylaApiEvent_onChatContextFinishedSpeaking, type LaylaApiEvent_onChatContextNewMessage, type LaylaApiEvent_onChatContextSentimentUpdate, type LaylaApiEvent_onChatContextStartedSpeaking, type LaylaApiEvent_onChatContextStartedThinking, type LaylaApiEvent_onCreateOrUpdateMemoriesResponse, type LaylaApiEvent_onError, type LaylaApiEvent_onFinishedSpeaking, type LaylaApiEvent_onGenerateImageProgress, type LaylaApiEvent_onGenerateImageResponse, type LaylaApiEvent_onGenerateVoiceToFileResponse, type LaylaApiEvent_onGetCharacterImageResponse, type LaylaApiEvent_onGetCharactersResponse, type LaylaApiEvent_onGetChatHistoryResponse, type LaylaApiEvent_onGetChatSessionsResponse, type LaylaApiEvent_onGetExecutionContextResponse, type LaylaApiEvent_onGetImageGenerationModelsResponse, type LaylaApiEvent_onGetInferenceEnginesResponse, type LaylaApiEvent_onGetMemoriesResponse, type LaylaApiEvent_onGetPersonaResponse, type LaylaApiEvent_onGetScheduledChatMessagesResponse, type LaylaApiEvent_onGetSentimentResponse, type LaylaApiEvent_onGetTTSVoicesResponse, type LaylaApiEvent_onGetTopMemoriesResponse, type LaylaApiEvent_onMsg, type LaylaApiEvent_onMsgEnd, type LaylaApiEvent_onReadFileResponse, type LaylaApiEvent_onSaveChatMessageResponse, type LaylaApiEvent_onSaveFileResponse, type LaylaApiEvent_onScheduledChatMessage, type LaylaApiEvent_onSetInferenceEngineResponse, type LaylaApiEvent_onUpdateCharacterResponse, type LaylaApiGenerateImage, type LaylaApiGenerateVoice, type LaylaApiGenerateVoiceToFile, type LaylaApiGetCharacterImage, type LaylaApiGetCharacters, type LaylaApiGetChatHistory, type LaylaApiGetChatSessions, type LaylaApiGetExecutionContext, type LaylaApiGetImageGenerationModels, type LaylaApiGetInferenceEngines, type LaylaApiGetMemories, type LaylaApiGetPersona, type LaylaApiGetScheduledChatMessages, type LaylaApiGetSentiment, type LaylaApiGetTTSVoices, type LaylaApiGetTopMemories, type LaylaApiPauseBackgroundAudioPlayer, type LaylaApiReadFile, type LaylaApiRequest, type LaylaApiResumeBackgroundAudioPlayer, type LaylaApiSaveChatMessage, type LaylaApiSaveFile, type LaylaApiScheduledChatMessage, type LaylaApiSendMessage, type LaylaApiSetInferenceEngine, type LaylaApiSkipBackgroundAudioTrack, type LaylaApiStartBackgroundAudioPlayer, type LaylaApiStopBackgroundAudioPlayer, type LaylaApiStopSpeaking, type LaylaApiUpdateCharacter, LaylaBridgeUnavailableError, type LaylaCharacter, type LaylaChatHistoryEntry, type LaylaChatMessage, type LaylaChatRole, LaylaError, type LaylaExecutionContext, type LaylaImageGenerationModel, type LaylaMemory, type LaylaPersona, LaylaSDK, type LaylaSDKOptions, type LaylaScheduledChatMessage, type LaylaTTSVoice, Memories, type MemoryListOptions, Personas, type ReadFileResult, type RequestOptions, SENTIMENT_THRESHOLDS, type SaveFileResult, type SentimentValues, TTS, type TavernCardV2, type TavernCharacterBook, Utils, LaylaSDK as default, installLaylaMock, makeMockCharacter };