@devicai/ui 0.1.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 +363 -0
- package/dist/cjs/api/client.js +118 -0
- package/dist/cjs/api/client.js.map +1 -0
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js +122 -0
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -0
- package/dist/cjs/components/ChatDrawer/ChatInput.js +128 -0
- package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -0
- package/dist/cjs/components/ChatDrawer/ChatMessages.js +56 -0
- package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -0
- package/dist/cjs/components/ChatDrawer/ToolTimeline.js +26 -0
- package/dist/cjs/components/ChatDrawer/ToolTimeline.js.map +1 -0
- package/dist/cjs/hooks/useDevicChat.js +258 -0
- package/dist/cjs/hooks/useDevicChat.js.map +1 -0
- package/dist/cjs/hooks/useModelInterface.js +130 -0
- package/dist/cjs/hooks/useModelInterface.js.map +1 -0
- package/dist/cjs/hooks/usePolling.js +109 -0
- package/dist/cjs/hooks/usePolling.js.map +1 -0
- package/dist/cjs/index.js +36 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/provider/DevicContext.js +32 -0
- package/dist/cjs/provider/DevicContext.js.map +1 -0
- package/dist/cjs/provider/DevicProvider.js +43 -0
- package/dist/cjs/provider/DevicProvider.js.map +1 -0
- package/dist/cjs/styles.css +1 -0
- package/dist/cjs/utils/index.js +117 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/esm/api/client.d.ts +56 -0
- package/dist/esm/api/client.js +115 -0
- package/dist/esm/api/client.js.map +1 -0
- package/dist/esm/api/types.d.ts +184 -0
- package/dist/esm/components/ChatDrawer/ChatDrawer.d.ts +27 -0
- package/dist/esm/components/ChatDrawer/ChatDrawer.js +120 -0
- package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -0
- package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +197 -0
- package/dist/esm/components/ChatDrawer/ChatInput.d.ts +5 -0
- package/dist/esm/components/ChatDrawer/ChatInput.js +126 -0
- package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -0
- package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +5 -0
- package/dist/esm/components/ChatDrawer/ChatMessages.js +54 -0
- package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -0
- package/dist/esm/components/ChatDrawer/ToolTimeline.d.ts +5 -0
- package/dist/esm/components/ChatDrawer/ToolTimeline.js +24 -0
- package/dist/esm/components/ChatDrawer/ToolTimeline.js.map +1 -0
- package/dist/esm/components/ChatDrawer/index.d.ts +5 -0
- package/dist/esm/hooks/index.d.ts +6 -0
- package/dist/esm/hooks/useDevicChat.d.ts +120 -0
- package/dist/esm/hooks/useDevicChat.js +256 -0
- package/dist/esm/hooks/useDevicChat.js.map +1 -0
- package/dist/esm/hooks/useModelInterface.d.ts +68 -0
- package/dist/esm/hooks/useModelInterface.js +128 -0
- package/dist/esm/hooks/useModelInterface.js.map +1 -0
- package/dist/esm/hooks/usePolling.d.ts +64 -0
- package/dist/esm/hooks/usePolling.js +107 -0
- package/dist/esm/hooks/usePolling.js.map +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/provider/DevicContext.d.ts +15 -0
- package/dist/esm/provider/DevicContext.js +28 -0
- package/dist/esm/provider/DevicContext.js.map +1 -0
- package/dist/esm/provider/DevicProvider.d.ts +17 -0
- package/dist/esm/provider/DevicProvider.js +41 -0
- package/dist/esm/provider/DevicProvider.js.map +1 -0
- package/dist/esm/provider/index.d.ts +3 -0
- package/dist/esm/provider/types.d.ts +58 -0
- package/dist/esm/styles.css +1 -0
- package/dist/esm/utils/index.d.ts +32 -0
- package/dist/esm/utils/index.js +109 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook for implementing the Model Interface Protocol
|
|
7
|
+
*
|
|
8
|
+
* The Model Interface Protocol allows client-side tools to be executed
|
|
9
|
+
* during an assistant conversation. When the model calls a client-side tool,
|
|
10
|
+
* this hook handles executing the tool and preparing the response.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { toolSchemas, handleToolCalls } = useModelInterface({
|
|
15
|
+
* tools: [
|
|
16
|
+
* {
|
|
17
|
+
* toolName: 'get_user_location',
|
|
18
|
+
* schema: {
|
|
19
|
+
* type: 'function',
|
|
20
|
+
* function: {
|
|
21
|
+
* name: 'get_user_location',
|
|
22
|
+
* description: 'Get user current location',
|
|
23
|
+
* parameters: { type: 'object', properties: {} }
|
|
24
|
+
* }
|
|
25
|
+
* },
|
|
26
|
+
* callback: async () => {
|
|
27
|
+
* const pos = await getCurrentPosition();
|
|
28
|
+
* return { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ]
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function useModelInterface(options) {
|
|
36
|
+
const { tools, onToolExecute, onToolComplete, onToolError } = options;
|
|
37
|
+
// Extract tool schemas for API
|
|
38
|
+
const toolSchemas = react.useMemo(() => {
|
|
39
|
+
return tools.map((tool) => tool.schema);
|
|
40
|
+
}, [tools]);
|
|
41
|
+
// Map of tool name to tool definition
|
|
42
|
+
const toolMap = react.useMemo(() => {
|
|
43
|
+
return new Map(tools.map((tool) => [tool.toolName, tool]));
|
|
44
|
+
}, [tools]);
|
|
45
|
+
// Check if a tool is a client-side tool
|
|
46
|
+
const isClientTool = react.useCallback((toolName) => {
|
|
47
|
+
return toolMap.has(toolName);
|
|
48
|
+
}, [toolMap]);
|
|
49
|
+
// Handle tool calls and execute client-side tools
|
|
50
|
+
const handleToolCalls = react.useCallback(async (toolCalls) => {
|
|
51
|
+
const responses = [];
|
|
52
|
+
for (const toolCall of toolCalls) {
|
|
53
|
+
const toolName = toolCall.function.name;
|
|
54
|
+
const tool = toolMap.get(toolName);
|
|
55
|
+
if (!tool) {
|
|
56
|
+
// Not a client-side tool, skip
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
// Parse arguments
|
|
61
|
+
let params = {};
|
|
62
|
+
try {
|
|
63
|
+
params = JSON.parse(toolCall.function.arguments || '{}');
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Keep empty params if parsing fails
|
|
67
|
+
}
|
|
68
|
+
// Notify about execution
|
|
69
|
+
onToolExecute?.(toolName, params);
|
|
70
|
+
// Execute the tool callback
|
|
71
|
+
const result = await tool.callback(params);
|
|
72
|
+
// Notify about completion
|
|
73
|
+
onToolComplete?.(toolName, result);
|
|
74
|
+
// Add response
|
|
75
|
+
responses.push({
|
|
76
|
+
tool_call_id: toolCall.id,
|
|
77
|
+
content: result,
|
|
78
|
+
role: 'tool',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
83
|
+
// Notify about error
|
|
84
|
+
onToolError?.(toolName, error);
|
|
85
|
+
// Add error response
|
|
86
|
+
responses.push({
|
|
87
|
+
tool_call_id: toolCall.id,
|
|
88
|
+
content: { error: error.message },
|
|
89
|
+
role: 'tool',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return responses;
|
|
94
|
+
}, [toolMap, onToolExecute, onToolComplete, onToolError]);
|
|
95
|
+
// Extract pending tool calls from messages that need client handling
|
|
96
|
+
const extractPendingToolCalls = react.useCallback((messages) => {
|
|
97
|
+
const pendingCalls = [];
|
|
98
|
+
// Look at the last assistant message
|
|
99
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
100
|
+
const message = messages[i];
|
|
101
|
+
if (message.role === 'assistant' && message.tool_calls?.length) {
|
|
102
|
+
// Filter for client-side tools only
|
|
103
|
+
const clientToolCalls = message.tool_calls.filter((tc) => isClientTool(tc.function.name));
|
|
104
|
+
// Check if these tool calls have been responded to
|
|
105
|
+
const respondedToolIds = new Set(messages
|
|
106
|
+
.slice(i + 1)
|
|
107
|
+
.filter((m) => m.role === 'tool')
|
|
108
|
+
.map((m) => m.tool_call_id));
|
|
109
|
+
// Get unresponded tool calls
|
|
110
|
+
for (const tc of clientToolCalls) {
|
|
111
|
+
if (!respondedToolIds.has(tc.id)) {
|
|
112
|
+
pendingCalls.push(tc);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Only check the most recent assistant message with tool calls
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return pendingCalls;
|
|
120
|
+
}, [isClientTool]);
|
|
121
|
+
return {
|
|
122
|
+
toolSchemas,
|
|
123
|
+
isClientTool,
|
|
124
|
+
handleToolCalls,
|
|
125
|
+
extractPendingToolCalls,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
exports.useModelInterface = useModelInterface;
|
|
130
|
+
//# sourceMappingURL=useModelInterface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModelInterface.js","sources":["../../../../src/hooks/useModelInterface.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport type {\n ModelInterfaceTool,\n ModelInterfaceToolSchema,\n ToolCall,\n ToolCallResponse,\n ChatMessage,\n} from '../api/types';\n\nexport interface UseModelInterfaceOptions {\n /**\n * Client-side tools available for model interface protocol\n */\n tools: ModelInterfaceTool[];\n\n /**\n * Callback when a tool is being executed\n */\n onToolExecute?: (toolName: string, params: any) => void;\n\n /**\n * Callback when a tool execution completes\n */\n onToolComplete?: (toolName: string, result: any) => void;\n\n /**\n * Callback when a tool execution fails\n */\n onToolError?: (toolName: string, error: Error) => void;\n}\n\nexport interface UseModelInterfaceResult {\n /**\n * Tool schemas to send to the API\n */\n toolSchemas: ModelInterfaceToolSchema[];\n\n /**\n * Check if a tool call should be handled client-side\n */\n isClientTool: (toolName: string) => boolean;\n\n /**\n * Handle tool calls from the model, returns tool responses\n */\n handleToolCalls: (toolCalls: ToolCall[]) => Promise<ToolCallResponse[]>;\n\n /**\n * Process messages and extract pending tool calls that need client handling\n */\n extractPendingToolCalls: (messages: ChatMessage[]) => ToolCall[];\n}\n\n/**\n * Hook for implementing the Model Interface Protocol\n *\n * The Model Interface Protocol allows client-side tools to be executed\n * during an assistant conversation. When the model calls a client-side tool,\n * this hook handles executing the tool and preparing the response.\n *\n * @example\n * ```tsx\n * const { toolSchemas, handleToolCalls } = useModelInterface({\n * tools: [\n * {\n * toolName: 'get_user_location',\n * schema: {\n * type: 'function',\n * function: {\n * name: 'get_user_location',\n * description: 'Get user current location',\n * parameters: { type: 'object', properties: {} }\n * }\n * },\n * callback: async () => {\n * const pos = await getCurrentPosition();\n * return { lat: pos.coords.latitude, lng: pos.coords.longitude };\n * }\n * }\n * ]\n * });\n * ```\n */\nexport function useModelInterface(\n options: UseModelInterfaceOptions\n): UseModelInterfaceResult {\n const { tools, onToolExecute, onToolComplete, onToolError } = options;\n\n // Extract tool schemas for API\n const toolSchemas = useMemo(() => {\n return tools.map((tool) => tool.schema);\n }, [tools]);\n\n // Map of tool name to tool definition\n const toolMap = useMemo(() => {\n return new Map(tools.map((tool) => [tool.toolName, tool]));\n }, [tools]);\n\n // Check if a tool is a client-side tool\n const isClientTool = useCallback(\n (toolName: string): boolean => {\n return toolMap.has(toolName);\n },\n [toolMap]\n );\n\n // Handle tool calls and execute client-side tools\n const handleToolCalls = useCallback(\n async (toolCalls: ToolCall[]): Promise<ToolCallResponse[]> => {\n const responses: ToolCallResponse[] = [];\n\n for (const toolCall of toolCalls) {\n const toolName = toolCall.function.name;\n const tool = toolMap.get(toolName);\n\n if (!tool) {\n // Not a client-side tool, skip\n continue;\n }\n\n try {\n // Parse arguments\n let params: any = {};\n try {\n params = JSON.parse(toolCall.function.arguments || '{}');\n } catch {\n // Keep empty params if parsing fails\n }\n\n // Notify about execution\n onToolExecute?.(toolName, params);\n\n // Execute the tool callback\n const result = await tool.callback(params);\n\n // Notify about completion\n onToolComplete?.(toolName, result);\n\n // Add response\n responses.push({\n tool_call_id: toolCall.id,\n content: result,\n role: 'tool',\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n // Notify about error\n onToolError?.(toolName, error);\n\n // Add error response\n responses.push({\n tool_call_id: toolCall.id,\n content: { error: error.message },\n role: 'tool',\n });\n }\n }\n\n return responses;\n },\n [toolMap, onToolExecute, onToolComplete, onToolError]\n );\n\n // Extract pending tool calls from messages that need client handling\n const extractPendingToolCalls = useCallback(\n (messages: ChatMessage[]): ToolCall[] => {\n const pendingCalls: ToolCall[] = [];\n\n // Look at the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n\n if (message.role === 'assistant' && message.tool_calls?.length) {\n // Filter for client-side tools only\n const clientToolCalls = message.tool_calls.filter((tc) =>\n isClientTool(tc.function.name)\n );\n\n // Check if these tool calls have been responded to\n const respondedToolIds = new Set(\n messages\n .slice(i + 1)\n .filter((m) => m.role === 'tool')\n .map((m) => m.tool_call_id)\n );\n\n // Get unresponded tool calls\n for (const tc of clientToolCalls) {\n if (!respondedToolIds.has(tc.id)) {\n pendingCalls.push(tc);\n }\n }\n\n // Only check the most recent assistant message with tool calls\n break;\n }\n }\n\n return pendingCalls;\n },\n [isClientTool]\n );\n\n return {\n toolSchemas,\n isClientTool,\n handleToolCalls,\n extractPendingToolCalls,\n };\n}\n"],"names":["useMemo","useCallback"],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook for polling real-time chat history
|
|
7
|
+
*
|
|
8
|
+
* @param chatUid - The chat UID to poll for
|
|
9
|
+
* @param fetchFn - Function that fetches the realtime history
|
|
10
|
+
* @param options - Polling options
|
|
11
|
+
*/
|
|
12
|
+
function usePolling(chatUid, fetchFn, options = {}) {
|
|
13
|
+
const { interval = 1000, enabled = true, stopStatuses = ['completed', 'error'], onStop, onUpdate, onError, } = options;
|
|
14
|
+
const [data, setData] = react.useState(null);
|
|
15
|
+
const [isPolling, setIsPolling] = react.useState(false);
|
|
16
|
+
const [error, setError] = react.useState(null);
|
|
17
|
+
const intervalRef = react.useRef(null);
|
|
18
|
+
const isMountedRef = react.useRef(true);
|
|
19
|
+
// Refs for callbacks to avoid stale closures
|
|
20
|
+
const onStopRef = react.useRef(onStop);
|
|
21
|
+
const onUpdateRef = react.useRef(onUpdate);
|
|
22
|
+
const onErrorRef = react.useRef(onError);
|
|
23
|
+
const fetchFnRef = react.useRef(fetchFn);
|
|
24
|
+
react.useEffect(() => {
|
|
25
|
+
onStopRef.current = onStop;
|
|
26
|
+
onUpdateRef.current = onUpdate;
|
|
27
|
+
onErrorRef.current = onError;
|
|
28
|
+
fetchFnRef.current = fetchFn;
|
|
29
|
+
});
|
|
30
|
+
const clearPolling = react.useCallback(() => {
|
|
31
|
+
if (intervalRef.current) {
|
|
32
|
+
clearInterval(intervalRef.current);
|
|
33
|
+
intervalRef.current = null;
|
|
34
|
+
}
|
|
35
|
+
}, []);
|
|
36
|
+
const fetchData = react.useCallback(async () => {
|
|
37
|
+
if (!isMountedRef.current)
|
|
38
|
+
return;
|
|
39
|
+
try {
|
|
40
|
+
const result = await fetchFnRef.current();
|
|
41
|
+
if (!isMountedRef.current)
|
|
42
|
+
return;
|
|
43
|
+
setData(result);
|
|
44
|
+
setError(null);
|
|
45
|
+
onUpdateRef.current?.(result);
|
|
46
|
+
// Check if we should stop polling
|
|
47
|
+
if (stopStatuses.includes(result.status)) {
|
|
48
|
+
clearPolling();
|
|
49
|
+
setIsPolling(false);
|
|
50
|
+
onStopRef.current?.(result);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (!isMountedRef.current)
|
|
55
|
+
return;
|
|
56
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
57
|
+
setError(error);
|
|
58
|
+
onErrorRef.current?.(error);
|
|
59
|
+
// Stop polling on error
|
|
60
|
+
clearPolling();
|
|
61
|
+
setIsPolling(false);
|
|
62
|
+
}
|
|
63
|
+
}, [stopStatuses, clearPolling]);
|
|
64
|
+
const start = react.useCallback(() => {
|
|
65
|
+
if (!chatUid || intervalRef.current)
|
|
66
|
+
return;
|
|
67
|
+
setIsPolling(true);
|
|
68
|
+
setError(null);
|
|
69
|
+
// Immediate first fetch
|
|
70
|
+
fetchData();
|
|
71
|
+
// Set up interval
|
|
72
|
+
intervalRef.current = setInterval(fetchData, interval);
|
|
73
|
+
}, [chatUid, interval, fetchData]);
|
|
74
|
+
const stop = react.useCallback(() => {
|
|
75
|
+
clearPolling();
|
|
76
|
+
setIsPolling(false);
|
|
77
|
+
}, [clearPolling]);
|
|
78
|
+
const refetch = react.useCallback(async () => {
|
|
79
|
+
await fetchData();
|
|
80
|
+
}, [fetchData]);
|
|
81
|
+
// Auto-start polling when enabled and chatUid is set
|
|
82
|
+
react.useEffect(() => {
|
|
83
|
+
if (enabled && chatUid && !isPolling) {
|
|
84
|
+
start();
|
|
85
|
+
}
|
|
86
|
+
return () => {
|
|
87
|
+
clearPolling();
|
|
88
|
+
};
|
|
89
|
+
}, [enabled, chatUid, start, isPolling, clearPolling]);
|
|
90
|
+
// Cleanup on unmount
|
|
91
|
+
react.useEffect(() => {
|
|
92
|
+
isMountedRef.current = true;
|
|
93
|
+
return () => {
|
|
94
|
+
isMountedRef.current = false;
|
|
95
|
+
clearPolling();
|
|
96
|
+
};
|
|
97
|
+
}, [clearPolling]);
|
|
98
|
+
return {
|
|
99
|
+
data,
|
|
100
|
+
isPolling,
|
|
101
|
+
error,
|
|
102
|
+
start,
|
|
103
|
+
stop,
|
|
104
|
+
refetch,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
exports.usePolling = usePolling;
|
|
109
|
+
//# sourceMappingURL=usePolling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePolling.js","sources":["../../../../src/hooks/usePolling.ts"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { RealtimeChatHistory, RealtimeStatus } from '../api/types';\n\nexport interface UsePollingOptions {\n /**\n * Polling interval in milliseconds\n * @default 1000\n */\n interval?: number;\n\n /**\n * Whether polling is enabled\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Statuses that should stop polling\n * @default ['completed', 'error']\n */\n stopStatuses?: RealtimeStatus[];\n\n /**\n * Callback when polling stops\n */\n onStop?: (data: RealtimeChatHistory | null) => void;\n\n /**\n * Callback on each poll update\n */\n onUpdate?: (data: RealtimeChatHistory) => void;\n\n /**\n * Callback on poll error\n */\n onError?: (error: Error) => void;\n}\n\nexport interface UsePollingResult {\n /**\n * Current polling data\n */\n data: RealtimeChatHistory | null;\n\n /**\n * Whether polling is currently active\n */\n isPolling: boolean;\n\n /**\n * Last error that occurred\n */\n error: Error | null;\n\n /**\n * Start polling\n */\n start: () => void;\n\n /**\n * Stop polling\n */\n stop: () => void;\n\n /**\n * Manually trigger a fetch\n */\n refetch: () => Promise<void>;\n}\n\n/**\n * Hook for polling real-time chat history\n *\n * @param chatUid - The chat UID to poll for\n * @param fetchFn - Function that fetches the realtime history\n * @param options - Polling options\n */\nexport function usePolling(\n chatUid: string | null,\n fetchFn: () => Promise<RealtimeChatHistory>,\n options: UsePollingOptions = {}\n): UsePollingResult {\n const {\n interval = 1000,\n enabled = true,\n stopStatuses = ['completed', 'error'],\n onStop,\n onUpdate,\n onError,\n } = options;\n\n const [data, setData] = useState<RealtimeChatHistory | null>(null);\n const [isPolling, setIsPolling] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const isMountedRef = useRef(true);\n\n // Refs for callbacks to avoid stale closures\n const onStopRef = useRef(onStop);\n const onUpdateRef = useRef(onUpdate);\n const onErrorRef = useRef(onError);\n const fetchFnRef = useRef(fetchFn);\n\n useEffect(() => {\n onStopRef.current = onStop;\n onUpdateRef.current = onUpdate;\n onErrorRef.current = onError;\n fetchFnRef.current = fetchFn;\n });\n\n const clearPolling = useCallback(() => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n }, []);\n\n const fetchData = useCallback(async () => {\n if (!isMountedRef.current) return;\n\n try {\n const result = await fetchFnRef.current();\n\n if (!isMountedRef.current) return;\n\n setData(result);\n setError(null);\n onUpdateRef.current?.(result);\n\n // Check if we should stop polling\n if (stopStatuses.includes(result.status)) {\n clearPolling();\n setIsPolling(false);\n onStopRef.current?.(result);\n }\n } catch (err) {\n if (!isMountedRef.current) return;\n\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n\n // Stop polling on error\n clearPolling();\n setIsPolling(false);\n }\n }, [stopStatuses, clearPolling]);\n\n const start = useCallback(() => {\n if (!chatUid || intervalRef.current) return;\n\n setIsPolling(true);\n setError(null);\n\n // Immediate first fetch\n fetchData();\n\n // Set up interval\n intervalRef.current = setInterval(fetchData, interval);\n }, [chatUid, interval, fetchData]);\n\n const stop = useCallback(() => {\n clearPolling();\n setIsPolling(false);\n }, [clearPolling]);\n\n const refetch = useCallback(async () => {\n await fetchData();\n }, [fetchData]);\n\n // Auto-start polling when enabled and chatUid is set\n useEffect(() => {\n if (enabled && chatUid && !isPolling) {\n start();\n }\n\n return () => {\n clearPolling();\n };\n }, [enabled, chatUid, start, isPolling, clearPolling]);\n\n // Cleanup on unmount\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n clearPolling();\n };\n }, [clearPolling]);\n\n return {\n data,\n isPolling,\n error,\n start,\n stop,\n refetch,\n };\n}\n"],"names":["useState","useRef","useEffect","useCallback"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var DevicProvider = require('./provider/DevicProvider.js');
|
|
4
|
+
var DevicContext = require('./provider/DevicContext.js');
|
|
5
|
+
var ChatDrawer = require('./components/ChatDrawer/ChatDrawer.js');
|
|
6
|
+
var ChatMessages = require('./components/ChatDrawer/ChatMessages.js');
|
|
7
|
+
var ChatInput = require('./components/ChatDrawer/ChatInput.js');
|
|
8
|
+
var ToolTimeline = require('./components/ChatDrawer/ToolTimeline.js');
|
|
9
|
+
var useDevicChat = require('./hooks/useDevicChat.js');
|
|
10
|
+
var usePolling = require('./hooks/usePolling.js');
|
|
11
|
+
var useModelInterface = require('./hooks/useModelInterface.js');
|
|
12
|
+
var client = require('./api/client.js');
|
|
13
|
+
var index = require('./utils/index.js');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
exports.DevicProvider = DevicProvider.DevicProvider;
|
|
18
|
+
exports.DevicContext = DevicContext.DevicContext;
|
|
19
|
+
exports.useDevicContext = DevicContext.useDevicContext;
|
|
20
|
+
exports.useOptionalDevicContext = DevicContext.useOptionalDevicContext;
|
|
21
|
+
exports.ChatDrawer = ChatDrawer.ChatDrawer;
|
|
22
|
+
exports.ChatMessages = ChatMessages.ChatMessages;
|
|
23
|
+
exports.ChatInput = ChatInput.ChatInput;
|
|
24
|
+
exports.ToolTimeline = ToolTimeline.ToolTimeline;
|
|
25
|
+
exports.useDevicChat = useDevicChat.useDevicChat;
|
|
26
|
+
exports.usePolling = usePolling.usePolling;
|
|
27
|
+
exports.useModelInterface = useModelInterface.useModelInterface;
|
|
28
|
+
exports.DevicApiClient = client.DevicApiClient;
|
|
29
|
+
exports.DevicApiError = client.DevicApiError;
|
|
30
|
+
exports.debounce = index.debounce;
|
|
31
|
+
exports.deepMerge = index.deepMerge;
|
|
32
|
+
exports.formatFileSize = index.formatFileSize;
|
|
33
|
+
exports.generateId = index.generateId;
|
|
34
|
+
exports.storage = index.storage;
|
|
35
|
+
exports.throttle = index.throttle;
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Context for Devic configuration
|
|
7
|
+
*/
|
|
8
|
+
const DevicContext = react.createContext(null);
|
|
9
|
+
/**
|
|
10
|
+
* Hook to access the Devic context
|
|
11
|
+
* @throws Error if used outside of DevicProvider
|
|
12
|
+
*/
|
|
13
|
+
function useDevicContext() {
|
|
14
|
+
const context = react.useContext(DevicContext);
|
|
15
|
+
if (!context) {
|
|
16
|
+
throw new Error('useDevicContext must be used within a DevicProvider. ' +
|
|
17
|
+
'Make sure to wrap your component tree with <DevicProvider>.');
|
|
18
|
+
}
|
|
19
|
+
return context;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Hook to optionally access the Devic context
|
|
23
|
+
* Returns null if not within a provider (for components that can work standalone)
|
|
24
|
+
*/
|
|
25
|
+
function useOptionalDevicContext() {
|
|
26
|
+
return react.useContext(DevicContext);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.DevicContext = DevicContext;
|
|
30
|
+
exports.useDevicContext = useDevicContext;
|
|
31
|
+
exports.useOptionalDevicContext = useOptionalDevicContext;
|
|
32
|
+
//# sourceMappingURL=DevicContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevicContext.js","sources":["../../../../src/provider/DevicContext.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\nimport type { DevicContextValue } from './types';\n\n/**\n * Context for Devic configuration\n */\nexport const DevicContext = createContext<DevicContextValue | null>(null);\n\n/**\n * Hook to access the Devic context\n * @throws Error if used outside of DevicProvider\n */\nexport function useDevicContext(): DevicContextValue {\n const context = useContext(DevicContext);\n if (!context) {\n throw new Error(\n 'useDevicContext must be used within a DevicProvider. ' +\n 'Make sure to wrap your component tree with <DevicProvider>.'\n );\n }\n return context;\n}\n\n/**\n * Hook to optionally access the Devic context\n * Returns null if not within a provider (for components that can work standalone)\n */\nexport function useOptionalDevicContext(): DevicContextValue | null {\n return useContext(DevicContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;;AAGA;;AAEG;MACU,YAAY,GAAGA,mBAAa,CAA2B,IAAI;AAExE;;;AAGG;SACa,eAAe,GAAA;AAC7B,IAAA,MAAM,OAAO,GAAGC,gBAAU,CAAC,YAAY,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CACb,uDAAuD;AACvD,YAAA,6DAA6D,CAC9D;IACH;AACA,IAAA,OAAO,OAAO;AAChB;AAEA;;;AAGG;SACa,uBAAuB,GAAA;AACrC,IAAA,OAAOA,gBAAU,CAAC,YAAY,CAAC;AACjC;;;;;;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var DevicContext = require('./DevicContext.js');
|
|
6
|
+
var client = require('../api/client.js');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_BASE_URL = 'https://api.devic.ai';
|
|
9
|
+
/**
|
|
10
|
+
* Provider component for Devic UI configuration
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <DevicProvider
|
|
15
|
+
* apiKey="devic-xxx"
|
|
16
|
+
* baseUrl="https://api.devic.ai"
|
|
17
|
+
* tenantId="tenant-123"
|
|
18
|
+
* tenantMetadata={{ userId: '456' }}
|
|
19
|
+
* >
|
|
20
|
+
* <App />
|
|
21
|
+
* </DevicProvider>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, children, }) {
|
|
25
|
+
const contextValue = react.useMemo(() => {
|
|
26
|
+
const client$1 = new client.DevicApiClient({
|
|
27
|
+
apiKey,
|
|
28
|
+
baseUrl,
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
client: client$1,
|
|
32
|
+
apiKey,
|
|
33
|
+
baseUrl,
|
|
34
|
+
tenantId,
|
|
35
|
+
tenantMetadata,
|
|
36
|
+
isConfigured: !!apiKey,
|
|
37
|
+
};
|
|
38
|
+
}, [apiKey, baseUrl, tenantId, tenantMetadata]);
|
|
39
|
+
return (jsxRuntime.jsx(DevicContext.DevicContext.Provider, { value: contextValue, children: children }));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.DevicProvider = DevicProvider;
|
|
43
|
+
//# sourceMappingURL=DevicProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevicProvider.js","sources":["../../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport type { DevicProviderProps, DevicContextValue } from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n children,\n}: DevicProviderProps): JSX.Element {\n const contextValue = useMemo<DevicContextValue>(() => {\n const client = new DevicApiClient({\n apiKey,\n baseUrl,\n });\n\n return {\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n isConfigured: !!apiKey,\n };\n }, [apiKey, baseUrl, tenantId, tenantMetadata]);\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["useMemo","client","DevicApiClient","_jsx","DevicContext"],"mappings":";;;;;;;AAKA,MAAM,gBAAgB,GAAG,sBAAsB;AAE/C;;;;;;;;;;;;;;AAcG;AACG,SAAU,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,GAAG,gBAAgB,EAC1B,QAAQ,EACR,cAAc,EACd,QAAQ,GACW,EAAA;AACnB,IAAA,MAAM,YAAY,GAAGA,aAAO,CAAoB,MAAK;AACnD,QAAA,MAAMC,QAAM,GAAG,IAAIC,qBAAc,CAAC;YAChC,MAAM;YACN,OAAO;AACR,SAAA,CAAC;QAEF,OAAO;oBACLD,QAAM;YACN,MAAM;YACN,OAAO;YACP,QAAQ;YACR,cAAc;YACd,YAAY,EAAE,CAAC,CAAC,MAAM;SACvB;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAE/C,IAAA,QACEE,cAAA,CAACC,yBAAY,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,YAAY,EAAA,QAAA,EACvC,QAAQ,EAAA,CACa;AAE5B;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.devic-chat-drawer{--devic-primary:#1890ff;--devic-primary-hover:#40a9ff;--devic-primary-light:#e6f7ff;--devic-bg:#fff;--devic-bg-secondary:#f5f5f5;--devic-text:#333;--devic-text-secondary:#666;--devic-text-muted:#999;--devic-border:#e8e8e8;--devic-shadow:0 4px 12px rgba(0,0,0,.15);--devic-radius:8px;--devic-radius-sm:4px;--devic-radius-lg:16px;--devic-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--devic-transition:0.3s ease;background:var(--devic-bg);bottom:0;box-shadow:var(--devic-shadow);color:var(--devic-text);display:flex;flex-direction:column;font-family:var(--devic-font-family);font-size:14px;line-height:1.5;position:fixed;top:0;transition:transform var(--devic-transition);width:400px}.devic-chat-drawer[data-position=right]{right:0;transform:translateX(100%)}.devic-chat-drawer[data-position=left]{left:0;transform:translateX(-100%)}.devic-chat-drawer[data-open=true]{transform:translateX(0)}.devic-drawer-overlay{background:rgba(0,0,0,.3);inset:0;opacity:0;position:fixed;transition:opacity var(--devic-transition),visibility var(--devic-transition);visibility:hidden}.devic-drawer-overlay[data-open=true]{opacity:1;visibility:visible}.devic-drawer-header{align-items:center;border-bottom:1px solid var(--devic-border);display:flex;flex-shrink:0;justify-content:space-between;padding:16px}.devic-drawer-title{font-size:16px;font-weight:600;margin:0}.devic-drawer-close{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-drawer-close:hover{background:var(--devic-bg-secondary);color:var(--devic-text)}.devic-messages-container{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.devic-welcome{color:var(--devic-text-secondary);padding:24px 16px;text-align:center}.devic-welcome-text{font-size:16px;margin-bottom:16px}.devic-suggested-messages{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}.devic-suggested-btn{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-lg);color:var(--devic-text);cursor:pointer;font-size:13px;padding:8px 16px;transition:border-color var(--devic-transition),background var(--devic-transition)}.devic-suggested-btn:hover{background:var(--devic-primary-light);border-color:var(--devic-primary)}.devic-message{display:flex;flex-direction:column;max-width:85%}.devic-message[data-role=user]{align-self:flex-end}.devic-message[data-role=assistant],.devic-message[data-role=tool]{align-self:flex-start}.devic-message-bubble{word-wrap:break-word;border-radius:var(--devic-radius);padding:10px 14px}.devic-message[data-role=user] .devic-message-bubble{background:var(--devic-primary);border-bottom-right-radius:var(--devic-radius-sm);color:#fff}.devic-message[data-role=assistant] .devic-message-bubble{background:var(--devic-bg-secondary);border-bottom-left-radius:var(--devic-radius-sm);color:var(--devic-text)}.devic-message[data-role=tool] .devic-message-bubble{background:var(--devic-primary-light);border:1px solid var(--devic-primary);color:var(--devic-text);font-size:12px}.devic-message-time{color:var(--devic-text-muted);font-size:11px;margin-top:4px}.devic-message[data-role=user] .devic-message-time{text-align:right}.devic-message-files{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.devic-message-file{align-items:center;background:hsla(0,0%,100%,.2);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:6px 10px}.devic-loading{align-self:flex-start;display:flex;gap:4px;padding:10px 14px}.devic-loading-dot{animation:devic-bounce 1.4s ease-in-out infinite both;background:var(--devic-text-muted);border-radius:50%;height:8px;width:8px}.devic-loading-dot:first-child{animation-delay:-.32s}.devic-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes devic-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.devic-tool-timeline{background:var(--devic-bg-secondary);border-radius:var(--devic-radius);font-size:12px;margin:8px 0;padding:8px 12px}.devic-tool-item{align-items:center;display:flex;gap:8px;padding:6px 0}.devic-tool-item+.devic-tool-item{border-top:1px solid var(--devic-border)}.devic-tool-status{border-radius:50%;flex-shrink:0;height:8px;width:8px}.devic-tool-status[data-status=pending]{background:var(--devic-text-muted)}.devic-tool-status[data-status=executing]{animation:devic-pulse 1s infinite;background:var(--devic-primary)}.devic-tool-status[data-status=completed]{background:#52c41a}.devic-tool-status[data-status=error]{background:#ff4d4f}@keyframes devic-pulse{0%,to{opacity:1}50%{opacity:.5}}.devic-tool-name{color:var(--devic-text);font-weight:500}.devic-input-area{border-top:1px solid var(--devic-border);flex-shrink:0;padding:16px}.devic-input-wrapper{align-items:flex-end;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);display:flex;gap:8px;padding:8px 12px}.devic-input{background:none;border:none;color:var(--devic-text);flex:1;font-family:inherit;font-size:14px;line-height:1.5;max-height:120px;min-height:24px;outline:none;resize:none}.devic-input::placeholder{color:var(--devic-text-muted)}.devic-input-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;flex-shrink:0;padding:4px;transition:color var(--devic-transition)}.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-input-btn:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn{background:var(--devic-primary);border-radius:var(--devic-radius-sm);color:#fff;padding:6px 12px}.devic-send-btn:hover:not(:disabled){background:var(--devic-primary-hover);color:#fff}.devic-file-preview{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.devic-file-preview-item{align-items:center;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:4px 8px}.devic-file-remove{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;font-size:16px;line-height:1;padding:0}.devic-file-remove:hover{color:#ff4d4f}.devic-trigger{align-items:center;background:var(--devic-primary);border:none;border-radius:50%;box-shadow:var(--devic-shadow);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;position:fixed;transition:background var(--devic-transition),transform var(--devic-transition);width:56px}.devic-trigger:hover{background:var(--devic-primary-hover);transform:scale(1.05)}.devic-trigger svg{height:24px;width:24px}.devic-error{background:#fff2f0;border:1px solid #ffccc7;border-radius:var(--devic-radius);color:#ff4d4f;font-size:13px;margin:8px 16px;padding:12px}.devic-messages-container::-webkit-scrollbar{width:6px}.devic-messages-container::-webkit-scrollbar-track{background:transparent}.devic-messages-container::-webkit-scrollbar-thumb{background:var(--devic-border);border-radius:3px}.devic-messages-container::-webkit-scrollbar-thumb:hover{background:var(--devic-text-muted)}@media (max-width:480px){.devic-chat-drawer{width:100%}}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a unique ID
|
|
5
|
+
*/
|
|
6
|
+
function generateId() {
|
|
7
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Deep merge two objects
|
|
11
|
+
*/
|
|
12
|
+
function deepMerge(target, source) {
|
|
13
|
+
const result = { ...target };
|
|
14
|
+
for (const key in source) {
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
16
|
+
const sourceValue = source[key];
|
|
17
|
+
const targetValue = result[key];
|
|
18
|
+
if (sourceValue &&
|
|
19
|
+
typeof sourceValue === 'object' &&
|
|
20
|
+
!Array.isArray(sourceValue) &&
|
|
21
|
+
targetValue &&
|
|
22
|
+
typeof targetValue === 'object' &&
|
|
23
|
+
!Array.isArray(targetValue)) {
|
|
24
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
25
|
+
}
|
|
26
|
+
else if (sourceValue !== undefined) {
|
|
27
|
+
result[key] = sourceValue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Debounce a function
|
|
35
|
+
*/
|
|
36
|
+
function debounce(fn, delay) {
|
|
37
|
+
let timeoutId;
|
|
38
|
+
return (...args) => {
|
|
39
|
+
clearTimeout(timeoutId);
|
|
40
|
+
timeoutId = setTimeout(() => fn(...args), delay);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Throttle a function
|
|
45
|
+
*/
|
|
46
|
+
function throttle(fn, delay) {
|
|
47
|
+
let lastCall = 0;
|
|
48
|
+
return (...args) => {
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
if (now - lastCall >= delay) {
|
|
51
|
+
lastCall = now;
|
|
52
|
+
fn(...args);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format file size for display
|
|
58
|
+
*/
|
|
59
|
+
function formatFileSize(bytes) {
|
|
60
|
+
if (bytes === 0)
|
|
61
|
+
return '0 B';
|
|
62
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
63
|
+
const k = 1024;
|
|
64
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
65
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${units[i]}`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if running in browser
|
|
69
|
+
*/
|
|
70
|
+
function isBrowser() {
|
|
71
|
+
return typeof window !== 'undefined';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Local storage helper with JSON serialization
|
|
75
|
+
*/
|
|
76
|
+
const storage = {
|
|
77
|
+
get(key, defaultValue) {
|
|
78
|
+
if (!isBrowser())
|
|
79
|
+
return defaultValue ?? null;
|
|
80
|
+
try {
|
|
81
|
+
const item = localStorage.getItem(key);
|
|
82
|
+
return item ? JSON.parse(item) : (defaultValue ?? null);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return defaultValue ?? null;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
set(key, value) {
|
|
89
|
+
if (!isBrowser())
|
|
90
|
+
return;
|
|
91
|
+
try {
|
|
92
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Storage full or other error
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
remove(key) {
|
|
99
|
+
if (!isBrowser())
|
|
100
|
+
return;
|
|
101
|
+
try {
|
|
102
|
+
localStorage.removeItem(key);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Error removing item
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
exports.debounce = debounce;
|
|
111
|
+
exports.deepMerge = deepMerge;
|
|
112
|
+
exports.formatFileSize = formatFileSize;
|
|
113
|
+
exports.generateId = generateId;
|
|
114
|
+
exports.isBrowser = isBrowser;
|
|
115
|
+
exports.storage = storage;
|
|
116
|
+
exports.throttle = throttle;
|
|
117
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/utils/index.ts"],"sourcesContent":["/**\n * Generate a unique ID\n */\nexport function generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Deep merge two objects\n */\nexport function deepMerge<T extends Record<string, any>>(\n target: T,\n source: Partial<T>\n): T {\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const sourceValue = source[key];\n const targetValue = result[key];\n\n if (\n sourceValue &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(targetValue, sourceValue as any);\n } else if (sourceValue !== undefined) {\n result[key] = sourceValue as any;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Debounce a function\n */\nexport function debounce<T extends (...args: any[]) => any>(\n fn: T,\n delay: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout>;\n\n return (...args: Parameters<T>) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), delay);\n };\n}\n\n/**\n * Throttle a function\n */\nexport function throttle<T extends (...args: any[]) => any>(\n fn: T,\n delay: number\n): (...args: Parameters<T>) => void {\n let lastCall = 0;\n\n return (...args: Parameters<T>) => {\n const now = Date.now();\n if (now - lastCall >= delay) {\n lastCall = now;\n fn(...args);\n }\n };\n}\n\n/**\n * Format file size for display\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n\n const units = ['B', 'KB', 'MB', 'GB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${units[i]}`;\n}\n\n/**\n * Check if running in browser\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\n/**\n * Local storage helper with JSON serialization\n */\nexport const storage = {\n get<T>(key: string, defaultValue?: T): T | null {\n if (!isBrowser()) return defaultValue ?? null;\n\n try {\n const item = localStorage.getItem(key);\n return item ? JSON.parse(item) : (defaultValue ?? null);\n } catch {\n return defaultValue ?? null;\n }\n },\n\n set<T>(key: string, value: T): void {\n if (!isBrowser()) return;\n\n try {\n localStorage.setItem(key, JSON.stringify(value));\n } catch {\n // Storage full or other error\n }\n },\n\n remove(key: string): void {\n if (!isBrowser()) return;\n\n try {\n localStorage.removeItem(key);\n } catch {\n // Error removing item\n }\n },\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ProcessMessageDto, ChatMessage, AsyncResponse, RealtimeChatHistory, ChatHistory, AssistantSpecialization, ApiError, ToolCallResponse } from './types';
|
|
2
|
+
export interface DevicApiClientConfig {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Devic API client using native fetch
|
|
8
|
+
*/
|
|
9
|
+
export declare class DevicApiClient {
|
|
10
|
+
private config;
|
|
11
|
+
constructor(config: DevicApiClientConfig);
|
|
12
|
+
/**
|
|
13
|
+
* Update client configuration
|
|
14
|
+
*/
|
|
15
|
+
setConfig(config: Partial<DevicApiClientConfig>): void;
|
|
16
|
+
/**
|
|
17
|
+
* Make an authenticated request to the API
|
|
18
|
+
*/
|
|
19
|
+
private request;
|
|
20
|
+
/**
|
|
21
|
+
* Get all assistant specializations
|
|
22
|
+
*/
|
|
23
|
+
getAssistants(external?: boolean): Promise<AssistantSpecialization[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Get a specific assistant specialization
|
|
26
|
+
*/
|
|
27
|
+
getAssistant(identifier: string): Promise<AssistantSpecialization>;
|
|
28
|
+
/**
|
|
29
|
+
* Send a message to an assistant (sync mode)
|
|
30
|
+
*/
|
|
31
|
+
sendMessage(assistantId: string, dto: ProcessMessageDto): Promise<ChatMessage[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Send a message to an assistant (async mode)
|
|
34
|
+
*/
|
|
35
|
+
sendMessageAsync(assistantId: string, dto: ProcessMessageDto): Promise<AsyncResponse>;
|
|
36
|
+
/**
|
|
37
|
+
* Get real-time chat history (for polling in async mode)
|
|
38
|
+
*/
|
|
39
|
+
getRealtimeHistory(assistantId: string, chatUid: string): Promise<RealtimeChatHistory>;
|
|
40
|
+
/**
|
|
41
|
+
* Get chat history for a specific conversation
|
|
42
|
+
*/
|
|
43
|
+
getChatHistory(assistantId: string, chatUid: string): Promise<ChatHistory>;
|
|
44
|
+
/**
|
|
45
|
+
* Send tool call responses back to the assistant
|
|
46
|
+
*/
|
|
47
|
+
sendToolResponses(assistantId: string, chatUid: string, responses: ToolCallResponse[]): Promise<AsyncResponse>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Custom error class for API errors
|
|
51
|
+
*/
|
|
52
|
+
export declare class DevicApiError extends Error {
|
|
53
|
+
statusCode: number;
|
|
54
|
+
errorType?: string;
|
|
55
|
+
constructor(error: ApiError);
|
|
56
|
+
}
|