@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.
Files changed (70) hide show
  1. package/README.md +363 -0
  2. package/dist/cjs/api/client.js +118 -0
  3. package/dist/cjs/api/client.js.map +1 -0
  4. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +122 -0
  5. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -0
  6. package/dist/cjs/components/ChatDrawer/ChatInput.js +128 -0
  7. package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -0
  8. package/dist/cjs/components/ChatDrawer/ChatMessages.js +56 -0
  9. package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -0
  10. package/dist/cjs/components/ChatDrawer/ToolTimeline.js +26 -0
  11. package/dist/cjs/components/ChatDrawer/ToolTimeline.js.map +1 -0
  12. package/dist/cjs/hooks/useDevicChat.js +258 -0
  13. package/dist/cjs/hooks/useDevicChat.js.map +1 -0
  14. package/dist/cjs/hooks/useModelInterface.js +130 -0
  15. package/dist/cjs/hooks/useModelInterface.js.map +1 -0
  16. package/dist/cjs/hooks/usePolling.js +109 -0
  17. package/dist/cjs/hooks/usePolling.js.map +1 -0
  18. package/dist/cjs/index.js +36 -0
  19. package/dist/cjs/index.js.map +1 -0
  20. package/dist/cjs/provider/DevicContext.js +32 -0
  21. package/dist/cjs/provider/DevicContext.js.map +1 -0
  22. package/dist/cjs/provider/DevicProvider.js +43 -0
  23. package/dist/cjs/provider/DevicProvider.js.map +1 -0
  24. package/dist/cjs/styles.css +1 -0
  25. package/dist/cjs/utils/index.js +117 -0
  26. package/dist/cjs/utils/index.js.map +1 -0
  27. package/dist/esm/api/client.d.ts +56 -0
  28. package/dist/esm/api/client.js +115 -0
  29. package/dist/esm/api/client.js.map +1 -0
  30. package/dist/esm/api/types.d.ts +184 -0
  31. package/dist/esm/components/ChatDrawer/ChatDrawer.d.ts +27 -0
  32. package/dist/esm/components/ChatDrawer/ChatDrawer.js +120 -0
  33. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -0
  34. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +197 -0
  35. package/dist/esm/components/ChatDrawer/ChatInput.d.ts +5 -0
  36. package/dist/esm/components/ChatDrawer/ChatInput.js +126 -0
  37. package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -0
  38. package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +5 -0
  39. package/dist/esm/components/ChatDrawer/ChatMessages.js +54 -0
  40. package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -0
  41. package/dist/esm/components/ChatDrawer/ToolTimeline.d.ts +5 -0
  42. package/dist/esm/components/ChatDrawer/ToolTimeline.js +24 -0
  43. package/dist/esm/components/ChatDrawer/ToolTimeline.js.map +1 -0
  44. package/dist/esm/components/ChatDrawer/index.d.ts +5 -0
  45. package/dist/esm/hooks/index.d.ts +6 -0
  46. package/dist/esm/hooks/useDevicChat.d.ts +120 -0
  47. package/dist/esm/hooks/useDevicChat.js +256 -0
  48. package/dist/esm/hooks/useDevicChat.js.map +1 -0
  49. package/dist/esm/hooks/useModelInterface.d.ts +68 -0
  50. package/dist/esm/hooks/useModelInterface.js +128 -0
  51. package/dist/esm/hooks/useModelInterface.js.map +1 -0
  52. package/dist/esm/hooks/usePolling.d.ts +64 -0
  53. package/dist/esm/hooks/usePolling.js +107 -0
  54. package/dist/esm/hooks/usePolling.js.map +1 -0
  55. package/dist/esm/index.d.ts +10 -0
  56. package/dist/esm/index.js +12 -0
  57. package/dist/esm/index.js.map +1 -0
  58. package/dist/esm/provider/DevicContext.d.ts +15 -0
  59. package/dist/esm/provider/DevicContext.js +28 -0
  60. package/dist/esm/provider/DevicContext.js.map +1 -0
  61. package/dist/esm/provider/DevicProvider.d.ts +17 -0
  62. package/dist/esm/provider/DevicProvider.js +41 -0
  63. package/dist/esm/provider/DevicProvider.js.map +1 -0
  64. package/dist/esm/provider/index.d.ts +3 -0
  65. package/dist/esm/provider/types.d.ts +58 -0
  66. package/dist/esm/styles.css +1 -0
  67. package/dist/esm/utils/index.d.ts +32 -0
  68. package/dist/esm/utils/index.js +109 -0
  69. package/dist/esm/utils/index.js.map +1 -0
  70. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,363 @@
1
+ # @devicai/ui
2
+
3
+ React component library for integrating Devic AI assistants into your application.
4
+
5
+ ## Features
6
+
7
+ - **ChatDrawer** - A ready-to-use chat drawer component
8
+ - **useDevicChat** - Hook for building custom chat UIs
9
+ - **Model Interface Protocol** - Support for client-side tool execution
10
+ - **CSS Variables** - Easy theming with CSS custom properties
11
+ - **TypeScript** - Full type definitions included
12
+ - **React 17+** - Compatible with React 17 and above
13
+ - **Minimal Dependencies** - Only React as a peer dependency
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @devicai/ui
19
+ # or
20
+ yarn add @devicai/ui
21
+ # or
22
+ pnpm add @devicai/ui
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ### Using ChatDrawer (Simplest)
28
+
29
+ ```tsx
30
+ import { DevicProvider, ChatDrawer } from '@devicai/ui';
31
+ import '@devicai/ui/dist/esm/styles.css';
32
+
33
+ function App() {
34
+ return (
35
+ <DevicProvider apiKey="your-api-key">
36
+ <ChatDrawer
37
+ assistantId="my-assistant"
38
+ options={{
39
+ position: 'right',
40
+ welcomeMessage: 'Hello! How can I help you?',
41
+ suggestedMessages: ['Help me with...', 'Tell me about...'],
42
+ }}
43
+ />
44
+ </DevicProvider>
45
+ );
46
+ }
47
+ ```
48
+
49
+ ### Using the Hook (Custom UI)
50
+
51
+ ```tsx
52
+ import { DevicProvider, useDevicChat } from '@devicai/ui';
53
+
54
+ function CustomChat() {
55
+ const { messages, isLoading, sendMessage } = useDevicChat({
56
+ assistantId: 'my-assistant',
57
+ });
58
+
59
+ return (
60
+ <div>
61
+ {messages.map((msg) => (
62
+ <div key={msg.uid}>
63
+ <strong>{msg.role}:</strong> {msg.content.message}
64
+ </div>
65
+ ))}
66
+ {isLoading && <div>Thinking...</div>}
67
+ <button onClick={() => sendMessage('Hello!')}>Send</button>
68
+ </div>
69
+ );
70
+ }
71
+
72
+ function App() {
73
+ return (
74
+ <DevicProvider apiKey="your-api-key">
75
+ <CustomChat />
76
+ </DevicProvider>
77
+ );
78
+ }
79
+ ```
80
+
81
+ ## Components
82
+
83
+ ### DevicProvider
84
+
85
+ Context provider for global configuration.
86
+
87
+ ```tsx
88
+ <DevicProvider
89
+ apiKey="devic-xxx" // Required
90
+ baseUrl="https://api.devic.ai"
91
+ tenantId="tenant-123" // Optional global tenant
92
+ tenantMetadata={{ ... }} // Optional global metadata
93
+ >
94
+ <App />
95
+ </DevicProvider>
96
+ ```
97
+
98
+ ### ChatDrawer
99
+
100
+ A complete chat drawer component.
101
+
102
+ ```tsx
103
+ <ChatDrawer
104
+ assistantId="my-assistant"
105
+ chatUid="optional-existing-chat"
106
+ options={{
107
+ position: 'right', // 'left' | 'right'
108
+ width: 400,
109
+ defaultOpen: false,
110
+ color: '#1890ff', // Primary color
111
+ welcomeMessage: 'Hello!',
112
+ suggestedMessages: ['Help me...'],
113
+ enableFileUploads: true,
114
+ allowedFileTypes: { images: true, documents: true },
115
+ inputPlaceholder: 'Type a message...',
116
+ title: 'Chat Assistant',
117
+ showToolTimeline: true,
118
+ }}
119
+ enabledTools={['tool1', 'tool2']}
120
+ modelInterfaceTools={[
121
+ {
122
+ toolName: 'get_user_location',
123
+ schema: {
124
+ type: 'function',
125
+ function: {
126
+ name: 'get_user_location',
127
+ description: 'Get user current location',
128
+ parameters: { type: 'object', properties: {} }
129
+ }
130
+ },
131
+ callback: async () => {
132
+ const pos = await getCurrentPosition();
133
+ return { lat: pos.coords.latitude, lng: pos.coords.longitude };
134
+ }
135
+ }
136
+ ]}
137
+ tenantId="specific-tenant" // Override provider
138
+ tenantMetadata={{ userId: '123' }}
139
+ apiKey="override-key" // Override provider
140
+
141
+ // Callbacks
142
+ onMessageSent={(message) => {}}
143
+ onMessageReceived={(message) => {}}
144
+ onToolCall={(toolName, params) => {}}
145
+ onError={(error) => {}}
146
+ onChatCreated={(chatUid) => {}}
147
+ onOpen={() => {}}
148
+ onClose={() => {}}
149
+
150
+ // Controlled mode
151
+ isOpen={true}
152
+ />
153
+ ```
154
+
155
+ ## Hooks
156
+
157
+ ### useDevicChat
158
+
159
+ Main hook for chat functionality.
160
+
161
+ ```tsx
162
+ const {
163
+ messages, // ChatMessage[]
164
+ chatUid, // string | null
165
+ isLoading, // boolean
166
+ status, // 'idle' | 'processing' | 'completed' | 'error'
167
+ error, // Error | null
168
+ sendMessage, // (message: string, options?: { files?: ChatFile[] }) => Promise<void>
169
+ clearChat, // () => void
170
+ loadChat, // (chatUid: string) => Promise<void>
171
+ } = useDevicChat({
172
+ assistantId: 'my-assistant',
173
+ chatUid: 'optional-existing-chat',
174
+ apiKey: 'override-key',
175
+ baseUrl: 'https://api.devic.ai',
176
+ tenantId: 'tenant-123',
177
+ tenantMetadata: { userId: '456' },
178
+ enabledTools: ['tool1', 'tool2'],
179
+ modelInterfaceTools: [...],
180
+ pollingInterval: 1000,
181
+ onMessageSent: (message) => {},
182
+ onMessageReceived: (message) => {},
183
+ onToolCall: (toolName, params) => {},
184
+ onError: (error) => {},
185
+ onChatCreated: (chatUid) => {},
186
+ });
187
+ ```
188
+
189
+ ### useModelInterface
190
+
191
+ Hook for implementing the Model Interface Protocol.
192
+
193
+ ```tsx
194
+ const {
195
+ toolSchemas, // Tool schemas to send to API
196
+ isClientTool, // (name: string) => boolean
197
+ handleToolCalls, // (toolCalls: ToolCall[]) => Promise<ToolCallResponse[]>
198
+ extractPendingToolCalls, // (messages: ChatMessage[]) => ToolCall[]
199
+ } = useModelInterface({
200
+ tools: [
201
+ {
202
+ toolName: 'get_user_location',
203
+ schema: {
204
+ type: 'function',
205
+ function: {
206
+ name: 'get_user_location',
207
+ description: 'Get user location',
208
+ parameters: { type: 'object', properties: {} }
209
+ }
210
+ },
211
+ callback: async () => ({ lat: 40.7, lng: -74.0 })
212
+ }
213
+ ],
214
+ onToolExecute: (toolName, params) => {},
215
+ onToolComplete: (toolName, result) => {},
216
+ onToolError: (toolName, error) => {},
217
+ });
218
+ ```
219
+
220
+ ### usePolling
221
+
222
+ Hook for polling real-time chat history.
223
+
224
+ ```tsx
225
+ const {
226
+ data, // RealtimeChatHistory | null
227
+ isPolling, // boolean
228
+ error, // Error | null
229
+ start, // () => void
230
+ stop, // () => void
231
+ refetch, // () => Promise<void>
232
+ } = usePolling(
233
+ chatUid,
234
+ async () => client.getRealtimeHistory(assistantId, chatUid),
235
+ {
236
+ interval: 1000,
237
+ enabled: true,
238
+ stopStatuses: ['completed', 'error'],
239
+ onUpdate: (data) => {},
240
+ onStop: (data) => {},
241
+ onError: (error) => {},
242
+ }
243
+ );
244
+ ```
245
+
246
+ ## API Client
247
+
248
+ Use the API client directly for advanced use cases.
249
+
250
+ ```tsx
251
+ import { DevicApiClient } from '@devicai/ui';
252
+
253
+ const client = new DevicApiClient({
254
+ apiKey: 'your-api-key',
255
+ baseUrl: 'https://api.devic.ai',
256
+ });
257
+
258
+ // Get assistants
259
+ const assistants = await client.getAssistants();
260
+
261
+ // Send message (async mode)
262
+ const { chatUid } = await client.sendMessageAsync('my-assistant', {
263
+ message: 'Hello!',
264
+ tenantId: 'tenant-123',
265
+ });
266
+
267
+ // Poll for results
268
+ const result = await client.getRealtimeHistory('my-assistant', chatUid);
269
+
270
+ // Send tool responses
271
+ await client.sendToolResponses('my-assistant', chatUid, [
272
+ { tool_call_id: 'call_123', content: { result: 'data' }, role: 'tool' }
273
+ ]);
274
+ ```
275
+
276
+ ## Theming
277
+
278
+ Customize appearance with CSS variables:
279
+
280
+ ```css
281
+ .devic-chat-drawer {
282
+ --devic-primary: #1890ff;
283
+ --devic-primary-hover: #40a9ff;
284
+ --devic-primary-light: #e6f7ff;
285
+ --devic-bg: #ffffff;
286
+ --devic-bg-secondary: #f5f5f5;
287
+ --devic-text: #333333;
288
+ --devic-text-secondary: #666666;
289
+ --devic-text-muted: #999999;
290
+ --devic-border: #e8e8e8;
291
+ --devic-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
292
+ --devic-radius: 8px;
293
+ --devic-radius-sm: 4px;
294
+ --devic-radius-lg: 16px;
295
+ }
296
+ ```
297
+
298
+ Or use the `color` option in ChatDrawer:
299
+
300
+ ```tsx
301
+ <ChatDrawer
302
+ options={{ color: '#ff4081' }}
303
+ />
304
+ ```
305
+
306
+ ## Model Interface Protocol
307
+
308
+ The Model Interface Protocol allows you to define client-side tools that the assistant can call during a conversation.
309
+
310
+ ```tsx
311
+ const locationTool: ModelInterfaceTool = {
312
+ toolName: 'get_user_location',
313
+ schema: {
314
+ type: 'function',
315
+ function: {
316
+ name: 'get_user_location',
317
+ description: 'Get the user current geographic location',
318
+ parameters: {
319
+ type: 'object',
320
+ properties: {},
321
+ }
322
+ }
323
+ },
324
+ callback: async () => {
325
+ return new Promise((resolve, reject) => {
326
+ navigator.geolocation.getCurrentPosition(
327
+ (pos) => resolve({
328
+ latitude: pos.coords.latitude,
329
+ longitude: pos.coords.longitude,
330
+ }),
331
+ (err) => reject(err)
332
+ );
333
+ });
334
+ }
335
+ };
336
+
337
+ <ChatDrawer
338
+ assistantId="my-assistant"
339
+ modelInterfaceTools={[locationTool]}
340
+ />
341
+ ```
342
+
343
+ ## TypeScript
344
+
345
+ All types are exported:
346
+
347
+ ```tsx
348
+ import type {
349
+ ChatMessage,
350
+ ChatFile,
351
+ ModelInterfaceTool,
352
+ ModelInterfaceToolSchema,
353
+ ToolCall,
354
+ ToolCallResponse,
355
+ RealtimeChatHistory,
356
+ ChatDrawerOptions,
357
+ UseDevicChatOptions,
358
+ } from '@devicai/ui';
359
+ ```
360
+
361
+ ## License
362
+
363
+ MIT
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Devic API client using native fetch
5
+ */
6
+ class DevicApiClient {
7
+ constructor(config) {
8
+ this.config = config;
9
+ }
10
+ /**
11
+ * Update client configuration
12
+ */
13
+ setConfig(config) {
14
+ this.config = { ...this.config, ...config };
15
+ }
16
+ /**
17
+ * Make an authenticated request to the API
18
+ */
19
+ async request(endpoint, options = {}) {
20
+ const url = `${this.config.baseUrl}${endpoint}`;
21
+ const headers = {
22
+ 'Content-Type': 'application/json',
23
+ 'Authorization': `Bearer ${this.config.apiKey}`,
24
+ ...options.headers,
25
+ };
26
+ const response = await fetch(url, {
27
+ ...options,
28
+ headers,
29
+ });
30
+ if (!response.ok) {
31
+ let errorData;
32
+ try {
33
+ errorData = await response.json();
34
+ }
35
+ catch {
36
+ errorData = {
37
+ statusCode: response.status,
38
+ message: response.statusText,
39
+ };
40
+ }
41
+ throw new DevicApiError(errorData);
42
+ }
43
+ // Handle responses that may have a wrapper structure
44
+ const data = await response.json();
45
+ // If the response has a data property, extract it (common wrapper pattern)
46
+ if (data && typeof data === 'object' && 'data' in data) {
47
+ return data.data;
48
+ }
49
+ return data;
50
+ }
51
+ /**
52
+ * Get all assistant specializations
53
+ */
54
+ async getAssistants(external = false) {
55
+ const query = external ? '?external=true' : '';
56
+ return this.request(`/api/v1/assistants${query}`);
57
+ }
58
+ /**
59
+ * Get a specific assistant specialization
60
+ */
61
+ async getAssistant(identifier) {
62
+ return this.request(`/api/v1/assistants/${identifier}`);
63
+ }
64
+ /**
65
+ * Send a message to an assistant (sync mode)
66
+ */
67
+ async sendMessage(assistantId, dto) {
68
+ return this.request(`/api/v1/assistants/${assistantId}/messages`, {
69
+ method: 'POST',
70
+ body: JSON.stringify(dto),
71
+ });
72
+ }
73
+ /**
74
+ * Send a message to an assistant (async mode)
75
+ */
76
+ async sendMessageAsync(assistantId, dto) {
77
+ return this.request(`/api/v1/assistants/${assistantId}/messages?async=true`, {
78
+ method: 'POST',
79
+ body: JSON.stringify(dto),
80
+ });
81
+ }
82
+ /**
83
+ * Get real-time chat history (for polling in async mode)
84
+ */
85
+ async getRealtimeHistory(assistantId, chatUid) {
86
+ return this.request(`/api/v1/assistants/${assistantId}/chats/${chatUid}/realtime`);
87
+ }
88
+ /**
89
+ * Get chat history for a specific conversation
90
+ */
91
+ async getChatHistory(assistantId, chatUid) {
92
+ return this.request(`/api/v1/assistants/${assistantId}/chats/${chatUid}`);
93
+ }
94
+ /**
95
+ * Send tool call responses back to the assistant
96
+ */
97
+ async sendToolResponses(assistantId, chatUid, responses) {
98
+ return this.request(`/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`, {
99
+ method: 'POST',
100
+ body: JSON.stringify({ responses }),
101
+ });
102
+ }
103
+ }
104
+ /**
105
+ * Custom error class for API errors
106
+ */
107
+ class DevicApiError extends Error {
108
+ constructor(error) {
109
+ super(error.message);
110
+ this.name = 'DevicApiError';
111
+ this.statusCode = error.statusCode;
112
+ this.errorType = error.error;
113
+ }
114
+ }
115
+
116
+ exports.DevicApiClient = DevicApiClient;
117
+ exports.DevicApiError = DevicApiError;
118
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sources":["../../../../src/api/client.ts"],"sourcesContent":["import type {\n ProcessMessageDto,\n ChatMessage,\n AsyncResponse,\n RealtimeChatHistory,\n ChatHistory,\n AssistantSpecialization,\n ApiError,\n ToolCallResponse,\n} from './types';\n\nexport interface DevicApiClientConfig {\n apiKey: string;\n baseUrl: string;\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n // Handle responses that may have a wrapper structure\n const data = await response.json();\n\n // If the response has a data property, extract it (common wrapper pattern)\n if (data && typeof data === 'object' && 'data' in data) {\n return data.data as T;\n }\n\n return data as T;\n }\n\n /**\n * Get all assistant specializations\n */\n async getAssistants(external = false): Promise<AssistantSpecialization[]> {\n const query = external ? '?external=true' : '';\n return this.request<AssistantSpecialization[]>(`/api/v1/assistants${query}`);\n }\n\n /**\n * Get a specific assistant specialization\n */\n async getAssistant(identifier: string): Promise<AssistantSpecialization> {\n return this.request<AssistantSpecialization>(`/api/v1/assistants/${identifier}`);\n }\n\n /**\n * Send a message to an assistant (sync mode)\n */\n async sendMessage(\n assistantId: string,\n dto: ProcessMessageDto\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/messages`,\n {\n method: 'POST',\n body: JSON.stringify(dto),\n }\n );\n }\n\n /**\n * Send a message to an assistant (async mode)\n */\n async sendMessageAsync(\n assistantId: string,\n dto: ProcessMessageDto\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/messages?async=true`,\n {\n method: 'POST',\n body: JSON.stringify(dto),\n }\n );\n }\n\n /**\n * Get real-time chat history (for polling in async mode)\n */\n async getRealtimeHistory(\n assistantId: string,\n chatUid: string\n ): Promise<RealtimeChatHistory> {\n return this.request<RealtimeChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/realtime`\n );\n }\n\n /**\n * Get chat history for a specific conversation\n */\n async getChatHistory(\n assistantId: string,\n chatUid: string\n ): Promise<ChatHistory> {\n return this.request<ChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}`\n );\n }\n\n /**\n * Send tool call responses back to the assistant\n */\n async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[]\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: 'POST',\n body: JSON.stringify({ responses }),\n }\n );\n }\n}\n\n/**\n * Custom error class for API errors\n */\nexport class DevicApiError extends Error {\n public statusCode: number;\n public errorType?: string;\n\n constructor(error: ApiError) {\n super(error.message);\n this.name = 'DevicApiError';\n this.statusCode = error.statusCode;\n this.errorType = error.error;\n }\n}\n"],"names":[],"mappings":";;AAgBA;;AAEG;MACU,cAAc,CAAA;AAGzB,IAAA,WAAA,CAAY,MAA4B,EAAA;AACtC,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;IACtB;AAEA;;AAEG;AACH,IAAA,SAAS,CAAC,MAAqC,EAAA;AAC7C,QAAA,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE;IAC7C;AAEA;;AAEG;AACK,IAAA,MAAM,OAAO,CACnB,QAAgB,EAChB,UAAuB,EAAE,EAAA;QAEzB,MAAM,GAAG,GAAG,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAE;AAE/C,QAAA,MAAM,OAAO,GAAgB;AAC3B,YAAA,cAAc,EAAE,kBAAkB;AAClC,YAAA,eAAe,EAAE,CAAA,OAAA,EAAU,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA,CAAE;YAC/C,GAAG,OAAO,CAAC,OAAO;SACnB;AAED,QAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;AAChC,YAAA,GAAG,OAAO;YACV,OAAO;AACR,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,YAAA,IAAI,SAAmB;AACvB,YAAA,IAAI;AACF,gBAAA,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;YACnC;AAAE,YAAA,MAAM;AACN,gBAAA,SAAS,GAAG;oBACV,UAAU,EAAE,QAAQ,CAAC,MAAM;oBAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU;iBAC7B;YACH;AACA,YAAA,MAAM,IAAI,aAAa,CAAC,SAAS,CAAC;QACpC;;AAGA,QAAA,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;;QAGlC,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE;YACtD,OAAO,IAAI,CAAC,IAAS;QACvB;AAEA,QAAA,OAAO,IAAS;IAClB;AAEA;;AAEG;AACH,IAAA,MAAM,aAAa,CAAC,QAAQ,GAAG,KAAK,EAAA;QAClC,MAAM,KAAK,GAAG,QAAQ,GAAG,gBAAgB,GAAG,EAAE;QAC9C,OAAO,IAAI,CAAC,OAAO,CAA4B,qBAAqB,KAAK,CAAA,CAAE,CAAC;IAC9E;AAEA;;AAEG;IACH,MAAM,YAAY,CAAC,UAAkB,EAAA;QACnC,OAAO,IAAI,CAAC,OAAO,CAA0B,sBAAsB,UAAU,CAAA,CAAE,CAAC;IAClF;AAEA;;AAEG;AACH,IAAA,MAAM,WAAW,CACf,WAAmB,EACnB,GAAsB,EAAA;AAEtB,QAAA,OAAO,IAAI,CAAC,OAAO,CACjB,CAAA,mBAAA,EAAsB,WAAW,WAAW,EAC5C;AACE,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;AAC1B,SAAA,CACF;IACH;AAEA;;AAEG;AACH,IAAA,MAAM,gBAAgB,CACpB,WAAmB,EACnB,GAAsB,EAAA;AAEtB,QAAA,OAAO,IAAI,CAAC,OAAO,CACjB,CAAA,mBAAA,EAAsB,WAAW,sBAAsB,EACvD;AACE,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;AAC1B,SAAA,CACF;IACH;AAEA;;AAEG;AACH,IAAA,MAAM,kBAAkB,CACtB,WAAmB,EACnB,OAAe,EAAA;QAEf,OAAO,IAAI,CAAC,OAAO,CACjB,CAAA,mBAAA,EAAsB,WAAW,CAAA,OAAA,EAAU,OAAO,CAAA,SAAA,CAAW,CAC9D;IACH;AAEA;;AAEG;AACH,IAAA,MAAM,cAAc,CAClB,WAAmB,EACnB,OAAe,EAAA;QAEf,OAAO,IAAI,CAAC,OAAO,CACjB,CAAA,mBAAA,EAAsB,WAAW,CAAA,OAAA,EAAU,OAAO,CAAA,CAAE,CACrD;IACH;AAEA;;AAEG;AACH,IAAA,MAAM,iBAAiB,CACrB,WAAmB,EACnB,OAAe,EACf,SAA6B,EAAA;QAE7B,OAAO,IAAI,CAAC,OAAO,CACjB,sBAAsB,WAAW,CAAA,OAAA,EAAU,OAAO,CAAA,cAAA,CAAgB,EAClE;AACE,YAAA,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC;AACpC,SAAA,CACF;IACH;AACD;AAED;;AAEG;AACG,MAAO,aAAc,SAAQ,KAAK,CAAA;AAItC,IAAA,WAAA,CAAY,KAAe,EAAA;AACzB,QAAA,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AACpB,QAAA,IAAI,CAAC,IAAI,GAAG,eAAe;AAC3B,QAAA,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU;AAClC,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK;IAC9B;AACD;;;;;"}
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var useDevicChat = require('../../hooks/useDevicChat.js');
6
+ var ChatMessages = require('./ChatMessages.js');
7
+ var ChatInput = require('./ChatInput.js');
8
+
9
+ const DEFAULT_OPTIONS = {
10
+ position: 'right',
11
+ width: 400,
12
+ defaultOpen: false,
13
+ color: '#1890ff',
14
+ welcomeMessage: '',
15
+ suggestedMessages: [],
16
+ enableFileUploads: false,
17
+ allowedFileTypes: { images: true, documents: true },
18
+ maxFileSize: 10 * 1024 * 1024,
19
+ inputPlaceholder: 'Type a message...',
20
+ title: 'Chat',
21
+ showToolTimeline: true,
22
+ zIndex: 1000,
23
+ };
24
+ /**
25
+ * Chat drawer component for Devic assistants
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * <ChatDrawer
30
+ * assistantId="my-assistant"
31
+ * options={{
32
+ * position: 'right',
33
+ * width: 400,
34
+ * welcomeMessage: 'Hello! How can I help you?',
35
+ * suggestedMessages: ['Help me with...', 'Tell me about...'],
36
+ * }}
37
+ * modelInterfaceTools={[
38
+ * {
39
+ * toolName: 'get_user_location',
40
+ * schema: { ... },
41
+ * callback: async () => ({ lat: 40.7, lng: -74.0 })
42
+ * }
43
+ * ]}
44
+ * onMessageReceived={(msg) => console.log('Received:', msg)}
45
+ * />
46
+ * ```
47
+ */
48
+ function ChatDrawer({ assistantId, chatUid: initialChatUid, options = {}, enabledTools, modelInterfaceTools, tenantId, tenantMetadata, apiKey, baseUrl, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, onOpen, onClose, isOpen: controlledIsOpen, className, }) {
49
+ // Merge options with defaults
50
+ const mergedOptions = react.useMemo(() => ({ ...DEFAULT_OPTIONS, ...options }), [options]);
51
+ // Drawer open state (can be controlled or uncontrolled)
52
+ const [internalIsOpen, setInternalIsOpen] = react.useState(mergedOptions.defaultOpen);
53
+ const isOpen = controlledIsOpen ?? internalIsOpen;
54
+ // Use chat hook
55
+ const chat = useDevicChat.useDevicChat({
56
+ assistantId,
57
+ chatUid: initialChatUid,
58
+ apiKey,
59
+ baseUrl,
60
+ tenantId,
61
+ tenantMetadata,
62
+ enabledTools,
63
+ modelInterfaceTools,
64
+ onMessageSent,
65
+ onMessageReceived,
66
+ onToolCall,
67
+ onError,
68
+ onChatCreated,
69
+ });
70
+ // Handle open/close
71
+ const handleOpen = react.useCallback(() => {
72
+ setInternalIsOpen(true);
73
+ onOpen?.();
74
+ }, [onOpen]);
75
+ const handleClose = react.useCallback(() => {
76
+ setInternalIsOpen(false);
77
+ onClose?.();
78
+ }, [onClose]);
79
+ // Handle send message
80
+ const handleSend = react.useCallback((message, files) => {
81
+ chat.sendMessage(message, { files });
82
+ }, [chat]);
83
+ // Handle suggested message click
84
+ const handleSuggestedClick = react.useCallback((message) => {
85
+ chat.sendMessage(message);
86
+ }, [chat]);
87
+ // Apply CSS variable for primary color
88
+ react.useEffect(() => {
89
+ if (mergedOptions.color !== DEFAULT_OPTIONS.color) {
90
+ document.documentElement.style.setProperty('--devic-primary', mergedOptions.color);
91
+ }
92
+ }, [mergedOptions.color]);
93
+ // Build style object
94
+ const drawerStyle = react.useMemo(() => ({
95
+ width: mergedOptions.width,
96
+ zIndex: mergedOptions.zIndex,
97
+ }), [mergedOptions.width, mergedOptions.zIndex]);
98
+ const overlayStyle = react.useMemo(() => ({
99
+ zIndex: mergedOptions.zIndex - 1,
100
+ }), [mergedOptions.zIndex]);
101
+ const triggerStyle = react.useMemo(() => ({
102
+ zIndex: mergedOptions.zIndex - 1,
103
+ [mergedOptions.position]: 20,
104
+ bottom: 20,
105
+ }), [mergedOptions.zIndex, mergedOptions.position]);
106
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose }), jsxRuntime.jsxs("div", { className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, style: drawerStyle, children: [jsxRuntime.jsxs("div", { className: "devic-drawer-header", children: [jsxRuntime.jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsxRuntime.jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) })] }), chat.error && (jsxRuntime.jsx("div", { className: "devic-error", children: chat.error.message })), jsxRuntime.jsx(ChatMessages.ChatMessages, { messages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline }), jsxRuntime.jsx(ChatInput.ChatInput, { onSend: handleSend, disabled: chat.isLoading, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize })] }), !isOpen && (jsxRuntime.jsx("button", { className: "devic-trigger", onClick: handleOpen, style: triggerStyle, type: "button", "aria-label": "Open chat", children: jsxRuntime.jsx(ChatIcon, {}) }))] }));
107
+ }
108
+ /**
109
+ * Close icon
110
+ */
111
+ function CloseIcon() {
112
+ return (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
113
+ }
114
+ /**
115
+ * Chat icon for trigger button
116
+ */
117
+ function ChatIcon() {
118
+ return (jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" }) }));
119
+ }
120
+
121
+ exports.ChatDrawer = ChatDrawer;
122
+ //# sourceMappingURL=ChatDrawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatDrawer.js","sources":["../../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport type { ChatDrawerProps, ChatDrawerOptions } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: 400,\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showToolTimeline: true,\n zIndex: 1000,\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport function ChatDrawer({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n}: ChatDrawerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // Drawer open state (can be controlled or uncontrolled)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isOpen = controlledIsOpen ?? internalIsOpen;\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: initialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n });\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n // Handle send message\n const handleSend = useCallback(\n (message: string, files?: any[]) => {\n chat.sendMessage(message, { files });\n },\n [chat]\n );\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Apply CSS variable for primary color\n useEffect(() => {\n if (mergedOptions.color !== DEFAULT_OPTIONS.color) {\n document.documentElement.style.setProperty(\n '--devic-primary',\n mergedOptions.color\n );\n }\n }, [mergedOptions.color]);\n\n // Build style object\n const drawerStyle = useMemo(\n () => ({\n width: mergedOptions.width,\n zIndex: mergedOptions.zIndex,\n }),\n [mergedOptions.width, mergedOptions.zIndex]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay */}\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n\n {/* Drawer */}\n <div\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n style={drawerStyle}\n >\n {/* Header */}\n <div className=\"devic-drawer-header\">\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n />\n\n {/* Input */}\n <ChatInput\n onSend={handleSend}\n disabled={chat.isLoading}\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n />\n </div>\n\n {/* Trigger button (when drawer is closed) */}\n {!isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["useMemo","useState","useDevicChat","useCallback","useEffect","_jsxs","_jsx","ChatMessages","ChatInput"],"mappings":"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"}