@devicai/ui 0.61.2 → 0.62.1
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/dist/cjs/api/client.js +3 -2
- package/dist/cjs/api/client.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/LiveVoicePanel.js +8 -4
- package/dist/cjs/components/ChatDrawer/LiveVoicePanel.js.map +1 -1
- package/dist/cjs/hooks/useDevicChat.js +7 -0
- package/dist/cjs/hooks/useDevicChat.js.map +1 -1
- package/dist/cjs/hooks/useDevicLiveVoice.js +1 -0
- package/dist/cjs/hooks/useDevicLiveVoice.js.map +1 -1
- package/dist/cjs/styles.css +1 -1
- package/dist/cjs/voice/LiveVoiceController.js +102 -2
- package/dist/cjs/voice/LiveVoiceController.js.map +1 -1
- package/dist/esm/api/client.d.ts +2 -1
- package/dist/esm/api/client.js +3 -2
- package/dist/esm/api/client.js.map +1 -1
- package/dist/esm/api/liveVoice.types.d.ts +5 -0
- package/dist/esm/components/ChatDrawer/LiveVoicePanel.js +8 -4
- package/dist/esm/components/ChatDrawer/LiveVoicePanel.js.map +1 -1
- package/dist/esm/hooks/useDevicChat.js +7 -0
- package/dist/esm/hooks/useDevicChat.js.map +1 -1
- package/dist/esm/hooks/useDevicLiveVoice.d.ts +2 -0
- package/dist/esm/hooks/useDevicLiveVoice.js +1 -0
- package/dist/esm/hooks/useDevicLiveVoice.js.map +1 -1
- package/dist/esm/styles.css +1 -1
- package/dist/esm/voice/LiveVoiceController.d.ts +10 -0
- package/dist/esm/voice/LiveVoiceController.js +102 -2
- package/dist/esm/voice/LiveVoiceController.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/api/client.js
CHANGED
|
@@ -186,8 +186,9 @@ class DevicApiClient {
|
|
|
186
186
|
method: 'POST', body: JSON.stringify(body),
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
/** `touch`: the person confirmed they are still on the call; the server restarts its idle clock. */
|
|
190
|
+
getLiveSessionStatus(assistantId, sessionId, touch = false) {
|
|
191
|
+
return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}${touch ? '?touch=1' : ''}`);
|
|
191
192
|
}
|
|
192
193
|
closeLiveSession(assistantId, sessionId) {
|
|
193
194
|
return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}`, { method: 'DELETE', keepalive: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../../../src/api/client.ts"],"sourcesContent":["import { consumeChatStream } from '../utils/consumeChatStream';\nimport type { CreateLiveSessionRequest, LiveVoiceSession, LiveVoiceSessionStatus, LiveVoiceRecording, LiveVoiceUsage } from './liveVoice.types';\nimport type {\n ProcessMessageDto,\n ChatMessage,\n AsyncResponse,\n RealtimeChatHistory,\n ChatHistory,\n AssistantSpecialization,\n ApiError,\n ToolCallResponse,\n ConversationSummary,\n ListConversationsResponse,\n FeedbackSubmission,\n FeedbackEntry,\n AgentThreadDto,\n AgentDto,\n WhisperTranscriptionResponse,\n TenantUsage,\n TenantUsageHistoryRow,\n TenantUsageHistoryQuery,\n CoreMemoryList,\n CoreMemoryEntry,\n Integration,\n TenantMcpAuthInput,\n TenantMcpConnectResult,\n TenantMcpListing,\n IntegrationAuthScheme,\n IntegrationSetupRequired,\n ModelInterfaceToolSchema,\n StopChatResponse,\n} from \"./types\";\n\n/**\n * A tenant session, as the integrator's backend hands it over.\n *\n * A bare string is accepted too — the expiry is then read out of the token\n * itself, so the simplest possible source still gets proactive renewal.\n */\nexport interface TenantSessionToken {\n token: string;\n /** Epoch milliseconds. */\n expiresAt?: number;\n /** Seconds from now. Used when `expiresAt` is absent. */\n expiresIn?: number;\n}\n\nexport interface DevicApiClientConfig {\n /**\n * The public API key. Optional when `getTenantSession` is supplied — a page\n * using tenant sessions has no reason to carry one.\n */\n apiKey?: string;\n baseUrl: string;\n /**\n * Where the tenant session comes from.\n *\n * Supplying this changes what the tenant IS: with an API key alone the tenant\n * is whatever the page says it is, and the page can say anything. With a\n * session it is what your server signed.\n *\n * A function rather than a value because it is called again on its own —\n * before the token expires and after the API rejects one. It does not have to\n * reach your backend: reading a cookie your login already set is a perfectly\n * good answer, and then the whole thing is `async () => readCookie(…)`.\n *\n * It is called with `force: true` when the API has just rejected the token in\n * hand, meaning a cached answer is known to be dead. Your own function can\n * ignore the argument — `DevicProvider` uses it to share one session across\n * every component without ever serving a refused token back.\n */\n getTenantSession?: (force?: boolean) => Promise<string | TenantSessionToken>;\n /**\n * Called when the session is dead and cannot be replaced — the API rejected\n * it and `getTenantSession` handed back the same expired token.\n *\n * Matters most when the session comes from a cookie with no way to renew it:\n * without this the widget simply stops answering, at the exact moment the\n * user's own login has also expired. Refresh the page, send them to log in,\n * or say something — but say it.\n */\n onSessionExpired?: () => void;\n}\n\n/** Renew this long before expiry, so a request never leaves with a dead token. */\nconst RENEWAL_MARGIN_MS = 60_000;\n\n/**\n * The expiry inside a JWT, in epoch milliseconds.\n *\n * Read rather than required, so the session source can return just the string.\n * Any failure means \"no idea\", and the token is then renewed only when the API\n * rejects it — correct, just less graceful.\n */\nfunction expiryOf(token: string): number | undefined {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return undefined;\n const json = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const exp = JSON.parse(json)?.exp;\n return typeof exp === \"number\" ? exp * 1000 : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n private session?: { token: string; expiresAt?: number };\n /** In flight renewal, shared so a burst of calls fetches one token. */\n private renewing?: Promise<string>;\n /** So a page full of widgets reports one expiry, not one per widget. */\n private expiryReported = false;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n const previous = this.config;\n this.config = { ...this.config, ...config };\n // A new session source speaks for a different end user; keeping the old\n // token would show them the previous one's conversations.\n if (\n config.getTenantSession &&\n config.getTenantSession !== previous.getTenantSession\n ) {\n this.session = undefined;\n this.expiryReported = false;\n }\n }\n\n /** The credential for the next request, renewed if it is about to expire. */\n private async authorization(force = false): Promise<string> {\n if (!this.config.getTenantSession) return this.config.apiKey ?? \"\";\n\n const current = this.session;\n const stillGood =\n current &&\n (current.expiresAt === undefined ||\n current.expiresAt - Date.now() > RENEWAL_MARGIN_MS);\n if (stillGood && !force) return current.token;\n\n return this.renew(force);\n }\n\n private renew(force = false): Promise<string> {\n if (!this.renewing) {\n this.renewing = Promise.resolve(this.config.getTenantSession!(force))\n .then((result) => {\n const token = typeof result === \"string\" ? result : result.token;\n const declared =\n typeof result === \"string\"\n ? undefined\n : (result.expiresAt ??\n (result.expiresIn\n ? Date.now() + result.expiresIn * 1000\n : undefined));\n this.session = { token, expiresAt: declared ?? expiryOf(token) };\n return token;\n })\n .finally(() => {\n this.renewing = undefined;\n });\n }\n return this.renewing;\n }\n\n /**\n * Whether a rejected request is worth retrying, having got a live session.\n *\n * Takes the token the request actually went out with, not the current one:\n * with several requests in flight another may already have replaced it, and\n * comparing against the current one would read that success as a failure.\n *\n * False means the session is dead and cannot be replaced — a cookie set at\n * login, now expired, with nowhere to renew it from. That is worth telling\n * the host application about, once.\n */\n private async recoverSession(rejected: string): Promise<boolean> {\n if (this.session && this.session.token !== rejected) {\n this.expiryReported = false;\n return true;\n }\n\n let fresh: string | undefined;\n try {\n // Forced: whatever is cached upstream is the token that was just\n // refused, so asking for it again would only confirm the refusal.\n fresh = await this.renew(true);\n } catch {\n fresh = undefined;\n }\n if (fresh && fresh !== rejected) {\n this.expiryReported = false;\n return true;\n }\n\n if (!this.expiryReported) {\n this.expiryReported = true;\n this.config.onSessionExpired?.();\n }\n return false;\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n isRetry = false,\n binary = false,\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n const credential = await this.authorization();\n\n const headers: HeadersInit = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n // A session can die between being checked and being used — a clock adrift,\n // a tab asleep for an hour, the key revoked. One retry with a fresh token\n // turns that into a pause instead of a broken conversation.\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) {\n return this.request<T>(endpoint, options, true, binary);\n }\n }\n\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n // Not every refusal carries its own status in the body. A 409 raised with\n // an object (`{ error: 'CHAT_BUSY', ... }`) is returned verbatim, so\n // reading the code off the body alone leaves it undefined and every\n // `statusCode === 409` branch silently misses it.\n if (typeof errorData?.statusCode !== \"number\") {\n errorData = { ...errorData, statusCode: response.status };\n }\n throw new DevicApiError(errorData);\n }\n\n if (binary) return await response.blob() as T;\n if (response.status === 204) return undefined as T;\n // Handle responses that may have a wrapper structure\n const data = await response.json();\n\n // If the response has a data property, extract it (common wrapper pattern)\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data as T;\n }\n\n return data as T;\n }\n\n private async liveRequest<T>(path: string, options: RequestInit = {}): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 25000);\n try { return await this.request<T>(path, { ...options, signal: controller.signal }); }\n finally { clearTimeout(timeout); }\n }\n\n createLiveSession(assistantId: string, body: CreateLiveSessionRequest): Promise<LiveVoiceSession> {\n // No network-error retry: an ambiguous response could hide a paid session.\n return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions`, {\n method: 'POST', body: JSON.stringify(body),\n });\n }\n\n getLiveSessionStatus(assistantId: string, sessionId: string): Promise<LiveVoiceSessionStatus> {\n return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}`);\n }\n\n closeLiveSession(assistantId: string, sessionId: string): Promise<{ closing: boolean; chatUid: string }> {\n return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}`, { method: 'DELETE', keepalive: true });\n }\n\n getLiveRecordings(assistantId: string, chatUid: string, offset = 0, limit = 100): Promise<LiveVoiceRecording[]> {\n return this.request(`/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/recordings?offset=${offset}&limit=${limit}`);\n }\n\n getLiveRecordingAudio(assistantId: string, chatUid: string, sessionId: string): Promise<Blob> {\n return this.request(`/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/recordings/${encodeURIComponent(sessionId)}/audio`, {}, false, true);\n }\n\n getLiveVoiceUsage(assistantId: string, chatUid: string): Promise<LiveVoiceUsage> {\n return this.request(`/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/live-usage`);\n }\n\n /** Get all assistant specializations. */\n async getAssistants(external = false): Promise<AssistantSpecialization[]> {\n const query = external ? \"?external=true\" : \"\";\n return this.request<AssistantSpecialization[]>(\n `/api/v1/assistants${query}`,\n );\n }\n\n /**\n * Get a specific assistant specialization\n */\n async getAssistant(identifier: string): Promise<AssistantSpecialization> {\n return this.request<AssistantSpecialization>(\n `/api/v1/assistants/${identifier}`,\n );\n }\n\n /**\n * Send a message to an assistant (sync mode)\n */\n async sendMessage(\n assistantId: string,\n dto: ProcessMessageDto,\n signal?: AbortSignal,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/messages${dto.skipSummarization ? \"?skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n signal,\n },\n );\n }\n\n /**\n * Send a message to an assistant (async mode)\n */\n async sendMessageAsync(\n assistantId: string,\n dto: ProcessMessageDto,\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/messages?async=true${dto.skipSummarization ? \"&skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n },\n );\n }\n\n /**\n * Get the list of unique tags used across this account's chat histories.\n * Backed by GET /api/v1/assistants/tags. Useful for autocompletion / filters.\n */\n async getChatTags(): Promise<string[]> {\n return this.request<string[]>(`/api/v1/assistants/tags`);\n }\n\n /**\n * Follow a conversation in progress over its server-sent event stream.\n * Resolves when the server closes the stream; rejects when it is not a\n * stream at all (an older API) or the connection fails. `onActivity` fires\n * on every chunk received, keep-alives included.\n */\n async streamRealtimeHistory(\n assistantId: string,\n chatUid: string,\n onSnapshot: (snapshot: RealtimeChatHistory) => void | Promise<void>,\n signal: AbortSignal,\n onActivity?: () => void,\n ): Promise<void> {\n // `partial=1`: while only the reply being written changes, the API sends\n // `partial` frames with just that instead of the whole conversation.\n const url = `${this.config.baseUrl}/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/stream?partial=1`;\n let credential = await this.authorization();\n const open = () => fetch(url, { signal, headers: { Authorization: `Bearer ${credential}`, Accept: 'text/event-stream', 'devic-api-source': 'ui' } });\n let response = await open();\n if (response.status === 401 && this.config.getTenantSession && await this.recoverSession(credential)) {\n credential = await this.authorization(); response = await open();\n }\n await consumeChatStream(response, onSnapshot, onActivity);\n }\n\n async getRealtimeHistory(\n assistantId: string,\n chatUid: string,\n ): Promise<RealtimeChatHistory> {\n return this.request<RealtimeChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/realtime`,\n );\n }\n\n /**\n * Get chat history for a specific conversation\n */\n async getChatHistory(\n assistantId: string,\n chatUid: string,\n options?: { tenantId?: string },\n ): Promise<ChatHistory> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n const query = params.toString();\n return this.request<ChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * List conversations for an assistant\n */\n async listConversations(\n assistantId: string,\n options?: {\n tenantId?: string;\n subtenantId?: string;\n offset?: number;\n limit?: number;\n },\n ): Promise<ListConversationsResponse> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n if (options?.subtenantId) {\n params.set(\"subtenantId\", options.subtenantId);\n }\n if (options?.offset != null) {\n params.set(\"offset\", String(options.offset));\n }\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n params.set(\"omitContent\", \"true\");\n const query = params.toString();\n return this.request<ListConversationsResponse>(\n `/api/v1/assistants/${assistantId}/chats${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * Send tool call responses back to the assistant.\n *\n * `toolSchemas` re-states the client-side tools for the continuation. The\n * API takes them from the first response of the batch, and without them the\n * turn resumes with no client tools at all — the model stops being able to\n * call them after the first round.\n */\n async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[],\n toolSchemas?: ModelInterfaceToolSchema[],\n ): Promise<AsyncResponse> {\n const body =\n toolSchemas?.length && responses.length > 0\n ? responses.map((response, index) =>\n index === 0 ? { ...response, tools: toolSchemas } : response,\n )\n : responses;\n\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: \"POST\",\n body: JSON.stringify({ responses: body }),\n },\n );\n }\n\n /**\n * Submit feedback for a chat message\n */\n async submitChatFeedback(\n assistantId: string,\n chatUid: string,\n data: FeedbackSubmission,\n ): Promise<FeedbackEntry> {\n return this.request<FeedbackEntry>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n {\n method: \"POST\",\n body: JSON.stringify(data),\n },\n );\n }\n\n /**\n * Get all feedback for a chat\n */\n async getChatFeedback(\n assistantId: string,\n chatUid: string,\n ): Promise<FeedbackEntry[]> {\n return this.request<FeedbackEntry[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n );\n }\n\n /**\n * Get an agent thread by ID\n */\n async getThreadById(\n threadId: string,\n withTasks = false,\n ): Promise<AgentThreadDto> {\n const query = withTasks ? \"?withTasks=true\" : \"\";\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}${query}`,\n );\n }\n\n /**\n * Get agent details\n */\n async getAgentDetails(agentId: string): Promise<AgentDto> {\n return this.request<AgentDto>(`/api/v1/agents/${agentId}`);\n }\n\n /**\n * Get an AI-generated explanation of a thread's execution\n */\n async explainAgentThread(threadId: string): Promise<string> {\n return this.request<string>(\n `/api/v1/agents/threads/${threadId}/explain`,\n );\n }\n\n /**\n * Pause or resume a thread\n */\n async pauseResumeThread(\n threadId: string,\n action: \"paused\" | \"queued\",\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/pause-resume`,\n {\n method: \"POST\",\n body: JSON.stringify({ action }),\n },\n );\n }\n\n /**\n * Handle thread approval (approve/reject)\n */\n async handleThreadApproval(\n threadId: string,\n approved: boolean,\n retry: boolean,\n message: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/approval`,\n {\n method: \"POST\",\n body: JSON.stringify({\n action: approved ? \"approved\" : \"rejected\",\n message,\n retry,\n }),\n },\n );\n }\n\n /**\n * Manually complete a thread\n */\n async completeThread(\n threadId: string,\n completionState: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/complete`,\n {\n method: \"POST\",\n body: JSON.stringify({ state: completionState }),\n },\n );\n }\n\n /**\n * Continue an existing thread with a new user message. The backend decides how\n * to apply it based on the thread state: a finished/failed/waiting thread is\n * re-queued and re-run with the message appended, while a running/queued thread\n * receives it on its next turn (right after the pending tool response). Returns\n * the updated thread.\n */\n async sendThreadMessage(\n threadId: string,\n message: string | Record<string, unknown>,\n ): Promise<AgentThreadDto> {\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}/messages`,\n {\n method: \"POST\",\n body: JSON.stringify({ message }),\n },\n );\n }\n\n /**\n * Stop an in-progress async chat.\n * The current LLM call or tool execution will finish, then the chat\n * will be marked as completed with the history accumulated so far.\n */\n async stopChat(\n assistantId: string,\n chatUid: string,\n ): Promise<StopChatResponse> {\n return this.request<StopChatResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/stop`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Upload a file and get a download URL\n */\n async uploadFile(\n file: File,\n isRetry = false,\n ): Promise<{ name: string; downloadUrl: string; fileType: string }> {\n const url = `${this.config.baseUrl}/api/v1/files/upload`;\n\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const credential = await this.authorization();\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n // The FormData is rebuilt from `file` on the way back in, so unlike a\n // consumed stream this retry is safe.\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) return this.uploadFile(file, true);\n }\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n // See `request`: a body-shaped refusal need not carry its own status.\n if (typeof errorData?.statusCode !== \"number\") {\n errorData = { ...errorData, statusCode: response.status };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Transcribe audio to text using the /whisper endpoint.\n * Accepts either an audio binary (Blob/File, sent as multipart/form-data) or\n * a download URL string (sent as `audioUrl`). The backend stores the binary\n * and runs speech-to-text with Devic's own OpenAI key. Returns the text and a\n * `transcriptId` to attach to the resulting message.\n */\n async transcribeAudio(\n audio: Blob | string,\n options?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n fileName?: string;\n },\n isRetry = false,\n ): Promise<WhisperTranscriptionResponse> {\n const url = `${this.config.baseUrl}/api/v1/whisper`;\n\n const formData = new FormData();\n if (typeof audio === \"string\") {\n formData.append(\"audioUrl\", audio);\n } else {\n formData.append(\"audio\", audio, options?.fileName || \"recording.webm\");\n }\n if (options?.language) formData.append(\"language\", options.language);\n if (options?.messageUid) formData.append(\"messageUid\", options.messageUid);\n if (options?.chatUid) formData.append(\"chatUid\", options.chatUid);\n if (options?.tenantId) formData.append(\"tenantId\", options.tenantId);\n\n const credential = await this.authorization();\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) {\n return this.transcribeAudio(audio, options, true);\n }\n }\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n // See `request`: a body-shaped refusal need not carry its own status.\n if (typeof errorData?.statusCode !== \"number\") {\n errorData = { ...errorData, statusCode: response.status };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Fetch a single speech-to-text transcript by its id (the `transcriptId`\n * stored on a message). Returns the transcribed text and the download URL of\n * the source audio so the chat can offer playback of a dictated message.\n */\n async getTranscript(\n transcriptId: string,\n ): Promise<WhisperTranscriptionResponse> {\n return this.request<WhisperTranscriptionResponse>(\n `/api/v1/whisper/${encodeURIComponent(transcriptId)}`,\n );\n }\n\n /**\n * Get chat history content (full conversation after handoff)\n */\n async getChatHistoryContent(\n assistantId: string,\n chatUid: string,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/content`,\n );\n }\n\n /**\n * Get the current usage limits + consumption for a tenant (or a specific\n * subtenant). Read-only — backed by `GET /api/v1/tenant-usage/:tenantId`\n * (or `/:tenantId/subtenants/:subtenantId`), which is part of the devic-ui\n * key preset. Returns the effective rules with their live consumption and the\n * active tier. Use it to render a usage bar.\n */\n async getTenantUsage(\n tenantId: string,\n subtenantId?: string,\n ): Promise<TenantUsage> {\n const path = subtenantId\n ? `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/subtenants/${encodeURIComponent(subtenantId)}`\n : `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}`;\n return this.request<TenantUsage>(path);\n }\n\n /**\n * Get the durable per-window usage history for a tenant (or subtenant).\n * Read-only — backed by `GET /api/v1/tenant-usage/:tenantId/history`.\n */\n async getTenantUsageHistory(\n tenantId: string,\n options?: TenantUsageHistoryQuery,\n ): Promise<TenantUsageHistoryRow[]> {\n const params = new URLSearchParams();\n if (options?.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options?.scope) params.set(\"scope\", options.scope);\n if (options?.metric) params.set(\"metric\", options.metric);\n if (options?.windowUnit) params.set(\"windowUnit\", options.windowUnit);\n if (options?.from != null) params.set(\"from\", String(options.from));\n if (options?.to != null) params.set(\"to\", String(options.to));\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.skip != null) params.set(\"skip\", String(options.skip));\n const query = params.toString();\n return this.request<TenantUsageHistoryRow[]>(\n `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/history${query ? `?${query}` : \"\"}`,\n );\n }\n\n private coreMemoryPath(\n assistantId: string,\n tenantId?: string,\n subtenantId?: string,\n entryId?: number,\n ): string {\n const params = new URLSearchParams();\n if (tenantId) params.set(\"tenantId\", tenantId);\n if (subtenantId) params.set(\"subtenantId\", subtenantId);\n const query = params.toString();\n return `/api/v1/memory/assistants/${encodeURIComponent(assistantId)}/core${\n entryId != null ? `/${entryId}` : \"\"\n }${query ? `?${query}` : \"\"}`;\n }\n\n /**\n * Core memory entries of the bucket the assistant resolves for a\n * tenant/subtenant combination — what the assistant permanently remembers\n * there. `enabled: false` when the assistant has no core memory tier.\n */\n async getCoreMemory(\n assistantId: string,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryList> {\n return this.request<CoreMemoryList>(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n );\n }\n\n /** Add a standing core memory entry to the assistant's resolved bucket. */\n async addCoreMemoryEntry(\n assistantId: string,\n entry: { content: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ entry?: CoreMemoryEntry; deduped: boolean }> {\n return this.request(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n { method: \"POST\", body: JSON.stringify(entry) },\n );\n }\n\n /** Edit the text, section or pinned flag of a core memory entry. */\n async updateCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n patch: { content?: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryEntry> {\n return this.request<CoreMemoryEntry>(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"PATCH\", body: JSON.stringify(patch) },\n );\n }\n\n /** Remove (archive) a core memory entry. */\n async deleteCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ removed: boolean; id?: number }> {\n return this.request(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"DELETE\" },\n );\n }\n\n // ── Connected apps of the end user ────────────────────────────────\n //\n // Backed by `/api/v1/tenant-integrations`: the tenant is resolved on the\n // server and never taken from the path. The tenant/subtenant sent here\n // identify the end user in front of the widget, so one tenant's accounts are\n // never reachable from another's.\n\n private integrationsQuery(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n }): string {\n const params = new URLSearchParams({ assistantId: options.assistantId });\n if (options.tenantId) params.set(\"tenantId\", options.tenantId);\n if (options.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options.returnTo) params.set(\"returnTo\", options.returnTo);\n return params.toString();\n }\n\n /** Apps this assistant offers, with the end user's own connection status. */\n async getIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<Integration[]> {\n return this.request<Integration[]>(\n `/api/v1/tenant-integrations?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * How this app can be connected, and what it asks the end user for.\n *\n * Scoped like everything else here: the schemes of an app this assistant\n * does not offer cannot be read by asking for them.\n */\n async getIntegrationAuth(\n app: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ schemes: IntegrationAuthScheme[] }> {\n return this.request(\n `/api/v1/tenant-integrations/${encodeURIComponent(app)}/auth?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * Connects an account, in one of two ways.\n *\n * `connected: true` means it is done: the app authenticates with a key the\n * user supplied, so there is nobody to authorise with. Otherwise\n * `authorizationUrl` must be opened in a popup.\n *\n * `returnTo` is where the callback posts the result back to, and the server\n * refuses any value that does not match the origin this request came from —\n * so it cannot be turned into an open redirector.\n *\n * Rejects with a `DevicApiError` carrying `setupRequired` when the app needs\n * values that were not sent.\n */\n async connectIntegration(\n app: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n /** Which scheme to use, from {@link getIntegrationAuth}. */\n authScheme?: string;\n /** This account's own values: its API key, its subdomain. */\n accountFields?: Record<string, string>;\n },\n ): Promise<{ connected: boolean; authorizationUrl?: string }> {\n const { authScheme, accountFields, ...query } = options;\n return this.request(\n `/api/v1/tenant-integrations/${encodeURIComponent(app)}/connect?${this.integrationsQuery(query)}`,\n {\n method: \"POST\",\n body: JSON.stringify({ authScheme, accountFields }),\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n /** Disconnects one of the end user's own accounts. */\n async disconnectIntegration(\n accountId: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ disconnected: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/accounts/${encodeURIComponent(accountId)}?${this.integrationsQuery(options)}`,\n { method: \"DELETE\" },\n );\n }\n\n /**\n * Drops the server's short-lived cache of the end user's connections.\n *\n * Called right after the OAuth popup closes: without it the freshly connected\n * app would keep reading as disconnected until the cache expires, which looks\n * like the connection silently failed.\n */\n async refreshIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<{ refreshed: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/refresh?${this.integrationsQuery(options)}`,\n { method: \"POST\" },\n );\n }\n\n // ---------------------------------------------------------------------------\n // MCP servers the end user connects for themselves\n // ---------------------------------------------------------------------------\n // Backed by `/api/v1/tenant-mcp`, scoped exactly like the integrations above:\n // the tenant is resolved on the server, never taken from the path. Sending a\n // `subtenantId` makes the connection that end user's own; omitting it puts it\n // on the tenant, where every one of its end users shares it.\n\n /** The MCP servers this assistant offers, and the ones this tenant connected. */\n async getMcpServers(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<TenantMcpListing> {\n return this.request<TenantMcpListing>(\n `/api/v1/tenant-mcp?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * Connects a server: one the developer offers (`templateId`) or one the end\n * user brings (`url`).\n *\n * `returnTo` is where the callback posts the result back to, and the server\n * refuses any value that does not match the origin this request came from —\n * so it cannot be turned into an open redirector.\n */\n async connectMcpServer(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n templateId?: string;\n url?: string;\n name?: string;\n auth?: TenantMcpAuthInput;\n }): Promise<TenantMcpConnectResult> {\n const { templateId, url, name, auth, returnTo, ...query } = options;\n return this.request(`/api/v1/tenant-mcp?${this.integrationsQuery(query)}`, {\n method: \"POST\",\n // The scope travels in the body as well as the query string: it is what\n // decides whether this connection is the end user's own or the tenant's,\n // and the server reads it from there on writes.\n body: JSON.stringify({\n templateId,\n url,\n name,\n auth,\n returnTo,\n tenantId: options.tenantId,\n subtenantId: options.subtenantId,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Authorises again, for a server whose credentials expired or were revoked. */\n async reconnectMcpServer(\n id: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n auth?: TenantMcpAuthInput;\n },\n ): Promise<TenantMcpConnectResult> {\n const { auth, returnTo, ...query } = options;\n return this.request(\n `/api/v1/tenant-mcp/${encodeURIComponent(id)}/reconnect?${this.integrationsQuery(query)}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n auth,\n returnTo,\n tenantId: options.tenantId,\n subtenantId: options.subtenantId,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n /** Disconnects one of the end user's own MCP servers. */\n async disconnectMcpServer(\n id: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ disconnected: boolean }> {\n return this.request(\n `/api/v1/tenant-mcp/${encodeURIComponent(id)}?${this.integrationsQuery(options)}`,\n { method: \"DELETE\" },\n );\n }\n}\n\n/**\n * Custom error class for API errors\n */\nexport class DevicApiError extends Error {\n public statusCode: number;\n public errorType?: string;\n /** Structured error details (e.g. usage-limit blocking info on a 429). */\n public details?: any;\n /** What connecting an app is still waiting for, when that is why it failed.\n * Carried whole because the fields *are* the form to render. */\n public setupRequired?: IntegrationSetupRequired;\n\n constructor(error: ApiError) {\n super(error.message);\n this.name = \"DevicApiError\";\n this.statusCode = error.statusCode;\n this.errorType = error.error;\n this.details = error.details;\n if ((error as any)?.code === \"INTEGRATION_SETUP_REQUIRED\") {\n this.setupRequired = error as unknown as IntegrationSetupRequired;\n }\n }\n}\n"],"names":["consumeChatStream"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../../../src/api/client.ts"],"sourcesContent":["import { consumeChatStream } from '../utils/consumeChatStream';\nimport type { CreateLiveSessionRequest, LiveVoiceSession, LiveVoiceSessionStatus, LiveVoiceRecording, LiveVoiceUsage } from './liveVoice.types';\nimport type {\n ProcessMessageDto,\n ChatMessage,\n AsyncResponse,\n RealtimeChatHistory,\n ChatHistory,\n AssistantSpecialization,\n ApiError,\n ToolCallResponse,\n ConversationSummary,\n ListConversationsResponse,\n FeedbackSubmission,\n FeedbackEntry,\n AgentThreadDto,\n AgentDto,\n WhisperTranscriptionResponse,\n TenantUsage,\n TenantUsageHistoryRow,\n TenantUsageHistoryQuery,\n CoreMemoryList,\n CoreMemoryEntry,\n Integration,\n TenantMcpAuthInput,\n TenantMcpConnectResult,\n TenantMcpListing,\n IntegrationAuthScheme,\n IntegrationSetupRequired,\n ModelInterfaceToolSchema,\n StopChatResponse,\n} from \"./types\";\n\n/**\n * A tenant session, as the integrator's backend hands it over.\n *\n * A bare string is accepted too — the expiry is then read out of the token\n * itself, so the simplest possible source still gets proactive renewal.\n */\nexport interface TenantSessionToken {\n token: string;\n /** Epoch milliseconds. */\n expiresAt?: number;\n /** Seconds from now. Used when `expiresAt` is absent. */\n expiresIn?: number;\n}\n\nexport interface DevicApiClientConfig {\n /**\n * The public API key. Optional when `getTenantSession` is supplied — a page\n * using tenant sessions has no reason to carry one.\n */\n apiKey?: string;\n baseUrl: string;\n /**\n * Where the tenant session comes from.\n *\n * Supplying this changes what the tenant IS: with an API key alone the tenant\n * is whatever the page says it is, and the page can say anything. With a\n * session it is what your server signed.\n *\n * A function rather than a value because it is called again on its own —\n * before the token expires and after the API rejects one. It does not have to\n * reach your backend: reading a cookie your login already set is a perfectly\n * good answer, and then the whole thing is `async () => readCookie(…)`.\n *\n * It is called with `force: true` when the API has just rejected the token in\n * hand, meaning a cached answer is known to be dead. Your own function can\n * ignore the argument — `DevicProvider` uses it to share one session across\n * every component without ever serving a refused token back.\n */\n getTenantSession?: (force?: boolean) => Promise<string | TenantSessionToken>;\n /**\n * Called when the session is dead and cannot be replaced — the API rejected\n * it and `getTenantSession` handed back the same expired token.\n *\n * Matters most when the session comes from a cookie with no way to renew it:\n * without this the widget simply stops answering, at the exact moment the\n * user's own login has also expired. Refresh the page, send them to log in,\n * or say something — but say it.\n */\n onSessionExpired?: () => void;\n}\n\n/** Renew this long before expiry, so a request never leaves with a dead token. */\nconst RENEWAL_MARGIN_MS = 60_000;\n\n/**\n * The expiry inside a JWT, in epoch milliseconds.\n *\n * Read rather than required, so the session source can return just the string.\n * Any failure means \"no idea\", and the token is then renewed only when the API\n * rejects it — correct, just less graceful.\n */\nfunction expiryOf(token: string): number | undefined {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return undefined;\n const json = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const exp = JSON.parse(json)?.exp;\n return typeof exp === \"number\" ? exp * 1000 : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n private session?: { token: string; expiresAt?: number };\n /** In flight renewal, shared so a burst of calls fetches one token. */\n private renewing?: Promise<string>;\n /** So a page full of widgets reports one expiry, not one per widget. */\n private expiryReported = false;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n const previous = this.config;\n this.config = { ...this.config, ...config };\n // A new session source speaks for a different end user; keeping the old\n // token would show them the previous one's conversations.\n if (\n config.getTenantSession &&\n config.getTenantSession !== previous.getTenantSession\n ) {\n this.session = undefined;\n this.expiryReported = false;\n }\n }\n\n /** The credential for the next request, renewed if it is about to expire. */\n private async authorization(force = false): Promise<string> {\n if (!this.config.getTenantSession) return this.config.apiKey ?? \"\";\n\n const current = this.session;\n const stillGood =\n current &&\n (current.expiresAt === undefined ||\n current.expiresAt - Date.now() > RENEWAL_MARGIN_MS);\n if (stillGood && !force) return current.token;\n\n return this.renew(force);\n }\n\n private renew(force = false): Promise<string> {\n if (!this.renewing) {\n this.renewing = Promise.resolve(this.config.getTenantSession!(force))\n .then((result) => {\n const token = typeof result === \"string\" ? result : result.token;\n const declared =\n typeof result === \"string\"\n ? undefined\n : (result.expiresAt ??\n (result.expiresIn\n ? Date.now() + result.expiresIn * 1000\n : undefined));\n this.session = { token, expiresAt: declared ?? expiryOf(token) };\n return token;\n })\n .finally(() => {\n this.renewing = undefined;\n });\n }\n return this.renewing;\n }\n\n /**\n * Whether a rejected request is worth retrying, having got a live session.\n *\n * Takes the token the request actually went out with, not the current one:\n * with several requests in flight another may already have replaced it, and\n * comparing against the current one would read that success as a failure.\n *\n * False means the session is dead and cannot be replaced — a cookie set at\n * login, now expired, with nowhere to renew it from. That is worth telling\n * the host application about, once.\n */\n private async recoverSession(rejected: string): Promise<boolean> {\n if (this.session && this.session.token !== rejected) {\n this.expiryReported = false;\n return true;\n }\n\n let fresh: string | undefined;\n try {\n // Forced: whatever is cached upstream is the token that was just\n // refused, so asking for it again would only confirm the refusal.\n fresh = await this.renew(true);\n } catch {\n fresh = undefined;\n }\n if (fresh && fresh !== rejected) {\n this.expiryReported = false;\n return true;\n }\n\n if (!this.expiryReported) {\n this.expiryReported = true;\n this.config.onSessionExpired?.();\n }\n return false;\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n isRetry = false,\n binary = false,\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n const credential = await this.authorization();\n\n const headers: HeadersInit = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n // A session can die between being checked and being used — a clock adrift,\n // a tab asleep for an hour, the key revoked. One retry with a fresh token\n // turns that into a pause instead of a broken conversation.\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) {\n return this.request<T>(endpoint, options, true, binary);\n }\n }\n\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n // Not every refusal carries its own status in the body. A 409 raised with\n // an object (`{ error: 'CHAT_BUSY', ... }`) is returned verbatim, so\n // reading the code off the body alone leaves it undefined and every\n // `statusCode === 409` branch silently misses it.\n if (typeof errorData?.statusCode !== \"number\") {\n errorData = { ...errorData, statusCode: response.status };\n }\n throw new DevicApiError(errorData);\n }\n\n if (binary) return await response.blob() as T;\n if (response.status === 204) return undefined as T;\n // Handle responses that may have a wrapper structure\n const data = await response.json();\n\n // If the response has a data property, extract it (common wrapper pattern)\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data as T;\n }\n\n return data as T;\n }\n\n private async liveRequest<T>(path: string, options: RequestInit = {}): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 25000);\n try { return await this.request<T>(path, { ...options, signal: controller.signal }); }\n finally { clearTimeout(timeout); }\n }\n\n createLiveSession(assistantId: string, body: CreateLiveSessionRequest): Promise<LiveVoiceSession> {\n // No network-error retry: an ambiguous response could hide a paid session.\n return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions`, {\n method: 'POST', body: JSON.stringify(body),\n });\n }\n\n /** `touch`: the person confirmed they are still on the call; the server restarts its idle clock. */\n getLiveSessionStatus(assistantId: string, sessionId: string, touch = false): Promise<LiveVoiceSessionStatus> {\n return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}${touch ? '?touch=1' : ''}`);\n }\n\n closeLiveSession(assistantId: string, sessionId: string): Promise<{ closing: boolean; chatUid: string }> {\n return this.liveRequest(`/api/v1/assistants/${encodeURIComponent(assistantId)}/live/sessions/${encodeURIComponent(sessionId)}`, { method: 'DELETE', keepalive: true });\n }\n\n getLiveRecordings(assistantId: string, chatUid: string, offset = 0, limit = 100): Promise<LiveVoiceRecording[]> {\n return this.request(`/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/recordings?offset=${offset}&limit=${limit}`);\n }\n\n getLiveRecordingAudio(assistantId: string, chatUid: string, sessionId: string): Promise<Blob> {\n return this.request(`/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/recordings/${encodeURIComponent(sessionId)}/audio`, {}, false, true);\n }\n\n getLiveVoiceUsage(assistantId: string, chatUid: string): Promise<LiveVoiceUsage> {\n return this.request(`/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/live-usage`);\n }\n\n /** Get all assistant specializations. */\n async getAssistants(external = false): Promise<AssistantSpecialization[]> {\n const query = external ? \"?external=true\" : \"\";\n return this.request<AssistantSpecialization[]>(\n `/api/v1/assistants${query}`,\n );\n }\n\n /**\n * Get a specific assistant specialization\n */\n async getAssistant(identifier: string): Promise<AssistantSpecialization> {\n return this.request<AssistantSpecialization>(\n `/api/v1/assistants/${identifier}`,\n );\n }\n\n /**\n * Send a message to an assistant (sync mode)\n */\n async sendMessage(\n assistantId: string,\n dto: ProcessMessageDto,\n signal?: AbortSignal,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/messages${dto.skipSummarization ? \"?skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n signal,\n },\n );\n }\n\n /**\n * Send a message to an assistant (async mode)\n */\n async sendMessageAsync(\n assistantId: string,\n dto: ProcessMessageDto,\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/messages?async=true${dto.skipSummarization ? \"&skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n },\n );\n }\n\n /**\n * Get the list of unique tags used across this account's chat histories.\n * Backed by GET /api/v1/assistants/tags. Useful for autocompletion / filters.\n */\n async getChatTags(): Promise<string[]> {\n return this.request<string[]>(`/api/v1/assistants/tags`);\n }\n\n /**\n * Follow a conversation in progress over its server-sent event stream.\n * Resolves when the server closes the stream; rejects when it is not a\n * stream at all (an older API) or the connection fails. `onActivity` fires\n * on every chunk received, keep-alives included.\n */\n async streamRealtimeHistory(\n assistantId: string,\n chatUid: string,\n onSnapshot: (snapshot: RealtimeChatHistory) => void | Promise<void>,\n signal: AbortSignal,\n onActivity?: () => void,\n ): Promise<void> {\n // `partial=1`: while only the reply being written changes, the API sends\n // `partial` frames with just that instead of the whole conversation.\n const url = `${this.config.baseUrl}/api/v1/assistants/${encodeURIComponent(assistantId)}/chats/${encodeURIComponent(chatUid)}/stream?partial=1`;\n let credential = await this.authorization();\n const open = () => fetch(url, { signal, headers: { Authorization: `Bearer ${credential}`, Accept: 'text/event-stream', 'devic-api-source': 'ui' } });\n let response = await open();\n if (response.status === 401 && this.config.getTenantSession && await this.recoverSession(credential)) {\n credential = await this.authorization(); response = await open();\n }\n await consumeChatStream(response, onSnapshot, onActivity);\n }\n\n async getRealtimeHistory(\n assistantId: string,\n chatUid: string,\n ): Promise<RealtimeChatHistory> {\n return this.request<RealtimeChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/realtime`,\n );\n }\n\n /**\n * Get chat history for a specific conversation\n */\n async getChatHistory(\n assistantId: string,\n chatUid: string,\n options?: { tenantId?: string },\n ): Promise<ChatHistory> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n const query = params.toString();\n return this.request<ChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * List conversations for an assistant\n */\n async listConversations(\n assistantId: string,\n options?: {\n tenantId?: string;\n subtenantId?: string;\n offset?: number;\n limit?: number;\n },\n ): Promise<ListConversationsResponse> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n if (options?.subtenantId) {\n params.set(\"subtenantId\", options.subtenantId);\n }\n if (options?.offset != null) {\n params.set(\"offset\", String(options.offset));\n }\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n params.set(\"omitContent\", \"true\");\n const query = params.toString();\n return this.request<ListConversationsResponse>(\n `/api/v1/assistants/${assistantId}/chats${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * Send tool call responses back to the assistant.\n *\n * `toolSchemas` re-states the client-side tools for the continuation. The\n * API takes them from the first response of the batch, and without them the\n * turn resumes with no client tools at all — the model stops being able to\n * call them after the first round.\n */\n async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[],\n toolSchemas?: ModelInterfaceToolSchema[],\n ): Promise<AsyncResponse> {\n const body =\n toolSchemas?.length && responses.length > 0\n ? responses.map((response, index) =>\n index === 0 ? { ...response, tools: toolSchemas } : response,\n )\n : responses;\n\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: \"POST\",\n body: JSON.stringify({ responses: body }),\n },\n );\n }\n\n /**\n * Submit feedback for a chat message\n */\n async submitChatFeedback(\n assistantId: string,\n chatUid: string,\n data: FeedbackSubmission,\n ): Promise<FeedbackEntry> {\n return this.request<FeedbackEntry>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n {\n method: \"POST\",\n body: JSON.stringify(data),\n },\n );\n }\n\n /**\n * Get all feedback for a chat\n */\n async getChatFeedback(\n assistantId: string,\n chatUid: string,\n ): Promise<FeedbackEntry[]> {\n return this.request<FeedbackEntry[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n );\n }\n\n /**\n * Get an agent thread by ID\n */\n async getThreadById(\n threadId: string,\n withTasks = false,\n ): Promise<AgentThreadDto> {\n const query = withTasks ? \"?withTasks=true\" : \"\";\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}${query}`,\n );\n }\n\n /**\n * Get agent details\n */\n async getAgentDetails(agentId: string): Promise<AgentDto> {\n return this.request<AgentDto>(`/api/v1/agents/${agentId}`);\n }\n\n /**\n * Get an AI-generated explanation of a thread's execution\n */\n async explainAgentThread(threadId: string): Promise<string> {\n return this.request<string>(\n `/api/v1/agents/threads/${threadId}/explain`,\n );\n }\n\n /**\n * Pause or resume a thread\n */\n async pauseResumeThread(\n threadId: string,\n action: \"paused\" | \"queued\",\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/pause-resume`,\n {\n method: \"POST\",\n body: JSON.stringify({ action }),\n },\n );\n }\n\n /**\n * Handle thread approval (approve/reject)\n */\n async handleThreadApproval(\n threadId: string,\n approved: boolean,\n retry: boolean,\n message: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/approval`,\n {\n method: \"POST\",\n body: JSON.stringify({\n action: approved ? \"approved\" : \"rejected\",\n message,\n retry,\n }),\n },\n );\n }\n\n /**\n * Manually complete a thread\n */\n async completeThread(\n threadId: string,\n completionState: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/complete`,\n {\n method: \"POST\",\n body: JSON.stringify({ state: completionState }),\n },\n );\n }\n\n /**\n * Continue an existing thread with a new user message. The backend decides how\n * to apply it based on the thread state: a finished/failed/waiting thread is\n * re-queued and re-run with the message appended, while a running/queued thread\n * receives it on its next turn (right after the pending tool response). Returns\n * the updated thread.\n */\n async sendThreadMessage(\n threadId: string,\n message: string | Record<string, unknown>,\n ): Promise<AgentThreadDto> {\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}/messages`,\n {\n method: \"POST\",\n body: JSON.stringify({ message }),\n },\n );\n }\n\n /**\n * Stop an in-progress async chat.\n * The current LLM call or tool execution will finish, then the chat\n * will be marked as completed with the history accumulated so far.\n */\n async stopChat(\n assistantId: string,\n chatUid: string,\n ): Promise<StopChatResponse> {\n return this.request<StopChatResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/stop`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Upload a file and get a download URL\n */\n async uploadFile(\n file: File,\n isRetry = false,\n ): Promise<{ name: string; downloadUrl: string; fileType: string }> {\n const url = `${this.config.baseUrl}/api/v1/files/upload`;\n\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const credential = await this.authorization();\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n // The FormData is rebuilt from `file` on the way back in, so unlike a\n // consumed stream this retry is safe.\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) return this.uploadFile(file, true);\n }\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n // See `request`: a body-shaped refusal need not carry its own status.\n if (typeof errorData?.statusCode !== \"number\") {\n errorData = { ...errorData, statusCode: response.status };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Transcribe audio to text using the /whisper endpoint.\n * Accepts either an audio binary (Blob/File, sent as multipart/form-data) or\n * a download URL string (sent as `audioUrl`). The backend stores the binary\n * and runs speech-to-text with Devic's own OpenAI key. Returns the text and a\n * `transcriptId` to attach to the resulting message.\n */\n async transcribeAudio(\n audio: Blob | string,\n options?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n fileName?: string;\n },\n isRetry = false,\n ): Promise<WhisperTranscriptionResponse> {\n const url = `${this.config.baseUrl}/api/v1/whisper`;\n\n const formData = new FormData();\n if (typeof audio === \"string\") {\n formData.append(\"audioUrl\", audio);\n } else {\n formData.append(\"audio\", audio, options?.fileName || \"recording.webm\");\n }\n if (options?.language) formData.append(\"language\", options.language);\n if (options?.messageUid) formData.append(\"messageUid\", options.messageUid);\n if (options?.chatUid) formData.append(\"chatUid\", options.chatUid);\n if (options?.tenantId) formData.append(\"tenantId\", options.tenantId);\n\n const credential = await this.authorization();\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) {\n return this.transcribeAudio(audio, options, true);\n }\n }\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n // See `request`: a body-shaped refusal need not carry its own status.\n if (typeof errorData?.statusCode !== \"number\") {\n errorData = { ...errorData, statusCode: response.status };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Fetch a single speech-to-text transcript by its id (the `transcriptId`\n * stored on a message). Returns the transcribed text and the download URL of\n * the source audio so the chat can offer playback of a dictated message.\n */\n async getTranscript(\n transcriptId: string,\n ): Promise<WhisperTranscriptionResponse> {\n return this.request<WhisperTranscriptionResponse>(\n `/api/v1/whisper/${encodeURIComponent(transcriptId)}`,\n );\n }\n\n /**\n * Get chat history content (full conversation after handoff)\n */\n async getChatHistoryContent(\n assistantId: string,\n chatUid: string,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/content`,\n );\n }\n\n /**\n * Get the current usage limits + consumption for a tenant (or a specific\n * subtenant). Read-only — backed by `GET /api/v1/tenant-usage/:tenantId`\n * (or `/:tenantId/subtenants/:subtenantId`), which is part of the devic-ui\n * key preset. Returns the effective rules with their live consumption and the\n * active tier. Use it to render a usage bar.\n */\n async getTenantUsage(\n tenantId: string,\n subtenantId?: string,\n ): Promise<TenantUsage> {\n const path = subtenantId\n ? `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/subtenants/${encodeURIComponent(subtenantId)}`\n : `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}`;\n return this.request<TenantUsage>(path);\n }\n\n /**\n * Get the durable per-window usage history for a tenant (or subtenant).\n * Read-only — backed by `GET /api/v1/tenant-usage/:tenantId/history`.\n */\n async getTenantUsageHistory(\n tenantId: string,\n options?: TenantUsageHistoryQuery,\n ): Promise<TenantUsageHistoryRow[]> {\n const params = new URLSearchParams();\n if (options?.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options?.scope) params.set(\"scope\", options.scope);\n if (options?.metric) params.set(\"metric\", options.metric);\n if (options?.windowUnit) params.set(\"windowUnit\", options.windowUnit);\n if (options?.from != null) params.set(\"from\", String(options.from));\n if (options?.to != null) params.set(\"to\", String(options.to));\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.skip != null) params.set(\"skip\", String(options.skip));\n const query = params.toString();\n return this.request<TenantUsageHistoryRow[]>(\n `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/history${query ? `?${query}` : \"\"}`,\n );\n }\n\n private coreMemoryPath(\n assistantId: string,\n tenantId?: string,\n subtenantId?: string,\n entryId?: number,\n ): string {\n const params = new URLSearchParams();\n if (tenantId) params.set(\"tenantId\", tenantId);\n if (subtenantId) params.set(\"subtenantId\", subtenantId);\n const query = params.toString();\n return `/api/v1/memory/assistants/${encodeURIComponent(assistantId)}/core${\n entryId != null ? `/${entryId}` : \"\"\n }${query ? `?${query}` : \"\"}`;\n }\n\n /**\n * Core memory entries of the bucket the assistant resolves for a\n * tenant/subtenant combination — what the assistant permanently remembers\n * there. `enabled: false` when the assistant has no core memory tier.\n */\n async getCoreMemory(\n assistantId: string,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryList> {\n return this.request<CoreMemoryList>(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n );\n }\n\n /** Add a standing core memory entry to the assistant's resolved bucket. */\n async addCoreMemoryEntry(\n assistantId: string,\n entry: { content: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ entry?: CoreMemoryEntry; deduped: boolean }> {\n return this.request(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n { method: \"POST\", body: JSON.stringify(entry) },\n );\n }\n\n /** Edit the text, section or pinned flag of a core memory entry. */\n async updateCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n patch: { content?: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryEntry> {\n return this.request<CoreMemoryEntry>(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"PATCH\", body: JSON.stringify(patch) },\n );\n }\n\n /** Remove (archive) a core memory entry. */\n async deleteCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ removed: boolean; id?: number }> {\n return this.request(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"DELETE\" },\n );\n }\n\n // ── Connected apps of the end user ────────────────────────────────\n //\n // Backed by `/api/v1/tenant-integrations`: the tenant is resolved on the\n // server and never taken from the path. The tenant/subtenant sent here\n // identify the end user in front of the widget, so one tenant's accounts are\n // never reachable from another's.\n\n private integrationsQuery(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n }): string {\n const params = new URLSearchParams({ assistantId: options.assistantId });\n if (options.tenantId) params.set(\"tenantId\", options.tenantId);\n if (options.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options.returnTo) params.set(\"returnTo\", options.returnTo);\n return params.toString();\n }\n\n /** Apps this assistant offers, with the end user's own connection status. */\n async getIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<Integration[]> {\n return this.request<Integration[]>(\n `/api/v1/tenant-integrations?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * How this app can be connected, and what it asks the end user for.\n *\n * Scoped like everything else here: the schemes of an app this assistant\n * does not offer cannot be read by asking for them.\n */\n async getIntegrationAuth(\n app: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ schemes: IntegrationAuthScheme[] }> {\n return this.request(\n `/api/v1/tenant-integrations/${encodeURIComponent(app)}/auth?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * Connects an account, in one of two ways.\n *\n * `connected: true` means it is done: the app authenticates with a key the\n * user supplied, so there is nobody to authorise with. Otherwise\n * `authorizationUrl` must be opened in a popup.\n *\n * `returnTo` is where the callback posts the result back to, and the server\n * refuses any value that does not match the origin this request came from —\n * so it cannot be turned into an open redirector.\n *\n * Rejects with a `DevicApiError` carrying `setupRequired` when the app needs\n * values that were not sent.\n */\n async connectIntegration(\n app: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n /** Which scheme to use, from {@link getIntegrationAuth}. */\n authScheme?: string;\n /** This account's own values: its API key, its subdomain. */\n accountFields?: Record<string, string>;\n },\n ): Promise<{ connected: boolean; authorizationUrl?: string }> {\n const { authScheme, accountFields, ...query } = options;\n return this.request(\n `/api/v1/tenant-integrations/${encodeURIComponent(app)}/connect?${this.integrationsQuery(query)}`,\n {\n method: \"POST\",\n body: JSON.stringify({ authScheme, accountFields }),\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n /** Disconnects one of the end user's own accounts. */\n async disconnectIntegration(\n accountId: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ disconnected: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/accounts/${encodeURIComponent(accountId)}?${this.integrationsQuery(options)}`,\n { method: \"DELETE\" },\n );\n }\n\n /**\n * Drops the server's short-lived cache of the end user's connections.\n *\n * Called right after the OAuth popup closes: without it the freshly connected\n * app would keep reading as disconnected until the cache expires, which looks\n * like the connection silently failed.\n */\n async refreshIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<{ refreshed: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/refresh?${this.integrationsQuery(options)}`,\n { method: \"POST\" },\n );\n }\n\n // ---------------------------------------------------------------------------\n // MCP servers the end user connects for themselves\n // ---------------------------------------------------------------------------\n // Backed by `/api/v1/tenant-mcp`, scoped exactly like the integrations above:\n // the tenant is resolved on the server, never taken from the path. Sending a\n // `subtenantId` makes the connection that end user's own; omitting it puts it\n // on the tenant, where every one of its end users shares it.\n\n /** The MCP servers this assistant offers, and the ones this tenant connected. */\n async getMcpServers(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<TenantMcpListing> {\n return this.request<TenantMcpListing>(\n `/api/v1/tenant-mcp?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * Connects a server: one the developer offers (`templateId`) or one the end\n * user brings (`url`).\n *\n * `returnTo` is where the callback posts the result back to, and the server\n * refuses any value that does not match the origin this request came from —\n * so it cannot be turned into an open redirector.\n */\n async connectMcpServer(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n templateId?: string;\n url?: string;\n name?: string;\n auth?: TenantMcpAuthInput;\n }): Promise<TenantMcpConnectResult> {\n const { templateId, url, name, auth, returnTo, ...query } = options;\n return this.request(`/api/v1/tenant-mcp?${this.integrationsQuery(query)}`, {\n method: \"POST\",\n // The scope travels in the body as well as the query string: it is what\n // decides whether this connection is the end user's own or the tenant's,\n // and the server reads it from there on writes.\n body: JSON.stringify({\n templateId,\n url,\n name,\n auth,\n returnTo,\n tenantId: options.tenantId,\n subtenantId: options.subtenantId,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Authorises again, for a server whose credentials expired or were revoked. */\n async reconnectMcpServer(\n id: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n auth?: TenantMcpAuthInput;\n },\n ): Promise<TenantMcpConnectResult> {\n const { auth, returnTo, ...query } = options;\n return this.request(\n `/api/v1/tenant-mcp/${encodeURIComponent(id)}/reconnect?${this.integrationsQuery(query)}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n auth,\n returnTo,\n tenantId: options.tenantId,\n subtenantId: options.subtenantId,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n /** Disconnects one of the end user's own MCP servers. */\n async disconnectMcpServer(\n id: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ disconnected: boolean }> {\n return this.request(\n `/api/v1/tenant-mcp/${encodeURIComponent(id)}?${this.integrationsQuery(options)}`,\n { method: \"DELETE\" },\n );\n }\n}\n\n/**\n * Custom error class for API errors\n */\nexport class DevicApiError extends Error {\n public statusCode: number;\n public errorType?: string;\n /** Structured error details (e.g. usage-limit blocking info on a 429). */\n public details?: any;\n /** What connecting an app is still waiting for, when that is why it failed.\n * Carried whole because the fields *are* the form to render. */\n public setupRequired?: IntegrationSetupRequired;\n\n constructor(error: ApiError) {\n super(error.message);\n this.name = \"DevicApiError\";\n this.statusCode = error.statusCode;\n this.errorType = error.error;\n this.details = error.details;\n if ((error as any)?.code === \"INTEGRATION_SETUP_REQUIRED\") {\n this.setupRequired = error as unknown as IntegrationSetupRequired;\n }\n }\n}\n"],"names":["consumeChatStream"],"mappings":"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"}
|
|
@@ -23,15 +23,19 @@ function LiveVoicePanel({ voice, canStart, recordSessions, onDismiss, invitation
|
|
|
23
23
|
const start = () => { if (canStart)
|
|
24
24
|
void voice.start(); };
|
|
25
25
|
if (voice.active) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
// About to end for silence: the countdown takes the status line, and the
|
|
27
|
+
// button next to it keeps the call.
|
|
28
|
+
const idleIn = voice.idleEndsAt && voice.state === 'connected' ? Math.max(0, Math.ceil((voice.idleEndsAt - Date.now()) / 1000)) : undefined;
|
|
29
|
+
const status = idleIn !== undefined ? t('Still there? The call ends in {seconds} s', { seconds: idleIn })
|
|
30
|
+
: voice.state === 'connected' ? t('Live · {time}', { time: formatSeconds(voice.seconds) })
|
|
31
|
+
: voice.state === 'reconnecting' ? t('Restoring voice…') : voice.state === 'closing' ? t('Closing voice…') : t('Connecting voice…');
|
|
32
|
+
return jsxRuntime.jsxs("div", { className: "devic-input-area devic-voice-area", "data-voice-state": voice.state, "data-voice-idle": idleIn !== undefined ? 'true' : undefined, children: [children, jsxRuntime.jsxs("section", { className: "devic-voice-box", "aria-label": t('Voice mode'), children: [jsxRuntime.jsx(LiveVoicePrompter.LiveVoicePrompter, { voice: voice }), jsxRuntime.jsxs("div", { className: "devic-voice-bar", children: [jsxRuntime.jsxs("span", { className: "devic-voice-status", role: "status", children: [jsxRuntime.jsx("i", { className: "devic-voice-status-dot", "aria-hidden": "true" }), status] }), idleIn !== undefined && jsxRuntime.jsx("button", { type: "button", className: "devic-voice-text-btn devic-voice-still-here", onClick: () => voice.stillHere(), children: t("I'm here") }), voice.playbackBlocked && jsxRuntime.jsx("button", { type: "button", className: "devic-voice-text-btn", onClick: () => void voice.play(), children: t('Enable audio') }), voice.state === 'connecting'
|
|
29
33
|
? jsxRuntime.jsx("button", { type: "button", className: "devic-voice-text-btn", onClick: () => void voice.stop(), children: t('Cancel') })
|
|
30
34
|
: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", className: "devic-input-btn devic-voice-mute", "aria-pressed": voice.muted, disabled: voice.state !== 'connected', title: voice.muted ? t('Unmute') : t('Mute'), "aria-label": voice.muted ? t('Unmute') : t('Mute'), onClick: () => voice.mute(!voice.muted), children: voice.muted ? jsxRuntime.jsx(MicOffIcon, {}) : jsxRuntime.jsx(MicIcon, {}) }), jsxRuntime.jsxs("button", { type: "button", className: "devic-voice-end", disabled: voice.state === 'closing', onClick: () => void voice.stop(), children: [jsxRuntime.jsx(HangUpIcon, {}), t('End voice')] })] })] })] })] });
|
|
31
35
|
}
|
|
32
36
|
if (invitation)
|
|
33
37
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: invitation({ start, canStart, dismiss: () => onDismiss?.(), recordSessions, error: voice.error }) });
|
|
34
|
-
return jsxRuntime.jsxs("section", { className: "devic-live-voice", "aria-label": t('Voice mode'), children: [jsxRuntime.jsxs("div", { className: "devic-voice-card", children: [jsxRuntime.jsx("span", { className: "devic-voice-card-icon", "aria-hidden": "true", children: jsxRuntime.jsx(MicIcon, {}) }), jsxRuntime.jsxs("div", { className: "devic-voice-card-copy", children: [jsxRuntime.jsx("div", { className: "devic-voice-card-title", children: t('Voice mode') }), jsxRuntime.jsxs("div", { className: "devic-voice-card-subtitle", children: [t('Talk to the assistant in real time.'), recordSessions !== false && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [" ", t('Voice sessions are recorded according to the assistant settings.')] })] })] }), jsxRuntime.jsxs("button", { className: "devic-voice-start", type: "button", disabled: !canStart, onClick: start, children: [jsxRuntime.jsx(MicIcon, {}), t('Start voice')] }), onDismiss && jsxRuntime.jsx("button", { className: "devic-voice-card-close", type: "button", onClick: onDismiss, title: t('Hide voice mode'), "aria-label": t('Hide voice mode'), children: jsxRuntime.jsx(CloseIcon, {}) })] }), voice.error && jsxRuntime.jsx("div", { className: "devic-voice-error", role: "alert", children: t(voice.error.message) })] });
|
|
38
|
+
return jsxRuntime.jsxs("section", { className: "devic-live-voice", "aria-label": t('Voice mode'), children: [jsxRuntime.jsxs("div", { className: "devic-voice-card", children: [jsxRuntime.jsx("span", { className: "devic-voice-card-icon", "aria-hidden": "true", children: jsxRuntime.jsx(MicIcon, {}) }), jsxRuntime.jsxs("div", { className: "devic-voice-card-copy", children: [jsxRuntime.jsx("div", { className: "devic-voice-card-title", children: t('Voice mode') }), jsxRuntime.jsxs("div", { className: "devic-voice-card-subtitle", children: [t('Talk to the assistant in real time.'), recordSessions !== false && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [" ", t('Voice sessions are recorded according to the assistant settings.')] })] })] }), jsxRuntime.jsxs("button", { className: "devic-voice-start", type: "button", disabled: !canStart, onClick: start, children: [jsxRuntime.jsx(MicIcon, {}), t('Start voice')] }), onDismiss && jsxRuntime.jsx("button", { className: "devic-voice-card-close", type: "button", onClick: onDismiss, title: t('Hide voice mode'), "aria-label": t('Hide voice mode'), children: jsxRuntime.jsx(CloseIcon, {}) })] }), voice.error && jsxRuntime.jsx("div", { className: "devic-voice-error", role: "alert", children: t(voice.error.message) }), !voice.error && voice.endReason === 'idle' && jsxRuntime.jsx("div", { className: "devic-voice-note", role: "status", children: t('The call ended after a while without anyone speaking.') })] });
|
|
35
39
|
}
|
|
36
40
|
function MicIcon() {
|
|
37
41
|
return jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }), jsxRuntime.jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }), jsxRuntime.jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" }), jsxRuntime.jsx("line", { x1: "8", y1: "23", x2: "16", y2: "23" })] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveVoicePanel.js","sources":["../../../../../src/components/ChatDrawer/LiveVoicePanel.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { UseDevicLiveVoiceResult } from '../../hooks/useDevicLiveVoice';\nimport type { LiveVoiceInvitationProps } from './ChatDrawer.types';\nimport { useTranslations } from '../../i18n';\nimport './LiveVoicePanel.css';\nimport { LiveVoicePrompter } from './LiveVoicePrompter';\n\nexport interface LiveVoicePanelProps {\n voice: UseDevicLiveVoiceResult;\n canStart: boolean;\n recordSessions?: boolean;\n /** Close the invitation card; the drawer remembers it per assistant. */\n onDismiss?: () => void;\n /** A host's own invitation, in place of the default card. */\n invitation?: (props: LiveVoiceInvitationProps) => ReactNode;\n /** Rendered above the call box while voice is active: the composer's own banners. */\n children?: ReactNode;\n}\n\n/** `m:ss` of a running call, as the dictation timer formats it. */\nfunction formatSeconds(total: number): string {\n const seconds = Math.max(0, Math.floor(total));\n return `${Math.floor(seconds / 60)}:${(seconds % 60).toString().padStart(2, '0')}`;\n}\n\n/**\n * The live voice widget. Idle, it is an invitation card sitting above the\n * composer of a new conversation; once a call starts it takes the composer's\n * place — the same input area, the same rounded surface — with the transcript\n * prompter, one wave per speaker and the call controls where the send button\n * normally sits.\n */\nexport default function LiveVoicePanel({ voice, canStart, recordSessions, onDismiss, invitation, children }: LiveVoicePanelProps) {\n const t = useTranslations();\n const start = () => { if (canStart) void voice.start(); };\n\n if (voice.active) {\n const status = voice.state === 'connected' ? t('Live · {time}', { time: formatSeconds(voice.seconds) })\n : voice.state === 'reconnecting' ? t('Restoring voice…') : voice.state === 'closing' ? t('Closing voice…') : t('Connecting voice…');\n return <div className=\"devic-input-area devic-voice-area\" data-voice-state={voice.state}>\n {children}\n <section className=\"devic-voice-box\" aria-label={t('Voice mode')}>\n <LiveVoicePrompter voice={voice} />\n <div className=\"devic-voice-bar\">\n <span className=\"devic-voice-status\" role=\"status\"><i className=\"devic-voice-status-dot\" aria-hidden=\"true\" />{status}</span>\n {voice.playbackBlocked && <button type=\"button\" className=\"devic-voice-text-btn\" onClick={() => void voice.play()}>{t('Enable audio')}</button>}\n {voice.state === 'connecting'\n ? <button type=\"button\" className=\"devic-voice-text-btn\" onClick={() => void voice.stop()}>{t('Cancel')}</button>\n : <>\n <button type=\"button\" className=\"devic-input-btn devic-voice-mute\" aria-pressed={voice.muted} disabled={voice.state !== 'connected'}\n title={voice.muted ? t('Unmute') : t('Mute')} aria-label={voice.muted ? t('Unmute') : t('Mute')} onClick={() => voice.mute(!voice.muted)}>\n {voice.muted ? <MicOffIcon /> : <MicIcon />}\n </button>\n <button type=\"button\" className=\"devic-voice-end\" disabled={voice.state === 'closing'} onClick={() => void voice.stop()}>\n <HangUpIcon />{t('End voice')}\n </button>\n </>}\n </div>\n </section>\n </div>;\n }\n\n if (invitation) return <>{invitation({ start, canStart, dismiss: () => onDismiss?.(), recordSessions, error: voice.error })}</>;\n\n return <section className=\"devic-live-voice\" aria-label={t('Voice mode')}>\n <div className=\"devic-voice-card\">\n <span className=\"devic-voice-card-icon\" aria-hidden=\"true\"><MicIcon /></span>\n <div className=\"devic-voice-card-copy\">\n <div className=\"devic-voice-card-title\">{t('Voice mode')}</div>\n <div className=\"devic-voice-card-subtitle\">\n {t('Talk to the assistant in real time.')}{recordSessions !== false && <> {t('Voice sessions are recorded according to the assistant settings.')}</>}\n </div>\n </div>\n <button className=\"devic-voice-start\" type=\"button\" disabled={!canStart} onClick={start}><MicIcon />{t('Start voice')}</button>\n {onDismiss && <button className=\"devic-voice-card-close\" type=\"button\" onClick={onDismiss} title={t('Hide voice mode')} aria-label={t('Hide voice mode')}><CloseIcon /></button>}\n </div>\n {voice.error && <div className=\"devic-voice-error\" role=\"alert\">{t(voice.error.message)}</div>}\n </section>;\n}\n\nfunction MicIcon() {\n return <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" /><path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" /><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" /><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>;\n}\nfunction MicOffIcon() {\n return <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" /><path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\" /><path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23\" /><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" /><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>;\n}\nfunction CloseIcon() {\n return <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden=\"true\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>;\n}\nfunction HangUpIcon() {\n return <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.996.996 0 0 1 0-1.41C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z\" />\n </svg>;\n}\n"],"names":["useTranslations","_jsxs","_jsx","LiveVoicePrompter","_Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LiveVoicePanel.js","sources":["../../../../../src/components/ChatDrawer/LiveVoicePanel.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { UseDevicLiveVoiceResult } from '../../hooks/useDevicLiveVoice';\nimport type { LiveVoiceInvitationProps } from './ChatDrawer.types';\nimport { useTranslations } from '../../i18n';\nimport './LiveVoicePanel.css';\nimport { LiveVoicePrompter } from './LiveVoicePrompter';\n\nexport interface LiveVoicePanelProps {\n voice: UseDevicLiveVoiceResult;\n canStart: boolean;\n recordSessions?: boolean;\n /** Close the invitation card; the drawer remembers it per assistant. */\n onDismiss?: () => void;\n /** A host's own invitation, in place of the default card. */\n invitation?: (props: LiveVoiceInvitationProps) => ReactNode;\n /** Rendered above the call box while voice is active: the composer's own banners. */\n children?: ReactNode;\n}\n\n/** `m:ss` of a running call, as the dictation timer formats it. */\nfunction formatSeconds(total: number): string {\n const seconds = Math.max(0, Math.floor(total));\n return `${Math.floor(seconds / 60)}:${(seconds % 60).toString().padStart(2, '0')}`;\n}\n\n/**\n * The live voice widget. Idle, it is an invitation card sitting above the\n * composer of a new conversation; once a call starts it takes the composer's\n * place — the same input area, the same rounded surface — with the transcript\n * prompter, one wave per speaker and the call controls where the send button\n * normally sits.\n */\nexport default function LiveVoicePanel({ voice, canStart, recordSessions, onDismiss, invitation, children }: LiveVoicePanelProps) {\n const t = useTranslations();\n const start = () => { if (canStart) void voice.start(); };\n\n if (voice.active) {\n // About to end for silence: the countdown takes the status line, and the\n // button next to it keeps the call.\n const idleIn = voice.idleEndsAt && voice.state === 'connected' ? Math.max(0, Math.ceil((voice.idleEndsAt - Date.now()) / 1000)) : undefined;\n const status = idleIn !== undefined ? t('Still there? The call ends in {seconds} s', { seconds: idleIn })\n : voice.state === 'connected' ? t('Live · {time}', { time: formatSeconds(voice.seconds) })\n : voice.state === 'reconnecting' ? t('Restoring voice…') : voice.state === 'closing' ? t('Closing voice…') : t('Connecting voice…');\n return <div className=\"devic-input-area devic-voice-area\" data-voice-state={voice.state} data-voice-idle={idleIn !== undefined ? 'true' : undefined}>\n {children}\n <section className=\"devic-voice-box\" aria-label={t('Voice mode')}>\n <LiveVoicePrompter voice={voice} />\n <div className=\"devic-voice-bar\">\n <span className=\"devic-voice-status\" role=\"status\"><i className=\"devic-voice-status-dot\" aria-hidden=\"true\" />{status}</span>\n {idleIn !== undefined && <button type=\"button\" className=\"devic-voice-text-btn devic-voice-still-here\" onClick={() => voice.stillHere()}>{t(\"I'm here\")}</button>}\n {voice.playbackBlocked && <button type=\"button\" className=\"devic-voice-text-btn\" onClick={() => void voice.play()}>{t('Enable audio')}</button>}\n {voice.state === 'connecting'\n ? <button type=\"button\" className=\"devic-voice-text-btn\" onClick={() => void voice.stop()}>{t('Cancel')}</button>\n : <>\n <button type=\"button\" className=\"devic-input-btn devic-voice-mute\" aria-pressed={voice.muted} disabled={voice.state !== 'connected'}\n title={voice.muted ? t('Unmute') : t('Mute')} aria-label={voice.muted ? t('Unmute') : t('Mute')} onClick={() => voice.mute(!voice.muted)}>\n {voice.muted ? <MicOffIcon /> : <MicIcon />}\n </button>\n <button type=\"button\" className=\"devic-voice-end\" disabled={voice.state === 'closing'} onClick={() => void voice.stop()}>\n <HangUpIcon />{t('End voice')}\n </button>\n </>}\n </div>\n </section>\n </div>;\n }\n\n if (invitation) return <>{invitation({ start, canStart, dismiss: () => onDismiss?.(), recordSessions, error: voice.error })}</>;\n\n return <section className=\"devic-live-voice\" aria-label={t('Voice mode')}>\n <div className=\"devic-voice-card\">\n <span className=\"devic-voice-card-icon\" aria-hidden=\"true\"><MicIcon /></span>\n <div className=\"devic-voice-card-copy\">\n <div className=\"devic-voice-card-title\">{t('Voice mode')}</div>\n <div className=\"devic-voice-card-subtitle\">\n {t('Talk to the assistant in real time.')}{recordSessions !== false && <> {t('Voice sessions are recorded according to the assistant settings.')}</>}\n </div>\n </div>\n <button className=\"devic-voice-start\" type=\"button\" disabled={!canStart} onClick={start}><MicIcon />{t('Start voice')}</button>\n {onDismiss && <button className=\"devic-voice-card-close\" type=\"button\" onClick={onDismiss} title={t('Hide voice mode')} aria-label={t('Hide voice mode')}><CloseIcon /></button>}\n </div>\n {voice.error && <div className=\"devic-voice-error\" role=\"alert\">{t(voice.error.message)}</div>}\n {!voice.error && voice.endReason === 'idle' && <div className=\"devic-voice-note\" role=\"status\">{t('The call ended after a while without anyone speaking.')}</div>}\n </section>;\n}\n\nfunction MicIcon() {\n return <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" /><path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" /><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" /><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>;\n}\nfunction MicOffIcon() {\n return <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" /><path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\" /><path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23\" /><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" /><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>;\n}\nfunction CloseIcon() {\n return <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden=\"true\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>;\n}\nfunction HangUpIcon() {\n return <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.996.996 0 0 1 0-1.41C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z\" />\n </svg>;\n}\n"],"names":["useTranslations","_jsxs","_jsx","LiveVoicePrompter","_Fragment"],"mappings":";;;;;;;;AAmBA;AACA,SAAS,aAAa,CAAC,KAAa,EAAA;AAClC,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAA,EAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAA,CAAA,EAAI,CAAC,OAAO,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAE;AACpF;AAEA;;;;;;AAMG;AACW,SAAU,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAuB,EAAA;AAC9H,IAAA,MAAM,CAAC,GAAGA,+BAAe,EAAE;AAC3B,IAAA,MAAM,KAAK,GAAG,MAAK,EAAG,IAAI,QAAQ;AAAE,QAAA,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAEzD,IAAA,IAAI,KAAK,CAAC,MAAM,EAAE;;;AAGhB,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,SAAS;AAC3I,QAAA,MAAM,MAAM,GAAG,MAAM,KAAK,SAAS,GAAG,CAAC,CAAC,2CAA2C,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;cACpG,KAAK,CAAC,KAAK,KAAK,WAAW,GAAG,CAAC,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AACzF,kBAAE,KAAK,CAAC,KAAK,KAAK,cAAc,GAAG,CAAC,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,GAAG,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,mBAAmB,CAAC;AACrI,QAAA,OAAOC,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mCAAmC,EAAA,kBAAA,EAAmB,KAAK,CAAC,KAAK,EAAA,iBAAA,EAAmB,MAAM,KAAK,SAAS,GAAG,MAAM,GAAG,SAAS,EAAA,QAAA,EAAA,CAChJ,QAAQ,EACTA,eAAA,CAAA,SAAA,EAAA,EAAS,SAAS,EAAC,iBAAiB,EAAA,YAAA,EAAa,CAAC,CAAC,YAAY,CAAC,EAAA,QAAA,EAAA,CAC9DC,cAAA,CAACC,mCAAiB,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,CAAI,EACnCF,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iBAAiB,EAAA,QAAA,EAAA,CAC9BA,eAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAC,QAAQ,EAAA,QAAA,EAAA,CAACC,cAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,wBAAwB,EAAA,aAAA,EAAa,MAAM,GAAG,EAAC,MAAM,CAAA,EAAA,CAAQ,EAC5H,MAAM,KAAK,SAAS,IAAIA,cAAA,CAAA,QAAA,EAAA,EAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,6CAA6C,EAAC,OAAO,EAAE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAA,QAAA,EAAG,CAAC,CAAC,UAAU,CAAC,EAAA,CAAU,EAChK,KAAK,CAAC,eAAe,IAAIA,cAAA,CAAA,QAAA,EAAA,EAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,sBAAsB,EAAC,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC,IAAI,EAAE,EAAA,QAAA,EAAG,CAAC,CAAC,cAAc,CAAC,EAAA,CAAU,EAC9I,KAAK,CAAC,KAAK,KAAK;sCACbA,cAAA,CAAA,QAAA,EAAA,EAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,sBAAsB,EAAC,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC,IAAI,EAAE,EAAA,QAAA,EAAG,CAAC,CAAC,QAAQ,CAAC,EAAA;AACvG,sCAAED,eAAA,CAAAG,mBAAA,EAAA,EAAA,QAAA,EAAA,CACAF,cAAA,CAAA,QAAA,EAAA,EAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,kCAAkC,EAAA,cAAA,EAAe,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,KAAK,WAAW,EACjI,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAA,YAAA,EAAc,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAA,QAAA,EACvI,KAAK,CAAC,KAAK,GAAGA,cAAA,CAAC,UAAU,EAAA,EAAA,CAAG,GAAGA,cAAA,CAAC,OAAO,EAAA,EAAA,CAAG,EAAA,CACpC,EACTD,eAAA,CAAA,QAAA,EAAA,EAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,iBAAiB,EAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC,IAAI,EAAE,EAAA,QAAA,EAAA,CACrHC,cAAA,CAAC,UAAU,EAAA,EAAA,CAAG,EAAC,CAAC,CAAC,WAAW,CAAC,CAAA,EAAA,CACtB,CAAA,EAAA,CACR,CAAA,EAAA,CACD,CAAA,EAAA,CACE,IACN;IACR;AAEA,IAAA,IAAI,UAAU;QAAE,OAAOA,cAAA,CAAAE,mBAAA,EAAA,EAAA,QAAA,EAAG,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,EAAA,CAAI;AAE/H,IAAA,OAAOH,6BAAS,SAAS,EAAC,kBAAkB,EAAA,YAAA,EAAa,CAAC,CAAC,YAAY,CAAC,EAAA,QAAA,EAAA,CACtEA,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kBAAkB,aAC/BC,cAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,uBAAuB,EAAA,aAAA,EAAa,MAAM,EAAA,QAAA,EAACA,eAAC,OAAO,EAAA,EAAA,CAAG,GAAO,EAC7ED,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,uBAAuB,aACpCC,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,wBAAwB,EAAA,QAAA,EAAE,CAAC,CAAC,YAAY,CAAC,EAAA,CAAO,EAC/DD,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,2BAA2B,EAAA,QAAA,EAAA,CACvC,CAAC,CAAC,qCAAqC,CAAC,EAAE,cAAc,KAAK,KAAK,IAAIA,eAAA,CAAAG,mBAAA,EAAA,EAAA,QAAA,EAAA,CAAA,GAAA,EAAI,CAAC,CAAC,kEAAkE,CAAC,IAAI,CAAA,EAAA,CAChJ,CAAA,EAAA,CACF,EACNH,eAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,mBAAmB,EAAC,IAAI,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAA,QAAA,EAAA,CAAEC,cAAA,CAAC,OAAO,EAAA,EAAA,CAAG,EAAC,CAAC,CAAC,aAAa,CAAC,CAAA,EAAA,CAAU,EAC9H,SAAS,IAAIA,2BAAQ,SAAS,EAAC,wBAAwB,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,iBAAiB,CAAC,gBAAc,CAAC,CAAC,iBAAiB,CAAC,EAAA,QAAA,EAAEA,eAAC,SAAS,EAAA,EAAA,CAAG,GAAS,CAAA,EAAA,CAC5K,EACL,KAAK,CAAC,KAAK,IAAIA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,EAAC,IAAI,EAAC,OAAO,EAAA,QAAA,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAA,CAAO,EAC7F,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,MAAM,IAAIA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kBAAkB,EAAC,IAAI,EAAC,QAAQ,YAAE,CAAC,CAAC,uDAAuD,CAAC,EAAA,CAAO,IACzJ;AACZ;AAEA,SAAS,OAAO,GAAA;AACd,IAAA,OAAOD,yBAAK,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,GAAG,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,iBAAa,MAAM,EAAA,QAAA,EAAA,CACtKC,yBAAM,CAAC,EAAC,sDAAsD,EAAA,CAAG,EAAAA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,4BAA4B,EAAA,CAAG,EAAAA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EAAAA,yBAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,IACnL;AACR;AACA,SAAS,UAAU,GAAA;IACjB,OAAOD,eAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,GAAG,EAAC,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,EAAA,aAAA,EAAa,MAAM,EAAA,QAAA,EAAA,CACtKC,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EAAAA,yBAAM,CAAC,EAAC,wDAAwD,EAAA,CAAG,EAAAA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,uDAAuD,GAAG,EAAAA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EAAAA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,CAAA,EAAA,CACtP;AACR;AACA,SAAS,SAAS,GAAA;AAChB,IAAA,OAAOD,eAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAC,GAAG,EAAC,aAAa,EAAC,OAAO,EAAA,aAAA,EAAa,MAAM,aAC/IC,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EAAAA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,IACxE;AACR;AACA,SAAS,UAAU,GAAA;IACjB,OAAOA,cAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,cAAc,EAAA,aAAA,EAAa,MAAM,EAAA,QAAA,EAC3FA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,gXAAgX,EAAA,CAAG,EAAA,CACvX;AACR;;;;"}
|
|
@@ -265,6 +265,13 @@ function useDevicChat(options) {
|
|
|
265
265
|
React.useEffect(() => {
|
|
266
266
|
if (previousInitialChatRef.current !== initialChatUid) {
|
|
267
267
|
previousInitialChatRef.current = initialChatUid;
|
|
268
|
+
// The parent can echo the ID just emitted by onChatCreated. That adopts
|
|
269
|
+
// the running voice chat; it does not select a different conversation.
|
|
270
|
+
if (initialChatUid && initialChatUid === chatUidRef.current &&
|
|
271
|
+
voiceRef.current.active && voiceRef.current.chatUid === initialChatUid) {
|
|
272
|
+
initialChatLoadedRef.current = true;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
268
275
|
initialChatLoadedRef.current = false;
|
|
269
276
|
void voiceRef.current.stop();
|
|
270
277
|
}
|