@devicai/ui 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/api/client.js +39 -0
- package/dist/cjs/api/client.js.map +1 -1
- package/dist/cjs/api/types.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js +37 -12
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatInput.js +2 -2
- package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/LimitBanner.js +36 -0
- package/dist/cjs/components/ChatDrawer/LimitBanner.js.map +1 -0
- package/dist/cjs/components/ChatDrawer/UsageBar.js +116 -0
- package/dist/cjs/components/ChatDrawer/UsageBar.js.map +1 -0
- package/dist/cjs/hooks/useDevicChat.js +50 -3
- package/dist/cjs/hooks/useDevicChat.js.map +1 -1
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/provider/DevicProvider.js +5 -1
- package/dist/cjs/provider/DevicProvider.js.map +1 -1
- package/dist/cjs/styles.css +1 -1
- package/dist/esm/api/client.d.ts +16 -1
- package/dist/esm/api/client.js +39 -0
- package/dist/esm/api/client.js.map +1 -1
- package/dist/esm/api/types.d.ts +105 -2
- package/dist/esm/api/types.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.js +37 -12
- package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +52 -1
- package/dist/esm/components/ChatDrawer/ChatInput.d.ts +1 -1
- package/dist/esm/components/ChatDrawer/ChatInput.js +2 -2
- package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -1
- package/dist/esm/components/ChatDrawer/LimitBanner.d.ts +11 -0
- package/dist/esm/components/ChatDrawer/LimitBanner.js +34 -0
- package/dist/esm/components/ChatDrawer/LimitBanner.js.map +1 -0
- package/dist/esm/components/ChatDrawer/UsageBar.d.ts +36 -0
- package/dist/esm/components/ChatDrawer/UsageBar.js +114 -0
- package/dist/esm/components/ChatDrawer/UsageBar.js.map +1 -0
- package/dist/esm/components/ChatDrawer/index.d.ts +4 -0
- package/dist/esm/hooks/useDevicChat.d.ts +16 -1
- package/dist/esm/hooks/useDevicChat.js +51 -4
- package/dist/esm/hooks/useDevicChat.js.map +1 -1
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/provider/DevicProvider.d.ts +1 -1
- package/dist/esm/provider/DevicProvider.js +5 -1
- package/dist/esm/provider/DevicProvider.js.map +1 -1
- package/dist/esm/provider/types.d.ts +18 -0
- package/dist/esm/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMemo, useRef, useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import { useOptionalDevicContext } from '../provider/DevicContext.js';
|
|
4
|
-
import { DevicApiClient } from '../api/client.js';
|
|
4
|
+
import { DevicApiClient, DevicApiError } from '../api/client.js';
|
|
5
5
|
import { createLogger } from '../utils/logger.js';
|
|
6
6
|
import { usePolling } from './usePolling.js';
|
|
7
7
|
import { useModelInterface } from './useModelInterface.js';
|
|
@@ -29,7 +29,7 @@ import { useModelInterface } from './useModelInterface.js';
|
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
31
|
function useDevicChat(options) {
|
|
32
|
-
const { assistantId, chatUid: initialChatUid, apiKey: propsApiKey, baseUrl: propsBaseUrl, tenantId, tenantMetadata, enabledTools, modelInterfaceTools = [], pollingInterval = 1000, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, onFileUpload, debug: propsDebug, } = options;
|
|
32
|
+
const { assistantId, chatUid: initialChatUid, apiKey: propsApiKey, baseUrl: propsBaseUrl, tenantId, tenantMetadata, subtenantId, subtenantMetadata, enabledTools, modelInterfaceTools = [], pollingInterval = 1000, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, onFileUpload, debug: propsDebug, } = options;
|
|
33
33
|
// Get context (may be null if not wrapped in provider)
|
|
34
34
|
const context = useOptionalDevicContext();
|
|
35
35
|
// Resolve configuration
|
|
@@ -37,6 +37,11 @@ function useDevicChat(options) {
|
|
|
37
37
|
const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';
|
|
38
38
|
const resolvedTenantId = tenantId || context?.tenantId;
|
|
39
39
|
const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };
|
|
40
|
+
const resolvedSubtenantId = subtenantId || context?.subtenantId;
|
|
41
|
+
const resolvedSubtenantMetadata = {
|
|
42
|
+
...context?.subtenantMetadata,
|
|
43
|
+
...subtenantMetadata,
|
|
44
|
+
};
|
|
40
45
|
const debug = propsDebug ?? context?.debug ?? false;
|
|
41
46
|
const log = useMemo(() => createLogger(debug), [debug]);
|
|
42
47
|
const logRef = useRef(log);
|
|
@@ -47,6 +52,7 @@ function useDevicChat(options) {
|
|
|
47
52
|
const [isLoading, setIsLoading] = useState(false);
|
|
48
53
|
const [status, setStatus] = useState('idle');
|
|
49
54
|
const [error, setError] = useState(null);
|
|
55
|
+
const [limitExceeded, setLimitExceeded] = useState(null);
|
|
50
56
|
// Handoff state
|
|
51
57
|
const [handedOff, setHandedOff] = useState(false);
|
|
52
58
|
const [handedOffSubThreadId, setHandedOffSubThreadId] = useState(null);
|
|
@@ -170,7 +176,13 @@ function useDevicChat(options) {
|
|
|
170
176
|
}, {
|
|
171
177
|
interval: pollingInterval,
|
|
172
178
|
enabled: shouldPoll,
|
|
173
|
-
stopStatuses: [
|
|
179
|
+
stopStatuses: [
|
|
180
|
+
'completed',
|
|
181
|
+
'error',
|
|
182
|
+
'waiting_for_tool_response',
|
|
183
|
+
'handed_off',
|
|
184
|
+
'limit_exceeded',
|
|
185
|
+
],
|
|
174
186
|
onUpdate: async (data) => {
|
|
175
187
|
logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);
|
|
176
188
|
// Merge realtime data with optimistic messages.
|
|
@@ -210,7 +222,21 @@ function useDevicChat(options) {
|
|
|
210
222
|
onStop: (data) => {
|
|
211
223
|
logRef.current.log('[useDevicChat] onStop called, status:', data?.status);
|
|
212
224
|
setShouldPoll(false);
|
|
213
|
-
if (data?.status === '
|
|
225
|
+
if (data?.status === 'limit_exceeded') {
|
|
226
|
+
// The message was blocked by a tenant/subtenant usage limit before
|
|
227
|
+
// reaching the LLM. Surface the details so the UI can show a banner.
|
|
228
|
+
setIsLoading(false);
|
|
229
|
+
const details = data.limitExceeded || {
|
|
230
|
+
message: 'Usage limit reached.',
|
|
231
|
+
};
|
|
232
|
+
setLimitExceeded(details);
|
|
233
|
+
const err = new Error(details.message || 'Usage limit reached.');
|
|
234
|
+
err.errorType = 'TENANT_LIMIT_EXCEEDED';
|
|
235
|
+
err.details = details;
|
|
236
|
+
setError(err);
|
|
237
|
+
onErrorRef.current?.(err);
|
|
238
|
+
}
|
|
239
|
+
else if (data?.status === 'error') {
|
|
214
240
|
setIsLoading(false);
|
|
215
241
|
const err = new Error('Chat processing failed');
|
|
216
242
|
setError(err);
|
|
@@ -289,6 +315,7 @@ function useDevicChat(options) {
|
|
|
289
315
|
}
|
|
290
316
|
setIsLoading(true);
|
|
291
317
|
setError(null);
|
|
318
|
+
setLimitExceeded(null);
|
|
292
319
|
setStatus('processing');
|
|
293
320
|
// Add user message optimistically (show file names before upload)
|
|
294
321
|
const userMessage = {
|
|
@@ -344,15 +371,21 @@ function useDevicChat(options) {
|
|
|
344
371
|
: m));
|
|
345
372
|
}
|
|
346
373
|
// Build request DTO
|
|
374
|
+
const hasSubtenantMetadata = resolvedSubtenantMetadata &&
|
|
375
|
+
Object.keys(resolvedSubtenantMetadata).length > 0;
|
|
347
376
|
const dto = {
|
|
348
377
|
message,
|
|
349
378
|
chatUid: chatUid || undefined,
|
|
350
379
|
files: uploadedFiles,
|
|
351
380
|
metadata: {
|
|
352
381
|
...resolvedTenantMetadata,
|
|
382
|
+
...(hasSubtenantMetadata && {
|
|
383
|
+
subtenantMetadata: resolvedSubtenantMetadata,
|
|
384
|
+
}),
|
|
353
385
|
...sendOptions?.metadata,
|
|
354
386
|
},
|
|
355
387
|
tenantId: resolvedTenantId,
|
|
388
|
+
...(resolvedSubtenantId && { subtenantId: resolvedSubtenantId }),
|
|
356
389
|
enabledTools,
|
|
357
390
|
// Include model interface tools if any
|
|
358
391
|
...(toolSchemas.length > 0 && { tools: toolSchemas }),
|
|
@@ -375,6 +408,16 @@ function useDevicChat(options) {
|
|
|
375
408
|
}
|
|
376
409
|
catch (err) {
|
|
377
410
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
411
|
+
// A synchronous usage-limit block surfaces as HTTP 429 /
|
|
412
|
+
// TENANT_LIMIT_EXCEEDED (sync send path). Async sends surface it via the
|
|
413
|
+
// realtime `limit_exceeded` status instead — both are handled.
|
|
414
|
+
if (err instanceof DevicApiError &&
|
|
415
|
+
(err.statusCode === 429 || err.errorType === 'TENANT_LIMIT_EXCEEDED')) {
|
|
416
|
+
const details = err.details || { message: err.message };
|
|
417
|
+
if (!details.message)
|
|
418
|
+
details.message = err.message;
|
|
419
|
+
setLimitExceeded(details);
|
|
420
|
+
}
|
|
378
421
|
setError(error);
|
|
379
422
|
setIsLoading(false);
|
|
380
423
|
setStatus('error');
|
|
@@ -388,6 +431,8 @@ function useDevicChat(options) {
|
|
|
388
431
|
enabledTools,
|
|
389
432
|
resolvedTenantId,
|
|
390
433
|
resolvedTenantMetadata,
|
|
434
|
+
resolvedSubtenantId,
|
|
435
|
+
resolvedSubtenantMetadata,
|
|
391
436
|
toolSchemas,
|
|
392
437
|
onMessageSent,
|
|
393
438
|
onFileUpload,
|
|
@@ -406,6 +451,7 @@ function useDevicChat(options) {
|
|
|
406
451
|
setIsLoading(false);
|
|
407
452
|
setStatus('idle');
|
|
408
453
|
setError(null);
|
|
454
|
+
setLimitExceeded(null);
|
|
409
455
|
pendingWidgetCallsRef.current = [];
|
|
410
456
|
setPendingWidgetCalls([]);
|
|
411
457
|
}, []);
|
|
@@ -549,6 +595,7 @@ function useDevicChat(options) {
|
|
|
549
595
|
isLoading,
|
|
550
596
|
status,
|
|
551
597
|
error,
|
|
598
|
+
limitExceeded,
|
|
552
599
|
handedOff,
|
|
553
600
|
handedOffSubThreadId,
|
|
554
601
|
sendMessage,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDevicChat.js","sources":["../../../src/hooks/useDevicChat.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useOptionalDevicContext } from '../provider';\nimport { DevicApiClient } from '../api/client';\nimport { usePolling } from './usePolling';\nimport { useModelInterface, type PendingWidgetCall } from './useModelInterface';\nimport { createLogger } from '../utils/logger';\nimport type {\n ChatMessage,\n ChatFile,\n ModelInterfaceTool,\n RealtimeChatHistory,\n RealtimeStatus,\n} from '../api/types';\n\nexport interface UseDevicChatOptions {\n /**\n * Assistant identifier\n */\n assistantId: string;\n\n /**\n * Existing chat UID to continue a conversation\n */\n chatUid?: string;\n\n /**\n * API key (overrides provider context)\n */\n apiKey?: string;\n\n /**\n * Base URL (overrides provider context)\n */\n baseUrl?: string;\n\n /**\n * Tenant ID for multi-tenant environments\n */\n tenantId?: string;\n\n /**\n * Tenant metadata\n */\n tenantMetadata?: Record<string, any>;\n\n /**\n * Tools enabled from the assistant's configured tool groups\n */\n enabledTools?: string[];\n\n /**\n * Client-side tools for model interface protocol\n */\n modelInterfaceTools?: ModelInterfaceTool[];\n\n /**\n * Polling interval for async mode (ms)\n * @default 1000\n */\n pollingInterval?: number;\n\n /**\n * Callback when a message is sent\n */\n onMessageSent?: (message: ChatMessage) => void;\n\n /**\n * Callback when a message is received\n */\n onMessageReceived?: (message: ChatMessage) => void;\n\n /**\n * Callback when a tool is called\n */\n onToolCall?: (toolName: string, params: any) => void;\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Callback when a new chat is created\n */\n onChatCreated?: (chatUid: string) => void;\n\n /**\n * Custom file upload handler. When provided, replaces the default\n * upload to Devic API. Receives the raw File objects and must return\n * an array of ChatFile with downloadUrl set.\n */\n onFileUpload?: (files: File[]) => Promise<ChatFile[]>;\n\n /**\n * Enable debug logging to the browser console.\n * Overrides the provider-level debug setting when provided.\n * @default false\n */\n debug?: boolean;\n}\n\nexport interface UseDevicChatResult {\n /**\n * Current chat messages\n */\n messages: ChatMessage[];\n\n /**\n * Current chat UID\n */\n chatUid: string | null;\n\n /**\n * Whether a message is being processed\n */\n isLoading: boolean;\n\n /**\n * Current status\n */\n status: RealtimeStatus | 'idle';\n\n /**\n * Last error\n */\n error: Error | null;\n\n /**\n * Whether the assistant has handed off to a subagent\n */\n handedOff: boolean;\n\n /**\n * The subthread ID when a handoff is active\n */\n handedOffSubThreadId: string | null;\n\n /**\n * Send a message\n */\n sendMessage: (\n message: string,\n options?: {\n files?: File[];\n metadata?: Record<string, any>;\n /** Id of a speech-to-text transcript that seeded this message. */\n transcriptId?: string;\n }\n ) => Promise<void>;\n\n /**\n * Clear the chat and start a new conversation\n */\n clearChat: () => void;\n\n /**\n * Load an existing chat\n */\n loadChat: (chatUid: string) => Promise<void>;\n\n /**\n * Called when the handoff subagent completes.\n * Triggers reload of full chat content.\n */\n onHandoffCompleted: () => void;\n\n /**\n * Stop the current conversation processing (client-side only).\n * Stops polling and resets loading state.\n */\n stopChat: () => void;\n\n /**\n * Pending tool calls that require user interaction via a response widget\n */\n pendingWidgetCalls: PendingWidgetCall[];\n\n /**\n * Submit a response for a pending widget tool call.\n * Sends the response to the API and resumes the conversation.\n */\n submitWidgetResponse: (toolCallId: string, response: any) => Promise<void>;\n\n /**\n * Cancel a pending widget tool call.\n * Sends an error response so the model can continue.\n */\n cancelWidgetCall: (toolCallId: string, reason?: string) => Promise<void>;\n}\n\n/**\n * Main hook for managing chat with a Devic assistant\n *\n * @example\n * ```tsx\n * const {\n * messages,\n * isLoading,\n * sendMessage,\n * } = useDevicChat({\n * assistantId: 'my-assistant',\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 function useDevicChat(options: UseDevicChatOptions): UseDevicChatResult {\n const {\n assistantId,\n chatUid: initialChatUid,\n apiKey: propsApiKey,\n baseUrl: propsBaseUrl,\n tenantId,\n tenantMetadata,\n enabledTools,\n modelInterfaceTools = [],\n pollingInterval = 1000,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n debug: propsDebug,\n } = options;\n\n // Get context (may be null if not wrapped in provider)\n const context = useOptionalDevicContext();\n\n // Resolve configuration\n const apiKey = propsApiKey || context?.apiKey;\n const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };\n const debug = propsDebug ?? context?.debug ?? false;\n const log = useMemo(() => createLogger(debug), [debug]);\n const logRef = useRef(log);\n logRef.current = log;\n\n // State\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [chatUid, setChatUid] = useState<string | null>(initialChatUid || null);\n const [isLoading, setIsLoading] = useState(false);\n const [status, setStatus] = useState<RealtimeStatus | 'idle'>('idle');\n const [error, setError] = useState<Error | null>(null);\n\n // Handoff state\n const [handedOff, setHandedOff] = useState(false);\n const [handedOffSubThreadId, setHandedOffSubThreadId] = useState<string | null>(null);\n const handoffPollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Polling state\n const [shouldPoll, setShouldPoll] = useState(false);\n\n // Keep a ref to chatUid so async callbacks always read the latest value\n const chatUidRef = useRef(chatUid);\n chatUidRef.current = chatUid;\n\n // Refs for callbacks\n const onMessageReceivedRef = useRef(onMessageReceived);\n const onErrorRef = useRef(onError);\n const onChatCreatedRef = useRef(onChatCreated);\n\n useEffect(() => {\n onMessageReceivedRef.current = onMessageReceived;\n onErrorRef.current = onError;\n onChatCreatedRef.current = onChatCreated;\n });\n\n // Create API client\n const clientRef = useRef<DevicApiClient | null>(null);\n if (!clientRef.current && apiKey) {\n clientRef.current = new DevicApiClient({ apiKey, baseUrl });\n }\n\n // Update client config if it changes\n useEffect(() => {\n if (clientRef.current && apiKey) {\n clientRef.current.setConfig({ apiKey, baseUrl });\n }\n }, [apiKey, baseUrl]);\n\n // Resume chat state based on realtime status.\n // Called after loading chat history to detect in-progress conversations.\n const resumeFromRealtimeStatus = useCallback(\n async (targetChatUid: string) => {\n if (!clientRef.current) return;\n try {\n const realtime = await clientRef.current.getRealtimeHistory(assistantId, targetChatUid);\n logRef.current.log('[useDevicChat] resumeFromRealtimeStatus:', realtime.status);\n\n // Update messages with realtime data (may be fresher than static history)\n if (realtime.chatHistory?.length) {\n setMessages(realtime.chatHistory);\n }\n setStatus(realtime.status);\n\n if (realtime.status === 'processing') {\n // Chat is still processing — resume polling\n setIsLoading(true);\n setShouldPoll(true);\n } else if (realtime.status === 'waiting_for_tool_response') {\n // Chat is waiting for tool response — resume polling to trigger tool handling\n setIsLoading(true);\n setShouldPoll(true);\n } else if (realtime.status === 'handed_off') {\n // Chat has an active handoff\n setIsLoading(true);\n setHandedOff(true);\n const subThreadId = realtime.handedOffSubThreadId || null;\n logRef.current.log('[useDevicChat] Resuming handoff state:', { subThreadId });\n if (subThreadId) {\n setHandedOffSubThreadId(subThreadId);\n }\n } else {\n // completed or error — just stop\n setIsLoading(false);\n }\n } catch (err) {\n // If realtime fetch fails (e.g. chat has no realtime entry), just stay idle\n logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);\n setIsLoading(false);\n }\n },\n [assistantId]\n );\n\n // Load initial chat history if chatUid prop is provided\n // This runs once on mount (or when initialChatUid changes) to fetch existing conversation\n const initialChatLoadedRef = useRef(false);\n useEffect(() => {\n if (initialChatUid && clientRef.current && !initialChatLoadedRef.current) {\n initialChatLoadedRef.current = true;\n\n const loadInitialChat = async () => {\n setIsLoading(true);\n setError(null);\n try {\n const history = await clientRef.current!.getChatHistory(\n assistantId,\n initialChatUid,\n { tenantId: resolvedTenantId }\n );\n setMessages(history.chatContent);\n setChatUid(initialChatUid);\n\n // Check realtime status to resume in-progress conversations\n await resumeFromRealtimeStatus(initialChatUid);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n setIsLoading(false);\n }\n };\n\n loadInitialChat();\n }\n }, [initialChatUid, assistantId, resolvedTenantId, resumeFromRealtimeStatus]);\n\n // Model interface hook\n const {\n toolSchemas,\n handleToolCalls,\n extractPendingToolCalls,\n } = useModelInterface({\n tools: modelInterfaceTools,\n onToolExecute: onToolCall,\n });\n\n // Pending widget calls awaiting user interaction\n const [pendingWidgetCalls, setPendingWidgetCalls] = useState<PendingWidgetCall[]>([]);\n const pendingWidgetCallsRef = useRef<PendingWidgetCall[]>([]);\n useEffect(() => {\n pendingWidgetCallsRef.current = pendingWidgetCalls;\n }, [pendingWidgetCalls]);\n\n // Polling hook - uses callbacks for side effects, return value not needed\n logRef.current.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);\n usePolling(\n shouldPoll ? chatUid : null,\n async () => {\n logRef.current.log('[useDevicChat] fetchFn called, chatUid:', chatUid);\n if (!clientRef.current || !chatUid) {\n throw new Error('Cannot poll without client or chatUid');\n }\n const result = await clientRef.current.getRealtimeHistory(assistantId, chatUid);\n logRef.current.log('[useDevicChat] getRealtimeHistory result:', result);\n return result;\n },\n {\n interval: pollingInterval,\n enabled: shouldPoll,\n stopStatuses: ['completed', 'error', 'waiting_for_tool_response', 'handed_off'],\n onUpdate: async (data: RealtimeChatHistory) => {\n logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);\n\n // Merge realtime data with optimistic messages.\n // When a server user message matches an optimistic one by text, adopt the\n // optimistic uid so React's key stays stable (avoids unmount/remount flicker).\n setMessages((prev) => {\n const normalize = (t?: string) => (t ?? '').trim();\n const optimisticUserByText = new Map(\n prev\n .filter((m) => m.role === 'user' && m.uid.startsWith('temp-'))\n .map((m) => [normalize(m.content?.message), m.uid])\n );\n\n const adoptedTempUids = new Set<string>();\n const merged = data.chatHistory.map((m) => {\n if (m.role === 'user') {\n const tempUid = optimisticUserByText.get(normalize(m.content?.message));\n if (tempUid) {\n adoptedTempUids.add(tempUid);\n return { ...m, uid: tempUid };\n }\n }\n return m;\n });\n\n const mergedUIDs = new Set(merged.map((m) => m.uid));\n const optimistic = prev.filter(\n (m) => !mergedUIDs.has(m.uid) && !adoptedTempUids.has(m.uid)\n );\n\n return [...merged, ...optimistic];\n });\n setStatus(data.status);\n\n // Notify about new messages\n const lastMessage = data.chatHistory[data.chatHistory.length - 1];\n if (lastMessage && lastMessage.role === 'assistant') {\n onMessageReceivedRef.current?.(lastMessage);\n }\n\n // Handle model interface - check for pending tool calls\n if (data.status === 'waiting_for_tool_response' || data.pendingToolCalls?.length) {\n await handlePendingToolCalls(data);\n }\n },\n onStop: (data) => {\n logRef.current.log('[useDevicChat] onStop called, status:', data?.status);\n setShouldPoll(false);\n\n if (data?.status === 'error') {\n setIsLoading(false);\n const err = new Error('Chat processing failed');\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'completed') {\n setIsLoading(false);\n } else if (data?.status === 'handed_off') {\n // Subagent is working — keep isLoading true so the UI stays in loading state.\n // Set handoff state directly from the realtime status.\n setHandedOff(true);\n\n const subThreadId = data.handedOffSubThreadId || null;\n logRef.current.log('[useDevicChat] Handoff state set:', { handedOff: true, subThreadId });\n if (subThreadId) {\n setHandedOffSubThreadId(subThreadId);\n }\n }\n // Note: waiting_for_tool_response is handled in onUpdate to avoid double execution\n },\n onError: (err) => {\n logRef.current.error('[useDevicChat] onError called:', err);\n setError(err);\n setIsLoading(false);\n setShouldPoll(false);\n onErrorRef.current?.(err);\n },\n debug,\n }\n );\n\n // Handle pending tool calls from model interface\n const handlePendingToolCalls = useCallback(\n async (data: RealtimeChatHistory) => {\n if (!clientRef.current || !chatUid) return;\n\n // Get pending tool calls\n const pendingCalls = data.pendingToolCalls || extractPendingToolCalls(data.chatHistory);\n\n if (pendingCalls.length === 0) return;\n\n try {\n // Execute client-side tools (partitioned into immediate responses and widget-driven)\n const { responses, widgetCalls } = await handleToolCalls(pendingCalls);\n\n // Queue widget-driven tool calls for user interaction\n if (widgetCalls.length > 0) {\n const existingIds = new Set(pendingWidgetCallsRef.current.map((c) => c.toolCall.id));\n const deduped = widgetCalls.filter((c) => !existingIds.has(c.toolCall.id));\n const next = [...pendingWidgetCallsRef.current, ...deduped];\n pendingWidgetCallsRef.current = next;\n setPendingWidgetCalls(next);\n // Stop polling while we wait for the user to submit the widget response.\n // The widget submission will re-trigger polling via submitWidgetResponse.\n setShouldPoll(false);\n setIsLoading(false);\n }\n\n if (responses.length > 0) {\n // Send tool responses back to the API\n await clientRef.current.sendToolResponses(assistantId, chatUid, responses);\n\n // Only resume polling if no widgets are blocking\n if (widgetCalls.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [chatUid, assistantId, handleToolCalls, extractPendingToolCalls]\n );\n\n // Send a message\n const sendMessage = useCallback(\n async (\n message: string,\n sendOptions?: {\n files?: File[];\n metadata?: Record<string, any>;\n transcriptId?: string;\n }\n ) => {\n if (!clientRef.current) {\n const err = new Error(\n 'API client not configured. Please provide an API key.'\n );\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n setStatus('processing');\n\n // Add user message optimistically (show file names before upload)\n const userMessage: ChatMessage = {\n uid: `temp-${Date.now()}`,\n role: 'user',\n content: {\n message,\n files: sendOptions?.files?.map((f) => ({\n name: f.name,\n url: '',\n type: f.type.split('/')[0] || 'other',\n })),\n },\n timestamp: Date.now(),\n ...(sendOptions?.transcriptId && {\n transcriptId: sendOptions.transcriptId,\n }),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n try {\n // Upload files if provided\n let uploadedFiles: ChatFile[] | undefined;\n if (sendOptions?.files && sendOptions.files.length > 0) {\n logRef.current.log('[useDevicChat] Uploading files...');\n if (onFileUpload) {\n // Use custom upload handler\n uploadedFiles = await onFileUpload(sendOptions.files);\n } else {\n // Default: upload via Devic API\n const uploadResults = await Promise.all(\n sendOptions.files.map((file) => clientRef.current!.uploadFile(file))\n );\n uploadedFiles = uploadResults.map((r) => ({\n name: r.name,\n downloadUrl: r.downloadUrl,\n fileType: r.fileType as ChatFile['fileType'],\n }));\n }\n logRef.current.log('[useDevicChat] Files uploaded:', uploadedFiles);\n\n // Update optimistic message with download URLs\n setMessages((prev) =>\n prev.map((m) =>\n m.uid === userMessage.uid\n ? {\n ...m,\n content: {\n ...m.content,\n files: uploadedFiles!.map((f) => ({\n name: f.name,\n url: f.downloadUrl || '',\n type: f.fileType || 'other',\n })),\n },\n }\n : m\n )\n );\n }\n\n // Build request DTO\n const dto = {\n message,\n chatUid: chatUid || undefined,\n files: uploadedFiles,\n metadata: {\n ...resolvedTenantMetadata,\n ...sendOptions?.metadata,\n },\n tenantId: resolvedTenantId,\n enabledTools,\n // Include model interface tools if any\n ...(toolSchemas.length > 0 && { tools: toolSchemas }),\n // Link to the speech-to-text transcript that seeded this message, if any\n ...(sendOptions?.transcriptId && { transcriptId: sendOptions.transcriptId }),\n };\n\n // Send message in async mode\n logRef.current.log('[useDevicChat] Sending message async...');\n const response = await clientRef.current.sendMessageAsync(assistantId, dto);\n logRef.current.log('[useDevicChat] sendMessageAsync response:', response);\n\n // Update chat UID if this is a new chat\n if (response.chatUid && response.chatUid !== chatUid) {\n logRef.current.log('[useDevicChat] Setting chatUid:', response.chatUid);\n setChatUid(response.chatUid);\n onChatCreatedRef.current?.(response.chatUid);\n }\n\n // Start polling for results\n logRef.current.log('[useDevicChat] Setting shouldPoll to true');\n setShouldPoll(true);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n setIsLoading(false);\n setStatus('error');\n onErrorRef.current?.(error);\n\n // Remove optimistic user message on error\n setMessages((prev) => prev.filter((m) => m.uid !== userMessage.uid));\n }\n },\n [\n chatUid,\n assistantId,\n enabledTools,\n resolvedTenantId,\n resolvedTenantMetadata,\n toolSchemas,\n onMessageSent,\n onFileUpload,\n ]\n );\n\n // Clear chat\n const clearChat = useCallback(() => {\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n setMessages([]);\n setChatUid(null);\n setIsLoading(false);\n setStatus('idle');\n setError(null);\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n }, []);\n\n // Load existing chat\n const loadChat = useCallback(\n async (loadChatUid: string) => {\n if (!clientRef.current) {\n const err = new Error('API client not configured');\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n // Reset any active polling/handoff state from previous conversation\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const history = await clientRef.current.getChatHistory(\n assistantId,\n loadChatUid,\n { tenantId: resolvedTenantId }\n );\n\n setMessages(history.chatContent);\n setChatUid(loadChatUid);\n\n // Check realtime status to resume in-progress conversations\n await resumeFromRealtimeStatus(loadChatUid);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n setIsLoading(false);\n }\n },\n [assistantId, resolvedTenantId, resumeFromRealtimeStatus]\n );\n\n // Handoff polling: while handedOff is true, poll the realtime endpoint every 5s\n // to detect when the parent thread is no longer in handed_off state.\n useEffect(() => {\n if (!handedOff || !chatUid || !clientRef.current) return;\n\n const pollHandoff = async () => {\n try {\n const realtime = await clientRef.current!.getRealtimeHistory(assistantId, chatUid!);\n logRef.current.log('[useDevicChat] Handoff poll - realtime status:', realtime.status);\n if (realtime.status !== 'handed_off') {\n // Handoff completed — clear handoff state and resume main polling\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n // Resume main polling to pick up the parent thread's continuation\n setShouldPoll(true);\n }\n } catch {}\n };\n\n handoffPollRef.current = setInterval(pollHandoff, 5000);\n return () => {\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n };\n }, [handedOff, chatUid, assistantId]);\n\n // Called by HandoffSubagentWidget when the subthread reaches a terminal state\n const onHandoffCompleted = useCallback(() => {\n logRef.current.log('[useDevicChat] onHandoffCompleted called');\n // Clear the handoff polling\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n // Clear handoff state and resume main polling\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n setShouldPoll(true);\n }, []);\n\n // Submit a response for a pending widget tool call\n const submitWidgetResponse = useCallback(\n async (toolCallId: string, response: any) => {\n const uid = chatUidRef.current;\n if (!clientRef.current || !uid) return;\n\n // Check pending widgets via ref (state updates are async)\n const current = pendingWidgetCallsRef.current;\n const found = current.some((c) => c.toolCall.id === toolCallId);\n if (!found) return;\n\n // Remove the widget call from pending list\n const remaining = current.filter((c) => c.toolCall.id !== toolCallId);\n pendingWidgetCallsRef.current = remaining;\n setPendingWidgetCalls(remaining);\n\n try {\n logRef.current.log('[useDevicChat] sending widget tool response', toolCallId);\n await clientRef.current.sendToolResponses(assistantId, uid, [\n { tool_call_id: toolCallId, content: response, role: 'tool' },\n ]);\n // Resume polling only if no more widget calls are blocking\n if (remaining.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logRef.current.error('[useDevicChat] submitWidgetResponse failed', error);\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [assistantId]\n );\n\n // Cancel a pending widget tool call (sends an error response to the model)\n const cancelWidgetCall = useCallback(\n async (toolCallId: string, reason?: string) => {\n await submitWidgetResponse(toolCallId, {\n error: reason || 'User cancelled the tool call',\n });\n },\n [submitWidgetResponse]\n );\n\n // Stop current conversation — calls the server-side stop endpoint\n // then stops polling and resets loading state.\n const stopChat = useCallback(async () => {\n const uid = chatUidRef.current;\n logRef.current.log('[useDevicChat] stopChat called, chatUid:', uid);\n if (clientRef.current && uid) {\n try {\n await clientRef.current.stopChat(assistantId, uid);\n logRef.current.log('[useDevicChat] stopChat API call succeeded');\n } catch (err) {\n logRef.current.warn('[useDevicChat] stopChat API call failed:', err);\n }\n }\n setShouldPoll(false);\n setIsLoading(false);\n setStatus('idle');\n }, [assistantId]);\n\n return {\n messages,\n chatUid,\n isLoading,\n status,\n error,\n handedOff,\n handedOffSubThreadId,\n sendMessage,\n clearChat,\n loadChat,\n onHandoffCompleted,\n stopChat,\n pendingWidgetCalls,\n submitWidgetResponse,\n cancelWidgetCall,\n };\n}\n"],"names":[],"mappings":";;;;;;;;AA8LA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,YAAY,CAAC,OAA4B,EAAA;IACvD,MAAM,EACJ,WAAW,EACX,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,EACrB,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,mBAAmB,GAAG,EAAE,EACxB,eAAe,GAAG,IAAI,EACtB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,OAAO,EACP,aAAa,EACb,YAAY,EACZ,KAAK,EAAE,UAAU,GAClB,GAAG,OAAO;;AAGX,IAAA,MAAM,OAAO,GAAG,uBAAuB,EAAE;;AAGzC,IAAA,MAAM,MAAM,GAAG,WAAW,IAAI,OAAO,EAAE,MAAM;IAC7C,MAAM,OAAO,GAAG,YAAY,IAAI,OAAO,EAAE,OAAO,IAAI,sBAAsB;AAC1E,IAAA,MAAM,gBAAgB,GAAG,QAAQ,IAAI,OAAO,EAAE,QAAQ;IACtD,MAAM,sBAAsB,GAAG,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE;IAChF,MAAM,KAAK,GAAG,UAAU,IAAI,OAAO,EAAE,KAAK,IAAI,KAAK;AACnD,IAAA,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AACvD,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC;AAC1B,IAAA,MAAM,CAAC,OAAO,GAAG,GAAG;;IAGpB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAgB,EAAE,CAAC;AAC3D,IAAA,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,cAAc,IAAI,IAAI,CAAC;IAC7E,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IACjD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA0B,MAAM,CAAC;IACrE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC;;IAGtD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IACjD,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC;AACrF,IAAA,MAAM,cAAc,GAAG,MAAM,CAAwC,IAAI,CAAC;;IAG1E,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;;AAGnD,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;AAClC,IAAA,UAAU,CAAC,OAAO,GAAG,OAAO;;AAG5B,IAAA,MAAM,oBAAoB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACtD,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;AAClC,IAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC;IAE9C,SAAS,CAAC,MAAK;AACb,QAAA,oBAAoB,CAAC,OAAO,GAAG,iBAAiB;AAChD,QAAA,UAAU,CAAC,OAAO,GAAG,OAAO;AAC5B,QAAA,gBAAgB,CAAC,OAAO,GAAG,aAAa;AAC1C,IAAA,CAAC,CAAC;;AAGF,IAAA,MAAM,SAAS,GAAG,MAAM,CAAwB,IAAI,CAAC;AACrD,IAAA,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,MAAM,EAAE;AAChC,QAAA,SAAS,CAAC,OAAO,GAAG,IAAI,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC7D;;IAGA,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,SAAS,CAAC,OAAO,IAAI,MAAM,EAAE;YAC/B,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAClD;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;IAIrB,MAAM,wBAAwB,GAAG,WAAW,CAC1C,OAAO,aAAqB,KAAI;QAC9B,IAAI,CAAC,SAAS,CAAC,OAAO;YAAE;AACxB,QAAA,IAAI;AACF,YAAA,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE,aAAa,CAAC;YACvF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,0CAA0C,EAAE,QAAQ,CAAC,MAAM,CAAC;;AAG/E,YAAA,IAAI,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE;AAChC,gBAAA,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC;YACnC;AACA,YAAA,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;AAE1B,YAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,YAAY,EAAE;;gBAEpC,YAAY,CAAC,IAAI,CAAC;gBAClB,aAAa,CAAC,IAAI,CAAC;YACrB;AAAO,iBAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,2BAA2B,EAAE;;gBAE1D,YAAY,CAAC,IAAI,CAAC;gBAClB,aAAa,CAAC,IAAI,CAAC;YACrB;AAAO,iBAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,YAAY,EAAE;;gBAE3C,YAAY,CAAC,IAAI,CAAC;gBAClB,YAAY,CAAC,IAAI,CAAC;AAClB,gBAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,oBAAoB,IAAI,IAAI;gBACzD,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE,EAAE,WAAW,EAAE,CAAC;gBAC7E,IAAI,WAAW,EAAE;oBACf,uBAAuB,CAAC,WAAW,CAAC;gBACtC;YACF;iBAAO;;gBAEL,YAAY,CAAC,KAAK,CAAC;YACrB;QACF;QAAE,OAAO,GAAG,EAAE;;YAEZ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,iDAAiD,EAAE,GAAG,CAAC;YAC3E,YAAY,CAAC,KAAK,CAAC;QACrB;AACF,IAAA,CAAC,EACD,CAAC,WAAW,CAAC,CACd;;;AAID,IAAA,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,CAAC;IAC1C,SAAS,CAAC,MAAK;QACb,IAAI,cAAc,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE;AACxE,YAAA,oBAAoB,CAAC,OAAO,GAAG,IAAI;AAEnC,YAAA,MAAM,eAAe,GAAG,YAAW;gBACjC,YAAY,CAAC,IAAI,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC;AACd,gBAAA,IAAI;AACF,oBAAA,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAQ,CAAC,cAAc,CACrD,WAAW,EACX,cAAc,EACd,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAC/B;AACD,oBAAA,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC;oBAChC,UAAU,CAAC,cAAc,CAAC;;AAG1B,oBAAA,MAAM,wBAAwB,CAAC,cAAc,CAAC;gBAChD;gBAAE,OAAO,GAAG,EAAE;oBACZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACjE,QAAQ,CAAC,KAAK,CAAC;AACf,oBAAA,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;oBAC3B,YAAY,CAAC,KAAK,CAAC;gBACrB;AACF,YAAA,CAAC;AAED,YAAA,eAAe,EAAE;QACnB;IACF,CAAC,EAAE,CAAC,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,wBAAwB,CAAC,CAAC;;IAG7E,MAAM,EACJ,WAAW,EACX,eAAe,EACf,uBAAuB,GACxB,GAAG,iBAAiB,CAAC;AACpB,QAAA,KAAK,EAAE,mBAAmB;AAC1B,QAAA,aAAa,EAAE,UAAU;AAC1B,KAAA,CAAC;;IAGF,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAsB,EAAE,CAAC;AACrF,IAAA,MAAM,qBAAqB,GAAG,MAAM,CAAsB,EAAE,CAAC;IAC7D,SAAS,CAAC,MAAK;AACb,QAAA,qBAAqB,CAAC,OAAO,GAAG,kBAAkB;AACpD,IAAA,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC;;AAGxB,IAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC;AAC1F,IAAA,UAAU,CACR,UAAU,GAAG,OAAO,GAAG,IAAI,EAC3B,YAAW;QACT,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yCAAyC,EAAE,OAAO,CAAC;QACtE,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE;AAClC,YAAA,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC;QAC1D;AACA,QAAA,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE,OAAO,CAAC;QAC/E,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,MAAM,CAAC;AACvE,QAAA,OAAO,MAAM;AACf,IAAA,CAAC,EACD;AACE,QAAA,QAAQ,EAAE,eAAe;AACzB,QAAA,OAAO,EAAE,UAAU;QACnB,YAAY,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,2BAA2B,EAAE,YAAY,CAAC;AAC/E,QAAA,QAAQ,EAAE,OAAO,IAAyB,KAAI;YAC5C,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yCAAyC,EAAE,IAAI,CAAC,MAAM,CAAC;;;;AAK1E,YAAA,WAAW,CAAC,CAAC,IAAI,KAAI;AACnB,gBAAA,MAAM,SAAS,GAAG,CAAC,CAAU,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE;AAClD,gBAAA,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAClC;qBACG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;qBAC5D,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CACtD;AAED,gBAAA,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU;gBACzC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAI;AACxC,oBAAA,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE;AACrB,wBAAA,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBACvE,IAAI,OAAO,EAAE;AACX,4BAAA,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;4BAC5B,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE;wBAC/B;oBACF;AACA,oBAAA,OAAO,CAAC;AACV,gBAAA,CAAC,CAAC;AAEF,gBAAA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;AACpD,gBAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAC5B,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAC7D;AAED,gBAAA,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC;AACnC,YAAA,CAAC,CAAC;AACF,YAAA,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;;AAGtB,YAAA,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;YACjE,IAAI,WAAW,IAAI,WAAW,CAAC,IAAI,KAAK,WAAW,EAAE;AACnD,gBAAA,oBAAoB,CAAC,OAAO,GAAG,WAAW,CAAC;YAC7C;;AAGA,YAAA,IAAI,IAAI,CAAC,MAAM,KAAK,2BAA2B,IAAI,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE;AAChF,gBAAA,MAAM,sBAAsB,CAAC,IAAI,CAAC;YACpC;QACF,CAAC;AACD,QAAA,MAAM,EAAE,CAAC,IAAI,KAAI;YACf,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,uCAAuC,EAAE,IAAI,EAAE,MAAM,CAAC;YACzE,aAAa,CAAC,KAAK,CAAC;AAEpB,YAAA,IAAI,IAAI,EAAE,MAAM,KAAK,OAAO,EAAE;gBAC5B,YAAY,CAAC,KAAK,CAAC;AACnB,gBAAA,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,wBAAwB,CAAC;gBAC/C,QAAQ,CAAC,GAAG,CAAC;AACb,gBAAA,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC;YAC3B;AAAO,iBAAA,IAAI,IAAI,EAAE,MAAM,KAAK,WAAW,EAAE;gBACvC,YAAY,CAAC,KAAK,CAAC;YACrB;AAAO,iBAAA,IAAI,IAAI,EAAE,MAAM,KAAK,YAAY,EAAE;;;gBAGxC,YAAY,CAAC,IAAI,CAAC;AAElB,gBAAA,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,IAAI,IAAI;AACrD,gBAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;gBACzF,IAAI,WAAW,EAAE;oBACf,uBAAuB,CAAC,WAAW,CAAC;gBACtC;YACF;;QAEF,CAAC;AACD,QAAA,OAAO,EAAE,CAAC,GAAG,KAAI;YACf,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC;YAC3D,QAAQ,CAAC,GAAG,CAAC;YACb,YAAY,CAAC,KAAK,CAAC;YACnB,aAAa,CAAC,KAAK,CAAC;AACpB,YAAA,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC;QAC3B,CAAC;QACD,KAAK;AACN,KAAA,CACF;;IAGD,MAAM,sBAAsB,GAAG,WAAW,CACxC,OAAO,IAAyB,KAAI;AAClC,QAAA,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,OAAO;YAAE;;AAGpC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,IAAI,uBAAuB,CAAC,IAAI,CAAC,WAAW,CAAC;AAEvF,QAAA,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE;AAE/B,QAAA,IAAI;;YAEF,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC;;AAGtE,YAAA,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC1B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACpF,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAC1E,MAAM,IAAI,GAAG,CAAC,GAAG,qBAAqB,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC;AAC3D,gBAAA,qBAAqB,CAAC,OAAO,GAAG,IAAI;gBACpC,qBAAqB,CAAC,IAAI,CAAC;;;gBAG3B,aAAa,CAAC,KAAK,CAAC;gBACpB,YAAY,CAAC,KAAK,CAAC;YACrB;AAEA,YAAA,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;;AAExB,gBAAA,MAAM,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC;;AAG1E,gBAAA,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;oBAC5B,aAAa,CAAC,IAAI,CAAC;oBACnB,YAAY,CAAC,IAAI,CAAC;gBACpB;YACF;QACF;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,QAAQ,CAAC,KAAK,CAAC;AACf,YAAA,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC7B;IACF,CAAC,EACD,CAAC,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,uBAAuB,CAAC,CACjE;;IAGD,MAAM,WAAW,GAAG,WAAW,CAC7B,OACE,OAAe,EACf,WAIC,KACC;AACF,QAAA,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;AACtB,YAAA,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,uDAAuD,CACxD;YACD,QAAQ,CAAC,GAAG,CAAC;AACb,YAAA,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC;YACzB;QACF;QAEA,YAAY,CAAC,IAAI,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC;QACd,SAAS,CAAC,YAAY,CAAC;;AAGvB,QAAA,MAAM,WAAW,GAAgB;AAC/B,YAAA,GAAG,EAAE,CAAA,KAAA,EAAQ,IAAI,CAAC,GAAG,EAAE,CAAA,CAAE;AACzB,YAAA,IAAI,EAAE,MAAM;AACZ,YAAA,OAAO,EAAE;gBACP,OAAO;AACP,gBAAA,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM;oBACrC,IAAI,EAAE,CAAC,CAAC,IAAI;AACZ,oBAAA,GAAG,EAAE,EAAE;AACP,oBAAA,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO;AACtC,iBAAA,CAAC,CAAC;AACJ,aAAA;AACD,YAAA,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;AACrB,YAAA,IAAI,WAAW,EAAE,YAAY,IAAI;gBAC/B,YAAY,EAAE,WAAW,CAAC,YAAY;aACvC,CAAC;SACH;AAED,QAAA,WAAW,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC;AAC7C,QAAA,aAAa,GAAG,WAAW,CAAC;AAE5B,QAAA,IAAI;;AAEF,YAAA,IAAI,aAAqC;AACzC,YAAA,IAAI,WAAW,EAAE,KAAK,IAAI,WAAW,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACtD,gBAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC;gBACvD,IAAI,YAAY,EAAE;;oBAEhB,aAAa,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC;gBACvD;qBAAO;;AAEL,oBAAA,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CACrC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,OAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CACrE;oBACD,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;wBACxC,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,WAAW,EAAE,CAAC,CAAC,WAAW;wBAC1B,QAAQ,EAAE,CAAC,CAAC,QAAgC;AAC7C,qBAAA,CAAC,CAAC;gBACL;gBACA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,aAAa,CAAC;;gBAGnE,WAAW,CAAC,CAAC,IAAI,KACf,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KACT,CAAC,CAAC,GAAG,KAAK,WAAW,CAAC;AACpB,sBAAE;AACE,wBAAA,GAAG,CAAC;AACJ,wBAAA,OAAO,EAAE;4BACP,GAAG,CAAC,CAAC,OAAO;4BACZ,KAAK,EAAE,aAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;gCAChC,IAAI,EAAE,CAAC,CAAC,IAAI;AACZ,gCAAA,GAAG,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;AACxB,gCAAA,IAAI,EAAE,CAAC,CAAC,QAAQ,IAAI,OAAO;AAC5B,6BAAA,CAAC,CAAC;AACJ,yBAAA;AACF;AACH,sBAAE,CAAC,CACN,CACF;YACH;;AAGA,YAAA,MAAM,GAAG,GAAG;gBACV,OAAO;gBACP,OAAO,EAAE,OAAO,IAAI,SAAS;AAC7B,gBAAA,KAAK,EAAE,aAAa;AACpB,gBAAA,QAAQ,EAAE;AACR,oBAAA,GAAG,sBAAsB;oBACzB,GAAG,WAAW,EAAE,QAAQ;AACzB,iBAAA;AACD,gBAAA,QAAQ,EAAE,gBAAgB;gBAC1B,YAAY;;AAEZ,gBAAA,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;;AAErD,gBAAA,IAAI,WAAW,EAAE,YAAY,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC;aAC7E;;AAGD,YAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC;AAC7D,YAAA,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,CAAC;YAC3E,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,QAAQ,CAAC;;YAGzE,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,EAAE;gBACpD,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,QAAQ,CAAC,OAAO,CAAC;AACvE,gBAAA,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC5B,gBAAgB,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;YAC9C;;AAGA,YAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC;YAC/D,aAAa,CAAC,IAAI,CAAC;QACrB;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,QAAQ,CAAC,KAAK,CAAC;YACf,YAAY,CAAC,KAAK,CAAC;YACnB,SAAS,CAAC,OAAO,CAAC;AAClB,YAAA,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;;YAG3B,WAAW,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,WAAW,CAAC,GAAG,CAAC,CAAC;QACtE;AACF,IAAA,CAAC,EACD;QACE,OAAO;QACP,WAAW;QACX,YAAY;QACZ,gBAAgB;QAChB,sBAAsB;QACtB,WAAW;QACX,aAAa;QACb,YAAY;AACb,KAAA,CACF;;AAGD,IAAA,MAAM,SAAS,GAAG,WAAW,CAAC,MAAK;QACjC,aAAa,CAAC,KAAK,CAAC;QACpB,YAAY,CAAC,KAAK,CAAC;QACnB,uBAAuB,CAAC,IAAI,CAAC;AAC7B,QAAA,IAAI,cAAc,CAAC,OAAO,EAAE;AAC1B,YAAA,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC;AACrC,YAAA,cAAc,CAAC,OAAO,GAAG,IAAI;QAC/B;QACA,WAAW,CAAC,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,CAAC;QAChB,YAAY,CAAC,KAAK,CAAC;QACnB,SAAS,CAAC,MAAM,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC;AACd,QAAA,qBAAqB,CAAC,OAAO,GAAG,EAAE;QAClC,qBAAqB,CAAC,EAAE,CAAC;IAC3B,CAAC,EAAE,EAAE,CAAC;;IAGN,MAAM,QAAQ,GAAG,WAAW,CAC1B,OAAO,WAAmB,KAAI;AAC5B,QAAA,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;AACtB,YAAA,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC;YAClD,QAAQ,CAAC,GAAG,CAAC;AACb,YAAA,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC;YACzB;QACF;;QAGA,aAAa,CAAC,KAAK,CAAC;QACpB,YAAY,CAAC,KAAK,CAAC;QACnB,uBAAuB,CAAC,IAAI,CAAC;AAC7B,QAAA,qBAAqB,CAAC,OAAO,GAAG,EAAE;QACpC,qBAAqB,CAAC,EAAE,CAAC;AACvB,QAAA,IAAI,cAAc,CAAC,OAAO,EAAE;AAC1B,YAAA,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC;AACrC,YAAA,cAAc,CAAC,OAAO,GAAG,IAAI;QAC/B;QAEA,YAAY,CAAC,IAAI,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC;AAEd,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,cAAc,CACpD,WAAW,EACX,WAAW,EACX,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAC/B;AAED,YAAA,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC;YAChC,UAAU,CAAC,WAAW,CAAC;;AAGvB,YAAA,MAAM,wBAAwB,CAAC,WAAW,CAAC;QAC7C;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,QAAQ,CAAC,KAAK,CAAC;AACf,YAAA,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,YAAY,CAAC,KAAK,CAAC;QACrB;IACF,CAAC,EACD,CAAC,WAAW,EAAE,gBAAgB,EAAE,wBAAwB,CAAC,CAC1D;;;IAID,SAAS,CAAC,MAAK;QACb,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO;YAAE;AAElD,QAAA,MAAM,WAAW,GAAG,YAAW;AAC7B,YAAA,IAAI;AACF,gBAAA,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAQ,CAAC,kBAAkB,CAAC,WAAW,EAAE,OAAQ,CAAC;gBACnF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gDAAgD,EAAE,QAAQ,CAAC,MAAM,CAAC;AACrF,gBAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,YAAY,EAAE;;AAEpC,oBAAA,IAAI,cAAc,CAAC,OAAO,EAAE;AAC1B,wBAAA,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC;AACrC,wBAAA,cAAc,CAAC,OAAO,GAAG,IAAI;oBAC/B;oBACA,YAAY,CAAC,KAAK,CAAC;oBACnB,uBAAuB,CAAC,IAAI,CAAC;;oBAE7B,aAAa,CAAC,IAAI,CAAC;gBACrB;YACF;YAAE,MAAM,EAAC;AACX,QAAA,CAAC;QAED,cAAc,CAAC,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC;AACvD,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,cAAc,CAAC,OAAO,EAAE;AAC1B,gBAAA,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC;AACrC,gBAAA,cAAc,CAAC,OAAO,GAAG,IAAI;YAC/B;AACF,QAAA,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;;AAGrC,IAAA,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAK;AAC1C,QAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC;;AAE9D,QAAA,IAAI,cAAc,CAAC,OAAO,EAAE;AAC1B,YAAA,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC;AACrC,YAAA,cAAc,CAAC,OAAO,GAAG,IAAI;QAC/B;;QAEA,YAAY,CAAC,KAAK,CAAC;QACnB,uBAAuB,CAAC,IAAI,CAAC;QAC7B,aAAa,CAAC,IAAI,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC;;IAGN,MAAM,oBAAoB,GAAG,WAAW,CACtC,OAAO,UAAkB,EAAE,QAAa,KAAI;AAC1C,QAAA,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO;AAC9B,QAAA,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,GAAG;YAAE;;AAGhC,QAAA,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO;AAC7C,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,UAAU,CAAC;AAC/D,QAAA,IAAI,CAAC,KAAK;YAAE;;AAGZ,QAAA,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,UAAU,CAAC;AACrE,QAAA,qBAAqB,CAAC,OAAO,GAAG,SAAS;QACzC,qBAAqB,CAAC,SAAS,CAAC;AAEhC,QAAA,IAAI;YACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,6CAA6C,EAAE,UAAU,CAAC;YAC7E,MAAM,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC,WAAW,EAAE,GAAG,EAAE;gBAC1D,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;AAC9D,aAAA,CAAC;;AAEF,YAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;gBAC1B,aAAa,CAAC,IAAI,CAAC;gBACnB,YAAY,CAAC,IAAI,CAAC;YACpB;QACF;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,KAAK,CAAC;YACzE,QAAQ,CAAC,KAAK,CAAC;AACf,YAAA,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC7B;AACF,IAAA,CAAC,EACD,CAAC,WAAW,CAAC,CACd;;IAGD,MAAM,gBAAgB,GAAG,WAAW,CAClC,OAAO,UAAkB,EAAE,MAAe,KAAI;QAC5C,MAAM,oBAAoB,CAAC,UAAU,EAAE;YACrC,KAAK,EAAE,MAAM,IAAI,8BAA8B;AAChD,SAAA,CAAC;AACJ,IAAA,CAAC,EACD,CAAC,oBAAoB,CAAC,CACvB;;;AAID,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAW;AACtC,QAAA,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO;QAC9B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,0CAA0C,EAAE,GAAG,CAAC;AACnE,QAAA,IAAI,SAAS,CAAC,OAAO,IAAI,GAAG,EAAE;AAC5B,YAAA,IAAI;gBACF,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;AAClD,gBAAA,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC;YAClE;YAAE,OAAO,GAAG,EAAE;gBACZ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,GAAG,CAAC;YACtE;QACF;QACA,aAAa,CAAC,KAAK,CAAC;QACpB,YAAY,CAAC,KAAK,CAAC;QACnB,SAAS,CAAC,MAAM,CAAC;AACnB,IAAA,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAEjB,OAAO;QACL,QAAQ;QACR,OAAO;QACP,SAAS;QACT,MAAM;QACN,KAAK;QACL,SAAS;QACT,oBAAoB;QACpB,WAAW;QACX,SAAS;QACT,QAAQ;QACR,kBAAkB;QAClB,QAAQ;QACR,kBAAkB;QAClB,oBAAoB;QACpB,gBAAgB;KACjB;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"useDevicChat.js","sources":["../../../src/hooks/useDevicChat.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useOptionalDevicContext } from '../provider';\nimport { DevicApiClient, DevicApiError } from '../api/client';\nimport { usePolling } from './usePolling';\nimport { useModelInterface, type PendingWidgetCall } from './useModelInterface';\nimport { createLogger } from '../utils/logger';\nimport type {\n ChatMessage,\n ChatFile,\n ModelInterfaceTool,\n RealtimeChatHistory,\n RealtimeStatus,\n TenantLimitExceeded,\n} from '../api/types';\n\nexport interface UseDevicChatOptions {\n /**\n * Assistant identifier\n */\n assistantId: string;\n\n /**\n * Existing chat UID to continue a conversation\n */\n chatUid?: string;\n\n /**\n * API key (overrides provider context)\n */\n apiKey?: string;\n\n /**\n * Base URL (overrides provider context)\n */\n baseUrl?: string;\n\n /**\n * Tenant ID for multi-tenant environments\n */\n tenantId?: string;\n\n /**\n * Tenant metadata\n */\n tenantMetadata?: Record<string, any>;\n\n /**\n * Subtenant ID identifying a user/entity inside the tenant\n */\n subtenantId?: string;\n\n /**\n * Subtenant metadata (e.g. { id, name, email })\n */\n subtenantMetadata?: Record<string, any>;\n\n /**\n * Tools enabled from the assistant's configured tool groups\n */\n enabledTools?: string[];\n\n /**\n * Client-side tools for model interface protocol\n */\n modelInterfaceTools?: ModelInterfaceTool[];\n\n /**\n * Polling interval for async mode (ms)\n * @default 1000\n */\n pollingInterval?: number;\n\n /**\n * Callback when a message is sent\n */\n onMessageSent?: (message: ChatMessage) => void;\n\n /**\n * Callback when a message is received\n */\n onMessageReceived?: (message: ChatMessage) => void;\n\n /**\n * Callback when a tool is called\n */\n onToolCall?: (toolName: string, params: any) => void;\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Callback when a new chat is created\n */\n onChatCreated?: (chatUid: string) => void;\n\n /**\n * Custom file upload handler. When provided, replaces the default\n * upload to Devic API. Receives the raw File objects and must return\n * an array of ChatFile with downloadUrl set.\n */\n onFileUpload?: (files: File[]) => Promise<ChatFile[]>;\n\n /**\n * Enable debug logging to the browser console.\n * Overrides the provider-level debug setting when provided.\n * @default false\n */\n debug?: boolean;\n}\n\nexport interface UseDevicChatResult {\n /**\n * Current chat messages\n */\n messages: ChatMessage[];\n\n /**\n * Current chat UID\n */\n chatUid: string | null;\n\n /**\n * Whether a message is being processed\n */\n isLoading: boolean;\n\n /**\n * Current status\n */\n status: RealtimeStatus | 'idle';\n\n /**\n * Last error\n */\n error: Error | null;\n\n /**\n * Set when the last message was blocked by a tenant/subtenant usage limit\n * (HTTP 429 / realtime status `limit_exceeded`). Carries the blocking rule,\n * current vs. limit and when the window resets. `null` while not limited.\n * Cleared when a new message is sent or the chat is cleared.\n */\n limitExceeded: TenantLimitExceeded | null;\n\n /**\n * Whether the assistant has handed off to a subagent\n */\n handedOff: boolean;\n\n /**\n * The subthread ID when a handoff is active\n */\n handedOffSubThreadId: string | null;\n\n /**\n * Send a message\n */\n sendMessage: (\n message: string,\n options?: {\n files?: File[];\n metadata?: Record<string, any>;\n /** Id of a speech-to-text transcript that seeded this message. */\n transcriptId?: string;\n }\n ) => Promise<void>;\n\n /**\n * Clear the chat and start a new conversation\n */\n clearChat: () => void;\n\n /**\n * Load an existing chat\n */\n loadChat: (chatUid: string) => Promise<void>;\n\n /**\n * Called when the handoff subagent completes.\n * Triggers reload of full chat content.\n */\n onHandoffCompleted: () => void;\n\n /**\n * Stop the current conversation processing (client-side only).\n * Stops polling and resets loading state.\n */\n stopChat: () => void;\n\n /**\n * Pending tool calls that require user interaction via a response widget\n */\n pendingWidgetCalls: PendingWidgetCall[];\n\n /**\n * Submit a response for a pending widget tool call.\n * Sends the response to the API and resumes the conversation.\n */\n submitWidgetResponse: (toolCallId: string, response: any) => Promise<void>;\n\n /**\n * Cancel a pending widget tool call.\n * Sends an error response so the model can continue.\n */\n cancelWidgetCall: (toolCallId: string, reason?: string) => Promise<void>;\n}\n\n/**\n * Main hook for managing chat with a Devic assistant\n *\n * @example\n * ```tsx\n * const {\n * messages,\n * isLoading,\n * sendMessage,\n * } = useDevicChat({\n * assistantId: 'my-assistant',\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 function useDevicChat(options: UseDevicChatOptions): UseDevicChatResult {\n const {\n assistantId,\n chatUid: initialChatUid,\n apiKey: propsApiKey,\n baseUrl: propsBaseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n enabledTools,\n modelInterfaceTools = [],\n pollingInterval = 1000,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n debug: propsDebug,\n } = options;\n\n // Get context (may be null if not wrapped in provider)\n const context = useOptionalDevicContext();\n\n // Resolve configuration\n const apiKey = propsApiKey || context?.apiKey;\n const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n const resolvedSubtenantMetadata = {\n ...context?.subtenantMetadata,\n ...subtenantMetadata,\n };\n const debug = propsDebug ?? context?.debug ?? false;\n const log = useMemo(() => createLogger(debug), [debug]);\n const logRef = useRef(log);\n logRef.current = log;\n\n // State\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [chatUid, setChatUid] = useState<string | null>(initialChatUid || null);\n const [isLoading, setIsLoading] = useState(false);\n const [status, setStatus] = useState<RealtimeStatus | 'idle'>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [limitExceeded, setLimitExceeded] = useState<TenantLimitExceeded | null>(\n null\n );\n\n // Handoff state\n const [handedOff, setHandedOff] = useState(false);\n const [handedOffSubThreadId, setHandedOffSubThreadId] = useState<string | null>(null);\n const handoffPollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Polling state\n const [shouldPoll, setShouldPoll] = useState(false);\n\n // Keep a ref to chatUid so async callbacks always read the latest value\n const chatUidRef = useRef(chatUid);\n chatUidRef.current = chatUid;\n\n // Refs for callbacks\n const onMessageReceivedRef = useRef(onMessageReceived);\n const onErrorRef = useRef(onError);\n const onChatCreatedRef = useRef(onChatCreated);\n\n useEffect(() => {\n onMessageReceivedRef.current = onMessageReceived;\n onErrorRef.current = onError;\n onChatCreatedRef.current = onChatCreated;\n });\n\n // Create API client\n const clientRef = useRef<DevicApiClient | null>(null);\n if (!clientRef.current && apiKey) {\n clientRef.current = new DevicApiClient({ apiKey, baseUrl });\n }\n\n // Update client config if it changes\n useEffect(() => {\n if (clientRef.current && apiKey) {\n clientRef.current.setConfig({ apiKey, baseUrl });\n }\n }, [apiKey, baseUrl]);\n\n // Resume chat state based on realtime status.\n // Called after loading chat history to detect in-progress conversations.\n const resumeFromRealtimeStatus = useCallback(\n async (targetChatUid: string) => {\n if (!clientRef.current) return;\n try {\n const realtime = await clientRef.current.getRealtimeHistory(assistantId, targetChatUid);\n logRef.current.log('[useDevicChat] resumeFromRealtimeStatus:', realtime.status);\n\n // Update messages with realtime data (may be fresher than static history)\n if (realtime.chatHistory?.length) {\n setMessages(realtime.chatHistory);\n }\n setStatus(realtime.status);\n\n if (realtime.status === 'processing') {\n // Chat is still processing — resume polling\n setIsLoading(true);\n setShouldPoll(true);\n } else if (realtime.status === 'waiting_for_tool_response') {\n // Chat is waiting for tool response — resume polling to trigger tool handling\n setIsLoading(true);\n setShouldPoll(true);\n } else if (realtime.status === 'handed_off') {\n // Chat has an active handoff\n setIsLoading(true);\n setHandedOff(true);\n const subThreadId = realtime.handedOffSubThreadId || null;\n logRef.current.log('[useDevicChat] Resuming handoff state:', { subThreadId });\n if (subThreadId) {\n setHandedOffSubThreadId(subThreadId);\n }\n } else {\n // completed or error — just stop\n setIsLoading(false);\n }\n } catch (err) {\n // If realtime fetch fails (e.g. chat has no realtime entry), just stay idle\n logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);\n setIsLoading(false);\n }\n },\n [assistantId]\n );\n\n // Load initial chat history if chatUid prop is provided\n // This runs once on mount (or when initialChatUid changes) to fetch existing conversation\n const initialChatLoadedRef = useRef(false);\n useEffect(() => {\n if (initialChatUid && clientRef.current && !initialChatLoadedRef.current) {\n initialChatLoadedRef.current = true;\n\n const loadInitialChat = async () => {\n setIsLoading(true);\n setError(null);\n try {\n const history = await clientRef.current!.getChatHistory(\n assistantId,\n initialChatUid,\n { tenantId: resolvedTenantId }\n );\n setMessages(history.chatContent);\n setChatUid(initialChatUid);\n\n // Check realtime status to resume in-progress conversations\n await resumeFromRealtimeStatus(initialChatUid);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n setIsLoading(false);\n }\n };\n\n loadInitialChat();\n }\n }, [initialChatUid, assistantId, resolvedTenantId, resumeFromRealtimeStatus]);\n\n // Model interface hook\n const {\n toolSchemas,\n handleToolCalls,\n extractPendingToolCalls,\n } = useModelInterface({\n tools: modelInterfaceTools,\n onToolExecute: onToolCall,\n });\n\n // Pending widget calls awaiting user interaction\n const [pendingWidgetCalls, setPendingWidgetCalls] = useState<PendingWidgetCall[]>([]);\n const pendingWidgetCallsRef = useRef<PendingWidgetCall[]>([]);\n useEffect(() => {\n pendingWidgetCallsRef.current = pendingWidgetCalls;\n }, [pendingWidgetCalls]);\n\n // Polling hook - uses callbacks for side effects, return value not needed\n logRef.current.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);\n usePolling(\n shouldPoll ? chatUid : null,\n async () => {\n logRef.current.log('[useDevicChat] fetchFn called, chatUid:', chatUid);\n if (!clientRef.current || !chatUid) {\n throw new Error('Cannot poll without client or chatUid');\n }\n const result = await clientRef.current.getRealtimeHistory(assistantId, chatUid);\n logRef.current.log('[useDevicChat] getRealtimeHistory result:', result);\n return result;\n },\n {\n interval: pollingInterval,\n enabled: shouldPoll,\n stopStatuses: [\n 'completed',\n 'error',\n 'waiting_for_tool_response',\n 'handed_off',\n 'limit_exceeded',\n ],\n onUpdate: async (data: RealtimeChatHistory) => {\n logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);\n\n // Merge realtime data with optimistic messages.\n // When a server user message matches an optimistic one by text, adopt the\n // optimistic uid so React's key stays stable (avoids unmount/remount flicker).\n setMessages((prev) => {\n const normalize = (t?: string) => (t ?? '').trim();\n const optimisticUserByText = new Map(\n prev\n .filter((m) => m.role === 'user' && m.uid.startsWith('temp-'))\n .map((m) => [normalize(m.content?.message), m.uid])\n );\n\n const adoptedTempUids = new Set<string>();\n const merged = data.chatHistory.map((m) => {\n if (m.role === 'user') {\n const tempUid = optimisticUserByText.get(normalize(m.content?.message));\n if (tempUid) {\n adoptedTempUids.add(tempUid);\n return { ...m, uid: tempUid };\n }\n }\n return m;\n });\n\n const mergedUIDs = new Set(merged.map((m) => m.uid));\n const optimistic = prev.filter(\n (m) => !mergedUIDs.has(m.uid) && !adoptedTempUids.has(m.uid)\n );\n\n return [...merged, ...optimistic];\n });\n setStatus(data.status);\n\n // Notify about new messages\n const lastMessage = data.chatHistory[data.chatHistory.length - 1];\n if (lastMessage && lastMessage.role === 'assistant') {\n onMessageReceivedRef.current?.(lastMessage);\n }\n\n // Handle model interface - check for pending tool calls\n if (data.status === 'waiting_for_tool_response' || data.pendingToolCalls?.length) {\n await handlePendingToolCalls(data);\n }\n },\n onStop: (data) => {\n logRef.current.log('[useDevicChat] onStop called, status:', data?.status);\n setShouldPoll(false);\n\n if (data?.status === 'limit_exceeded') {\n // The message was blocked by a tenant/subtenant usage limit before\n // reaching the LLM. Surface the details so the UI can show a banner.\n setIsLoading(false);\n const details: TenantLimitExceeded = data.limitExceeded || {\n message: 'Usage limit reached.',\n };\n setLimitExceeded(details);\n const err = new Error(\n details.message || 'Usage limit reached.'\n ) as Error & { errorType?: string; details?: TenantLimitExceeded };\n err.errorType = 'TENANT_LIMIT_EXCEEDED';\n err.details = details;\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'error') {\n setIsLoading(false);\n const err = new Error('Chat processing failed');\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'completed') {\n setIsLoading(false);\n } else if (data?.status === 'handed_off') {\n // Subagent is working — keep isLoading true so the UI stays in loading state.\n // Set handoff state directly from the realtime status.\n setHandedOff(true);\n\n const subThreadId = data.handedOffSubThreadId || null;\n logRef.current.log('[useDevicChat] Handoff state set:', { handedOff: true, subThreadId });\n if (subThreadId) {\n setHandedOffSubThreadId(subThreadId);\n }\n }\n // Note: waiting_for_tool_response is handled in onUpdate to avoid double execution\n },\n onError: (err) => {\n logRef.current.error('[useDevicChat] onError called:', err);\n setError(err);\n setIsLoading(false);\n setShouldPoll(false);\n onErrorRef.current?.(err);\n },\n debug,\n }\n );\n\n // Handle pending tool calls from model interface\n const handlePendingToolCalls = useCallback(\n async (data: RealtimeChatHistory) => {\n if (!clientRef.current || !chatUid) return;\n\n // Get pending tool calls\n const pendingCalls = data.pendingToolCalls || extractPendingToolCalls(data.chatHistory);\n\n if (pendingCalls.length === 0) return;\n\n try {\n // Execute client-side tools (partitioned into immediate responses and widget-driven)\n const { responses, widgetCalls } = await handleToolCalls(pendingCalls);\n\n // Queue widget-driven tool calls for user interaction\n if (widgetCalls.length > 0) {\n const existingIds = new Set(pendingWidgetCallsRef.current.map((c) => c.toolCall.id));\n const deduped = widgetCalls.filter((c) => !existingIds.has(c.toolCall.id));\n const next = [...pendingWidgetCallsRef.current, ...deduped];\n pendingWidgetCallsRef.current = next;\n setPendingWidgetCalls(next);\n // Stop polling while we wait for the user to submit the widget response.\n // The widget submission will re-trigger polling via submitWidgetResponse.\n setShouldPoll(false);\n setIsLoading(false);\n }\n\n if (responses.length > 0) {\n // Send tool responses back to the API\n await clientRef.current.sendToolResponses(assistantId, chatUid, responses);\n\n // Only resume polling if no widgets are blocking\n if (widgetCalls.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [chatUid, assistantId, handleToolCalls, extractPendingToolCalls]\n );\n\n // Send a message\n const sendMessage = useCallback(\n async (\n message: string,\n sendOptions?: {\n files?: File[];\n metadata?: Record<string, any>;\n transcriptId?: string;\n }\n ) => {\n if (!clientRef.current) {\n const err = new Error(\n 'API client not configured. Please provide an API key.'\n );\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n setLimitExceeded(null);\n setStatus('processing');\n\n // Add user message optimistically (show file names before upload)\n const userMessage: ChatMessage = {\n uid: `temp-${Date.now()}`,\n role: 'user',\n content: {\n message,\n files: sendOptions?.files?.map((f) => ({\n name: f.name,\n url: '',\n type: f.type.split('/')[0] || 'other',\n })),\n },\n timestamp: Date.now(),\n ...(sendOptions?.transcriptId && {\n transcriptId: sendOptions.transcriptId,\n }),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n try {\n // Upload files if provided\n let uploadedFiles: ChatFile[] | undefined;\n if (sendOptions?.files && sendOptions.files.length > 0) {\n logRef.current.log('[useDevicChat] Uploading files...');\n if (onFileUpload) {\n // Use custom upload handler\n uploadedFiles = await onFileUpload(sendOptions.files);\n } else {\n // Default: upload via Devic API\n const uploadResults = await Promise.all(\n sendOptions.files.map((file) => clientRef.current!.uploadFile(file))\n );\n uploadedFiles = uploadResults.map((r) => ({\n name: r.name,\n downloadUrl: r.downloadUrl,\n fileType: r.fileType as ChatFile['fileType'],\n }));\n }\n logRef.current.log('[useDevicChat] Files uploaded:', uploadedFiles);\n\n // Update optimistic message with download URLs\n setMessages((prev) =>\n prev.map((m) =>\n m.uid === userMessage.uid\n ? {\n ...m,\n content: {\n ...m.content,\n files: uploadedFiles!.map((f) => ({\n name: f.name,\n url: f.downloadUrl || '',\n type: f.fileType || 'other',\n })),\n },\n }\n : m\n )\n );\n }\n\n // Build request DTO\n const hasSubtenantMetadata =\n resolvedSubtenantMetadata &&\n Object.keys(resolvedSubtenantMetadata).length > 0;\n const dto = {\n message,\n chatUid: chatUid || undefined,\n files: uploadedFiles,\n metadata: {\n ...resolvedTenantMetadata,\n ...(hasSubtenantMetadata && {\n subtenantMetadata: resolvedSubtenantMetadata,\n }),\n ...sendOptions?.metadata,\n },\n tenantId: resolvedTenantId,\n ...(resolvedSubtenantId && { subtenantId: resolvedSubtenantId }),\n enabledTools,\n // Include model interface tools if any\n ...(toolSchemas.length > 0 && { tools: toolSchemas }),\n // Link to the speech-to-text transcript that seeded this message, if any\n ...(sendOptions?.transcriptId && { transcriptId: sendOptions.transcriptId }),\n };\n\n // Send message in async mode\n logRef.current.log('[useDevicChat] Sending message async...');\n const response = await clientRef.current.sendMessageAsync(assistantId, dto);\n logRef.current.log('[useDevicChat] sendMessageAsync response:', response);\n\n // Update chat UID if this is a new chat\n if (response.chatUid && response.chatUid !== chatUid) {\n logRef.current.log('[useDevicChat] Setting chatUid:', response.chatUid);\n setChatUid(response.chatUid);\n onChatCreatedRef.current?.(response.chatUid);\n }\n\n // Start polling for results\n logRef.current.log('[useDevicChat] Setting shouldPoll to true');\n setShouldPoll(true);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n // A synchronous usage-limit block surfaces as HTTP 429 /\n // TENANT_LIMIT_EXCEEDED (sync send path). Async sends surface it via the\n // realtime `limit_exceeded` status instead — both are handled.\n if (\n err instanceof DevicApiError &&\n (err.statusCode === 429 || err.errorType === 'TENANT_LIMIT_EXCEEDED')\n ) {\n const details: TenantLimitExceeded =\n (err.details as TenantLimitExceeded) || { message: err.message };\n if (!details.message) details.message = err.message;\n setLimitExceeded(details);\n }\n\n setError(error);\n setIsLoading(false);\n setStatus('error');\n onErrorRef.current?.(error);\n\n // Remove optimistic user message on error\n setMessages((prev) => prev.filter((m) => m.uid !== userMessage.uid));\n }\n },\n [\n chatUid,\n assistantId,\n enabledTools,\n resolvedTenantId,\n resolvedTenantMetadata,\n resolvedSubtenantId,\n resolvedSubtenantMetadata,\n toolSchemas,\n onMessageSent,\n onFileUpload,\n ]\n );\n\n // Clear chat\n const clearChat = useCallback(() => {\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n setMessages([]);\n setChatUid(null);\n setIsLoading(false);\n setStatus('idle');\n setError(null);\n setLimitExceeded(null);\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n }, []);\n\n // Load existing chat\n const loadChat = useCallback(\n async (loadChatUid: string) => {\n if (!clientRef.current) {\n const err = new Error('API client not configured');\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n // Reset any active polling/handoff state from previous conversation\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const history = await clientRef.current.getChatHistory(\n assistantId,\n loadChatUid,\n { tenantId: resolvedTenantId }\n );\n\n setMessages(history.chatContent);\n setChatUid(loadChatUid);\n\n // Check realtime status to resume in-progress conversations\n await resumeFromRealtimeStatus(loadChatUid);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n setIsLoading(false);\n }\n },\n [assistantId, resolvedTenantId, resumeFromRealtimeStatus]\n );\n\n // Handoff polling: while handedOff is true, poll the realtime endpoint every 5s\n // to detect when the parent thread is no longer in handed_off state.\n useEffect(() => {\n if (!handedOff || !chatUid || !clientRef.current) return;\n\n const pollHandoff = async () => {\n try {\n const realtime = await clientRef.current!.getRealtimeHistory(assistantId, chatUid!);\n logRef.current.log('[useDevicChat] Handoff poll - realtime status:', realtime.status);\n if (realtime.status !== 'handed_off') {\n // Handoff completed — clear handoff state and resume main polling\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n // Resume main polling to pick up the parent thread's continuation\n setShouldPoll(true);\n }\n } catch {}\n };\n\n handoffPollRef.current = setInterval(pollHandoff, 5000);\n return () => {\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n };\n }, [handedOff, chatUid, assistantId]);\n\n // Called by HandoffSubagentWidget when the subthread reaches a terminal state\n const onHandoffCompleted = useCallback(() => {\n logRef.current.log('[useDevicChat] onHandoffCompleted called');\n // Clear the handoff polling\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n // Clear handoff state and resume main polling\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n setShouldPoll(true);\n }, []);\n\n // Submit a response for a pending widget tool call\n const submitWidgetResponse = useCallback(\n async (toolCallId: string, response: any) => {\n const uid = chatUidRef.current;\n if (!clientRef.current || !uid) return;\n\n // Check pending widgets via ref (state updates are async)\n const current = pendingWidgetCallsRef.current;\n const found = current.some((c) => c.toolCall.id === toolCallId);\n if (!found) return;\n\n // Remove the widget call from pending list\n const remaining = current.filter((c) => c.toolCall.id !== toolCallId);\n pendingWidgetCallsRef.current = remaining;\n setPendingWidgetCalls(remaining);\n\n try {\n logRef.current.log('[useDevicChat] sending widget tool response', toolCallId);\n await clientRef.current.sendToolResponses(assistantId, uid, [\n { tool_call_id: toolCallId, content: response, role: 'tool' },\n ]);\n // Resume polling only if no more widget calls are blocking\n if (remaining.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logRef.current.error('[useDevicChat] submitWidgetResponse failed', error);\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [assistantId]\n );\n\n // Cancel a pending widget tool call (sends an error response to the model)\n const cancelWidgetCall = useCallback(\n async (toolCallId: string, reason?: string) => {\n await submitWidgetResponse(toolCallId, {\n error: reason || 'User cancelled the tool call',\n });\n },\n [submitWidgetResponse]\n );\n\n // Stop current conversation — calls the server-side stop endpoint\n // then stops polling and resets loading state.\n const stopChat = useCallback(async () => {\n const uid = chatUidRef.current;\n logRef.current.log('[useDevicChat] stopChat called, chatUid:', uid);\n if (clientRef.current && uid) {\n try {\n await clientRef.current.stopChat(assistantId, uid);\n logRef.current.log('[useDevicChat] stopChat API call succeeded');\n } catch (err) {\n logRef.current.warn('[useDevicChat] stopChat API call failed:', err);\n }\n }\n setShouldPoll(false);\n setIsLoading(false);\n setStatus('idle');\n }, [assistantId]);\n\n return {\n messages,\n chatUid,\n isLoading,\n status,\n error,\n limitExceeded,\n handedOff,\n handedOffSubThreadId,\n sendMessage,\n clearChat,\n loadChat,\n onHandoffCompleted,\n stopChat,\n pendingWidgetCalls,\n submitWidgetResponse,\n cancelWidgetCall,\n };\n}\n"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { DevicProvider, DevicContext, useDevicContext, useOptionalDevicContext } from './provider';
|
|
2
2
|
export type { DevicProviderConfig, DevicProviderProps, DevicContextValue, AIReference, DrawerRegistration, } from './provider';
|
|
3
|
-
export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector, HandoffSubagentWidget } from './components/ChatDrawer';
|
|
4
|
-
export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, HandoffSubagentWidgetProps, SuggestedMessage, } from './components/ChatDrawer';
|
|
3
|
+
export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector, HandoffSubagentWidget, UsageBar, LimitBanner } from './components/ChatDrawer';
|
|
4
|
+
export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, HandoffSubagentWidgetProps, SuggestedMessage, UsageBarProps, LimitBannerProps, } from './components/ChatDrawer';
|
|
5
5
|
export { ThreadStateTag } from './components/ThreadStateTag';
|
|
6
6
|
export type { ThreadStateTagProps, StateConfig } from './components/ThreadStateTag';
|
|
7
7
|
export { AICommandBar, useAICommandBar, formatShortcut } from './components/AICommandBar';
|
|
@@ -15,7 +15,7 @@ export type { UseDevicChatOptions, UseDevicChatResult, UsePollingOptions, UsePol
|
|
|
15
15
|
export { DevicApiClient, DevicApiError } from './api/client';
|
|
16
16
|
export type { DevicApiClientConfig } from './api/client';
|
|
17
17
|
export { AgentThreadState, } from './api/types';
|
|
18
|
-
export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, ResponseWidgetProps, ResponseWidgetConfig, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentTaskDto, AgentDto, HandOffToolResponse, ToolGroupCall, ToolGroupConfig, WhisperTranscriptionResponse, } from './api/types';
|
|
18
|
+
export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, ResponseWidgetProps, ResponseWidgetConfig, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentTaskDto, AgentDto, HandOffToolResponse, ToolGroupCall, ToolGroupConfig, WhisperTranscriptionResponse, TenantLimitExceeded, TenantUsage, TenantUsageRule, TenantUsageHistoryRow, TenantUsageHistoryQuery, } from './api/types';
|
|
19
19
|
export { MessageActions, FeedbackModal } from './components/Feedback';
|
|
20
20
|
export type { MessageActionsProps, FeedbackModalProps, FeedbackState, FeedbackTheme } from './components/Feedback';
|
|
21
21
|
export { generateId, deepMerge, debounce, throttle, formatFileSize, storage, segmentToolCalls } from './utils';
|
package/dist/esm/index.js
CHANGED
|
@@ -6,6 +6,8 @@ export { ChatInput } from './components/ChatDrawer/ChatInput.js';
|
|
|
6
6
|
export { ToolTimeline } from './components/ChatDrawer/ToolTimeline.js';
|
|
7
7
|
export { ConversationSelector } from './components/ChatDrawer/ConversationSelector.js';
|
|
8
8
|
export { HandoffSubagentWidget } from './components/ChatDrawer/HandoffSubagentWidget.js';
|
|
9
|
+
export { UsageBar } from './components/ChatDrawer/UsageBar.js';
|
|
10
|
+
export { LimitBanner } from './components/ChatDrawer/LimitBanner.js';
|
|
9
11
|
export { ThreadStateTag } from './components/ThreadStateTag/ThreadStateTag.js';
|
|
10
12
|
export { AICommandBar } from './components/AICommandBar/AICommandBar.js';
|
|
11
13
|
export { formatShortcut, useAICommandBar } from './components/AICommandBar/useAICommandBar.js';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -14,4 +14,4 @@ import type { DevicProviderProps } from './types';
|
|
|
14
14
|
* </DevicProvider>
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
export declare function DevicProvider({ apiKey, baseUrl, tenantId, tenantMetadata, debug, children, }: DevicProviderProps): JSX.Element;
|
|
17
|
+
export declare function DevicProvider({ apiKey, baseUrl, tenantId, tenantMetadata, subtenantId, subtenantMetadata, debug, children, }: DevicProviderProps): JSX.Element;
|
|
@@ -20,7 +20,7 @@ const DEFAULT_BASE_URL = 'https://api.devic.ai';
|
|
|
20
20
|
* </DevicProvider>
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
-
function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, debug, children, }) {
|
|
23
|
+
function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, subtenantId, subtenantMetadata, debug, children, }) {
|
|
24
24
|
const [references, setReferences] = useState([]);
|
|
25
25
|
const drawerRef = useRef(null);
|
|
26
26
|
const addReference = useCallback((ref) => {
|
|
@@ -52,6 +52,8 @@ function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMet
|
|
|
52
52
|
baseUrl,
|
|
53
53
|
tenantId,
|
|
54
54
|
tenantMetadata,
|
|
55
|
+
subtenantId,
|
|
56
|
+
subtenantMetadata,
|
|
55
57
|
isConfigured: !!apiKey,
|
|
56
58
|
debug,
|
|
57
59
|
references,
|
|
@@ -66,6 +68,8 @@ function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMet
|
|
|
66
68
|
baseUrl,
|
|
67
69
|
tenantId,
|
|
68
70
|
tenantMetadata,
|
|
71
|
+
subtenantId,
|
|
72
|
+
subtenantMetadata,
|
|
69
73
|
debug,
|
|
70
74
|
references,
|
|
71
75
|
addReference,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevicProvider.js","sources":["../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo, useState, useRef, useCallback } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport { generateId } from '../utils';\nimport type {\n DevicProviderProps,\n DevicContextValue,\n AIReference,\n DrawerRegistration,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n debug,\n children,\n}: DevicProviderProps): JSX.Element {\n const [references, setReferences] = useState<AIReference[]>([]);\n const drawerRef = useRef<DrawerRegistration | null>(null);\n\n const addReference = useCallback((ref: Omit<AIReference, 'id'>): string => {\n const id = generateId();\n setReferences((prev) => [...prev, { ...ref, id }]);\n return id;\n }, []);\n\n const removeReference = useCallback((id: string) => {\n setReferences((prev) => prev.filter((r) => r.id !== id));\n }, []);\n\n const clearReferences = useCallback(() => {\n setReferences([]);\n }, []);\n\n const registerDrawer = useCallback((handle: DrawerRegistration) => {\n drawerRef.current = handle;\n return () => {\n if (drawerRef.current === handle) {\n drawerRef.current = null;\n }\n };\n }, []);\n\n const openDrawer = useCallback(() => {\n drawerRef.current?.open();\n }, []);\n\n const client = useMemo(\n () => new DevicApiClient({ apiKey, baseUrl }),\n [apiKey, baseUrl]\n );\n\n const contextValue = useMemo<DevicContextValue>(\n () => ({\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n isConfigured: !!apiKey,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n }),\n [\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n ]\n );\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["_jsx"],"mappings":";;;;;;AAWA,MAAM,gBAAgB,GAAG,sBAAsB;AAE/C;;;;;;;;;;;;;;AAcG;
|
|
1
|
+
{"version":3,"file":"DevicProvider.js","sources":["../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo, useState, useRef, useCallback } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport { generateId } from '../utils';\nimport type {\n DevicProviderProps,\n DevicContextValue,\n AIReference,\n DrawerRegistration,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n debug,\n children,\n}: DevicProviderProps): JSX.Element {\n const [references, setReferences] = useState<AIReference[]>([]);\n const drawerRef = useRef<DrawerRegistration | null>(null);\n\n const addReference = useCallback((ref: Omit<AIReference, 'id'>): string => {\n const id = generateId();\n setReferences((prev) => [...prev, { ...ref, id }]);\n return id;\n }, []);\n\n const removeReference = useCallback((id: string) => {\n setReferences((prev) => prev.filter((r) => r.id !== id));\n }, []);\n\n const clearReferences = useCallback(() => {\n setReferences([]);\n }, []);\n\n const registerDrawer = useCallback((handle: DrawerRegistration) => {\n drawerRef.current = handle;\n return () => {\n if (drawerRef.current === handle) {\n drawerRef.current = null;\n }\n };\n }, []);\n\n const openDrawer = useCallback(() => {\n drawerRef.current?.open();\n }, []);\n\n const client = useMemo(\n () => new DevicApiClient({ apiKey, baseUrl }),\n [apiKey, baseUrl]\n );\n\n const contextValue = useMemo<DevicContextValue>(\n () => ({\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n isConfigured: !!apiKey,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n }),\n [\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n ]\n );\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["_jsx"],"mappings":";;;;;;AAWA,MAAM,gBAAgB,GAAG,sBAAsB;AAE/C;;;;;;;;;;;;;;AAcG;AACG,SAAU,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,GAAG,gBAAgB,EAC1B,QAAQ,EACR,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,KAAK,EACL,QAAQ,GACW,EAAA;IACnB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAgB,EAAE,CAAC;AAC/D,IAAA,MAAM,SAAS,GAAG,MAAM,CAA4B,IAAI,CAAC;AAEzD,IAAA,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,GAA4B,KAAY;AACxE,QAAA,MAAM,EAAE,GAAG,UAAU,EAAE;AACvB,QAAA,aAAa,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;AAClD,QAAA,OAAO,EAAE;IACX,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,EAAU,KAAI;QACjD,aAAa,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,eAAe,GAAG,WAAW,CAAC,MAAK;QACvC,aAAa,CAAC,EAAE,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,MAA0B,KAAI;AAChE,QAAA,SAAS,CAAC,OAAO,GAAG,MAAM;AAC1B,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,SAAS,CAAC,OAAO,KAAK,MAAM,EAAE;AAChC,gBAAA,SAAS,CAAC,OAAO,GAAG,IAAI;YAC1B;AACF,QAAA,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,UAAU,GAAG,WAAW,CAAC,MAAK;AAClC,QAAA,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;IAC3B,CAAC,EAAE,EAAE,CAAC;IAEN,MAAM,MAAM,GAAG,OAAO,CACpB,MAAM,IAAI,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAC7C,CAAC,MAAM,EAAE,OAAO,CAAC,CAClB;AAED,IAAA,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO;QACL,MAAM;QACN,MAAM;QACN,OAAO;QACP,QAAQ;QACR,cAAc;QACd,WAAW;QACX,iBAAiB;QACjB,YAAY,EAAE,CAAC,CAAC,MAAM;QACtB,KAAK;QACL,UAAU;QACV,YAAY;QACZ,eAAe;QACf,eAAe;QACf,cAAc;QACd,UAAU;AACX,KAAA,CAAC,EACF;QACE,MAAM;QACN,MAAM;QACN,OAAO;QACP,QAAQ;QACR,cAAc;QACd,WAAW;QACX,iBAAiB;QACjB,KAAK;QACL,UAAU;QACV,YAAY;QACZ,eAAe;QACf,eAAe;QACf,cAAc;QACd,UAAU;AACX,KAAA,CACF;AAED,IAAA,QACEA,GAAA,CAAC,YAAY,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,YAAY,EAAA,QAAA,EACvC,QAAQ,EAAA,CACa;AAE5B;;;;"}
|
|
@@ -20,6 +20,16 @@ export interface DevicProviderConfig {
|
|
|
20
20
|
* Global tenant metadata
|
|
21
21
|
*/
|
|
22
22
|
tenantMetadata?: Record<string, any>;
|
|
23
|
+
/**
|
|
24
|
+
* Global subtenant ID identifying a user/entity inside the tenant
|
|
25
|
+
* (e.g. an end user of a SaaS that integrates Devic).
|
|
26
|
+
*/
|
|
27
|
+
subtenantId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Global subtenant metadata (e.g. { id, name, email }). Used for
|
|
30
|
+
* per-subtenant cost attribution and automatic tenant domain detection.
|
|
31
|
+
*/
|
|
32
|
+
subtenantMetadata?: Record<string, any>;
|
|
23
33
|
/**
|
|
24
34
|
* Enable debug logging to the browser console
|
|
25
35
|
* @default false
|
|
@@ -74,6 +84,14 @@ export interface DevicContextValue {
|
|
|
74
84
|
* Global tenant metadata
|
|
75
85
|
*/
|
|
76
86
|
tenantMetadata?: Record<string, any>;
|
|
87
|
+
/**
|
|
88
|
+
* Global subtenant ID
|
|
89
|
+
*/
|
|
90
|
+
subtenantId?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Global subtenant metadata
|
|
93
|
+
*/
|
|
94
|
+
subtenantMetadata?: Record<string, any>;
|
|
77
95
|
/**
|
|
78
96
|
* Whether the provider is properly configured
|
|
79
97
|
*/
|