@devicai/ui 0.10.1 → 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 +97 -29
- 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 +98 -30
- 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
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
|
+
import { useMemo, useState, useRef, useCallback, useEffect } from 'react';
|
|
3
3
|
import { useOptionalDevicContext } from '../../provider/DevicContext.js';
|
|
4
4
|
import { DevicApiClient } from '../../api/client.js';
|
|
5
5
|
import { AgentThreadState } from '../../api/types.js';
|
|
6
6
|
import { ThreadStateTag } from '../ThreadStateTag/ThreadStateTag.js';
|
|
7
|
+
import { createLogger } from '../../utils/logger.js';
|
|
7
8
|
|
|
8
9
|
const TERMINAL_STATES = [
|
|
9
10
|
AgentThreadState.COMPLETED,
|
|
@@ -20,6 +21,8 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
20
21
|
const context = useOptionalDevicContext();
|
|
21
22
|
const resolvedApiKey = apiKey || context?.apiKey;
|
|
22
23
|
const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';
|
|
24
|
+
const debug = context?.debug ?? false;
|
|
25
|
+
const log = useMemo(() => createLogger(debug), [debug]);
|
|
23
26
|
const [thread, setThread] = useState(null);
|
|
24
27
|
const [agent, setAgent] = useState(null);
|
|
25
28
|
const [elapsedSeconds, setElapsedSeconds] = useState(0);
|
|
@@ -38,7 +41,7 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
38
41
|
return;
|
|
39
42
|
try {
|
|
40
43
|
const data = await client.getThreadById(subThreadId, true);
|
|
41
|
-
|
|
44
|
+
log.log('[HandoffSubagentWidget] Thread loaded:', {
|
|
42
45
|
id: data._id,
|
|
43
46
|
agentId: data.agentId,
|
|
44
47
|
parentAgentId: data.parentAgentId,
|
|
@@ -54,7 +57,7 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
catch (err) {
|
|
57
|
-
|
|
60
|
+
log.error('[HandoffSubagentWidget] Error fetching thread:', err);
|
|
58
61
|
}
|
|
59
62
|
}, [subThreadId, getClient, onCompleted]);
|
|
60
63
|
// Initial fetch + polling
|
|
@@ -73,15 +76,15 @@ function HandoffSubagentWidget({ subThreadId, onCompleted, apiKey, baseUrl, rend
|
|
|
73
76
|
return;
|
|
74
77
|
const client = getClient();
|
|
75
78
|
if (!client) {
|
|
76
|
-
|
|
79
|
+
log.warn('[HandoffSubagentWidget] No API client available (missing apiKey?)');
|
|
77
80
|
return;
|
|
78
81
|
}
|
|
79
|
-
|
|
82
|
+
log.log('[HandoffSubagentWidget] Fetching agent details for:', agentIdToFetch);
|
|
80
83
|
client.getAgentDetails(agentIdToFetch).then((data) => {
|
|
81
|
-
|
|
84
|
+
log.log('[HandoffSubagentWidget] Agent details loaded:', data?.name);
|
|
82
85
|
setAgent(data);
|
|
83
86
|
}).catch((err) => {
|
|
84
|
-
|
|
87
|
+
log.warn('[HandoffSubagentWidget] Could not fetch agent details:', err);
|
|
85
88
|
});
|
|
86
89
|
}, [agentIdToFetch, agent, getClient]);
|
|
87
90
|
// 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":["_jsx","_Fragment","_jsxs"],"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":["_jsx","_Fragment","_jsxs"],"mappings":"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"}
|
|
@@ -57,6 +57,12 @@ export interface UseDevicChatOptions {
|
|
|
57
57
|
* Callback when a new chat is created
|
|
58
58
|
*/
|
|
59
59
|
onChatCreated?: (chatUid: string) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Enable debug logging to the browser console.
|
|
62
|
+
* Overrides the provider-level debug setting when provided.
|
|
63
|
+
* @default false
|
|
64
|
+
*/
|
|
65
|
+
debug?: boolean;
|
|
60
66
|
}
|
|
61
67
|
export interface UseDevicChatResult {
|
|
62
68
|
/**
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo, useRef, useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import { useOptionalDevicContext } from '../provider/DevicContext.js';
|
|
4
4
|
import { DevicApiClient } from '../api/client.js';
|
|
5
5
|
import { usePolling } from './usePolling.js';
|
|
6
6
|
import { useModelInterface } from './useModelInterface.js';
|
|
7
|
+
import { createLogger } from '../utils/logger.js';
|
|
7
8
|
|
|
8
|
-
console.log('[devic-ui] Version: 0.6.1');
|
|
9
9
|
/**
|
|
10
10
|
* Main hook for managing chat with a Devic assistant
|
|
11
11
|
*
|
|
@@ -29,7 +29,7 @@ console.log('[devic-ui] Version: 0.6.1');
|
|
|
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, } = options;
|
|
32
|
+
const { assistantId, chatUid: initialChatUid, apiKey: propsApiKey, baseUrl: propsBaseUrl, tenantId, tenantMetadata, enabledTools, modelInterfaceTools = [], pollingInterval = 1000, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, 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,10 @@ 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 debug = propsDebug ?? context?.debug ?? false;
|
|
41
|
+
const log = useMemo(() => createLogger(debug), [debug]);
|
|
42
|
+
const logRef = useRef(log);
|
|
43
|
+
logRef.current = log;
|
|
40
44
|
// State
|
|
41
45
|
const [messages, setMessages] = useState([]);
|
|
42
46
|
const [chatUid, setChatUid] = useState(initialChatUid || null);
|
|
@@ -49,6 +53,9 @@ function useDevicChat(options) {
|
|
|
49
53
|
const handoffPollRef = useRef(null);
|
|
50
54
|
// Polling state
|
|
51
55
|
const [shouldPoll, setShouldPoll] = useState(false);
|
|
56
|
+
// Keep a ref to chatUid so async callbacks always read the latest value
|
|
57
|
+
const chatUidRef = useRef(chatUid);
|
|
58
|
+
chatUidRef.current = chatUid;
|
|
52
59
|
// Refs for callbacks
|
|
53
60
|
const onMessageReceivedRef = useRef(onMessageReceived);
|
|
54
61
|
const onErrorRef = useRef(onError);
|
|
@@ -69,6 +76,50 @@ function useDevicChat(options) {
|
|
|
69
76
|
clientRef.current.setConfig({ apiKey, baseUrl });
|
|
70
77
|
}
|
|
71
78
|
}, [apiKey, baseUrl]);
|
|
79
|
+
// Resume chat state based on realtime status.
|
|
80
|
+
// Called after loading chat history to detect in-progress conversations.
|
|
81
|
+
const resumeFromRealtimeStatus = useCallback(async (targetChatUid) => {
|
|
82
|
+
if (!clientRef.current)
|
|
83
|
+
return;
|
|
84
|
+
try {
|
|
85
|
+
const realtime = await clientRef.current.getRealtimeHistory(assistantId, targetChatUid);
|
|
86
|
+
logRef.current.log('[useDevicChat] resumeFromRealtimeStatus:', realtime.status);
|
|
87
|
+
// Update messages with realtime data (may be fresher than static history)
|
|
88
|
+
if (realtime.chatHistory?.length) {
|
|
89
|
+
setMessages(realtime.chatHistory);
|
|
90
|
+
}
|
|
91
|
+
setStatus(realtime.status);
|
|
92
|
+
if (realtime.status === 'processing') {
|
|
93
|
+
// Chat is still processing — resume polling
|
|
94
|
+
setIsLoading(true);
|
|
95
|
+
setShouldPoll(true);
|
|
96
|
+
}
|
|
97
|
+
else if (realtime.status === 'waiting_for_tool_response') {
|
|
98
|
+
// Chat is waiting for tool response — resume polling to trigger tool handling
|
|
99
|
+
setIsLoading(true);
|
|
100
|
+
setShouldPoll(true);
|
|
101
|
+
}
|
|
102
|
+
else if (realtime.status === 'handed_off') {
|
|
103
|
+
// Chat has an active handoff
|
|
104
|
+
setIsLoading(true);
|
|
105
|
+
setHandedOff(true);
|
|
106
|
+
const subThreadId = realtime.handedOffSubThreadId || null;
|
|
107
|
+
logRef.current.log('[useDevicChat] Resuming handoff state:', { subThreadId });
|
|
108
|
+
if (subThreadId) {
|
|
109
|
+
setHandedOffSubThreadId(subThreadId);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// completed or error — just stop
|
|
114
|
+
setIsLoading(false);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
// If realtime fetch fails (e.g. chat has no realtime entry), just stay idle
|
|
119
|
+
logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);
|
|
120
|
+
setIsLoading(false);
|
|
121
|
+
}
|
|
122
|
+
}, [assistantId]);
|
|
72
123
|
// Load initial chat history if chatUid prop is provided
|
|
73
124
|
// This runs once on mount (or when initialChatUid changes) to fetch existing conversation
|
|
74
125
|
const initialChatLoadedRef = useRef(false);
|
|
@@ -82,41 +133,40 @@ function useDevicChat(options) {
|
|
|
82
133
|
const history = await clientRef.current.getChatHistory(assistantId, initialChatUid, { tenantId: resolvedTenantId });
|
|
83
134
|
setMessages(history.chatContent);
|
|
84
135
|
setChatUid(initialChatUid);
|
|
85
|
-
|
|
136
|
+
// Check realtime status to resume in-progress conversations
|
|
137
|
+
await resumeFromRealtimeStatus(initialChatUid);
|
|
86
138
|
}
|
|
87
139
|
catch (err) {
|
|
88
140
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
89
141
|
setError(error);
|
|
90
142
|
onErrorRef.current?.(error);
|
|
91
|
-
}
|
|
92
|
-
finally {
|
|
93
143
|
setIsLoading(false);
|
|
94
144
|
}
|
|
95
145
|
};
|
|
96
146
|
loadInitialChat();
|
|
97
147
|
}
|
|
98
|
-
}, [initialChatUid, assistantId, resolvedTenantId]);
|
|
148
|
+
}, [initialChatUid, assistantId, resolvedTenantId, resumeFromRealtimeStatus]);
|
|
99
149
|
// Model interface hook
|
|
100
150
|
const { toolSchemas, handleToolCalls, extractPendingToolCalls, } = useModelInterface({
|
|
101
151
|
tools: modelInterfaceTools,
|
|
102
152
|
onToolExecute: onToolCall,
|
|
103
153
|
});
|
|
104
154
|
// Polling hook - uses callbacks for side effects, return value not needed
|
|
105
|
-
|
|
155
|
+
logRef.current.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);
|
|
106
156
|
usePolling(shouldPoll ? chatUid : null, async () => {
|
|
107
|
-
|
|
157
|
+
logRef.current.log('[useDevicChat] fetchFn called, chatUid:', chatUid);
|
|
108
158
|
if (!clientRef.current || !chatUid) {
|
|
109
159
|
throw new Error('Cannot poll without client or chatUid');
|
|
110
160
|
}
|
|
111
161
|
const result = await clientRef.current.getRealtimeHistory(assistantId, chatUid);
|
|
112
|
-
|
|
162
|
+
logRef.current.log('[useDevicChat] getRealtimeHistory result:', result);
|
|
113
163
|
return result;
|
|
114
164
|
}, {
|
|
115
165
|
interval: pollingInterval,
|
|
116
166
|
enabled: shouldPoll,
|
|
117
167
|
stopStatuses: ['completed', 'error', 'waiting_for_tool_response', 'handed_off'],
|
|
118
168
|
onUpdate: async (data) => {
|
|
119
|
-
|
|
169
|
+
logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);
|
|
120
170
|
// Merge realtime data with optimistic messages
|
|
121
171
|
setMessages((prev) => {
|
|
122
172
|
const realtimeUIDs = new Set(data.chatHistory.map((m) => m.uid));
|
|
@@ -145,7 +195,7 @@ function useDevicChat(options) {
|
|
|
145
195
|
}
|
|
146
196
|
},
|
|
147
197
|
onStop: (data) => {
|
|
148
|
-
|
|
198
|
+
logRef.current.log('[useDevicChat] onStop called, status:', data?.status);
|
|
149
199
|
setShouldPoll(false);
|
|
150
200
|
if (data?.status === 'error') {
|
|
151
201
|
setIsLoading(false);
|
|
@@ -161,7 +211,7 @@ function useDevicChat(options) {
|
|
|
161
211
|
// Set handoff state directly from the realtime status.
|
|
162
212
|
setHandedOff(true);
|
|
163
213
|
const subThreadId = data.handedOffSubThreadId || null;
|
|
164
|
-
|
|
214
|
+
logRef.current.log('[useDevicChat] Handoff state set:', { handedOff: true, subThreadId });
|
|
165
215
|
if (subThreadId) {
|
|
166
216
|
setHandedOffSubThreadId(subThreadId);
|
|
167
217
|
}
|
|
@@ -169,12 +219,13 @@ function useDevicChat(options) {
|
|
|
169
219
|
// Note: waiting_for_tool_response is handled in onUpdate to avoid double execution
|
|
170
220
|
},
|
|
171
221
|
onError: (err) => {
|
|
172
|
-
|
|
222
|
+
logRef.current.error('[useDevicChat] onError called:', err);
|
|
173
223
|
setError(err);
|
|
174
224
|
setIsLoading(false);
|
|
175
225
|
setShouldPoll(false);
|
|
176
226
|
onErrorRef.current?.(err);
|
|
177
227
|
},
|
|
228
|
+
debug,
|
|
178
229
|
});
|
|
179
230
|
// Handle pending tool calls from model interface
|
|
180
231
|
const handlePendingToolCalls = useCallback(async (data) => {
|
|
@@ -244,17 +295,17 @@ function useDevicChat(options) {
|
|
|
244
295
|
...(toolSchemas.length > 0 && { tools: toolSchemas }),
|
|
245
296
|
};
|
|
246
297
|
// Send message in async mode
|
|
247
|
-
|
|
298
|
+
logRef.current.log('[useDevicChat] Sending message async...');
|
|
248
299
|
const response = await clientRef.current.sendMessageAsync(assistantId, dto);
|
|
249
|
-
|
|
300
|
+
logRef.current.log('[useDevicChat] sendMessageAsync response:', response);
|
|
250
301
|
// Update chat UID if this is a new chat
|
|
251
302
|
if (response.chatUid && response.chatUid !== chatUid) {
|
|
252
|
-
|
|
303
|
+
logRef.current.log('[useDevicChat] Setting chatUid:', response.chatUid);
|
|
253
304
|
setChatUid(response.chatUid);
|
|
254
305
|
onChatCreatedRef.current?.(response.chatUid);
|
|
255
306
|
}
|
|
256
307
|
// Start polling for results
|
|
257
|
-
|
|
308
|
+
logRef.current.log('[useDevicChat] Setting shouldPoll to true');
|
|
258
309
|
setShouldPoll(true);
|
|
259
310
|
}
|
|
260
311
|
catch (err) {
|
|
@@ -277,11 +328,18 @@ function useDevicChat(options) {
|
|
|
277
328
|
]);
|
|
278
329
|
// Clear chat
|
|
279
330
|
const clearChat = useCallback(() => {
|
|
331
|
+
setShouldPoll(false);
|
|
332
|
+
setHandedOff(false);
|
|
333
|
+
setHandedOffSubThreadId(null);
|
|
334
|
+
if (handoffPollRef.current) {
|
|
335
|
+
clearInterval(handoffPollRef.current);
|
|
336
|
+
handoffPollRef.current = null;
|
|
337
|
+
}
|
|
280
338
|
setMessages([]);
|
|
281
339
|
setChatUid(null);
|
|
340
|
+
setIsLoading(false);
|
|
282
341
|
setStatus('idle');
|
|
283
342
|
setError(null);
|
|
284
|
-
setShouldPoll(false);
|
|
285
343
|
}, []);
|
|
286
344
|
// Load existing chat
|
|
287
345
|
const loadChat = useCallback(async (loadChatUid) => {
|
|
@@ -291,23 +349,30 @@ function useDevicChat(options) {
|
|
|
291
349
|
onErrorRef.current?.(err);
|
|
292
350
|
return;
|
|
293
351
|
}
|
|
352
|
+
// Reset any active polling/handoff state from previous conversation
|
|
353
|
+
setShouldPoll(false);
|
|
354
|
+
setHandedOff(false);
|
|
355
|
+
setHandedOffSubThreadId(null);
|
|
356
|
+
if (handoffPollRef.current) {
|
|
357
|
+
clearInterval(handoffPollRef.current);
|
|
358
|
+
handoffPollRef.current = null;
|
|
359
|
+
}
|
|
294
360
|
setIsLoading(true);
|
|
295
361
|
setError(null);
|
|
296
362
|
try {
|
|
297
363
|
const history = await clientRef.current.getChatHistory(assistantId, loadChatUid, { tenantId: resolvedTenantId });
|
|
298
364
|
setMessages(history.chatContent);
|
|
299
365
|
setChatUid(loadChatUid);
|
|
300
|
-
|
|
366
|
+
// Check realtime status to resume in-progress conversations
|
|
367
|
+
await resumeFromRealtimeStatus(loadChatUid);
|
|
301
368
|
}
|
|
302
369
|
catch (err) {
|
|
303
370
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
304
371
|
setError(error);
|
|
305
372
|
onErrorRef.current?.(error);
|
|
306
|
-
}
|
|
307
|
-
finally {
|
|
308
373
|
setIsLoading(false);
|
|
309
374
|
}
|
|
310
|
-
}, [assistantId, resolvedTenantId]);
|
|
375
|
+
}, [assistantId, resolvedTenantId, resumeFromRealtimeStatus]);
|
|
311
376
|
// Handoff polling: while handedOff is true, poll the realtime endpoint every 5s
|
|
312
377
|
// to detect when the parent thread is no longer in handed_off state.
|
|
313
378
|
useEffect(() => {
|
|
@@ -316,7 +381,7 @@ function useDevicChat(options) {
|
|
|
316
381
|
const pollHandoff = async () => {
|
|
317
382
|
try {
|
|
318
383
|
const realtime = await clientRef.current.getRealtimeHistory(assistantId, chatUid);
|
|
319
|
-
|
|
384
|
+
logRef.current.log('[useDevicChat] Handoff poll - realtime status:', realtime.status);
|
|
320
385
|
if (realtime.status !== 'handed_off') {
|
|
321
386
|
// Handoff completed — clear handoff state and resume main polling
|
|
322
387
|
if (handoffPollRef.current) {
|
|
@@ -341,7 +406,7 @@ function useDevicChat(options) {
|
|
|
341
406
|
}, [handedOff, chatUid, assistantId]);
|
|
342
407
|
// Called by HandoffSubagentWidget when the subthread reaches a terminal state
|
|
343
408
|
const onHandoffCompleted = useCallback(() => {
|
|
344
|
-
|
|
409
|
+
logRef.current.log('[useDevicChat] onHandoffCompleted called');
|
|
345
410
|
// Clear the handoff polling
|
|
346
411
|
if (handoffPollRef.current) {
|
|
347
412
|
clearInterval(handoffPollRef.current);
|
|
@@ -355,18 +420,21 @@ function useDevicChat(options) {
|
|
|
355
420
|
// Stop current conversation — calls the server-side stop endpoint
|
|
356
421
|
// then stops polling and resets loading state.
|
|
357
422
|
const stopChat = useCallback(async () => {
|
|
358
|
-
|
|
423
|
+
const uid = chatUidRef.current;
|
|
424
|
+
logRef.current.log('[useDevicChat] stopChat called, chatUid:', uid);
|
|
425
|
+
if (clientRef.current && uid) {
|
|
359
426
|
try {
|
|
360
|
-
await clientRef.current.stopChat(assistantId,
|
|
427
|
+
await clientRef.current.stopChat(assistantId, uid);
|
|
428
|
+
logRef.current.log('[useDevicChat] stopChat API call succeeded');
|
|
361
429
|
}
|
|
362
|
-
catch {
|
|
363
|
-
|
|
430
|
+
catch (err) {
|
|
431
|
+
logRef.current.warn('[useDevicChat] stopChat API call failed:', err);
|
|
364
432
|
}
|
|
365
433
|
}
|
|
366
434
|
setShouldPoll(false);
|
|
367
435
|
setIsLoading(false);
|
|
368
436
|
setStatus('idle');
|
|
369
|
-
}, [
|
|
437
|
+
}, [assistantId]);
|
|
370
438
|
return {
|
|
371
439
|
messages,
|
|
372
440
|
chatUid,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDevicChat.js","sources":["../../../src/hooks/useDevicChat.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useRef } from 'react';\nimport { useOptionalDevicContext } from '../provider';\nimport { DevicApiClient } from '../api/client';\nimport { usePolling } from './usePolling';\nimport { useModelInterface } from './useModelInterface';\n\nconsole.log('[devic-ui] Version: 0.6.1');\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\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?: ChatFile[];\n metadata?: Record<string, any>;\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/**\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 } = 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\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 // 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 // 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 setStatus('completed');\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n } finally {\n setIsLoading(false);\n }\n };\n\n loadInitialChat();\n }\n }, [initialChatUid, assistantId, resolvedTenantId]);\n\n // Model interface hook\n const {\n toolSchemas,\n handleToolCalls,\n extractPendingToolCalls,\n } = useModelInterface({\n tools: modelInterfaceTools,\n onToolExecute: onToolCall,\n });\n\n // Polling hook - uses callbacks for side effects, return value not needed\n console.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);\n usePolling(\n shouldPoll ? chatUid : null,\n async () => {\n console.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 console.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 console.log('[useDevicChat] onUpdate called, status:', data.status);\n\n // Merge realtime data with optimistic messages\n setMessages((prev) => {\n const realtimeUIDs = new Set(data.chatHistory.map((m) => m.uid));\n const realtimeUserMessages = new Set(\n data.chatHistory\n .filter((m) => m.role === 'user')\n .map((m) => m.content?.message)\n );\n\n // Keep optimistic messages not yet in realtime data\n const optimistic = prev.filter((m) => {\n if (realtimeUIDs.has(m.uid)) return false;\n if (m.role === 'user' && realtimeUserMessages.has(m.content?.message)) return false;\n return true;\n });\n\n return [...data.chatHistory, ...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 console.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 console.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 console.error('[useDevicChat] onError called:', err);\n setError(err);\n setIsLoading(false);\n setShouldPoll(false);\n onErrorRef.current?.(err);\n },\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\n const responses = await handleToolCalls(pendingCalls);\n\n if (responses.length > 0) {\n // Send tool responses back to the API\n await clientRef.current.sendToolResponses(assistantId, chatUid, responses);\n\n // Resume polling\n setShouldPoll(true);\n setIsLoading(true);\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?: ChatFile[];\n metadata?: Record<string, any>;\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\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: f.downloadUrl || '',\n type: f.fileType || 'other',\n })),\n },\n timestamp: Date.now(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n try {\n // Build request DTO\n const dto = {\n message,\n chatUid: chatUid || undefined,\n files: sendOptions?.files,\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 };\n\n // Send message in async mode\n console.log('[useDevicChat] Sending message async...');\n const response = await clientRef.current.sendMessageAsync(assistantId, dto);\n console.log('[useDevicChat] sendMessageAsync response:', response);\n\n // Update chat UID if this is a new chat\n if (response.chatUid && response.chatUid !== chatUid) {\n console.log('[useDevicChat] Setting chatUid:', response.chatUid);\n setChatUid(response.chatUid);\n onChatCreatedRef.current?.(response.chatUid);\n }\n\n // Start polling for results\n console.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 ]\n );\n\n // Clear chat\n const clearChat = useCallback(() => {\n setMessages([]);\n setChatUid(null);\n setStatus('idle');\n setError(null);\n setShouldPoll(false);\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 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 setStatus('completed');\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n } finally {\n setIsLoading(false);\n }\n },\n [assistantId, resolvedTenantId]\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 console.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 console.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 // Stop current conversation — calls the server-side stop endpoint\n // then stops polling and resets loading state.\n const stopChat = useCallback(async () => {\n if (clientRef.current && chatUid) {\n try {\n await clientRef.current.stopChat(assistantId, chatUid);\n } catch {\n // Ignore errors (e.g. chat already completed)\n }\n }\n setShouldPoll(false);\n setIsLoading(false);\n setStatus('idle');\n }, [chatUid, 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 };\n}\n"],"names":[],"mappings":";;;;;;;AAMA,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;AAwJxC;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,YAAY,CAAC,OAA4B,EAAA;AACvD,IAAA,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,GACd,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;;IAGhF,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,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;;;AAIrB,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;oBAC1B,SAAS,CAAC,WAAW,CAAC;gBACxB;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;gBAC7B;wBAAU;oBACR,YAAY,CAAC,KAAK,CAAC;gBACrB;AACF,YAAA,CAAC;AAED,YAAA,eAAe,EAAE;QACnB;IACF,CAAC,EAAE,CAAC,cAAc,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;;IAGnD,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,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC;AACnF,IAAA,UAAU,CACR,UAAU,GAAG,OAAO,GAAG,IAAI,EAC3B,YAAW;AACT,QAAA,OAAO,CAAC,GAAG,CAAC,yCAAyC,EAAE,OAAO,CAAC;QAC/D,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;AAC/E,QAAA,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,MAAM,CAAC;AAChE,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,OAAO,CAAC,GAAG,CAAC,yCAAyC,EAAE,IAAI,CAAC,MAAM,CAAC;;AAGnE,YAAA,WAAW,CAAC,CAAC,IAAI,KAAI;gBACnB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;AAChE,gBAAA,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAClC,IAAI,CAAC;qBACF,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM;AAC/B,qBAAA,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAClC;;gBAGD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAI;AACnC,oBAAA,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAAE,wBAAA,OAAO,KAAK;AACzC,oBAAA,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC;AAAE,wBAAA,OAAO,KAAK;AACnF,oBAAA,OAAO,IAAI;AACb,gBAAA,CAAC,CAAC;gBAEF,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC;AAC7C,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,OAAO,CAAC,GAAG,CAAC,uCAAuC,EAAE,IAAI,EAAE,MAAM,CAAC;YAClE,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,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;gBAClF,IAAI,WAAW,EAAE;oBACf,uBAAuB,CAAC,WAAW,CAAC;gBACtC;YACF;;QAEF,CAAC;AACD,QAAA,OAAO,EAAE,CAAC,GAAG,KAAI;AACf,YAAA,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC;YACpD,QAAQ,CAAC,GAAG,CAAC;YACb,YAAY,CAAC,KAAK,CAAC;YACnB,aAAa,CAAC,KAAK,CAAC;AACpB,YAAA,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC;QAC3B,CAAC;AACF,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;;AAEF,YAAA,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC;AAErD,YAAA,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;;AAExB,gBAAA,MAAM,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC;;gBAG1E,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,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,WAGC,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,CAAC,CAAC,WAAW,IAAI,EAAE;AACxB,oBAAA,IAAI,EAAE,CAAC,CAAC,QAAQ,IAAI,OAAO;AAC5B,iBAAA,CAAC,CAAC;AACJ,aAAA;AACD,YAAA,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB;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,MAAM,GAAG,GAAG;gBACV,OAAO;gBACP,OAAO,EAAE,OAAO,IAAI,SAAS;gBAC7B,KAAK,EAAE,WAAW,EAAE,KAAK;AACzB,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;aACtD;;AAGD,YAAA,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC;AACtD,YAAA,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,CAAC;AAC3E,YAAA,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,QAAQ,CAAC;;YAGlE,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,EAAE;gBACpD,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,QAAQ,CAAC,OAAO,CAAC;AAChE,gBAAA,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC5B,gBAAgB,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;YAC9C;;AAGA,YAAA,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC;YACxD,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;AACd,KAAA,CACF;;AAGD,IAAA,MAAM,SAAS,GAAG,WAAW,CAAC,MAAK;QACjC,WAAW,CAAC,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,CAAC;QAChB,SAAS,CAAC,MAAM,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC;QACd,aAAa,CAAC,KAAK,CAAC;IACtB,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;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;YACvB,SAAS,CAAC,WAAW,CAAC;QACxB;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;gBAAU;YACR,YAAY,CAAC,KAAK,CAAC;QACrB;AACF,IAAA,CAAC,EACD,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAChC;;;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,OAAO,CAAC,GAAG,CAAC,gDAAgD,EAAE,QAAQ,CAAC,MAAM,CAAC;AAC9E,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,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC;;AAEvD,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;;;AAIN,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAW;AACtC,QAAA,IAAI,SAAS,CAAC,OAAO,IAAI,OAAO,EAAE;AAChC,YAAA,IAAI;gBACF,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;YACxD;AAAE,YAAA,MAAM;;YAER;QACF;QACA,aAAa,CAAC,KAAK,CAAC;QACpB,YAAY,CAAC,KAAK,CAAC;QACnB,SAAS,CAAC,MAAM,CAAC;AACnB,IAAA,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAE1B,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;KACT;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 } from '../api/client';\nimport { usePolling } from './usePolling';\nimport { useModelInterface } 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 * 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?: ChatFile[];\n metadata?: Record<string, any>;\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/**\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 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 // 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 setMessages((prev) => {\n const realtimeUIDs = new Set(data.chatHistory.map((m) => m.uid));\n const realtimeUserMessages = new Set(\n data.chatHistory\n .filter((m) => m.role === 'user')\n .map((m) => m.content?.message)\n );\n\n // Keep optimistic messages not yet in realtime data\n const optimistic = prev.filter((m) => {\n if (realtimeUIDs.has(m.uid)) return false;\n if (m.role === 'user' && realtimeUserMessages.has(m.content?.message)) return false;\n return true;\n });\n\n return [...data.chatHistory, ...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\n const responses = await handleToolCalls(pendingCalls);\n\n if (responses.length > 0) {\n // Send tool responses back to the API\n await clientRef.current.sendToolResponses(assistantId, chatUid, responses);\n\n // Resume polling\n setShouldPoll(true);\n setIsLoading(true);\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?: ChatFile[];\n metadata?: Record<string, any>;\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\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: f.downloadUrl || '',\n type: f.fileType || 'other',\n })),\n },\n timestamp: Date.now(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n try {\n // Build request DTO\n const dto = {\n message,\n chatUid: chatUid || undefined,\n files: sendOptions?.files,\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 };\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 ]\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 }, []);\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 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 // 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 };\n}\n"],"names":[],"mappings":"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"}
|