@devicai/ui 0.10.2 → 0.10.3
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/components/ChatDrawer/ChatDrawer.js +2 -0
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/HandoffSubagentWidget.js +9 -6
- package/dist/cjs/components/ChatDrawer/HandoffSubagentWidget.js.map +1 -1
- package/dist/cjs/hooks/useDevicChat.js +89 -27
- package/dist/cjs/hooks/useDevicChat.js.map +1 -1
- package/dist/cjs/hooks/usePolling.js +16 -12
- package/dist/cjs/hooks/usePolling.js.map +1 -1
- package/dist/cjs/provider/DevicProvider.js +3 -2
- package/dist/cjs/provider/DevicProvider.js.map +1 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/logger.js +17 -0
- package/dist/cjs/utils/logger.js.map +1 -0
- package/dist/esm/components/ChatDrawer/ChatDrawer.js +2 -0
- package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +6 -0
- package/dist/esm/components/ChatDrawer/HandoffSubagentWidget.js +10 -7
- package/dist/esm/components/ChatDrawer/HandoffSubagentWidget.js.map +1 -1
- package/dist/esm/hooks/useDevicChat.d.ts +6 -0
- package/dist/esm/hooks/useDevicChat.js +90 -28
- package/dist/esm/hooks/useDevicChat.js.map +1 -1
- package/dist/esm/hooks/usePolling.d.ts +5 -0
- package/dist/esm/hooks/usePolling.js +17 -13
- package/dist/esm/hooks/usePolling.js.map +1 -1
- package/dist/esm/provider/DevicProvider.d.ts +1 -1
- package/dist/esm/provider/DevicProvider.js +3 -2
- package/dist/esm/provider/DevicProvider.js.map +1 -1
- package/dist/esm/provider/types.d.ts +9 -0
- package/dist/esm/utils/index.d.ts +2 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/logger.d.ts +10 -0
- package/dist/esm/utils/logger.js +15 -0
- package/dist/esm/utils/logger.js.map +1 -0
- package/package.json +1 -1
|
@@ -48,6 +48,7 @@ const DEFAULT_OPTIONS = {
|
|
|
48
48
|
handoffWidgetRenderer: undefined,
|
|
49
49
|
toolGroups: undefined,
|
|
50
50
|
stopButtonContent: undefined,
|
|
51
|
+
debug: false,
|
|
51
52
|
};
|
|
52
53
|
/**
|
|
53
54
|
* Chat drawer component for Devic assistants
|
|
@@ -99,6 +100,7 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
|
|
|
99
100
|
onToolCall,
|
|
100
101
|
onError,
|
|
101
102
|
onChatCreated,
|
|
103
|
+
debug: mergedOptions.debug,
|
|
102
104
|
});
|
|
103
105
|
// Fetch assistant avatar when showAvatar is enabled
|
|
104
106
|
const context = DevicContext.useOptionalDevicContext();
|
|
@@ -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 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 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};\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 apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\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 // 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 // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: initialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // 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 // Handle send message\n const handleSend = useCallback(\n (message: string, files?: any[]) => {\n chat.sendMessage(message, { files });\n },\n [chat]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n },\n [chat, onConversationChange]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n }, [chat]);\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 />\n <div className=\"devic-drawer-header-actions\">\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n handedOffSubThreadId={chat.handedOffSubThreadId || undefined}\n onHandoffCompleted={chat.onHandoffCompleted}\n handoffWidgetRenderer={mergedOptions.handoffWidgetRenderer}\n toolGroups={mergedOptions.toolGroups}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n />\n\n {/* Input */}\n <ChatInput\n onSend={handleSend}\n disabled={chat.isLoading || chat.handedOff}\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n sendButtonContent={mergedOptions.sendButtonContent}\n disabledMessage={chat.handedOff ? 'Waiting for subagent to complete' : undefined}\n isProcessing={chat.isLoading && !chat.handedOff}\n onStop={chat.stopChat}\n stopButtonContent={mergedOptions.stopButtonContent}\n />\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["forwardRef","_jsx","ChatDrawerErrorBoundary","useMemo","useState","useDevicChat","useOptionalDevicContext","useRef","useEffect","client","DevicApiClient","useCallback","useImperativeHandle","_jsxs","ConversationSelector","ChatMessages","ChatInput"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatDrawer.js","sources":["../../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport { ConversationSelector } from './ConversationSelector';\nimport { ChatDrawerErrorBoundary } from './ErrorBoundary';\nimport 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 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};\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 apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\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 // 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 // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: initialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n debug: mergedOptions.debug,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // 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 // Handle send message\n const handleSend = useCallback(\n (message: string, files?: any[]) => {\n chat.sendMessage(message, { files });\n },\n [chat]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n },\n [chat, onConversationChange]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n }, [chat]);\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 />\n <div className=\"devic-drawer-header-actions\">\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n handedOffSubThreadId={chat.handedOffSubThreadId || undefined}\n onHandoffCompleted={chat.onHandoffCompleted}\n handoffWidgetRenderer={mergedOptions.handoffWidgetRenderer}\n toolGroups={mergedOptions.toolGroups}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n />\n\n {/* Input */}\n <ChatInput\n onSend={handleSend}\n disabled={chat.isLoading || chat.handedOff}\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n sendButtonContent={mergedOptions.sendButtonContent}\n disabledMessage={chat.handedOff ? 'Waiting for subagent to complete' : undefined}\n isProcessing={chat.isLoading && !chat.handedOff}\n onStop={chat.stopChat}\n stopButtonContent={mergedOptions.stopButtonContent}\n />\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["forwardRef","_jsx","ChatDrawerErrorBoundary","useMemo","useState","useDevicChat","useOptionalDevicContext","useRef","useEffect","client","DevicApiClient","useCallback","useImperativeHandle","_jsxs","ConversationSelector","ChatMessages","ChatInput"],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ var DevicContext = require('../../provider/DevicContext.js');
|
|
|
6
6
|
var client = require('../../api/client.js');
|
|
7
7
|
var types = require('../../api/types.js');
|
|
8
8
|
var ThreadStateTag = require('../ThreadStateTag/ThreadStateTag.js');
|
|
9
|
+
var logger = require('../../utils/logger.js');
|
|
9
10
|
|
|
10
11
|
const TERMINAL_STATES = [
|
|
11
12
|
types.AgentThreadState.COMPLETED,
|
|
@@ -22,6 +23,8 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
22
23
|
const context = DevicContext.useOptionalDevicContext();
|
|
23
24
|
const resolvedApiKey = apiKey || context?.apiKey;
|
|
24
25
|
const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';
|
|
26
|
+
const debug = context?.debug ?? false;
|
|
27
|
+
const log = React.useMemo(() => logger.createLogger(debug), [debug]);
|
|
25
28
|
const [thread, setThread] = React.useState(null);
|
|
26
29
|
const [agent, setAgent] = React.useState(null);
|
|
27
30
|
const [elapsedSeconds, setElapsedSeconds] = React.useState(0);
|
|
@@ -40,7 +43,7 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
40
43
|
return;
|
|
41
44
|
try {
|
|
42
45
|
const data = await client.getThreadById(subThreadId, true);
|
|
43
|
-
|
|
46
|
+
log.log('[HandoffSubagentWidget] Thread loaded:', {
|
|
44
47
|
id: data._id,
|
|
45
48
|
agentId: data.agentId,
|
|
46
49
|
parentAgentId: data.parentAgentId,
|
|
@@ -56,7 +59,7 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
catch (err) {
|
|
59
|
-
|
|
62
|
+
log.error('[HandoffSubagentWidget] Error fetching thread:', err);
|
|
60
63
|
}
|
|
61
64
|
}, [subThreadId, getClient, onCompleted]);
|
|
62
65
|
// Initial fetch + polling
|
|
@@ -75,15 +78,15 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
75
78
|
return;
|
|
76
79
|
const client = getClient();
|
|
77
80
|
if (!client) {
|
|
78
|
-
|
|
81
|
+
log.warn('[HandoffSubagentWidget] No API client available (missing apiKey?)');
|
|
79
82
|
return;
|
|
80
83
|
}
|
|
81
|
-
|
|
84
|
+
log.log('[HandoffSubagentWidget] Fetching agent details for:', agentIdToFetch);
|
|
82
85
|
client.getAgentDetails(agentIdToFetch).then((data) => {
|
|
83
|
-
|
|
86
|
+
log.log('[HandoffSubagentWidget] Agent details loaded:', data?.name);
|
|
84
87
|
setAgent(data);
|
|
85
88
|
}).catch((err) => {
|
|
86
|
-
|
|
89
|
+
log.warn('[HandoffSubagentWidget] Could not fetch agent details:', err);
|
|
87
90
|
});
|
|
88
91
|
}, [agentIdToFetch, agent, getClient]);
|
|
89
92
|
// Stop polling on terminal state
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandoffSubagentWidget.js","sources":["../../../../../src/components/ChatDrawer/HandoffSubagentWidget.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { AgentThreadState } from '../../api/types';\nimport type { AgentThreadDto, AgentDto } from '../../api/types';\nimport { ThreadStateTag } from '../ThreadStateTag';\n\nconst TERMINAL_STATES: AgentThreadState[] = [\n AgentThreadState.COMPLETED,\n AgentThreadState.FAILED,\n AgentThreadState.TERMINATED,\n];\n\nconst POLL_INTERVAL_MS = 5000;\n\nexport interface HandoffSubagentWidgetProps {\n /**\n * The subthread ID to monitor\n */\n subThreadId: string;\n\n /**\n * Called when the subthread reaches a terminal state\n */\n onCompleted?: () => void;\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 * Custom renderer to replace the entire widget content.\n * Receives the thread and agent data.\n */\n renderWidget?: (props: {\n thread: AgentThreadDto | null;\n agent: AgentDto | null;\n elapsedSeconds: number;\n isTerminal: boolean;\n }) => React.ReactNode;\n}\n\nfunction formatElapsed(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return m > 0 ? `${m}m ${s}s` : `${s}s`;\n}\n\nexport function HandoffSubagentWidget({\n subThreadId,\n onCompleted,\n apiKey,\n baseUrl,\n renderWidget,\n}: HandoffSubagentWidgetProps): JSX.Element {\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n\n const [thread, setThread] = useState<AgentThreadDto | null>(null);\n const [agent, setAgent] = useState<AgentDto | null>(null);\n const [elapsedSeconds, setElapsedSeconds] = useState(0);\n\n const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const hasCalledCompleted = useRef(false);\n const startTimeRef = useRef(Date.now());\n\n const getClient = useCallback((): DevicApiClient | null => {\n if (!resolvedApiKey) return null;\n return new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n const fetchThread = useCallback(async () => {\n const client = getClient();\n if (!client) return;\n\n try {\n const data = await client.getThreadById(subThreadId, true);\n console.log('[HandoffSubagentWidget] Thread loaded:', {\n id: data._id,\n agentId: data.agentId,\n parentAgentId: data.parentAgentId,\n name: data.name,\n state: data.state,\n });\n setThread(data);\n\n if (\n data.state &&\n TERMINAL_STATES.includes(data.state) &&\n !hasCalledCompleted.current\n ) {\n hasCalledCompleted.current = true;\n onCompleted?.();\n }\n } catch (err) {\n console.error('[HandoffSubagentWidget] Error fetching thread:', err);\n }\n }, [subThreadId, getClient, onCompleted]);\n\n // Initial fetch + polling\n useEffect(() => {\n fetchThread();\n pollRef.current = setInterval(fetchThread, POLL_INTERVAL_MS);\n return () => {\n if (pollRef.current) clearInterval(pollRef.current);\n };\n }, [fetchThread]);\n\n // Fetch agent details once we have a thread with an agent ID\n const agentIdToFetch = thread?.agentId || thread?.parentAgentId;\n useEffect(() => {\n if (!agentIdToFetch || agent) return;\n const client = getClient();\n if (!client) {\n console.warn('[HandoffSubagentWidget] No API client available (missing apiKey?)');\n return;\n }\n\n console.log('[HandoffSubagentWidget] Fetching agent details for:', agentIdToFetch);\n client.getAgentDetails(agentIdToFetch).then((data) => {\n console.log('[HandoffSubagentWidget] Agent details loaded:', data?.name);\n setAgent(data);\n }).catch((err) => {\n console.warn('[HandoffSubagentWidget] Could not fetch agent details:', err);\n });\n }, [agentIdToFetch, agent, getClient]);\n\n // Stop polling on terminal state\n useEffect(() => {\n if (thread?.state && TERMINAL_STATES.includes(thread.state)) {\n if (pollRef.current) {\n clearInterval(pollRef.current);\n pollRef.current = null;\n }\n }\n }, [thread?.state]);\n\n // Elapsed timer\n useEffect(() => {\n startTimeRef.current = Date.now();\n timerRef.current = setInterval(() => {\n setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1000));\n }, 1000);\n return () => {\n if (timerRef.current) clearInterval(timerRef.current);\n };\n }, []);\n\n // Stop timer on terminal\n useEffect(() => {\n if (thread?.state && TERMINAL_STATES.includes(thread.state)) {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n }\n }, [thread?.state]);\n\n // Computed\n const isTerminal = !!(thread?.state && TERMINAL_STATES.includes(thread.state));\n const isProcessing = thread?.state === AgentThreadState.PROCESSING || thread?.state === AgentThreadState.HANDED_OFF;\n const totalTasks = thread?.tasks?.length || 0;\n const completedTasks = thread?.tasks?.filter((t) => t.completed).length || 0;\n const taskPercentage = totalTasks ? Math.round((completedTasks / totalTasks) * 100) : 0;\n\n const lastMessage = thread?.threadContent?.[thread.threadContent.length - 1];\n const lastSummary = lastMessage?.summary;\n\n // Custom renderer\n if (renderWidget) {\n return <>{renderWidget({ thread, agent, elapsedSeconds, isTerminal })}</>;\n }\n\n return (\n <div className=\"devic-handoff-widget\">\n {/* Header: Agent avatar + name */}\n <div className=\"devic-handoff-header\">\n <div className=\"devic-handoff-agent-avatar\">\n {agent?.imgUrl ? (\n <img src={agent.imgUrl} alt=\"\" className=\"devic-handoff-avatar-img\" />\n ) : (\n <RobotFallbackIcon />\n )}\n </div>\n <span className=\"devic-handoff-agent-name\">\n {agent?.name || thread?.name || 'Subagent'}\n </span>\n </div>\n\n {/* State tag */}\n {thread?.state && (\n <div className=\"devic-handoff-state-row\">\n <ThreadStateTag\n state={thread.state}\n threadId={thread._id || subThreadId}\n agentName={agent?.name || thread?.name || 'Subagent'}\n pausedReason={thread.pausedReason}\n finishReason={thread.finishReason}\n pauseUntil={thread.pauseUntil}\n interactive={true}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n />\n </div>\n )}\n\n {/* Progress bar */}\n {totalTasks > 0 && (\n <div className=\"devic-handoff-progress\">\n <div className=\"devic-handoff-progress-bar\">\n <div\n className=\"devic-handoff-progress-fill\"\n data-status={thread?.state === AgentThreadState.FAILED ? 'error' : isTerminal ? 'success' : 'active'}\n style={{ width: `${taskPercentage}%` }}\n />\n </div>\n <span className=\"devic-handoff-progress-text\">\n {completedTasks}/{totalTasks}\n </span>\n </div>\n )}\n\n {/* Indeterminate progress when no tasks */}\n {totalTasks === 0 && isProcessing && (\n <div className=\"devic-handoff-progress\">\n <div className=\"devic-handoff-progress-bar\">\n <div className=\"devic-handoff-progress-indeterminate\" />\n </div>\n </div>\n )}\n\n {/* Last message summary */}\n {lastSummary && (\n <div className={`devic-handoff-summary ${isProcessing ? 'devic-handoff-summary-active' : ''}`}>\n {lastSummary}\n </div>\n )}\n\n {/* Elapsed time */}\n {isProcessing && (\n <div className=\"devic-handoff-elapsed\">\n <ClockSmallIcon />\n <span>{formatElapsed(elapsedSeconds)}</span>\n </div>\n )}\n </div>\n );\n}\n\n/* ── Icons ── */\n\nfunction RobotFallbackIcon(): JSX.Element {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"#999\">\n <rect x=\"4\" y=\"8\" width=\"16\" height=\"12\" rx=\"2\" />\n <circle cx=\"9\" cy=\"14\" r=\"2\" fill=\"#fff\" />\n <circle cx=\"15\" cy=\"14\" r=\"2\" fill=\"#fff\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"8\" stroke=\"#999\" strokeWidth=\"2\" />\n <circle cx=\"12\" cy=\"2\" r=\"1.5\" />\n </svg>\n );\n}\n\nfunction ClockSmallIcon(): JSX.Element {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12,6 12,12 16,14\" />\n </svg>\n );\n}\n"],"names":["AgentThreadState","useOptionalDevicContext","useState","useRef","useCallback","DevicApiClient","useEffect","_jsx","_Fragment","_jsxs","ThreadStateTag"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HandoffSubagentWidget.js","sources":["../../../../../src/components/ChatDrawer/HandoffSubagentWidget.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { AgentThreadState } from '../../api/types';\nimport type { AgentThreadDto, AgentDto } from '../../api/types';\nimport { ThreadStateTag } from '../ThreadStateTag';\nimport { createLogger } from '../../utils/logger';\n\nconst TERMINAL_STATES: AgentThreadState[] = [\n AgentThreadState.COMPLETED,\n AgentThreadState.FAILED,\n AgentThreadState.TERMINATED,\n];\n\nconst POLL_INTERVAL_MS = 5000;\n\nexport interface HandoffSubagentWidgetProps {\n /**\n * The subthread ID to monitor\n */\n subThreadId: string;\n\n /**\n * Called when the subthread reaches a terminal state\n */\n onCompleted?: () => void;\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 * Custom renderer to replace the entire widget content.\n * Receives the thread and agent data.\n */\n renderWidget?: (props: {\n thread: AgentThreadDto | null;\n agent: AgentDto | null;\n elapsedSeconds: number;\n isTerminal: boolean;\n }) => React.ReactNode;\n}\n\nfunction formatElapsed(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return m > 0 ? `${m}m ${s}s` : `${s}s`;\n}\n\nexport function HandoffSubagentWidget({\n subThreadId,\n onCompleted,\n apiKey,\n baseUrl,\n renderWidget,\n}: HandoffSubagentWidgetProps): JSX.Element {\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const debug = context?.debug ?? false;\n const log = useMemo(() => createLogger(debug), [debug]);\n\n const [thread, setThread] = useState<AgentThreadDto | null>(null);\n const [agent, setAgent] = useState<AgentDto | null>(null);\n const [elapsedSeconds, setElapsedSeconds] = useState(0);\n\n const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const hasCalledCompleted = useRef(false);\n const startTimeRef = useRef(Date.now());\n\n const getClient = useCallback((): DevicApiClient | null => {\n if (!resolvedApiKey) return null;\n return new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n const fetchThread = useCallback(async () => {\n const client = getClient();\n if (!client) return;\n\n try {\n const data = await client.getThreadById(subThreadId, true);\n log.log('[HandoffSubagentWidget] Thread loaded:', {\n id: data._id,\n agentId: data.agentId,\n parentAgentId: data.parentAgentId,\n name: data.name,\n state: data.state,\n });\n setThread(data);\n\n if (\n data.state &&\n TERMINAL_STATES.includes(data.state) &&\n !hasCalledCompleted.current\n ) {\n hasCalledCompleted.current = true;\n onCompleted?.();\n }\n } catch (err) {\n log.error('[HandoffSubagentWidget] Error fetching thread:', err);\n }\n }, [subThreadId, getClient, onCompleted]);\n\n // Initial fetch + polling\n useEffect(() => {\n fetchThread();\n pollRef.current = setInterval(fetchThread, POLL_INTERVAL_MS);\n return () => {\n if (pollRef.current) clearInterval(pollRef.current);\n };\n }, [fetchThread]);\n\n // Fetch agent details once we have a thread with an agent ID\n const agentIdToFetch = thread?.agentId || thread?.parentAgentId;\n useEffect(() => {\n if (!agentIdToFetch || agent) return;\n const client = getClient();\n if (!client) {\n log.warn('[HandoffSubagentWidget] No API client available (missing apiKey?)');\n return;\n }\n\n log.log('[HandoffSubagentWidget] Fetching agent details for:', agentIdToFetch);\n client.getAgentDetails(agentIdToFetch).then((data) => {\n log.log('[HandoffSubagentWidget] Agent details loaded:', data?.name);\n setAgent(data);\n }).catch((err) => {\n log.warn('[HandoffSubagentWidget] Could not fetch agent details:', err);\n });\n }, [agentIdToFetch, agent, getClient]);\n\n // Stop polling on terminal state\n useEffect(() => {\n if (thread?.state && TERMINAL_STATES.includes(thread.state)) {\n if (pollRef.current) {\n clearInterval(pollRef.current);\n pollRef.current = null;\n }\n }\n }, [thread?.state]);\n\n // Elapsed timer\n useEffect(() => {\n startTimeRef.current = Date.now();\n timerRef.current = setInterval(() => {\n setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1000));\n }, 1000);\n return () => {\n if (timerRef.current) clearInterval(timerRef.current);\n };\n }, []);\n\n // Stop timer on terminal\n useEffect(() => {\n if (thread?.state && TERMINAL_STATES.includes(thread.state)) {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n }\n }, [thread?.state]);\n\n // Computed\n const isTerminal = !!(thread?.state && TERMINAL_STATES.includes(thread.state));\n const isProcessing = thread?.state === AgentThreadState.PROCESSING || thread?.state === AgentThreadState.HANDED_OFF;\n const totalTasks = thread?.tasks?.length || 0;\n const completedTasks = thread?.tasks?.filter((t) => t.completed).length || 0;\n const taskPercentage = totalTasks ? Math.round((completedTasks / totalTasks) * 100) : 0;\n\n const lastMessage = thread?.threadContent?.[thread.threadContent.length - 1];\n const lastSummary = lastMessage?.summary;\n\n // Custom renderer\n if (renderWidget) {\n return <>{renderWidget({ thread, agent, elapsedSeconds, isTerminal })}</>;\n }\n\n return (\n <div className=\"devic-handoff-widget\">\n {/* Header: Agent avatar + name */}\n <div className=\"devic-handoff-header\">\n <div className=\"devic-handoff-agent-avatar\">\n {agent?.imgUrl ? (\n <img src={agent.imgUrl} alt=\"\" className=\"devic-handoff-avatar-img\" />\n ) : (\n <RobotFallbackIcon />\n )}\n </div>\n <span className=\"devic-handoff-agent-name\">\n {agent?.name || thread?.name || 'Subagent'}\n </span>\n </div>\n\n {/* State tag */}\n {thread?.state && (\n <div className=\"devic-handoff-state-row\">\n <ThreadStateTag\n state={thread.state}\n threadId={thread._id || subThreadId}\n agentName={agent?.name || thread?.name || 'Subagent'}\n pausedReason={thread.pausedReason}\n finishReason={thread.finishReason}\n pauseUntil={thread.pauseUntil}\n interactive={true}\n apiKey={resolvedApiKey}\n baseUrl={resolvedBaseUrl}\n />\n </div>\n )}\n\n {/* Progress bar */}\n {totalTasks > 0 && (\n <div className=\"devic-handoff-progress\">\n <div className=\"devic-handoff-progress-bar\">\n <div\n className=\"devic-handoff-progress-fill\"\n data-status={thread?.state === AgentThreadState.FAILED ? 'error' : isTerminal ? 'success' : 'active'}\n style={{ width: `${taskPercentage}%` }}\n />\n </div>\n <span className=\"devic-handoff-progress-text\">\n {completedTasks}/{totalTasks}\n </span>\n </div>\n )}\n\n {/* Indeterminate progress when no tasks */}\n {totalTasks === 0 && isProcessing && (\n <div className=\"devic-handoff-progress\">\n <div className=\"devic-handoff-progress-bar\">\n <div className=\"devic-handoff-progress-indeterminate\" />\n </div>\n </div>\n )}\n\n {/* Last message summary */}\n {lastSummary && (\n <div className={`devic-handoff-summary ${isProcessing ? 'devic-handoff-summary-active' : ''}`}>\n {lastSummary}\n </div>\n )}\n\n {/* Elapsed time */}\n {isProcessing && (\n <div className=\"devic-handoff-elapsed\">\n <ClockSmallIcon />\n <span>{formatElapsed(elapsedSeconds)}</span>\n </div>\n )}\n </div>\n );\n}\n\n/* ── Icons ── */\n\nfunction RobotFallbackIcon(): JSX.Element {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"#999\">\n <rect x=\"4\" y=\"8\" width=\"16\" height=\"12\" rx=\"2\" />\n <circle cx=\"9\" cy=\"14\" r=\"2\" fill=\"#fff\" />\n <circle cx=\"15\" cy=\"14\" r=\"2\" fill=\"#fff\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"8\" stroke=\"#999\" strokeWidth=\"2\" />\n <circle cx=\"12\" cy=\"2\" r=\"1.5\" />\n </svg>\n );\n}\n\nfunction ClockSmallIcon(): JSX.Element {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12,6 12,12 16,14\" />\n </svg>\n );\n}\n"],"names":["AgentThreadState","useOptionalDevicContext","useMemo","createLogger","useState","useRef","useCallback","DevicApiClient","useEffect","_jsx","_Fragment","_jsxs","ThreadStateTag"],"mappings":"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"}
|
|
@@ -6,8 +6,8 @@ var DevicContext = require('../provider/DevicContext.js');
|
|
|
6
6
|
var client = require('../api/client.js');
|
|
7
7
|
var usePolling = require('./usePolling.js');
|
|
8
8
|
var useModelInterface = require('./useModelInterface.js');
|
|
9
|
+
var logger = require('../utils/logger.js');
|
|
9
10
|
|
|
10
|
-
console.log('[devic-ui] Version: 0.6.1');
|
|
11
11
|
/**
|
|
12
12
|
* Main hook for managing chat with a Devic assistant
|
|
13
13
|
*
|
|
@@ -31,7 +31,7 @@ console.log('[devic-ui] Version: 0.6.1');
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
function useDevicChat(options) {
|
|
34
|
-
const { assistantId, chatUid: initialChatUid, apiKey: propsApiKey, baseUrl: propsBaseUrl, tenantId, tenantMetadata, enabledTools, modelInterfaceTools = [], pollingInterval = 1000, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, } = options;
|
|
34
|
+
const { assistantId, chatUid: initialChatUid, apiKey: propsApiKey, baseUrl: propsBaseUrl, tenantId, tenantMetadata, enabledTools, modelInterfaceTools = [], pollingInterval = 1000, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, debug: propsDebug, } = options;
|
|
35
35
|
// Get context (may be null if not wrapped in provider)
|
|
36
36
|
const context = DevicContext.useOptionalDevicContext();
|
|
37
37
|
// Resolve configuration
|
|
@@ -39,6 +39,10 @@ function useDevicChat(options) {
|
|
|
39
39
|
const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';
|
|
40
40
|
const resolvedTenantId = tenantId || context?.tenantId;
|
|
41
41
|
const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };
|
|
42
|
+
const debug = propsDebug ?? context?.debug ?? false;
|
|
43
|
+
const log = React.useMemo(() => logger.createLogger(debug), [debug]);
|
|
44
|
+
const logRef = React.useRef(log);
|
|
45
|
+
logRef.current = log;
|
|
42
46
|
// State
|
|
43
47
|
const [messages, setMessages] = React.useState([]);
|
|
44
48
|
const [chatUid, setChatUid] = React.useState(initialChatUid || null);
|
|
@@ -74,6 +78,50 @@ function useDevicChat(options) {
|
|
|
74
78
|
clientRef.current.setConfig({ apiKey, baseUrl });
|
|
75
79
|
}
|
|
76
80
|
}, [apiKey, baseUrl]);
|
|
81
|
+
// Resume chat state based on realtime status.
|
|
82
|
+
// Called after loading chat history to detect in-progress conversations.
|
|
83
|
+
const resumeFromRealtimeStatus = React.useCallback(async (targetChatUid) => {
|
|
84
|
+
if (!clientRef.current)
|
|
85
|
+
return;
|
|
86
|
+
try {
|
|
87
|
+
const realtime = await clientRef.current.getRealtimeHistory(assistantId, targetChatUid);
|
|
88
|
+
logRef.current.log('[useDevicChat] resumeFromRealtimeStatus:', realtime.status);
|
|
89
|
+
// Update messages with realtime data (may be fresher than static history)
|
|
90
|
+
if (realtime.chatHistory?.length) {
|
|
91
|
+
setMessages(realtime.chatHistory);
|
|
92
|
+
}
|
|
93
|
+
setStatus(realtime.status);
|
|
94
|
+
if (realtime.status === 'processing') {
|
|
95
|
+
// Chat is still processing — resume polling
|
|
96
|
+
setIsLoading(true);
|
|
97
|
+
setShouldPoll(true);
|
|
98
|
+
}
|
|
99
|
+
else if (realtime.status === 'waiting_for_tool_response') {
|
|
100
|
+
// Chat is waiting for tool response — resume polling to trigger tool handling
|
|
101
|
+
setIsLoading(true);
|
|
102
|
+
setShouldPoll(true);
|
|
103
|
+
}
|
|
104
|
+
else if (realtime.status === 'handed_off') {
|
|
105
|
+
// Chat has an active handoff
|
|
106
|
+
setIsLoading(true);
|
|
107
|
+
setHandedOff(true);
|
|
108
|
+
const subThreadId = realtime.handedOffSubThreadId || null;
|
|
109
|
+
logRef.current.log('[useDevicChat] Resuming handoff state:', { subThreadId });
|
|
110
|
+
if (subThreadId) {
|
|
111
|
+
setHandedOffSubThreadId(subThreadId);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// completed or error — just stop
|
|
116
|
+
setIsLoading(false);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
// If realtime fetch fails (e.g. chat has no realtime entry), just stay idle
|
|
121
|
+
logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);
|
|
122
|
+
setIsLoading(false);
|
|
123
|
+
}
|
|
124
|
+
}, [assistantId]);
|
|
77
125
|
// Load initial chat history if chatUid prop is provided
|
|
78
126
|
// This runs once on mount (or when initialChatUid changes) to fetch existing conversation
|
|
79
127
|
const initialChatLoadedRef = React.useRef(false);
|
|
@@ -87,41 +135,40 @@ function useDevicChat(options) {
|
|
|
87
135
|
const history = await clientRef.current.getChatHistory(assistantId, initialChatUid, { tenantId: resolvedTenantId });
|
|
88
136
|
setMessages(history.chatContent);
|
|
89
137
|
setChatUid(initialChatUid);
|
|
90
|
-
|
|
138
|
+
// Check realtime status to resume in-progress conversations
|
|
139
|
+
await resumeFromRealtimeStatus(initialChatUid);
|
|
91
140
|
}
|
|
92
141
|
catch (err) {
|
|
93
142
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
94
143
|
setError(error);
|
|
95
144
|
onErrorRef.current?.(error);
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
145
|
setIsLoading(false);
|
|
99
146
|
}
|
|
100
147
|
};
|
|
101
148
|
loadInitialChat();
|
|
102
149
|
}
|
|
103
|
-
}, [initialChatUid, assistantId, resolvedTenantId]);
|
|
150
|
+
}, [initialChatUid, assistantId, resolvedTenantId, resumeFromRealtimeStatus]);
|
|
104
151
|
// Model interface hook
|
|
105
152
|
const { toolSchemas, handleToolCalls, extractPendingToolCalls, } = useModelInterface.useModelInterface({
|
|
106
153
|
tools: modelInterfaceTools,
|
|
107
154
|
onToolExecute: onToolCall,
|
|
108
155
|
});
|
|
109
156
|
// Polling hook - uses callbacks for side effects, return value not needed
|
|
110
|
-
|
|
157
|
+
logRef.current.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);
|
|
111
158
|
usePolling.usePolling(shouldPoll ? chatUid : null, async () => {
|
|
112
|
-
|
|
159
|
+
logRef.current.log('[useDevicChat] fetchFn called, chatUid:', chatUid);
|
|
113
160
|
if (!clientRef.current || !chatUid) {
|
|
114
161
|
throw new Error('Cannot poll without client or chatUid');
|
|
115
162
|
}
|
|
116
163
|
const result = await clientRef.current.getRealtimeHistory(assistantId, chatUid);
|
|
117
|
-
|
|
164
|
+
logRef.current.log('[useDevicChat] getRealtimeHistory result:', result);
|
|
118
165
|
return result;
|
|
119
166
|
}, {
|
|
120
167
|
interval: pollingInterval,
|
|
121
168
|
enabled: shouldPoll,
|
|
122
169
|
stopStatuses: ['completed', 'error', 'waiting_for_tool_response', 'handed_off'],
|
|
123
170
|
onUpdate: async (data) => {
|
|
124
|
-
|
|
171
|
+
logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);
|
|
125
172
|
// Merge realtime data with optimistic messages
|
|
126
173
|
setMessages((prev) => {
|
|
127
174
|
const realtimeUIDs = new Set(data.chatHistory.map((m) => m.uid));
|
|
@@ -150,7 +197,7 @@ function useDevicChat(options) {
|
|
|
150
197
|
}
|
|
151
198
|
},
|
|
152
199
|
onStop: (data) => {
|
|
153
|
-
|
|
200
|
+
logRef.current.log('[useDevicChat] onStop called, status:', data?.status);
|
|
154
201
|
setShouldPoll(false);
|
|
155
202
|
if (data?.status === 'error') {
|
|
156
203
|
setIsLoading(false);
|
|
@@ -166,7 +213,7 @@ function useDevicChat(options) {
|
|
|
166
213
|
// Set handoff state directly from the realtime status.
|
|
167
214
|
setHandedOff(true);
|
|
168
215
|
const subThreadId = data.handedOffSubThreadId || null;
|
|
169
|
-
|
|
216
|
+
logRef.current.log('[useDevicChat] Handoff state set:', { handedOff: true, subThreadId });
|
|
170
217
|
if (subThreadId) {
|
|
171
218
|
setHandedOffSubThreadId(subThreadId);
|
|
172
219
|
}
|
|
@@ -174,12 +221,13 @@ function useDevicChat(options) {
|
|
|
174
221
|
// Note: waiting_for_tool_response is handled in onUpdate to avoid double execution
|
|
175
222
|
},
|
|
176
223
|
onError: (err) => {
|
|
177
|
-
|
|
224
|
+
logRef.current.error('[useDevicChat] onError called:', err);
|
|
178
225
|
setError(err);
|
|
179
226
|
setIsLoading(false);
|
|
180
227
|
setShouldPoll(false);
|
|
181
228
|
onErrorRef.current?.(err);
|
|
182
229
|
},
|
|
230
|
+
debug,
|
|
183
231
|
});
|
|
184
232
|
// Handle pending tool calls from model interface
|
|
185
233
|
const handlePendingToolCalls = React.useCallback(async (data) => {
|
|
@@ -249,17 +297,17 @@ function useDevicChat(options) {
|
|
|
249
297
|
...(toolSchemas.length > 0 && { tools: toolSchemas }),
|
|
250
298
|
};
|
|
251
299
|
// Send message in async mode
|
|
252
|
-
|
|
300
|
+
logRef.current.log('[useDevicChat] Sending message async...');
|
|
253
301
|
const response = await clientRef.current.sendMessageAsync(assistantId, dto);
|
|
254
|
-
|
|
302
|
+
logRef.current.log('[useDevicChat] sendMessageAsync response:', response);
|
|
255
303
|
// Update chat UID if this is a new chat
|
|
256
304
|
if (response.chatUid && response.chatUid !== chatUid) {
|
|
257
|
-
|
|
305
|
+
logRef.current.log('[useDevicChat] Setting chatUid:', response.chatUid);
|
|
258
306
|
setChatUid(response.chatUid);
|
|
259
307
|
onChatCreatedRef.current?.(response.chatUid);
|
|
260
308
|
}
|
|
261
309
|
// Start polling for results
|
|
262
|
-
|
|
310
|
+
logRef.current.log('[useDevicChat] Setting shouldPoll to true');
|
|
263
311
|
setShouldPoll(true);
|
|
264
312
|
}
|
|
265
313
|
catch (err) {
|
|
@@ -282,11 +330,18 @@ function useDevicChat(options) {
|
|
|
282
330
|
]);
|
|
283
331
|
// Clear chat
|
|
284
332
|
const clearChat = React.useCallback(() => {
|
|
333
|
+
setShouldPoll(false);
|
|
334
|
+
setHandedOff(false);
|
|
335
|
+
setHandedOffSubThreadId(null);
|
|
336
|
+
if (handoffPollRef.current) {
|
|
337
|
+
clearInterval(handoffPollRef.current);
|
|
338
|
+
handoffPollRef.current = null;
|
|
339
|
+
}
|
|
285
340
|
setMessages([]);
|
|
286
341
|
setChatUid(null);
|
|
342
|
+
setIsLoading(false);
|
|
287
343
|
setStatus('idle');
|
|
288
344
|
setError(null);
|
|
289
|
-
setShouldPoll(false);
|
|
290
345
|
}, []);
|
|
291
346
|
// Load existing chat
|
|
292
347
|
const loadChat = React.useCallback(async (loadChatUid) => {
|
|
@@ -296,23 +351,30 @@ function useDevicChat(options) {
|
|
|
296
351
|
onErrorRef.current?.(err);
|
|
297
352
|
return;
|
|
298
353
|
}
|
|
354
|
+
// Reset any active polling/handoff state from previous conversation
|
|
355
|
+
setShouldPoll(false);
|
|
356
|
+
setHandedOff(false);
|
|
357
|
+
setHandedOffSubThreadId(null);
|
|
358
|
+
if (handoffPollRef.current) {
|
|
359
|
+
clearInterval(handoffPollRef.current);
|
|
360
|
+
handoffPollRef.current = null;
|
|
361
|
+
}
|
|
299
362
|
setIsLoading(true);
|
|
300
363
|
setError(null);
|
|
301
364
|
try {
|
|
302
365
|
const history = await clientRef.current.getChatHistory(assistantId, loadChatUid, { tenantId: resolvedTenantId });
|
|
303
366
|
setMessages(history.chatContent);
|
|
304
367
|
setChatUid(loadChatUid);
|
|
305
|
-
|
|
368
|
+
// Check realtime status to resume in-progress conversations
|
|
369
|
+
await resumeFromRealtimeStatus(loadChatUid);
|
|
306
370
|
}
|
|
307
371
|
catch (err) {
|
|
308
372
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
309
373
|
setError(error);
|
|
310
374
|
onErrorRef.current?.(error);
|
|
311
|
-
}
|
|
312
|
-
finally {
|
|
313
375
|
setIsLoading(false);
|
|
314
376
|
}
|
|
315
|
-
}, [assistantId, resolvedTenantId]);
|
|
377
|
+
}, [assistantId, resolvedTenantId, resumeFromRealtimeStatus]);
|
|
316
378
|
// Handoff polling: while handedOff is true, poll the realtime endpoint every 5s
|
|
317
379
|
// to detect when the parent thread is no longer in handed_off state.
|
|
318
380
|
React.useEffect(() => {
|
|
@@ -321,7 +383,7 @@ function useDevicChat(options) {
|
|
|
321
383
|
const pollHandoff = async () => {
|
|
322
384
|
try {
|
|
323
385
|
const realtime = await clientRef.current.getRealtimeHistory(assistantId, chatUid);
|
|
324
|
-
|
|
386
|
+
logRef.current.log('[useDevicChat] Handoff poll - realtime status:', realtime.status);
|
|
325
387
|
if (realtime.status !== 'handed_off') {
|
|
326
388
|
// Handoff completed — clear handoff state and resume main polling
|
|
327
389
|
if (handoffPollRef.current) {
|
|
@@ -346,7 +408,7 @@ function useDevicChat(options) {
|
|
|
346
408
|
}, [handedOff, chatUid, assistantId]);
|
|
347
409
|
// Called by HandoffSubagentWidget when the subthread reaches a terminal state
|
|
348
410
|
const onHandoffCompleted = React.useCallback(() => {
|
|
349
|
-
|
|
411
|
+
logRef.current.log('[useDevicChat] onHandoffCompleted called');
|
|
350
412
|
// Clear the handoff polling
|
|
351
413
|
if (handoffPollRef.current) {
|
|
352
414
|
clearInterval(handoffPollRef.current);
|
|
@@ -361,14 +423,14 @@ function useDevicChat(options) {
|
|
|
361
423
|
// then stops polling and resets loading state.
|
|
362
424
|
const stopChat = React.useCallback(async () => {
|
|
363
425
|
const uid = chatUidRef.current;
|
|
364
|
-
|
|
426
|
+
logRef.current.log('[useDevicChat] stopChat called, chatUid:', uid);
|
|
365
427
|
if (clientRef.current && uid) {
|
|
366
428
|
try {
|
|
367
429
|
await clientRef.current.stopChat(assistantId, uid);
|
|
368
|
-
|
|
430
|
+
logRef.current.log('[useDevicChat] stopChat API call succeeded');
|
|
369
431
|
}
|
|
370
432
|
catch (err) {
|
|
371
|
-
|
|
433
|
+
logRef.current.warn('[useDevicChat] stopChat API call failed:', err);
|
|
372
434
|
}
|
|
373
435
|
}
|
|
374
436
|
setShouldPoll(false);
|