@devicai/ui 0.55.0 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/cjs/api/types.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js +3 -1
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatMessages.js +41 -4
- package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/CompactionWidget.js +72 -0
- package/dist/cjs/components/ChatDrawer/CompactionWidget.js.map +1 -0
- package/dist/cjs/hooks/useDevicChat.js +32 -1
- package/dist/cjs/hooks/useDevicChat.js.map +1 -1
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/styles.css +1 -1
- package/dist/esm/api/types.d.ts +83 -0
- package/dist/esm/api/types.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.js +3 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +33 -1
- package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +1 -1
- package/dist/esm/components/ChatDrawer/ChatMessages.js +41 -4
- package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
- package/dist/esm/components/ChatDrawer/CompactionWidget.d.ts +47 -0
- package/dist/esm/components/ChatDrawer/CompactionWidget.js +70 -0
- package/dist/esm/components/ChatDrawer/CompactionWidget.js.map +1 -0
- package/dist/esm/components/ChatDrawer/index.d.ts +2 -0
- package/dist/esm/hooks/useDevicChat.d.ts +13 -1
- package/dist/esm/hooks/useDevicChat.js +32 -1
- package/dist/esm/hooks/useDevicChat.js.map +1 -1
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/styles.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompactionWidget.js","sources":["../../../../src/components/ChatDrawer/CompactionWidget.tsx"],"sourcesContent":["import { useState, type JSX, type ReactNode } from \"react\";\nimport type {\n CompactionActivity,\n CompactionCheckpoint,\n CompactionSummary,\n} from \"../../api/types\";\n\n/** Data handed to a custom compaction renderer. */\nexport interface CompactionRendererProps {\n /**\n * The checkpoint at this point of the conversation. Null while a compaction\n * is being written and there is nothing to show yet.\n */\n checkpoint: CompactionCheckpoint | null;\n /**\n * True for the checkpoint that currently governs the context. Each\n * compaction merges the previous summary into itself, so the earlier ones\n * are a record rather than something still being sent.\n */\n isActive: boolean;\n /**\n * The compaction happening right now, or null. Present without a checkpoint\n * means one is being written; the numbers say what it is folding.\n */\n activity: CompactionActivity | null;\n}\n\n/** Replaces the built-in compaction marker. Return null to hide it. */\nexport type CompactionRenderer = (props: CompactionRendererProps) => ReactNode;\n\nfunction formatTokens(value: number): string {\n if (!value) return \"0\";\n if (value < 1000) return String(value);\n if (value < 1_000_000) return `${(value / 1000).toFixed(1)}k`;\n return `${(value / 1_000_000).toFixed(2)}M`;\n}\n\nfunction CompressIcon(): JSX.Element {\n return (\n <svg\n className=\"devic-compaction-icon\"\n width=\"13\"\n height=\"13\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"4 14 10 14 10 20\" />\n <polyline points=\"20 10 14 10 14 4\" />\n <line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </svg>\n );\n}\n\nfunction ChevronIcon({ up }: { up: boolean }): JSX.Element {\n return (\n <svg\n className=\"devic-compaction-chevron\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n style={{ transform: up ? \"rotate(180deg)\" : undefined }}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nfunction Section({\n title,\n children,\n}: {\n title: string;\n children: ReactNode;\n}): JSX.Element {\n return (\n <div className=\"devic-compaction-section\">\n <span className=\"devic-compaction-section-title\">{title}</span>\n {children}\n </div>\n );\n}\n\nfunction Bullets({ items }: { items?: string[] }): JSX.Element | null {\n if (!items?.length) return null;\n return (\n <ul className=\"devic-compaction-list\">\n {items.map((item, i) => (\n <li key={i}>{item}</li>\n ))}\n </ul>\n );\n}\n\nfunction hasStructure(summary: CompactionSummary): boolean {\n return Boolean(\n summary.goal ||\n summary.constraints?.length ||\n summary.inProgress ||\n summary.pending?.length ||\n summary.decisions?.length ||\n summary.data?.length ||\n summary.done?.length ||\n summary.openQuestions?.length\n );\n}\n\nexport interface CompactionWidgetProps {\n checkpoint: CompactionCheckpoint | null;\n isActive?: boolean;\n activity?: CompactionActivity | null;\n renderer?: CompactionRenderer;\n}\n\n/**\n * The cut line in the conversation.\n *\n * Anchored to the last message a checkpoint folded, it marks the exact point\n * where the assistant's view of the conversation stops: everything above it\n * is still here, still readable, and no longer sent. Collapsed it is a rule\n * across the thread with the headline numbers; expanded it shows what the\n * assistant reads in place of those messages.\n *\n * With no checkpoint yet and a compaction in flight it says so instead — that\n * is a model call of its own, and without it the conversation just appears to\n * have gone quiet.\n *\n * Deliberately not a message bubble: a checkpoint is not something anyone\n * said.\n */\nexport function CompactionWidget({\n checkpoint,\n isActive = true,\n activity = null,\n renderer,\n}: CompactionWidgetProps): JSX.Element | null {\n const [expanded, setExpanded] = useState(false);\n\n if (renderer) {\n return <>{renderer({ checkpoint, isActive, activity })}</>;\n }\n\n const running = activity?.state === \"running\";\n\n if (!checkpoint) {\n if (!running) return null;\n return (\n <div className=\"devic-compaction devic-compaction-running\">\n <span className=\"devic-compaction-rule\" />\n <span className=\"devic-compaction-pill\">\n <CompressIcon />\n <span className=\"devic-compaction-title\">Compacting context</span>\n <span className=\"devic-compaction-meta\">\n {activity!.messageCount} message\n {activity!.messageCount === 1 ? \"\" : \"s\"} ·{\" \"}\n {formatTokens(activity!.tokensBefore)} tokens\n </span>\n <span className=\"devic-compaction-dots\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n </span>\n </span>\n <span className=\"devic-compaction-rule\" />\n </div>\n );\n }\n\n const summary = checkpoint.summary || {};\n const structured = hasStructure(summary);\n\n return (\n <div className=\"devic-compaction\">\n <div className=\"devic-compaction-head\">\n <span className=\"devic-compaction-rule\" />\n <button\n type=\"button\"\n className=\"devic-compaction-pill\"\n onClick={() => setExpanded((v) => !v)}\n aria-expanded={expanded}\n title={`${checkpoint.compactedMessageCount} message${\n checkpoint.compactedMessageCount === 1 ? \"\" : \"s\"\n } are still in this conversation but no longer sent to the assistant`}\n >\n <CompressIcon />\n <span className=\"devic-compaction-title\">\n Context compacted\n {checkpoint.index > 1 ? ` (#${checkpoint.index})` : \"\"}\n </span>\n <span className=\"devic-compaction-meta\">\n {checkpoint.compactedMessageCount} messages ·{\" \"}\n {formatTokens(checkpoint.tokensBefore)} →{\" \"}\n {formatTokens(checkpoint.tokensAfter)} tokens\n </span>\n {!isActive && (\n <span\n className=\"devic-compaction-tag\"\n title=\"Superseded by a later compaction, which merged this summary into itself. Kept for the record.\"\n >\n superseded\n </span>\n )}\n <ChevronIcon up={expanded} />\n </button>\n <span className=\"devic-compaction-rule\" />\n </div>\n\n {expanded && (\n <div className=\"devic-compaction-body\">\n <div className=\"devic-compaction-note\">\n This is what the assistant reads in place of the messages above.\n The messages themselves are still here.\n </div>\n\n {structured && (\n <>\n {summary.goal && <Section title=\"Goal\">{summary.goal}</Section>}\n {!!summary.constraints?.length && (\n <Section title=\"Constraints\">\n <Bullets items={summary.constraints} />\n </Section>\n )}\n {summary.inProgress && (\n <Section title=\"In progress\">{summary.inProgress}</Section>\n )}\n {!!summary.pending?.length && (\n <Section title=\"Pending\">\n <Bullets items={summary.pending} />\n </Section>\n )}\n {!!summary.decisions?.length && (\n <Section title=\"Decisions\">\n <Bullets items={summary.decisions} />\n </Section>\n )}\n {!!summary.data?.length && (\n <Section title=\"Key data\">\n <Bullets\n items={summary.data.map((entry) =>\n entry.label ? `${entry.label}: ${entry.value}` : entry.value\n )}\n />\n </Section>\n )}\n {!!summary.done?.length && (\n <Section title=\"Done\">\n <Bullets items={summary.done} />\n </Section>\n )}\n {!!summary.openQuestions?.length && (\n <Section title=\"Open questions\">\n <Bullets items={summary.openQuestions} />\n </Section>\n )}\n </>\n )}\n\n {summary.raw && (\n <Section title={structured ? \"Notes\" : \"Summary\"}>\n <div className=\"devic-compaction-raw\">{summary.raw}</div>\n </Section>\n )}\n\n {!!checkpoint.facts?.length && (\n <Section title=\"Preserved exactly\">\n <div className=\"devic-compaction-facts\">\n {checkpoint.facts.map((fact, i) => (\n <span key={i} className=\"devic-compaction-fact\">\n {fact.label ? (\n <span className=\"devic-compaction-fact-label\">\n {fact.label}:{\" \"}\n </span>\n ) : null}\n {fact.value}\n </span>\n ))}\n </div>\n </Section>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport default CompactionWidget;\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":"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"}
|
|
@@ -13,6 +13,8 @@ export type { LimitBannerProps } from './LimitBanner';
|
|
|
13
13
|
export { QueueNotice } from './QueueNotice';
|
|
14
14
|
export type { QueueNoticeProps } from './QueueNotice';
|
|
15
15
|
export { RecalledMemoriesWidget } from './RecalledMemoriesWidget';
|
|
16
|
+
export type { CompactionWidgetProps, CompactionRenderer, CompactionRendererProps, } from './CompactionWidget';
|
|
17
|
+
export { CompactionWidget } from './CompactionWidget';
|
|
16
18
|
export type { RecalledMemoriesWidgetProps, RecalledMemoriesRenderer, RecalledMemoriesRendererProps, } from './RecalledMemoriesWidget';
|
|
17
19
|
export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, MessageBubbleRenderer, MessageBubbleRendererProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, SuggestedMessage, } from './ChatDrawer.types';
|
|
18
20
|
export type { HandoffSubagentWidgetProps } from './HandoffSubagentWidget';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TenantMetadata, SubtenantMetadata } from '../provider';
|
|
2
2
|
import { type PendingWidgetCall } from './useModelInterface';
|
|
3
|
-
import type { ChatMessage, ChatFile, ModelInterfaceTool, QueueDisposition, RealtimeStatus, RecalledMemoryRecord, TenantLimitExceeded } from '../api/types';
|
|
3
|
+
import type { ChatMessage, ChatFile, CompactionActivity, CompactionCheckpoint, ModelInterfaceTool, QueueDisposition, RealtimeStatus, RecalledMemoryRecord, TenantLimitExceeded } from '../api/types';
|
|
4
4
|
export interface UseDevicChatOptions {
|
|
5
5
|
/**
|
|
6
6
|
* Assistant identifier
|
|
@@ -177,6 +177,18 @@ export interface UseDevicChatResult {
|
|
|
177
177
|
* without memory.
|
|
178
178
|
*/
|
|
179
179
|
recalledMemories: RecalledMemoryRecord[];
|
|
180
|
+
/**
|
|
181
|
+
* Compaction checkpoints of the conversation, oldest first. Each one folds
|
|
182
|
+
* the messages before its boundary into a summary the model reads instead
|
|
183
|
+
* of them; the messages themselves stay in `messages`.
|
|
184
|
+
*/
|
|
185
|
+
compactions: CompactionCheckpoint[];
|
|
186
|
+
/**
|
|
187
|
+
* The compaction being written right now, or null. A compaction is a model
|
|
188
|
+
* call of its own between two assistant messages, so this is what tells a
|
|
189
|
+
* UI why the conversation has gone quiet.
|
|
190
|
+
*/
|
|
191
|
+
compaction: CompactionActivity | null;
|
|
180
192
|
/**
|
|
181
193
|
* Whether the assistant has handed off to a subagent
|
|
182
194
|
*/
|
|
@@ -90,6 +90,22 @@ function useDevicChat(options) {
|
|
|
90
90
|
return fresh.length ? [...prev, ...fresh] : prev;
|
|
91
91
|
});
|
|
92
92
|
}, []);
|
|
93
|
+
// Compaction checkpoints of the conversation, and the one being written
|
|
94
|
+
// right now. Same merge rule as the recalls: the realtime blob only carries
|
|
95
|
+
// the in-flight run's checkpoints, so incoming batches merge by uid.
|
|
96
|
+
const [compactions, setCompactions] = useState([]);
|
|
97
|
+
const mergeCompactions = useCallback((incoming) => {
|
|
98
|
+
if (!incoming?.length)
|
|
99
|
+
return;
|
|
100
|
+
setCompactions((prev) => {
|
|
101
|
+
const known = new Set(prev.map((c) => c.uid));
|
|
102
|
+
const fresh = incoming.filter((c) => !known.has(c.uid));
|
|
103
|
+
return fresh.length ? [...prev, ...fresh] : prev;
|
|
104
|
+
});
|
|
105
|
+
}, []);
|
|
106
|
+
// Absent on every ordinary realtime write, which is how a finished
|
|
107
|
+
// compaction stops being reported.
|
|
108
|
+
const [compaction, setCompaction] = useState(null);
|
|
93
109
|
// Handoff state
|
|
94
110
|
const [handedOff, setHandedOff] = useState(false);
|
|
95
111
|
const [handedOffSubThreadId, setHandedOffSubThreadId] = useState(null);
|
|
@@ -192,6 +208,8 @@ function useDevicChat(options) {
|
|
|
192
208
|
setMessages([...(realtime.chatHistory ?? []), ...queuedOnServer]);
|
|
193
209
|
}
|
|
194
210
|
mergeRecalledMemories(realtime.recalledMemories);
|
|
211
|
+
mergeCompactions(realtime.compactions);
|
|
212
|
+
setCompaction(realtime.compaction ?? null);
|
|
195
213
|
setStatus(realtime.status);
|
|
196
214
|
setQueuedCount(realtime.queuedMessages ?? 0);
|
|
197
215
|
if (realtime.status === 'processing') {
|
|
@@ -231,7 +249,7 @@ function useDevicChat(options) {
|
|
|
231
249
|
logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);
|
|
232
250
|
setIsLoading(false);
|
|
233
251
|
}
|
|
234
|
-
}, [assistantId, mergeRecalledMemories]);
|
|
252
|
+
}, [assistantId, mergeRecalledMemories, mergeCompactions]);
|
|
235
253
|
// Load initial chat history if chatUid prop is provided
|
|
236
254
|
// This runs once on mount (or when initialChatUid changes) to fetch existing conversation
|
|
237
255
|
const initialChatLoadedRef = useRef(false);
|
|
@@ -245,6 +263,7 @@ function useDevicChat(options) {
|
|
|
245
263
|
const history = await clientRef.current.getChatHistory(assistantId, initialChatUid, { tenantId: resolvedTenantId });
|
|
246
264
|
setMessages(history.chatContent);
|
|
247
265
|
mergeRecalledMemories(history.recalledMemories);
|
|
266
|
+
mergeCompactions(history.compactions);
|
|
248
267
|
setChatUid(initialChatUid);
|
|
249
268
|
// Check realtime status to resume in-progress conversations
|
|
250
269
|
await resumeFromRealtimeStatus(initialChatUid);
|
|
@@ -373,6 +392,10 @@ function useDevicChat(options) {
|
|
|
373
392
|
// Surface recall events while the run is still processing, so the
|
|
374
393
|
// "recalled memories" strip shows before the first response lands.
|
|
375
394
|
mergeRecalledMemories(data.recalledMemories);
|
|
395
|
+
// A compaction runs between two assistant messages: without this the
|
|
396
|
+
// conversation looks stalled while it is being written.
|
|
397
|
+
mergeCompactions(data.compactions);
|
|
398
|
+
setCompaction(data.compaction ?? null);
|
|
376
399
|
setStatus(data.status);
|
|
377
400
|
// Notify about new messages
|
|
378
401
|
const lastMessage = data.chatHistory[data.chatHistory.length - 1];
|
|
@@ -717,6 +740,8 @@ function useDevicChat(options) {
|
|
|
717
740
|
setError(null);
|
|
718
741
|
setLimitExceeded(null);
|
|
719
742
|
setRecalledMemories([]);
|
|
743
|
+
setCompactions([]);
|
|
744
|
+
setCompaction(null);
|
|
720
745
|
resetQueueState();
|
|
721
746
|
pendingWidgetCallsRef.current = [];
|
|
722
747
|
setPendingWidgetCalls([]);
|
|
@@ -742,12 +767,15 @@ function useDevicChat(options) {
|
|
|
742
767
|
setIsLoading(true);
|
|
743
768
|
setError(null);
|
|
744
769
|
setRecalledMemories([]);
|
|
770
|
+
setCompactions([]);
|
|
771
|
+
setCompaction(null);
|
|
745
772
|
// The queue belongs to the conversation being left behind.
|
|
746
773
|
resetQueueState();
|
|
747
774
|
try {
|
|
748
775
|
const history = await clientRef.current.getChatHistory(assistantId, loadChatUid, { tenantId: resolvedTenantId });
|
|
749
776
|
setMessages(history.chatContent);
|
|
750
777
|
mergeRecalledMemories(history.recalledMemories);
|
|
778
|
+
mergeCompactions(history.compactions);
|
|
751
779
|
setChatUid(loadChatUid);
|
|
752
780
|
// Check realtime status to resume in-progress conversations
|
|
753
781
|
await resumeFromRealtimeStatus(loadChatUid);
|
|
@@ -763,6 +791,7 @@ function useDevicChat(options) {
|
|
|
763
791
|
resolvedTenantId,
|
|
764
792
|
resumeFromRealtimeStatus,
|
|
765
793
|
mergeRecalledMemories,
|
|
794
|
+
mergeCompactions,
|
|
766
795
|
resetQueueState,
|
|
767
796
|
]);
|
|
768
797
|
// Handoff polling: while handedOff is true, poll the realtime endpoint every
|
|
@@ -891,6 +920,8 @@ function useDevicChat(options) {
|
|
|
891
920
|
error,
|
|
892
921
|
limitExceeded,
|
|
893
922
|
recalledMemories,
|
|
923
|
+
compactions,
|
|
924
|
+
compaction,
|
|
894
925
|
handedOff,
|
|
895
926
|
handedOffSubThreadId,
|
|
896
927
|
queuedCount,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDevicChat.js","sources":["../../../src/hooks/useDevicChat.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useOptionalDevicContext } from '../provider';\nimport type { TenantMetadata, SubtenantMetadata } from '../provider';\nimport { DevicApiClient, DevicApiError } from '../api/client';\nimport { usePolling, resolvePollingInterval } from './usePolling';\nimport { useModelInterface, type PendingWidgetCall } from './useModelInterface';\nimport { createLogger } from '../utils/logger';\nimport { useAssistantInfo } from '../api/assistantInfo';\nimport type {\n ChatMessage,\n ChatFile,\n ModelInterfaceTool,\n QueueDisposition,\n RealtimeChatHistory,\n RealtimeStatus,\n RecalledMemoryRecord,\n TenantLimitExceeded,\n} from '../api/types';\n\n/**\n * Cadence for the handoff watch, which only waits for the parent thread to\n * leave `handed_off` and so does not need the main conversation's rhythm.\n * A configured `pollingInterval` still wins over it.\n */\nconst DEFAULT_HANDOFF_POLL_INTERVAL_MS = 5000;\n\n/**\n * How many polls the conversation may read as finished while it still owes an\n * answer to something queued, before the wait is given up.\n *\n * The window is real: a run liquidates, and the follow-up run that drains the\n * queue has not marked itself as processing yet. Bounded so a message that\n * never comes back cannot poll forever.\n */\nconst QUEUE_HANDOVER_GRACE_TICKS = 60;\n\n/** Messages are matched to their optimistic copies by text, so it is normalized. */\nconst normalizeText = (text?: string): string => (text ?? '').trim();\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 (e.g. { name, email, imageUrl })\n */\n tenantMetadata?: TenantMetadata;\n\n /**\n * Subtenant ID identifying a user/entity inside the tenant\n */\n subtenantId?: string;\n\n /**\n * Subtenant metadata (e.g. { id, name, email, imageUrl })\n */\n subtenantMetadata?: SubtenantMetadata;\n\n /**\n * Tags applied to the conversation. Sent as the top-level `tags` of each\n * message (distinct from metadata). Falls back to the DevicProvider's `tags`\n * and is merged (deduped) with any per-message tags passed to `sendMessage`.\n */\n tags?: string[];\n\n /**\n * Tools enabled from the assistant's configured tool groups\n */\n enabledTools?: string[];\n\n /**\n * Apps the end user connected that should sit out the messages sent from\n * here, by slug (`[\"gmail\"]`).\n *\n * A deny list over their own connected apps, not over the assistant's tools:\n * what is not named stays available. Sent with every message while it is set,\n * so it lasts as long as the caller keeps it set — the server keeps nothing\n * and the account is never disconnected.\n */\n disabledIntegrations?: string[];\n\n /**\n * Client-side tools for model interface protocol\n */\n modelInterfaceTools?: ModelInterfaceTool[];\n\n /**\n * How often (ms) the conversation in progress is polled for new content.\n * Overrides the DevicProvider's `pollingInterval`. Values below 250 ms are\n * clamped.\n * @default 1000\n */\n pollingInterval?: number;\n\n /**\n * Callback when a message is sent\n */\n onMessageSent?: (message: ChatMessage) => void;\n\n /**\n * Callback when a message is received\n */\n onMessageReceived?: (message: ChatMessage) => void;\n\n /**\n * Callback when a tool is called\n */\n onToolCall?: (toolName: string, params: any) => void;\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Callback when a new chat is created\n */\n onChatCreated?: (chatUid: string) => void;\n\n /**\n * Custom file upload handler. When provided, replaces the default\n * upload to Devic API. Receives the raw File objects and must return\n * an array of ChatFile with downloadUrl set.\n */\n onFileUpload?: (files: File[]) => Promise<ChatFile[]>;\n\n /**\n * Whether this assistant takes messages while the conversation is busy.\n *\n * Left unset it is resolved from the assistant itself (`messageQueueEnabled`),\n * through the shared per-assistant lookup — one request, shared with the\n * avatar and the connected-apps control, whichever asks first. Pass a boolean\n * to skip the lookup entirely or to override what it says.\n *\n * With it off the input closes while the assistant answers, as it always has.\n * With it on, a message written mid-answer is accepted and joins the\n * assistant's next turn.\n */\n messageQueue?: boolean;\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\n/**\n * What became of a send.\n *\n * `queued` is an acceptance, not a failure: the message is on the conversation\n * and will be answered later. `rejected` is the opposite — nothing was\n * accepted, and the caller still holds the only copy of what the user wrote.\n */\nexport type SendMessageResult =\n | { queued: true; queuePosition: number; willProcess: QueueDisposition }\n | { queued: false }\n | {\n rejected: true;\n /**\n * `chat_busy`: this assistant does not queue and is working.\n * `queue_full`: it does, and the queue is at its configured ceiling.\n * `error`: anything else, already reported through `error`/`onError`.\n */\n reason: 'chat_busy' | 'queue_full' | 'error';\n message: string;\n /** What the user wrote, so it can be restored. */\n restoredText: string;\n };\n\nexport interface StopResult {\n /** Text of the queued messages the stop threw away, joined by newlines. */\n restoredText?: string;\n /** How many were discarded. */\n discarded: number;\n}\n\nexport interface UseDevicChatResult {\n /**\n * Current chat messages\n */\n messages: ChatMessage[];\n\n /**\n * Current chat UID\n */\n chatUid: string | null;\n\n /**\n * Whether a message is being processed\n */\n isLoading: boolean;\n\n /**\n * Current status\n */\n status: RealtimeStatus | 'idle';\n\n /**\n * Last error\n */\n error: Error | null;\n\n /**\n * Set when the last message was blocked by a tenant/subtenant usage limit\n * (HTTP 429 / realtime status `limit_exceeded`). Carries the blocking rule,\n * current vs. limit and when the window resets. `null` while not limited.\n * Cleared when a new message is sent or the chat is cleared.\n */\n limitExceeded: TenantLimitExceeded | null;\n\n /**\n * Structured long-term-memory recall events of the conversation, streamed\n * in while the assistant is still processing (via the realtime poll) and\n * hydrated from the persisted history on load. Empty for assistants\n * without memory.\n */\n recalledMemories: RecalledMemoryRecord[];\n\n /**\n * Whether the assistant has handed off to a subagent\n */\n handedOff: boolean;\n\n /**\n * The subthread ID when a handoff is active\n */\n handedOffSubThreadId: string | null;\n\n /**\n * Send a message\n */\n sendMessage: (\n message: string,\n options?: {\n files?: File[];\n metadata?: Record<string, any>;\n /** Id of a speech-to-text transcript that seeded this message. */\n transcriptId?: string;\n /** Per-message tags, merged (deduped) with the resolved conversation tags. */\n tags?: string[];\n /**\n * Connected apps to leave out of this one message, by slug. Replaces the\n * hook's own `disabledIntegrations` rather than adding to it, so a caller\n * can send one message with everything on by passing `[]`.\n */\n disabledIntegrations?: string[];\n }\n ) => Promise<SendMessageResult>;\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 * How many messages this conversation has accepted but not yet shown to the\n * model. Includes anything queued through another channel, so it is the\n * conversation's queue and not this client's.\n */\n queuedCount: number;\n\n /**\n * Whether this assistant takes messages while it is busy — resolved from the\n * assistant, or from the `messageQueue` option when given. False until the\n * lookup settles: an input that opens and then closes is worse than one that\n * opens a beat late.\n */\n queueEnabled: boolean;\n\n /**\n * Stop the current conversation processing.\n *\n * Returns the text of anything the stop discarded, so the caller can put it\n * back where the user wrote it — a stop should not be the way someone's\n * typing disappears.\n */\n stopChat: () => Promise<StopResult>;\n\n /**\n * Pending tool calls that require user interaction via a response widget\n */\n pendingWidgetCalls: PendingWidgetCall[];\n\n /**\n * Submit a response for a pending widget tool call.\n * Sends the response to the API and resumes the conversation.\n */\n submitWidgetResponse: (toolCallId: string, response: any) => Promise<void>;\n\n /**\n * Cancel a pending widget tool call.\n * Sends an error response so the model can continue.\n */\n cancelWidgetCall: (toolCallId: string, reason?: string) => Promise<void>;\n}\n\n/**\n * Main hook for managing chat with a Devic assistant\n *\n * @example\n * ```tsx\n * const {\n * messages,\n * isLoading,\n * sendMessage,\n * } = useDevicChat({\n * assistantId: 'my-assistant',\n * modelInterfaceTools: [\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ],\n * onMessageReceived: (msg) => console.log('Received:', msg),\n * });\n * ```\n */\nexport function useDevicChat(options: UseDevicChatOptions): UseDevicChatResult {\n const {\n assistantId,\n chatUid: initialChatUid,\n apiKey: propsApiKey,\n baseUrl: propsBaseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n enabledTools,\n disabledIntegrations,\n modelInterfaceTools = [],\n pollingInterval: propsPollingInterval,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n messageQueue,\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 getTenantSession = context?.getTenantSession;\n const onSessionExpired = context?.onSessionExpired;\n const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n const resolvedSubtenantMetadata = {\n ...context?.subtenantMetadata,\n ...subtenantMetadata,\n };\n // Provider tags + hook tags, deduped. Per-message tags are merged at send time.\n const resolvedTags = useMemo(\n () => Array.from(new Set([...(context?.tags ?? []), ...(tags ?? [])])),\n [context?.tags, tags]\n );\n const pollingInterval = resolvePollingInterval(\n propsPollingInterval,\n context?.pollingInterval\n );\n const handoffPollingInterval = resolvePollingInterval(\n propsPollingInterval,\n context?.pollingInterval,\n DEFAULT_HANDOFF_POLL_INTERVAL_MS\n );\n const debug = propsDebug ?? context?.debug ?? false;\n const log = useMemo(() => createLogger(debug), [debug]);\n const logRef = useRef(log);\n logRef.current = log;\n\n // State\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [chatUid, setChatUid] = useState<string | null>(initialChatUid || null);\n const [isLoading, setIsLoading] = useState(false);\n const [status, setStatus] = useState<RealtimeStatus | 'idle'>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [limitExceeded, setLimitExceeded] = useState<TenantLimitExceeded | null>(\n null\n );\n\n // Long-term-memory recall events of the conversation. The realtime blob\n // only carries the in-flight run's records, so incoming batches merge (by\n // uid) instead of replacing — earlier runs' recalls stay visible.\n const [recalledMemories, setRecalledMemories] = useState<RecalledMemoryRecord[]>([]);\n const mergeRecalledMemories = useCallback(\n (incoming?: RecalledMemoryRecord[]) => {\n if (!incoming?.length) return;\n setRecalledMemories((prev) => {\n const known = new Set(prev.map((r) => r.uid));\n const fresh = incoming.filter((r) => !known.has(r.uid));\n return fresh.length ? [...prev, ...fresh] : prev;\n });\n },\n []\n );\n\n // Handoff state\n const [handedOff, setHandedOff] = useState(false);\n const [handedOffSubThreadId, setHandedOffSubThreadId] = useState<string | null>(null);\n const handoffPollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Polling state\n const [shouldPoll, setShouldPoll] = useState(false);\n\n // Keep a ref to chatUid so async callbacks always read the latest value\n const chatUidRef = useRef(chatUid);\n chatUidRef.current = chatUid;\n\n // Read by `sendMessage`, which must not restate the state of a run already in\n // flight — its own callback identity would otherwise carry a stale value.\n const isLoadingRef = useRef(isLoading);\n isLoadingRef.current = isLoading;\n\n // Two messages sent inside the same millisecond would otherwise share a uid,\n // which the queue makes easy to do.\n const optimisticSeqRef = useRef(0);\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 || getTenantSession)) {\n clientRef.current = new DevicApiClient({ apiKey, baseUrl, getTenantSession, onSessionExpired });\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 // --- Message queue --------------------------------------------------------\n\n /**\n * Messages accepted by this conversation that the model has not seen yet.\n * Taken from the poll, so it counts whatever else queued on the conversation\n * too — another tab, or the same person writing from another channel.\n */\n const [queuedCount, setQueuedCount] = useState(0);\n\n /**\n * When something was queued from here that has not been answered yet.\n *\n * Deliberately not a list of the texts sent: a drain can merge several queued\n * messages into a single user turn, so what comes back is not what went out\n * and matching them by text would wait forever. What is being waited for is an\n * answer, and an assistant message written after the message was accepted is\n * that answer.\n */\n const awaitingAnswerSinceRef = useRef<number | null>(null);\n const queueGraceTicksRef = useRef(0);\n\n const rememberAwaiting = useCallback(() => {\n awaitingAnswerSinceRef.current = Date.now();\n }, []);\n\n const resetQueueState = useCallback(() => {\n awaitingAnswerSinceRef.current = null;\n queueGraceTicksRef.current = 0;\n setQueuedCount(0);\n }, []);\n\n /**\n * Asked for as soon as the hook is alive, rather than when the first run\n * starts: the answer decides whether the input stays open while the assistant\n * works, and resolving it late means the box visibly closes and reopens on the\n * first message of every session. One request, shared with everything else\n * that asks about this assistant. Passing `messageQueue` skips it entirely.\n */\n const queueLookup = useAssistantInfo({\n assistantId,\n client: clientRef.current,\n baseUrl,\n credential: apiKey || 'session',\n enabled: messageQueue === undefined,\n });\n\n /**\n * Absent means no. An assistant that has not answered yet, or an API too old\n * to carry the field, leaves the input closed while it works — the same thing\n * it did before this existed. Opening it on a maybe would promise a queue the\n * conversation then refuses.\n */\n const queueEnabled =\n messageQueue ??\n (queueLookup.settled &&\n queueLookup.assistant?.messageQueueEnabled === true);\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 const queuedOnServer = (realtime.pendingUserMessages ?? []).map((m) => ({\n ...m,\n queued: true,\n }));\n if (realtime.chatHistory?.length || queuedOnServer.length) {\n setMessages([...(realtime.chatHistory ?? []), ...queuedOnServer]);\n }\n mergeRecalledMemories(realtime.recalledMemories);\n setStatus(realtime.status);\n setQueuedCount(realtime.queuedMessages ?? 0);\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 if ((realtime.queuedMessages ?? 0) > 0) {\n // The run settled, but the conversation still owes an answer to\n // something queued — reopened on a conversation whose follow-up run\n // has not started yet. Watch it until the queue is served.\n setIsLoading(true);\n setShouldPoll(true);\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, mergeRecalledMemories]\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 mergeRecalledMemories(history.recalledMemories);\n setChatUid(initialChatUid);\n\n // Check realtime status to resume in-progress conversations\n await resumeFromRealtimeStatus(initialChatUid);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n setIsLoading(false);\n }\n };\n\n loadInitialChat();\n }\n }, [initialChatUid, assistantId, resolvedTenantId, resumeFromRealtimeStatus]);\n\n // Model interface hook\n const {\n toolSchemas,\n handleToolCalls,\n extractPendingToolCalls,\n } = useModelInterface({\n tools: modelInterfaceTools,\n onToolExecute: onToolCall,\n });\n\n // Pending widget calls awaiting user interaction\n const [pendingWidgetCalls, setPendingWidgetCalls] = useState<PendingWidgetCall[]>([]);\n const pendingWidgetCallsRef = useRef<PendingWidgetCall[]>([]);\n useEffect(() => {\n pendingWidgetCallsRef.current = pendingWidgetCalls;\n }, [pendingWidgetCalls]);\n\n // Polling hook - uses callbacks for side effects, return value not needed\n logRef.current.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);\n usePolling(\n shouldPoll ? chatUid : null,\n async () => {\n logRef.current.log('[useDevicChat] fetchFn called, chatUid:', chatUid);\n if (!clientRef.current || !chatUid) {\n throw new Error('Cannot poll without client or chatUid');\n }\n const result = await clientRef.current.getRealtimeHistory(assistantId, chatUid);\n logRef.current.log('[useDevicChat] getRealtimeHistory result:', result);\n return result;\n },\n {\n interval: pollingInterval,\n enabled: shouldPoll,\n stopStatuses: [\n 'completed',\n 'error',\n 'waiting_for_tool_response',\n 'handed_off',\n 'limit_exceeded',\n ],\n onUpdate: async (data: RealtimeChatHistory) => {\n logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);\n\n // An assistant message written after something was queued from here is\n // the answer that was being waited for.\n const awaitingSince = awaitingAnswerSinceRef.current;\n if (\n awaitingSince !== null &&\n (data.queuedMessages ?? 0) === 0 &&\n (data.chatHistory ?? []).some(\n (m) => m.role === 'assistant' && (m.timestamp ?? 0) > awaitingSince\n )\n ) {\n awaitingAnswerSinceRef.current = null;\n }\n\n // Merge realtime data with optimistic messages.\n // When a server user message matches an optimistic one by text, adopt the\n // optimistic uid so React's key stays stable (avoids unmount/remount flicker).\n setMessages((prev) => {\n // A queue of uids per text rather than one: two identical messages are\n // two messages, and pairing both with the same optimistic copy would\n // drop one of them from the conversation.\n const optimisticUserByText = new Map<string, string[]>();\n prev\n .filter((m) => m.role === 'user' && m.uid.startsWith('temp-'))\n .forEach((m) => {\n const key = normalizeText(m.content?.message);\n const bucket = optimisticUserByText.get(key);\n if (bucket) bucket.push(m.uid);\n else optimisticUserByText.set(key, [m.uid]);\n });\n\n const adoptedTempUids = new Set<string>();\n const adopt = (m: ChatMessage): ChatMessage => {\n if (m.role !== 'user') return m;\n const tempUid = optimisticUserByText\n .get(normalizeText(m.content?.message))\n ?.shift();\n if (!tempUid) return m;\n adoptedTempUids.add(tempUid);\n // Keep the server uid around: recall anchors reference it.\n return { ...m, uid: tempUid, serverUid: m.uid };\n };\n\n const merged = data.chatHistory.map(adopt);\n // Accepted, but not part of the conversation yet. Drawn between the\n // history and the optimistic ones, which is where they land once a\n // turn takes them. The copy is the server's, so it survives a reload —\n // where the API does not return them, this is empty and the optimistic\n // ones kept below stand in.\n const queued = (data.pendingUserMessages ?? []).map((m) => ({\n ...adopt(m),\n queued: true,\n }));\n\n // Which of this client's own queued bubbles to keep drawing.\n //\n // Matching them to the history by text does not work: a drain can\n // merge several queued messages into one user turn, and an optimistic\n // copy that never finds its pair would sit there marked as queued for\n // the rest of the conversation. The server's queue is the authority,\n // and these are kept only where it cannot speak for them:\n // - too recently accepted for this poll to have seen them;\n // - counted by `queuedMessages` but not itemised, which is what an\n // API without `pendingUserMessages` reports.\n const optimisticQueued = prev.filter(\n (m) => m.queued && m.uid.startsWith('temp-')\n );\n const tooRecent = Date.now() - pollingInterval;\n const keptQueued = new Set(\n optimisticQueued\n .filter((m) => (m.queuedAt ?? 0) > tooRecent)\n .map((m) => m.uid)\n );\n let unitemised =\n (data.queuedMessages ?? queued.length) - queued.length - keptQueued.size;\n for (let i = optimisticQueued.length - 1; i >= 0 && unitemised > 0; i--) {\n if (keptQueued.has(optimisticQueued[i].uid)) continue;\n keptQueued.add(optimisticQueued[i].uid);\n unitemised -= 1;\n }\n\n const mergedUIDs = new Set(\n [...merged, ...queued].map((m) => m.uid)\n );\n const optimistic = prev.filter(\n (m) =>\n !mergedUIDs.has(m.uid) &&\n !adoptedTempUids.has(m.uid) &&\n (!m.queued || keptQueued.has(m.uid))\n );\n\n return [...merged, ...queued, ...optimistic];\n });\n setQueuedCount(data.queuedMessages ?? 0);\n // Surface recall events while the run is still processing, so the\n // \"recalled memories\" strip shows before the first response lands.\n mergeRecalledMemories(data.recalledMemories);\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 holdOpen: (data) => {\n // Only `completed` is worth waiting on. An error, a usage limit or a\n // gate mean something else is going on, and holding the poll open would\n // just be watching a conversation that is not coming back.\n const owed =\n (data.queuedMessages ?? 0) > 0 ||\n awaitingAnswerSinceRef.current !== null;\n if (!owed || data.status !== 'completed') {\n queueGraceTicksRef.current = 0;\n return false;\n }\n queueGraceTicksRef.current += 1;\n if (queueGraceTicksRef.current <= QUEUE_HANDOVER_GRACE_TICKS) return true;\n // Nothing came back in time: stop pretending it will.\n logRef.current.warn(\n '[useDevicChat] queue handover window expired, stopping the watch'\n );\n awaitingAnswerSinceRef.current = null;\n return false;\n },\n onStop: (data) => {\n logRef.current.log('[useDevicChat] onStop called, status:', data?.status);\n setShouldPoll(false);\n queueGraceTicksRef.current = 0;\n\n if (data?.status === 'limit_exceeded') {\n // The message was blocked by a tenant/subtenant usage limit before\n // reaching the LLM. Surface the details so the UI can show a banner.\n setIsLoading(false);\n const details: TenantLimitExceeded = data.limitExceeded || {\n message: 'Usage limit reached.',\n };\n setLimitExceeded(details);\n const err = new Error(\n details.message || 'Usage limit reached.'\n ) as Error & { errorType?: string; details?: TenantLimitExceeded };\n err.errorType = 'TENANT_LIMIT_EXCEEDED';\n err.details = details;\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'error') {\n setIsLoading(false);\n const err = new Error('Chat processing failed');\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'completed') {\n setIsLoading(false);\n } else if (data?.status === 'handed_off') {\n // Subagent is working — keep isLoading true so the UI stays in loading state.\n // Set handoff state directly from the realtime status.\n setHandedOff(true);\n\n const subThreadId = data.handedOffSubThreadId || null;\n logRef.current.log('[useDevicChat] Handoff state set:', { handedOff: true, subThreadId });\n if (subThreadId) {\n setHandedOffSubThreadId(subThreadId);\n }\n }\n // Note: waiting_for_tool_response is handled in onUpdate to avoid double execution\n },\n onError: (err) => {\n logRef.current.error('[useDevicChat] onError called:', err);\n setError(err);\n setIsLoading(false);\n setShouldPoll(false);\n onErrorRef.current?.(err);\n },\n debug,\n }\n );\n\n // Handle pending tool calls from model interface\n const handlePendingToolCalls = useCallback(\n async (data: RealtimeChatHistory) => {\n if (!clientRef.current || !chatUid) return;\n\n // Get pending tool calls\n const pendingCalls = data.pendingToolCalls || extractPendingToolCalls(data.chatHistory);\n\n if (pendingCalls.length === 0) return;\n\n try {\n // Execute client-side tools (partitioned into immediate responses and widget-driven)\n const { responses, widgetCalls } = await handleToolCalls(pendingCalls);\n\n // Queue widget-driven tool calls for user interaction\n if (widgetCalls.length > 0) {\n const existingIds = new Set(pendingWidgetCallsRef.current.map((c) => c.toolCall.id));\n const deduped = widgetCalls.filter((c) => !existingIds.has(c.toolCall.id));\n const next = [...pendingWidgetCallsRef.current, ...deduped];\n pendingWidgetCallsRef.current = next;\n setPendingWidgetCalls(next);\n // Stop polling while we wait for the user to submit the widget response.\n // The widget submission will re-trigger polling via submitWidgetResponse.\n setShouldPoll(false);\n setIsLoading(false);\n }\n\n if (responses.length > 0) {\n // Send tool responses back to the API, restating the tools so the\n // continuation keeps them on offer\n await clientRef.current.sendToolResponses(\n assistantId,\n chatUid,\n responses,\n toolSchemas\n );\n\n // Only resume polling if no widgets are blocking\n if (widgetCalls.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [chatUid, assistantId, handleToolCalls, extractPendingToolCalls, toolSchemas]\n );\n\n // Send a message\n const sendMessage = useCallback(\n async (\n message: string,\n sendOptions?: {\n files?: File[];\n metadata?: Record<string, any>;\n transcriptId?: string;\n tags?: string[];\n disabledIntegrations?: string[];\n }\n ): Promise<SendMessageResult> => {\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 { rejected: true, reason: 'error', message: err.message, restoredText: message };\n }\n\n // Whether something was already running when this was written. If it was,\n // this send must not restate it: turning the indicator on and off around a\n // message that merely joined a queue would report on a run it has nothing\n // to do with — and a refusal would then stop an indicator for a run that\n // is still perfectly alive.\n const wasBusy = isLoadingRef.current;\n\n if (!wasBusy) {\n setIsLoading(true);\n setStatus('processing');\n }\n setError(null);\n setLimitExceeded(null);\n\n // Add user message optimistically (show file names before upload)\n const userMessage: ChatMessage = {\n uid: `temp-${Date.now()}-${optimisticSeqRef.current++}`,\n role: 'user',\n content: {\n message,\n files: sendOptions?.files?.map((f) => ({\n name: f.name,\n url: '',\n type: f.type.split('/')[0] || 'other',\n })),\n },\n timestamp: Date.now(),\n ...(sendOptions?.transcriptId && {\n transcriptId: sendOptions.transcriptId,\n }),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n try {\n // Upload files if provided\n let uploadedFiles: ChatFile[] | undefined;\n if (sendOptions?.files && sendOptions.files.length > 0) {\n logRef.current.log('[useDevicChat] Uploading files...');\n if (onFileUpload) {\n // Use custom upload handler\n uploadedFiles = await onFileUpload(sendOptions.files);\n } else {\n // Default: upload via Devic API\n const uploadResults = await Promise.all(\n sendOptions.files.map((file) => clientRef.current!.uploadFile(file))\n );\n uploadedFiles = uploadResults.map((r) => ({\n name: r.name,\n downloadUrl: r.downloadUrl,\n fileType: r.fileType as ChatFile['fileType'],\n }));\n }\n logRef.current.log('[useDevicChat] Files uploaded:', uploadedFiles);\n\n // Update optimistic message with download URLs\n setMessages((prev) =>\n prev.map((m) =>\n m.uid === userMessage.uid\n ? {\n ...m,\n content: {\n ...m.content,\n files: uploadedFiles!.map((f) => ({\n name: f.name,\n url: f.downloadUrl || '',\n type: f.fileType || 'other',\n })),\n },\n }\n : m\n )\n );\n }\n\n // Build request DTO\n const hasSubtenantMetadata =\n resolvedSubtenantMetadata &&\n Object.keys(resolvedSubtenantMetadata).length > 0;\n const dto = {\n message,\n chatUid: chatUid || undefined,\n files: uploadedFiles,\n metadata: {\n ...resolvedTenantMetadata,\n ...(hasSubtenantMetadata && {\n subtenantMetadata: resolvedSubtenantMetadata,\n }),\n ...sendOptions?.metadata,\n },\n tenantId: resolvedTenantId,\n ...(resolvedSubtenantId && { subtenantId: resolvedSubtenantId }),\n // Conversation tags: provider + hook + per-message, deduped\n ...(() => {\n const merged = Array.from(\n new Set([...resolvedTags, ...(sendOptions?.tags ?? [])])\n );\n return merged.length > 0 ? { tags: merged } : {};\n })(),\n enabledTools,\n // The end user's own apps that sit this message out. Sent only when\n // some are switched off: an older API ignores the field, and there is\n // no reason to put an empty array in every request.\n ...(() => {\n const off = sendOptions?.disabledIntegrations ?? disabledIntegrations;\n return off?.length ? { disabledIntegrations: off } : {};\n })(),\n // Include model interface tools if any\n ...(toolSchemas.length > 0 && { tools: toolSchemas }),\n // Link to the speech-to-text transcript that seeded this message, if any\n ...(sendOptions?.transcriptId && { transcriptId: sendOptions.transcriptId }),\n };\n\n // Send message in async mode\n logRef.current.log('[useDevicChat] Sending message async...');\n const response = await clientRef.current.sendMessageAsync(assistantId, dto);\n logRef.current.log('[useDevicChat] sendMessageAsync response:', response);\n\n // Update chat UID if this is a new chat\n if (response.chatUid && response.chatUid !== chatUid) {\n logRef.current.log('[useDevicChat] Setting chatUid:', response.chatUid);\n setChatUid(response.chatUid);\n onChatCreatedRef.current?.(response.chatUid);\n }\n\n // Start polling for results\n logRef.current.log('[useDevicChat] Setting shouldPoll to true');\n setShouldPoll(true);\n\n if (response.queued) {\n // Accepted, but not on its way to the model yet. Draw it as such, and\n // remember it: the poll has to keep running until it comes back inside\n // the conversation, however long the run in flight takes.\n rememberAwaiting();\n const queuedAt = Date.now();\n setMessages((prev) =>\n prev.map((m) =>\n m.uid === userMessage.uid ? { ...m, queued: true, queuedAt } : m\n )\n );\n setQueuedCount(response.queuePosition || 1);\n return {\n queued: true,\n queuePosition: response.queuePosition || 1,\n willProcess: response.willProcess || 'next_turn',\n };\n }\n\n return { queued: false };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n // Nothing was accepted either way, so the bubble goes.\n setMessages((prev) => prev.filter((m) => m.uid !== userMessage.uid));\n\n // The conversation turning a message down is not the conversation\n // breaking. Two shapes of the same 409: an assistant that does not queue\n // says so by name, and a full queue comes back as a plain conflict.\n const refusal =\n err instanceof DevicApiError\n ? err.errorType === 'CHAT_BUSY'\n ? 'chat_busy'\n : err.statusCode === 409\n ? 'queue_full'\n : null\n : null;\n\n if (refusal) {\n logRef.current.log('[useDevicChat] send refused:', refusal, error.message);\n // Deliberately leaves `isLoading`, `status` and `error` alone: the run\n // this message was written into is still going, and reporting the\n // refusal by stopping its indicator — or by painting the conversation\n // as failed — would be a lie about the run, not about the send.\n if (!wasBusy) {\n setIsLoading(false);\n setStatus('idle');\n }\n return {\n rejected: true,\n reason: refusal,\n message: error.message,\n restoredText: message,\n };\n }\n\n // A synchronous usage-limit block surfaces as HTTP 429 /\n // TENANT_LIMIT_EXCEEDED (sync send path). Async sends surface it via the\n // realtime `limit_exceeded` status instead — both are handled.\n if (\n err instanceof DevicApiError &&\n (err.statusCode === 429 || err.errorType === 'TENANT_LIMIT_EXCEEDED')\n ) {\n const details: TenantLimitExceeded =\n (err.details as TenantLimitExceeded) || { message: err.message };\n if (!details.message) details.message = err.message;\n setLimitExceeded(details);\n }\n\n setError(error);\n // Same reasoning as the refusal above: a send that failed while a run\n // was already going says nothing about that run, which the poll is still\n // watching. The error is reported either way.\n if (!wasBusy) {\n setIsLoading(false);\n setStatus('error');\n }\n onErrorRef.current?.(error);\n\n return {\n rejected: true,\n reason: 'error',\n message: error.message,\n restoredText: message,\n };\n }\n },\n [\n chatUid,\n assistantId,\n enabledTools,\n // Without this, the callback keeps the list from the render that created\n // it: switching an app off would not take effect until something else\n // happened to rebuild it.\n disabledIntegrations,\n resolvedTenantId,\n resolvedTenantMetadata,\n resolvedSubtenantId,\n resolvedSubtenantMetadata,\n resolvedTags,\n toolSchemas,\n onMessageSent,\n onFileUpload,\n rememberAwaiting,\n ]\n );\n\n // Clear chat\n const clearChat = useCallback(() => {\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n setMessages([]);\n setChatUid(null);\n setIsLoading(false);\n setStatus('idle');\n setError(null);\n setLimitExceeded(null);\n setRecalledMemories([]);\n resetQueueState();\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n }, [resetQueueState]);\n\n // Load existing chat\n const loadChat = useCallback(\n async (loadChatUid: string) => {\n if (!clientRef.current) {\n const err = new Error('API client not configured');\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n // Reset any active polling/handoff state from previous conversation\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n\n setIsLoading(true);\n setError(null);\n setRecalledMemories([]);\n // The queue belongs to the conversation being left behind.\n resetQueueState();\n\n try {\n const history = await clientRef.current.getChatHistory(\n assistantId,\n loadChatUid,\n { tenantId: resolvedTenantId }\n );\n\n setMessages(history.chatContent);\n mergeRecalledMemories(history.recalledMemories);\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 [\n assistantId,\n resolvedTenantId,\n resumeFromRealtimeStatus,\n mergeRecalledMemories,\n resetQueueState,\n ]\n );\n\n // Handoff polling: while handedOff is true, poll the realtime endpoint every\n // 5s (or the configured cadence) to detect when the parent thread is no\n // 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, handoffPollingInterval);\n return () => {\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n };\n }, [handedOff, chatUid, assistantId, handoffPollingInterval]);\n\n // Called by HandoffSubagentWidget when the subthread reaches a terminal state\n const onHandoffCompleted = useCallback(() => {\n logRef.current.log('[useDevicChat] onHandoffCompleted called');\n // Clear the handoff polling\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n // Clear handoff state and resume main polling\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n setShouldPoll(true);\n }, []);\n\n // Submit a response for a pending widget tool call\n const submitWidgetResponse = useCallback(\n async (toolCallId: string, response: any) => {\n const uid = chatUidRef.current;\n if (!clientRef.current || !uid) return;\n\n // Check pending widgets via ref (state updates are async)\n const current = pendingWidgetCallsRef.current;\n const found = current.some((c) => c.toolCall.id === toolCallId);\n if (!found) return;\n\n // Remove the widget call from pending list\n const remaining = current.filter((c) => c.toolCall.id !== toolCallId);\n pendingWidgetCallsRef.current = remaining;\n setPendingWidgetCalls(remaining);\n\n try {\n logRef.current.log('[useDevicChat] sending widget tool response', toolCallId);\n await clientRef.current.sendToolResponses(\n assistantId,\n uid,\n [{ tool_call_id: toolCallId, content: response, role: 'tool' }],\n toolSchemas\n );\n // Resume polling only if no more widget calls are blocking\n if (remaining.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logRef.current.error('[useDevicChat] submitWidgetResponse failed', error);\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [assistantId, toolSchemas]\n );\n\n // Cancel a pending widget tool call (sends an error response to the model)\n const cancelWidgetCall = useCallback(\n async (toolCallId: string, reason?: string) => {\n await submitWidgetResponse(toolCallId, {\n error: reason || 'User cancelled the tool call',\n });\n },\n [submitWidgetResponse]\n );\n\n // Stop current conversation — calls the server-side stop endpoint\n // then stops polling and resets loading state.\n const stopChat = useCallback(async (): Promise<StopResult> => {\n const uid = chatUidRef.current;\n logRef.current.log('[useDevicChat] stopChat called, chatUid:', uid);\n let discarded: ChatMessage[] = [];\n if (clientRef.current && uid) {\n try {\n const result = await clientRef.current.stopChat(assistantId, uid);\n discarded = result?.discardedMessages ?? [];\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\n // Stopping throws away whatever was queued behind the run — answering it\n // would be the opposite of what was just asked for. The bubbles go with it,\n // and the text is handed back so it can return to the box instead of\n // disappearing. An API that does not report what it discarded leaves the\n // bubbles alone, and the next poll has the last word.\n if (discarded.length) {\n setMessages((prev) => prev.filter((m) => !m.queued));\n }\n resetQueueState();\n\n setShouldPoll(false);\n setIsLoading(false);\n setStatus('idle');\n\n const restoredText = discarded\n .map((m) => m.content?.message)\n .filter(Boolean)\n .join('\\n');\n\n return {\n discarded: discarded.length,\n ...(restoredText ? { restoredText } : {}),\n };\n }, [assistantId, resetQueueState]);\n\n return {\n messages,\n chatUid,\n isLoading,\n status,\n error,\n limitExceeded,\n recalledMemories,\n handedOff,\n handedOffSubThreadId,\n queuedCount,\n queueEnabled,\n sendMessage,\n clearChat,\n loadChat,\n onHandoffCompleted,\n stopChat,\n pendingWidgetCalls,\n submitWidgetResponse,\n cancelWidgetCall,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
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 type { TenantMetadata, SubtenantMetadata } from '../provider';\nimport { DevicApiClient, DevicApiError } from '../api/client';\nimport { usePolling, resolvePollingInterval } from './usePolling';\nimport { useModelInterface, type PendingWidgetCall } from './useModelInterface';\nimport { createLogger } from '../utils/logger';\nimport { useAssistantInfo } from '../api/assistantInfo';\nimport type {\n ChatMessage,\n ChatFile,\n CompactionActivity,\n CompactionCheckpoint,\n ModelInterfaceTool,\n QueueDisposition,\n RealtimeChatHistory,\n RealtimeStatus,\n RecalledMemoryRecord,\n TenantLimitExceeded,\n} from '../api/types';\n\n/**\n * Cadence for the handoff watch, which only waits for the parent thread to\n * leave `handed_off` and so does not need the main conversation's rhythm.\n * A configured `pollingInterval` still wins over it.\n */\nconst DEFAULT_HANDOFF_POLL_INTERVAL_MS = 5000;\n\n/**\n * How many polls the conversation may read as finished while it still owes an\n * answer to something queued, before the wait is given up.\n *\n * The window is real: a run liquidates, and the follow-up run that drains the\n * queue has not marked itself as processing yet. Bounded so a message that\n * never comes back cannot poll forever.\n */\nconst QUEUE_HANDOVER_GRACE_TICKS = 60;\n\n/** Messages are matched to their optimistic copies by text, so it is normalized. */\nconst normalizeText = (text?: string): string => (text ?? '').trim();\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 (e.g. { name, email, imageUrl })\n */\n tenantMetadata?: TenantMetadata;\n\n /**\n * Subtenant ID identifying a user/entity inside the tenant\n */\n subtenantId?: string;\n\n /**\n * Subtenant metadata (e.g. { id, name, email, imageUrl })\n */\n subtenantMetadata?: SubtenantMetadata;\n\n /**\n * Tags applied to the conversation. Sent as the top-level `tags` of each\n * message (distinct from metadata). Falls back to the DevicProvider's `tags`\n * and is merged (deduped) with any per-message tags passed to `sendMessage`.\n */\n tags?: string[];\n\n /**\n * Tools enabled from the assistant's configured tool groups\n */\n enabledTools?: string[];\n\n /**\n * Apps the end user connected that should sit out the messages sent from\n * here, by slug (`[\"gmail\"]`).\n *\n * A deny list over their own connected apps, not over the assistant's tools:\n * what is not named stays available. Sent with every message while it is set,\n * so it lasts as long as the caller keeps it set — the server keeps nothing\n * and the account is never disconnected.\n */\n disabledIntegrations?: string[];\n\n /**\n * Client-side tools for model interface protocol\n */\n modelInterfaceTools?: ModelInterfaceTool[];\n\n /**\n * How often (ms) the conversation in progress is polled for new content.\n * Overrides the DevicProvider's `pollingInterval`. Values below 250 ms are\n * clamped.\n * @default 1000\n */\n pollingInterval?: number;\n\n /**\n * Callback when a message is sent\n */\n onMessageSent?: (message: ChatMessage) => void;\n\n /**\n * Callback when a message is received\n */\n onMessageReceived?: (message: ChatMessage) => void;\n\n /**\n * Callback when a tool is called\n */\n onToolCall?: (toolName: string, params: any) => void;\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Callback when a new chat is created\n */\n onChatCreated?: (chatUid: string) => void;\n\n /**\n * Custom file upload handler. When provided, replaces the default\n * upload to Devic API. Receives the raw File objects and must return\n * an array of ChatFile with downloadUrl set.\n */\n onFileUpload?: (files: File[]) => Promise<ChatFile[]>;\n\n /**\n * Whether this assistant takes messages while the conversation is busy.\n *\n * Left unset it is resolved from the assistant itself (`messageQueueEnabled`),\n * through the shared per-assistant lookup — one request, shared with the\n * avatar and the connected-apps control, whichever asks first. Pass a boolean\n * to skip the lookup entirely or to override what it says.\n *\n * With it off the input closes while the assistant answers, as it always has.\n * With it on, a message written mid-answer is accepted and joins the\n * assistant's next turn.\n */\n messageQueue?: boolean;\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\n/**\n * What became of a send.\n *\n * `queued` is an acceptance, not a failure: the message is on the conversation\n * and will be answered later. `rejected` is the opposite — nothing was\n * accepted, and the caller still holds the only copy of what the user wrote.\n */\nexport type SendMessageResult =\n | { queued: true; queuePosition: number; willProcess: QueueDisposition }\n | { queued: false }\n | {\n rejected: true;\n /**\n * `chat_busy`: this assistant does not queue and is working.\n * `queue_full`: it does, and the queue is at its configured ceiling.\n * `error`: anything else, already reported through `error`/`onError`.\n */\n reason: 'chat_busy' | 'queue_full' | 'error';\n message: string;\n /** What the user wrote, so it can be restored. */\n restoredText: string;\n };\n\nexport interface StopResult {\n /** Text of the queued messages the stop threw away, joined by newlines. */\n restoredText?: string;\n /** How many were discarded. */\n discarded: number;\n}\n\nexport interface UseDevicChatResult {\n /**\n * Current chat messages\n */\n messages: ChatMessage[];\n\n /**\n * Current chat UID\n */\n chatUid: string | null;\n\n /**\n * Whether a message is being processed\n */\n isLoading: boolean;\n\n /**\n * Current status\n */\n status: RealtimeStatus | 'idle';\n\n /**\n * Last error\n */\n error: Error | null;\n\n /**\n * Set when the last message was blocked by a tenant/subtenant usage limit\n * (HTTP 429 / realtime status `limit_exceeded`). Carries the blocking rule,\n * current vs. limit and when the window resets. `null` while not limited.\n * Cleared when a new message is sent or the chat is cleared.\n */\n limitExceeded: TenantLimitExceeded | null;\n\n /**\n * Structured long-term-memory recall events of the conversation, streamed\n * in while the assistant is still processing (via the realtime poll) and\n * hydrated from the persisted history on load. Empty for assistants\n * without memory.\n */\n recalledMemories: RecalledMemoryRecord[];\n\n /**\n * Compaction checkpoints of the conversation, oldest first. Each one folds\n * the messages before its boundary into a summary the model reads instead\n * of them; the messages themselves stay in `messages`.\n */\n compactions: CompactionCheckpoint[];\n\n /**\n * The compaction being written right now, or null. A compaction is a model\n * call of its own between two assistant messages, so this is what tells a\n * UI why the conversation has gone quiet.\n */\n compaction: CompactionActivity | null;\n\n /**\n * Whether the assistant has handed off to a subagent\n */\n handedOff: boolean;\n\n /**\n * The subthread ID when a handoff is active\n */\n handedOffSubThreadId: string | null;\n\n /**\n * Send a message\n */\n sendMessage: (\n message: string,\n options?: {\n files?: File[];\n metadata?: Record<string, any>;\n /** Id of a speech-to-text transcript that seeded this message. */\n transcriptId?: string;\n /** Per-message tags, merged (deduped) with the resolved conversation tags. */\n tags?: string[];\n /**\n * Connected apps to leave out of this one message, by slug. Replaces the\n * hook's own `disabledIntegrations` rather than adding to it, so a caller\n * can send one message with everything on by passing `[]`.\n */\n disabledIntegrations?: string[];\n }\n ) => Promise<SendMessageResult>;\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 * How many messages this conversation has accepted but not yet shown to the\n * model. Includes anything queued through another channel, so it is the\n * conversation's queue and not this client's.\n */\n queuedCount: number;\n\n /**\n * Whether this assistant takes messages while it is busy — resolved from the\n * assistant, or from the `messageQueue` option when given. False until the\n * lookup settles: an input that opens and then closes is worse than one that\n * opens a beat late.\n */\n queueEnabled: boolean;\n\n /**\n * Stop the current conversation processing.\n *\n * Returns the text of anything the stop discarded, so the caller can put it\n * back where the user wrote it — a stop should not be the way someone's\n * typing disappears.\n */\n stopChat: () => Promise<StopResult>;\n\n /**\n * Pending tool calls that require user interaction via a response widget\n */\n pendingWidgetCalls: PendingWidgetCall[];\n\n /**\n * Submit a response for a pending widget tool call.\n * Sends the response to the API and resumes the conversation.\n */\n submitWidgetResponse: (toolCallId: string, response: any) => Promise<void>;\n\n /**\n * Cancel a pending widget tool call.\n * Sends an error response so the model can continue.\n */\n cancelWidgetCall: (toolCallId: string, reason?: string) => Promise<void>;\n}\n\n/**\n * Main hook for managing chat with a Devic assistant\n *\n * @example\n * ```tsx\n * const {\n * messages,\n * isLoading,\n * sendMessage,\n * } = useDevicChat({\n * assistantId: 'my-assistant',\n * modelInterfaceTools: [\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ],\n * onMessageReceived: (msg) => console.log('Received:', msg),\n * });\n * ```\n */\nexport function useDevicChat(options: UseDevicChatOptions): UseDevicChatResult {\n const {\n assistantId,\n chatUid: initialChatUid,\n apiKey: propsApiKey,\n baseUrl: propsBaseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n enabledTools,\n disabledIntegrations,\n modelInterfaceTools = [],\n pollingInterval: propsPollingInterval,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onFileUpload,\n messageQueue,\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 getTenantSession = context?.getTenantSession;\n const onSessionExpired = context?.onSessionExpired;\n const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n const resolvedSubtenantMetadata = {\n ...context?.subtenantMetadata,\n ...subtenantMetadata,\n };\n // Provider tags + hook tags, deduped. Per-message tags are merged at send time.\n const resolvedTags = useMemo(\n () => Array.from(new Set([...(context?.tags ?? []), ...(tags ?? [])])),\n [context?.tags, tags]\n );\n const pollingInterval = resolvePollingInterval(\n propsPollingInterval,\n context?.pollingInterval\n );\n const handoffPollingInterval = resolvePollingInterval(\n propsPollingInterval,\n context?.pollingInterval,\n DEFAULT_HANDOFF_POLL_INTERVAL_MS\n );\n const debug = propsDebug ?? context?.debug ?? false;\n const log = useMemo(() => createLogger(debug), [debug]);\n const logRef = useRef(log);\n logRef.current = log;\n\n // State\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [chatUid, setChatUid] = useState<string | null>(initialChatUid || null);\n const [isLoading, setIsLoading] = useState(false);\n const [status, setStatus] = useState<RealtimeStatus | 'idle'>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [limitExceeded, setLimitExceeded] = useState<TenantLimitExceeded | null>(\n null\n );\n\n // Long-term-memory recall events of the conversation. The realtime blob\n // only carries the in-flight run's records, so incoming batches merge (by\n // uid) instead of replacing — earlier runs' recalls stay visible.\n const [recalledMemories, setRecalledMemories] = useState<RecalledMemoryRecord[]>([]);\n const mergeRecalledMemories = useCallback(\n (incoming?: RecalledMemoryRecord[]) => {\n if (!incoming?.length) return;\n setRecalledMemories((prev) => {\n const known = new Set(prev.map((r) => r.uid));\n const fresh = incoming.filter((r) => !known.has(r.uid));\n return fresh.length ? [...prev, ...fresh] : prev;\n });\n },\n []\n );\n\n // Compaction checkpoints of the conversation, and the one being written\n // right now. Same merge rule as the recalls: the realtime blob only carries\n // the in-flight run's checkpoints, so incoming batches merge by uid.\n const [compactions, setCompactions] = useState<CompactionCheckpoint[]>([]);\n const mergeCompactions = useCallback((incoming?: CompactionCheckpoint[]) => {\n if (!incoming?.length) return;\n setCompactions((prev) => {\n const known = new Set(prev.map((c) => c.uid));\n const fresh = incoming.filter((c) => !known.has(c.uid));\n return fresh.length ? [...prev, ...fresh] : prev;\n });\n }, []);\n // Absent on every ordinary realtime write, which is how a finished\n // compaction stops being reported.\n const [compaction, setCompaction] = useState<CompactionActivity | 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 // Read by `sendMessage`, which must not restate the state of a run already in\n // flight — its own callback identity would otherwise carry a stale value.\n const isLoadingRef = useRef(isLoading);\n isLoadingRef.current = isLoading;\n\n // Two messages sent inside the same millisecond would otherwise share a uid,\n // which the queue makes easy to do.\n const optimisticSeqRef = useRef(0);\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 || getTenantSession)) {\n clientRef.current = new DevicApiClient({ apiKey, baseUrl, getTenantSession, onSessionExpired });\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 // --- Message queue --------------------------------------------------------\n\n /**\n * Messages accepted by this conversation that the model has not seen yet.\n * Taken from the poll, so it counts whatever else queued on the conversation\n * too — another tab, or the same person writing from another channel.\n */\n const [queuedCount, setQueuedCount] = useState(0);\n\n /**\n * When something was queued from here that has not been answered yet.\n *\n * Deliberately not a list of the texts sent: a drain can merge several queued\n * messages into a single user turn, so what comes back is not what went out\n * and matching them by text would wait forever. What is being waited for is an\n * answer, and an assistant message written after the message was accepted is\n * that answer.\n */\n const awaitingAnswerSinceRef = useRef<number | null>(null);\n const queueGraceTicksRef = useRef(0);\n\n const rememberAwaiting = useCallback(() => {\n awaitingAnswerSinceRef.current = Date.now();\n }, []);\n\n const resetQueueState = useCallback(() => {\n awaitingAnswerSinceRef.current = null;\n queueGraceTicksRef.current = 0;\n setQueuedCount(0);\n }, []);\n\n /**\n * Asked for as soon as the hook is alive, rather than when the first run\n * starts: the answer decides whether the input stays open while the assistant\n * works, and resolving it late means the box visibly closes and reopens on the\n * first message of every session. One request, shared with everything else\n * that asks about this assistant. Passing `messageQueue` skips it entirely.\n */\n const queueLookup = useAssistantInfo({\n assistantId,\n client: clientRef.current,\n baseUrl,\n credential: apiKey || 'session',\n enabled: messageQueue === undefined,\n });\n\n /**\n * Absent means no. An assistant that has not answered yet, or an API too old\n * to carry the field, leaves the input closed while it works — the same thing\n * it did before this existed. Opening it on a maybe would promise a queue the\n * conversation then refuses.\n */\n const queueEnabled =\n messageQueue ??\n (queueLookup.settled &&\n queueLookup.assistant?.messageQueueEnabled === true);\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 const queuedOnServer = (realtime.pendingUserMessages ?? []).map((m) => ({\n ...m,\n queued: true,\n }));\n if (realtime.chatHistory?.length || queuedOnServer.length) {\n setMessages([...(realtime.chatHistory ?? []), ...queuedOnServer]);\n }\n mergeRecalledMemories(realtime.recalledMemories);\n mergeCompactions(realtime.compactions);\n setCompaction(realtime.compaction ?? null);\n setStatus(realtime.status);\n setQueuedCount(realtime.queuedMessages ?? 0);\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 if ((realtime.queuedMessages ?? 0) > 0) {\n // The run settled, but the conversation still owes an answer to\n // something queued — reopened on a conversation whose follow-up run\n // has not started yet. Watch it until the queue is served.\n setIsLoading(true);\n setShouldPoll(true);\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, mergeRecalledMemories, mergeCompactions]\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 mergeRecalledMemories(history.recalledMemories);\n mergeCompactions(history.compactions);\n setChatUid(initialChatUid);\n\n // Check realtime status to resume in-progress conversations\n await resumeFromRealtimeStatus(initialChatUid);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n setIsLoading(false);\n }\n };\n\n loadInitialChat();\n }\n }, [initialChatUid, assistantId, resolvedTenantId, resumeFromRealtimeStatus]);\n\n // Model interface hook\n const {\n toolSchemas,\n handleToolCalls,\n extractPendingToolCalls,\n } = useModelInterface({\n tools: modelInterfaceTools,\n onToolExecute: onToolCall,\n });\n\n // Pending widget calls awaiting user interaction\n const [pendingWidgetCalls, setPendingWidgetCalls] = useState<PendingWidgetCall[]>([]);\n const pendingWidgetCallsRef = useRef<PendingWidgetCall[]>([]);\n useEffect(() => {\n pendingWidgetCallsRef.current = pendingWidgetCalls;\n }, [pendingWidgetCalls]);\n\n // Polling hook - uses callbacks for side effects, return value not needed\n logRef.current.log('[useDevicChat] Render - shouldPoll:', shouldPoll, 'chatUid:', chatUid);\n usePolling(\n shouldPoll ? chatUid : null,\n async () => {\n logRef.current.log('[useDevicChat] fetchFn called, chatUid:', chatUid);\n if (!clientRef.current || !chatUid) {\n throw new Error('Cannot poll without client or chatUid');\n }\n const result = await clientRef.current.getRealtimeHistory(assistantId, chatUid);\n logRef.current.log('[useDevicChat] getRealtimeHistory result:', result);\n return result;\n },\n {\n interval: pollingInterval,\n enabled: shouldPoll,\n stopStatuses: [\n 'completed',\n 'error',\n 'waiting_for_tool_response',\n 'handed_off',\n 'limit_exceeded',\n ],\n onUpdate: async (data: RealtimeChatHistory) => {\n logRef.current.log('[useDevicChat] onUpdate called, status:', data.status);\n\n // An assistant message written after something was queued from here is\n // the answer that was being waited for.\n const awaitingSince = awaitingAnswerSinceRef.current;\n if (\n awaitingSince !== null &&\n (data.queuedMessages ?? 0) === 0 &&\n (data.chatHistory ?? []).some(\n (m) => m.role === 'assistant' && (m.timestamp ?? 0) > awaitingSince\n )\n ) {\n awaitingAnswerSinceRef.current = null;\n }\n\n // Merge realtime data with optimistic messages.\n // When a server user message matches an optimistic one by text, adopt the\n // optimistic uid so React's key stays stable (avoids unmount/remount flicker).\n setMessages((prev) => {\n // A queue of uids per text rather than one: two identical messages are\n // two messages, and pairing both with the same optimistic copy would\n // drop one of them from the conversation.\n const optimisticUserByText = new Map<string, string[]>();\n prev\n .filter((m) => m.role === 'user' && m.uid.startsWith('temp-'))\n .forEach((m) => {\n const key = normalizeText(m.content?.message);\n const bucket = optimisticUserByText.get(key);\n if (bucket) bucket.push(m.uid);\n else optimisticUserByText.set(key, [m.uid]);\n });\n\n const adoptedTempUids = new Set<string>();\n const adopt = (m: ChatMessage): ChatMessage => {\n if (m.role !== 'user') return m;\n const tempUid = optimisticUserByText\n .get(normalizeText(m.content?.message))\n ?.shift();\n if (!tempUid) return m;\n adoptedTempUids.add(tempUid);\n // Keep the server uid around: recall anchors reference it.\n return { ...m, uid: tempUid, serverUid: m.uid };\n };\n\n const merged = data.chatHistory.map(adopt);\n // Accepted, but not part of the conversation yet. Drawn between the\n // history and the optimistic ones, which is where they land once a\n // turn takes them. The copy is the server's, so it survives a reload —\n // where the API does not return them, this is empty and the optimistic\n // ones kept below stand in.\n const queued = (data.pendingUserMessages ?? []).map((m) => ({\n ...adopt(m),\n queued: true,\n }));\n\n // Which of this client's own queued bubbles to keep drawing.\n //\n // Matching them to the history by text does not work: a drain can\n // merge several queued messages into one user turn, and an optimistic\n // copy that never finds its pair would sit there marked as queued for\n // the rest of the conversation. The server's queue is the authority,\n // and these are kept only where it cannot speak for them:\n // - too recently accepted for this poll to have seen them;\n // - counted by `queuedMessages` but not itemised, which is what an\n // API without `pendingUserMessages` reports.\n const optimisticQueued = prev.filter(\n (m) => m.queued && m.uid.startsWith('temp-')\n );\n const tooRecent = Date.now() - pollingInterval;\n const keptQueued = new Set(\n optimisticQueued\n .filter((m) => (m.queuedAt ?? 0) > tooRecent)\n .map((m) => m.uid)\n );\n let unitemised =\n (data.queuedMessages ?? queued.length) - queued.length - keptQueued.size;\n for (let i = optimisticQueued.length - 1; i >= 0 && unitemised > 0; i--) {\n if (keptQueued.has(optimisticQueued[i].uid)) continue;\n keptQueued.add(optimisticQueued[i].uid);\n unitemised -= 1;\n }\n\n const mergedUIDs = new Set(\n [...merged, ...queued].map((m) => m.uid)\n );\n const optimistic = prev.filter(\n (m) =>\n !mergedUIDs.has(m.uid) &&\n !adoptedTempUids.has(m.uid) &&\n (!m.queued || keptQueued.has(m.uid))\n );\n\n return [...merged, ...queued, ...optimistic];\n });\n setQueuedCount(data.queuedMessages ?? 0);\n // Surface recall events while the run is still processing, so the\n // \"recalled memories\" strip shows before the first response lands.\n mergeRecalledMemories(data.recalledMemories);\n // A compaction runs between two assistant messages: without this the\n // conversation looks stalled while it is being written.\n mergeCompactions(data.compactions);\n setCompaction(data.compaction ?? null);\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 holdOpen: (data) => {\n // Only `completed` is worth waiting on. An error, a usage limit or a\n // gate mean something else is going on, and holding the poll open would\n // just be watching a conversation that is not coming back.\n const owed =\n (data.queuedMessages ?? 0) > 0 ||\n awaitingAnswerSinceRef.current !== null;\n if (!owed || data.status !== 'completed') {\n queueGraceTicksRef.current = 0;\n return false;\n }\n queueGraceTicksRef.current += 1;\n if (queueGraceTicksRef.current <= QUEUE_HANDOVER_GRACE_TICKS) return true;\n // Nothing came back in time: stop pretending it will.\n logRef.current.warn(\n '[useDevicChat] queue handover window expired, stopping the watch'\n );\n awaitingAnswerSinceRef.current = null;\n return false;\n },\n onStop: (data) => {\n logRef.current.log('[useDevicChat] onStop called, status:', data?.status);\n setShouldPoll(false);\n queueGraceTicksRef.current = 0;\n\n if (data?.status === 'limit_exceeded') {\n // The message was blocked by a tenant/subtenant usage limit before\n // reaching the LLM. Surface the details so the UI can show a banner.\n setIsLoading(false);\n const details: TenantLimitExceeded = data.limitExceeded || {\n message: 'Usage limit reached.',\n };\n setLimitExceeded(details);\n const err = new Error(\n details.message || 'Usage limit reached.'\n ) as Error & { errorType?: string; details?: TenantLimitExceeded };\n err.errorType = 'TENANT_LIMIT_EXCEEDED';\n err.details = details;\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'error') {\n setIsLoading(false);\n const err = new Error('Chat processing failed');\n setError(err);\n onErrorRef.current?.(err);\n } else if (data?.status === 'completed') {\n setIsLoading(false);\n } else if (data?.status === 'handed_off') {\n // Subagent is working — keep isLoading true so the UI stays in loading state.\n // Set handoff state directly from the realtime status.\n setHandedOff(true);\n\n const subThreadId = data.handedOffSubThreadId || null;\n logRef.current.log('[useDevicChat] Handoff state set:', { handedOff: true, subThreadId });\n if (subThreadId) {\n setHandedOffSubThreadId(subThreadId);\n }\n }\n // Note: waiting_for_tool_response is handled in onUpdate to avoid double execution\n },\n onError: (err) => {\n logRef.current.error('[useDevicChat] onError called:', err);\n setError(err);\n setIsLoading(false);\n setShouldPoll(false);\n onErrorRef.current?.(err);\n },\n debug,\n }\n );\n\n // Handle pending tool calls from model interface\n const handlePendingToolCalls = useCallback(\n async (data: RealtimeChatHistory) => {\n if (!clientRef.current || !chatUid) return;\n\n // Get pending tool calls\n const pendingCalls = data.pendingToolCalls || extractPendingToolCalls(data.chatHistory);\n\n if (pendingCalls.length === 0) return;\n\n try {\n // Execute client-side tools (partitioned into immediate responses and widget-driven)\n const { responses, widgetCalls } = await handleToolCalls(pendingCalls);\n\n // Queue widget-driven tool calls for user interaction\n if (widgetCalls.length > 0) {\n const existingIds = new Set(pendingWidgetCallsRef.current.map((c) => c.toolCall.id));\n const deduped = widgetCalls.filter((c) => !existingIds.has(c.toolCall.id));\n const next = [...pendingWidgetCallsRef.current, ...deduped];\n pendingWidgetCallsRef.current = next;\n setPendingWidgetCalls(next);\n // Stop polling while we wait for the user to submit the widget response.\n // The widget submission will re-trigger polling via submitWidgetResponse.\n setShouldPoll(false);\n setIsLoading(false);\n }\n\n if (responses.length > 0) {\n // Send tool responses back to the API, restating the tools so the\n // continuation keeps them on offer\n await clientRef.current.sendToolResponses(\n assistantId,\n chatUid,\n responses,\n toolSchemas\n );\n\n // Only resume polling if no widgets are blocking\n if (widgetCalls.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [chatUid, assistantId, handleToolCalls, extractPendingToolCalls, toolSchemas]\n );\n\n // Send a message\n const sendMessage = useCallback(\n async (\n message: string,\n sendOptions?: {\n files?: File[];\n metadata?: Record<string, any>;\n transcriptId?: string;\n tags?: string[];\n disabledIntegrations?: string[];\n }\n ): Promise<SendMessageResult> => {\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 { rejected: true, reason: 'error', message: err.message, restoredText: message };\n }\n\n // Whether something was already running when this was written. If it was,\n // this send must not restate it: turning the indicator on and off around a\n // message that merely joined a queue would report on a run it has nothing\n // to do with — and a refusal would then stop an indicator for a run that\n // is still perfectly alive.\n const wasBusy = isLoadingRef.current;\n\n if (!wasBusy) {\n setIsLoading(true);\n setStatus('processing');\n }\n setError(null);\n setLimitExceeded(null);\n\n // Add user message optimistically (show file names before upload)\n const userMessage: ChatMessage = {\n uid: `temp-${Date.now()}-${optimisticSeqRef.current++}`,\n role: 'user',\n content: {\n message,\n files: sendOptions?.files?.map((f) => ({\n name: f.name,\n url: '',\n type: f.type.split('/')[0] || 'other',\n })),\n },\n timestamp: Date.now(),\n ...(sendOptions?.transcriptId && {\n transcriptId: sendOptions.transcriptId,\n }),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessageSent?.(userMessage);\n\n try {\n // Upload files if provided\n let uploadedFiles: ChatFile[] | undefined;\n if (sendOptions?.files && sendOptions.files.length > 0) {\n logRef.current.log('[useDevicChat] Uploading files...');\n if (onFileUpload) {\n // Use custom upload handler\n uploadedFiles = await onFileUpload(sendOptions.files);\n } else {\n // Default: upload via Devic API\n const uploadResults = await Promise.all(\n sendOptions.files.map((file) => clientRef.current!.uploadFile(file))\n );\n uploadedFiles = uploadResults.map((r) => ({\n name: r.name,\n downloadUrl: r.downloadUrl,\n fileType: r.fileType as ChatFile['fileType'],\n }));\n }\n logRef.current.log('[useDevicChat] Files uploaded:', uploadedFiles);\n\n // Update optimistic message with download URLs\n setMessages((prev) =>\n prev.map((m) =>\n m.uid === userMessage.uid\n ? {\n ...m,\n content: {\n ...m.content,\n files: uploadedFiles!.map((f) => ({\n name: f.name,\n url: f.downloadUrl || '',\n type: f.fileType || 'other',\n })),\n },\n }\n : m\n )\n );\n }\n\n // Build request DTO\n const hasSubtenantMetadata =\n resolvedSubtenantMetadata &&\n Object.keys(resolvedSubtenantMetadata).length > 0;\n const dto = {\n message,\n chatUid: chatUid || undefined,\n files: uploadedFiles,\n metadata: {\n ...resolvedTenantMetadata,\n ...(hasSubtenantMetadata && {\n subtenantMetadata: resolvedSubtenantMetadata,\n }),\n ...sendOptions?.metadata,\n },\n tenantId: resolvedTenantId,\n ...(resolvedSubtenantId && { subtenantId: resolvedSubtenantId }),\n // Conversation tags: provider + hook + per-message, deduped\n ...(() => {\n const merged = Array.from(\n new Set([...resolvedTags, ...(sendOptions?.tags ?? [])])\n );\n return merged.length > 0 ? { tags: merged } : {};\n })(),\n enabledTools,\n // The end user's own apps that sit this message out. Sent only when\n // some are switched off: an older API ignores the field, and there is\n // no reason to put an empty array in every request.\n ...(() => {\n const off = sendOptions?.disabledIntegrations ?? disabledIntegrations;\n return off?.length ? { disabledIntegrations: off } : {};\n })(),\n // Include model interface tools if any\n ...(toolSchemas.length > 0 && { tools: toolSchemas }),\n // Link to the speech-to-text transcript that seeded this message, if any\n ...(sendOptions?.transcriptId && { transcriptId: sendOptions.transcriptId }),\n };\n\n // Send message in async mode\n logRef.current.log('[useDevicChat] Sending message async...');\n const response = await clientRef.current.sendMessageAsync(assistantId, dto);\n logRef.current.log('[useDevicChat] sendMessageAsync response:', response);\n\n // Update chat UID if this is a new chat\n if (response.chatUid && response.chatUid !== chatUid) {\n logRef.current.log('[useDevicChat] Setting chatUid:', response.chatUid);\n setChatUid(response.chatUid);\n onChatCreatedRef.current?.(response.chatUid);\n }\n\n // Start polling for results\n logRef.current.log('[useDevicChat] Setting shouldPoll to true');\n setShouldPoll(true);\n\n if (response.queued) {\n // Accepted, but not on its way to the model yet. Draw it as such, and\n // remember it: the poll has to keep running until it comes back inside\n // the conversation, however long the run in flight takes.\n rememberAwaiting();\n const queuedAt = Date.now();\n setMessages((prev) =>\n prev.map((m) =>\n m.uid === userMessage.uid ? { ...m, queued: true, queuedAt } : m\n )\n );\n setQueuedCount(response.queuePosition || 1);\n return {\n queued: true,\n queuePosition: response.queuePosition || 1,\n willProcess: response.willProcess || 'next_turn',\n };\n }\n\n return { queued: false };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n // Nothing was accepted either way, so the bubble goes.\n setMessages((prev) => prev.filter((m) => m.uid !== userMessage.uid));\n\n // The conversation turning a message down is not the conversation\n // breaking. Two shapes of the same 409: an assistant that does not queue\n // says so by name, and a full queue comes back as a plain conflict.\n const refusal =\n err instanceof DevicApiError\n ? err.errorType === 'CHAT_BUSY'\n ? 'chat_busy'\n : err.statusCode === 409\n ? 'queue_full'\n : null\n : null;\n\n if (refusal) {\n logRef.current.log('[useDevicChat] send refused:', refusal, error.message);\n // Deliberately leaves `isLoading`, `status` and `error` alone: the run\n // this message was written into is still going, and reporting the\n // refusal by stopping its indicator — or by painting the conversation\n // as failed — would be a lie about the run, not about the send.\n if (!wasBusy) {\n setIsLoading(false);\n setStatus('idle');\n }\n return {\n rejected: true,\n reason: refusal,\n message: error.message,\n restoredText: message,\n };\n }\n\n // A synchronous usage-limit block surfaces as HTTP 429 /\n // TENANT_LIMIT_EXCEEDED (sync send path). Async sends surface it via the\n // realtime `limit_exceeded` status instead — both are handled.\n if (\n err instanceof DevicApiError &&\n (err.statusCode === 429 || err.errorType === 'TENANT_LIMIT_EXCEEDED')\n ) {\n const details: TenantLimitExceeded =\n (err.details as TenantLimitExceeded) || { message: err.message };\n if (!details.message) details.message = err.message;\n setLimitExceeded(details);\n }\n\n setError(error);\n // Same reasoning as the refusal above: a send that failed while a run\n // was already going says nothing about that run, which the poll is still\n // watching. The error is reported either way.\n if (!wasBusy) {\n setIsLoading(false);\n setStatus('error');\n }\n onErrorRef.current?.(error);\n\n return {\n rejected: true,\n reason: 'error',\n message: error.message,\n restoredText: message,\n };\n }\n },\n [\n chatUid,\n assistantId,\n enabledTools,\n // Without this, the callback keeps the list from the render that created\n // it: switching an app off would not take effect until something else\n // happened to rebuild it.\n disabledIntegrations,\n resolvedTenantId,\n resolvedTenantMetadata,\n resolvedSubtenantId,\n resolvedSubtenantMetadata,\n resolvedTags,\n toolSchemas,\n onMessageSent,\n onFileUpload,\n rememberAwaiting,\n ]\n );\n\n // Clear chat\n const clearChat = useCallback(() => {\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n setMessages([]);\n setChatUid(null);\n setIsLoading(false);\n setStatus('idle');\n setError(null);\n setLimitExceeded(null);\n setRecalledMemories([]);\n setCompactions([]);\n setCompaction(null);\n resetQueueState();\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n }, [resetQueueState]);\n\n // Load existing chat\n const loadChat = useCallback(\n async (loadChatUid: string) => {\n if (!clientRef.current) {\n const err = new Error('API client not configured');\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n // Reset any active polling/handoff state from previous conversation\n setShouldPoll(false);\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n pendingWidgetCallsRef.current = [];\n setPendingWidgetCalls([]);\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n\n setIsLoading(true);\n setError(null);\n setRecalledMemories([]);\n setCompactions([]);\n setCompaction(null);\n // The queue belongs to the conversation being left behind.\n resetQueueState();\n\n try {\n const history = await clientRef.current.getChatHistory(\n assistantId,\n loadChatUid,\n { tenantId: resolvedTenantId }\n );\n\n setMessages(history.chatContent);\n mergeRecalledMemories(history.recalledMemories);\n mergeCompactions(history.compactions);\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 [\n assistantId,\n resolvedTenantId,\n resumeFromRealtimeStatus,\n mergeRecalledMemories,\n mergeCompactions,\n resetQueueState,\n ]\n );\n\n // Handoff polling: while handedOff is true, poll the realtime endpoint every\n // 5s (or the configured cadence) to detect when the parent thread is no\n // 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, handoffPollingInterval);\n return () => {\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n };\n }, [handedOff, chatUid, assistantId, handoffPollingInterval]);\n\n // Called by HandoffSubagentWidget when the subthread reaches a terminal state\n const onHandoffCompleted = useCallback(() => {\n logRef.current.log('[useDevicChat] onHandoffCompleted called');\n // Clear the handoff polling\n if (handoffPollRef.current) {\n clearInterval(handoffPollRef.current);\n handoffPollRef.current = null;\n }\n // Clear handoff state and resume main polling\n setHandedOff(false);\n setHandedOffSubThreadId(null);\n setShouldPoll(true);\n }, []);\n\n // Submit a response for a pending widget tool call\n const submitWidgetResponse = useCallback(\n async (toolCallId: string, response: any) => {\n const uid = chatUidRef.current;\n if (!clientRef.current || !uid) return;\n\n // Check pending widgets via ref (state updates are async)\n const current = pendingWidgetCallsRef.current;\n const found = current.some((c) => c.toolCall.id === toolCallId);\n if (!found) return;\n\n // Remove the widget call from pending list\n const remaining = current.filter((c) => c.toolCall.id !== toolCallId);\n pendingWidgetCallsRef.current = remaining;\n setPendingWidgetCalls(remaining);\n\n try {\n logRef.current.log('[useDevicChat] sending widget tool response', toolCallId);\n await clientRef.current.sendToolResponses(\n assistantId,\n uid,\n [{ tool_call_id: toolCallId, content: response, role: 'tool' }],\n toolSchemas\n );\n // Resume polling only if no more widget calls are blocking\n if (remaining.length === 0) {\n setShouldPoll(true);\n setIsLoading(true);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logRef.current.error('[useDevicChat] submitWidgetResponse failed', error);\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [assistantId, toolSchemas]\n );\n\n // Cancel a pending widget tool call (sends an error response to the model)\n const cancelWidgetCall = useCallback(\n async (toolCallId: string, reason?: string) => {\n await submitWidgetResponse(toolCallId, {\n error: reason || 'User cancelled the tool call',\n });\n },\n [submitWidgetResponse]\n );\n\n // Stop current conversation — calls the server-side stop endpoint\n // then stops polling and resets loading state.\n const stopChat = useCallback(async (): Promise<StopResult> => {\n const uid = chatUidRef.current;\n logRef.current.log('[useDevicChat] stopChat called, chatUid:', uid);\n let discarded: ChatMessage[] = [];\n if (clientRef.current && uid) {\n try {\n const result = await clientRef.current.stopChat(assistantId, uid);\n discarded = result?.discardedMessages ?? [];\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\n // Stopping throws away whatever was queued behind the run — answering it\n // would be the opposite of what was just asked for. The bubbles go with it,\n // and the text is handed back so it can return to the box instead of\n // disappearing. An API that does not report what it discarded leaves the\n // bubbles alone, and the next poll has the last word.\n if (discarded.length) {\n setMessages((prev) => prev.filter((m) => !m.queued));\n }\n resetQueueState();\n\n setShouldPoll(false);\n setIsLoading(false);\n setStatus('idle');\n\n const restoredText = discarded\n .map((m) => m.content?.message)\n .filter(Boolean)\n .join('\\n');\n\n return {\n discarded: discarded.length,\n ...(restoredText ? { restoredText } : {}),\n };\n }, [assistantId, resetQueueState]);\n\n return {\n messages,\n chatUid,\n isLoading,\n status,\n error,\n limitExceeded,\n recalledMemories,\n compactions,\n compaction,\n handedOff,\n handedOffSubThreadId,\n queuedCount,\n queueEnabled,\n sendMessage,\n clearChat,\n loadChat,\n onHandoffCompleted,\n stopChat,\n pendingWidgetCalls,\n submitWidgetResponse,\n cancelWidgetCall,\n };\n}\n"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { DevicProvider, DevicContext, useDevicContext, useOptionalDevicContext } from './provider';
|
|
2
2
|
export type { DevicProviderConfig, DevicProviderProps, DevicContextValue, TenantMetadata, SubtenantMetadata, AIReference, DrawerRegistration, } from './provider';
|
|
3
|
-
export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector, HandoffSubagentWidget, ReferenceChip, UsageBar, LimitBanner, QueueNotice, RecalledMemoriesWidget } from './components/ChatDrawer';
|
|
4
|
-
export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, MessageBubbleRenderer, MessageBubbleRendererProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, HandoffSubagentWidgetProps, ReferenceChipProps, ReferenceChipVariant, SuggestedMessage, UsageBarProps, UsageBarDisplay, UsageBarData, LimitBannerProps, QueueNoticeProps, RecalledMemoriesWidgetProps, RecalledMemoriesRenderer, RecalledMemoriesRendererProps, } from './components/ChatDrawer';
|
|
3
|
+
export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector, HandoffSubagentWidget, ReferenceChip, UsageBar, LimitBanner, QueueNotice, RecalledMemoriesWidget, CompactionWidget } from './components/ChatDrawer';
|
|
4
|
+
export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, MessageBubbleRenderer, MessageBubbleRendererProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, HandoffSubagentWidgetProps, ReferenceChipProps, ReferenceChipVariant, SuggestedMessage, UsageBarProps, UsageBarDisplay, UsageBarData, LimitBannerProps, QueueNoticeProps, RecalledMemoriesWidgetProps, RecalledMemoriesRenderer, RecalledMemoriesRendererProps, CompactionWidgetProps, CompactionRenderer, CompactionRendererProps, } from './components/ChatDrawer';
|
|
5
5
|
export { CoreMemoryModal, DEFAULT_CORE_MEMORY_LABELS } from './components/CoreMemoryModal';
|
|
6
6
|
export type { CoreMemoryModalProps, CoreMemoryLabels } from './components/CoreMemoryModal';
|
|
7
7
|
export { IntegrationsModal, IntegrationsPanel, IntegrationsLauncher, IntegrationsHint, IntegrationLogo, useIntegrations, McpServersSection, McpConnectForm, useTenantMcp, integrationChoiceKey, readIntegrationChoice, writeIntegrationChoice, pruneIntegrationChoice, } from './components/IntegrationsModal';
|
|
@@ -24,7 +24,7 @@ export type { UseDevicChatOptions, UseDevicChatResult, SendMessageResult, StopRe
|
|
|
24
24
|
export { DevicApiClient, DevicApiError } from './api/client';
|
|
25
25
|
export type { DevicApiClientConfig, TenantSessionToken } from './api/client';
|
|
26
26
|
export { AgentThreadState, } from './api/types';
|
|
27
|
-
export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, QueueDisposition, StopChatResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, ResponseWidgetProps, ResponseWidgetConfig, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentTaskDto, AgentDto, HandOffToolResponse, ToolGroupCall, ToolGroupConfig, WhisperTranscriptionResponse, TenantLimitExceeded, TenantUsage, TenantUsageRule, TenantUsageHistoryRow, TenantUsageHistoryQuery, RecalledMemoryRecord, RecalledMemoryFact, RecalledMemoryEntity, RecalledMemoryTurn, CoreMemorySnapshot, CoreMemoryEntry, CoreMemoryLimits, CoreMemoryList, Integration, IntegrationAccount, IntegrationAuthField, IntegrationAuthScheme, IntegrationSetupRequired, TenantMcpAuthMode, TenantMcpConnection, TenantMcpServer, TenantMcpListing, TenantMcpAuthInput, TenantMcpConnectResult, } from './api/types';
|
|
27
|
+
export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, QueueDisposition, StopChatResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, ResponseWidgetProps, ResponseWidgetConfig, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentTaskDto, AgentDto, HandOffToolResponse, ToolGroupCall, ToolGroupConfig, WhisperTranscriptionResponse, TenantLimitExceeded, TenantUsage, TenantUsageRule, TenantUsageHistoryRow, TenantUsageHistoryQuery, RecalledMemoryRecord, RecalledMemoryFact, RecalledMemoryEntity, RecalledMemoryTurn, CompactionCheckpoint, CompactionSummary, CompactionFact, CompactionActivity, CoreMemorySnapshot, CoreMemoryEntry, CoreMemoryLimits, CoreMemoryList, Integration, IntegrationAccount, IntegrationAuthField, IntegrationAuthScheme, IntegrationSetupRequired, TenantMcpAuthMode, TenantMcpConnection, TenantMcpServer, TenantMcpListing, TenantMcpAuthInput, TenantMcpConnectResult, } from './api/types';
|
|
28
28
|
export { MessageActions, FeedbackModal } from './components/Feedback';
|
|
29
29
|
export type { MessageActionsProps, FeedbackModalProps, FeedbackState, FeedbackTheme } from './components/Feedback';
|
|
30
30
|
export { generateId, deepMerge, debounce, throttle, formatFileSize, storage, segmentToolCalls } from './utils';
|
package/dist/esm/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export { UsageBar } from './components/ChatDrawer/UsageBar.js';
|
|
|
11
11
|
export { LimitBanner } from './components/ChatDrawer/LimitBanner.js';
|
|
12
12
|
export { QueueNotice } from './components/ChatDrawer/QueueNotice.js';
|
|
13
13
|
export { RecalledMemoriesWidget } from './components/ChatDrawer/RecalledMemoriesWidget.js';
|
|
14
|
+
export { CompactionWidget } from './components/ChatDrawer/CompactionWidget.js';
|
|
14
15
|
export { CoreMemoryModal, DEFAULT_CORE_MEMORY_LABELS } from './components/CoreMemoryModal/CoreMemoryModal.js';
|
|
15
16
|
export { IntegrationsModal } from './components/IntegrationsModal/IntegrationsModal.js';
|
|
16
17
|
export { IntegrationsPanel } from './components/IntegrationsModal/IntegrationsPanel.js';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|