@devicai/ui 0.26.0 → 0.28.0
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 -0
- package/dist/cjs/api/client.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js +3 -2
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatInput.js +98 -8
- package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ConversationSelector.js +4 -2
- package/dist/cjs/components/ChatDrawer/ConversationSelector.js.map +1 -1
- package/dist/cjs/styles.css +1 -1
- package/dist/esm/api/client.d.ts +1 -0
- package/dist/esm/api/client.js +3 -0
- package/dist/esm/api/client.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.js +3 -2
- package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +19 -6
- package/dist/esm/components/ChatDrawer/ChatInput.d.ts +1 -1
- package/dist/esm/components/ChatDrawer/ChatInput.js +98 -8
- package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ConversationSelector.d.ts +1 -1
- package/dist/esm/components/ChatDrawer/ConversationSelector.js +4 -2
- package/dist/esm/components/ChatDrawer/ConversationSelector.js.map +1 -1
- package/dist/esm/styles.css +1 -1
- package/package.json +1 -1
package/dist/cjs/api/client.js
CHANGED
|
@@ -106,6 +106,9 @@ class DevicApiClient {
|
|
|
106
106
|
if (options?.tenantId) {
|
|
107
107
|
params.set("tenantId", options.tenantId);
|
|
108
108
|
}
|
|
109
|
+
if (options?.subtenantId) {
|
|
110
|
+
params.set("subtenantId", options.subtenantId);
|
|
111
|
+
}
|
|
109
112
|
if (options?.offset != null) {
|
|
110
113
|
params.set("offset", String(options.offset));
|
|
111
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../../../src/api/client.ts"],"sourcesContent":["import 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} from \"./types\";\n\nexport interface DevicApiClientConfig {\n apiKey: string;\n baseUrl: string;\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: HeadersInit = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\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 throw new DevicApiError(errorData);\n }\n\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 /**\n * Get all assistant specializations\n */\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 real-time chat history (for polling in async mode)\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?: { tenantId?: string; offset?: number; limit?: number },\n ): Promise<ListConversationsResponse> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\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 async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[],\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: \"POST\",\n body: JSON.stringify({ responses }),\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 * 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<{ chatUid: string; message: string }> {\n return this.request<{ chatUid: string; message: string }>(\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 ): 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 response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\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 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 ): 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 response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\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 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\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\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 }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../../../src/api/client.ts"],"sourcesContent":["import 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} from \"./types\";\n\nexport interface DevicApiClientConfig {\n apiKey: string;\n baseUrl: string;\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: HeadersInit = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\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 throw new DevicApiError(errorData);\n }\n\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 /**\n * Get all assistant specializations\n */\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 real-time chat history (for polling in async mode)\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 async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[],\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: \"POST\",\n body: JSON.stringify({ responses }),\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 * 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<{ chatUid: string; message: string }> {\n return this.request<{ chatUid: string; message: string }>(\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 ): 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 response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\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 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 ): 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 response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\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 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\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\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 }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,7 @@ const DEFAULT_OPTIONS = {
|
|
|
32
32
|
speechAutoStopSpeechLevel: 0.12,
|
|
33
33
|
speechHandoff: false,
|
|
34
34
|
speechHandoffSendDelayMs: 1000,
|
|
35
|
+
speechHandoffHoldMs: 3000,
|
|
35
36
|
inputPlaceholder: 'Type a message...',
|
|
36
37
|
title: 'Chat',
|
|
37
38
|
showAvatar: false,
|
|
@@ -414,7 +415,7 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
|
|
|
414
415
|
[mergedOptions.position]: 20,
|
|
415
416
|
bottom: 20,
|
|
416
417
|
}), [mergedOptions.zIndex, mergedOptions.position]);
|
|
417
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!isInline && (jsxRuntime.jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose })), jsxRuntime.jsxs("div", { ref: drawerRef, className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, "data-mode": mode, style: drawerStyle, children: [mergedOptions.resizable && (jsxRuntime.jsx("div", { className: "devic-resize-handle", "data-position": mergedOptions.position, onMouseDown: handleResizeStart })), jsxRuntime.jsxs("div", { className: "devic-drawer-header", children: [avatarUrl && (jsxRuntime.jsx("img", { className: "devic-drawer-avatar", src: avatarUrl, alt: "", "aria-hidden": "true" })), jsxRuntime.jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsxRuntime.jsx(ConversationSelector.ConversationSelector, { assistantId: assistantId, currentChatUid: chat.chatUid, onSelect: handleConversationSelect, onNewChat: handleNewChat, apiKey: apiKey, baseUrl: baseUrl, tenantId: tenantId, conversationPreview: mergedOptions.conversationPreview }), jsxRuntime.jsxs("div", { className: "devic-drawer-header-actions", children: [jsxRuntime.jsx("button", { className: "devic-new-chat-btn", onClick: handleNewChat, type: "button", "aria-label": "New chat", title: "New chat", children: jsxRuntime.jsx(PlusIcon, {}) }), !isInline && (jsxRuntime.jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) }))] })] }), chat.error && (jsxRuntime.jsx("div", { className: "devic-error", children: chat.error.message })), jsxRuntime.jsx(ChatMessages.ChatMessages, { messages: chat.messages, allMessages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline, toolRenderers: mergedOptions.toolRenderers, toolIcons: mergedOptions.toolIcons, loadingIndicator: mergedOptions.loadingIndicator, showFeedback: mergedOptions.showFeedback, feedbackMap: feedbackMap, onFeedback: handleFeedback, handedOffSubThreadId: chat.handedOffSubThreadId || undefined, onHandoffCompleted: chat.onHandoffCompleted, handoffWidgetRenderer: mergedOptions.handoffWidgetRenderer, toolGroups: mergedOptions.toolGroups, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, pendingInlineWidgets: inlineWidgets, onSubmitWidget: chat.submitWidgetResponse, onCancelWidget: chat.cancelWidgetCall }), mergedOptions.customPromptBox ? (jsxRuntime.jsxs("div", { className: "devic-input-area", children: [limitBannerNode, usageBarNode, mergedOptions.customPromptBox({
|
|
418
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!isInline && (jsxRuntime.jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose })), jsxRuntime.jsxs("div", { ref: drawerRef, className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, "data-mode": mode, style: drawerStyle, children: [mergedOptions.resizable && (jsxRuntime.jsx("div", { className: "devic-resize-handle", "data-position": mergedOptions.position, onMouseDown: handleResizeStart })), jsxRuntime.jsxs("div", { className: "devic-drawer-header", children: [avatarUrl && (jsxRuntime.jsx("img", { className: "devic-drawer-avatar", src: avatarUrl, alt: "", "aria-hidden": "true" })), jsxRuntime.jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsxRuntime.jsx(ConversationSelector.ConversationSelector, { assistantId: assistantId, currentChatUid: chat.chatUid, onSelect: handleConversationSelect, onNewChat: handleNewChat, apiKey: apiKey, baseUrl: baseUrl, tenantId: tenantId, subtenantId: subtenantId, conversationPreview: mergedOptions.conversationPreview }), jsxRuntime.jsxs("div", { className: "devic-drawer-header-actions", children: [jsxRuntime.jsx("button", { className: "devic-new-chat-btn", onClick: handleNewChat, type: "button", "aria-label": "New chat", title: "New chat", children: jsxRuntime.jsx(PlusIcon, {}) }), !isInline && (jsxRuntime.jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) }))] })] }), chat.error && (jsxRuntime.jsx("div", { className: "devic-error", children: chat.error.message })), jsxRuntime.jsx(ChatMessages.ChatMessages, { messages: chat.messages, allMessages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline, toolRenderers: mergedOptions.toolRenderers, toolIcons: mergedOptions.toolIcons, loadingIndicator: mergedOptions.loadingIndicator, showFeedback: mergedOptions.showFeedback, feedbackMap: feedbackMap, onFeedback: handleFeedback, handedOffSubThreadId: chat.handedOffSubThreadId || undefined, onHandoffCompleted: chat.onHandoffCompleted, handoffWidgetRenderer: mergedOptions.handoffWidgetRenderer, toolGroups: mergedOptions.toolGroups, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, pendingInlineWidgets: inlineWidgets, onSubmitWidget: chat.submitWidgetResponse, onCancelWidget: chat.cancelWidgetCall }), mergedOptions.customPromptBox ? (jsxRuntime.jsxs("div", { className: "devic-input-area", children: [limitBannerNode, usageBarNode, mergedOptions.customPromptBox({
|
|
418
419
|
sendMessage: handleSend,
|
|
419
420
|
transcribeAudio,
|
|
420
421
|
stop: chat.stopChat,
|
|
@@ -427,7 +428,7 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
|
|
|
427
428
|
})] })) : (jsxRuntime.jsx(ChatInput.ChatInput, { onSend: handleSend, disabled: chat.isLoading ||
|
|
428
429
|
chat.handedOff ||
|
|
429
430
|
inlineWidgets.length > 0 ||
|
|
430
|
-
!!chat.limitExceeded, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize, enableSpeechToText: mergedOptions.enableSpeechToText, speechLanguage: mergedOptions.speechLanguage, speechTenantId: tenantId, speechAutoStop: mergedOptions.speechAutoStop, speechAutoStopCountdownMs: mergedOptions.speechAutoStopCountdownMs, speechAutoStopSilenceMs: mergedOptions.speechAutoStopSilenceMs, speechAutoStopSilenceRatio: mergedOptions.speechAutoStopSilenceRatio, speechAutoStopSilenceLevel: mergedOptions.speechAutoStopSilenceLevel, speechAutoStopSpeechLevel: mergedOptions.speechAutoStopSpeechLevel, speechHandoff: mergedOptions.speechHandoff, speechHandoffSendDelayMs: mergedOptions.speechHandoffSendDelayMs, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, sendButtonContent: mergedOptions.sendButtonContent, disabledMessage: chat.handedOff
|
|
431
|
+
!!chat.limitExceeded, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize, enableSpeechToText: mergedOptions.enableSpeechToText, speechLanguage: mergedOptions.speechLanguage, speechTenantId: tenantId, speechAutoStop: mergedOptions.speechAutoStop, speechAutoStopCountdownMs: mergedOptions.speechAutoStopCountdownMs, speechAutoStopSilenceMs: mergedOptions.speechAutoStopSilenceMs, speechAutoStopSilenceRatio: mergedOptions.speechAutoStopSilenceRatio, speechAutoStopSilenceLevel: mergedOptions.speechAutoStopSilenceLevel, speechAutoStopSpeechLevel: mergedOptions.speechAutoStopSpeechLevel, speechHandoff: mergedOptions.speechHandoff, speechHandoffSendDelayMs: mergedOptions.speechHandoffSendDelayMs, speechHandoffHoldMs: mergedOptions.speechHandoffHoldMs, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, sendButtonContent: mergedOptions.sendButtonContent, disabledMessage: chat.handedOff
|
|
431
432
|
? 'Waiting for subagent to complete'
|
|
432
433
|
: inlineWidgets.length > 0
|
|
433
434
|
? 'Waiting for tool response'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatDrawer.js","sources":["../../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport { ConversationSelector } from './ConversationSelector';\nimport { ChatDrawerErrorBoundary } from './ErrorBoundary';\nimport { UsageBar } from './UsageBar';\nimport { LimitBanner } from './LimitBanner';\nimport type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: '100%',\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n enableSpeechToText: false,\n speechLanguage: undefined as any,\n speechAutoStop: true,\n speechAutoStopCountdownMs: 1000,\n speechAutoStopSilenceMs: 1000,\n speechAutoStopSilenceRatio: 0.1,\n speechAutoStopSilenceLevel: 0.02,\n speechAutoStopSpeechLevel: 0.12,\n speechHandoff: false,\n speechHandoffSendDelayMs: 1000,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showAvatar: false,\n showToolTimeline: true,\n zIndex: 1000,\n borderRadius: 0,\n resizable: false,\n minWidth: 300,\n maxWidth: 800,\n style: {},\n fontFamily: undefined as any,\n backgroundColor: undefined as any,\n textColor: undefined as any,\n secondaryBackgroundColor: undefined as any,\n borderColor: undefined as any,\n userBubbleColor: undefined as any,\n userBubbleTextColor: undefined as any,\n assistantBubbleColor: undefined as any,\n assistantBubbleTextColor: undefined as any,\n sendButtonColor: undefined as any,\n loadingIndicator: undefined as any,\n sendButtonContent: undefined as any,\n toolRenderers: undefined as any,\n toolIcons: undefined as any,\n showFeedback: true,\n handoffWidgetRenderer: undefined as any,\n toolGroups: undefined as any,\n stopButtonContent: undefined as any,\n debug: false,\n persistConversation: false,\n customPromptBox: undefined as any,\n conversationPreview: 'date',\n showUsageBar: false,\n usageBarMetric: undefined as any,\n usageBarDisplay: undefined as any,\n customUsageBar: undefined as any,\n hideLimitBanner: false,\n limitBannerRenderer: undefined as any,\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * ref={drawerRef}\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport const ChatDrawer = forwardRef<ChatDrawerHandle, ChatDrawerProps>(\n function ChatDrawer(props, ref) {\n return (\n <ChatDrawerErrorBoundary>\n <ChatDrawerInner {...props} forwardedRef={ref} />\n </ChatDrawerErrorBoundary>\n );\n }\n);\n\ninterface ChatDrawerInnerProps extends ChatDrawerProps {\n forwardedRef?: React.Ref<ChatDrawerHandle>;\n}\n\nfunction ChatDrawerInner({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n mode = 'drawer',\n onConversationChange,\n forwardedRef,\n}: ChatDrawerInnerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // localStorage key for persisting selected conversation\n const storageKey = mergedOptions.persistConversation\n ? `devic-ui-chatUid-${assistantId}`\n : null;\n\n // Resolve initial chatUid: prop takes priority, then localStorage\n const resolvedInitialChatUid = useMemo(() => {\n if (initialChatUid) return initialChatUid;\n if (storageKey) {\n try { return localStorage.getItem(storageKey) || undefined; } catch { return undefined; }\n }\n return undefined;\n }, [initialChatUid, storageKey]);\n\n // Drawer open state (can be controlled or uncontrolled; inline mode is always open)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isInline = mode === 'inline';\n const isOpen = isInline ? true : (controlledIsOpen ?? internalIsOpen);\n\n // Wrap onChatCreated to persist chatUid in localStorage\n const handleChatCreated = useCallback(\n (chatUid: string) => {\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n onChatCreated?.(chatUid);\n },\n [storageKey, onChatCreated]\n );\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: resolvedInitialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated: handleChatCreated,\n onFileUpload,\n debug: mergedOptions.debug,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // Tenant/subtenant resolution mirrors useDevicChat (prop overrides provider).\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n\n // Usage bar (above the input) — only when enabled and a tenant is known.\n // Refetches after each turn via the message count as refresh key.\n const usageBarNode =\n (mergedOptions.showUsageBar ||\n typeof mergedOptions.customUsageBar === 'function') &&\n resolvedTenantId ? (\n <UsageBar\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n tenantId={resolvedTenantId}\n subtenantId={resolvedSubtenantId}\n mode={mergedOptions.showUsageBar === 'onDemand' ? 'onDemand' : 'always'}\n metric={mergedOptions.usageBarMetric}\n display={mergedOptions.usageBarDisplay}\n customUsageBar={mergedOptions.customUsageBar}\n color={mergedOptions.color}\n refreshKey={chat.messages.length}\n debug={mergedOptions.debug}\n />\n ) : null;\n\n // Default usage-limit banner (above the input) — opt-out via hideLimitBanner,\n // override via limitBannerRenderer.\n const limitBannerNode =\n chat.limitExceeded && !mergedOptions.hideLimitBanner\n ? mergedOptions.limitBannerRenderer\n ? mergedOptions.limitBannerRenderer(chat.limitExceeded)\n : <LimitBanner limit={chat.limitExceeded} />\n : null;\n\n // Speech-to-text transcription, exposed to custom prompt boxes so a developer\n // can transcribe audio (binary or URL) and attach the resulting transcriptId.\n const transcribeAudio = useCallback(\n (\n audio: Blob | string,\n transcribeOptions?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n },\n ) => {\n if (!resolvedApiKey) {\n return Promise.reject(\n new Error('API key not configured. Cannot transcribe audio.'),\n );\n }\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n return client.transcribeAudio(audio, {\n language: transcribeOptions?.language ?? mergedOptions.speechLanguage,\n messageUid: transcribeOptions?.messageUid,\n chatUid: transcribeOptions?.chatUid,\n tenantId: transcribeOptions?.tenantId ?? tenantId,\n });\n },\n [resolvedApiKey, resolvedBaseUrl, mergedOptions.speechLanguage, tenantId],\n );\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleToggle = useCallback(() => {\n setInternalIsOpen((prev) => !prev);\n }, []);\n\n // Expose handle for programmatic control\n useImperativeHandle(forwardedRef, () => ({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n setChatUid: (chatUid: string) => {\n chat.loadChat(chatUid);\n },\n sendMessage: (message: string) => {\n chat.sendMessage(message);\n },\n }), [handleOpen, handleClose, handleToggle, chat]);\n\n // Register this drawer in the DevicProvider so AIElementWrapper can open it\n useEffect(() => {\n if (!context?.registerDrawer) return;\n const unregister = context.registerDrawer({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n sendMessage: (message: string) => chat.sendMessage(message),\n });\n return unregister;\n }, [context, handleOpen, handleClose, handleToggle, chat]);\n\n // Partition pending widget calls by render mode\n const { inlineWidgets, inputWidget } = useMemo(() => {\n const inline: typeof chat.pendingWidgetCalls = [];\n let input: typeof chat.pendingWidgetCalls[number] | null = null;\n for (const wc of chat.pendingWidgetCalls) {\n if (wc.widget.render === 'input' && !input) {\n input = wc;\n } else {\n inline.push(wc);\n }\n }\n return { inlineWidgets: inline, inputWidget: input };\n }, [chat.pendingWidgetCalls]);\n\n // Active references from DevicProvider (created by AIElementWrapper)\n const references = context?.references ?? [];\n const removeReference = useCallback(\n (id: string) => {\n context?.removeReference(id);\n },\n [context]\n );\n const clearReferences = useCallback(() => {\n context?.clearReferences();\n }, [context]);\n\n // Handle send message — prefix references and clear them after sending\n const handleSend = useCallback(\n (message: string, files?: File[], meta?: { transcriptId?: string }) => {\n let finalMessage = message;\n if (references.length > 0) {\n const labels = references.map((r) => `\"${r.label}\"`).join(', ');\n finalMessage = `Elemento referenciado: ${labels}\\n\\n${message}`;\n }\n chat.sendMessage(finalMessage, { files, transcriptId: meta?.transcriptId });\n if (references.length > 0) clearReferences();\n },\n [chat, references, clearReferences]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n },\n [chat, onConversationChange, storageKey]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n if (storageKey) {\n try { localStorage.removeItem(storageKey); } catch {}\n }\n }, [chat, storageKey]);\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Feedback state\n const [feedbackMap, setFeedbackMap] = useState<Map<string, 'positive' | 'negative'>>(new Map());\n const feedbackClientRef = useRef<DevicApiClient | null>(null);\n\n // Initialize feedback client\n useEffect(() => {\n if (resolvedApiKey && !feedbackClientRef.current) {\n feedbackClientRef.current = new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n });\n }\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n // Load existing feedback when chat changes\n useEffect(() => {\n if (!chat.chatUid || !feedbackClientRef.current || !mergedOptions.showFeedback) return;\n\n feedbackClientRef.current.getChatFeedback(assistantId, chat.chatUid)\n .then((entries) => {\n const newMap = new Map<string, 'positive' | 'negative'>();\n for (const entry of entries) {\n if (entry.feedback !== undefined) {\n newMap.set(entry.requestId, entry.feedback ? 'positive' : 'negative');\n }\n }\n setFeedbackMap(newMap);\n })\n .catch(() => {\n // Silently ignore feedback loading errors\n });\n }, [chat.chatUid, assistantId, mergedOptions.showFeedback]);\n\n // Handle feedback submission\n const handleFeedback = useCallback(\n async (messageId: string, positive: boolean, comment?: string) => {\n if (!chat.chatUid || !feedbackClientRef.current) return;\n\n try {\n await feedbackClientRef.current.submitChatFeedback(assistantId, chat.chatUid, {\n messageId,\n feedback: positive,\n feedbackComment: comment,\n });\n\n setFeedbackMap((prev) => {\n const newMap = new Map(prev);\n newMap.set(messageId, positive ? 'positive' : 'negative');\n return newMap;\n });\n } catch (err) {\n console.error('Failed to submit feedback:', err);\n throw err;\n }\n },\n [chat.chatUid, assistantId]\n );\n\n // Apply CSS variables for theming on the drawer element itself\n // (must target the component root so they override the defaults defined on .devic-chat-drawer)\n const drawerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = drawerRef.current;\n if (!el) return;\n const vars: [string, string | undefined][] = [\n ['--devic-primary', mergedOptions.color !== DEFAULT_OPTIONS.color ? mergedOptions.color : undefined],\n ['--devic-font-family', mergedOptions.fontFamily],\n ['--devic-bg', mergedOptions.backgroundColor],\n ['--devic-text', mergedOptions.textColor],\n ['--devic-bg-secondary', mergedOptions.secondaryBackgroundColor],\n ['--devic-border', mergedOptions.borderColor],\n ['--devic-user-bubble', mergedOptions.userBubbleColor],\n ['--devic-user-bubble-text', mergedOptions.userBubbleTextColor],\n ['--devic-assistant-bubble', mergedOptions.assistantBubbleColor],\n ['--devic-assistant-bubble-text', mergedOptions.assistantBubbleTextColor],\n ['--devic-send-btn', mergedOptions.sendButtonColor],\n ];\n for (const [name, value] of vars) {\n if (value) {\n el.style.setProperty(name, value);\n } else {\n el.style.removeProperty(name);\n }\n }\n }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);\n\n // Resizable drawer\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const startX = e.clientX;\n const startWidth = drawerRef.current?.offsetWidth ?? 0;\n const isLeft = mergedOptions.position === 'left';\n\n const onMove = (ev: MouseEvent) => {\n const delta = ev.clientX - startX;\n const newWidth = startWidth + (isLeft ? delta : -delta);\n const clamped = Math.min(\n mergedOptions.maxWidth,\n Math.max(mergedOptions.minWidth, newWidth)\n );\n setResizedWidth(clamped);\n };\n\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n },\n [mergedOptions.position, mergedOptions.minWidth, mergedOptions.maxWidth]\n );\n\n // Build style object\n const baseWidth = resizedWidth\n ? `${resizedWidth}px`\n : typeof mergedOptions.width === 'number'\n ? `${mergedOptions.width}px`\n : mergedOptions.width;\n\n const drawerStyle = useMemo(\n () => ({\n width: baseWidth,\n zIndex: mergedOptions.zIndex,\n borderRadius: typeof mergedOptions.borderRadius === 'number'\n ? `${mergedOptions.borderRadius}px`\n : mergedOptions.borderRadius,\n ...mergedOptions.style,\n }),\n [baseWidth, mergedOptions.zIndex, mergedOptions.borderRadius, mergedOptions.style]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay (drawer mode only) */}\n {!isInline && (\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n )}\n\n {/* Drawer */}\n <div\n ref={drawerRef}\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n data-mode={mode}\n style={drawerStyle}\n >\n {/* Resize handle */}\n {mergedOptions.resizable && (\n <div\n className=\"devic-resize-handle\"\n data-position={mergedOptions.position}\n onMouseDown={handleResizeStart}\n />\n )}\n\n {/* Header */}\n <div className=\"devic-drawer-header\">\n {avatarUrl && (\n <img\n className=\"devic-drawer-avatar\"\n src={avatarUrl}\n alt=\"\"\n aria-hidden=\"true\"\n />\n )}\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <ConversationSelector\n assistantId={assistantId}\n currentChatUid={chat.chatUid}\n onSelect={handleConversationSelect}\n onNewChat={handleNewChat}\n apiKey={apiKey}\n baseUrl={baseUrl}\n tenantId={tenantId}\n conversationPreview={mergedOptions.conversationPreview}\n />\n <div className=\"devic-drawer-header-actions\">\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n handedOffSubThreadId={chat.handedOffSubThreadId || undefined}\n onHandoffCompleted={chat.onHandoffCompleted}\n handoffWidgetRenderer={mergedOptions.handoffWidgetRenderer}\n toolGroups={mergedOptions.toolGroups}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n pendingInlineWidgets={inlineWidgets}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n />\n\n {/* Input */}\n {mergedOptions.customPromptBox ? (\n <div className=\"devic-input-area\">\n {limitBannerNode}\n {usageBarNode}\n {mergedOptions.customPromptBox({\n sendMessage: handleSend,\n transcribeAudio,\n stop: chat.stopChat,\n isLoading: chat.isLoading,\n newConversation: chat.clearChat,\n references,\n removeReference,\n clearReferences,\n limitExceeded: chat.limitExceeded,\n })}\n </div>\n ) : (\n <ChatInput\n onSend={handleSend}\n disabled={\n chat.isLoading ||\n chat.handedOff ||\n inlineWidgets.length > 0 ||\n !!chat.limitExceeded\n }\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n enableSpeechToText={mergedOptions.enableSpeechToText}\n speechLanguage={mergedOptions.speechLanguage}\n speechTenantId={tenantId}\n speechAutoStop={mergedOptions.speechAutoStop}\n speechAutoStopCountdownMs={mergedOptions.speechAutoStopCountdownMs}\n speechAutoStopSilenceMs={mergedOptions.speechAutoStopSilenceMs}\n speechAutoStopSilenceRatio={mergedOptions.speechAutoStopSilenceRatio}\n speechAutoStopSilenceLevel={mergedOptions.speechAutoStopSilenceLevel}\n speechAutoStopSpeechLevel={mergedOptions.speechAutoStopSpeechLevel}\n speechHandoff={mergedOptions.speechHandoff}\n speechHandoffSendDelayMs={mergedOptions.speechHandoffSendDelayMs}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n sendButtonContent={mergedOptions.sendButtonContent}\n disabledMessage={\n chat.handedOff\n ? 'Waiting for subagent to complete'\n : inlineWidgets.length > 0\n ? 'Waiting for tool response'\n : undefined\n }\n isProcessing={chat.isLoading && !chat.handedOff}\n onStop={chat.stopChat}\n stopButtonContent={mergedOptions.stopButtonContent}\n pendingInputWidget={inputWidget}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n references={references}\n onRemoveReference={removeReference}\n usageBar={usageBarNode}\n limitBanner={limitBannerNode}\n />\n )}\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["forwardRef","_jsx","ChatDrawerErrorBoundary","useMemo","useState","useCallback","useDevicChat","useOptionalDevicContext","useRef","useEffect","client","DevicApiClient","UsageBar","LimitBanner","useImperativeHandle","_jsxs","_Fragment","ConversationSelector","ChatMessages","ChatInput"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatDrawer.js","sources":["../../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport { ConversationSelector } from './ConversationSelector';\nimport { ChatDrawerErrorBoundary } from './ErrorBoundary';\nimport { UsageBar } from './UsageBar';\nimport { LimitBanner } from './LimitBanner';\nimport type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: '100%',\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n enableSpeechToText: false,\n speechLanguage: undefined as any,\n speechAutoStop: true,\n speechAutoStopCountdownMs: 1000,\n speechAutoStopSilenceMs: 1000,\n speechAutoStopSilenceRatio: 0.1,\n speechAutoStopSilenceLevel: 0.02,\n speechAutoStopSpeechLevel: 0.12,\n speechHandoff: false,\n speechHandoffSendDelayMs: 1000,\n speechHandoffHoldMs: 3000,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showAvatar: false,\n showToolTimeline: true,\n zIndex: 1000,\n borderRadius: 0,\n resizable: false,\n minWidth: 300,\n maxWidth: 800,\n style: {},\n fontFamily: undefined as any,\n backgroundColor: undefined as any,\n textColor: undefined as any,\n secondaryBackgroundColor: undefined as any,\n borderColor: undefined as any,\n userBubbleColor: undefined as any,\n userBubbleTextColor: undefined as any,\n assistantBubbleColor: undefined as any,\n assistantBubbleTextColor: undefined as any,\n sendButtonColor: undefined as any,\n loadingIndicator: undefined as any,\n sendButtonContent: undefined as any,\n toolRenderers: undefined as any,\n toolIcons: undefined as any,\n showFeedback: true,\n handoffWidgetRenderer: undefined as any,\n toolGroups: undefined as any,\n stopButtonContent: undefined as any,\n debug: false,\n persistConversation: false,\n customPromptBox: undefined as any,\n conversationPreview: 'date',\n showUsageBar: false,\n usageBarMetric: undefined as any,\n usageBarDisplay: undefined as any,\n customUsageBar: undefined as any,\n hideLimitBanner: false,\n limitBannerRenderer: undefined as any,\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * ref={drawerRef}\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport const ChatDrawer = forwardRef<ChatDrawerHandle, ChatDrawerProps>(\n function ChatDrawer(props, ref) {\n return (\n <ChatDrawerErrorBoundary>\n <ChatDrawerInner {...props} forwardedRef={ref} />\n </ChatDrawerErrorBoundary>\n );\n }\n);\n\ninterface ChatDrawerInnerProps extends ChatDrawerProps {\n forwardedRef?: React.Ref<ChatDrawerHandle>;\n}\n\nfunction ChatDrawerInner({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n mode = 'drawer',\n onConversationChange,\n forwardedRef,\n}: ChatDrawerInnerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // localStorage key for persisting selected conversation\n const storageKey = mergedOptions.persistConversation\n ? `devic-ui-chatUid-${assistantId}`\n : null;\n\n // Resolve initial chatUid: prop takes priority, then localStorage\n const resolvedInitialChatUid = useMemo(() => {\n if (initialChatUid) return initialChatUid;\n if (storageKey) {\n try { return localStorage.getItem(storageKey) || undefined; } catch { return undefined; }\n }\n return undefined;\n }, [initialChatUid, storageKey]);\n\n // Drawer open state (can be controlled or uncontrolled; inline mode is always open)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isInline = mode === 'inline';\n const isOpen = isInline ? true : (controlledIsOpen ?? internalIsOpen);\n\n // Wrap onChatCreated to persist chatUid in localStorage\n const handleChatCreated = useCallback(\n (chatUid: string) => {\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n onChatCreated?.(chatUid);\n },\n [storageKey, onChatCreated]\n );\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: resolvedInitialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated: handleChatCreated,\n onFileUpload,\n debug: mergedOptions.debug,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // Tenant/subtenant resolution mirrors useDevicChat (prop overrides provider).\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n\n // Usage bar (above the input) — only when enabled and a tenant is known.\n // Refetches after each turn via the message count as refresh key.\n const usageBarNode =\n (mergedOptions.showUsageBar ||\n typeof mergedOptions.customUsageBar === 'function') &&\n resolvedTenantId ? (\n <UsageBar\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n tenantId={resolvedTenantId}\n subtenantId={resolvedSubtenantId}\n mode={mergedOptions.showUsageBar === 'onDemand' ? 'onDemand' : 'always'}\n metric={mergedOptions.usageBarMetric}\n display={mergedOptions.usageBarDisplay}\n customUsageBar={mergedOptions.customUsageBar}\n color={mergedOptions.color}\n refreshKey={chat.messages.length}\n debug={mergedOptions.debug}\n />\n ) : null;\n\n // Default usage-limit banner (above the input) — opt-out via hideLimitBanner,\n // override via limitBannerRenderer.\n const limitBannerNode =\n chat.limitExceeded && !mergedOptions.hideLimitBanner\n ? mergedOptions.limitBannerRenderer\n ? mergedOptions.limitBannerRenderer(chat.limitExceeded)\n : <LimitBanner limit={chat.limitExceeded} />\n : null;\n\n // Speech-to-text transcription, exposed to custom prompt boxes so a developer\n // can transcribe audio (binary or URL) and attach the resulting transcriptId.\n const transcribeAudio = useCallback(\n (\n audio: Blob | string,\n transcribeOptions?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n },\n ) => {\n if (!resolvedApiKey) {\n return Promise.reject(\n new Error('API key not configured. Cannot transcribe audio.'),\n );\n }\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n return client.transcribeAudio(audio, {\n language: transcribeOptions?.language ?? mergedOptions.speechLanguage,\n messageUid: transcribeOptions?.messageUid,\n chatUid: transcribeOptions?.chatUid,\n tenantId: transcribeOptions?.tenantId ?? tenantId,\n });\n },\n [resolvedApiKey, resolvedBaseUrl, mergedOptions.speechLanguage, tenantId],\n );\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleToggle = useCallback(() => {\n setInternalIsOpen((prev) => !prev);\n }, []);\n\n // Expose handle for programmatic control\n useImperativeHandle(forwardedRef, () => ({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n setChatUid: (chatUid: string) => {\n chat.loadChat(chatUid);\n },\n sendMessage: (message: string) => {\n chat.sendMessage(message);\n },\n }), [handleOpen, handleClose, handleToggle, chat]);\n\n // Register this drawer in the DevicProvider so AIElementWrapper can open it\n useEffect(() => {\n if (!context?.registerDrawer) return;\n const unregister = context.registerDrawer({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n sendMessage: (message: string) => chat.sendMessage(message),\n });\n return unregister;\n }, [context, handleOpen, handleClose, handleToggle, chat]);\n\n // Partition pending widget calls by render mode\n const { inlineWidgets, inputWidget } = useMemo(() => {\n const inline: typeof chat.pendingWidgetCalls = [];\n let input: typeof chat.pendingWidgetCalls[number] | null = null;\n for (const wc of chat.pendingWidgetCalls) {\n if (wc.widget.render === 'input' && !input) {\n input = wc;\n } else {\n inline.push(wc);\n }\n }\n return { inlineWidgets: inline, inputWidget: input };\n }, [chat.pendingWidgetCalls]);\n\n // Active references from DevicProvider (created by AIElementWrapper)\n const references = context?.references ?? [];\n const removeReference = useCallback(\n (id: string) => {\n context?.removeReference(id);\n },\n [context]\n );\n const clearReferences = useCallback(() => {\n context?.clearReferences();\n }, [context]);\n\n // Handle send message — prefix references and clear them after sending\n const handleSend = useCallback(\n (message: string, files?: File[], meta?: { transcriptId?: string }) => {\n let finalMessage = message;\n if (references.length > 0) {\n const labels = references.map((r) => `\"${r.label}\"`).join(', ');\n finalMessage = `Elemento referenciado: ${labels}\\n\\n${message}`;\n }\n chat.sendMessage(finalMessage, { files, transcriptId: meta?.transcriptId });\n if (references.length > 0) clearReferences();\n },\n [chat, references, clearReferences]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n },\n [chat, onConversationChange, storageKey]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n if (storageKey) {\n try { localStorage.removeItem(storageKey); } catch {}\n }\n }, [chat, storageKey]);\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Feedback state\n const [feedbackMap, setFeedbackMap] = useState<Map<string, 'positive' | 'negative'>>(new Map());\n const feedbackClientRef = useRef<DevicApiClient | null>(null);\n\n // Initialize feedback client\n useEffect(() => {\n if (resolvedApiKey && !feedbackClientRef.current) {\n feedbackClientRef.current = new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n });\n }\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n // Load existing feedback when chat changes\n useEffect(() => {\n if (!chat.chatUid || !feedbackClientRef.current || !mergedOptions.showFeedback) return;\n\n feedbackClientRef.current.getChatFeedback(assistantId, chat.chatUid)\n .then((entries) => {\n const newMap = new Map<string, 'positive' | 'negative'>();\n for (const entry of entries) {\n if (entry.feedback !== undefined) {\n newMap.set(entry.requestId, entry.feedback ? 'positive' : 'negative');\n }\n }\n setFeedbackMap(newMap);\n })\n .catch(() => {\n // Silently ignore feedback loading errors\n });\n }, [chat.chatUid, assistantId, mergedOptions.showFeedback]);\n\n // Handle feedback submission\n const handleFeedback = useCallback(\n async (messageId: string, positive: boolean, comment?: string) => {\n if (!chat.chatUid || !feedbackClientRef.current) return;\n\n try {\n await feedbackClientRef.current.submitChatFeedback(assistantId, chat.chatUid, {\n messageId,\n feedback: positive,\n feedbackComment: comment,\n });\n\n setFeedbackMap((prev) => {\n const newMap = new Map(prev);\n newMap.set(messageId, positive ? 'positive' : 'negative');\n return newMap;\n });\n } catch (err) {\n console.error('Failed to submit feedback:', err);\n throw err;\n }\n },\n [chat.chatUid, assistantId]\n );\n\n // Apply CSS variables for theming on the drawer element itself\n // (must target the component root so they override the defaults defined on .devic-chat-drawer)\n const drawerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = drawerRef.current;\n if (!el) return;\n const vars: [string, string | undefined][] = [\n ['--devic-primary', mergedOptions.color !== DEFAULT_OPTIONS.color ? mergedOptions.color : undefined],\n ['--devic-font-family', mergedOptions.fontFamily],\n ['--devic-bg', mergedOptions.backgroundColor],\n ['--devic-text', mergedOptions.textColor],\n ['--devic-bg-secondary', mergedOptions.secondaryBackgroundColor],\n ['--devic-border', mergedOptions.borderColor],\n ['--devic-user-bubble', mergedOptions.userBubbleColor],\n ['--devic-user-bubble-text', mergedOptions.userBubbleTextColor],\n ['--devic-assistant-bubble', mergedOptions.assistantBubbleColor],\n ['--devic-assistant-bubble-text', mergedOptions.assistantBubbleTextColor],\n ['--devic-send-btn', mergedOptions.sendButtonColor],\n ];\n for (const [name, value] of vars) {\n if (value) {\n el.style.setProperty(name, value);\n } else {\n el.style.removeProperty(name);\n }\n }\n }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);\n\n // Resizable drawer\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const startX = e.clientX;\n const startWidth = drawerRef.current?.offsetWidth ?? 0;\n const isLeft = mergedOptions.position === 'left';\n\n const onMove = (ev: MouseEvent) => {\n const delta = ev.clientX - startX;\n const newWidth = startWidth + (isLeft ? delta : -delta);\n const clamped = Math.min(\n mergedOptions.maxWidth,\n Math.max(mergedOptions.minWidth, newWidth)\n );\n setResizedWidth(clamped);\n };\n\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n },\n [mergedOptions.position, mergedOptions.minWidth, mergedOptions.maxWidth]\n );\n\n // Build style object\n const baseWidth = resizedWidth\n ? `${resizedWidth}px`\n : typeof mergedOptions.width === 'number'\n ? `${mergedOptions.width}px`\n : mergedOptions.width;\n\n const drawerStyle = useMemo(\n () => ({\n width: baseWidth,\n zIndex: mergedOptions.zIndex,\n borderRadius: typeof mergedOptions.borderRadius === 'number'\n ? `${mergedOptions.borderRadius}px`\n : mergedOptions.borderRadius,\n ...mergedOptions.style,\n }),\n [baseWidth, mergedOptions.zIndex, mergedOptions.borderRadius, mergedOptions.style]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay (drawer mode only) */}\n {!isInline && (\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n )}\n\n {/* Drawer */}\n <div\n ref={drawerRef}\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n data-mode={mode}\n style={drawerStyle}\n >\n {/* Resize handle */}\n {mergedOptions.resizable && (\n <div\n className=\"devic-resize-handle\"\n data-position={mergedOptions.position}\n onMouseDown={handleResizeStart}\n />\n )}\n\n {/* Header */}\n <div className=\"devic-drawer-header\">\n {avatarUrl && (\n <img\n className=\"devic-drawer-avatar\"\n src={avatarUrl}\n alt=\"\"\n aria-hidden=\"true\"\n />\n )}\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <ConversationSelector\n assistantId={assistantId}\n currentChatUid={chat.chatUid}\n onSelect={handleConversationSelect}\n onNewChat={handleNewChat}\n apiKey={apiKey}\n baseUrl={baseUrl}\n tenantId={tenantId}\n subtenantId={subtenantId}\n conversationPreview={mergedOptions.conversationPreview}\n />\n <div className=\"devic-drawer-header-actions\">\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n handedOffSubThreadId={chat.handedOffSubThreadId || undefined}\n onHandoffCompleted={chat.onHandoffCompleted}\n handoffWidgetRenderer={mergedOptions.handoffWidgetRenderer}\n toolGroups={mergedOptions.toolGroups}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n pendingInlineWidgets={inlineWidgets}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n />\n\n {/* Input */}\n {mergedOptions.customPromptBox ? (\n <div className=\"devic-input-area\">\n {limitBannerNode}\n {usageBarNode}\n {mergedOptions.customPromptBox({\n sendMessage: handleSend,\n transcribeAudio,\n stop: chat.stopChat,\n isLoading: chat.isLoading,\n newConversation: chat.clearChat,\n references,\n removeReference,\n clearReferences,\n limitExceeded: chat.limitExceeded,\n })}\n </div>\n ) : (\n <ChatInput\n onSend={handleSend}\n disabled={\n chat.isLoading ||\n chat.handedOff ||\n inlineWidgets.length > 0 ||\n !!chat.limitExceeded\n }\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n enableSpeechToText={mergedOptions.enableSpeechToText}\n speechLanguage={mergedOptions.speechLanguage}\n speechTenantId={tenantId}\n speechAutoStop={mergedOptions.speechAutoStop}\n speechAutoStopCountdownMs={mergedOptions.speechAutoStopCountdownMs}\n speechAutoStopSilenceMs={mergedOptions.speechAutoStopSilenceMs}\n speechAutoStopSilenceRatio={mergedOptions.speechAutoStopSilenceRatio}\n speechAutoStopSilenceLevel={mergedOptions.speechAutoStopSilenceLevel}\n speechAutoStopSpeechLevel={mergedOptions.speechAutoStopSpeechLevel}\n speechHandoff={mergedOptions.speechHandoff}\n speechHandoffSendDelayMs={mergedOptions.speechHandoffSendDelayMs}\n speechHandoffHoldMs={mergedOptions.speechHandoffHoldMs}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n sendButtonContent={mergedOptions.sendButtonContent}\n disabledMessage={\n chat.handedOff\n ? 'Waiting for subagent to complete'\n : inlineWidgets.length > 0\n ? 'Waiting for tool response'\n : undefined\n }\n isProcessing={chat.isLoading && !chat.handedOff}\n onStop={chat.stopChat}\n stopButtonContent={mergedOptions.stopButtonContent}\n pendingInputWidget={inputWidget}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n references={references}\n onRemoveReference={removeReference}\n usageBar={usageBarNode}\n limitBanner={limitBannerNode}\n />\n )}\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["forwardRef","_jsx","ChatDrawerErrorBoundary","useMemo","useState","useCallback","useDevicChat","useOptionalDevicContext","useRef","useEffect","client","DevicApiClient","UsageBar","LimitBanner","useImperativeHandle","_jsxs","_Fragment","ConversationSelector","ChatMessages","ChatInput"],"mappings":";;;;;;;;;;;;;;AAaA,MAAM,eAAe,GAAgC;AACnD,IAAA,QAAQ,EAAE,OAAO;AACjB,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,WAAW,EAAE,KAAK;AAClB,IAAA,KAAK,EAAE,SAAS;AAChB,IAAA,cAAc,EAAE,EAAE;AAClB,IAAA,iBAAiB,EAAE,EAAE;AACrB,IAAA,iBAAiB,EAAE,KAAK;IACxB,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;AACnD,IAAA,WAAW,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;AAC7B,IAAA,kBAAkB,EAAE,KAAK;AACzB,IAAA,cAAc,EAAE,SAAgB;AAChC,IAAA,cAAc,EAAE,IAAI;AACpB,IAAA,yBAAyB,EAAE,IAAI;AAC/B,IAAA,uBAAuB,EAAE,IAAI;AAC7B,IAAA,0BAA0B,EAAE,GAAG;AAC/B,IAAA,0BAA0B,EAAE,IAAI;AAChC,IAAA,yBAAyB,EAAE,IAAI;AAC/B,IAAA,aAAa,EAAE,KAAK;AACpB,IAAA,wBAAwB,EAAE,IAAI;AAC9B,IAAA,mBAAmB,EAAE,IAAI;AACzB,IAAA,gBAAgB,EAAE,mBAAmB;AACrC,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,UAAU,EAAE,KAAK;AACjB,IAAA,gBAAgB,EAAE,IAAI;AACtB,IAAA,MAAM,EAAE,IAAI;AACZ,IAAA,YAAY,EAAE,CAAC;AACf,IAAA,SAAS,EAAE,KAAK;AAChB,IAAA,QAAQ,EAAE,GAAG;AACb,IAAA,QAAQ,EAAE,GAAG;AACb,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,UAAU,EAAE,SAAgB;AAC5B,IAAA,eAAe,EAAE,SAAgB;AACjC,IAAA,SAAS,EAAE,SAAgB;AAC3B,IAAA,wBAAwB,EAAE,SAAgB;AAC1C,IAAA,WAAW,EAAE,SAAgB;AAC7B,IAAA,eAAe,EAAE,SAAgB;AACjC,IAAA,mBAAmB,EAAE,SAAgB;AACrC,IAAA,oBAAoB,EAAE,SAAgB;AACtC,IAAA,wBAAwB,EAAE,SAAgB;AAC1C,IAAA,eAAe,EAAE,SAAgB;AACjC,IAAA,gBAAgB,EAAE,SAAgB;AAClC,IAAA,iBAAiB,EAAE,SAAgB;AACnC,IAAA,aAAa,EAAE,SAAgB;AAC/B,IAAA,SAAS,EAAE,SAAgB;AAC3B,IAAA,YAAY,EAAE,IAAI;AAClB,IAAA,qBAAqB,EAAE,SAAgB;AACvC,IAAA,UAAU,EAAE,SAAgB;AAC5B,IAAA,iBAAiB,EAAE,SAAgB;AACnC,IAAA,KAAK,EAAE,KAAK;AACZ,IAAA,mBAAmB,EAAE,KAAK;AAC1B,IAAA,eAAe,EAAE,SAAgB;AACjC,IAAA,mBAAmB,EAAE,MAAM;AAC3B,IAAA,YAAY,EAAE,KAAK;AACnB,IAAA,cAAc,EAAE,SAAgB;AAChC,IAAA,eAAe,EAAE,SAAgB;AACjC,IAAA,cAAc,EAAE,SAAgB;AAChC,IAAA,eAAe,EAAE,KAAK;AACtB,IAAA,mBAAmB,EAAE,SAAgB;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACI,MAAM,UAAU,GAAGA,gBAAU,CAClC,SAAS,UAAU,CAAC,KAAK,EAAE,GAAG,EAAA;AAC5B,IAAA,QACEC,cAAA,CAACC,qCAAuB,EAAA,EAAA,QAAA,EACtBD,eAAC,eAAe,EAAA,EAAA,GAAK,KAAK,EAAE,YAAY,EAAE,GAAG,EAAA,CAAI,EAAA,CACzB;AAE9B,CAAC;AAOH,SAAS,eAAe,CAAC,EACvB,WAAW,EACX,OAAO,EAAE,cAAc,EACvB,OAAO,GAAG,EAAE,EACZ,YAAY,EACZ,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,MAAM,EACN,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,OAAO,EACP,aAAa,EACb,YAAY,EACZ,MAAM,EACN,OAAO,EACP,MAAM,EAAE,gBAAgB,EACxB,SAAS,EACT,IAAI,GAAG,QAAQ,EACf,oBAAoB,EACpB,YAAY,GACS,EAAA;;IAErB,MAAM,aAAa,GAAGE,aAAO,CAC3B,OAAO,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC,EAC1C,CAAC,OAAO,CAAC,CACV;;AAGD,IAAA,MAAM,UAAU,GAAG,aAAa,CAAC;UAC7B,CAAA,iBAAA,EAAoB,WAAW,CAAA;UAC/B,IAAI;;AAGR,IAAA,MAAM,sBAAsB,GAAGA,aAAO,CAAC,MAAK;AAC1C,QAAA,IAAI,cAAc;AAAE,YAAA,OAAO,cAAc;QACzC,IAAI,UAAU,EAAE;AACd,YAAA,IAAI;gBAAE,OAAO,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,SAAS;YAAE;AAAE,YAAA,MAAM;AAAE,gBAAA,OAAO,SAAS;YAAE;QAC1F;AACA,QAAA,OAAO,SAAS;AAClB,IAAA,CAAC,EAAE,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;;AAGhC,IAAA,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAGC,cAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC/E,IAAA,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ;AAClC,IAAA,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI,gBAAgB,IAAI,cAAc,CAAC;;AAGrE,IAAA,MAAM,iBAAiB,GAAGC,iBAAW,CACnC,CAAC,OAAe,KAAI;QAClB,IAAI,UAAU,EAAE;AACd,YAAA,IAAI;AAAE,gBAAA,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC;YAAE;YAAE,MAAM,EAAC;QAC5D;AACA,QAAA,aAAa,GAAG,OAAO,CAAC;AAC1B,IAAA,CAAC,EACD,CAAC,UAAU,EAAE,aAAa,CAAC,CAC5B;;IAGD,MAAM,IAAI,GAAGC,yBAAY,CAAC;QACxB,WAAW;AACX,QAAA,OAAO,EAAE,sBAAsB;QAC/B,MAAM;QACN,OAAO;QACP,QAAQ;QACR,cAAc;QACd,WAAW;QACX,iBAAiB;QACjB,YAAY;QACZ,mBAAmB;QACnB,aAAa;QACb,iBAAiB;QACjB,UAAU;QACV,OAAO;AACP,QAAA,aAAa,EAAE,iBAAiB;QAChC,YAAY;QACZ,KAAK,EAAE,aAAa,CAAC,KAAK;AAC3B,KAAA,CAAC;;AAGF,IAAA,MAAM,OAAO,GAAGC,oCAAuB,EAAE;AACzC,IAAA,MAAM,cAAc,GAAG,MAAM,IAAI,OAAO,EAAE,MAAM;IAChD,MAAM,eAAe,GAAG,OAAO,IAAI,OAAO,EAAE,OAAO,IAAI,sBAAsB;IAC7E,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAGH,cAAQ,CAAgB,IAAI,CAAC;AAC/D,IAAA,MAAM,gBAAgB,GAAGI,YAAM,CAAgB,IAAI,CAAC;IAEpDC,eAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,aAAa,CAAC,UAAU,IAAI,CAAC,cAAc,IAAI,gBAAgB,CAAC,OAAO,KAAK,WAAW;YAAE;AAC9F,QAAA,gBAAgB,CAAC,OAAO,GAAG,WAAW;AACtC,QAAA,MAAMC,QAAM,GAAG,IAAIC,qBAAc,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;QACvFD,QAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAI;YAC1C,IAAI,CAAC,CAAC,MAAM;AAAE,gBAAA,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;QACtC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;AACpB,IAAA,CAAC,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;;AAG5E,IAAA,MAAM,gBAAgB,GAAG,QAAQ,IAAI,OAAO,EAAE,QAAQ;AACtD,IAAA,MAAM,mBAAmB,GAAG,WAAW,IAAI,OAAO,EAAE,WAAW;;;AAI/D,IAAA,MAAM,YAAY,GAChB,CAAC,aAAa,CAAC,YAAY;AACzB,QAAA,OAAO,aAAa,CAAC,cAAc,KAAK,UAAU;AACpD,QAAA,gBAAgB,IACdT,cAAA,CAACW,iBAAQ,EAAA,EACP,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,WAAW,EAAE,mBAAmB,EAChC,IAAI,EAAE,aAAa,CAAC,YAAY,KAAK,UAAU,GAAG,UAAU,GAAG,QAAQ,EACvE,MAAM,EAAE,aAAa,CAAC,cAAc,EACpC,OAAO,EAAE,aAAa,CAAC,eAAe,EACtC,cAAc,EAAE,aAAa,CAAC,cAAc,EAC5C,KAAK,EAAE,aAAa,CAAC,KAAK,EAC1B,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAChC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAA,CAC1B,IACA,IAAI;;;IAIV,MAAM,eAAe,GACnB,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC;UACjC,aAAa,CAAC;cACZ,aAAa,CAAC,mBAAmB,CAAC,IAAI,CAAC,aAAa;cACpDX,eAACY,uBAAW,EAAA,EAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAA;UACxC,IAAI;;;IAIV,MAAM,eAAe,GAAGR,iBAAW,CACjC,CACE,KAAoB,EACpB,iBAKC,KACC;QACF,IAAI,CAAC,cAAc,EAAE;YACnB,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAC9D;QACH;AACA,QAAA,MAAMK,QAAM,GAAG,IAAIC,qBAAc,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;AACvF,QAAA,OAAOD,QAAM,CAAC,eAAe,CAAC,KAAK,EAAE;AACnC,YAAA,QAAQ,EAAE,iBAAiB,EAAE,QAAQ,IAAI,aAAa,CAAC,cAAc;YACrE,UAAU,EAAE,iBAAiB,EAAE,UAAU;YACzC,OAAO,EAAE,iBAAiB,EAAE,OAAO;AACnC,YAAA,QAAQ,EAAE,iBAAiB,EAAE,QAAQ,IAAI,QAAQ;AAClD,SAAA,CAAC;AACJ,IAAA,CAAC,EACD,CAAC,cAAc,EAAE,eAAe,EAAE,aAAa,CAAC,cAAc,EAAE,QAAQ,CAAC,CAC1E;;AAGD,IAAA,MAAM,UAAU,GAAGL,iBAAW,CAAC,MAAK;QAClC,iBAAiB,CAAC,IAAI,CAAC;QACvB,MAAM,IAAI;AACZ,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,WAAW,GAAGA,iBAAW,CAAC,MAAK;QACnC,iBAAiB,CAAC,KAAK,CAAC;QACxB,OAAO,IAAI;AACb,IAAA,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;AAEb,IAAA,MAAM,YAAY,GAAGA,iBAAW,CAAC,MAAK;QACpC,iBAAiB,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAAS,yBAAmB,CAAC,YAAY,EAAE,OAAO;AACvC,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,KAAK,EAAE,WAAW;AAClB,QAAA,MAAM,EAAE,YAAY;AACpB,QAAA,UAAU,EAAE,CAAC,OAAe,KAAI;AAC9B,YAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxB,CAAC;AACD,QAAA,WAAW,EAAE,CAAC,OAAe,KAAI;AAC/B,YAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;QAC3B,CAAC;KACF,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;;IAGlDL,eAAS,CAAC,MAAK;QACb,IAAI,CAAC,OAAO,EAAE,cAAc;YAAE;AAC9B,QAAA,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;AACxC,YAAA,IAAI,EAAE,UAAU;AAChB,YAAA,KAAK,EAAE,WAAW;AAClB,YAAA,MAAM,EAAE,YAAY;YACpB,WAAW,EAAE,CAAC,OAAe,KAAK,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AAC5D,SAAA,CAAC;AACF,QAAA,OAAO,UAAU;AACnB,IAAA,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;;IAG1D,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,GAAGN,aAAO,CAAC,MAAK;QAClD,MAAM,MAAM,GAAmC,EAAE;QACjD,IAAI,KAAK,GAAkD,IAAI;AAC/D,QAAA,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE;YACxC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,KAAK,EAAE;gBAC1C,KAAK,GAAG,EAAE;YACZ;iBAAO;AACL,gBAAA,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB;QACF;QACA,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE;AACtD,IAAA,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;;AAG7B,IAAA,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,EAAE;AAC5C,IAAA,MAAM,eAAe,GAAGE,iBAAW,CACjC,CAAC,EAAU,KAAI;AACb,QAAA,OAAO,EAAE,eAAe,CAAC,EAAE,CAAC;AAC9B,IAAA,CAAC,EACD,CAAC,OAAO,CAAC,CACV;AACD,IAAA,MAAM,eAAe,GAAGA,iBAAW,CAAC,MAAK;QACvC,OAAO,EAAE,eAAe,EAAE;AAC5B,IAAA,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;;IAGb,MAAM,UAAU,GAAGA,iBAAW,CAC5B,CAAC,OAAe,EAAE,KAAc,EAAE,IAAgC,KAAI;QACpE,IAAI,YAAY,GAAG,OAAO;AAC1B,QAAA,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE;YACzB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAA,CAAA,CAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/D,YAAA,YAAY,GAAG,CAAA,uBAAA,EAA0B,MAAM,CAAA,IAAA,EAAO,OAAO,EAAE;QACjE;AACA,QAAA,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AAC3E,QAAA,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;AAAE,YAAA,eAAe,EAAE;IAC9C,CAAC,EACD,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,CAAC,CACpC;;AAGD,IAAA,MAAM,wBAAwB,GAAGA,iBAAW,CAC1C,CAAC,OAAe,KAAI;AAClB,QAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;AACtB,QAAA,oBAAoB,GAAG,OAAO,CAAC;QAC/B,IAAI,UAAU,EAAE;AACd,YAAA,IAAI;AAAE,gBAAA,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC;YAAE;YAAE,MAAM,EAAC;QAC5D;IACF,CAAC,EACD,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,CAAC,CACzC;AAED,IAAA,MAAM,aAAa,GAAGA,iBAAW,CAAC,MAAK;QACrC,IAAI,CAAC,SAAS,EAAE;QAChB,IAAI,UAAU,EAAE;AACd,YAAA,IAAI;AAAE,gBAAA,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE;YAAE,MAAM,EAAC;QACtD;AACF,IAAA,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;;AAGtB,IAAA,MAAM,oBAAoB,GAAGA,iBAAW,CACtC,CAAC,OAAe,KAAI;AAClB,QAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AAC3B,IAAA,CAAC,EACD,CAAC,IAAI,CAAC,CACP;;AAGD,IAAA,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAGD,cAAQ,CAAuC,IAAI,GAAG,EAAE,CAAC;AAC/F,IAAA,MAAM,iBAAiB,GAAGI,YAAM,CAAwB,IAAI,CAAC;;IAG7DC,eAAS,CAAC,MAAK;AACb,QAAA,IAAI,cAAc,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE;AAChD,YAAA,iBAAiB,CAAC,OAAO,GAAG,IAAIE,qBAAc,CAAC;AAC7C,gBAAA,MAAM,EAAE,cAAc;AACtB,gBAAA,OAAO,EAAE,eAAe;AACzB,aAAA,CAAC;QACJ;AACF,IAAA,CAAC,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;;IAGrCF,eAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,IAAI,CAAC,aAAa,CAAC,YAAY;YAAE;QAEhF,iBAAiB,CAAC,OAAO,CAAC,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO;AAChE,aAAA,IAAI,CAAC,CAAC,OAAO,KAAI;AAChB,YAAA,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmC;AACzD,YAAA,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;AAC3B,gBAAA,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE;AAChC,oBAAA,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;gBACvE;YACF;YACA,cAAc,CAAC,MAAM,CAAC;AACxB,QAAA,CAAC;aACA,KAAK,CAAC,MAAK;;AAEZ,QAAA,CAAC,CAAC;AACN,IAAA,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;;AAG3D,IAAA,MAAM,cAAc,GAAGJ,iBAAW,CAChC,OAAO,SAAiB,EAAE,QAAiB,EAAE,OAAgB,KAAI;QAC/D,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO;YAAE;AAEjD,QAAA,IAAI;YACF,MAAM,iBAAiB,CAAC,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE;gBAC5E,SAAS;AACT,gBAAA,QAAQ,EAAE,QAAQ;AAClB,gBAAA,eAAe,EAAE,OAAO;AACzB,aAAA,CAAC;AAEF,YAAA,cAAc,CAAC,CAAC,IAAI,KAAI;AACtB,gBAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC;AAC5B,gBAAA,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AACzD,gBAAA,OAAO,MAAM;AACf,YAAA,CAAC,CAAC;QACJ;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC;AAChD,YAAA,MAAM,GAAG;QACX;IACF,CAAC,EACD,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAC5B;;;AAID,IAAA,MAAM,SAAS,GAAGG,YAAM,CAAiB,IAAI,CAAC;IAC9CC,eAAS,CAAC,MAAK;AACb,QAAA,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO;AAC5B,QAAA,IAAI,CAAC,EAAE;YAAE;AACT,QAAA,MAAM,IAAI,GAAmC;AAC3C,YAAA,CAAC,iBAAiB,EAAE,aAAa,CAAC,KAAK,KAAK,eAAe,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,GAAG,SAAS,CAAC;AACpG,YAAA,CAAC,qBAAqB,EAAE,aAAa,CAAC,UAAU,CAAC;AACjD,YAAA,CAAC,YAAY,EAAE,aAAa,CAAC,eAAe,CAAC;AAC7C,YAAA,CAAC,cAAc,EAAE,aAAa,CAAC,SAAS,CAAC;AACzC,YAAA,CAAC,sBAAsB,EAAE,aAAa,CAAC,wBAAwB,CAAC;AAChE,YAAA,CAAC,gBAAgB,EAAE,aAAa,CAAC,WAAW,CAAC;AAC7C,YAAA,CAAC,qBAAqB,EAAE,aAAa,CAAC,eAAe,CAAC;AACtD,YAAA,CAAC,0BAA0B,EAAE,aAAa,CAAC,mBAAmB,CAAC;AAC/D,YAAA,CAAC,0BAA0B,EAAE,aAAa,CAAC,oBAAoB,CAAC;AAChE,YAAA,CAAC,+BAA+B,EAAE,aAAa,CAAC,wBAAwB,CAAC;AACzE,YAAA,CAAC,kBAAkB,EAAE,aAAa,CAAC,eAAe,CAAC;SACpD;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YAChC,IAAI,KAAK,EAAE;gBACT,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC;YACnC;iBAAO;AACL,gBAAA,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;YAC/B;QACF;IACF,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,UAAU,EAAE,aAAa,CAAC,eAAe,EAAE,aAAa,CAAC,SAAS,EAAE,aAAa,CAAC,wBAAwB,EAAE,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,eAAe,EAAE,aAAa,CAAC,mBAAmB,EAAE,aAAa,CAAC,oBAAoB,EAAE,aAAa,CAAC,wBAAwB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;;IAG3V,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAGL,cAAQ,CAAgB,IAAI,CAAC;AAErE,IAAA,MAAM,iBAAiB,GAAGC,iBAAW,CACnC,CAAC,CAAmB,KAAI;QACtB,CAAC,CAAC,cAAc,EAAE;AAClB,QAAA,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO;QACxB,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,EAAE,WAAW,IAAI,CAAC;AACtD,QAAA,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,KAAK,MAAM;AAEhD,QAAA,MAAM,MAAM,GAAG,CAAC,EAAc,KAAI;AAChC,YAAA,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,GAAG,MAAM;AACjC,YAAA,MAAM,QAAQ,GAAG,UAAU,IAAI,MAAM,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC;YACvD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CACtB,aAAa,CAAC,QAAQ,EACtB,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAC3C;YACD,eAAe,CAAC,OAAO,CAAC;AAC1B,QAAA,CAAC;QAED,MAAM,IAAI,GAAG,MAAK;AAChB,YAAA,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC;AACjD,YAAA,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC;AAC/C,QAAA,CAAC;AAED,QAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,CAAC;AAC9C,QAAA,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC;AAC5C,IAAA,CAAC,EACD,CAAC,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CACzE;;IAGD,MAAM,SAAS,GAAG;UACd,CAAA,EAAG,YAAY,CAAA,EAAA;AACjB,UAAE,OAAO,aAAa,CAAC,KAAK,KAAK;AAC/B,cAAE,CAAA,EAAG,aAAa,CAAC,KAAK,CAAA,EAAA;AACxB,cAAE,aAAa,CAAC,KAAK;AAEzB,IAAA,MAAM,WAAW,GAAGF,aAAO,CACzB,OAAO;AACL,QAAA,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,aAAa,CAAC,MAAM;AAC5B,QAAA,YAAY,EAAE,OAAO,aAAa,CAAC,YAAY,KAAK;AAClD,cAAE,CAAA,EAAG,aAAa,CAAC,YAAY,CAAA,EAAA;cAC7B,aAAa,CAAC,YAAY;QAC9B,GAAG,aAAa,CAAC,KAAK;AACvB,KAAA,CAAC,EACF,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,KAAK,CAAC,CACnF;AAED,IAAA,MAAM,YAAY,GAAGA,aAAO,CAC1B,OAAO;AACL,QAAA,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC;AACjC,KAAA,CAAC,EACF,CAAC,aAAa,CAAC,MAAM,CAAC,CACvB;AAED,IAAA,MAAM,YAAY,GAAGA,aAAO,CAC1B,OAAO;AACL,QAAA,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC;AAChC,QAAA,CAAC,aAAa,CAAC,QAAQ,GAAG,EAAE;AAC5B,QAAA,MAAM,EAAE,EAAE;KACX,CAAC,EACF,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAC/C;AAED,IAAA,QACEY,eAAA,CAAAC,mBAAA,EAAA,EAAA,QAAA,EAAA,CAEG,CAAC,QAAQ,KACRf,wBACE,SAAS,EAAC,sBAAsB,EAAA,WAAA,EACrB,MAAM,EACjB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,WAAW,EAAA,CACpB,CACH,EAGDc,yBACE,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,CAAA,kBAAA,EAAqB,SAAS,IAAI,EAAE,CAAA,CAAE,mBAClC,aAAa,CAAC,QAAQ,EAAA,WAAA,EAC1B,MAAM,eACN,IAAI,EACf,KAAK,EAAE,WAAW,EAAA,QAAA,EAAA,CAGjB,aAAa,CAAC,SAAS,KACtBd,cAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,qBAAqB,EAAA,eAAA,EAChB,aAAa,CAAC,QAAQ,EACrC,WAAW,EAAE,iBAAiB,EAAA,CAC9B,CACH,EAGDc,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,qBAAqB,aACjC,SAAS,KACRd,cAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,qBAAqB,EAC/B,GAAG,EAAE,SAAS,EACd,GAAG,EAAC,EAAE,EAAA,aAAA,EACM,MAAM,EAAA,CAClB,CACH,EACDA,cAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAC,oBAAoB,EAAA,QAAA,EAAE,aAAa,CAAC,KAAK,GAAM,EAC7DA,cAAA,CAACgB,yCAAoB,EAAA,EACnB,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,IAAI,CAAC,OAAO,EAC5B,QAAQ,EAAE,wBAAwB,EAClC,SAAS,EAAE,aAAa,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,aAAa,CAAC,mBAAmB,EAAA,CACtD,EACFF,yBAAK,SAAS,EAAC,6BAA6B,EAAA,QAAA,EAAA,CAC1Cd,cAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,oBAAoB,EAC9B,OAAO,EAAE,aAAa,EACtB,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,UAAU,EACrB,KAAK,EAAC,UAAU,EAAA,QAAA,EAEhBA,eAAC,QAAQ,EAAA,EAAA,CAAG,GACL,EACR,CAAC,QAAQ,KACRA,2BACE,SAAS,EAAC,oBAAoB,EAC9B,OAAO,EAAE,WAAW,EACpB,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,YAAY,YAEvBA,cAAA,CAAC,SAAS,KAAG,EAAA,CACN,CACV,IACG,CAAA,EAAA,CACF,EAGL,IAAI,CAAC,KAAK,KACTA,wBAAK,SAAS,EAAC,aAAa,EAAA,QAAA,EACzB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAA,CACf,CACP,EAGDA,cAAA,CAACiB,yBAAY,IACX,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,WAAW,EAAE,IAAI,CAAC,QAAQ,EAC1B,SAAS,EAAE,IAAI,CAAC,SAAS,EACzB,cAAc,EAAE,aAAa,CAAC,cAAc,EAC5C,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,EAClD,gBAAgB,EAAE,oBAAoB,EACtC,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,EAChD,aAAa,EAAE,aAAa,CAAC,aAAa,EAC1C,SAAS,EAAE,aAAa,CAAC,SAAS,EAClC,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,EAChD,YAAY,EAAE,aAAa,CAAC,YAAY,EACxC,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,cAAc,EAC1B,oBAAoB,EAAE,IAAI,CAAC,oBAAoB,IAAI,SAAS,EAC5D,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,EAC3C,qBAAqB,EAAE,aAAa,CAAC,qBAAqB,EAC1D,UAAU,EAAE,aAAa,CAAC,UAAU,EACpC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,eAAe,EACxB,oBAAoB,EAAE,aAAa,EACnC,cAAc,EAAE,IAAI,CAAC,oBAAoB,EACzC,cAAc,EAAE,IAAI,CAAC,gBAAgB,EAAA,CACrC,EAGD,aAAa,CAAC,eAAe,IAC5BH,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kBAAkB,EAAA,QAAA,EAAA,CAC9B,eAAe,EACf,YAAY,EACZ,aAAa,CAAC,eAAe,CAAC;AAC7B,gCAAA,WAAW,EAAE,UAAU;gCACvB,eAAe;gCACf,IAAI,EAAE,IAAI,CAAC,QAAQ;gCACnB,SAAS,EAAE,IAAI,CAAC,SAAS;gCACzB,eAAe,EAAE,IAAI,CAAC,SAAS;gCAC/B,UAAU;gCACV,eAAe;gCACf,eAAe;gCACf,aAAa,EAAE,IAAI,CAAC,aAAa;AAClC,6BAAA,CAAC,IACE,KAENd,cAAA,CAACkB,mBAAS,EAAA,EACR,MAAM,EAAE,UAAU,EAClB,QAAQ,EACN,IAAI,CAAC,SAAS;AACd,4BAAA,IAAI,CAAC,SAAS;4BACd,aAAa,CAAC,MAAM,GAAG,CAAC;4BACxB,CAAC,CAAC,IAAI,CAAC,aAAa,EAEtB,WAAW,EAAE,aAAa,CAAC,gBAAgB,EAC3C,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,EAClD,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,EAChD,WAAW,EAAE,aAAa,CAAC,WAAW,EACtC,kBAAkB,EAAE,aAAa,CAAC,kBAAkB,EACpD,cAAc,EAAE,aAAa,CAAC,cAAc,EAC5C,cAAc,EAAE,QAAQ,EACxB,cAAc,EAAE,aAAa,CAAC,cAAc,EAC5C,yBAAyB,EAAE,aAAa,CAAC,yBAAyB,EAClE,uBAAuB,EAAE,aAAa,CAAC,uBAAuB,EAC9D,0BAA0B,EAAE,aAAa,CAAC,0BAA0B,EACpE,0BAA0B,EAAE,aAAa,CAAC,0BAA0B,EACpE,yBAAyB,EAAE,aAAa,CAAC,yBAAyB,EAClE,aAAa,EAAE,aAAa,CAAC,aAAa,EAC1C,wBAAwB,EAAE,aAAa,CAAC,wBAAwB,EAChE,mBAAmB,EAAE,aAAa,CAAC,mBAAmB,EACtD,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,EAClD,eAAe,EACb,IAAI,CAAC;AACH,8BAAE;AACF,8BAAE,aAAa,CAAC,MAAM,GAAG;AACvB,kCAAE;kCACA,SAAS,EAEjB,YAAY,EAAE,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,EAC/C,MAAM,EAAE,IAAI,CAAC,QAAQ,EACrB,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,EAClD,kBAAkB,EAAE,WAAW,EAC/B,cAAc,EAAE,IAAI,CAAC,oBAAoB,EACzC,cAAc,EAAE,IAAI,CAAC,gBAAgB,EACrC,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,eAAe,EAClC,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,eAAe,EAAA,CAC5B,CACH,IACG,EAGL,CAAC,QAAQ,IAAI,CAAC,MAAM,KACnBlB,2BACE,SAAS,EAAC,eAAe,EACzB,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,WAAW,YAEtBA,cAAA,CAAC,QAAQ,KAAG,EAAA,CACL,CACV,CAAA,EAAA,CACA;AAEP;AAEA;;AAEG;AACH,SAAS,SAAS,GAAA;AAChB,IAAA,QACEc,eAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAAA,CAEtBd,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EACtCA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,CAAA,EAAA,CAClC;AAEV;AAEA;;AAEG;AACH,SAAS,QAAQ,GAAA;AACf,IAAA,QACEc,eAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAAA,CAEtBd,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EACvCA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,CAAA,EAAA,CACnC;AAEV;AAEA;;AAEG;AACH,SAAS,QAAQ,GAAA;IACf,QACEA,cAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,cAAc,EAAA,QAAA,EAEnBA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,yFAAyF,EAAA,CAAG,EAAA,CAChG;AAEV;;;;"}
|
|
@@ -20,11 +20,12 @@ const FILE_TYPE_ACCEPT = {
|
|
|
20
20
|
// Handoff (hands-free) loop timings.
|
|
21
21
|
const HANDOFF_PENDING_MS = 1000; // default cancellable countdown before auto-send
|
|
22
22
|
const HANDOFF_INACTIVITY_MS = 6000; // silence (no speech) that ends the loop
|
|
23
|
+
const HANDOFF_HOLD_MS = 3000; // press-and-hold duration on the mic to arm hands-free
|
|
23
24
|
/**
|
|
24
25
|
* Chat input component with file upload support
|
|
25
26
|
*/
|
|
26
27
|
function ChatInput({ onSend, disabled = false, placeholder = 'Type a message...', enableFileUploads = false, allowedFileTypes = { images: true, documents: true }, maxFileSize = 10 * 1024 * 1024, // 10MB
|
|
27
|
-
enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = true, speechAutoStopCountdownMs, speechAutoStopSilenceMs, speechAutoStopSilenceRatio, speechAutoStopSilenceLevel, speechAutoStopSpeechLevel, speechHandoff = false, speechHandoffSendDelayMs, apiKey, baseUrl, sendButtonContent, disabledMessage, isProcessing = false, onStop, stopButtonContent, pendingInputWidget, onSubmitWidget, onCancelWidget, references, onRemoveReference, usageBar, limitBanner, }) {
|
|
28
|
+
enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = true, speechAutoStopCountdownMs, speechAutoStopSilenceMs, speechAutoStopSilenceRatio, speechAutoStopSilenceLevel, speechAutoStopSpeechLevel, speechHandoff = false, speechHandoffSendDelayMs, speechHandoffHoldMs, apiKey, baseUrl, sendButtonContent, disabledMessage, isProcessing = false, onStop, stopButtonContent, pendingInputWidget, onSubmitWidget, onCancelWidget, references, onRemoveReference, usageBar, limitBanner, }) {
|
|
28
29
|
// When a widget is pending as 'input', render it in place of the textarea
|
|
29
30
|
if (pendingInputWidget) {
|
|
30
31
|
const WidgetComponent = pendingInputWidget.widget.component;
|
|
@@ -73,6 +74,13 @@ enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = tru
|
|
|
73
74
|
const prevProcessingRef = React.useRef(isProcessing);
|
|
74
75
|
// Always-fresh send fn so the deferred auto-send uses the latest message.
|
|
75
76
|
const handleSendRef = React.useRef(() => { });
|
|
77
|
+
// --- Press-and-hold to arm hands-free ---
|
|
78
|
+
// Holding the mic for `holdMs` fills a ring (0→1) and activates hands-free;
|
|
79
|
+
// releasing earlier falls back to a single one-shot recording.
|
|
80
|
+
const [holdProgress, setHoldProgress] = React.useState(0);
|
|
81
|
+
const [isHolding, setIsHolding] = React.useState(false);
|
|
82
|
+
const holdRafRef = React.useRef(null);
|
|
83
|
+
const holdFiredRef = React.useRef(false);
|
|
76
84
|
// Client used only for the /whisper transcription call.
|
|
77
85
|
const transcribeClient = React.useMemo(() => {
|
|
78
86
|
if (!enableSpeechToText || !apiKey)
|
|
@@ -133,14 +141,81 @@ enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = tru
|
|
|
133
141
|
}
|
|
134
142
|
recording.cancel();
|
|
135
143
|
}, [clearPending, recording]);
|
|
136
|
-
|
|
144
|
+
// One-shot recording: transcribe → fill the textarea for manual review/send.
|
|
145
|
+
// No hands-free loop, so the textarea stays available afterwards.
|
|
146
|
+
const startOneShotRecording = React.useCallback(() => {
|
|
137
147
|
setSpeechError(null);
|
|
138
|
-
if (speechHandoff) {
|
|
139
|
-
handoffActiveRef.current = true;
|
|
140
|
-
setHandoffActive(true);
|
|
141
|
-
}
|
|
142
148
|
void recording.start();
|
|
143
|
-
}, [recording
|
|
149
|
+
}, [recording]);
|
|
150
|
+
// Arm the hands-free loop and start listening.
|
|
151
|
+
const startHandsfreeRecording = React.useCallback(() => {
|
|
152
|
+
setSpeechError(null);
|
|
153
|
+
handoffActiveRef.current = true;
|
|
154
|
+
setHandoffActive(true);
|
|
155
|
+
void recording.start();
|
|
156
|
+
}, [recording]);
|
|
157
|
+
// Stop and reset the press-and-hold progress loop.
|
|
158
|
+
const clearHold = React.useCallback(() => {
|
|
159
|
+
if (holdRafRef.current !== null) {
|
|
160
|
+
cancelAnimationFrame(holdRafRef.current);
|
|
161
|
+
holdRafRef.current = null;
|
|
162
|
+
}
|
|
163
|
+
setIsHolding(false);
|
|
164
|
+
setHoldProgress(0);
|
|
165
|
+
}, []);
|
|
166
|
+
// Mic pressed: when hands-free is available, run a hold timer whose ring fills
|
|
167
|
+
// (0→1) over `holdMs`. Completing it activates hands-free; releasing earlier
|
|
168
|
+
// (handleMicPointerUp) falls back to a one-shot recording. Pointer capture
|
|
169
|
+
// keeps the release event on the button even if the finger drifts off.
|
|
170
|
+
const handleMicPointerDown = React.useCallback((e) => {
|
|
171
|
+
if (disabled || isProcessing)
|
|
172
|
+
return;
|
|
173
|
+
try {
|
|
174
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// ignore environments without pointer capture
|
|
178
|
+
}
|
|
179
|
+
const holdMs = speechHandoffHoldMs ?? HANDOFF_HOLD_MS;
|
|
180
|
+
holdFiredRef.current = false;
|
|
181
|
+
setIsHolding(true);
|
|
182
|
+
setHoldProgress(0);
|
|
183
|
+
const startedAt = Date.now();
|
|
184
|
+
const step = () => {
|
|
185
|
+
const progress = Math.min(1, (Date.now() - startedAt) / holdMs);
|
|
186
|
+
setHoldProgress(progress);
|
|
187
|
+
if (progress >= 1) {
|
|
188
|
+
holdRafRef.current = null;
|
|
189
|
+
holdFiredRef.current = true;
|
|
190
|
+
setIsHolding(false);
|
|
191
|
+
setHoldProgress(0);
|
|
192
|
+
startHandsfreeRecording();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
holdRafRef.current = requestAnimationFrame(step);
|
|
196
|
+
};
|
|
197
|
+
holdRafRef.current = requestAnimationFrame(step);
|
|
198
|
+
}, [disabled, isProcessing, speechHandoffHoldMs, startHandsfreeRecording]);
|
|
199
|
+
// Mic released: if the hold already armed hands-free, do nothing; otherwise
|
|
200
|
+
// treat it as a tap and start a one-shot recording.
|
|
201
|
+
const handleMicPointerUp = React.useCallback(() => {
|
|
202
|
+
if (holdFiredRef.current) {
|
|
203
|
+
holdFiredRef.current = false;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (holdRafRef.current === null && !isHolding)
|
|
207
|
+
return; // already aborted
|
|
208
|
+
clearHold();
|
|
209
|
+
startOneShotRecording();
|
|
210
|
+
}, [isHolding, clearHold, startOneShotRecording]);
|
|
211
|
+
// Pointer cancelled (e.g. interrupted touch): abort the hold without recording.
|
|
212
|
+
const handleMicPointerCancel = React.useCallback(() => {
|
|
213
|
+
if (holdFiredRef.current) {
|
|
214
|
+
holdFiredRef.current = false;
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
clearHold();
|
|
218
|
+
}, [clearHold]);
|
|
144
219
|
const cancelRecording = React.useCallback(() => {
|
|
145
220
|
cancelHandoff();
|
|
146
221
|
}, [cancelHandoff]);
|
|
@@ -287,6 +362,8 @@ enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = tru
|
|
|
287
362
|
cancelAnimationFrame(pendingRafRef.current);
|
|
288
363
|
if (inactivityTimerRef.current)
|
|
289
364
|
clearTimeout(inactivityTimerRef.current);
|
|
365
|
+
if (holdRafRef.current !== null)
|
|
366
|
+
cancelAnimationFrame(holdRafRef.current);
|
|
290
367
|
};
|
|
291
368
|
}, []);
|
|
292
369
|
// Handle key press
|
|
@@ -319,7 +396,9 @@ enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = tru
|
|
|
319
396
|
}, []);
|
|
320
397
|
return (jsxRuntime.jsxs("div", { className: "devic-input-area", children: [limitBanner, usageBar, disabledMessage && disabled && (jsxRuntime.jsxs("div", { className: "devic-input-disabled-notice", children: [jsxRuntime.jsx(WaitingIcon, {}), disabledMessage] })), speechError && (jsxRuntime.jsx("div", { className: "devic-speech-error", role: "alert", children: speechError })), handoffActive && (jsxRuntime.jsxs("div", { className: "devic-handoff-bar", "data-waiting": isProcessing ? 'true' : 'false', children: [jsxRuntime.jsx("span", { className: "devic-handoff-dot", "aria-hidden": "true" }), jsxRuntime.jsx("span", { className: "devic-handoff-label", children: isProcessing ? 'Hands-free · waiting for reply' : 'Hands-free on' }), jsxRuntime.jsx("button", { type: "button", className: "devic-handoff-stop", onClick: cancelHandoff, title: "Stop hands-free", "aria-label": "Stop hands-free", children: jsxRuntime.jsx(CloseIcon, {}) })] })), references && references.length > 0 && (jsxRuntime.jsx("div", { className: "devic-reference-chips", children: references.map((ref) => (jsxRuntime.jsxs("div", { className: "devic-reference-chip", title: ref.label, children: [jsxRuntime.jsx(ReferenceIcon, {}), jsxRuntime.jsxs("span", { className: "devic-reference-chip-label", children: ["\"", ref.label, "\""] }), jsxRuntime.jsx("button", { type: "button", className: "devic-reference-chip-remove", onClick: () => onRemoveReference?.(ref.id), "aria-label": "Quitar referencia", children: "\u00D7" })] }, ref.id))) })), files.length > 0 && (jsxRuntime.jsx("div", { className: "devic-file-preview", children: files.map((file, idx) => (jsxRuntime.jsxs("div", { className: "devic-file-preview-item", children: [jsxRuntime.jsx(FileIcon, {}), jsxRuntime.jsx("span", { children: file.name }), jsxRuntime.jsx("button", { className: "devic-file-remove", onClick: () => removeFile(idx), type: "button", children: "\u00D7" })] }, idx))) })), jsxRuntime.jsx("div", { className: "devic-input-wrapper", children: pendingSend ? (jsxRuntime.jsx("div", { className: "devic-speech-panel", "data-state": "pending", children: jsxRuntime.jsxs("div", { className: "devic-handoff-pending", children: [jsxRuntime.jsxs("div", { className: "devic-handoff-pending-icon", children: [jsxRuntime.jsx(SendCountdownRing, { progress: pendingProgress }), jsxRuntime.jsx(SendIcon, {})] }), jsxRuntime.jsxs("div", { className: "devic-handoff-pending-text", children: [jsxRuntime.jsx("span", { className: "devic-handoff-pending-title", children: "Sending\u2026 interact to cancel" }), message.trim() && (jsxRuntime.jsx("span", { className: "devic-handoff-pending-preview", children: message.trim() }))] })] }) })) : isTranscribing ? (jsxRuntime.jsxs("div", { className: "devic-speech-panel", "data-state": "processing", children: [jsxRuntime.jsx("span", { className: "devic-speech-spinner", "aria-hidden": "true" }), jsxRuntime.jsx("span", { className: "devic-speech-status", children: "Transcribing\u2026" })] })) : isRecordingActive ? (jsxRuntime.jsxs("div", { className: "devic-speech-panel", "data-state": "recording", children: [jsxRuntime.jsx("button", { className: "devic-input-btn devic-speech-cancel", onClick: cancelRecording, type: "button", title: "Cancel recording", children: jsxRuntime.jsx(CloseIcon, {}) }), jsxRuntime.jsxs("div", { className: "devic-speech-live", children: [jsxRuntime.jsx(Equalizer, { levels: recording.levels, paused: recording.isPaused }), jsxRuntime.jsx("span", { className: "devic-speech-timer", children: formatDuration(recording.durationMs) })] }), jsxRuntime.jsx("button", { className: "devic-input-btn", onClick: recording.isPaused ? recording.resume : recording.pause, type: "button", title: recording.isPaused ? 'Resume' : 'Pause', children: recording.isPaused ? jsxRuntime.jsx(PlayIcon, {}) : jsxRuntime.jsx(PauseIcon, {}) }), jsxRuntime.jsxs("div", { className: "devic-speech-confirm-wrap", "data-autostop": recording.isAutoStopping ? 'true' : 'false', children: [recording.isAutoStopping && (jsxRuntime.jsx(AutoStopRing, { progress: recording.autoStopProgress })), jsxRuntime.jsx("button", { className: "devic-input-btn devic-speech-confirm", onClick: () => void handleConfirm(), type: "button", title: recording.isAutoStopping
|
|
321
398
|
? 'Auto-sending… keep talking to cancel'
|
|
322
|
-
: 'Confirm', children: jsxRuntime.jsx(CheckIcon, {}) })] })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [enableFileUploads && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: acceptedTypes, multiple: true, onChange: handleFileSelect, style: { display: 'none' } }), jsxRuntime.jsx("button", { className: "devic-input-btn", onClick: () => fileInputRef.current?.click(), disabled: disabled, type: "button", title: "Attach file", children: jsxRuntime.jsx(AttachIcon, {}) })] })), speechEnabled && (jsxRuntime.
|
|
399
|
+
: 'Confirm', children: jsxRuntime.jsx(CheckIcon, {}) })] })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [enableFileUploads && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: acceptedTypes, multiple: true, onChange: handleFileSelect, style: { display: 'none' } }), jsxRuntime.jsx("button", { className: "devic-input-btn", onClick: () => fileInputRef.current?.click(), disabled: disabled, type: "button", title: "Attach file", children: jsxRuntime.jsx(AttachIcon, {}) })] })), speechEnabled && (jsxRuntime.jsxs("div", { className: "devic-speech-mic-wrap", "data-holding": isHolding ? 'true' : 'false', children: [isHolding && jsxRuntime.jsx(HoldRing, { progress: holdProgress }), jsxRuntime.jsx("button", { className: "devic-input-btn devic-speech-mic", onClick: speechHandoff ? undefined : startOneShotRecording, onPointerDown: speechHandoff ? handleMicPointerDown : undefined, onPointerUp: speechHandoff ? handleMicPointerUp : undefined, onPointerCancel: speechHandoff ? handleMicPointerCancel : undefined, disabled: disabled || isProcessing, type: "button", title: speechHandoff
|
|
400
|
+
? 'Tap to dictate · hold to start hands-free'
|
|
401
|
+
: 'Record voice message', children: jsxRuntime.jsx(MicIcon, {}) })] })), jsxRuntime.jsx("textarea", { ref: textareaRef, className: "devic-input", value: message, onChange: (e) => {
|
|
323
402
|
const value = e.target.value;
|
|
324
403
|
setMessage(value);
|
|
325
404
|
// If the user clears the field, drop the transcript link so a fresh
|
|
@@ -359,6 +438,17 @@ function SendCountdownRing({ progress }) {
|
|
|
359
438
|
strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),
|
|
360
439
|
} })] }));
|
|
361
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Filling ring drawn around the mic button while the user presses and holds to
|
|
443
|
+
* arm hands-free. Driven by `progress` (0 → 1): an empty ring that fills
|
|
444
|
+
* clockwise over the hold duration. Inverse of the draining auto-stop ring.
|
|
445
|
+
*/
|
|
446
|
+
function HoldRing({ progress }) {
|
|
447
|
+
return (jsxRuntime.jsxs("svg", { className: "devic-mic-hold-ring", viewBox: "0 0 40 40", "aria-hidden": "true", children: [jsxRuntime.jsx("circle", { className: "devic-mic-hold-ring-track", cx: "20", cy: "20", r: AUTOSTOP_RING_R }), jsxRuntime.jsx("circle", { className: "devic-mic-hold-ring-progress", cx: "20", cy: "20", r: AUTOSTOP_RING_R, style: {
|
|
448
|
+
strokeDasharray: AUTOSTOP_RING_C,
|
|
449
|
+
strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),
|
|
450
|
+
} })] }));
|
|
451
|
+
}
|
|
362
452
|
/** Formats milliseconds as m:ss. */
|
|
363
453
|
function formatDuration(ms) {
|
|
364
454
|
const totalSeconds = Math.floor(ms / 1000);
|