@devicai/ui 0.37.1 → 0.38.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.
Files changed (38) hide show
  1. package/README.md +53 -0
  2. package/dist/cjs/api/client.js +44 -0
  3. package/dist/cjs/api/client.js.map +1 -1
  4. package/dist/cjs/api/types.js.map +1 -1
  5. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +32 -2
  6. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  7. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js +6 -2
  8. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  9. package/dist/cjs/components/IntegrationsModal/IntegrationsModal.js +248 -0
  10. package/dist/cjs/components/IntegrationsModal/IntegrationsModal.js.map +1 -0
  11. package/dist/cjs/components/theme.js +33 -0
  12. package/dist/cjs/components/theme.js.map +1 -0
  13. package/dist/cjs/index.js +4 -0
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/styles.css +1 -1
  16. package/dist/esm/api/client.d.ts +45 -1
  17. package/dist/esm/api/client.js +44 -0
  18. package/dist/esm/api/client.js.map +1 -1
  19. package/dist/esm/api/types.d.ts +32 -0
  20. package/dist/esm/api/types.js.map +1 -1
  21. package/dist/esm/components/ChatDrawer/ChatDrawer.js +32 -2
  22. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  23. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +14 -0
  24. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.d.ts +8 -1
  25. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js +6 -2
  26. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  27. package/dist/esm/components/IntegrationsModal/IntegrationsModal.d.ts +47 -0
  28. package/dist/esm/components/IntegrationsModal/IntegrationsModal.js +246 -0
  29. package/dist/esm/components/IntegrationsModal/IntegrationsModal.js.map +1 -0
  30. package/dist/esm/components/IntegrationsModal/index.d.ts +2 -0
  31. package/dist/esm/components/theme.d.ts +33 -0
  32. package/dist/esm/components/theme.js +31 -0
  33. package/dist/esm/components/theme.js.map +1 -0
  34. package/dist/esm/index.d.ts +5 -1
  35. package/dist/esm/index.js +2 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/styles.css +1 -1
  38. package/package.json +1 -1
@@ -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 * 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 * Original server uid, present when the UI adopted an optimistic uid for\n * this message to keep React keys stable. Server-side references (e.g.\n * memory recall anchors) match against it.\n */\n serverUid?: 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/** One fact a long-term-memory recall surfaced. */\nexport interface RecalledMemoryFact {\n fact: string;\n relation: string;\n /** Source entity name of the graph edge, when the fact connects two. */\n source: string | null;\n /** Target entity name of the graph edge, when the fact connects two. */\n target: string | null;\n /** ISO date the fact became valid, if known. */\n validAt: string | null;\n}\n\n/** One graph entity a long-term-memory recall surfaced. */\nexport interface RecalledMemoryEntity {\n id: string;\n name: string;\n type: string;\n summary: string | null;\n}\n\n/** One previous-session turn a conversation-start recall carried over. */\nexport interface RecalledMemoryTurn {\n role: string;\n content: string;\n}\n\n/**\n * One structured long-term-memory recall event of a conversation: the facts,\n * entities and previous-session turns a recall surfaced, plus the uid of the\n * message that brought it in (`messageUid`: the initial user message, or the\n * assistant message carrying the memory tool call — resolvable through\n * `toolCallId` while the run is still in flight).\n */\nexport interface RecalledMemoryRecord {\n uid: string;\n messageUid?: string;\n toolCallId?: string;\n source:\n | 'conversation_start'\n | 'search_memory'\n | 'search_memory_nodes'\n | 'explore_memory_graph';\n query?: string;\n facts?: RecalledMemoryFact[];\n entities?: RecalledMemoryEntity[];\n turns?: RecalledMemoryTurn[];\n timestampMs: number;\n}\n\n/**\n * Snapshot of the core-memory block a conversation saw (audit trail): the\n * render revision plus the injected entries as structured items.\n */\nexport interface CoreMemorySnapshot {\n uid: string;\n revision: string;\n items: Array<{\n id: number;\n section: string;\n content: string;\n pinned: boolean;\n source: string;\n }>;\n entries: number;\n omitted: number;\n chars: number;\n timestampMs: 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 * Memory-recall events of the in-flight run — lets the UI show what the\n * assistant is recalling while the response is still processing.\n */\n recalledMemories?: RecalledMemoryRecord[];\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 /** Structured long-term-memory recall events of the conversation. */\n recalledMemories?: RecalledMemoryRecord[];\n /** Audit trail of the core-memory blocks the conversation saw. */\n coreMemories?: CoreMemorySnapshot[];\n}\n\n/** One core memory entry (the always-injected tier), as returned by the memory API. */\nexport interface CoreMemoryEntry {\n id: number;\n section: string;\n content: string;\n source: string;\n pinned: boolean;\n supersedes: number | null;\n archivedAt: string | null;\n createdAt?: string;\n updatedAt?: string;\n}\n\n/** Deployment caps of the core memory tier. */\nexport interface CoreMemoryLimits {\n maxChars: number;\n maxEntries: number;\n maxEntryChars: number;\n}\n\n/**\n * Response of GET /api/v1/memory/assistants/:identifier/core — the entries\n * of the bucket the assistant resolves for a tenant/subtenant combination.\n */\nexport interface CoreMemoryList {\n /** False when the assistant does not have the core memory tier enabled. */\n enabled: boolean;\n /** The resolved bucket tuple (tenant/subtenant/owner dimensions). */\n bucket: { tenantId?: string; subtenantId?: string; entityId?: string };\n entries: CoreMemoryEntry[];\n limits?: CoreMemoryLimits;\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;AAgiBA;;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 * Original server uid, present when the UI adopted an optimistic uid for\n * this message to keep React keys stable. Server-side references (e.g.\n * memory recall anchors) match against it.\n */\n serverUid?: 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/** One fact a long-term-memory recall surfaced. */\nexport interface RecalledMemoryFact {\n fact: string;\n relation: string;\n /** Source entity name of the graph edge, when the fact connects two. */\n source: string | null;\n /** Target entity name of the graph edge, when the fact connects two. */\n target: string | null;\n /** ISO date the fact became valid, if known. */\n validAt: string | null;\n}\n\n/** One graph entity a long-term-memory recall surfaced. */\nexport interface RecalledMemoryEntity {\n id: string;\n name: string;\n type: string;\n summary: string | null;\n}\n\n/** One previous-session turn a conversation-start recall carried over. */\nexport interface RecalledMemoryTurn {\n role: string;\n content: string;\n}\n\n/**\n * One structured long-term-memory recall event of a conversation: the facts,\n * entities and previous-session turns a recall surfaced, plus the uid of the\n * message that brought it in (`messageUid`: the initial user message, or the\n * assistant message carrying the memory tool call — resolvable through\n * `toolCallId` while the run is still in flight).\n */\nexport interface RecalledMemoryRecord {\n uid: string;\n messageUid?: string;\n toolCallId?: string;\n source:\n | 'conversation_start'\n | 'search_memory'\n | 'search_memory_nodes'\n | 'explore_memory_graph';\n query?: string;\n facts?: RecalledMemoryFact[];\n entities?: RecalledMemoryEntity[];\n turns?: RecalledMemoryTurn[];\n timestampMs: number;\n}\n\n/**\n * Snapshot of the core-memory block a conversation saw (audit trail): the\n * render revision plus the injected entries as structured items.\n */\nexport interface CoreMemorySnapshot {\n uid: string;\n revision: string;\n items: Array<{\n id: number;\n section: string;\n content: string;\n pinned: boolean;\n source: string;\n }>;\n entries: number;\n omitted: number;\n chars: number;\n timestampMs: 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 * Memory-recall events of the in-flight run — lets the UI show what the\n * assistant is recalling while the response is still processing.\n */\n recalledMemories?: RecalledMemoryRecord[];\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 /** Structured long-term-memory recall events of the conversation. */\n recalledMemories?: RecalledMemoryRecord[];\n /** Audit trail of the core-memory blocks the conversation saw. */\n coreMemories?: CoreMemorySnapshot[];\n}\n\n/** One core memory entry (the always-injected tier), as returned by the memory API. */\nexport interface CoreMemoryEntry {\n id: number;\n section: string;\n content: string;\n source: string;\n pinned: boolean;\n supersedes: number | null;\n archivedAt: string | null;\n createdAt?: string;\n updatedAt?: string;\n}\n\n/** Deployment caps of the core memory tier. */\nexport interface CoreMemoryLimits {\n maxChars: number;\n maxEntries: number;\n maxEntryChars: number;\n}\n\n/**\n * Response of GET /api/v1/memory/assistants/:identifier/core — the entries\n * of the bucket the assistant resolves for a tenant/subtenant combination.\n */\nexport interface CoreMemoryList {\n /** False when the assistant does not have the core memory tier enabled. */\n enabled: boolean;\n /** The resolved bucket tuple (tenant/subtenant/owner dimensions). */\n bucket: { tenantId?: string; subtenantId?: string; entityId?: string };\n entries: CoreMemoryEntry[];\n limits?: CoreMemoryLimits;\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\n/**\n * One of the end user's connected accounts for an app.\n *\n * The provider's own identifiers do not travel here beyond `id`, which the\n * client needs in order to name the account it wants disconnected — and which\n * the server re-checks against the caller's tenant on the way back in.\n */\nexport interface IntegrationAccount {\n id: string;\n status: string;\n connectedAt?: string;\n updatedAt?: string;\n /** True when the account exists but can no longer run tools. */\n needsReconnect?: boolean;\n statusReason?: string;\n}\n\n/**\n * An app the assistant offers to its tenants, with the accounts THIS tenant\n * has connected. Never another tenant's.\n */\nexport interface Integration {\n /** App slug, e.g. `gmail`. */\n app: string;\n name: string;\n description?: string;\n logo?: string;\n /** True when at least one account is active. */\n connected: boolean;\n accounts: IntegrationAccount[];\n /** Event types the developer allows this tenant to switch on. */\n availableTriggers?: string[];\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;AAgiBA;;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;;;;"}
@@ -10,6 +10,7 @@ import { ChatDrawerErrorBoundary } from './ErrorBoundary.js';
10
10
  import { UsageBar } from './UsageBar.js';
11
11
  import { LimitBanner } from './LimitBanner.js';
12
12
  import { CoreMemoryModal } from '../CoreMemoryModal/CoreMemoryModal.js';
13
+ import { IntegrationsModal } from '../IntegrationsModal/IntegrationsModal.js';
13
14
 
14
15
  const DEFAULT_OPTIONS = {
15
16
  position: 'right',
@@ -77,6 +78,8 @@ const DEFAULT_OPTIONS = {
77
78
  showRecalledMemories: true,
78
79
  recalledMemoriesRenderer: undefined,
79
80
  showCoreMemoryButton: false,
81
+ showIntegrationsButton: false,
82
+ integrationsLabel: 'Connected apps',
80
83
  };
81
84
  /**
82
85
  * Chat drawer component for Devic assistants
@@ -168,6 +171,7 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
168
171
  const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';
169
172
  const [avatarUrl, setAvatarUrl] = useState(null);
170
173
  const [coreMemoryOpen, setCoreMemoryOpen] = useState(false);
174
+ const [integrationsOpen, setIntegrationsOpen] = useState(false);
171
175
  const avatarFetchedRef = useRef(null);
172
176
  useEffect(() => {
173
177
  if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId)
@@ -385,6 +389,26 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
385
389
  }
386
390
  }
387
391
  }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);
392
+ // The same values, handed to the dialogs this drawer opens. They render
393
+ // through a portal into document.body, so the variables set above — which
394
+ // live on the drawer element — never reach them.
395
+ const modalTheme = useMemo(() => ({
396
+ color: mergedOptions.color !== DEFAULT_OPTIONS.color
397
+ ? mergedOptions.color
398
+ : undefined,
399
+ fontFamily: mergedOptions.fontFamily,
400
+ backgroundColor: mergedOptions.backgroundColor,
401
+ textColor: mergedOptions.textColor,
402
+ secondaryBackgroundColor: mergedOptions.secondaryBackgroundColor,
403
+ borderColor: mergedOptions.borderColor,
404
+ }), [
405
+ mergedOptions.color,
406
+ mergedOptions.fontFamily,
407
+ mergedOptions.backgroundColor,
408
+ mergedOptions.textColor,
409
+ mergedOptions.secondaryBackgroundColor,
410
+ mergedOptions.borderColor,
411
+ ]);
388
412
  // Resizable drawer
389
413
  const [resizedWidth, setResizedWidth] = useState(null);
390
414
  const handleResizeStart = useCallback((e) => {
@@ -427,7 +451,7 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
427
451
  [mergedOptions.position]: 20,
428
452
  bottom: 20,
429
453
  }), [mergedOptions.zIndex, mergedOptions.position]);
430
- return (jsxs(Fragment, { children: [!isInline && (jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose })), jsxs("div", { ref: drawerRef, className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, "data-mode": mode, style: drawerStyle, children: [mergedOptions.resizable && (jsx("div", { className: "devic-resize-handle", "data-position": mergedOptions.position, onMouseDown: handleResizeStart })), jsxs("div", { className: "devic-drawer-header", children: [avatarUrl && (jsx("img", { className: "devic-drawer-avatar", src: avatarUrl, alt: "", "aria-hidden": "true" })), jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsx(ConversationSelector, { assistantId: assistantId, currentChatUid: chat.chatUid, onSelect: handleConversationSelect, onNewChat: handleNewChat, apiKey: apiKey, baseUrl: baseUrl, tenantId: tenantId, subtenantId: subtenantId, conversationPreview: mergedOptions.conversationPreview }), jsxs("div", { className: "devic-drawer-header-actions", children: [mergedOptions.showCoreMemoryButton && (jsx("button", { className: "devic-new-chat-btn", onClick: () => setCoreMemoryOpen(true), type: "button", "aria-label": "Assistant memory", title: "Assistant memory", children: jsx(BrainIcon, {}) })), jsx("button", { className: "devic-new-chat-btn", onClick: handleNewChat, type: "button", "aria-label": "New chat", title: "New chat", children: jsx(PlusIcon, {}) }), !isInline && (jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsx(CloseIcon, {}) }))] })] }), chat.error && (jsx("div", { className: "devic-error", children: chat.error.message })), jsx(ChatMessages, { messages: chat.messages, allMessages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline, toolRenderers: mergedOptions.toolRenderers, toolIcons: mergedOptions.toolIcons, loadingIndicator: mergedOptions.loadingIndicator, showFeedback: mergedOptions.showFeedback, feedbackMap: feedbackMap, onFeedback: handleFeedback, handedOffSubThreadId: chat.handedOffSubThreadId || undefined, onHandoffCompleted: chat.onHandoffCompleted, handoffWidgetRenderer: mergedOptions.handoffWidgetRenderer, toolGroups: mergedOptions.toolGroups, userMessageRenderer: mergedOptions.userMessageRenderer, assistantMessageRenderer: mergedOptions.assistantMessageRenderer, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, pendingInlineWidgets: inlineWidgets, onSubmitWidget: chat.submitWidgetResponse, onCancelWidget: chat.cancelWidgetCall, recalledMemories: mergedOptions.showRecalledMemories
454
+ return (jsxs(Fragment, { children: [!isInline && (jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose })), jsxs("div", { ref: drawerRef, className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, "data-mode": mode, style: drawerStyle, children: [mergedOptions.resizable && (jsx("div", { className: "devic-resize-handle", "data-position": mergedOptions.position, onMouseDown: handleResizeStart })), jsxs("div", { className: "devic-drawer-header", children: [avatarUrl && (jsx("img", { className: "devic-drawer-avatar", src: avatarUrl, alt: "", "aria-hidden": "true" })), jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsx(ConversationSelector, { assistantId: assistantId, currentChatUid: chat.chatUid, onSelect: handleConversationSelect, onNewChat: handleNewChat, apiKey: apiKey, baseUrl: baseUrl, tenantId: tenantId, subtenantId: subtenantId, conversationPreview: mergedOptions.conversationPreview }), jsxs("div", { className: "devic-drawer-header-actions", children: [mergedOptions.showIntegrationsButton && (jsx("button", { className: "devic-new-chat-btn", onClick: () => setIntegrationsOpen(true), type: "button", "aria-label": mergedOptions.integrationsLabel, title: mergedOptions.integrationsLabel, children: jsx(PlugIcon, {}) })), mergedOptions.showCoreMemoryButton && (jsx("button", { className: "devic-new-chat-btn", onClick: () => setCoreMemoryOpen(true), type: "button", "aria-label": "Assistant memory", title: "Assistant memory", children: jsx(BrainIcon, {}) })), jsx("button", { className: "devic-new-chat-btn", onClick: handleNewChat, type: "button", "aria-label": "New chat", title: "New chat", children: jsx(PlusIcon, {}) }), !isInline && (jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsx(CloseIcon, {}) }))] })] }), chat.error && (jsx("div", { className: "devic-error", children: chat.error.message })), jsx(ChatMessages, { messages: chat.messages, allMessages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline, toolRenderers: mergedOptions.toolRenderers, toolIcons: mergedOptions.toolIcons, loadingIndicator: mergedOptions.loadingIndicator, showFeedback: mergedOptions.showFeedback, feedbackMap: feedbackMap, onFeedback: handleFeedback, handedOffSubThreadId: chat.handedOffSubThreadId || undefined, onHandoffCompleted: chat.onHandoffCompleted, handoffWidgetRenderer: mergedOptions.handoffWidgetRenderer, toolGroups: mergedOptions.toolGroups, userMessageRenderer: mergedOptions.userMessageRenderer, assistantMessageRenderer: mergedOptions.assistantMessageRenderer, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, pendingInlineWidgets: inlineWidgets, onSubmitWidget: chat.submitWidgetResponse, onCancelWidget: chat.cancelWidgetCall, recalledMemories: mergedOptions.showRecalledMemories
431
455
  ? chat.recalledMemories
432
456
  : undefined, recalledMemoriesRenderer: mergedOptions.recalledMemoriesRenderer }), mergedOptions.customPromptBox ? (jsxs("div", { className: "devic-input-area", children: [limitBannerNode, usageBarNode, mergedOptions.customPromptBox({
433
457
  sendMessage: handleSend,
@@ -446,11 +470,17 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
446
470
  ? 'Waiting for subagent to complete'
447
471
  : inlineWidgets.length > 0
448
472
  ? 'Waiting for tool response'
449
- : undefined, isProcessing: chat.isLoading && !chat.handedOff, onStop: chat.stopChat, stopButtonContent: mergedOptions.stopButtonContent, pendingInputWidget: inputWidget, onSubmitWidget: chat.submitWidgetResponse, onCancelWidget: chat.cancelWidgetCall, references: references, onRemoveReference: removeReference, usageBar: usageBarNode, limitBanner: limitBannerNode }))] }), !isInline && !isOpen && (jsx("button", { className: "devic-trigger", onClick: handleOpen, style: triggerStyle, type: "button", "aria-label": "Open chat", children: jsx(ChatIcon, {}) })), mergedOptions.showCoreMemoryButton && (jsx(CoreMemoryModal, { isOpen: coreMemoryOpen, onClose: () => setCoreMemoryOpen(false), assistantId: assistantId, tenantId: tenantId, subtenantId: subtenantId, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl }))] }));
473
+ : undefined, isProcessing: chat.isLoading && !chat.handedOff, onStop: chat.stopChat, stopButtonContent: mergedOptions.stopButtonContent, pendingInputWidget: inputWidget, onSubmitWidget: chat.submitWidgetResponse, onCancelWidget: chat.cancelWidgetCall, references: references, onRemoveReference: removeReference, usageBar: usageBarNode, limitBanner: limitBannerNode }))] }), !isInline && !isOpen && (jsx("button", { className: "devic-trigger", onClick: handleOpen, style: triggerStyle, type: "button", "aria-label": "Open chat", children: jsx(ChatIcon, {}) })), mergedOptions.showCoreMemoryButton && (jsx(CoreMemoryModal, { isOpen: coreMemoryOpen, onClose: () => setCoreMemoryOpen(false), assistantId: assistantId, tenantId: tenantId, subtenantId: subtenantId, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, theme: modalTheme })), mergedOptions.showIntegrationsButton && (jsx(IntegrationsModal, { isOpen: integrationsOpen, onClose: () => setIntegrationsOpen(false), assistantId: assistantId, tenantId: tenantId, subtenantId: subtenantId, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, title: mergedOptions.integrationsLabel, theme: modalTheme }))] }));
450
474
  }
451
475
  /**
452
476
  * Close icon
453
477
  */
478
+ /**
479
+ * Plug icon for the connected-apps button
480
+ */
481
+ function PlugIcon() {
482
+ return (jsxs("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M12 22v-5" }), jsx("path", { d: "M9 8V2" }), jsx("path", { d: "M15 8V2" }), jsx("path", { d: "M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z" })] }));
483
+ }
454
484
  /**
455
485
  * Brain icon for the core memory button
456
486
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ChatDrawer.js","sources":["../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport { ConversationSelector } from './ConversationSelector';\nimport { ChatDrawerErrorBoundary } from './ErrorBoundary';\nimport { UsageBar } from './UsageBar';\nimport { LimitBanner } from './LimitBanner';\nimport { CoreMemoryModal } from '../CoreMemoryModal';\nimport type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: '100%',\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n enableLongTextPaste: false,\n longTextPasteThreshold: 2000,\n enableSpeechToText: false,\n speechLanguage: undefined as any,\n speechAutoStop: true,\n speechAutoStopCountdownMs: 1000,\n speechAutoStopSilenceMs: 1000,\n speechAutoStopSilenceRatio: 0.1,\n speechAutoStopSilenceLevel: 0.02,\n speechAutoStopSpeechLevel: 0.12,\n speechHandoff: false,\n speechHandoffSendDelayMs: 1000,\n speechHandoffHoldMs: 3000,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showAvatar: false,\n showToolTimeline: true,\n zIndex: 1000,\n borderRadius: 0,\n resizable: false,\n minWidth: 300,\n maxWidth: 800,\n style: {},\n fontFamily: undefined as any,\n backgroundColor: undefined as any,\n textColor: undefined as any,\n secondaryBackgroundColor: undefined as any,\n borderColor: undefined as any,\n userBubbleColor: undefined as any,\n userBubbleTextColor: undefined as any,\n assistantBubbleColor: undefined as any,\n assistantBubbleTextColor: undefined as any,\n sendButtonColor: undefined as any,\n loadingIndicator: undefined as any,\n sendButtonContent: undefined as any,\n toolRenderers: undefined as any,\n toolIcons: undefined as any,\n showFeedback: true,\n handoffWidgetRenderer: undefined as any,\n toolGroups: undefined as any,\n stopButtonContent: undefined as any,\n debug: false,\n persistConversation: false,\n customPromptBox: undefined as any,\n userMessageRenderer: undefined as any,\n assistantMessageRenderer: undefined as any,\n conversationPreview: 'date',\n showUsageBar: false,\n usageBarMetric: undefined as any,\n usageBarDisplay: undefined as any,\n customUsageBar: undefined as any,\n hideLimitBanner: false,\n limitBannerRenderer: undefined as any,\n showRecalledMemories: true,\n recalledMemoriesRenderer: undefined as any,\n showCoreMemoryButton: false,\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * ref={drawerRef}\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport const ChatDrawer = forwardRef<ChatDrawerHandle, ChatDrawerProps>(\n function ChatDrawer(props, ref) {\n return (\n <ChatDrawerErrorBoundary>\n <ChatDrawerInner {...props} forwardedRef={ref} />\n </ChatDrawerErrorBoundary>\n );\n }\n);\n\ninterface ChatDrawerInnerProps extends ChatDrawerProps {\n forwardedRef?: React.Ref<ChatDrawerHandle>;\n}\n\nfunction ChatDrawerInner({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n mode = 'drawer',\n onConversationChange,\n forwardedRef,\n}: ChatDrawerInnerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // localStorage key for persisting selected conversation\n const storageKey = mergedOptions.persistConversation\n ? `devic-ui-chatUid-${assistantId}`\n : null;\n\n // Resolve initial chatUid: prop takes priority, then localStorage\n const resolvedInitialChatUid = useMemo(() => {\n if (initialChatUid) return initialChatUid;\n if (storageKey) {\n try { return localStorage.getItem(storageKey) || undefined; } catch { return undefined; }\n }\n return undefined;\n }, [initialChatUid, storageKey]);\n\n // Drawer open state (can be controlled or uncontrolled; inline mode is always open)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isInline = mode === 'inline';\n const isOpen = isInline ? true : (controlledIsOpen ?? internalIsOpen);\n\n // Wrap onChatCreated to persist chatUid in localStorage\n const handleChatCreated = useCallback(\n (chatUid: string) => {\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n onChatCreated?.(chatUid);\n },\n [storageKey, onChatCreated]\n );\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: resolvedInitialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated: handleChatCreated,\n onFileUpload,\n debug: mergedOptions.debug,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const [coreMemoryOpen, setCoreMemoryOpen] = useState(false);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // Tenant/subtenant resolution mirrors useDevicChat (prop overrides provider).\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n\n // Usage bar (above the input) — only when enabled and a tenant is known.\n // Refetches after each turn via the message count as refresh key.\n const usageBarNode =\n (mergedOptions.showUsageBar ||\n typeof mergedOptions.customUsageBar === 'function') &&\n resolvedTenantId ? (\n <UsageBar\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n tenantId={resolvedTenantId}\n subtenantId={resolvedSubtenantId}\n mode={mergedOptions.showUsageBar === 'onDemand' ? 'onDemand' : 'always'}\n metric={mergedOptions.usageBarMetric}\n display={mergedOptions.usageBarDisplay}\n customUsageBar={mergedOptions.customUsageBar}\n color={mergedOptions.color}\n refreshKey={chat.messages.length}\n debug={mergedOptions.debug}\n />\n ) : null;\n\n // Default usage-limit banner (above the input) — opt-out via hideLimitBanner,\n // override via limitBannerRenderer.\n const limitBannerNode =\n chat.limitExceeded && !mergedOptions.hideLimitBanner\n ? mergedOptions.limitBannerRenderer\n ? mergedOptions.limitBannerRenderer(chat.limitExceeded)\n : <LimitBanner limit={chat.limitExceeded} />\n : null;\n\n // Speech-to-text transcription, exposed to custom prompt boxes so a developer\n // can transcribe audio (binary or URL) and attach the resulting transcriptId.\n const transcribeAudio = useCallback(\n (\n audio: Blob | string,\n transcribeOptions?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n },\n ) => {\n if (!resolvedApiKey) {\n return Promise.reject(\n new Error('API key not configured. Cannot transcribe audio.'),\n );\n }\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n return client.transcribeAudio(audio, {\n language: transcribeOptions?.language ?? mergedOptions.speechLanguage,\n messageUid: transcribeOptions?.messageUid,\n chatUid: transcribeOptions?.chatUid,\n tenantId: transcribeOptions?.tenantId ?? tenantId,\n });\n },\n [resolvedApiKey, resolvedBaseUrl, mergedOptions.speechLanguage, tenantId],\n );\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleToggle = useCallback(() => {\n setInternalIsOpen((prev) => !prev);\n }, []);\n\n // Expose handle for programmatic control\n useImperativeHandle(forwardedRef, () => ({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n setChatUid: (chatUid: string) => {\n chat.loadChat(chatUid);\n },\n sendMessage: (message: string) => {\n chat.sendMessage(message);\n },\n }), [handleOpen, handleClose, handleToggle, chat]);\n\n // Register this drawer in the DevicProvider so AIElementWrapper can open it\n useEffect(() => {\n if (!context?.registerDrawer) return;\n const unregister = context.registerDrawer({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n sendMessage: (message: string) => chat.sendMessage(message),\n });\n return unregister;\n }, [context, handleOpen, handleClose, handleToggle, chat]);\n\n // Partition pending widget calls by render mode\n const { inlineWidgets, inputWidget } = useMemo(() => {\n const inline: typeof chat.pendingWidgetCalls = [];\n let input: typeof chat.pendingWidgetCalls[number] | null = null;\n for (const wc of chat.pendingWidgetCalls) {\n if (wc.widget.render === 'input' && !input) {\n input = wc;\n } else {\n inline.push(wc);\n }\n }\n return { inlineWidgets: inline, inputWidget: input };\n }, [chat.pendingWidgetCalls]);\n\n // Active references from DevicProvider (created by AIElementWrapper)\n const references = context?.references ?? [];\n const removeReference = useCallback(\n (id: string) => {\n context?.removeReference(id);\n },\n [context]\n );\n const clearReferences = useCallback(() => {\n context?.clearReferences();\n }, [context]);\n\n // Handle send message — prefix references and clear them after sending\n const handleSend = useCallback(\n (\n message: string,\n files?: File[],\n meta?: { transcriptId?: string; tags?: string[] }\n ) => {\n let finalMessage = message;\n if (references.length > 0) {\n const labels = references.map((r) => `\"${r.label}\"`).join(', ');\n finalMessage = `Elemento referenciado: ${labels}\\n\\n${message}`;\n }\n chat.sendMessage(finalMessage, {\n files,\n transcriptId: meta?.transcriptId,\n tags: meta?.tags,\n });\n if (references.length > 0) clearReferences();\n },\n [chat, references, clearReferences]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n },\n [chat, onConversationChange, storageKey]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n if (storageKey) {\n try { localStorage.removeItem(storageKey); } catch {}\n }\n }, [chat, storageKey]);\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Feedback state\n const [feedbackMap, setFeedbackMap] = useState<Map<string, 'positive' | 'negative'>>(new Map());\n const feedbackClientRef = useRef<DevicApiClient | null>(null);\n\n // Initialize feedback client\n useEffect(() => {\n if (resolvedApiKey && !feedbackClientRef.current) {\n feedbackClientRef.current = new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n });\n }\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n // Load existing feedback when chat changes\n useEffect(() => {\n if (!chat.chatUid || !feedbackClientRef.current || !mergedOptions.showFeedback) return;\n\n feedbackClientRef.current.getChatFeedback(assistantId, chat.chatUid)\n .then((entries) => {\n const newMap = new Map<string, 'positive' | 'negative'>();\n for (const entry of entries) {\n if (entry.feedback !== undefined) {\n newMap.set(entry.requestId, entry.feedback ? 'positive' : 'negative');\n }\n }\n setFeedbackMap(newMap);\n })\n .catch(() => {\n // Silently ignore feedback loading errors\n });\n }, [chat.chatUid, assistantId, mergedOptions.showFeedback]);\n\n // Handle feedback submission\n const handleFeedback = useCallback(\n async (messageId: string, positive: boolean, comment?: string) => {\n if (!chat.chatUid || !feedbackClientRef.current) return;\n\n try {\n await feedbackClientRef.current.submitChatFeedback(assistantId, chat.chatUid, {\n messageId,\n feedback: positive,\n feedbackComment: comment,\n });\n\n setFeedbackMap((prev) => {\n const newMap = new Map(prev);\n newMap.set(messageId, positive ? 'positive' : 'negative');\n return newMap;\n });\n } catch (err) {\n console.error('Failed to submit feedback:', err);\n throw err;\n }\n },\n [chat.chatUid, assistantId]\n );\n\n // Apply CSS variables for theming on the drawer element itself\n // (must target the component root so they override the defaults defined on .devic-chat-drawer)\n const drawerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = drawerRef.current;\n if (!el) return;\n const vars: [string, string | undefined][] = [\n ['--devic-primary', mergedOptions.color !== DEFAULT_OPTIONS.color ? mergedOptions.color : undefined],\n ['--devic-font-family', mergedOptions.fontFamily],\n ['--devic-bg', mergedOptions.backgroundColor],\n ['--devic-text', mergedOptions.textColor],\n ['--devic-bg-secondary', mergedOptions.secondaryBackgroundColor],\n ['--devic-border', mergedOptions.borderColor],\n ['--devic-user-bubble', mergedOptions.userBubbleColor],\n ['--devic-user-bubble-text', mergedOptions.userBubbleTextColor],\n ['--devic-assistant-bubble', mergedOptions.assistantBubbleColor],\n ['--devic-assistant-bubble-text', mergedOptions.assistantBubbleTextColor],\n ['--devic-send-btn', mergedOptions.sendButtonColor],\n ];\n for (const [name, value] of vars) {\n if (value) {\n el.style.setProperty(name, value);\n } else {\n el.style.removeProperty(name);\n }\n }\n }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);\n\n // Resizable drawer\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const startX = e.clientX;\n const startWidth = drawerRef.current?.offsetWidth ?? 0;\n const isLeft = mergedOptions.position === 'left';\n\n const onMove = (ev: MouseEvent) => {\n const delta = ev.clientX - startX;\n const newWidth = startWidth + (isLeft ? delta : -delta);\n const clamped = Math.min(\n mergedOptions.maxWidth,\n Math.max(mergedOptions.minWidth, newWidth)\n );\n setResizedWidth(clamped);\n };\n\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n },\n [mergedOptions.position, mergedOptions.minWidth, mergedOptions.maxWidth]\n );\n\n // Build style object\n const baseWidth = resizedWidth\n ? `${resizedWidth}px`\n : typeof mergedOptions.width === 'number'\n ? `${mergedOptions.width}px`\n : mergedOptions.width;\n\n const drawerStyle = useMemo(\n () => ({\n width: baseWidth,\n zIndex: mergedOptions.zIndex,\n borderRadius: typeof mergedOptions.borderRadius === 'number'\n ? `${mergedOptions.borderRadius}px`\n : mergedOptions.borderRadius,\n ...mergedOptions.style,\n }),\n [baseWidth, mergedOptions.zIndex, mergedOptions.borderRadius, mergedOptions.style]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay (drawer mode only) */}\n {!isInline && (\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n )}\n\n {/* Drawer */}\n <div\n ref={drawerRef}\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n data-mode={mode}\n style={drawerStyle}\n >\n {/* Resize handle */}\n {mergedOptions.resizable && (\n <div\n className=\"devic-resize-handle\"\n data-position={mergedOptions.position}\n onMouseDown={handleResizeStart}\n />\n )}\n\n {/* Header */}\n <div className=\"devic-drawer-header\">\n {avatarUrl && (\n <img\n className=\"devic-drawer-avatar\"\n src={avatarUrl}\n alt=\"\"\n aria-hidden=\"true\"\n />\n )}\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <ConversationSelector\n assistantId={assistantId}\n currentChatUid={chat.chatUid}\n onSelect={handleConversationSelect}\n onNewChat={handleNewChat}\n apiKey={apiKey}\n baseUrl={baseUrl}\n tenantId={tenantId}\n subtenantId={subtenantId}\n conversationPreview={mergedOptions.conversationPreview}\n />\n <div className=\"devic-drawer-header-actions\">\n {mergedOptions.showCoreMemoryButton && (\n <button\n className=\"devic-new-chat-btn\"\n onClick={() => setCoreMemoryOpen(true)}\n type=\"button\"\n aria-label=\"Assistant memory\"\n title=\"Assistant memory\"\n >\n <BrainIcon />\n </button>\n )}\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n handedOffSubThreadId={chat.handedOffSubThreadId || undefined}\n onHandoffCompleted={chat.onHandoffCompleted}\n handoffWidgetRenderer={mergedOptions.handoffWidgetRenderer}\n toolGroups={mergedOptions.toolGroups}\n userMessageRenderer={mergedOptions.userMessageRenderer}\n assistantMessageRenderer={mergedOptions.assistantMessageRenderer}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n pendingInlineWidgets={inlineWidgets}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n recalledMemories={\n mergedOptions.showRecalledMemories\n ? chat.recalledMemories\n : undefined\n }\n recalledMemoriesRenderer={mergedOptions.recalledMemoriesRenderer}\n />\n\n {/* Input */}\n {mergedOptions.customPromptBox ? (\n <div className=\"devic-input-area\">\n {limitBannerNode}\n {usageBarNode}\n {mergedOptions.customPromptBox({\n sendMessage: handleSend,\n transcribeAudio,\n stop: chat.stopChat,\n isLoading: chat.isLoading,\n newConversation: chat.clearChat,\n references,\n removeReference,\n clearReferences,\n limitExceeded: chat.limitExceeded,\n })}\n </div>\n ) : (\n <ChatInput\n onSend={handleSend}\n disabled={\n chat.isLoading ||\n chat.handedOff ||\n inlineWidgets.length > 0 ||\n !!chat.limitExceeded\n }\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n enableLongTextPaste={mergedOptions.enableLongTextPaste}\n longTextPasteThreshold={mergedOptions.longTextPasteThreshold}\n enableSpeechToText={mergedOptions.enableSpeechToText}\n speechLanguage={mergedOptions.speechLanguage}\n speechTenantId={tenantId}\n speechAutoStop={mergedOptions.speechAutoStop}\n speechAutoStopCountdownMs={mergedOptions.speechAutoStopCountdownMs}\n speechAutoStopSilenceMs={mergedOptions.speechAutoStopSilenceMs}\n speechAutoStopSilenceRatio={mergedOptions.speechAutoStopSilenceRatio}\n speechAutoStopSilenceLevel={mergedOptions.speechAutoStopSilenceLevel}\n speechAutoStopSpeechLevel={mergedOptions.speechAutoStopSpeechLevel}\n speechHandoff={mergedOptions.speechHandoff}\n speechHandoffSendDelayMs={mergedOptions.speechHandoffSendDelayMs}\n speechHandoffHoldMs={mergedOptions.speechHandoffHoldMs}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n sendButtonContent={mergedOptions.sendButtonContent}\n disabledMessage={\n chat.handedOff\n ? 'Waiting for subagent to complete'\n : inlineWidgets.length > 0\n ? 'Waiting for tool response'\n : undefined\n }\n isProcessing={chat.isLoading && !chat.handedOff}\n onStop={chat.stopChat}\n stopButtonContent={mergedOptions.stopButtonContent}\n pendingInputWidget={inputWidget}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n references={references}\n onRemoveReference={removeReference}\n usageBar={usageBarNode}\n limitBanner={limitBannerNode}\n />\n )}\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n\n {/* Core memory modal (opened from the header brain button) */}\n {mergedOptions.showCoreMemoryButton && (\n <CoreMemoryModal\n isOpen={coreMemoryOpen}\n onClose={() => setCoreMemoryOpen(false)}\n assistantId={assistantId}\n tenantId={tenantId}\n subtenantId={subtenantId}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n />\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\n/**\n * Brain icon for the core memory button\n */\nfunction BrainIcon(): JSX.Element {\n return (\n <svg\n width=\"17\"\n height=\"17\"\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=\"M9.5 2a2.5 2.5 0 0 0-2.45 2A3.5 3.5 0 0 0 4.6 8.6 3.5 3.5 0 0 0 3 11.5c0 1.1.5 2.08 1.29 2.73A3.5 3.5 0 0 0 7 20a3 3 0 0 0 5-2.24V4.5A2.5 2.5 0 0 0 9.5 2Z\" />\n <path d=\"M14.5 2a2.5 2.5 0 0 1 2.45 2 3.5 3.5 0 0 1 2.45 4.6A3.5 3.5 0 0 1 21 11.5a3.49 3.49 0 0 1-1.29 2.73A3.5 3.5 0 0 1 17 20a3 3 0 0 1-5-2.24V4.5A2.5 2.5 0 0 1 14.5 2Z\" />\n </svg>\n );\n}\n\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"ChatDrawer.js","sources":["../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport { ConversationSelector } from './ConversationSelector';\nimport { ChatDrawerErrorBoundary } from './ErrorBoundary';\nimport { UsageBar } from './UsageBar';\nimport { LimitBanner } from './LimitBanner';\nimport { CoreMemoryModal } from '../CoreMemoryModal';\nimport { IntegrationsModal } from '../IntegrationsModal';\nimport type { DevicTheme } from '../theme';\nimport type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: '100%',\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n enableLongTextPaste: false,\n longTextPasteThreshold: 2000,\n enableSpeechToText: false,\n speechLanguage: undefined as any,\n speechAutoStop: true,\n speechAutoStopCountdownMs: 1000,\n speechAutoStopSilenceMs: 1000,\n speechAutoStopSilenceRatio: 0.1,\n speechAutoStopSilenceLevel: 0.02,\n speechAutoStopSpeechLevel: 0.12,\n speechHandoff: false,\n speechHandoffSendDelayMs: 1000,\n speechHandoffHoldMs: 3000,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showAvatar: false,\n showToolTimeline: true,\n zIndex: 1000,\n borderRadius: 0,\n resizable: false,\n minWidth: 300,\n maxWidth: 800,\n style: {},\n fontFamily: undefined as any,\n backgroundColor: undefined as any,\n textColor: undefined as any,\n secondaryBackgroundColor: undefined as any,\n borderColor: undefined as any,\n userBubbleColor: undefined as any,\n userBubbleTextColor: undefined as any,\n assistantBubbleColor: undefined as any,\n assistantBubbleTextColor: undefined as any,\n sendButtonColor: undefined as any,\n loadingIndicator: undefined as any,\n sendButtonContent: undefined as any,\n toolRenderers: undefined as any,\n toolIcons: undefined as any,\n showFeedback: true,\n handoffWidgetRenderer: undefined as any,\n toolGroups: undefined as any,\n stopButtonContent: undefined as any,\n debug: false,\n persistConversation: false,\n customPromptBox: undefined as any,\n userMessageRenderer: undefined as any,\n assistantMessageRenderer: undefined as any,\n conversationPreview: 'date',\n showUsageBar: false,\n usageBarMetric: undefined as any,\n usageBarDisplay: undefined as any,\n customUsageBar: undefined as any,\n hideLimitBanner: false,\n limitBannerRenderer: undefined as any,\n showRecalledMemories: true,\n recalledMemoriesRenderer: undefined as any,\n showCoreMemoryButton: false,\n showIntegrationsButton: false,\n integrationsLabel: 'Connected apps',\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * ref={drawerRef}\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport const ChatDrawer = forwardRef<ChatDrawerHandle, ChatDrawerProps>(\n function ChatDrawer(props, ref) {\n return (\n <ChatDrawerErrorBoundary>\n <ChatDrawerInner {...props} forwardedRef={ref} />\n </ChatDrawerErrorBoundary>\n );\n }\n);\n\ninterface ChatDrawerInnerProps extends ChatDrawerProps {\n forwardedRef?: React.Ref<ChatDrawerHandle>;\n}\n\nfunction ChatDrawerInner({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n mode = 'drawer',\n onConversationChange,\n forwardedRef,\n}: ChatDrawerInnerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // localStorage key for persisting selected conversation\n const storageKey = mergedOptions.persistConversation\n ? `devic-ui-chatUid-${assistantId}`\n : null;\n\n // Resolve initial chatUid: prop takes priority, then localStorage\n const resolvedInitialChatUid = useMemo(() => {\n if (initialChatUid) return initialChatUid;\n if (storageKey) {\n try { return localStorage.getItem(storageKey) || undefined; } catch { return undefined; }\n }\n return undefined;\n }, [initialChatUid, storageKey]);\n\n // Drawer open state (can be controlled or uncontrolled; inline mode is always open)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isInline = mode === 'inline';\n const isOpen = isInline ? true : (controlledIsOpen ?? internalIsOpen);\n\n // Wrap onChatCreated to persist chatUid in localStorage\n const handleChatCreated = useCallback(\n (chatUid: string) => {\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n onChatCreated?.(chatUid);\n },\n [storageKey, onChatCreated]\n );\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: resolvedInitialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated: handleChatCreated,\n onFileUpload,\n debug: mergedOptions.debug,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const [coreMemoryOpen, setCoreMemoryOpen] = useState(false);\n const [integrationsOpen, setIntegrationsOpen] = useState(false);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // Tenant/subtenant resolution mirrors useDevicChat (prop overrides provider).\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n\n // Usage bar (above the input) — only when enabled and a tenant is known.\n // Refetches after each turn via the message count as refresh key.\n const usageBarNode =\n (mergedOptions.showUsageBar ||\n typeof mergedOptions.customUsageBar === 'function') &&\n resolvedTenantId ? (\n <UsageBar\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n tenantId={resolvedTenantId}\n subtenantId={resolvedSubtenantId}\n mode={mergedOptions.showUsageBar === 'onDemand' ? 'onDemand' : 'always'}\n metric={mergedOptions.usageBarMetric}\n display={mergedOptions.usageBarDisplay}\n customUsageBar={mergedOptions.customUsageBar}\n color={mergedOptions.color}\n refreshKey={chat.messages.length}\n debug={mergedOptions.debug}\n />\n ) : null;\n\n // Default usage-limit banner (above the input) — opt-out via hideLimitBanner,\n // override via limitBannerRenderer.\n const limitBannerNode =\n chat.limitExceeded && !mergedOptions.hideLimitBanner\n ? mergedOptions.limitBannerRenderer\n ? mergedOptions.limitBannerRenderer(chat.limitExceeded)\n : <LimitBanner limit={chat.limitExceeded} />\n : null;\n\n // Speech-to-text transcription, exposed to custom prompt boxes so a developer\n // can transcribe audio (binary or URL) and attach the resulting transcriptId.\n const transcribeAudio = useCallback(\n (\n audio: Blob | string,\n transcribeOptions?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n },\n ) => {\n if (!resolvedApiKey) {\n return Promise.reject(\n new Error('API key not configured. Cannot transcribe audio.'),\n );\n }\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n return client.transcribeAudio(audio, {\n language: transcribeOptions?.language ?? mergedOptions.speechLanguage,\n messageUid: transcribeOptions?.messageUid,\n chatUid: transcribeOptions?.chatUid,\n tenantId: transcribeOptions?.tenantId ?? tenantId,\n });\n },\n [resolvedApiKey, resolvedBaseUrl, mergedOptions.speechLanguage, tenantId],\n );\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleToggle = useCallback(() => {\n setInternalIsOpen((prev) => !prev);\n }, []);\n\n // Expose handle for programmatic control\n useImperativeHandle(forwardedRef, () => ({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n setChatUid: (chatUid: string) => {\n chat.loadChat(chatUid);\n },\n sendMessage: (message: string) => {\n chat.sendMessage(message);\n },\n }), [handleOpen, handleClose, handleToggle, chat]);\n\n // Register this drawer in the DevicProvider so AIElementWrapper can open it\n useEffect(() => {\n if (!context?.registerDrawer) return;\n const unregister = context.registerDrawer({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n sendMessage: (message: string) => chat.sendMessage(message),\n });\n return unregister;\n }, [context, handleOpen, handleClose, handleToggle, chat]);\n\n // Partition pending widget calls by render mode\n const { inlineWidgets, inputWidget } = useMemo(() => {\n const inline: typeof chat.pendingWidgetCalls = [];\n let input: typeof chat.pendingWidgetCalls[number] | null = null;\n for (const wc of chat.pendingWidgetCalls) {\n if (wc.widget.render === 'input' && !input) {\n input = wc;\n } else {\n inline.push(wc);\n }\n }\n return { inlineWidgets: inline, inputWidget: input };\n }, [chat.pendingWidgetCalls]);\n\n // Active references from DevicProvider (created by AIElementWrapper)\n const references = context?.references ?? [];\n const removeReference = useCallback(\n (id: string) => {\n context?.removeReference(id);\n },\n [context]\n );\n const clearReferences = useCallback(() => {\n context?.clearReferences();\n }, [context]);\n\n // Handle send message — prefix references and clear them after sending\n const handleSend = useCallback(\n (\n message: string,\n files?: File[],\n meta?: { transcriptId?: string; tags?: string[] }\n ) => {\n let finalMessage = message;\n if (references.length > 0) {\n const labels = references.map((r) => `\"${r.label}\"`).join(', ');\n finalMessage = `Elemento referenciado: ${labels}\\n\\n${message}`;\n }\n chat.sendMessage(finalMessage, {\n files,\n transcriptId: meta?.transcriptId,\n tags: meta?.tags,\n });\n if (references.length > 0) clearReferences();\n },\n [chat, references, clearReferences]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n if (storageKey) {\n try { localStorage.setItem(storageKey, chatUid); } catch {}\n }\n },\n [chat, onConversationChange, storageKey]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n if (storageKey) {\n try { localStorage.removeItem(storageKey); } catch {}\n }\n }, [chat, storageKey]);\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Feedback state\n const [feedbackMap, setFeedbackMap] = useState<Map<string, 'positive' | 'negative'>>(new Map());\n const feedbackClientRef = useRef<DevicApiClient | null>(null);\n\n // Initialize feedback client\n useEffect(() => {\n if (resolvedApiKey && !feedbackClientRef.current) {\n feedbackClientRef.current = new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n });\n }\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n // Load existing feedback when chat changes\n useEffect(() => {\n if (!chat.chatUid || !feedbackClientRef.current || !mergedOptions.showFeedback) return;\n\n feedbackClientRef.current.getChatFeedback(assistantId, chat.chatUid)\n .then((entries) => {\n const newMap = new Map<string, 'positive' | 'negative'>();\n for (const entry of entries) {\n if (entry.feedback !== undefined) {\n newMap.set(entry.requestId, entry.feedback ? 'positive' : 'negative');\n }\n }\n setFeedbackMap(newMap);\n })\n .catch(() => {\n // Silently ignore feedback loading errors\n });\n }, [chat.chatUid, assistantId, mergedOptions.showFeedback]);\n\n // Handle feedback submission\n const handleFeedback = useCallback(\n async (messageId: string, positive: boolean, comment?: string) => {\n if (!chat.chatUid || !feedbackClientRef.current) return;\n\n try {\n await feedbackClientRef.current.submitChatFeedback(assistantId, chat.chatUid, {\n messageId,\n feedback: positive,\n feedbackComment: comment,\n });\n\n setFeedbackMap((prev) => {\n const newMap = new Map(prev);\n newMap.set(messageId, positive ? 'positive' : 'negative');\n return newMap;\n });\n } catch (err) {\n console.error('Failed to submit feedback:', err);\n throw err;\n }\n },\n [chat.chatUid, assistantId]\n );\n\n // Apply CSS variables for theming on the drawer element itself\n // (must target the component root so they override the defaults defined on .devic-chat-drawer)\n const drawerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = drawerRef.current;\n if (!el) return;\n const vars: [string, string | undefined][] = [\n ['--devic-primary', mergedOptions.color !== DEFAULT_OPTIONS.color ? mergedOptions.color : undefined],\n ['--devic-font-family', mergedOptions.fontFamily],\n ['--devic-bg', mergedOptions.backgroundColor],\n ['--devic-text', mergedOptions.textColor],\n ['--devic-bg-secondary', mergedOptions.secondaryBackgroundColor],\n ['--devic-border', mergedOptions.borderColor],\n ['--devic-user-bubble', mergedOptions.userBubbleColor],\n ['--devic-user-bubble-text', mergedOptions.userBubbleTextColor],\n ['--devic-assistant-bubble', mergedOptions.assistantBubbleColor],\n ['--devic-assistant-bubble-text', mergedOptions.assistantBubbleTextColor],\n ['--devic-send-btn', mergedOptions.sendButtonColor],\n ];\n for (const [name, value] of vars) {\n if (value) {\n el.style.setProperty(name, value);\n } else {\n el.style.removeProperty(name);\n }\n }\n }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);\n\n // The same values, handed to the dialogs this drawer opens. They render\n // through a portal into document.body, so the variables set above — which\n // live on the drawer element — never reach them.\n const modalTheme: DevicTheme = useMemo(\n () => ({\n color:\n mergedOptions.color !== DEFAULT_OPTIONS.color\n ? mergedOptions.color\n : undefined,\n fontFamily: mergedOptions.fontFamily,\n backgroundColor: mergedOptions.backgroundColor,\n textColor: mergedOptions.textColor,\n secondaryBackgroundColor: mergedOptions.secondaryBackgroundColor,\n borderColor: mergedOptions.borderColor,\n }),\n [\n mergedOptions.color,\n mergedOptions.fontFamily,\n mergedOptions.backgroundColor,\n mergedOptions.textColor,\n mergedOptions.secondaryBackgroundColor,\n mergedOptions.borderColor,\n ]\n );\n\n // Resizable drawer\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const startX = e.clientX;\n const startWidth = drawerRef.current?.offsetWidth ?? 0;\n const isLeft = mergedOptions.position === 'left';\n\n const onMove = (ev: MouseEvent) => {\n const delta = ev.clientX - startX;\n const newWidth = startWidth + (isLeft ? delta : -delta);\n const clamped = Math.min(\n mergedOptions.maxWidth,\n Math.max(mergedOptions.minWidth, newWidth)\n );\n setResizedWidth(clamped);\n };\n\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n },\n [mergedOptions.position, mergedOptions.minWidth, mergedOptions.maxWidth]\n );\n\n // Build style object\n const baseWidth = resizedWidth\n ? `${resizedWidth}px`\n : typeof mergedOptions.width === 'number'\n ? `${mergedOptions.width}px`\n : mergedOptions.width;\n\n const drawerStyle = useMemo(\n () => ({\n width: baseWidth,\n zIndex: mergedOptions.zIndex,\n borderRadius: typeof mergedOptions.borderRadius === 'number'\n ? `${mergedOptions.borderRadius}px`\n : mergedOptions.borderRadius,\n ...mergedOptions.style,\n }),\n [baseWidth, mergedOptions.zIndex, mergedOptions.borderRadius, mergedOptions.style]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay (drawer mode only) */}\n {!isInline && (\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n )}\n\n {/* Drawer */}\n <div\n ref={drawerRef}\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n data-mode={mode}\n style={drawerStyle}\n >\n {/* Resize handle */}\n {mergedOptions.resizable && (\n <div\n className=\"devic-resize-handle\"\n data-position={mergedOptions.position}\n onMouseDown={handleResizeStart}\n />\n )}\n\n {/* Header */}\n <div className=\"devic-drawer-header\">\n {avatarUrl && (\n <img\n className=\"devic-drawer-avatar\"\n src={avatarUrl}\n alt=\"\"\n aria-hidden=\"true\"\n />\n )}\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <ConversationSelector\n assistantId={assistantId}\n currentChatUid={chat.chatUid}\n onSelect={handleConversationSelect}\n onNewChat={handleNewChat}\n apiKey={apiKey}\n baseUrl={baseUrl}\n tenantId={tenantId}\n subtenantId={subtenantId}\n conversationPreview={mergedOptions.conversationPreview}\n />\n <div className=\"devic-drawer-header-actions\">\n {mergedOptions.showIntegrationsButton && (\n <button\n className=\"devic-new-chat-btn\"\n onClick={() => setIntegrationsOpen(true)}\n type=\"button\"\n aria-label={mergedOptions.integrationsLabel}\n title={mergedOptions.integrationsLabel}\n >\n <PlugIcon />\n </button>\n )}\n {mergedOptions.showCoreMemoryButton && (\n <button\n className=\"devic-new-chat-btn\"\n onClick={() => setCoreMemoryOpen(true)}\n type=\"button\"\n aria-label=\"Assistant memory\"\n title=\"Assistant memory\"\n >\n <BrainIcon />\n </button>\n )}\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n handedOffSubThreadId={chat.handedOffSubThreadId || undefined}\n onHandoffCompleted={chat.onHandoffCompleted}\n handoffWidgetRenderer={mergedOptions.handoffWidgetRenderer}\n toolGroups={mergedOptions.toolGroups}\n userMessageRenderer={mergedOptions.userMessageRenderer}\n assistantMessageRenderer={mergedOptions.assistantMessageRenderer}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n pendingInlineWidgets={inlineWidgets}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n recalledMemories={\n mergedOptions.showRecalledMemories\n ? chat.recalledMemories\n : undefined\n }\n recalledMemoriesRenderer={mergedOptions.recalledMemoriesRenderer}\n />\n\n {/* Input */}\n {mergedOptions.customPromptBox ? (\n <div className=\"devic-input-area\">\n {limitBannerNode}\n {usageBarNode}\n {mergedOptions.customPromptBox({\n sendMessage: handleSend,\n transcribeAudio,\n stop: chat.stopChat,\n isLoading: chat.isLoading,\n newConversation: chat.clearChat,\n references,\n removeReference,\n clearReferences,\n limitExceeded: chat.limitExceeded,\n })}\n </div>\n ) : (\n <ChatInput\n onSend={handleSend}\n disabled={\n chat.isLoading ||\n chat.handedOff ||\n inlineWidgets.length > 0 ||\n !!chat.limitExceeded\n }\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n enableLongTextPaste={mergedOptions.enableLongTextPaste}\n longTextPasteThreshold={mergedOptions.longTextPasteThreshold}\n enableSpeechToText={mergedOptions.enableSpeechToText}\n speechLanguage={mergedOptions.speechLanguage}\n speechTenantId={tenantId}\n speechAutoStop={mergedOptions.speechAutoStop}\n speechAutoStopCountdownMs={mergedOptions.speechAutoStopCountdownMs}\n speechAutoStopSilenceMs={mergedOptions.speechAutoStopSilenceMs}\n speechAutoStopSilenceRatio={mergedOptions.speechAutoStopSilenceRatio}\n speechAutoStopSilenceLevel={mergedOptions.speechAutoStopSilenceLevel}\n speechAutoStopSpeechLevel={mergedOptions.speechAutoStopSpeechLevel}\n speechHandoff={mergedOptions.speechHandoff}\n speechHandoffSendDelayMs={mergedOptions.speechHandoffSendDelayMs}\n speechHandoffHoldMs={mergedOptions.speechHandoffHoldMs}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n sendButtonContent={mergedOptions.sendButtonContent}\n disabledMessage={\n chat.handedOff\n ? 'Waiting for subagent to complete'\n : inlineWidgets.length > 0\n ? 'Waiting for tool response'\n : undefined\n }\n isProcessing={chat.isLoading && !chat.handedOff}\n onStop={chat.stopChat}\n stopButtonContent={mergedOptions.stopButtonContent}\n pendingInputWidget={inputWidget}\n onSubmitWidget={chat.submitWidgetResponse}\n onCancelWidget={chat.cancelWidgetCall}\n references={references}\n onRemoveReference={removeReference}\n usageBar={usageBarNode}\n limitBanner={limitBannerNode}\n />\n )}\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n\n {/* Core memory modal (opened from the header brain button) */}\n {mergedOptions.showCoreMemoryButton && (\n <CoreMemoryModal\n isOpen={coreMemoryOpen}\n onClose={() => setCoreMemoryOpen(false)}\n assistantId={assistantId}\n tenantId={tenantId}\n subtenantId={subtenantId}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n theme={modalTheme}\n />\n )}\n\n {/* Connected apps modal (opened from the header plug button) */}\n {mergedOptions.showIntegrationsButton && (\n <IntegrationsModal\n isOpen={integrationsOpen}\n onClose={() => setIntegrationsOpen(false)}\n assistantId={assistantId}\n tenantId={tenantId}\n subtenantId={subtenantId}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n title={mergedOptions.integrationsLabel}\n theme={modalTheme}\n />\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\n/**\n * Plug icon for the connected-apps button\n */\nfunction PlugIcon(): JSX.Element {\n return (\n <svg\n width=\"17\"\n height=\"17\"\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 22v-5\" />\n <path d=\"M9 8V2\" />\n <path d=\"M15 8V2\" />\n <path d=\"M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z\" />\n </svg>\n );\n}\n\n/**\n * Brain icon for the core memory button\n */\nfunction BrainIcon(): JSX.Element {\n return (\n <svg\n width=\"17\"\n height=\"17\"\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=\"M9.5 2a2.5 2.5 0 0 0-2.45 2A3.5 3.5 0 0 0 4.6 8.6 3.5 3.5 0 0 0 3 11.5c0 1.1.5 2.08 1.29 2.73A3.5 3.5 0 0 0 7 20a3 3 0 0 0 5-2.24V4.5A2.5 2.5 0 0 0 9.5 2Z\" />\n <path d=\"M14.5 2a2.5 2.5 0 0 1 2.45 2 3.5 3.5 0 0 1 2.45 4.6A3.5 3.5 0 0 1 21 11.5a3.49 3.49 0 0 1-1.29 2.73A3.5 3.5 0 0 1 17 20a3 3 0 0 1-5-2.24V4.5A2.5 2.5 0 0 1 14.5 2Z\" />\n </svg>\n );\n}\n\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
@@ -498,6 +498,20 @@ export interface ChatDrawerOptions {
498
498
  * @default false
499
499
  */
500
500
  showCoreMemoryButton?: boolean;
501
+ /**
502
+ * Show a button in the drawer header that opens the IntegrationsModal: the
503
+ * apps the assistant offers to its tenants, where the end user connects and
504
+ * removes their OWN accounts. Requires the assistant (or its environment) to
505
+ * enable tenant integrations, and the API key to allow
506
+ * `/api/v1/tenant-integrations/*`.
507
+ * @default false
508
+ */
509
+ showIntegrationsButton?: boolean;
510
+ /**
511
+ * Label of the integrations button, used as its tooltip and accessible name.
512
+ * @default "Connected apps"
513
+ */
514
+ integrationsLabel?: string;
501
515
  }
502
516
  /**
503
517
  * Props for the ChatDrawer component
@@ -1,4 +1,5 @@
1
1
  import { type JSX } from "react";
2
+ import { type DevicTheme } from "../theme";
2
3
  import "./CoreMemoryModal.css";
3
4
  export interface CoreMemoryModalProps {
4
5
  /** Whether the modal is visible. */
@@ -22,6 +23,12 @@ export interface CoreMemoryModalProps {
22
23
  editable?: boolean;
23
24
  /** Modal title. @default "Assistant memory" */
24
25
  title?: string;
26
+ /**
27
+ * Colours and font. Same names as the drawer's style options, and the drawer
28
+ * passes its own down — a dialog opening in the default light palette over a
29
+ * themed application is the one thing this must not do.
30
+ */
31
+ theme?: DevicTheme;
25
32
  }
26
33
  /**
27
34
  * Modal showing — and, when `editable`, managing — the core memory of an
@@ -33,5 +40,5 @@ export interface CoreMemoryModalProps {
33
40
  * Backed by the public memory API (`/api/v1/memory/assistants/:id/core`);
34
41
  * the API key needs that endpoint allowed.
35
42
  */
36
- export declare function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable, title, }: CoreMemoryModalProps): JSX.Element | null;
43
+ export declare function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable, title, theme, }: CoreMemoryModalProps): JSX.Element | null;
37
44
  export default CoreMemoryModal;
@@ -3,6 +3,7 @@ import { useMemo, useState, useCallback, useRef, useEffect } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { DevicApiClient } from '../../api/client.js';
5
5
  import { useOptionalDevicContext } from '../../provider/DevicContext.js';
6
+ import { themeVars } from '../theme.js';
6
7
 
7
8
  /** Canonical sections of the core tier, in display order. */
8
9
  const SECTIONS = ["persona", "instructions", "decisions", "profile"];
@@ -22,7 +23,7 @@ function PinIcon() {
22
23
  * Backed by the public memory API (`/api/v1/memory/assistants/:id/core`);
23
24
  * the API key needs that endpoint allowed.
24
25
  */
25
- function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable = true, title = "Assistant memory", }) {
26
+ function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable = true, title = "Assistant memory", theme, }) {
26
27
  const context = useOptionalDevicContext();
27
28
  const resolvedApiKey = apiKey || context?.apiKey;
28
29
  const resolvedBaseUrl = baseUrl || context?.baseUrl || "https://api.devic.ai";
@@ -150,7 +151,10 @@ function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId,
150
151
  }
151
152
  for (const [name, list] of bySection)
152
153
  sections.push({ name, entries: list });
153
- return createPortal(jsx("div", { className: "devic-cm-overlay", onClick: onClose, children: jsxs("div", { className: "devic-cm-modal", role: "dialog", "aria-modal": "true", "aria-label": title, onClick: (e) => e.stopPropagation(), children: [jsxs("div", { className: "devic-cm-header", children: [jsxs("h3", { className: "devic-cm-title", children: [jsx(BrainIcon, {}), title] }), jsx("button", { className: "devic-cm-close", onClick: onClose, type: "button", "aria-label": "Close", children: "\u00D7" })] }), jsxs("div", { className: "devic-cm-body", children: [error && jsx("div", { className: "devic-cm-error", children: error }), loading ? (jsx("div", { className: "devic-cm-loading", children: "Loading memory\u2026" })) : !enabled ? (jsx("div", { className: "devic-cm-empty", children: "Memory is not enabled for this assistant." })) : entries.length === 0 && !composerOpen ? (jsx("div", { className: "devic-cm-empty", children: "Nothing remembered yet. What the assistant learns and is told to keep will appear here." })) : (sections.map((section) => (jsxs("div", { className: "devic-cm-section", children: [jsx("div", { className: "devic-cm-section-title", children: section.name }), section.entries.map((entry) => (jsx("div", { className: "devic-cm-entry", children: editingId === entry.id ? (jsxs("div", { className: "devic-cm-editor", children: [jsx("textarea", { className: "devic-cm-textarea", value: editingText, maxLength: limits?.maxEntryChars || undefined, onChange: (e) => setEditingText(e.target.value), disabled: saving, autoFocus: true }), jsxs("div", { className: "devic-cm-editor-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-primary", onClick: () => handleSaveEdit(entry), disabled: saving || !editingText.trim(), children: "Save" }), jsx("button", { type: "button", className: "devic-cm-btn", onClick: () => setEditingId(null), disabled: saving, children: "Cancel" })] })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "devic-cm-entry-content", children: [entry.pinned && (jsx("span", { className: "devic-cm-pin", title: "Pinned: always kept, never changed by the assistant", children: jsx(PinIcon, {}) })), jsx("span", { children: entry.content })] }), editable && (jsxs("div", { className: "devic-cm-entry-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-small", onClick: () => {
154
+ return createPortal(
155
+ // The variables go on the overlay: a portal inherits nothing from the
156
+ // drawer that opened it, so without this the dialog ignores the theme.
157
+ jsx("div", { className: "devic-cm-overlay", style: themeVars(theme), onClick: onClose, children: jsxs("div", { className: "devic-cm-modal", role: "dialog", "aria-modal": "true", "aria-label": title, onClick: (e) => e.stopPropagation(), children: [jsxs("div", { className: "devic-cm-header", children: [jsxs("h3", { className: "devic-cm-title", children: [jsx(BrainIcon, {}), title] }), jsx("button", { className: "devic-cm-close", onClick: onClose, type: "button", "aria-label": "Close", children: "\u00D7" })] }), jsxs("div", { className: "devic-cm-body", children: [error && jsx("div", { className: "devic-cm-error", children: error }), loading ? (jsx("div", { className: "devic-cm-loading", children: "Loading memory\u2026" })) : !enabled ? (jsx("div", { className: "devic-cm-empty", children: "Memory is not enabled for this assistant." })) : entries.length === 0 && !composerOpen ? (jsx("div", { className: "devic-cm-empty", children: "Nothing remembered yet. What the assistant learns and is told to keep will appear here." })) : (sections.map((section) => (jsxs("div", { className: "devic-cm-section", children: [jsx("div", { className: "devic-cm-section-title", children: section.name }), section.entries.map((entry) => (jsx("div", { className: "devic-cm-entry", children: editingId === entry.id ? (jsxs("div", { className: "devic-cm-editor", children: [jsx("textarea", { className: "devic-cm-textarea", value: editingText, maxLength: limits?.maxEntryChars || undefined, onChange: (e) => setEditingText(e.target.value), disabled: saving, autoFocus: true }), jsxs("div", { className: "devic-cm-editor-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-primary", onClick: () => handleSaveEdit(entry), disabled: saving || !editingText.trim(), children: "Save" }), jsx("button", { type: "button", className: "devic-cm-btn", onClick: () => setEditingId(null), disabled: saving, children: "Cancel" })] })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "devic-cm-entry-content", children: [entry.pinned && (jsx("span", { className: "devic-cm-pin", title: "Pinned: always kept, never changed by the assistant", children: jsx(PinIcon, {}) })), jsx("span", { children: entry.content })] }), editable && (jsxs("div", { className: "devic-cm-entry-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-small", onClick: () => {
154
158
  setEditingId(entry.id);
155
159
  setEditingText(entry.content);
156
160
  }, disabled: saving, children: "Edit" }), jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-small devic-cm-btn-danger", onClick: () => handleRemove(entry), disabled: saving, children: "Remove" })] }))] })) }, entry.id)))] }, section.name)))), editable && enabled && !loading && (jsx("div", { className: "devic-cm-composer", children: composerOpen ? (jsxs(Fragment, { children: [jsx("div", { className: "devic-cm-composer-row", children: jsx("select", { className: "devic-cm-select", value: composerSection, onChange: (e) => setComposerSection(e.target.value), disabled: saving, children: SECTIONS.map((s) => (jsx("option", { value: s, children: s }, s))) }) }), jsx("textarea", { className: "devic-cm-textarea", placeholder: "Something the assistant should always remember\u2026", value: composerText, maxLength: limits?.maxEntryChars || undefined, onChange: (e) => setComposerText(e.target.value), disabled: saving, autoFocus: true }), jsxs("div", { className: "devic-cm-editor-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-primary", onClick: handleAdd, disabled: saving || !composerText.trim(), children: "Add" }), jsx("button", { type: "button", className: "devic-cm-btn", onClick: () => {