@devicai/ui 0.34.0 → 0.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../../../src/api/types.ts"],"sourcesContent":["import type React from 'react';\n\n/**\n * File attachment for messages\n */\nexport interface ChatFile {\n name: string;\n downloadUrl?: string;\n fileType?: 'image' | 'document' | 'audio' | 'video' | 'other';\n}\n\n/**\n * Attachment as it appears on a message.\n *\n * Two shapes reach the UI for the same thing: the optimistic message built\n * locally on send uses `url`/`type`, while the history returned by the API\n * carries the stored `downloadUrl`/`fileType`. Both are accepted here; use\n * `normalizeMessageFile` before reading them.\n */\nexport interface MessageFile {\n name: string;\n url?: string;\n type?: string;\n downloadUrl?: string;\n fileType?: string;\n}\n\n/**\n * Message content structure\n */\nexport interface MessageContent {\n message?: string;\n data?: any;\n files?: MessageFile[];\n}\n\n/** Collapse either attachment shape into a single one the UI can render. */\nexport function normalizeMessageFile(file: MessageFile): {\n name: string;\n url: string;\n type: string;\n} {\n return {\n name: file.name,\n url: file.url || file.downloadUrl || '',\n type: file.type || file.fileType || 'other',\n };\n}\n\n/**\n * Tool call from the model\n */\nexport interface ToolCall {\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n}\n\n/**\n * Chat message structure\n */\nexport interface ChatMessage {\n uid: string;\n role: 'user' | 'assistant' | 'developer' | 'system' | 'tool';\n content: MessageContent;\n timestamp: number;\n chatUid?: string;\n tool_calls?: ToolCall[];\n tool_call_id?: string;\n summary?: string;\n /**\n * Id of a speech-to-text transcript (from POST /api/v1/whisper) that seeded\n * this message. Present on user messages dictated by voice; the chat can use\n * it to fetch the source audio (GET /api/v1/whisper/:transcriptId) and offer\n * playback.\n */\n transcriptId?: string;\n}\n\n/**\n * Previous conversation message for initialization\n */\nexport interface PreviousMessage {\n message: string;\n role: 'user' | 'assistant';\n}\n\n/**\n * Model interface tool schema following OpenAI function calling format\n */\nexport interface ModelInterfaceToolSchema {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, any>;\n required?: string[];\n };\n };\n}\n\n/**\n * Props passed to a response widget component.\n * The widget is responsible for collecting the user's response and\n * calling `submit` with the payload to resolve the tool call.\n */\nexport interface ResponseWidgetProps {\n /** The tool call this widget is responding to */\n toolCall: ToolCall;\n /** Parsed arguments from the tool call */\n params: any;\n /** Submit the tool response payload (sent as the tool call result to the model) */\n submit: (response: any) => void;\n /** Cancel the tool call. Sends an error response so the model can continue. */\n cancel?: (reason?: string) => void;\n /** Whether the widget is currently submitting */\n isSubmitting?: boolean;\n}\n\n/**\n * Interactive response widget configuration for a client-side tool.\n *\n * When the model calls a tool configured with a `responseWidget`, the\n * widget is rendered in the chat UI instead of executing a callback.\n * The user interacts with the widget, which calls `submit(response)` to\n * define the tool response sent back to the model.\n *\n * - `render: 'inline'` renders the widget in the message thread at the\n * position of the tool call. The text input remains enabled.\n * - `render: 'input'` replaces the chat input area with the widget\n * while it is pending. The text input is disabled until submission.\n */\nexport interface ResponseWidgetConfig {\n /** Where to render the widget */\n render: 'inline' | 'input';\n /** The widget component */\n component: React.ComponentType<ResponseWidgetProps>;\n}\n\n/**\n * Model interface tool definition for client-side tools.\n *\n * A tool must provide either a `callback` (executed automatically when\n * the model invokes the tool) or a `responseWidget` (renders UI for\n * the user to produce the tool response). Providing both is an error.\n */\nexport interface ModelInterfaceTool {\n toolName: string;\n schema: ModelInterfaceToolSchema;\n /** Executed automatically when the model calls this tool */\n callback?: (params: any) => Promise<any> | any;\n /** Interactive widget that collects the user's tool response */\n responseWidget?: ResponseWidgetConfig;\n}\n\n/**\n * Tool call response to send back to the API\n */\nexport interface ToolCallResponse {\n tool_call_id: string;\n content: any;\n role: 'tool';\n}\n\n/**\n * DTO for sending messages to the assistant\n */\nexport interface ProcessMessageDto {\n message: string;\n chatUid?: string;\n userName?: string;\n files?: ChatFile[];\n /** Tags to associate with this chat (top-level, distinct from `metadata`). */\n tags?: string[];\n metadata?: {\n promptTemplateParams?: Record<string, any>;\n tenantToken?: string;\n [key: string]: any;\n };\n tenantId?: string;\n previousConversation?: PreviousMessage[];\n enabledTools?: string[];\n provider?: string;\n model?: string;\n // Model interface protocol fields\n tools?: ModelInterfaceToolSchema[];\n applicationState?: Record<string, any>;\n skipSummarization?: boolean;\n /**\n * Id of a speech-to-text transcript (from POST /api/v1/whisper) that seeded\n * this message. Sent so the conversation keeps a link to the original audio.\n */\n transcriptId?: string;\n}\n\n/**\n * Response from the /whisper speech-to-text endpoint.\n */\nexport interface WhisperTranscriptionResponse {\n /** Public id of the transcript; send it back as ProcessMessageDto.transcriptId. */\n transcriptId: string;\n /** Transcribed text. */\n text: string;\n /** Language hint used, if any. */\n language?: string;\n /** Download URL of the source audio. */\n audioUrl?: string;\n /** Transcription model used. */\n model?: string;\n}\n\n/**\n * Response from the assistant\n */\nexport interface AssistantResponse {\n messages: ChatMessage[];\n chatUid: string;\n inputTokens?: number;\n outputTokens?: number;\n}\n\n/**\n * Async mode response\n */\nexport interface AsyncResponse {\n chatUid: string;\n message?: string;\n error?: string;\n}\n\n/**\n * Real-time chat history status.\n * `limit_exceeded` means the message was blocked before reaching the LLM\n * because a configured tenant/subtenant usage limit was reached.\n */\nexport type RealtimeStatus =\n | 'processing'\n | 'completed'\n | 'error'\n | 'waiting_for_tool_response'\n | 'handed_off'\n | 'limit_exceeded';\n\n/**\n * Details of a tenant/subtenant usage limit that blocked a message.\n * Returned on the realtime endpoint when status is `limit_exceeded`, and on\n * the HTTP 429 body (`details`) when a synchronous request is blocked.\n */\nexport interface TenantLimitExceeded {\n /** Human-readable message describing the block. */\n message?: string;\n /** The rule that triggered the block (scope, metric, window, limit…). */\n blockingRule?: {\n scope?: 'tenant' | 'subtenant';\n subtenantId?: string;\n metric?: 'tokens' | 'cost';\n windowUnit?: 'hour' | 'day' | 'week' | 'month';\n windowEvery?: number;\n limit?: number;\n };\n /** Current consumption in the blocking window. */\n current?: number;\n /** The limit that was reached. */\n limit?: number;\n /** Epoch ms when the blocking window resets and usage is allowed again. */\n resetsAt?: number;\n}\n\n/**\n * Real-time chat history response\n */\nexport interface RealtimeChatHistory {\n chatUID: string;\n clientUID: string;\n chatHistory: ChatMessage[];\n status: RealtimeStatus;\n lastUpdatedAt: number;\n pendingToolCalls?: ToolCall[];\n handedOffSubThreadId?: string;\n /** Present only when status is `limit_exceeded`. */\n limitExceeded?: TenantLimitExceeded;\n}\n\n/**\n * A single usage rule with its current consumption (from GET\n * /api/v1/tenant-usage/:tenantId[/subtenants/:subtenantId]).\n */\nexport interface TenantUsageRule {\n scope: 'tenant' | 'subtenant';\n subtenantId?: string;\n metric: 'tokens' | 'cost';\n windowUnit: 'hour' | 'day' | 'week' | 'month';\n windowEvery: number;\n /** Configured limit for the window. */\n limit: number;\n /** Current consumption in the active window. */\n current: number;\n /** Utilization percentage (0..100, capped). */\n percent: number;\n /** Epoch ms when the active window resets. */\n resetsAt?: number;\n /** Where the rule comes from ('tier' | 'adhoc'). */\n origin?: string;\n /** Tier the rule belongs to, if any. */\n tierId?: string;\n}\n\n/**\n * Response of GET /api/v1/tenant-usage/:tenantId[/subtenants/:subtenantId]:\n * the effective usage rules with their current consumption + the active tier.\n */\nexport interface TenantUsage {\n tenantId: string;\n subtenantId?: string;\n tierId?: string;\n usage: TenantUsageRule[];\n}\n\n/**\n * A durable per-window usage history row (from GET\n * /api/v1/tenant-usage/:tenantId/history).\n */\nexport interface TenantUsageHistoryRow {\n clientUID: string;\n tenantId: string;\n subtenantId: string;\n scope: 'tenant' | 'subtenant';\n metric: 'tokens' | 'cost';\n windowUnit: 'hour' | 'day' | 'week' | 'month';\n windowEvery: number;\n windowKey: string;\n windowStart: number;\n windowEnd: number;\n /** Counted consumption (enforced). */\n consumption: number;\n /** Exempt consumption that did not count toward the limit, if any. */\n exemptConsumption?: number;\n limit: number;\n percent: number;\n tierId?: string;\n origin?: string;\n capturedAt: number;\n}\n\n/**\n * Options for querying tenant usage history.\n */\nexport interface TenantUsageHistoryQuery {\n subtenantId?: string;\n scope?: 'tenant' | 'subtenant';\n metric?: 'tokens' | 'cost';\n windowUnit?: 'hour' | 'day' | 'week' | 'month';\n /** Epoch ms lower bound (windowEnd >= from). */\n from?: number;\n /** Epoch ms upper bound (windowEnd <= to). */\n to?: number;\n limit?: number;\n skip?: number;\n}\n\n/**\n * Chat history structure\n */\nexport interface ChatHistory {\n chatUID: string;\n clientUID: string;\n userUID: string;\n chatContent: ChatMessage[];\n name?: string;\n assistantSpecializationIdentifier: string;\n creationTimestampMs: number;\n lastEditTimestampMs?: number;\n llm?: string;\n inputTokens?: number;\n outputTokens?: number;\n metadata?: Record<string, any>;\n tenantId?: string;\n handedOff?: boolean;\n handedOffSubThreadId?: string;\n handedOffToolCallId?: string;\n}\n\n/**\n * Assistant specialization info\n */\nexport interface AssistantSpecialization {\n identifier: string;\n name: string;\n description: string;\n state: 'active' | 'inactive' | 'coming_soon';\n imgUrl?: string;\n availableToolsGroups?: Array<{\n name: string;\n description?: string;\n uid?: string;\n iconUrl?: string;\n tools?: Array<{\n name: string;\n description: string;\n }>;\n }>;\n model?: string;\n isCustom?: boolean;\n creationTimestampMs?: number;\n}\n\n/**\n * Summary of a conversation for listing\n */\nexport interface ConversationSummary {\n chatUID: string;\n name?: string;\n creationTimestampMs: number;\n lastEditTimestampMs?: number;\n}\n\nexport interface ListConversationsResponse {\n histories: ConversationSummary[];\n total: number;\n offset: number;\n limit: number;\n}\n\n/**\n * API error response\n */\nexport interface ApiError {\n statusCode: number;\n message: string;\n error?: string;\n /** Optional structured details (e.g. usage-limit blocking info on a 429). */\n details?: any;\n}\n\n/**\n * Feedback submission request\n */\nexport interface FeedbackSubmission {\n messageId: string;\n feedback?: boolean;\n feedbackComment?: string;\n feedbackData?: Record<string, any>;\n}\n\n/**\n * Feedback entry response\n */\nexport interface FeedbackEntry {\n _id: string;\n requestId: string;\n chatUID?: string;\n threadId?: string;\n agentId?: string;\n feedback?: boolean;\n feedbackComment?: string;\n feedbackData?: Record<string, any>;\n creationTimestamp: string;\n lastEditTimestamp?: string;\n}\n\n/**\n * Agent thread states\n */\nexport enum AgentThreadState {\n QUEUED = 'queued',\n PROCESSING = 'processing',\n COMPLETED = 'completed',\n FAILED = 'failed',\n TERMINATED = 'terminated',\n PAUSED = 'paused',\n PAUSED_FOR_APPROVAL = 'paused_for_approval',\n APPROVAL_REJECTED = 'approval_rejected',\n WAITING_FOR_RESPONSE = 'waiting_for_response',\n PAUSED_FOR_RESUME = 'paused_for_resume',\n HANDED_OFF = 'handed_off',\n GUARDRAIL_TRIGGER = 'guardrail_trigger',\n}\n\n/**\n * Task within an agent thread\n */\nexport interface AgentTaskDto {\n _id?: string;\n title?: string;\n description?: string;\n completed: boolean;\n}\n\n/**\n * Agent thread DTO\n */\nexport interface AgentThreadDto {\n _id?: string;\n agentId: string;\n state: AgentThreadState;\n threadContent: ChatMessage[];\n tasks?: AgentTaskDto[];\n finishReason?: string;\n pausedReason?: string;\n name?: string;\n creationTimestampMs?: number;\n lastEditTimestampMs?: number;\n pauseUntil?: number;\n isSubthread?: boolean;\n parentThreadId?: string;\n subThreadToolCallId?: string;\n parentAgentId?: string;\n}\n\n/**\n * Agent details\n */\nexport interface AgentDto {\n _id?: string;\n name: string;\n description?: string;\n imgUrl?: string;\n agentId?: string;\n}\n\n/**\n * Hand-off tool response content\n */\nexport interface HandOffToolResponse {\n response: string;\n subthreadId: string;\n}\n\n/**\n * Represents a single tool call within a tool group\n */\nexport interface ToolGroupCall {\n name: string;\n input: any;\n output: any;\n toolCallId: string;\n}\n\n/**\n * Configuration for grouping consecutive tool calls under a single renderer\n */\nexport interface ToolGroupConfig {\n tools: string[];\n renderer: (calls: ToolGroupCall[]) => React.ReactNode;\n}\n"],"names":[],"mappings":"AAoCA;AACM,SAAU,oBAAoB,CAAC,IAAiB,EAAA;IAKpD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,WAAW,IAAI,EAAE;QACvC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,OAAO;KAC5C;AACH;AAkaA;;AAEG;IACS;AAAZ,CAAA,UAAY,gBAAgB,EAAA;AAC1B,IAAA,gBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AACzB,IAAA,gBAAA,CAAA,WAAA,CAAA,GAAA,WAAuB;AACvB,IAAA,gBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AACzB,IAAA,gBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,gBAAA,CAAA,qBAAA,CAAA,GAAA,qBAA2C;AAC3C,IAAA,gBAAA,CAAA,mBAAA,CAAA,GAAA,mBAAuC;AACvC,IAAA,gBAAA,CAAA,sBAAA,CAAA,GAAA,sBAA6C;AAC7C,IAAA,gBAAA,CAAA,mBAAA,CAAA,GAAA,mBAAuC;AACvC,IAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AACzB,IAAA,gBAAA,CAAA,mBAAA,CAAA,GAAA,mBAAuC;AACzC,CAAC,EAbW,gBAAgB,KAAhB,gBAAgB,GAAA,EAAA,CAAA,CAAA;;;;"}
1
+ {"version":3,"file":"types.js","sources":["../../../src/api/types.ts"],"sourcesContent":["import type React from 'react';\n\n/**\n * File attachment for messages\n */\nexport interface ChatFile {\n name: string;\n downloadUrl?: string;\n fileType?: 'image' | 'document' | 'audio' | 'video' | 'other';\n}\n\n/**\n * Attachment as it appears on a message.\n *\n * Two shapes reach the UI for the same thing: the optimistic message built\n * locally on send uses `url`/`type`, while the history returned by the API\n * carries the stored `downloadUrl`/`fileType`. Both are accepted here; use\n * `normalizeMessageFile` before reading them.\n */\nexport interface MessageFile {\n name: string;\n url?: string;\n type?: string;\n downloadUrl?: string;\n fileType?: string;\n}\n\n/**\n * Message content structure\n */\nexport interface MessageContent {\n message?: string;\n data?: any;\n files?: MessageFile[];\n}\n\n/** Collapse either attachment shape into a single one the UI can render. */\nexport function normalizeMessageFile(file: MessageFile): {\n name: string;\n url: string;\n type: string;\n} {\n return {\n name: file.name,\n url: file.url || file.downloadUrl || '',\n type: file.type || file.fileType || 'other',\n };\n}\n\n/**\n * Tool call from the model\n */\nexport interface ToolCall {\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n}\n\n/**\n * Chat message structure\n */\nexport interface ChatMessage {\n uid: string;\n role: 'user' | 'assistant' | 'developer' | 'system' | 'tool';\n content: MessageContent;\n timestamp: number;\n chatUid?: string;\n tool_calls?: ToolCall[];\n tool_call_id?: string;\n summary?: string;\n /**\n * Where `content.message` came from, when the model did not write it.\n * `'finish_tool'`: the assistant is configured to require a tool call to\n * finish (\"Require Tool Use to Finish\") and the backend lifted the reply from\n * the finish tool's `message` argument, so it can be read without parsing\n * tool calls. Absent on replies the model wrote itself — use it to label the\n * bubble as produced by the tool.\n */\n contentSource?: string;\n /**\n * Id of a speech-to-text transcript (from POST /api/v1/whisper) that seeded\n * this message. Present on user messages dictated by voice; the chat can use\n * it to fetch the source audio (GET /api/v1/whisper/:transcriptId) and offer\n * playback.\n */\n transcriptId?: string;\n}\n\n/**\n * Previous conversation message for initialization\n */\nexport interface PreviousMessage {\n message: string;\n role: 'user' | 'assistant';\n}\n\n/**\n * Model interface tool schema following OpenAI function calling format\n */\nexport interface ModelInterfaceToolSchema {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, any>;\n required?: string[];\n };\n };\n}\n\n/**\n * Props passed to a response widget component.\n * The widget is responsible for collecting the user's response and\n * calling `submit` with the payload to resolve the tool call.\n */\nexport interface ResponseWidgetProps {\n /** The tool call this widget is responding to */\n toolCall: ToolCall;\n /** Parsed arguments from the tool call */\n params: any;\n /** Submit the tool response payload (sent as the tool call result to the model) */\n submit: (response: any) => void;\n /** Cancel the tool call. Sends an error response so the model can continue. */\n cancel?: (reason?: string) => void;\n /** Whether the widget is currently submitting */\n isSubmitting?: boolean;\n}\n\n/**\n * Interactive response widget configuration for a client-side tool.\n *\n * When the model calls a tool configured with a `responseWidget`, the\n * widget is rendered in the chat UI instead of executing a callback.\n * The user interacts with the widget, which calls `submit(response)` to\n * define the tool response sent back to the model.\n *\n * - `render: 'inline'` renders the widget in the message thread at the\n * position of the tool call. The text input remains enabled.\n * - `render: 'input'` replaces the chat input area with the widget\n * while it is pending. The text input is disabled until submission.\n */\nexport interface ResponseWidgetConfig {\n /** Where to render the widget */\n render: 'inline' | 'input';\n /** The widget component */\n component: React.ComponentType<ResponseWidgetProps>;\n}\n\n/**\n * Model interface tool definition for client-side tools.\n *\n * A tool must provide either a `callback` (executed automatically when\n * the model invokes the tool) or a `responseWidget` (renders UI for\n * the user to produce the tool response). Providing both is an error.\n */\nexport interface ModelInterfaceTool {\n toolName: string;\n schema: ModelInterfaceToolSchema;\n /** Executed automatically when the model calls this tool */\n callback?: (params: any) => Promise<any> | any;\n /** Interactive widget that collects the user's tool response */\n responseWidget?: ResponseWidgetConfig;\n}\n\n/**\n * Tool call response to send back to the API\n */\nexport interface ToolCallResponse {\n tool_call_id: string;\n content: any;\n role: 'tool';\n}\n\n/**\n * DTO for sending messages to the assistant\n */\nexport interface ProcessMessageDto {\n message: string;\n chatUid?: string;\n userName?: string;\n files?: ChatFile[];\n /** Tags to associate with this chat (top-level, distinct from `metadata`). */\n tags?: string[];\n metadata?: {\n promptTemplateParams?: Record<string, any>;\n tenantToken?: string;\n [key: string]: any;\n };\n tenantId?: string;\n previousConversation?: PreviousMessage[];\n enabledTools?: string[];\n provider?: string;\n model?: string;\n // Model interface protocol fields\n tools?: ModelInterfaceToolSchema[];\n applicationState?: Record<string, any>;\n skipSummarization?: boolean;\n /**\n * Id of a speech-to-text transcript (from POST /api/v1/whisper) that seeded\n * this message. Sent so the conversation keeps a link to the original audio.\n */\n transcriptId?: string;\n}\n\n/**\n * Response from the /whisper speech-to-text endpoint.\n */\nexport interface WhisperTranscriptionResponse {\n /** Public id of the transcript; send it back as ProcessMessageDto.transcriptId. */\n transcriptId: string;\n /** Transcribed text. */\n text: string;\n /** Language hint used, if any. */\n language?: string;\n /** Download URL of the source audio. */\n audioUrl?: string;\n /** Transcription model used. */\n model?: string;\n}\n\n/**\n * Response from the assistant\n */\nexport interface AssistantResponse {\n messages: ChatMessage[];\n chatUid: string;\n inputTokens?: number;\n outputTokens?: number;\n}\n\n/**\n * Async mode response\n */\nexport interface AsyncResponse {\n chatUid: string;\n message?: string;\n error?: string;\n}\n\n/**\n * Real-time chat history status.\n * `limit_exceeded` means the message was blocked before reaching the LLM\n * because a configured tenant/subtenant usage limit was reached.\n */\nexport type RealtimeStatus =\n | 'processing'\n | 'completed'\n | 'error'\n | 'waiting_for_tool_response'\n | 'handed_off'\n | 'limit_exceeded';\n\n/**\n * Details of a tenant/subtenant usage limit that blocked a message.\n * Returned on the realtime endpoint when status is `limit_exceeded`, and on\n * the HTTP 429 body (`details`) when a synchronous request is blocked.\n */\nexport interface TenantLimitExceeded {\n /** Human-readable message describing the block. */\n message?: string;\n /** The rule that triggered the block (scope, metric, window, limit…). */\n blockingRule?: {\n scope?: 'tenant' | 'subtenant';\n subtenantId?: string;\n metric?: 'tokens' | 'cost';\n windowUnit?: 'hour' | 'day' | 'week' | 'month';\n windowEvery?: number;\n limit?: number;\n };\n /** Current consumption in the blocking window. */\n current?: number;\n /** The limit that was reached. */\n limit?: number;\n /** Epoch ms when the blocking window resets and usage is allowed again. */\n resetsAt?: number;\n}\n\n/**\n * Real-time chat history response\n */\nexport interface RealtimeChatHistory {\n chatUID: string;\n clientUID: string;\n chatHistory: ChatMessage[];\n status: RealtimeStatus;\n lastUpdatedAt: number;\n pendingToolCalls?: ToolCall[];\n handedOffSubThreadId?: string;\n /** Present only when status is `limit_exceeded`. */\n limitExceeded?: TenantLimitExceeded;\n}\n\n/**\n * A single usage rule with its current consumption (from GET\n * /api/v1/tenant-usage/:tenantId[/subtenants/:subtenantId]).\n */\nexport interface TenantUsageRule {\n scope: 'tenant' | 'subtenant';\n subtenantId?: string;\n metric: 'tokens' | 'cost';\n windowUnit: 'hour' | 'day' | 'week' | 'month';\n windowEvery: number;\n /** Configured limit for the window. */\n limit: number;\n /** Current consumption in the active window. */\n current: number;\n /** Utilization percentage (0..100, capped). */\n percent: number;\n /** Epoch ms when the active window resets. */\n resetsAt?: number;\n /** Where the rule comes from ('tier' | 'adhoc'). */\n origin?: string;\n /** Tier the rule belongs to, if any. */\n tierId?: string;\n}\n\n/**\n * Response of GET /api/v1/tenant-usage/:tenantId[/subtenants/:subtenantId]:\n * the effective usage rules with their current consumption + the active tier.\n */\nexport interface TenantUsage {\n tenantId: string;\n subtenantId?: string;\n tierId?: string;\n usage: TenantUsageRule[];\n}\n\n/**\n * A durable per-window usage history row (from GET\n * /api/v1/tenant-usage/:tenantId/history).\n */\nexport interface TenantUsageHistoryRow {\n clientUID: string;\n tenantId: string;\n subtenantId: string;\n scope: 'tenant' | 'subtenant';\n metric: 'tokens' | 'cost';\n windowUnit: 'hour' | 'day' | 'week' | 'month';\n windowEvery: number;\n windowKey: string;\n windowStart: number;\n windowEnd: number;\n /** Counted consumption (enforced). */\n consumption: number;\n /** Exempt consumption that did not count toward the limit, if any. */\n exemptConsumption?: number;\n limit: number;\n percent: number;\n tierId?: string;\n origin?: string;\n capturedAt: number;\n}\n\n/**\n * Options for querying tenant usage history.\n */\nexport interface TenantUsageHistoryQuery {\n subtenantId?: string;\n scope?: 'tenant' | 'subtenant';\n metric?: 'tokens' | 'cost';\n windowUnit?: 'hour' | 'day' | 'week' | 'month';\n /** Epoch ms lower bound (windowEnd >= from). */\n from?: number;\n /** Epoch ms upper bound (windowEnd <= to). */\n to?: number;\n limit?: number;\n skip?: number;\n}\n\n/**\n * Chat history structure\n */\nexport interface ChatHistory {\n chatUID: string;\n clientUID: string;\n userUID: string;\n chatContent: ChatMessage[];\n name?: string;\n assistantSpecializationIdentifier: string;\n creationTimestampMs: number;\n lastEditTimestampMs?: number;\n llm?: string;\n inputTokens?: number;\n outputTokens?: number;\n metadata?: Record<string, any>;\n tenantId?: string;\n handedOff?: boolean;\n handedOffSubThreadId?: string;\n handedOffToolCallId?: string;\n}\n\n/**\n * Assistant specialization info\n */\nexport interface AssistantSpecialization {\n identifier: string;\n name: string;\n description: string;\n state: 'active' | 'inactive' | 'coming_soon';\n imgUrl?: string;\n availableToolsGroups?: Array<{\n name: string;\n description?: string;\n uid?: string;\n iconUrl?: string;\n tools?: Array<{\n name: string;\n description: string;\n }>;\n }>;\n model?: string;\n isCustom?: boolean;\n creationTimestampMs?: number;\n}\n\n/**\n * Summary of a conversation for listing\n */\nexport interface ConversationSummary {\n chatUID: string;\n name?: string;\n creationTimestampMs: number;\n lastEditTimestampMs?: number;\n}\n\nexport interface ListConversationsResponse {\n histories: ConversationSummary[];\n total: number;\n offset: number;\n limit: number;\n}\n\n/**\n * API error response\n */\nexport interface ApiError {\n statusCode: number;\n message: string;\n error?: string;\n /** Optional structured details (e.g. usage-limit blocking info on a 429). */\n details?: any;\n}\n\n/**\n * Feedback submission request\n */\nexport interface FeedbackSubmission {\n messageId: string;\n feedback?: boolean;\n feedbackComment?: string;\n feedbackData?: Record<string, any>;\n}\n\n/**\n * Feedback entry response\n */\nexport interface FeedbackEntry {\n _id: string;\n requestId: string;\n chatUID?: string;\n threadId?: string;\n agentId?: string;\n feedback?: boolean;\n feedbackComment?: string;\n feedbackData?: Record<string, any>;\n creationTimestamp: string;\n lastEditTimestamp?: string;\n}\n\n/**\n * Agent thread states\n */\nexport enum AgentThreadState {\n QUEUED = 'queued',\n PROCESSING = 'processing',\n COMPLETED = 'completed',\n FAILED = 'failed',\n TERMINATED = 'terminated',\n PAUSED = 'paused',\n PAUSED_FOR_APPROVAL = 'paused_for_approval',\n APPROVAL_REJECTED = 'approval_rejected',\n WAITING_FOR_RESPONSE = 'waiting_for_response',\n PAUSED_FOR_RESUME = 'paused_for_resume',\n HANDED_OFF = 'handed_off',\n GUARDRAIL_TRIGGER = 'guardrail_trigger',\n}\n\n/**\n * Task within an agent thread\n */\nexport interface AgentTaskDto {\n _id?: string;\n title?: string;\n description?: string;\n completed: boolean;\n}\n\n/**\n * Agent thread DTO\n */\nexport interface AgentThreadDto {\n _id?: string;\n agentId: string;\n state: AgentThreadState;\n threadContent: ChatMessage[];\n tasks?: AgentTaskDto[];\n finishReason?: string;\n pausedReason?: string;\n name?: string;\n creationTimestampMs?: number;\n lastEditTimestampMs?: number;\n pauseUntil?: number;\n isSubthread?: boolean;\n parentThreadId?: string;\n subThreadToolCallId?: string;\n parentAgentId?: string;\n}\n\n/**\n * Agent details\n */\nexport interface AgentDto {\n _id?: string;\n name: string;\n description?: string;\n imgUrl?: string;\n agentId?: string;\n}\n\n/**\n * Hand-off tool response content\n */\nexport interface HandOffToolResponse {\n response: string;\n subthreadId: string;\n}\n\n/**\n * Represents a single tool call within a tool group\n */\nexport interface ToolGroupCall {\n name: string;\n input: any;\n output: any;\n toolCallId: string;\n}\n\n/**\n * Configuration for grouping consecutive tool calls under a single renderer\n */\nexport interface ToolGroupConfig {\n tools: string[];\n renderer: (calls: ToolGroupCall[]) => React.ReactNode;\n}\n"],"names":[],"mappings":"AAoCA;AACM,SAAU,oBAAoB,CAAC,IAAiB,EAAA;IAKpD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,WAAW,IAAI,EAAE;QACvC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,OAAO;KAC5C;AACH;AA2aA;;AAEG;IACS;AAAZ,CAAA,UAAY,gBAAgB,EAAA;AAC1B,IAAA,gBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AACzB,IAAA,gBAAA,CAAA,WAAA,CAAA,GAAA,WAAuB;AACvB,IAAA,gBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AACzB,IAAA,gBAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,gBAAA,CAAA,qBAAA,CAAA,GAAA,qBAA2C;AAC3C,IAAA,gBAAA,CAAA,mBAAA,CAAA,GAAA,mBAAuC;AACvC,IAAA,gBAAA,CAAA,sBAAA,CAAA,GAAA,sBAA6C;AAC7C,IAAA,gBAAA,CAAA,mBAAA,CAAA,GAAA,mBAAuC;AACvC,IAAA,gBAAA,CAAA,YAAA,CAAA,GAAA,YAAyB;AACzB,IAAA,gBAAA,CAAA,mBAAA,CAAA,GAAA,mBAAuC;AACzC,CAAC,EAbW,gBAAgB,KAAhB,gBAAgB,GAAA,EAAA,CAAA,CAAA;;;;"}
@@ -1,6 +1,16 @@
1
1
  import type { ChatInputProps } from './ChatDrawer.types';
2
2
  /**
3
- * Chat input component with file upload support
3
+ * Chat input component with file upload support.
4
+ *
5
+ * When a widget is pending as 'input' it replaces the whole input area. The swap
6
+ * lives here, in a component with no hooks of its own, so that each subtree is
7
+ * mounted and unmounted whole. Returning the widget from inside ChatInputBox
8
+ * instead would skip every hook below the early return, which violates the rules
9
+ * of hooks (and is what react-hooks/rules-of-hooks flags). React tolerates that
10
+ * particular shape today — its "fewer hooks than expected" check only fires once
11
+ * at least one hook has run — so it is a latent fragility rather than a crash,
12
+ * but the toggle is on the hot path for interactive widgets and does not need to
13
+ * depend on that internal detail. Draft text in the textarea is dropped on the
14
+ * swap, same as before.
4
15
  */
5
- export declare function ChatInput({ onSend, disabled, placeholder, enableFileUploads, allowedFileTypes, maxFileSize, // 10MB
6
- enableLongTextPaste, longTextPasteThreshold, enableSpeechToText, speechLanguage, speechTenantId, speechAutoStop, speechAutoStopCountdownMs, speechAutoStopSilenceMs, speechAutoStopSilenceRatio, speechAutoStopSilenceLevel, speechAutoStopSpeechLevel, speechHandoff, speechHandoffSendDelayMs, speechHandoffHoldMs, apiKey, baseUrl, sendButtonContent, disabledMessage, isProcessing, onStop, stopButtonContent, pendingInputWidget, onSubmitWidget, onCancelWidget, references, onRemoveReference, usageBar, limitBanner, }: ChatInputProps): JSX.Element;
16
+ export declare function ChatInput(props: ChatInputProps): JSX.Element;
@@ -30,15 +30,29 @@ const HANDOFF_PENDING_MS = 1000; // default cancellable countdown before auto-se
30
30
  const HANDOFF_INACTIVITY_MS = 6000; // silence (no speech) that ends the loop
31
31
  const HANDOFF_HOLD_MS = 3000; // press-and-hold duration on the mic to arm hands-free
32
32
  /**
33
- * Chat input component with file upload support
33
+ * Chat input component with file upload support.
34
+ *
35
+ * When a widget is pending as 'input' it replaces the whole input area. The swap
36
+ * lives here, in a component with no hooks of its own, so that each subtree is
37
+ * mounted and unmounted whole. Returning the widget from inside ChatInputBox
38
+ * instead would skip every hook below the early return, which violates the rules
39
+ * of hooks (and is what react-hooks/rules-of-hooks flags). React tolerates that
40
+ * particular shape today — its "fewer hooks than expected" check only fires once
41
+ * at least one hook has run — so it is a latent fragility rather than a crash,
42
+ * but the toggle is on the hot path for interactive widgets and does not need to
43
+ * depend on that internal detail. Draft text in the textarea is dropped on the
44
+ * swap, same as before.
34
45
  */
35
- function ChatInput({ onSend, disabled = false, placeholder = 'Type a message...', enableFileUploads = false, allowedFileTypes = { images: true, documents: true }, maxFileSize = 10 * 1024 * 1024, // 10MB
36
- enableLongTextPaste = false, longTextPasteThreshold = 2000, 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, }) {
37
- // When a widget is pending as 'input', render it in place of the textarea
46
+ function ChatInput(props) {
47
+ const { pendingInputWidget, onSubmitWidget, onCancelWidget } = props;
38
48
  if (pendingInputWidget) {
39
49
  const WidgetComponent = pendingInputWidget.widget.component;
40
50
  return (jsx("div", { className: "devic-input-area", "data-widget-mode": "input", children: jsx("div", { className: "devic-input-widget", "data-tool-name": pendingInputWidget.toolName, children: jsx(WidgetComponent, { toolCall: pendingInputWidget.toolCall, params: pendingInputWidget.params, submit: (response) => onSubmitWidget?.(pendingInputWidget.toolCall.id, response), cancel: (reason) => onCancelWidget?.(pendingInputWidget.toolCall.id, reason) }) }) }));
41
51
  }
52
+ return jsx(ChatInputBox, { ...props });
53
+ }
54
+ function ChatInputBox({ onSend, disabled = false, placeholder = 'Type a message...', enableFileUploads = false, allowedFileTypes = { images: true, documents: true }, maxFileSize = 10 * 1024 * 1024, // 10MB
55
+ enableLongTextPaste = false, longTextPasteThreshold = 2000, enableSpeechToText = false, speechLanguage, speechTenantId, speechAutoStop = true, speechAutoStopCountdownMs, speechAutoStopSilenceMs, speechAutoStopSilenceRatio, speechAutoStopSilenceLevel, speechAutoStopSpeechLevel, speechHandoff = false, speechHandoffSendDelayMs, speechHandoffHoldMs, apiKey, baseUrl, sendButtonContent, disabledMessage, isProcessing = false, onStop, stopButtonContent, references, onRemoveReference, usageBar, limitBanner, }) {
42
56
  const [message, setMessage] = useState('');
43
57
  const [files, setFiles] = useState([]);
44
58
  // Long blocks of pasted text, kept out of the textarea and shown as cards.
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInput.js","sources":["../../../../src/components/ChatDrawer/ChatInput.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';\nimport type { ChatInputProps } from './ChatDrawer.types';\nimport { useSpeechRecording } from '../../hooks/useSpeechRecording';\nimport { DevicApiClient } from '../../api/client';\nimport { ReferenceChip } from './ReferenceChip';\nimport {\n toPastedBlock,\n pastedPreview,\n pastedLineCount,\n type PastedText,\n} from './pastedText';\n\nconst FILE_TYPE_ACCEPT: Record<string, string[]> = {\n images: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],\n documents: [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'text/plain',\n 'text/csv',\n ],\n audio: ['audio/mpeg', 'audio/wav', 'audio/ogg'],\n video: ['video/mp4', 'video/webm', 'video/ogg'],\n};\n\n// Extensions used to name images pasted from the clipboard, which arrive with a\n// generic name (\"image.png\") or none at all.\nconst IMAGE_EXT_BY_MIME: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/gif': 'gif',\n 'image/webp': 'webp',\n};\n\n// Handoff (hands-free) loop timings.\nconst HANDOFF_PENDING_MS = 1000; // default cancellable countdown before auto-send\nconst HANDOFF_INACTIVITY_MS = 6000; // silence (no speech) that ends the loop\nconst HANDOFF_HOLD_MS = 3000; // press-and-hold duration on the mic to arm hands-free\n\n/**\n * Chat input component with file upload support\n */\nexport function ChatInput({\n onSend,\n disabled = false,\n placeholder = 'Type a message...',\n enableFileUploads = false,\n allowedFileTypes = { images: true, documents: true },\n maxFileSize = 10 * 1024 * 1024, // 10MB\n enableLongTextPaste = false,\n longTextPasteThreshold = 2000,\n enableSpeechToText = false,\n speechLanguage,\n speechTenantId,\n speechAutoStop = true,\n speechAutoStopCountdownMs,\n speechAutoStopSilenceMs,\n speechAutoStopSilenceRatio,\n speechAutoStopSilenceLevel,\n speechAutoStopSpeechLevel,\n speechHandoff = false,\n speechHandoffSendDelayMs,\n speechHandoffHoldMs,\n apiKey,\n baseUrl,\n sendButtonContent,\n disabledMessage,\n isProcessing = false,\n onStop,\n stopButtonContent,\n pendingInputWidget,\n onSubmitWidget,\n onCancelWidget,\n references,\n onRemoveReference,\n usageBar,\n limitBanner,\n}: ChatInputProps): JSX.Element {\n // When a widget is pending as 'input', render it in place of the textarea\n if (pendingInputWidget) {\n const WidgetComponent = pendingInputWidget.widget.component;\n return (\n <div className=\"devic-input-area\" data-widget-mode=\"input\">\n <div className=\"devic-input-widget\" data-tool-name={pendingInputWidget.toolName}>\n <WidgetComponent\n toolCall={pendingInputWidget.toolCall}\n params={pendingInputWidget.params}\n submit={(response) => onSubmitWidget?.(pendingInputWidget.toolCall.id, response)}\n cancel={(reason) => onCancelWidget?.(pendingInputWidget.toolCall.id, reason)}\n />\n </div>\n </div>\n );\n }\n const [message, setMessage] = useState('');\n const [files, setFiles] = useState<File[]>([]);\n // Long blocks of pasted text, kept out of the textarea and shown as cards.\n const [pastedTexts, setPastedTexts] = useState<PastedText[]>([]);\n const [isDraggingOver, setIsDraggingOver] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n // Monotonic counters so pasted images and text blocks get stable, unique ids.\n const pasteCounterRef = useRef(0);\n // Nested dragenter/dragleave events fire per child node; count them so the\n // overlay only clears when the pointer truly leaves the input area.\n const dragDepthRef = useRef(0);\n\n // Speech-to-text state\n const [transcriptId, setTranscriptId] = useState<string | undefined>();\n const [isTranscribing, setIsTranscribing] = useState(false);\n const [speechError, setSpeechError] = useState<string | null>(null);\n // Holds the latest confirmRecording so the auto-stop callback (created before\n // confirmRecording is defined) always calls the current closure.\n const confirmRef = useRef<() => void>(() => {});\n const recording = useSpeechRecording({\n bars: 5,\n autoStop: speechAutoStop,\n ...(speechAutoStopCountdownMs != null && {\n autoStopCountdownMs: speechAutoStopCountdownMs,\n }),\n ...(speechAutoStopSilenceMs != null && {\n autoStopSilenceMs: speechAutoStopSilenceMs,\n }),\n ...(speechAutoStopSilenceRatio != null && {\n autoStopSilenceRatio: speechAutoStopSilenceRatio,\n }),\n ...(speechAutoStopSilenceLevel != null && {\n autoStopSilenceLevel: speechAutoStopSilenceLevel,\n }),\n ...(speechAutoStopSpeechLevel != null && {\n autoStopSpeechLevel: speechAutoStopSpeechLevel,\n }),\n onAutoStop: () => confirmRef.current(),\n });\n\n // --- Handoff (hands-free loop) state ---\n const [handoffActive, setHandoffActive] = useState(false);\n const [pendingSend, setPendingSend] = useState(false);\n const [pendingProgress, setPendingProgress] = useState(1);\n // Ref mirror so async callbacks (rAF, timers, document listeners) read the\n // live value without going stale.\n const handoffActiveRef = useRef(false);\n const pendingRafRef = useRef<number | null>(null);\n const inactivityTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const prevProcessingRef = useRef(isProcessing);\n // Always-fresh send fn so the deferred auto-send uses the latest message.\n const handleSendRef = useRef<() => void>(() => {});\n\n // --- Press-and-hold to arm hands-free ---\n // Holding the mic for `holdMs` fills a ring (0→1) and activates hands-free;\n // releasing earlier falls back to a single one-shot recording.\n const [holdProgress, setHoldProgress] = useState(0);\n const [isHolding, setIsHolding] = useState(false);\n const holdRafRef = useRef<number | null>(null);\n const holdFiredRef = useRef(false);\n\n // Client used only for the /whisper transcription call.\n const transcribeClient = useMemo(() => {\n if (!enableSpeechToText || !apiKey) return null;\n return new DevicApiClient({\n apiKey,\n baseUrl: baseUrl || 'https://api.devic.ai',\n });\n }, [enableSpeechToText, apiKey, baseUrl]);\n\n const speechEnabled =\n enableSpeechToText && recording.isSupported && !!transcribeClient;\n const isRecordingActive = recording.isRecording || recording.isPaused;\n\n // Calculate accepted file types\n const acceptedTypeList = useMemo(\n () =>\n Object.entries(allowedFileTypes)\n .filter(([, enabled]) => enabled)\n .flatMap(([type]) => FILE_TYPE_ACCEPT[type] || []),\n [allowedFileTypes]\n );\n const acceptedTypes = acceptedTypeList.join(',');\n\n // Single entry point for every way of attaching a file (button, paste, drop):\n // enforces the size limit and the allowed MIME types, which until now were\n // only hinted at the native file dialog and never actually checked.\n const addFiles = useCallback(\n (incoming: File[]) => {\n const validFiles = incoming.filter((file) => {\n if (file.size > maxFileSize) {\n console.warn(`File ${file.name} exceeds maximum size`);\n return false;\n }\n if (acceptedTypeList.length > 0 && !acceptedTypeList.includes(file.type)) {\n console.warn(`File type ${file.type || 'unknown'} is not allowed`);\n return false;\n }\n return true;\n });\n if (validFiles.length > 0) setFiles((prev) => [...prev, ...validFiles]);\n },\n [maxFileSize, acceptedTypeList]\n );\n\n // Thumbnails for attached images. The cleanup revokes the previous batch on\n // every change (and on unmount), so the object URLs never leak.\n const filePreviews = useMemo(\n () =>\n files.map((file) =>\n file.type.startsWith('image/') ? URL.createObjectURL(file) : null\n ),\n [files]\n );\n useEffect(\n () => () => {\n filePreviews.forEach((url) => url && URL.revokeObjectURL(url));\n },\n [filePreviews]\n );\n\n // Auto-resize textarea\n const handleInput = useCallback(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n }\n }, []);\n\n // Handle send\n const handleSend = useCallback(() => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage && files.length === 0 && pastedTexts.length === 0) return;\n\n // Pasted text is shown as a card but still reaches the model in full: each\n // block is prepended to the message inside a delimiter the thread can parse\n // back out (see parsePastedBlocks in ChatMessages).\n const composedMessage =\n pastedTexts.length > 0\n ? [...pastedTexts.map(toPastedBlock), trimmedMessage]\n .filter(Boolean)\n .join('\\n\\n')\n : trimmedMessage;\n\n onSend(\n composedMessage,\n files.length > 0 ? files : undefined,\n transcriptId ? { transcriptId } : undefined,\n );\n setMessage('');\n setFiles([]);\n setPastedTexts([]);\n setTranscriptId(undefined);\n\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n }\n }, [message, files, pastedTexts, onSend, transcriptId]);\n // Keep a fresh send fn for the deferred handoff auto-send.\n handleSendRef.current = handleSend;\n\n // --- Speech-to-text handlers ---\n\n const clearPending = useCallback(() => {\n if (pendingRafRef.current !== null) {\n cancelAnimationFrame(pendingRafRef.current);\n pendingRafRef.current = null;\n }\n setPendingSend(false);\n setPendingProgress(1);\n }, []);\n\n // Fully exit the hands-free loop and stop any recording in progress.\n const cancelHandoff = useCallback(() => {\n handoffActiveRef.current = false;\n setHandoffActive(false);\n clearPending();\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current);\n inactivityTimerRef.current = null;\n }\n recording.cancel();\n }, [clearPending, recording]);\n\n // One-shot recording: transcribe → fill the textarea for manual review/send.\n // No hands-free loop, so the textarea stays available afterwards.\n const startOneShotRecording = useCallback(() => {\n setSpeechError(null);\n void recording.start();\n }, [recording]);\n\n // Arm the hands-free loop and start listening.\n const startHandsfreeRecording = useCallback(() => {\n setSpeechError(null);\n handoffActiveRef.current = true;\n setHandoffActive(true);\n void recording.start();\n }, [recording]);\n\n // Stop and reset the press-and-hold progress loop.\n const clearHold = useCallback(() => {\n if (holdRafRef.current !== null) {\n cancelAnimationFrame(holdRafRef.current);\n holdRafRef.current = null;\n }\n setIsHolding(false);\n setHoldProgress(0);\n }, []);\n\n // Mic pressed: when hands-free is available, run a hold timer whose ring fills\n // (0→1) over `holdMs`. Completing it activates hands-free; releasing earlier\n // (handleMicPointerUp) falls back to a one-shot recording. Pointer capture\n // keeps the release event on the button even if the finger drifts off.\n const handleMicPointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (disabled || isProcessing) return;\n try {\n e.currentTarget.setPointerCapture(e.pointerId);\n } catch {\n // ignore environments without pointer capture\n }\n const holdMs = speechHandoffHoldMs ?? HANDOFF_HOLD_MS;\n holdFiredRef.current = false;\n setIsHolding(true);\n setHoldProgress(0);\n const startedAt = Date.now();\n const step = () => {\n const progress = Math.min(1, (Date.now() - startedAt) / holdMs);\n setHoldProgress(progress);\n if (progress >= 1) {\n holdRafRef.current = null;\n holdFiredRef.current = true;\n setIsHolding(false);\n setHoldProgress(0);\n startHandsfreeRecording();\n return;\n }\n holdRafRef.current = requestAnimationFrame(step);\n };\n holdRafRef.current = requestAnimationFrame(step);\n },\n [disabled, isProcessing, speechHandoffHoldMs, startHandsfreeRecording],\n );\n\n // Mic released: if the hold already armed hands-free, do nothing; otherwise\n // treat it as a tap and start a one-shot recording.\n const handleMicPointerUp = useCallback(() => {\n if (holdFiredRef.current) {\n holdFiredRef.current = false;\n return;\n }\n if (holdRafRef.current === null && !isHolding) return; // already aborted\n clearHold();\n startOneShotRecording();\n }, [isHolding, clearHold, startOneShotRecording]);\n\n // Pointer cancelled (e.g. interrupted touch): abort the hold without recording.\n const handleMicPointerCancel = useCallback(() => {\n if (holdFiredRef.current) {\n holdFiredRef.current = false;\n return;\n }\n clearHold();\n }, [clearHold]);\n\n const cancelRecording = useCallback(() => {\n cancelHandoff();\n }, [cancelHandoff]);\n\n // Stop recording, transcribe the audio and fill the input for review.\n // Returns the trimmed transcription (or null if nothing was transcribed) so\n // the handoff loop can decide whether to auto-send or end.\n const confirmRecording = useCallback(async (): Promise<string | null> => {\n if (!transcribeClient) return null;\n const blob = await recording.stop();\n if (!blob || blob.size === 0) return null;\n\n setIsTranscribing(true);\n setSpeechError(null);\n try {\n const result = await transcribeClient.transcribeAudio(blob, {\n language: speechLanguage,\n tenantId: speechTenantId,\n });\n const text = (result.text || '').trim();\n if (text) {\n setMessage((prev) => (prev ? `${prev} ${text}`.trim() : text));\n setTranscriptId(result.transcriptId);\n }\n // Resize textarea and focus for review/edit.\n requestAnimationFrame(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n textarea.focus();\n }\n });\n return text;\n } catch (e) {\n setSpeechError(\n `Could not transcribe the audio: ${(e as Error)?.message || 'unknown error'}`,\n );\n return null;\n } finally {\n setIsTranscribing(false);\n }\n }, [transcribeClient, recording, speechLanguage, speechTenantId]);\n\n // Cancellable countdown, then auto-send. Handoff stays active across the send\n // so the loop can continue after the assistant replies.\n const startPendingSend = useCallback(() => {\n const totalMs = speechHandoffSendDelayMs ?? HANDOFF_PENDING_MS;\n setPendingSend(true);\n setPendingProgress(1);\n const startedAt = Date.now();\n const step = () => {\n const elapsed = Date.now() - startedAt;\n setPendingProgress(Math.max(0, 1 - elapsed / totalMs));\n if (elapsed >= totalMs) {\n pendingRafRef.current = null;\n setPendingSend(false);\n setPendingProgress(1);\n handleSendRef.current(); // auto-send with the freshest message\n return;\n }\n pendingRafRef.current = requestAnimationFrame(step);\n };\n pendingRafRef.current = requestAnimationFrame(step);\n }, [speechHandoffSendDelayMs]);\n\n // Drives both the mic auto-stop and the manual confirm button, branching on\n // whether the hands-free loop is active.\n const handleConfirm = useCallback(async () => {\n const text = await confirmRecording();\n if (!handoffActiveRef.current) return; // normal mode: input already filled\n if (!text) {\n // Silent / empty turn → end the hands-free loop.\n cancelHandoff();\n setMessage('');\n setTranscriptId(undefined);\n return;\n }\n startPendingSend();\n }, [confirmRecording, cancelHandoff, startPendingSend]);\n\n // Auto-stop fires handleConfirm with the freshest closure.\n useEffect(() => {\n confirmRef.current = () => void handleConfirm();\n }, [handleConfirm]);\n\n // Any interaction during the pending countdown cancels the auto-send and\n // exits the loop (the user is taking manual control); text stays for editing.\n useEffect(() => {\n if (!pendingSend) return;\n const onInteract = () => {\n clearPending();\n handoffActiveRef.current = false;\n setHandoffActive(false);\n requestAnimationFrame(() => textareaRef.current?.focus());\n };\n document.addEventListener('mousedown', onInteract, true);\n document.addEventListener('keydown', onInteract, true);\n return () => {\n document.removeEventListener('mousedown', onInteract, true);\n document.removeEventListener('keydown', onInteract, true);\n };\n }, [pendingSend, clearPending]);\n\n // When the assistant finishes (isProcessing falls) while the loop is active,\n // re-activate listening for the next turn.\n useEffect(() => {\n const wasProcessing = prevProcessingRef.current;\n prevProcessingRef.current = isProcessing;\n if (\n handoffActive &&\n wasProcessing &&\n !isProcessing &&\n !disabled &&\n !pendingSend &&\n !isTranscribing &&\n !recording.isRecording &&\n !recording.isPaused\n ) {\n void recording.start();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isProcessing, handoffActive, disabled, pendingSend, isTranscribing]);\n\n // While listening in handoff with no speech yet, end the loop after a silence\n // window (an open mic with nothing said means the user is done).\n useEffect(() => {\n if (!(handoffActive && recording.isRecording && !recording.speechDetected)) {\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current);\n inactivityTimerRef.current = null;\n }\n return;\n }\n inactivityTimerRef.current = setTimeout(() => {\n if (handoffActiveRef.current && !recording.speechDetected) cancelHandoff();\n }, HANDOFF_INACTIVITY_MS);\n return () => {\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current);\n inactivityTimerRef.current = null;\n }\n };\n }, [handoffActive, recording.isRecording, recording.speechDetected, cancelHandoff]);\n\n // Cleanup deferred work on unmount.\n useEffect(() => {\n return () => {\n if (pendingRafRef.current !== null) cancelAnimationFrame(pendingRafRef.current);\n if (inactivityTimerRef.current) clearTimeout(inactivityTimerRef.current);\n if (holdRafRef.current !== null) cancelAnimationFrame(holdRafRef.current);\n };\n }, []);\n\n // Handle key press\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend]\n );\n\n // Handle file selection\n const handleFileSelect = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n addFiles(Array.from(e.target.files || []));\n\n // Reset input\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n },\n [addFiles]\n );\n\n // Remove file\n const removeFile = useCallback((index: number) => {\n setFiles((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n // Remove a pasted-text card\n const removePastedText = useCallback((id: string) => {\n setPastedTexts((prev) => prev.filter((p) => p.id !== id));\n }, []);\n\n // Paste: files in the clipboard become attachments; a long block of plain\n // text becomes a card instead of flooding the textarea.\n const handlePaste = useCallback(\n (e: React.ClipboardEvent<HTMLTextAreaElement>) => {\n const clipboard = e.clipboardData;\n if (!clipboard) return;\n\n if (enableFileUploads) {\n const pastedFiles = Array.from(clipboard.items)\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((file): file is File => file !== null)\n .map((file) => {\n // Clipboard images share a generic name; give each one its own so\n // several pasted screenshots don't collapse into the same label.\n const ext = IMAGE_EXT_BY_MIME[file.type];\n if (!ext) return file;\n pasteCounterRef.current += 1;\n return new File([file], `pasted-image-${pasteCounterRef.current}.${ext}`, {\n type: file.type,\n });\n });\n\n if (pastedFiles.length > 0) {\n e.preventDefault();\n addFiles(pastedFiles);\n return;\n }\n }\n\n if (!enableLongTextPaste) return;\n\n const text = clipboard.getData('text/plain');\n if (text.length <= longTextPasteThreshold) return;\n\n e.preventDefault();\n pasteCounterRef.current += 1;\n setPastedTexts((prev) => [\n ...prev,\n { id: String(pasteCounterRef.current), text },\n ]);\n },\n [enableFileUploads, enableLongTextPaste, longTextPasteThreshold, addFiles]\n );\n\n // --- Drag & drop ---\n\n const handleDragEnter = useCallback(\n (e: React.DragEvent) => {\n if (!enableFileUploads || disabled) return;\n if (!e.dataTransfer.types.includes('Files')) return;\n e.preventDefault();\n dragDepthRef.current += 1;\n setIsDraggingOver(true);\n },\n [enableFileUploads, disabled]\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n if (!enableFileUploads || disabled) return;\n if (!e.dataTransfer.types.includes('Files')) return;\n // Without this the browser navigates away to open the dropped file.\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n },\n [enableFileUploads, disabled]\n );\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n dragDepthRef.current = Math.max(0, dragDepthRef.current - 1);\n if (dragDepthRef.current === 0) setIsDraggingOver(false);\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n if (!enableFileUploads || disabled) return;\n e.preventDefault();\n dragDepthRef.current = 0;\n setIsDraggingOver(false);\n addFiles(Array.from(e.dataTransfer.files || []));\n },\n [enableFileUploads, disabled, addFiles]\n );\n\n return (\n <div\n className=\"devic-input-area\"\n data-dragging={isDraggingOver ? 'true' : 'false'}\n onDragEnter={handleDragEnter}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n {isDraggingOver && (\n <div className=\"devic-drop-overlay\">\n <AttachIcon />\n <span>Drop files to attach</span>\n </div>\n )}\n {limitBanner}\n {usageBar}\n {disabledMessage && disabled && (\n <div className=\"devic-input-disabled-notice\">\n <WaitingIcon />\n {disabledMessage}\n </div>\n )}\n {speechError && (\n <div className=\"devic-speech-error\" role=\"alert\">\n {speechError}\n </div>\n )}\n {handoffActive && (\n <div className=\"devic-handoff-bar\" data-waiting={isProcessing ? 'true' : 'false'}>\n <span className=\"devic-handoff-dot\" aria-hidden=\"true\" />\n <span className=\"devic-handoff-label\">\n {isProcessing ? 'Hands-free · waiting for reply' : 'Hands-free on'}\n </span>\n <button\n type=\"button\"\n className=\"devic-handoff-stop\"\n onClick={cancelHandoff}\n title=\"Stop hands-free\"\n aria-label=\"Stop hands-free\"\n >\n <CloseIcon />\n </button>\n </div>\n )}\n {references && references.length > 0 && (\n <div className=\"devic-reference-chips\">\n {references.map((ref) => (\n <ReferenceChip\n key={ref.id}\n label={ref.label}\n variant=\"input\"\n onRemove={() => onRemoveReference?.(ref.id)}\n />\n ))}\n </div>\n )}\n {pastedTexts.length > 0 && (\n <div className=\"devic-pasted-cards\">\n {pastedTexts.map((pasted) => (\n <div key={pasted.id} className=\"devic-pasted-card\">\n <p className=\"devic-pasted-card-preview\">\n {pastedPreview(pasted.text)}\n </p>\n <div className=\"devic-pasted-card-footer\">\n <span className=\"devic-pasted-card-badge\">PASTED</span>\n <span className=\"devic-pasted-card-meta\">\n {pastedLineCount(pasted.text)} lines\n </span>\n </div>\n <button\n className=\"devic-file-remove devic-pasted-card-remove\"\n onClick={() => removePastedText(pasted.id)}\n type=\"button\"\n title=\"Remove pasted text\"\n aria-label=\"Remove pasted text\"\n >\n &times;\n </button>\n </div>\n ))}\n </div>\n )}\n {files.length > 0 && (\n <div className=\"devic-file-preview\">\n {files.map((file, idx) => (\n <div key={idx} className=\"devic-file-preview-item\">\n {filePreviews[idx] ? (\n <img\n className=\"devic-file-preview-thumb\"\n src={filePreviews[idx]!}\n alt={file.name}\n />\n ) : (\n <FileIcon />\n )}\n <span>{file.name}</span>\n <button\n className=\"devic-file-remove\"\n onClick={() => removeFile(idx)}\n type=\"button\"\n >\n &times;\n </button>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"devic-input-wrapper\">\n {pendingSend ? (\n <div className=\"devic-speech-panel\" data-state=\"pending\">\n <div className=\"devic-handoff-pending\">\n <div className=\"devic-handoff-pending-icon\">\n <SendCountdownRing progress={pendingProgress} />\n <SendIcon />\n </div>\n <div className=\"devic-handoff-pending-text\">\n <span className=\"devic-handoff-pending-title\">\n Sending… interact to cancel\n </span>\n {message.trim() && (\n <span className=\"devic-handoff-pending-preview\">{message.trim()}</span>\n )}\n </div>\n </div>\n </div>\n ) : isTranscribing ? (\n <div className=\"devic-speech-panel\" data-state=\"processing\">\n <span className=\"devic-speech-spinner\" aria-hidden=\"true\" />\n <span className=\"devic-speech-status\">Transcribing…</span>\n </div>\n ) : isRecordingActive ? (\n <div className=\"devic-speech-panel\" data-state=\"recording\">\n <button\n className=\"devic-input-btn devic-speech-cancel\"\n onClick={cancelRecording}\n type=\"button\"\n title=\"Cancel recording\"\n >\n <CloseIcon />\n </button>\n <div className=\"devic-speech-live\">\n <Equalizer levels={recording.levels} paused={recording.isPaused} />\n <span className=\"devic-speech-timer\">\n {formatDuration(recording.durationMs)}\n </span>\n </div>\n <button\n className=\"devic-input-btn\"\n onClick={recording.isPaused ? recording.resume : recording.pause}\n type=\"button\"\n title={recording.isPaused ? 'Resume' : 'Pause'}\n >\n {recording.isPaused ? <PlayIcon /> : <PauseIcon />}\n </button>\n <div\n className=\"devic-speech-confirm-wrap\"\n data-autostop={recording.isAutoStopping ? 'true' : 'false'}\n >\n {recording.isAutoStopping && (\n <AutoStopRing progress={recording.autoStopProgress} />\n )}\n <button\n className=\"devic-input-btn devic-speech-confirm\"\n onClick={() => void handleConfirm()}\n type=\"button\"\n title={\n recording.isAutoStopping\n ? 'Auto-sending… keep talking to cancel'\n : 'Confirm'\n }\n >\n <CheckIcon />\n </button>\n </div>\n </div>\n ) : (\n <>\n {enableFileUploads && (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={acceptedTypes}\n multiple\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n <button\n className=\"devic-input-btn\"\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled}\n type=\"button\"\n title=\"Attach file\"\n >\n <AttachIcon />\n </button>\n </>\n )}\n\n {speechEnabled && (\n <div\n className=\"devic-speech-mic-wrap\"\n data-holding={isHolding ? 'true' : 'false'}\n >\n {isHolding && <HoldRing progress={holdProgress} />}\n <button\n className=\"devic-input-btn devic-speech-mic\"\n onClick={speechHandoff ? undefined : startOneShotRecording}\n onPointerDown={speechHandoff ? handleMicPointerDown : undefined}\n onPointerUp={speechHandoff ? handleMicPointerUp : undefined}\n onPointerCancel={speechHandoff ? handleMicPointerCancel : undefined}\n disabled={disabled || isProcessing}\n type=\"button\"\n title={\n speechHandoff\n ? 'Tap to dictate · hold to start hands-free'\n : 'Record voice message'\n }\n >\n <MicIcon />\n </button>\n </div>\n )}\n\n <textarea\n ref={textareaRef}\n className=\"devic-input\"\n value={message}\n onChange={(e) => {\n const value = e.target.value;\n setMessage(value);\n // If the user clears the field, drop the transcript link so a fresh\n // message isn't wrongly attributed to the previous transcription.\n if (transcriptId && value.trim() === '') setTranscriptId(undefined);\n handleInput();\n }}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder}\n disabled={disabled}\n rows={1}\n />\n\n {isProcessing ? (\n stopButtonContent ? (\n <div className=\"devic-send-btn-wrapper\">\n <div className=\"devic-send-btn-custom\" aria-hidden=\"true\">\n {stopButtonContent}\n </div>\n <button\n className=\"devic-send-btn-overlay\"\n onClick={onStop}\n type=\"button\"\n title=\"Stop\"\n />\n </div>\n ) : (\n <button\n className=\"devic-input-btn devic-stop-btn\"\n onClick={onStop}\n type=\"button\"\n title=\"Stop\"\n >\n <StopIcon />\n </button>\n )\n ) : sendButtonContent ? (\n <div className=\"devic-send-btn-wrapper\">\n <div className=\"devic-send-btn-custom\" aria-hidden=\"true\">\n {sendButtonContent}\n </div>\n <button\n className=\"devic-send-btn-overlay\"\n onClick={handleSend}\n disabled={disabled || (!message.trim() && files.length === 0 && pastedTexts.length === 0)}\n type=\"button\"\n title=\"Send message\"\n />\n </div>\n ) : (\n <button\n className=\"devic-input-btn devic-send-btn\"\n onClick={handleSend}\n disabled={disabled || (!message.trim() && files.length === 0 && pastedTexts.length === 0)}\n type=\"button\"\n title=\"Send message\"\n >\n <SendIcon />\n </button>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Live equalizer rendered from the recording amplitude levels (0..1 per bar).\n * When paused, bars collapse to a flat baseline.\n */\nfunction Equalizer({\n levels,\n paused,\n}: {\n levels: number[];\n paused: boolean;\n}): JSX.Element {\n return (\n <div className=\"devic-equalizer\" aria-hidden=\"true\" data-paused={paused}>\n {levels.map((level, i) => (\n <span\n key={i}\n className=\"devic-equalizer-bar\"\n style={{ height: `${Math.max(10, Math.round((paused ? 0 : level) * 100))}%` }}\n />\n ))}\n </div>\n );\n}\n\n// Geometry for the auto-stop ring drawn around the confirm button.\nconst AUTOSTOP_RING_R = 18;\nconst AUTOSTOP_RING_C = 2 * Math.PI * AUTOSTOP_RING_R;\n\n/**\n * Inverted circular progress drawn around the confirm button. Driven by\n * `progress` (1 → 0): a full ring that drains to empty over the countdown.\n */\nfunction AutoStopRing({ progress }: { progress: number }): JSX.Element {\n return (\n <svg className=\"devic-autostop-ring\" viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <circle\n className=\"devic-autostop-ring-track\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n />\n <circle\n className=\"devic-autostop-ring-progress\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n style={{\n strokeDasharray: AUTOSTOP_RING_C,\n strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),\n }}\n />\n </svg>\n );\n}\n\n/**\n * Draining ring around the send icon during the handoff pending countdown.\n * Visually distinct from the auto-stop ring (slate→primary track, larger).\n */\nfunction SendCountdownRing({ progress }: { progress: number }): JSX.Element {\n return (\n <svg className=\"devic-handoff-ring\" viewBox=\"0 0 44 44\" aria-hidden=\"true\">\n <circle className=\"devic-handoff-ring-track\" cx=\"22\" cy=\"22\" r={AUTOSTOP_RING_R} />\n <circle\n className=\"devic-handoff-ring-progress\"\n cx=\"22\"\n cy=\"22\"\n r={AUTOSTOP_RING_R}\n style={{\n strokeDasharray: AUTOSTOP_RING_C,\n strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),\n }}\n />\n </svg>\n );\n}\n\n/**\n * Filling ring drawn around the mic button while the user presses and holds to\n * arm hands-free. Driven by `progress` (0 → 1): an empty ring that fills\n * clockwise over the hold duration. Inverse of the draining auto-stop ring.\n */\nfunction HoldRing({ progress }: { progress: number }): JSX.Element {\n return (\n <svg className=\"devic-mic-hold-ring\" viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <circle\n className=\"devic-mic-hold-ring-track\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n />\n <circle\n className=\"devic-mic-hold-ring-progress\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n style={{\n strokeDasharray: AUTOSTOP_RING_C,\n strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),\n }}\n />\n </svg>\n );\n}\n\n/** Formats milliseconds as m:ss. */\nfunction formatDuration(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n}\n\n/**\n * Attach icon\n */\nfunction AttachIcon(): 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 <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48\" />\n </svg>\n );\n}\n\n/**\n * Send icon\n */\nfunction SendIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\n </svg>\n );\n}\n\n/**\n * File icon\n */\nfunction FileIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14,2 14,8 20,8\" />\n </svg>\n );\n}\n\n/**\n * Microphone icon\n */\nfunction MicIcon(): 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 <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>\n );\n}\n\n/**\n * Pause icon (two bars)\n */\nfunction PauseIcon(): JSX.Element {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\" />\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\" />\n </svg>\n );\n}\n\n/**\n * Play icon (triangle)\n */\nfunction PlayIcon(): JSX.Element {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n );\n}\n\n/**\n * Check icon (confirm)\n */\nfunction CheckIcon(): 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.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\n/**\n * Close icon (cancel)\n */\nfunction CloseIcon(): 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.5\"\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 * Stop icon (square)\n */\nfunction StopIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" />\n </svg>\n );\n}\n\n/**\n * Waiting icon (clock)\n */\nfunction WaitingIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12,6 12,12 16,14\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":";;;;;;;AAYA,MAAM,gBAAgB,GAA6B;IACjD,MAAM,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,CAAC;AAC9D,IAAA,SAAS,EAAE;QACT,iBAAiB;QACjB,oBAAoB;QACpB,yEAAyE;QACzE,YAAY;QACZ,UAAU;AACX,KAAA;AACD,IAAA,KAAK,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,CAAC;AAC/C,IAAA,KAAK,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC;CAChD;AAED;AACA;AACA,MAAM,iBAAiB,GAA2B;AAChD,IAAA,YAAY,EAAE,KAAK;AACnB,IAAA,WAAW,EAAE,KAAK;AAClB,IAAA,WAAW,EAAE,KAAK;AAClB,IAAA,YAAY,EAAE,MAAM;CACrB;AAED;AACA,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;AAEG;SACa,SAAS,CAAC,EACxB,MAAM,EACN,QAAQ,GAAG,KAAK,EAChB,WAAW,GAAG,mBAAmB,EACjC,iBAAiB,GAAG,KAAK,EACzB,gBAAgB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EACpD,WAAW,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;AAC9B,mBAAmB,GAAG,KAAK,EAC3B,sBAAsB,GAAG,IAAI,EAC7B,kBAAkB,GAAG,KAAK,EAC1B,cAAc,EACd,cAAc,EACd,cAAc,GAAG,IAAI,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,0BAA0B,EAC1B,0BAA0B,EAC1B,yBAAyB,EACzB,aAAa,GAAG,KAAK,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,MAAM,EACN,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,YAAY,GAAG,KAAK,EACpB,MAAM,EACN,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,WAAW,GACI,EAAA;;IAEf,IAAI,kBAAkB,EAAE;AACtB,QAAA,MAAM,eAAe,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS;AAC3D,QAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kBAAkB,EAAA,kBAAA,EAAkB,OAAO,EAAA,QAAA,EACxDA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,oBAAoB,EAAA,gBAAA,EAAiB,kBAAkB,CAAC,QAAQ,EAAA,QAAA,EAC7EA,GAAA,CAAC,eAAe,EAAA,EACd,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,EACrC,MAAM,EAAE,kBAAkB,CAAC,MAAM,EACjC,MAAM,EAAE,CAAC,QAAQ,KAAK,cAAc,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,EAChF,MAAM,EAAE,CAAC,MAAM,KAAK,cAAc,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,EAAA,CAC5E,EAAA,CACE,EAAA,CACF;IAEV;IACA,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAS,EAAE,CAAC;;IAE9C,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAe,EAAE,CAAC;IAChE,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AAC3D,IAAA,MAAM,WAAW,GAAG,MAAM,CAAsB,IAAI,CAAC;AACrD,IAAA,MAAM,YAAY,GAAG,MAAM,CAAmB,IAAI,CAAC;;AAEnD,IAAA,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC;;;AAGjC,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC;;IAG9B,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,EAAsB;IACtE,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC3D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC;;;IAGnE,MAAM,UAAU,GAAG,MAAM,CAAa,MAAK,EAAE,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,kBAAkB,CAAC;AACnC,QAAA,IAAI,EAAE,CAAC;AACP,QAAA,QAAQ,EAAE,cAAc;AACxB,QAAA,IAAI,yBAAyB,IAAI,IAAI,IAAI;AACvC,YAAA,mBAAmB,EAAE,yBAAyB;SAC/C,CAAC;AACF,QAAA,IAAI,uBAAuB,IAAI,IAAI,IAAI;AACrC,YAAA,iBAAiB,EAAE,uBAAuB;SAC3C,CAAC;AACF,QAAA,IAAI,0BAA0B,IAAI,IAAI,IAAI;AACxC,YAAA,oBAAoB,EAAE,0BAA0B;SACjD,CAAC;AACF,QAAA,IAAI,0BAA0B,IAAI,IAAI,IAAI;AACxC,YAAA,oBAAoB,EAAE,0BAA0B;SACjD,CAAC;AACF,QAAA,IAAI,yBAAyB,IAAI,IAAI,IAAI;AACvC,YAAA,mBAAmB,EAAE,yBAAyB;SAC/C,CAAC;AACF,QAAA,UAAU,EAAE,MAAM,UAAU,CAAC,OAAO,EAAE;AACvC,KAAA,CAAC;;IAGF,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IACzD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IACrD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;;;AAGzD,IAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;AACtC,IAAA,MAAM,aAAa,GAAG,MAAM,CAAgB,IAAI,CAAC;AACjD,IAAA,MAAM,kBAAkB,GAAG,MAAM,CAAuC,IAAI,CAAC;AAC7E,IAAA,MAAM,iBAAiB,GAAG,MAAM,CAAC,YAAY,CAAC;;IAE9C,MAAM,aAAa,GAAG,MAAM,CAAa,MAAK,EAAE,CAAC,CAAC;;;;IAKlD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AACjD,IAAA,MAAM,UAAU,GAAG,MAAM,CAAgB,IAAI,CAAC;AAC9C,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;;AAGlC,IAAA,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAK;AACpC,QAAA,IAAI,CAAC,kBAAkB,IAAI,CAAC,MAAM;AAAE,YAAA,OAAO,IAAI;QAC/C,OAAO,IAAI,cAAc,CAAC;YACxB,MAAM;YACN,OAAO,EAAE,OAAO,IAAI,sBAAsB;AAC3C,SAAA,CAAC;IACJ,CAAC,EAAE,CAAC,kBAAkB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAEzC,MAAM,aAAa,GACjB,kBAAkB,IAAI,SAAS,CAAC,WAAW,IAAI,CAAC,CAAC,gBAAgB;IACnE,MAAM,iBAAiB,GAAG,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,QAAQ;;AAGrE,IAAA,MAAM,gBAAgB,GAAG,OAAO,CAC9B,MACE,MAAM,CAAC,OAAO,CAAC,gBAAgB;SAC5B,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,OAAO;SAC/B,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EACtD,CAAC,gBAAgB,CAAC,CACnB;IACD,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;;;;AAKhD,IAAA,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,QAAgB,KAAI;QACnB,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,KAAI;AAC1C,YAAA,IAAI,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE;gBAC3B,OAAO,CAAC,IAAI,CAAC,CAAA,KAAA,EAAQ,IAAI,CAAC,IAAI,CAAA,qBAAA,CAAuB,CAAC;AACtD,gBAAA,OAAO,KAAK;YACd;AACA,YAAA,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACxE,OAAO,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,IAAI,CAAC,IAAI,IAAI,SAAS,CAAA,eAAA,CAAiB,CAAC;AAClE,gBAAA,OAAO,KAAK;YACd;AACA,YAAA,OAAO,IAAI;AACb,QAAA,CAAC,CAAC;AACF,QAAA,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;AAAE,YAAA,QAAQ,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,UAAU,CAAC,CAAC;AACzE,IAAA,CAAC,EACD,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAChC;;;AAID,IAAA,MAAM,YAAY,GAAG,OAAO,CAC1B,MACE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KACb,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,IAAI,CAClE,EACH,CAAC,KAAK,CAAC,CACR;AACD,IAAA,SAAS,CACP,MAAM,MAAK;AACT,QAAA,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AAChE,IAAA,CAAC,EACD,CAAC,YAAY,CAAC,CACf;;AAGD,IAAA,MAAM,WAAW,GAAG,WAAW,CAAC,MAAK;AACnC,QAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO;QACpC,IAAI,QAAQ,EAAE;AACZ,YAAA,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;AAC9B,YAAA,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI;QACrE;IACF,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAA,MAAM,UAAU,GAAG,WAAW,CAAC,MAAK;AAClC,QAAA,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE;AACrC,QAAA,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE;;;;AAKvE,QAAA,MAAM,eAAe,GACnB,WAAW,CAAC,MAAM,GAAG;cACjB,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,cAAc;iBAC/C,MAAM,CAAC,OAAO;iBACd,IAAI,CAAC,MAAM;cACd,cAAc;AAEpB,QAAA,MAAM,CACJ,eAAe,EACf,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,SAAS,EACpC,YAAY,GAAG,EAAE,YAAY,EAAE,GAAG,SAAS,CAC5C;QACD,UAAU,CAAC,EAAE,CAAC;QACd,QAAQ,CAAC,EAAE,CAAC;QACZ,cAAc,CAAC,EAAE,CAAC;QAClB,eAAe,CAAC,SAAS,CAAC;;AAG1B,QAAA,IAAI,WAAW,CAAC,OAAO,EAAE;YACvB,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;QAC3C;AACF,IAAA,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;;AAEvD,IAAA,aAAa,CAAC,OAAO,GAAG,UAAU;;AAIlC,IAAA,MAAM,YAAY,GAAG,WAAW,CAAC,MAAK;AACpC,QAAA,IAAI,aAAa,CAAC,OAAO,KAAK,IAAI,EAAE;AAClC,YAAA,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC;AAC3C,YAAA,aAAa,CAAC,OAAO,GAAG,IAAI;QAC9B;QACA,cAAc,CAAC,KAAK,CAAC;QACrB,kBAAkB,CAAC,CAAC,CAAC;IACvB,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAA,MAAM,aAAa,GAAG,WAAW,CAAC,MAAK;AACrC,QAAA,gBAAgB,CAAC,OAAO,GAAG,KAAK;QAChC,gBAAgB,CAAC,KAAK,CAAC;AACvB,QAAA,YAAY,EAAE;AACd,QAAA,IAAI,kBAAkB,CAAC,OAAO,EAAE;AAC9B,YAAA,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC;AACxC,YAAA,kBAAkB,CAAC,OAAO,GAAG,IAAI;QACnC;QACA,SAAS,CAAC,MAAM,EAAE;AACpB,IAAA,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;;;AAI7B,IAAA,MAAM,qBAAqB,GAAG,WAAW,CAAC,MAAK;QAC7C,cAAc,CAAC,IAAI,CAAC;AACpB,QAAA,KAAK,SAAS,CAAC,KAAK,EAAE;AACxB,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;;AAGf,IAAA,MAAM,uBAAuB,GAAG,WAAW,CAAC,MAAK;QAC/C,cAAc,CAAC,IAAI,CAAC;AACpB,QAAA,gBAAgB,CAAC,OAAO,GAAG,IAAI;QAC/B,gBAAgB,CAAC,IAAI,CAAC;AACtB,QAAA,KAAK,SAAS,CAAC,KAAK,EAAE;AACxB,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;;AAGf,IAAA,MAAM,SAAS,GAAG,WAAW,CAAC,MAAK;AACjC,QAAA,IAAI,UAAU,CAAC,OAAO,KAAK,IAAI,EAAE;AAC/B,YAAA,oBAAoB,CAAC,UAAU,CAAC,OAAO,CAAC;AACxC,YAAA,UAAU,CAAC,OAAO,GAAG,IAAI;QAC3B;QACA,YAAY,CAAC,KAAK,CAAC;QACnB,eAAe,CAAC,CAAC,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC;;;;;AAMN,IAAA,MAAM,oBAAoB,GAAG,WAAW,CACtC,CAAC,CAAqB,KAAI;QACxB,IAAI,QAAQ,IAAI,YAAY;YAAE;AAC9B,QAAA,IAAI;YACF,CAAC,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC;QAChD;AAAE,QAAA,MAAM;;QAER;AACA,QAAA,MAAM,MAAM,GAAG,mBAAmB,IAAI,eAAe;AACrD,QAAA,YAAY,CAAC,OAAO,GAAG,KAAK;QAC5B,YAAY,CAAC,IAAI,CAAC;QAClB,eAAe,CAAC,CAAC,CAAC;AAClB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;QAC5B,MAAM,IAAI,GAAG,MAAK;AAChB,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,MAAM,CAAC;YAC/D,eAAe,CAAC,QAAQ,CAAC;AACzB,YAAA,IAAI,QAAQ,IAAI,CAAC,EAAE;AACjB,gBAAA,UAAU,CAAC,OAAO,GAAG,IAAI;AACzB,gBAAA,YAAY,CAAC,OAAO,GAAG,IAAI;gBAC3B,YAAY,CAAC,KAAK,CAAC;gBACnB,eAAe,CAAC,CAAC,CAAC;AAClB,gBAAA,uBAAuB,EAAE;gBACzB;YACF;AACA,YAAA,UAAU,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC;AAClD,QAAA,CAAC;AACD,QAAA,UAAU,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC;IAClD,CAAC,EACD,CAAC,QAAQ,EAAE,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,CAAC,CACvE;;;AAID,IAAA,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAK;AAC1C,QAAA,IAAI,YAAY,CAAC,OAAO,EAAE;AACxB,YAAA,YAAY,CAAC,OAAO,GAAG,KAAK;YAC5B;QACF;AACA,QAAA,IAAI,UAAU,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO;AACtD,QAAA,SAAS,EAAE;AACX,QAAA,qBAAqB,EAAE;IACzB,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;;AAGjD,IAAA,MAAM,sBAAsB,GAAG,WAAW,CAAC,MAAK;AAC9C,QAAA,IAAI,YAAY,CAAC,OAAO,EAAE;AACxB,YAAA,YAAY,CAAC,OAAO,GAAG,KAAK;YAC5B;QACF;AACA,QAAA,SAAS,EAAE;AACb,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;AAEf,IAAA,MAAM,eAAe,GAAG,WAAW,CAAC,MAAK;AACvC,QAAA,aAAa,EAAE;AACjB,IAAA,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;;;;AAKnB,IAAA,MAAM,gBAAgB,GAAG,WAAW,CAAC,YAAmC;AACtE,QAAA,IAAI,CAAC,gBAAgB;AAAE,YAAA,OAAO,IAAI;AAClC,QAAA,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE;AACnC,QAAA,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;AAAE,YAAA,OAAO,IAAI;QAEzC,iBAAiB,CAAC,IAAI,CAAC;QACvB,cAAc,CAAC,IAAI,CAAC;AACpB,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,eAAe,CAAC,IAAI,EAAE;AAC1D,gBAAA,QAAQ,EAAE,cAAc;AACxB,gBAAA,QAAQ,EAAE,cAAc;AACzB,aAAA,CAAC;AACF,YAAA,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE;YACvC,IAAI,IAAI,EAAE;gBACR,UAAU,CAAC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;AAC9D,gBAAA,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC;YACtC;;YAEA,qBAAqB,CAAC,MAAK;AACzB,gBAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO;gBACpC,IAAI,QAAQ,EAAE;AACZ,oBAAA,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;AAC9B,oBAAA,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI;oBACnE,QAAQ,CAAC,KAAK,EAAE;gBAClB;AACF,YAAA,CAAC,CAAC;AACF,YAAA,OAAO,IAAI;QACb;QAAE,OAAO,CAAC,EAAE;YACV,cAAc,CACZ,mCAAoC,CAAW,EAAE,OAAO,IAAI,eAAe,CAAA,CAAE,CAC9E;AACD,YAAA,OAAO,IAAI;QACb;gBAAU;YACR,iBAAiB,CAAC,KAAK,CAAC;QAC1B;IACF,CAAC,EAAE,CAAC,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;;;AAIjE,IAAA,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAK;AACxC,QAAA,MAAM,OAAO,GAAG,wBAAwB,IAAI,kBAAkB;QAC9D,cAAc,CAAC,IAAI,CAAC;QACpB,kBAAkB,CAAC,CAAC,CAAC;AACrB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;QAC5B,MAAM,IAAI,GAAG,MAAK;YAChB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;AACtC,YAAA,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;AACtD,YAAA,IAAI,OAAO,IAAI,OAAO,EAAE;AACtB,gBAAA,aAAa,CAAC,OAAO,GAAG,IAAI;gBAC5B,cAAc,CAAC,KAAK,CAAC;gBACrB,kBAAkB,CAAC,CAAC,CAAC;AACrB,gBAAA,aAAa,CAAC,OAAO,EAAE,CAAC;gBACxB;YACF;AACA,YAAA,aAAa,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC;AACrD,QAAA,CAAC;AACD,QAAA,aAAa,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC;AACrD,IAAA,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC;;;AAI9B,IAAA,MAAM,aAAa,GAAG,WAAW,CAAC,YAAW;AAC3C,QAAA,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE;QACrC,IAAI,CAAC,gBAAgB,CAAC,OAAO;AAAE,YAAA,OAAO;QACtC,IAAI,CAAC,IAAI,EAAE;;AAET,YAAA,aAAa,EAAE;YACf,UAAU,CAAC,EAAE,CAAC;YACd,eAAe,CAAC,SAAS,CAAC;YAC1B;QACF;AACA,QAAA,gBAAgB,EAAE;IACpB,CAAC,EAAE,CAAC,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;;IAGvD,SAAS,CAAC,MAAK;QACb,UAAU,CAAC,OAAO,GAAG,MAAM,KAAK,aAAa,EAAE;AACjD,IAAA,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;;;IAInB,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,WAAW;YAAE;QAClB,MAAM,UAAU,GAAG,MAAK;AACtB,YAAA,YAAY,EAAE;AACd,YAAA,gBAAgB,CAAC,OAAO,GAAG,KAAK;YAChC,gBAAgB,CAAC,KAAK,CAAC;YACvB,qBAAqB,CAAC,MAAM,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;AAC3D,QAAA,CAAC;QACD,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC;QACxD,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC;AACtD,QAAA,OAAO,MAAK;YACV,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC;YAC3D,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC;AAC3D,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;;;IAI/B,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAO;AAC/C,QAAA,iBAAiB,CAAC,OAAO,GAAG,YAAY;AACxC,QAAA,IACE,aAAa;YACb,aAAa;AACb,YAAA,CAAC,YAAY;AACb,YAAA,CAAC,QAAQ;AACT,YAAA,CAAC,WAAW;AACZ,YAAA,CAAC,cAAc;YACf,CAAC,SAAS,CAAC,WAAW;AACtB,YAAA,CAAC,SAAS,CAAC,QAAQ,EACnB;AACA,YAAA,KAAK,SAAS,CAAC,KAAK,EAAE;QACxB;;AAEF,IAAA,CAAC,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;;;IAIxE,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,EAAE,aAAa,IAAI,SAAS,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE;AAC1E,YAAA,IAAI,kBAAkB,CAAC,OAAO,EAAE;AAC9B,gBAAA,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC;AACxC,gBAAA,kBAAkB,CAAC,OAAO,GAAG,IAAI;YACnC;YACA;QACF;AACA,QAAA,kBAAkB,CAAC,OAAO,GAAG,UAAU,CAAC,MAAK;AAC3C,YAAA,IAAI,gBAAgB,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,cAAc;AAAE,gBAAA,aAAa,EAAE;QAC5E,CAAC,EAAE,qBAAqB,CAAC;AACzB,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,kBAAkB,CAAC,OAAO,EAAE;AAC9B,gBAAA,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC;AACxC,gBAAA,kBAAkB,CAAC,OAAO,GAAG,IAAI;YACnC;AACF,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;;IAGnF,SAAS,CAAC,MAAK;AACb,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,aAAa,CAAC,OAAO,KAAK,IAAI;AAAE,gBAAA,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC;YAC/E,IAAI,kBAAkB,CAAC,OAAO;AAAE,gBAAA,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC;AACxE,YAAA,IAAI,UAAU,CAAC,OAAO,KAAK,IAAI;AAAE,gBAAA,oBAAoB,CAAC,UAAU,CAAC,OAAO,CAAC;AAC3E,QAAA,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAA,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,CAAsB,KAAI;QACzB,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;YACpC,CAAC,CAAC,cAAc,EAAE;AAClB,YAAA,UAAU,EAAE;QACd;AACF,IAAA,CAAC,EACD,CAAC,UAAU,CAAC,CACb;;AAGD,IAAA,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,CAAsC,KAAI;AACzC,QAAA,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;;AAG1C,QAAA,IAAI,YAAY,CAAC,OAAO,EAAE;AACxB,YAAA,YAAY,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE;QACjC;AACF,IAAA,CAAC,EACD,CAAC,QAAQ,CAAC,CACX;;AAGD,IAAA,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,KAAa,KAAI;QAC/C,QAAQ,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC;IACxD,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAA,MAAM,gBAAgB,GAAG,WAAW,CAAC,CAAC,EAAU,KAAI;QAClD,cAAc,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC,EAAE,EAAE,CAAC;;;AAIN,IAAA,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,CAA4C,KAAI;AAC/C,QAAA,MAAM,SAAS,GAAG,CAAC,CAAC,aAAa;AACjC,QAAA,IAAI,CAAC,SAAS;YAAE;QAEhB,IAAI,iBAAiB,EAAE;YACrB,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK;iBAC3C,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,MAAM;iBACrC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,EAAE;iBAC9B,MAAM,CAAC,CAAC,IAAI,KAAmB,IAAI,KAAK,IAAI;AAC5C,iBAAA,GAAG,CAAC,CAAC,IAAI,KAAI;;;gBAGZ,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;AACxC,gBAAA,IAAI,CAAC,GAAG;AAAE,oBAAA,OAAO,IAAI;AACrB,gBAAA,eAAe,CAAC,OAAO,IAAI,CAAC;AAC5B,gBAAA,OAAO,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAA,aAAA,EAAgB,eAAe,CAAC,OAAO,CAAA,CAAA,EAAI,GAAG,EAAE,EAAE;oBACxE,IAAI,EAAE,IAAI,CAAC,IAAI;AAChB,iBAAA,CAAC;AACJ,YAAA,CAAC,CAAC;AAEJ,YAAA,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC1B,CAAC,CAAC,cAAc,EAAE;gBAClB,QAAQ,CAAC,WAAW,CAAC;gBACrB;YACF;QACF;AAEA,QAAA,IAAI,CAAC,mBAAmB;YAAE;QAE1B,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC;AAC5C,QAAA,IAAI,IAAI,CAAC,MAAM,IAAI,sBAAsB;YAAE;QAE3C,CAAC,CAAC,cAAc,EAAE;AAClB,QAAA,eAAe,CAAC,OAAO,IAAI,CAAC;AAC5B,QAAA,cAAc,CAAC,CAAC,IAAI,KAAK;AACvB,YAAA,GAAG,IAAI;YACP,EAAE,EAAE,EAAE,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;AAC9C,SAAA,CAAC;IACJ,CAAC,EACD,CAAC,iBAAiB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,QAAQ,CAAC,CAC3E;;AAID,IAAA,MAAM,eAAe,GAAG,WAAW,CACjC,CAAC,CAAkB,KAAI;QACrB,IAAI,CAAC,iBAAiB,IAAI,QAAQ;YAAE;QACpC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE;QAC7C,CAAC,CAAC,cAAc,EAAE;AAClB,QAAA,YAAY,CAAC,OAAO,IAAI,CAAC;QACzB,iBAAiB,CAAC,IAAI,CAAC;AACzB,IAAA,CAAC,EACD,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAC9B;AAED,IAAA,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,CAAkB,KAAI;QACrB,IAAI,CAAC,iBAAiB,IAAI,QAAQ;YAAE;QACpC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE;;QAE7C,CAAC,CAAC,cAAc,EAAE;AAClB,QAAA,CAAC,CAAC,YAAY,CAAC,UAAU,GAAG,MAAM;AACpC,IAAA,CAAC,EACD,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAC9B;AAED,IAAA,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,CAAkB,KAAI;QACzD,CAAC,CAAC,cAAc,EAAE;AAClB,QAAA,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC;AAC5D,QAAA,IAAI,YAAY,CAAC,OAAO,KAAK,CAAC;YAAE,iBAAiB,CAAC,KAAK,CAAC;IAC1D,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,CAAkB,KAAI;QACrB,IAAI,CAAC,iBAAiB,IAAI,QAAQ;YAAE;QACpC,CAAC,CAAC,cAAc,EAAE;AAClB,QAAA,YAAY,CAAC,OAAO,GAAG,CAAC;QACxB,iBAAiB,CAAC,KAAK,CAAC;AACxB,QAAA,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC,EACD,CAAC,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,CAAC,CACxC;AAED,IAAA,QACEC,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,kBAAkB,EAAA,eAAA,EACb,cAAc,GAAG,MAAM,GAAG,OAAO,EAChD,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,cAAc,EAC1B,WAAW,EAAE,eAAe,EAC5B,MAAM,EAAE,UAAU,EAAA,QAAA,EAAA,CAEjB,cAAc,KACbA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,oBAAoB,aACjCD,GAAA,CAAC,UAAU,EAAA,EAAA,CAAG,EACdA,iDAAiC,CAAA,EAAA,CAC7B,CACP,EACA,WAAW,EACX,QAAQ,EACR,eAAe,IAAI,QAAQ,KAC1BC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,6BAA6B,aAC1CD,GAAA,CAAC,WAAW,EAAA,EAAA,CAAG,EACd,eAAe,CAAA,EAAA,CACZ,CACP,EACA,WAAW,KACVA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAC,OAAO,EAAA,QAAA,EAC7C,WAAW,GACR,CACP,EACA,aAAa,KACZC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,EAAA,cAAA,EAAe,YAAY,GAAG,MAAM,GAAG,OAAO,EAAA,QAAA,EAAA,CAC9ED,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,mBAAmB,EAAA,aAAA,EAAa,MAAM,GAAG,EACzDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,qBAAqB,YAClC,YAAY,GAAG,gCAAgC,GAAG,eAAe,EAAA,CAC7D,EACPA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,oBAAoB,EAC9B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAC,iBAAiB,EAAA,YAAA,EACZ,iBAAiB,YAE5BA,GAAA,CAAC,SAAS,KAAG,EAAA,CACN,CAAA,EAAA,CACL,CACP,EACA,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,KAClCA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,uBAAuB,EAAA,QAAA,EACnC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,MAClBA,GAAA,CAAC,aAAa,EAAA,EAEZ,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,OAAO,EAAC,OAAO,EACf,QAAQ,EAAE,MAAM,iBAAiB,GAAG,GAAG,CAAC,EAAE,CAAC,EAAA,EAHtC,GAAG,CAAC,EAAE,CAIX,CACH,CAAC,EAAA,CACE,CACP,EACA,WAAW,CAAC,MAAM,GAAG,CAAC,KACrBA,aAAK,SAAS,EAAC,oBAAoB,EAAA,QAAA,EAChC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,MACtBC,IAAA,CAAA,KAAA,EAAA,EAAqB,SAAS,EAAC,mBAAmB,EAAA,QAAA,EAAA,CAChDD,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,2BAA2B,EAAA,QAAA,EACrC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,EAAA,CACzB,EACJC,cAAK,SAAS,EAAC,0BAA0B,EAAA,QAAA,EAAA,CACvCD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,yBAAyB,EAAA,QAAA,EAAA,QAAA,EAAA,CAAc,EACvDC,eAAM,SAAS,EAAC,wBAAwB,EAAA,QAAA,EAAA,CACrC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,cACxB,CAAA,EAAA,CACH,EACND,gBACE,SAAS,EAAC,4CAA4C,EACtD,OAAO,EAAE,MAAM,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC,EAC1C,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,oBAAoB,EAAA,YAAA,EACf,oBAAoB,EAAA,QAAA,EAAA,QAAA,EAAA,CAGxB,CAAA,EAAA,EAlBD,MAAM,CAAC,EAAE,CAmBb,CACP,CAAC,EAAA,CACE,CACP,EACA,KAAK,CAAC,MAAM,GAAG,CAAC,KACfA,aAAK,SAAS,EAAC,oBAAoB,EAAA,QAAA,EAChC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,MACnBC,IAAA,CAAA,KAAA,EAAA,EAAe,SAAS,EAAC,yBAAyB,EAAA,QAAA,EAAA,CAC/C,YAAY,CAAC,GAAG,CAAC,IAChBD,aACE,SAAS,EAAC,0BAA0B,EACpC,GAAG,EAAE,YAAY,CAAC,GAAG,CAAE,EACvB,GAAG,EAAE,IAAI,CAAC,IAAI,GACd,KAEFA,GAAA,CAAC,QAAQ,KAAG,CACb,EACDA,wBAAO,IAAI,CAAC,IAAI,EAAA,CAAQ,EACxBA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,mBAAmB,EAC7B,OAAO,EAAE,MAAM,UAAU,CAAC,GAAG,CAAC,EAC9B,IAAI,EAAC,QAAQ,EAAA,QAAA,EAAA,QAAA,EAAA,CAGN,CAAA,EAAA,EAjBD,GAAG,CAkBP,CACP,CAAC,GACE,CACP,EAEDA,aAAK,SAAS,EAAC,qBAAqB,EAAA,QAAA,EACjC,WAAW,IACVA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,oBAAoB,EAAA,YAAA,EAAY,SAAS,YACtDC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,uBAAuB,EAAA,QAAA,EAAA,CACpCA,cAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACzCD,IAAC,iBAAiB,EAAA,EAAC,QAAQ,EAAE,eAAe,GAAI,EAChDA,GAAA,CAAC,QAAQ,EAAA,EAAA,CAAG,IACR,EACNC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,aACzCD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,6BAA6B,iDAEtC,EACN,OAAO,CAAC,IAAI,EAAE,KACbA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,+BAA+B,EAAA,QAAA,EAAE,OAAO,CAAC,IAAI,EAAE,GAAQ,CACxE,CAAA,EAAA,CACG,CAAA,EAAA,CACF,EAAA,CACF,IACJ,cAAc,IAChBC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,oBAAoB,EAAA,YAAA,EAAY,YAAY,EAAA,QAAA,EAAA,CACzDD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,sBAAsB,EAAA,aAAA,EAAa,MAAM,GAAG,EAC5DA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,qBAAqB,mCAAqB,CAAA,EAAA,CACtD,IACJ,iBAAiB,IACnBC,cAAK,SAAS,EAAC,oBAAoB,EAAA,YAAA,EAAY,WAAW,EAAA,QAAA,EAAA,CACxDD,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,qCAAqC,EAC/C,OAAO,EAAE,eAAe,EACxB,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,kBAAkB,EAAA,QAAA,EAExBA,GAAA,CAAC,SAAS,EAAA,EAAA,CAAG,GACN,EACTC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,aAChCD,GAAA,CAAC,SAAS,EAAA,EAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,EAAA,CAAI,EACnEA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,oBAAoB,EAAA,QAAA,EACjC,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,EAAA,CAChC,CAAA,EAAA,CACH,EACNA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,iBAAiB,EAC3B,OAAO,EAAE,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,KAAK,EAChE,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE,SAAS,CAAC,QAAQ,GAAG,QAAQ,GAAG,OAAO,YAE7C,SAAS,CAAC,QAAQ,GAAGA,GAAA,CAAC,QAAQ,EAAA,EAAA,CAAG,GAAGA,GAAA,CAAC,SAAS,EAAA,EAAA,CAAG,EAAA,CAC3C,EACTC,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,2BAA2B,mBACtB,SAAS,CAAC,cAAc,GAAG,MAAM,GAAG,OAAO,EAAA,QAAA,EAAA,CAEzD,SAAS,CAAC,cAAc,KACvBD,GAAA,CAAC,YAAY,EAAA,EAAC,QAAQ,EAAE,SAAS,CAAC,gBAAgB,EAAA,CAAI,CACvD,EACDA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,sCAAsC,EAChD,OAAO,EAAE,MAAM,KAAK,aAAa,EAAE,EACnC,IAAI,EAAC,QAAQ,EACb,KAAK,EACH,SAAS,CAAC;AACR,0CAAE;AACF,0CAAE,SAAS,EAAA,QAAA,EAGfA,IAAC,SAAS,EAAA,EAAA,CAAG,GACN,CAAA,EAAA,CACL,CAAA,EAAA,CACF,KAENC,4BACG,iBAAiB,KAChBA,IAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAA,CACEF,GAAA,CAAA,OAAA,EAAA,EACE,GAAG,EAAE,YAAY,EACjB,IAAI,EAAC,MAAM,EACX,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAA,IAAA,EACR,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAC1B,EACFA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,iBAAiB,EAC3B,OAAO,EAAE,MAAM,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,EAC5C,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,aAAa,EAAA,QAAA,EAEnBA,IAAC,UAAU,EAAA,EAAA,CAAG,GACP,CAAA,EAAA,CACR,CACJ,EAEA,aAAa,KACZC,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,uBAAuB,kBACnB,SAAS,GAAG,MAAM,GAAG,OAAO,EAAA,QAAA,EAAA,CAEzC,SAAS,IAAID,GAAA,CAAC,QAAQ,EAAA,EAAC,QAAQ,EAAE,YAAY,EAAA,CAAI,EAClDA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,kCAAkC,EAC5C,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,qBAAqB,EAC1D,aAAa,EAAE,aAAa,GAAG,oBAAoB,GAAG,SAAS,EAC/D,WAAW,EAAE,aAAa,GAAG,kBAAkB,GAAG,SAAS,EAC3D,eAAe,EAAE,aAAa,GAAG,sBAAsB,GAAG,SAAS,EACnE,QAAQ,EAAE,QAAQ,IAAI,YAAY,EAClC,IAAI,EAAC,QAAQ,EACb,KAAK,EACH;AACE,0CAAE;AACF,0CAAE,sBAAsB,EAAA,QAAA,EAG5BA,GAAA,CAAC,OAAO,EAAA,EAAA,CAAG,EAAA,CACJ,CAAA,EAAA,CACL,CACP,EAEDA,GAAA,CAAA,UAAA,EAAA,EACE,GAAG,EAAE,WAAW,EAChB,SAAS,EAAC,aAAa,EACvB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,KAAI;AACd,gCAAA,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK;gCAC5B,UAAU,CAAC,KAAK,CAAC;;;AAGjB,gCAAA,IAAI,YAAY,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;oCAAE,eAAe,CAAC,SAAS,CAAC;AACnE,gCAAA,WAAW,EAAE;4BACf,CAAC,EACD,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,EAAA,CACP,EAED,YAAY,IACX,iBAAiB,IACfC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,wBAAwB,EAAA,QAAA,EAAA,CACrCD,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,uBAAuB,EAAA,aAAA,EAAa,MAAM,EAAA,QAAA,EACtD,iBAAiB,GACd,EACNA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,wBAAwB,EAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,MAAM,EAAA,CACZ,CAAA,EAAA,CACE,KAENA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,gCAAgC,EAC1C,OAAO,EAAE,MAAM,EACf,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,MAAM,YAEZA,GAAA,CAAC,QAAQ,EAAA,EAAA,CAAG,EAAA,CACL,CACV,IACC,iBAAiB,IACnBC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,wBAAwB,EAAA,QAAA,EAAA,CACrCD,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,uBAAuB,iBAAa,MAAM,EAAA,QAAA,EACtD,iBAAiB,EAAA,CACd,EACNA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,wBAAwB,EAClC,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,QAAQ,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,EACzF,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,cAAc,EAAA,CACpB,CAAA,EAAA,CACE,KAENA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,gCAAgC,EAC1C,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,QAAQ,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,EACzF,IAAI,EAAC,QAAQ,EACb,KAAK,EAAC,cAAc,EAAA,QAAA,EAEpBA,GAAA,CAAC,QAAQ,EAAA,EAAA,CAAG,EAAA,CACL,CACV,IACA,CACJ,EAAA,CACG,CAAA,EAAA,CACF;AAEV;AAEA;;;AAGG;AACH,SAAS,SAAS,CAAC,EACjB,MAAM,EACN,MAAM,GAIP,EAAA;AACC,IAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iBAAiB,EAAA,aAAA,EAAa,MAAM,EAAA,aAAA,EAAc,MAAM,EAAA,QAAA,EACpE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,MACnBA,GAAA,CAAA,MAAA,EAAA,EAEE,SAAS,EAAC,qBAAqB,EAC/B,KAAK,EAAE,EAAE,MAAM,EAAE,CAAA,EAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAA,CAAA,CAAG,EAAE,EAAA,EAFxE,CAAC,CAGN,CACH,CAAC,EAAA,CACE;AAEV;AAEA;AACA,MAAM,eAAe,GAAG,EAAE;AAC1B,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,eAAe;AAErD;;;AAGG;AACH,SAAS,YAAY,CAAC,EAAE,QAAQ,EAAwB,EAAA;IACtD,QACEC,cAAK,SAAS,EAAC,qBAAqB,EAAC,OAAO,EAAC,WAAW,EAAA,aAAA,EAAa,MAAM,aACzED,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,2BAA2B,EACrC,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,eAAe,EAAA,CAClB,EACFA,gBACE,SAAS,EAAC,8BAA8B,EACxC,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,eAAe,EAClB,KAAK,EAAE;AACL,oBAAA,eAAe,EAAE,eAAe;AAChC,oBAAA,gBAAgB,EAAE,eAAe,IAAI,CAAC,GAAG,QAAQ,CAAC;iBACnD,EAAA,CACD,CAAA,EAAA,CACE;AAEV;AAEA;;;AAGG;AACH,SAAS,iBAAiB,CAAC,EAAE,QAAQ,EAAwB,EAAA;IAC3D,QACEC,cAAK,SAAS,EAAC,oBAAoB,EAAC,OAAO,EAAC,WAAW,EAAA,aAAA,EAAa,MAAM,aACxED,GAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,0BAA0B,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAE,eAAe,EAAA,CAAI,EACnFA,gBACE,SAAS,EAAC,6BAA6B,EACvC,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,eAAe,EAClB,KAAK,EAAE;AACL,oBAAA,eAAe,EAAE,eAAe;AAChC,oBAAA,gBAAgB,EAAE,eAAe,IAAI,CAAC,GAAG,QAAQ,CAAC;iBACnD,EAAA,CACD,CAAA,EAAA,CACE;AAEV;AAEA;;;;AAIG;AACH,SAAS,QAAQ,CAAC,EAAE,QAAQ,EAAwB,EAAA;IAClD,QACEC,cAAK,SAAS,EAAC,qBAAqB,EAAC,OAAO,EAAC,WAAW,EAAA,aAAA,EAAa,MAAM,aACzED,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,2BAA2B,EACrC,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,eAAe,EAAA,CAClB,EACFA,gBACE,SAAS,EAAC,8BAA8B,EACxC,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,eAAe,EAClB,KAAK,EAAE;AACL,oBAAA,eAAe,EAAE,eAAe;AAChC,oBAAA,gBAAgB,EAAE,eAAe,IAAI,CAAC,GAAG,QAAQ,CAAC;iBACnD,EAAA,CACD,CAAA,EAAA,CACE;AAEV;AAEA;AACA,SAAS,cAAc,CAAC,EAAU,EAAA;IAChC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC;AAC7C,IAAA,MAAM,OAAO,GAAG,YAAY,GAAG,EAAE;AACjC,IAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;AAC5D;AAEA;;AAEG;AACH,SAAS,UAAU,GAAA;AACjB,IAAA,QACEA,GAAA,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,EAEtBA,cAAM,CAAC,EAAC,mHAAmH,EAAA,CAAG,EAAA,CAC1H;AAEV;AAEA;;AAEG;AACH,SAAS,QAAQ,GAAA;IACf,QACEA,GAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,cAAc,EAAA,QAAA,EAEnBA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,uCAAuC,EAAA,CAAG,EAAA,CAC9C;AAEV;AAEA;;AAEG;AACH,SAAS,QAAQ,GAAA;IACf,QACEC,cACE,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,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,4DAA4D,EAAA,CAAG,EACvEA,GAAA,CAAA,UAAA,EAAA,EAAU,MAAM,EAAC,gBAAgB,EAAA,CAAG,CAAA,EAAA,CAChC;AAEV;AAEA;;AAEG;AACH,SAAS,OAAO,GAAA;AACd,IAAA,QACEC,IAAA,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,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,sDAAsD,GAAG,EACjEA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,4BAA4B,EAAA,CAAG,EACvCA,cAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EACxCA,GAAA,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,SAAS,GAAA;AAChB,IAAA,QACEC,IAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,cAAc,EAAA,QAAA,EAAA,CACjED,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,GAAG,EAAC,CAAC,EAAC,GAAG,EAAC,KAAK,EAAC,GAAG,EAAC,MAAM,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAA,CAAG,EACjDA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,GAAG,EAAC,KAAK,EAAC,GAAG,EAAC,MAAM,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAA,CAAG,CAAA,EAAA,CAC9C;AAEV;AAEA;;AAEG;AACH,SAAS,QAAQ,GAAA;IACf,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,cAAc,EAAA,QAAA,EACjEA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,eAAe,EAAA,CAAG,EAAA,CACtB;AAEV;AAEA;;AAEG;AACH,SAAS,SAAS,GAAA;AAChB,IAAA,QACEA,GAAA,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,KAAK,EACjB,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAEtBA,kBAAU,MAAM,EAAC,gBAAgB,EAAA,CAAG,EAAA,CAChC;AAEV;AAEA;;AAEG;AACH,SAAS,SAAS,GAAA;AAChB,IAAA,QACEC,IAAA,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,KAAK,EACjB,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAAA,CAEtBD,GAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EACtCA,GAAA,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,QACEA,GAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,cAAc,YAEnBA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,GAAG,EAAC,CAAC,EAAC,GAAG,EAAC,KAAK,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAA,CAAG,EAAA,CAC9C;AAEV;AAEA;;AAEG;AACH,SAAS,WAAW,GAAA;IAClB,QACEC,IAAA,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,GAAA,CAAA,QAAA,EAAA,EAAQ,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAA,CAAG,EACjCA,GAAA,CAAA,UAAA,EAAA,EAAU,MAAM,EAAC,kBAAkB,EAAA,CAAG,CAAA,EAAA,CAClC;AAEV;;;;"}
1
+ {"version":3,"file":"ChatInput.js","sources":["../../../../src/components/ChatDrawer/ChatInput.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';\nimport type { ChatInputProps } from './ChatDrawer.types';\nimport { useSpeechRecording } from '../../hooks/useSpeechRecording';\nimport { DevicApiClient } from '../../api/client';\nimport { ReferenceChip } from './ReferenceChip';\nimport {\n toPastedBlock,\n pastedPreview,\n pastedLineCount,\n type PastedText,\n} from './pastedText';\n\nconst FILE_TYPE_ACCEPT: Record<string, string[]> = {\n images: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],\n documents: [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'text/plain',\n 'text/csv',\n ],\n audio: ['audio/mpeg', 'audio/wav', 'audio/ogg'],\n video: ['video/mp4', 'video/webm', 'video/ogg'],\n};\n\n// Extensions used to name images pasted from the clipboard, which arrive with a\n// generic name (\"image.png\") or none at all.\nconst IMAGE_EXT_BY_MIME: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/gif': 'gif',\n 'image/webp': 'webp',\n};\n\n// Handoff (hands-free) loop timings.\nconst HANDOFF_PENDING_MS = 1000; // default cancellable countdown before auto-send\nconst HANDOFF_INACTIVITY_MS = 6000; // silence (no speech) that ends the loop\nconst HANDOFF_HOLD_MS = 3000; // press-and-hold duration on the mic to arm hands-free\n\n/**\n * Chat input component with file upload support.\n *\n * When a widget is pending as 'input' it replaces the whole input area. The swap\n * lives here, in a component with no hooks of its own, so that each subtree is\n * mounted and unmounted whole. Returning the widget from inside ChatInputBox\n * instead would skip every hook below the early return, which violates the rules\n * of hooks (and is what react-hooks/rules-of-hooks flags). React tolerates that\n * particular shape today — its \"fewer hooks than expected\" check only fires once\n * at least one hook has run — so it is a latent fragility rather than a crash,\n * but the toggle is on the hot path for interactive widgets and does not need to\n * depend on that internal detail. Draft text in the textarea is dropped on the\n * swap, same as before.\n */\nexport function ChatInput(props: ChatInputProps): JSX.Element {\n const { pendingInputWidget, onSubmitWidget, onCancelWidget } = props;\n\n if (pendingInputWidget) {\n const WidgetComponent = pendingInputWidget.widget.component;\n return (\n <div className=\"devic-input-area\" data-widget-mode=\"input\">\n <div className=\"devic-input-widget\" data-tool-name={pendingInputWidget.toolName}>\n <WidgetComponent\n toolCall={pendingInputWidget.toolCall}\n params={pendingInputWidget.params}\n submit={(response) => onSubmitWidget?.(pendingInputWidget.toolCall.id, response)}\n cancel={(reason) => onCancelWidget?.(pendingInputWidget.toolCall.id, reason)}\n />\n </div>\n </div>\n );\n }\n\n return <ChatInputBox {...props} />;\n}\n\nfunction ChatInputBox({\n onSend,\n disabled = false,\n placeholder = 'Type a message...',\n enableFileUploads = false,\n allowedFileTypes = { images: true, documents: true },\n maxFileSize = 10 * 1024 * 1024, // 10MB\n enableLongTextPaste = false,\n longTextPasteThreshold = 2000,\n enableSpeechToText = false,\n speechLanguage,\n speechTenantId,\n speechAutoStop = true,\n speechAutoStopCountdownMs,\n speechAutoStopSilenceMs,\n speechAutoStopSilenceRatio,\n speechAutoStopSilenceLevel,\n speechAutoStopSpeechLevel,\n speechHandoff = false,\n speechHandoffSendDelayMs,\n speechHandoffHoldMs,\n apiKey,\n baseUrl,\n sendButtonContent,\n disabledMessage,\n isProcessing = false,\n onStop,\n stopButtonContent,\n references,\n onRemoveReference,\n usageBar,\n limitBanner,\n}: ChatInputProps): JSX.Element {\n const [message, setMessage] = useState('');\n const [files, setFiles] = useState<File[]>([]);\n // Long blocks of pasted text, kept out of the textarea and shown as cards.\n const [pastedTexts, setPastedTexts] = useState<PastedText[]>([]);\n const [isDraggingOver, setIsDraggingOver] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n // Monotonic counters so pasted images and text blocks get stable, unique ids.\n const pasteCounterRef = useRef(0);\n // Nested dragenter/dragleave events fire per child node; count them so the\n // overlay only clears when the pointer truly leaves the input area.\n const dragDepthRef = useRef(0);\n\n // Speech-to-text state\n const [transcriptId, setTranscriptId] = useState<string | undefined>();\n const [isTranscribing, setIsTranscribing] = useState(false);\n const [speechError, setSpeechError] = useState<string | null>(null);\n // Holds the latest confirmRecording so the auto-stop callback (created before\n // confirmRecording is defined) always calls the current closure.\n const confirmRef = useRef<() => void>(() => {});\n const recording = useSpeechRecording({\n bars: 5,\n autoStop: speechAutoStop,\n ...(speechAutoStopCountdownMs != null && {\n autoStopCountdownMs: speechAutoStopCountdownMs,\n }),\n ...(speechAutoStopSilenceMs != null && {\n autoStopSilenceMs: speechAutoStopSilenceMs,\n }),\n ...(speechAutoStopSilenceRatio != null && {\n autoStopSilenceRatio: speechAutoStopSilenceRatio,\n }),\n ...(speechAutoStopSilenceLevel != null && {\n autoStopSilenceLevel: speechAutoStopSilenceLevel,\n }),\n ...(speechAutoStopSpeechLevel != null && {\n autoStopSpeechLevel: speechAutoStopSpeechLevel,\n }),\n onAutoStop: () => confirmRef.current(),\n });\n\n // --- Handoff (hands-free loop) state ---\n const [handoffActive, setHandoffActive] = useState(false);\n const [pendingSend, setPendingSend] = useState(false);\n const [pendingProgress, setPendingProgress] = useState(1);\n // Ref mirror so async callbacks (rAF, timers, document listeners) read the\n // live value without going stale.\n const handoffActiveRef = useRef(false);\n const pendingRafRef = useRef<number | null>(null);\n const inactivityTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const prevProcessingRef = useRef(isProcessing);\n // Always-fresh send fn so the deferred auto-send uses the latest message.\n const handleSendRef = useRef<() => void>(() => {});\n\n // --- Press-and-hold to arm hands-free ---\n // Holding the mic for `holdMs` fills a ring (0→1) and activates hands-free;\n // releasing earlier falls back to a single one-shot recording.\n const [holdProgress, setHoldProgress] = useState(0);\n const [isHolding, setIsHolding] = useState(false);\n const holdRafRef = useRef<number | null>(null);\n const holdFiredRef = useRef(false);\n\n // Client used only for the /whisper transcription call.\n const transcribeClient = useMemo(() => {\n if (!enableSpeechToText || !apiKey) return null;\n return new DevicApiClient({\n apiKey,\n baseUrl: baseUrl || 'https://api.devic.ai',\n });\n }, [enableSpeechToText, apiKey, baseUrl]);\n\n const speechEnabled =\n enableSpeechToText && recording.isSupported && !!transcribeClient;\n const isRecordingActive = recording.isRecording || recording.isPaused;\n\n // Calculate accepted file types\n const acceptedTypeList = useMemo(\n () =>\n Object.entries(allowedFileTypes)\n .filter(([, enabled]) => enabled)\n .flatMap(([type]) => FILE_TYPE_ACCEPT[type] || []),\n [allowedFileTypes]\n );\n const acceptedTypes = acceptedTypeList.join(',');\n\n // Single entry point for every way of attaching a file (button, paste, drop):\n // enforces the size limit and the allowed MIME types, which until now were\n // only hinted at the native file dialog and never actually checked.\n const addFiles = useCallback(\n (incoming: File[]) => {\n const validFiles = incoming.filter((file) => {\n if (file.size > maxFileSize) {\n console.warn(`File ${file.name} exceeds maximum size`);\n return false;\n }\n if (acceptedTypeList.length > 0 && !acceptedTypeList.includes(file.type)) {\n console.warn(`File type ${file.type || 'unknown'} is not allowed`);\n return false;\n }\n return true;\n });\n if (validFiles.length > 0) setFiles((prev) => [...prev, ...validFiles]);\n },\n [maxFileSize, acceptedTypeList]\n );\n\n // Thumbnails for attached images. The cleanup revokes the previous batch on\n // every change (and on unmount), so the object URLs never leak.\n const filePreviews = useMemo(\n () =>\n files.map((file) =>\n file.type.startsWith('image/') ? URL.createObjectURL(file) : null\n ),\n [files]\n );\n useEffect(\n () => () => {\n filePreviews.forEach((url) => url && URL.revokeObjectURL(url));\n },\n [filePreviews]\n );\n\n // Auto-resize textarea\n const handleInput = useCallback(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n }\n }, []);\n\n // Handle send\n const handleSend = useCallback(() => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage && files.length === 0 && pastedTexts.length === 0) return;\n\n // Pasted text is shown as a card but still reaches the model in full: each\n // block is prepended to the message inside a delimiter the thread can parse\n // back out (see parsePastedBlocks in ChatMessages).\n const composedMessage =\n pastedTexts.length > 0\n ? [...pastedTexts.map(toPastedBlock), trimmedMessage]\n .filter(Boolean)\n .join('\\n\\n')\n : trimmedMessage;\n\n onSend(\n composedMessage,\n files.length > 0 ? files : undefined,\n transcriptId ? { transcriptId } : undefined,\n );\n setMessage('');\n setFiles([]);\n setPastedTexts([]);\n setTranscriptId(undefined);\n\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n }\n }, [message, files, pastedTexts, onSend, transcriptId]);\n // Keep a fresh send fn for the deferred handoff auto-send.\n handleSendRef.current = handleSend;\n\n // --- Speech-to-text handlers ---\n\n const clearPending = useCallback(() => {\n if (pendingRafRef.current !== null) {\n cancelAnimationFrame(pendingRafRef.current);\n pendingRafRef.current = null;\n }\n setPendingSend(false);\n setPendingProgress(1);\n }, []);\n\n // Fully exit the hands-free loop and stop any recording in progress.\n const cancelHandoff = useCallback(() => {\n handoffActiveRef.current = false;\n setHandoffActive(false);\n clearPending();\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current);\n inactivityTimerRef.current = null;\n }\n recording.cancel();\n }, [clearPending, recording]);\n\n // One-shot recording: transcribe → fill the textarea for manual review/send.\n // No hands-free loop, so the textarea stays available afterwards.\n const startOneShotRecording = useCallback(() => {\n setSpeechError(null);\n void recording.start();\n }, [recording]);\n\n // Arm the hands-free loop and start listening.\n const startHandsfreeRecording = useCallback(() => {\n setSpeechError(null);\n handoffActiveRef.current = true;\n setHandoffActive(true);\n void recording.start();\n }, [recording]);\n\n // Stop and reset the press-and-hold progress loop.\n const clearHold = useCallback(() => {\n if (holdRafRef.current !== null) {\n cancelAnimationFrame(holdRafRef.current);\n holdRafRef.current = null;\n }\n setIsHolding(false);\n setHoldProgress(0);\n }, []);\n\n // Mic pressed: when hands-free is available, run a hold timer whose ring fills\n // (0→1) over `holdMs`. Completing it activates hands-free; releasing earlier\n // (handleMicPointerUp) falls back to a one-shot recording. Pointer capture\n // keeps the release event on the button even if the finger drifts off.\n const handleMicPointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (disabled || isProcessing) return;\n try {\n e.currentTarget.setPointerCapture(e.pointerId);\n } catch {\n // ignore environments without pointer capture\n }\n const holdMs = speechHandoffHoldMs ?? HANDOFF_HOLD_MS;\n holdFiredRef.current = false;\n setIsHolding(true);\n setHoldProgress(0);\n const startedAt = Date.now();\n const step = () => {\n const progress = Math.min(1, (Date.now() - startedAt) / holdMs);\n setHoldProgress(progress);\n if (progress >= 1) {\n holdRafRef.current = null;\n holdFiredRef.current = true;\n setIsHolding(false);\n setHoldProgress(0);\n startHandsfreeRecording();\n return;\n }\n holdRafRef.current = requestAnimationFrame(step);\n };\n holdRafRef.current = requestAnimationFrame(step);\n },\n [disabled, isProcessing, speechHandoffHoldMs, startHandsfreeRecording],\n );\n\n // Mic released: if the hold already armed hands-free, do nothing; otherwise\n // treat it as a tap and start a one-shot recording.\n const handleMicPointerUp = useCallback(() => {\n if (holdFiredRef.current) {\n holdFiredRef.current = false;\n return;\n }\n if (holdRafRef.current === null && !isHolding) return; // already aborted\n clearHold();\n startOneShotRecording();\n }, [isHolding, clearHold, startOneShotRecording]);\n\n // Pointer cancelled (e.g. interrupted touch): abort the hold without recording.\n const handleMicPointerCancel = useCallback(() => {\n if (holdFiredRef.current) {\n holdFiredRef.current = false;\n return;\n }\n clearHold();\n }, [clearHold]);\n\n const cancelRecording = useCallback(() => {\n cancelHandoff();\n }, [cancelHandoff]);\n\n // Stop recording, transcribe the audio and fill the input for review.\n // Returns the trimmed transcription (or null if nothing was transcribed) so\n // the handoff loop can decide whether to auto-send or end.\n const confirmRecording = useCallback(async (): Promise<string | null> => {\n if (!transcribeClient) return null;\n const blob = await recording.stop();\n if (!blob || blob.size === 0) return null;\n\n setIsTranscribing(true);\n setSpeechError(null);\n try {\n const result = await transcribeClient.transcribeAudio(blob, {\n language: speechLanguage,\n tenantId: speechTenantId,\n });\n const text = (result.text || '').trim();\n if (text) {\n setMessage((prev) => (prev ? `${prev} ${text}`.trim() : text));\n setTranscriptId(result.transcriptId);\n }\n // Resize textarea and focus for review/edit.\n requestAnimationFrame(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n textarea.focus();\n }\n });\n return text;\n } catch (e) {\n setSpeechError(\n `Could not transcribe the audio: ${(e as Error)?.message || 'unknown error'}`,\n );\n return null;\n } finally {\n setIsTranscribing(false);\n }\n }, [transcribeClient, recording, speechLanguage, speechTenantId]);\n\n // Cancellable countdown, then auto-send. Handoff stays active across the send\n // so the loop can continue after the assistant replies.\n const startPendingSend = useCallback(() => {\n const totalMs = speechHandoffSendDelayMs ?? HANDOFF_PENDING_MS;\n setPendingSend(true);\n setPendingProgress(1);\n const startedAt = Date.now();\n const step = () => {\n const elapsed = Date.now() - startedAt;\n setPendingProgress(Math.max(0, 1 - elapsed / totalMs));\n if (elapsed >= totalMs) {\n pendingRafRef.current = null;\n setPendingSend(false);\n setPendingProgress(1);\n handleSendRef.current(); // auto-send with the freshest message\n return;\n }\n pendingRafRef.current = requestAnimationFrame(step);\n };\n pendingRafRef.current = requestAnimationFrame(step);\n }, [speechHandoffSendDelayMs]);\n\n // Drives both the mic auto-stop and the manual confirm button, branching on\n // whether the hands-free loop is active.\n const handleConfirm = useCallback(async () => {\n const text = await confirmRecording();\n if (!handoffActiveRef.current) return; // normal mode: input already filled\n if (!text) {\n // Silent / empty turn → end the hands-free loop.\n cancelHandoff();\n setMessage('');\n setTranscriptId(undefined);\n return;\n }\n startPendingSend();\n }, [confirmRecording, cancelHandoff, startPendingSend]);\n\n // Auto-stop fires handleConfirm with the freshest closure.\n useEffect(() => {\n confirmRef.current = () => void handleConfirm();\n }, [handleConfirm]);\n\n // Any interaction during the pending countdown cancels the auto-send and\n // exits the loop (the user is taking manual control); text stays for editing.\n useEffect(() => {\n if (!pendingSend) return;\n const onInteract = () => {\n clearPending();\n handoffActiveRef.current = false;\n setHandoffActive(false);\n requestAnimationFrame(() => textareaRef.current?.focus());\n };\n document.addEventListener('mousedown', onInteract, true);\n document.addEventListener('keydown', onInteract, true);\n return () => {\n document.removeEventListener('mousedown', onInteract, true);\n document.removeEventListener('keydown', onInteract, true);\n };\n }, [pendingSend, clearPending]);\n\n // When the assistant finishes (isProcessing falls) while the loop is active,\n // re-activate listening for the next turn.\n useEffect(() => {\n const wasProcessing = prevProcessingRef.current;\n prevProcessingRef.current = isProcessing;\n if (\n handoffActive &&\n wasProcessing &&\n !isProcessing &&\n !disabled &&\n !pendingSend &&\n !isTranscribing &&\n !recording.isRecording &&\n !recording.isPaused\n ) {\n void recording.start();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isProcessing, handoffActive, disabled, pendingSend, isTranscribing]);\n\n // While listening in handoff with no speech yet, end the loop after a silence\n // window (an open mic with nothing said means the user is done).\n useEffect(() => {\n if (!(handoffActive && recording.isRecording && !recording.speechDetected)) {\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current);\n inactivityTimerRef.current = null;\n }\n return;\n }\n inactivityTimerRef.current = setTimeout(() => {\n if (handoffActiveRef.current && !recording.speechDetected) cancelHandoff();\n }, HANDOFF_INACTIVITY_MS);\n return () => {\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current);\n inactivityTimerRef.current = null;\n }\n };\n }, [handoffActive, recording.isRecording, recording.speechDetected, cancelHandoff]);\n\n // Cleanup deferred work on unmount.\n useEffect(() => {\n return () => {\n if (pendingRafRef.current !== null) cancelAnimationFrame(pendingRafRef.current);\n if (inactivityTimerRef.current) clearTimeout(inactivityTimerRef.current);\n if (holdRafRef.current !== null) cancelAnimationFrame(holdRafRef.current);\n };\n }, []);\n\n // Handle key press\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend]\n );\n\n // Handle file selection\n const handleFileSelect = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n addFiles(Array.from(e.target.files || []));\n\n // Reset input\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n },\n [addFiles]\n );\n\n // Remove file\n const removeFile = useCallback((index: number) => {\n setFiles((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n // Remove a pasted-text card\n const removePastedText = useCallback((id: string) => {\n setPastedTexts((prev) => prev.filter((p) => p.id !== id));\n }, []);\n\n // Paste: files in the clipboard become attachments; a long block of plain\n // text becomes a card instead of flooding the textarea.\n const handlePaste = useCallback(\n (e: React.ClipboardEvent<HTMLTextAreaElement>) => {\n const clipboard = e.clipboardData;\n if (!clipboard) return;\n\n if (enableFileUploads) {\n const pastedFiles = Array.from(clipboard.items)\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((file): file is File => file !== null)\n .map((file) => {\n // Clipboard images share a generic name; give each one its own so\n // several pasted screenshots don't collapse into the same label.\n const ext = IMAGE_EXT_BY_MIME[file.type];\n if (!ext) return file;\n pasteCounterRef.current += 1;\n return new File([file], `pasted-image-${pasteCounterRef.current}.${ext}`, {\n type: file.type,\n });\n });\n\n if (pastedFiles.length > 0) {\n e.preventDefault();\n addFiles(pastedFiles);\n return;\n }\n }\n\n if (!enableLongTextPaste) return;\n\n const text = clipboard.getData('text/plain');\n if (text.length <= longTextPasteThreshold) return;\n\n e.preventDefault();\n pasteCounterRef.current += 1;\n setPastedTexts((prev) => [\n ...prev,\n { id: String(pasteCounterRef.current), text },\n ]);\n },\n [enableFileUploads, enableLongTextPaste, longTextPasteThreshold, addFiles]\n );\n\n // --- Drag & drop ---\n\n const handleDragEnter = useCallback(\n (e: React.DragEvent) => {\n if (!enableFileUploads || disabled) return;\n if (!e.dataTransfer.types.includes('Files')) return;\n e.preventDefault();\n dragDepthRef.current += 1;\n setIsDraggingOver(true);\n },\n [enableFileUploads, disabled]\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n if (!enableFileUploads || disabled) return;\n if (!e.dataTransfer.types.includes('Files')) return;\n // Without this the browser navigates away to open the dropped file.\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n },\n [enableFileUploads, disabled]\n );\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n dragDepthRef.current = Math.max(0, dragDepthRef.current - 1);\n if (dragDepthRef.current === 0) setIsDraggingOver(false);\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n if (!enableFileUploads || disabled) return;\n e.preventDefault();\n dragDepthRef.current = 0;\n setIsDraggingOver(false);\n addFiles(Array.from(e.dataTransfer.files || []));\n },\n [enableFileUploads, disabled, addFiles]\n );\n\n return (\n <div\n className=\"devic-input-area\"\n data-dragging={isDraggingOver ? 'true' : 'false'}\n onDragEnter={handleDragEnter}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n {isDraggingOver && (\n <div className=\"devic-drop-overlay\">\n <AttachIcon />\n <span>Drop files to attach</span>\n </div>\n )}\n {limitBanner}\n {usageBar}\n {disabledMessage && disabled && (\n <div className=\"devic-input-disabled-notice\">\n <WaitingIcon />\n {disabledMessage}\n </div>\n )}\n {speechError && (\n <div className=\"devic-speech-error\" role=\"alert\">\n {speechError}\n </div>\n )}\n {handoffActive && (\n <div className=\"devic-handoff-bar\" data-waiting={isProcessing ? 'true' : 'false'}>\n <span className=\"devic-handoff-dot\" aria-hidden=\"true\" />\n <span className=\"devic-handoff-label\">\n {isProcessing ? 'Hands-free · waiting for reply' : 'Hands-free on'}\n </span>\n <button\n type=\"button\"\n className=\"devic-handoff-stop\"\n onClick={cancelHandoff}\n title=\"Stop hands-free\"\n aria-label=\"Stop hands-free\"\n >\n <CloseIcon />\n </button>\n </div>\n )}\n {references && references.length > 0 && (\n <div className=\"devic-reference-chips\">\n {references.map((ref) => (\n <ReferenceChip\n key={ref.id}\n label={ref.label}\n variant=\"input\"\n onRemove={() => onRemoveReference?.(ref.id)}\n />\n ))}\n </div>\n )}\n {pastedTexts.length > 0 && (\n <div className=\"devic-pasted-cards\">\n {pastedTexts.map((pasted) => (\n <div key={pasted.id} className=\"devic-pasted-card\">\n <p className=\"devic-pasted-card-preview\">\n {pastedPreview(pasted.text)}\n </p>\n <div className=\"devic-pasted-card-footer\">\n <span className=\"devic-pasted-card-badge\">PASTED</span>\n <span className=\"devic-pasted-card-meta\">\n {pastedLineCount(pasted.text)} lines\n </span>\n </div>\n <button\n className=\"devic-file-remove devic-pasted-card-remove\"\n onClick={() => removePastedText(pasted.id)}\n type=\"button\"\n title=\"Remove pasted text\"\n aria-label=\"Remove pasted text\"\n >\n &times;\n </button>\n </div>\n ))}\n </div>\n )}\n {files.length > 0 && (\n <div className=\"devic-file-preview\">\n {files.map((file, idx) => (\n <div key={idx} className=\"devic-file-preview-item\">\n {filePreviews[idx] ? (\n <img\n className=\"devic-file-preview-thumb\"\n src={filePreviews[idx]!}\n alt={file.name}\n />\n ) : (\n <FileIcon />\n )}\n <span>{file.name}</span>\n <button\n className=\"devic-file-remove\"\n onClick={() => removeFile(idx)}\n type=\"button\"\n >\n &times;\n </button>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"devic-input-wrapper\">\n {pendingSend ? (\n <div className=\"devic-speech-panel\" data-state=\"pending\">\n <div className=\"devic-handoff-pending\">\n <div className=\"devic-handoff-pending-icon\">\n <SendCountdownRing progress={pendingProgress} />\n <SendIcon />\n </div>\n <div className=\"devic-handoff-pending-text\">\n <span className=\"devic-handoff-pending-title\">\n Sending… interact to cancel\n </span>\n {message.trim() && (\n <span className=\"devic-handoff-pending-preview\">{message.trim()}</span>\n )}\n </div>\n </div>\n </div>\n ) : isTranscribing ? (\n <div className=\"devic-speech-panel\" data-state=\"processing\">\n <span className=\"devic-speech-spinner\" aria-hidden=\"true\" />\n <span className=\"devic-speech-status\">Transcribing…</span>\n </div>\n ) : isRecordingActive ? (\n <div className=\"devic-speech-panel\" data-state=\"recording\">\n <button\n className=\"devic-input-btn devic-speech-cancel\"\n onClick={cancelRecording}\n type=\"button\"\n title=\"Cancel recording\"\n >\n <CloseIcon />\n </button>\n <div className=\"devic-speech-live\">\n <Equalizer levels={recording.levels} paused={recording.isPaused} />\n <span className=\"devic-speech-timer\">\n {formatDuration(recording.durationMs)}\n </span>\n </div>\n <button\n className=\"devic-input-btn\"\n onClick={recording.isPaused ? recording.resume : recording.pause}\n type=\"button\"\n title={recording.isPaused ? 'Resume' : 'Pause'}\n >\n {recording.isPaused ? <PlayIcon /> : <PauseIcon />}\n </button>\n <div\n className=\"devic-speech-confirm-wrap\"\n data-autostop={recording.isAutoStopping ? 'true' : 'false'}\n >\n {recording.isAutoStopping && (\n <AutoStopRing progress={recording.autoStopProgress} />\n )}\n <button\n className=\"devic-input-btn devic-speech-confirm\"\n onClick={() => void handleConfirm()}\n type=\"button\"\n title={\n recording.isAutoStopping\n ? 'Auto-sending… keep talking to cancel'\n : 'Confirm'\n }\n >\n <CheckIcon />\n </button>\n </div>\n </div>\n ) : (\n <>\n {enableFileUploads && (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={acceptedTypes}\n multiple\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n <button\n className=\"devic-input-btn\"\n onClick={() => fileInputRef.current?.click()}\n disabled={disabled}\n type=\"button\"\n title=\"Attach file\"\n >\n <AttachIcon />\n </button>\n </>\n )}\n\n {speechEnabled && (\n <div\n className=\"devic-speech-mic-wrap\"\n data-holding={isHolding ? 'true' : 'false'}\n >\n {isHolding && <HoldRing progress={holdProgress} />}\n <button\n className=\"devic-input-btn devic-speech-mic\"\n onClick={speechHandoff ? undefined : startOneShotRecording}\n onPointerDown={speechHandoff ? handleMicPointerDown : undefined}\n onPointerUp={speechHandoff ? handleMicPointerUp : undefined}\n onPointerCancel={speechHandoff ? handleMicPointerCancel : undefined}\n disabled={disabled || isProcessing}\n type=\"button\"\n title={\n speechHandoff\n ? 'Tap to dictate · hold to start hands-free'\n : 'Record voice message'\n }\n >\n <MicIcon />\n </button>\n </div>\n )}\n\n <textarea\n ref={textareaRef}\n className=\"devic-input\"\n value={message}\n onChange={(e) => {\n const value = e.target.value;\n setMessage(value);\n // If the user clears the field, drop the transcript link so a fresh\n // message isn't wrongly attributed to the previous transcription.\n if (transcriptId && value.trim() === '') setTranscriptId(undefined);\n handleInput();\n }}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder}\n disabled={disabled}\n rows={1}\n />\n\n {isProcessing ? (\n stopButtonContent ? (\n <div className=\"devic-send-btn-wrapper\">\n <div className=\"devic-send-btn-custom\" aria-hidden=\"true\">\n {stopButtonContent}\n </div>\n <button\n className=\"devic-send-btn-overlay\"\n onClick={onStop}\n type=\"button\"\n title=\"Stop\"\n />\n </div>\n ) : (\n <button\n className=\"devic-input-btn devic-stop-btn\"\n onClick={onStop}\n type=\"button\"\n title=\"Stop\"\n >\n <StopIcon />\n </button>\n )\n ) : sendButtonContent ? (\n <div className=\"devic-send-btn-wrapper\">\n <div className=\"devic-send-btn-custom\" aria-hidden=\"true\">\n {sendButtonContent}\n </div>\n <button\n className=\"devic-send-btn-overlay\"\n onClick={handleSend}\n disabled={disabled || (!message.trim() && files.length === 0 && pastedTexts.length === 0)}\n type=\"button\"\n title=\"Send message\"\n />\n </div>\n ) : (\n <button\n className=\"devic-input-btn devic-send-btn\"\n onClick={handleSend}\n disabled={disabled || (!message.trim() && files.length === 0 && pastedTexts.length === 0)}\n type=\"button\"\n title=\"Send message\"\n >\n <SendIcon />\n </button>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Live equalizer rendered from the recording amplitude levels (0..1 per bar).\n * When paused, bars collapse to a flat baseline.\n */\nfunction Equalizer({\n levels,\n paused,\n}: {\n levels: number[];\n paused: boolean;\n}): JSX.Element {\n return (\n <div className=\"devic-equalizer\" aria-hidden=\"true\" data-paused={paused}>\n {levels.map((level, i) => (\n <span\n key={i}\n className=\"devic-equalizer-bar\"\n style={{ height: `${Math.max(10, Math.round((paused ? 0 : level) * 100))}%` }}\n />\n ))}\n </div>\n );\n}\n\n// Geometry for the auto-stop ring drawn around the confirm button.\nconst AUTOSTOP_RING_R = 18;\nconst AUTOSTOP_RING_C = 2 * Math.PI * AUTOSTOP_RING_R;\n\n/**\n * Inverted circular progress drawn around the confirm button. Driven by\n * `progress` (1 → 0): a full ring that drains to empty over the countdown.\n */\nfunction AutoStopRing({ progress }: { progress: number }): JSX.Element {\n return (\n <svg className=\"devic-autostop-ring\" viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <circle\n className=\"devic-autostop-ring-track\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n />\n <circle\n className=\"devic-autostop-ring-progress\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n style={{\n strokeDasharray: AUTOSTOP_RING_C,\n strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),\n }}\n />\n </svg>\n );\n}\n\n/**\n * Draining ring around the send icon during the handoff pending countdown.\n * Visually distinct from the auto-stop ring (slate→primary track, larger).\n */\nfunction SendCountdownRing({ progress }: { progress: number }): JSX.Element {\n return (\n <svg className=\"devic-handoff-ring\" viewBox=\"0 0 44 44\" aria-hidden=\"true\">\n <circle className=\"devic-handoff-ring-track\" cx=\"22\" cy=\"22\" r={AUTOSTOP_RING_R} />\n <circle\n className=\"devic-handoff-ring-progress\"\n cx=\"22\"\n cy=\"22\"\n r={AUTOSTOP_RING_R}\n style={{\n strokeDasharray: AUTOSTOP_RING_C,\n strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),\n }}\n />\n </svg>\n );\n}\n\n/**\n * Filling ring drawn around the mic button while the user presses and holds to\n * arm hands-free. Driven by `progress` (0 → 1): an empty ring that fills\n * clockwise over the hold duration. Inverse of the draining auto-stop ring.\n */\nfunction HoldRing({ progress }: { progress: number }): JSX.Element {\n return (\n <svg className=\"devic-mic-hold-ring\" viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <circle\n className=\"devic-mic-hold-ring-track\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n />\n <circle\n className=\"devic-mic-hold-ring-progress\"\n cx=\"20\"\n cy=\"20\"\n r={AUTOSTOP_RING_R}\n style={{\n strokeDasharray: AUTOSTOP_RING_C,\n strokeDashoffset: AUTOSTOP_RING_C * (1 - progress),\n }}\n />\n </svg>\n );\n}\n\n/** Formats milliseconds as m:ss. */\nfunction formatDuration(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n}\n\n/**\n * Attach icon\n */\nfunction AttachIcon(): 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 <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48\" />\n </svg>\n );\n}\n\n/**\n * Send icon\n */\nfunction SendIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\n </svg>\n );\n}\n\n/**\n * File icon\n */\nfunction FileIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14,2 14,8 20,8\" />\n </svg>\n );\n}\n\n/**\n * Microphone icon\n */\nfunction MicIcon(): 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 <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\n </svg>\n );\n}\n\n/**\n * Pause icon (two bars)\n */\nfunction PauseIcon(): JSX.Element {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\" />\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\" />\n </svg>\n );\n}\n\n/**\n * Play icon (triangle)\n */\nfunction PlayIcon(): JSX.Element {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n );\n}\n\n/**\n * Check icon (confirm)\n */\nfunction CheckIcon(): 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.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\n/**\n * Close icon (cancel)\n */\nfunction CloseIcon(): 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.5\"\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 * Stop icon (square)\n */\nfunction StopIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" />\n </svg>\n );\n}\n\n/**\n * Waiting icon (clock)\n */\nfunction WaitingIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12,6 12,12 16,14\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
@@ -9,6 +9,12 @@ import { segmentToolCalls } from '../../utils/toolGroups.js';
9
9
  import { DevicApiClient } from '../../api/client.js';
10
10
  import { parsePastedBlocks, pastedPreview, pastedLineCount } from './pastedText.js';
11
11
 
12
+ // Backend finalizer tool for assistants configured with "Require Tool Use to
13
+ // Finish". It carries the final answer in its `message` argument, which the
14
+ // backend copies to content.message, so it renders as a plain assistant bubble
15
+ // instead of a tool activity line. Agents have a same-named tool with a
16
+ // different shape, but their timeline does not go through this component.
17
+ const FINISH_EXECUTION_TOOL = "finish_execution";
12
18
  /**
13
19
  * Format timestamp to readable time
14
20
  */
@@ -130,7 +136,13 @@ function groupMessages(messages, isLoading) {
130
136
  if (msg.role === "developer" || msg.role === "system" || msg.role === "tool") {
131
137
  continue;
132
138
  }
133
- const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
139
+ // `finish_execution` is not an action the assistant took, it is how the
140
+ // backend delivers the final answer when the assistant is configured with
141
+ // "Require Tool Use to Finish": the tool's `message` argument is copied to
142
+ // content.message and rendered as the assistant bubble below. Showing it as
143
+ // a tool activity line would just duplicate that bubble with plumbing.
144
+ const visibleToolCalls = (msg.tool_calls || []).filter((toolCall) => toolCall.function?.name !== FINISH_EXECUTION_TOOL);
145
+ const hasToolCalls = visibleToolCalls.length > 0;
134
146
  const hasText = !!msg.content?.message;
135
147
  const hasFiles = msg.content?.files && msg.content.files.length > 0;
136
148
  if (hasToolCalls) {
@@ -145,7 +157,9 @@ function groupMessages(messages, isLoading) {
145
157
  result.push({ type: "message", message: msg });
146
158
  }
147
159
  // Always accumulate the tool call
148
- currentToolGroup.push(msg);
160
+ currentToolGroup.push(visibleToolCalls.length === msg.tool_calls.length
161
+ ? msg
162
+ : { ...msg, tool_calls: visibleToolCalls });
149
163
  }
150
164
  else {
151
165
  // Regular message → flush any accumulated tool group first