@arbidocs/react 0.4.2 → 0.4.4
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 +24 -0
- package/dist/{chunk-3CLGHHME.js → chunk-MIJRORQL.js} +395 -313
- package/dist/chunk-MIJRORQL.js.map +1 -0
- package/dist/{chunk-OU2QLIKS.cjs → chunk-ORKGCXG3.cjs} +444 -361
- package/dist/chunk-ORKGCXG3.cjs.map +1 -0
- package/dist/index.cjs +990 -1337
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1820 -291
- package/dist/index.d.ts +1820 -291
- package/dist/index.js +743 -1123
- package/dist/index.js.map +1 -1
- package/dist/ui/index.cjs +126 -126
- package/dist/ui/index.d.cts +12 -12
- package/dist/ui/index.d.ts +12 -12
- package/dist/ui/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-3CLGHHME.js.map +0 -1
- package/dist/chunk-OU2QLIKS.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { formatRelativeTime } from './chunk-EJ2BMHYK.js';
|
|
2
2
|
export { DEFAULT_NOTIFY_TONE, NotificationBell, Toaster, formatRelativeTime, notify, seedNotifications, selectUnread, toast, useNotify } from './chunk-EJ2BMHYK.js';
|
|
3
|
-
import { MarkMenu, AiMarkdown, Card, Button, Badge, TagEntity, MarkdownRenderer, Input, FILE_TYPE_COLORS, getEntityIcon, UserEntity, getEntityColorStyles, AgentBadge, Textarea, Slider, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DocumentEntity, DocumentCard, useAudioRecorder, MicWaveformIndicator, IconToggle, classifyMediaError, formatElapsed, PassageCard } from './chunk-
|
|
4
|
-
export { AgentBadge, AiMarkdown, ArbiBotHeadIcon, AudIcon, Avatar, AvatarFallback, AvatarImage, BASE_COLORS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DocumentCard, DocumentEntity, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, ImgIcon, InlineMicButton, Input, Label, MarkMenu, MarkdownRenderer, MarkdownStreamingContext, MicRecordingOverlay, MicWaveformIndicator, NEUTRAL_GRAY, PLACEHOLDER_COLOR, PassageCard, PdfIcon, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PresenceLabel, Progress, ProjectEntity, RadioGroup, RadioGroupItem, RagDot, RelevanceDot, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Slider, StatusPill, Switch, TAG_TYPE_ICONS, TAG_TYPE_LABELS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagEntity, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserEntity, UserMenu, VISIBILITY_ICONS, VidIcon, VisibilityIcon, badgeVariants, buttonVariants, cardVariants, configureEntityRegistry, configureRagLabels, configureStatusRegistry, formatElapsed, getDocIcon, getEntityColor, getEntityColorStyles, getEntityIcon, getEntityLabel, getStatusVariant, getTagTypeIcon, getTagTypeLabel, getWorkspaceColor, markdownBaseComponents, splitMarkdownBlocks, toggleVariants, useAudioRecorder } from './chunk-
|
|
3
|
+
import { normalizeCitationMarkup, MarkMenu, AiMarkdown, Card, Button, Badge, TagEntity, MarkdownRenderer, Input, FILE_TYPE_COLORS, getEntityIcon, UserEntity, getEntityColorStyles, AgentBadge, Textarea, Label, Slider, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DocumentEntity, DocumentCard, useAudioRecorder, MicWaveformIndicator, IconToggle, classifyMediaError, formatElapsed, PassageCard } from './chunk-MIJRORQL.js';
|
|
4
|
+
export { AgentBadge, AiMarkdown, ArbiBotHeadIcon, AudIcon, Avatar, AvatarFallback, AvatarImage, BASE_COLORS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DocumentCard, DocumentEntity, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, ImgIcon, InlineMicButton, Input, Label, MarkMenu, MarkdownRenderer, MarkdownStreamingContext, MicRecordingOverlay, MicWaveformIndicator, NEUTRAL_GRAY, PLACEHOLDER_COLOR, PassageCard, PdfIcon, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PresenceLabel, Progress, ProjectEntity, RadioGroup, RadioGroupItem, RagDot, RelevanceDot, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Slider, StatusPill, Switch, TAG_TYPE_ICONS, TAG_TYPE_LABELS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagEntity, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserEntity, UserMenu, VISIBILITY_ICONS, VidIcon, VisibilityIcon, badgeVariants, buttonVariants, cardVariants, configureEntityRegistry, configureRagLabels, configureStatusRegistry, formatElapsed, getDocIcon, getEntityColor, getEntityColorStyles, getEntityIcon, getEntityLabel, getStatusVariant, getTagTypeIcon, getTagTypeLabel, getWorkspaceColor, markdownBaseComponents, normalizeCitationMarkup, splitMarkdownBlocks, toggleVariants, useAudioRecorder } from './chunk-MIJRORQL.js';
|
|
5
5
|
import { cn, ScrollArea, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from './chunk-6ALMBER7.js';
|
|
6
6
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ScrollArea, ScrollBar, cn } from './chunk-6ALMBER7.js';
|
|
7
|
-
import { useArbi,
|
|
7
|
+
import { useArbi, AudioViewer, ImageViewer, VideoViewer } from './chunk-JKO3NR5L.js';
|
|
8
8
|
export { ArbiProvider, useArbi } from './chunk-JKO3NR5L.js';
|
|
9
9
|
import React, { memo, useState, createContext, useMemo, useCallback, useEffect, useRef, useLayoutEffect, useContext, useId, Fragment as Fragment$1 } from 'react';
|
|
10
|
-
import { useQuery, useMutation, useQueries,
|
|
10
|
+
import { useQuery, useMutation, useQueries, useQueryClient } from '@tanstack/react-query';
|
|
11
|
+
import { Link, Trash2, CheckCheck, Check, Loader2, AlertTriangle, ShieldCheck, Copy, Sparkles, FileText, GitCompareArrows, Download, Image as Image$1, Search, CornerDownLeft, X, ArrowLeft, Send, Tags, Crown, Info, Activity, Gauge, Gift, PartyPopper, UserCheck, MessageCircleMore, FileX2, FileCheck2, Pencil, FolderPlus, SquareArrowOutUpRight, MessagesSquare, ArrowRight, MoreHorizontal, SquarePen, Mic, Pause, Play, Square, RotateCcw, Camera, Circle } from 'lucide-react';
|
|
11
12
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
|
-
import { connectWithReconnect
|
|
13
|
+
import { connectWithReconnect } from '@arbidocs/sdk/browser';
|
|
13
14
|
export { Arbi, ArbiError } from '@arbidocs/sdk/browser';
|
|
14
|
-
import { Link, Trash2, CheckCheck, Check, Loader2, AlertTriangle, ShieldCheck, Copy, Sparkles, FileText, GitCompareArrows, Download, Image as Image$1, Search, CornerDownLeft, X, ArrowLeft, Send, Tags, Crown, Info, Activity, Gauge, Gift, PartyPopper, UserCheck, MessageCircleMore, FileX2, FileCheck2, Pencil, FolderPlus, SquareArrowOutUpRight, MessagesSquare, ArrowRight, MoreHorizontal, SquarePen, Mic, Pause, Play, Square, RotateCcw, Camera, Circle } from 'lucide-react';
|
|
15
15
|
import { isMessageType } from '@arbidocs/client';
|
|
16
16
|
export { isMessageType } from '@arbidocs/client';
|
|
17
17
|
import { create } from 'zustand';
|
|
@@ -23,566 +23,23 @@ import Cropper from 'react-easy-crop';
|
|
|
23
23
|
import { AgGridReact } from 'ag-grid-react';
|
|
24
24
|
import { ModuleRegistry, AllCommunityModule } from 'ag-grid-community';
|
|
25
25
|
|
|
26
|
-
// src/
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
borderColor: "#e5e7eb",
|
|
34
|
-
userBubbleColor: "#f3f4f6",
|
|
35
|
-
userBubbleTextColor: "#111827",
|
|
36
|
-
assistantBubbleColor: "rgba(0, 173, 239, 0.08)",
|
|
37
|
-
assistantBubbleTextColor: "#111827",
|
|
38
|
-
borderRadius: "8px",
|
|
39
|
-
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
|
40
|
-
};
|
|
41
|
-
var DEFAULT_LABELS = {
|
|
42
|
-
title: "Chat",
|
|
43
|
-
email: "Email",
|
|
44
|
-
password: "Password",
|
|
45
|
-
loginButton: "Log in",
|
|
46
|
-
loginButtonLoading: "Logging in...",
|
|
47
|
-
registerButton: "Create account",
|
|
48
|
-
sendCodeButton: "Email me a code",
|
|
49
|
-
haveCodeButton: "I have an invitation code",
|
|
50
|
-
verificationCode: "Verification code",
|
|
51
|
-
confirmPassword: "Confirm password",
|
|
52
|
-
firstName: "First name",
|
|
53
|
-
lastName: "Last name",
|
|
54
|
-
switchToRegister: "Create account",
|
|
55
|
-
switchToLogin: "Back to login",
|
|
56
|
-
selectWorkspace: "Select a workspace",
|
|
57
|
-
workspacePlaceholder: "Choose...",
|
|
58
|
-
continueButton: "Continue",
|
|
59
|
-
createWorkspace: "Create new workspace",
|
|
60
|
-
workspaceName: "Workspace name",
|
|
61
|
-
createButton: "Create",
|
|
62
|
-
changeWorkspace: "Change workspace",
|
|
63
|
-
documents: "Documents",
|
|
64
|
-
sendButton: "Send",
|
|
65
|
-
placeholder: "Ask a question...",
|
|
66
|
-
uploadButton: "Upload",
|
|
67
|
-
uploading: "Uploading...",
|
|
68
|
-
emptyNoDocs: "No documents found in this workspace.",
|
|
69
|
-
emptyNoSelection: "Select at least one document to start chatting.",
|
|
70
|
-
emptyReady: "Ask a question about your documents."
|
|
71
|
-
};
|
|
72
|
-
function getTheme(partial) {
|
|
73
|
-
return { ...DEFAULT_THEME, ...partial };
|
|
74
|
-
}
|
|
75
|
-
function getLabels(partial) {
|
|
76
|
-
return { ...DEFAULT_LABELS, ...partial };
|
|
77
|
-
}
|
|
78
|
-
function containerStyle(theme, width, height) {
|
|
79
|
-
return {
|
|
80
|
-
width: typeof width === "number" ? `${width}px` : width,
|
|
81
|
-
height: typeof height === "number" ? `${height}px` : height,
|
|
82
|
-
display: "flex",
|
|
83
|
-
flexDirection: "column",
|
|
84
|
-
fontFamily: theme.fontFamily,
|
|
85
|
-
fontSize: "14px",
|
|
86
|
-
lineHeight: "1.5",
|
|
87
|
-
color: theme.textColor,
|
|
88
|
-
backgroundColor: theme.backgroundColor,
|
|
89
|
-
border: `1px solid ${theme.borderColor}`,
|
|
90
|
-
borderRadius: theme.borderRadius,
|
|
91
|
-
overflow: "hidden",
|
|
92
|
-
boxSizing: "border-box"
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function headerStyle(theme) {
|
|
96
|
-
return {
|
|
97
|
-
display: "flex",
|
|
98
|
-
alignItems: "center",
|
|
99
|
-
padding: "12px 16px",
|
|
100
|
-
fontWeight: 600,
|
|
101
|
-
fontSize: "15px",
|
|
102
|
-
borderBottom: `1px solid ${theme.borderColor}`,
|
|
103
|
-
flexShrink: 0
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function bodyStyle() {
|
|
107
|
-
return {
|
|
108
|
-
flex: 1,
|
|
109
|
-
display: "flex",
|
|
110
|
-
flexDirection: "column",
|
|
111
|
-
overflow: "hidden"
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
function formContainerStyle() {
|
|
115
|
-
return {
|
|
116
|
-
flex: 1,
|
|
117
|
-
display: "flex",
|
|
118
|
-
flexDirection: "column",
|
|
119
|
-
justifyContent: "center",
|
|
120
|
-
padding: "24px 16px",
|
|
121
|
-
gap: "12px"
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
function labelStyle(theme) {
|
|
125
|
-
return {
|
|
126
|
-
fontSize: "13px",
|
|
127
|
-
fontWeight: 500,
|
|
128
|
-
color: theme.textColor,
|
|
129
|
-
marginBottom: "4px"
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
function inputStyle(theme) {
|
|
133
|
-
return {
|
|
134
|
-
width: "100%",
|
|
135
|
-
padding: "8px 12px",
|
|
136
|
-
fontSize: "14px",
|
|
137
|
-
fontFamily: theme.fontFamily,
|
|
138
|
-
color: theme.textColor,
|
|
139
|
-
backgroundColor: theme.backgroundColor,
|
|
140
|
-
border: `1px solid ${theme.borderColor}`,
|
|
141
|
-
borderRadius: "8px",
|
|
142
|
-
outline: "none",
|
|
143
|
-
boxSizing: "border-box"
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
function selectStyle(theme) {
|
|
147
|
-
return {
|
|
148
|
-
...inputStyle(theme),
|
|
149
|
-
cursor: "pointer",
|
|
150
|
-
appearance: "auto"
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
function buttonStyle(theme, disabled) {
|
|
154
|
-
return {
|
|
155
|
-
padding: "8px 16px",
|
|
156
|
-
fontSize: "14px",
|
|
157
|
-
fontWeight: 500,
|
|
158
|
-
fontFamily: theme.fontFamily,
|
|
159
|
-
color: "#ffffff",
|
|
160
|
-
backgroundColor: disabled ? theme.mutedColor : theme.primaryColor,
|
|
161
|
-
border: "none",
|
|
162
|
-
borderRadius: "8px",
|
|
163
|
-
cursor: disabled ? "not-allowed" : "pointer",
|
|
164
|
-
opacity: disabled ? 0.6 : 1,
|
|
165
|
-
transition: "opacity 150ms"
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
function errorStyle() {
|
|
169
|
-
return {
|
|
170
|
-
fontSize: "13px",
|
|
171
|
-
color: "#ef4444",
|
|
172
|
-
margin: "4px 0 0"
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
function messagesContainerStyle() {
|
|
176
|
-
return {
|
|
177
|
-
flex: 1,
|
|
178
|
-
overflowY: "auto",
|
|
179
|
-
padding: "12px 16px",
|
|
180
|
-
display: "flex",
|
|
181
|
-
flexDirection: "column",
|
|
182
|
-
gap: "8px"
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
function messageBubbleStyle(theme, role) {
|
|
186
|
-
const isUser = role === "user";
|
|
187
|
-
return {
|
|
188
|
-
maxWidth: "85%",
|
|
189
|
-
padding: "8px 12px",
|
|
190
|
-
borderRadius: "12px",
|
|
191
|
-
fontSize: "14px",
|
|
192
|
-
lineHeight: "1.5",
|
|
193
|
-
wordBreak: "break-word",
|
|
194
|
-
whiteSpace: "pre-wrap",
|
|
195
|
-
alignSelf: isUser ? "flex-end" : "flex-start",
|
|
196
|
-
backgroundColor: isUser ? theme.userBubbleColor : theme.assistantBubbleColor,
|
|
197
|
-
color: isUser ? theme.userBubbleTextColor : theme.assistantBubbleTextColor
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
function inputBarStyle(theme) {
|
|
201
|
-
return {
|
|
202
|
-
display: "flex",
|
|
203
|
-
gap: "8px",
|
|
204
|
-
padding: "12px 16px",
|
|
205
|
-
borderTop: `1px solid ${theme.borderColor}`,
|
|
206
|
-
flexShrink: 0
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
function chatInputStyle(theme) {
|
|
210
|
-
return {
|
|
211
|
-
...inputStyle(theme),
|
|
212
|
-
flex: 1
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
function sendButtonStyle(theme, disabled) {
|
|
216
|
-
return {
|
|
217
|
-
...buttonStyle(theme, disabled),
|
|
218
|
-
padding: "8px 14px",
|
|
219
|
-
flexShrink: 0
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
function docSelectorStyle(theme) {
|
|
223
|
-
return {
|
|
224
|
-
padding: "8px 16px",
|
|
225
|
-
borderBottom: `1px solid ${theme.borderColor}`,
|
|
226
|
-
flexShrink: 0
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
function docToggleStyle(theme) {
|
|
230
|
-
return {
|
|
231
|
-
display: "flex",
|
|
232
|
-
alignItems: "center",
|
|
233
|
-
gap: "6px",
|
|
234
|
-
fontSize: "13px",
|
|
235
|
-
fontWeight: 500,
|
|
236
|
-
color: theme.mutedColor,
|
|
237
|
-
cursor: "pointer",
|
|
238
|
-
background: "none",
|
|
239
|
-
border: "none",
|
|
240
|
-
padding: 0,
|
|
241
|
-
fontFamily: theme.fontFamily
|
|
242
|
-
};
|
|
26
|
+
// src/credits.ts
|
|
27
|
+
var DEFAULT_USD_PER_CREDIT = 0.01;
|
|
28
|
+
function formatCredits(credits, options = {}) {
|
|
29
|
+
const { unit = true, locale = "en-US" } = options;
|
|
30
|
+
const whole = Math.round(Number.isFinite(credits) ? credits : 0);
|
|
31
|
+
const digits = whole.toLocaleString(locale);
|
|
32
|
+
return unit ? `${digits} ${whole === 1 ? "credit" : "credits"}` : digits;
|
|
243
33
|
}
|
|
244
|
-
function
|
|
245
|
-
return
|
|
246
|
-
marginTop: "6px",
|
|
247
|
-
display: "flex",
|
|
248
|
-
flexDirection: "column",
|
|
249
|
-
gap: "4px",
|
|
250
|
-
maxHeight: "120px",
|
|
251
|
-
overflowY: "auto"
|
|
252
|
-
};
|
|
34
|
+
function creditsToUsd(credits, usdPerCredit = DEFAULT_USD_PER_CREDIT) {
|
|
35
|
+
return credits * usdPerCredit;
|
|
253
36
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
alignItems: "center",
|
|
258
|
-
gap: "6px",
|
|
259
|
-
fontSize: "13px",
|
|
260
|
-
color: theme.textColor,
|
|
261
|
-
cursor: "pointer",
|
|
262
|
-
textAlign: "left"
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
function emptyStateStyle(theme) {
|
|
266
|
-
return {
|
|
267
|
-
flex: 1,
|
|
268
|
-
display: "flex",
|
|
269
|
-
alignItems: "center",
|
|
270
|
-
justifyContent: "center",
|
|
271
|
-
color: theme.mutedColor,
|
|
272
|
-
fontSize: "13px",
|
|
273
|
-
padding: "24px",
|
|
274
|
-
textAlign: "center"
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
function loadingContainerStyle() {
|
|
278
|
-
return {
|
|
279
|
-
flex: 1,
|
|
280
|
-
display: "flex",
|
|
281
|
-
alignItems: "center",
|
|
282
|
-
justifyContent: "center",
|
|
283
|
-
gap: "8px",
|
|
284
|
-
fontSize: "13px"
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
function brandingStyle(theme) {
|
|
288
|
-
return {
|
|
289
|
-
display: "flex",
|
|
290
|
-
alignItems: "center",
|
|
291
|
-
justifyContent: "center",
|
|
292
|
-
gap: "4px",
|
|
293
|
-
padding: "6px 16px",
|
|
294
|
-
fontSize: "11px",
|
|
295
|
-
color: theme.mutedColor,
|
|
296
|
-
borderTop: `1px solid ${theme.borderColor}`,
|
|
297
|
-
flexShrink: 0,
|
|
298
|
-
userSelect: "none"
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
function brandingLinkStyle(theme) {
|
|
302
|
-
return {
|
|
303
|
-
color: theme.mutedColor,
|
|
304
|
-
fontWeight: 600,
|
|
305
|
-
textDecoration: "none"
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
function linkButtonStyle(theme) {
|
|
309
|
-
return {
|
|
310
|
-
background: "none",
|
|
311
|
-
border: "none",
|
|
312
|
-
padding: 0,
|
|
313
|
-
fontSize: "13px",
|
|
314
|
-
color: theme.primaryColor,
|
|
315
|
-
cursor: "pointer",
|
|
316
|
-
fontFamily: theme.fontFamily,
|
|
317
|
-
textDecoration: "underline"
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function secondaryButtonStyle(theme, disabled) {
|
|
321
|
-
return {
|
|
322
|
-
padding: "4px 10px",
|
|
323
|
-
fontSize: "12px",
|
|
324
|
-
fontWeight: 500,
|
|
325
|
-
fontFamily: theme.fontFamily,
|
|
326
|
-
color: disabled ? theme.mutedColor : theme.primaryColor,
|
|
327
|
-
backgroundColor: "transparent",
|
|
328
|
-
border: `1px solid ${disabled ? theme.borderColor : theme.primaryColor}`,
|
|
329
|
-
borderRadius: "6px",
|
|
330
|
-
cursor: disabled ? "not-allowed" : "pointer",
|
|
331
|
-
opacity: disabled ? 0.6 : 1,
|
|
332
|
-
transition: "opacity 150ms",
|
|
333
|
-
whiteSpace: "nowrap"
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
function fileInputStyle() {
|
|
337
|
-
return { display: "none" };
|
|
338
|
-
}
|
|
339
|
-
function agentStatusStyle(theme) {
|
|
340
|
-
return {
|
|
341
|
-
fontSize: "12px",
|
|
342
|
-
color: theme.mutedColor,
|
|
343
|
-
fontStyle: "italic",
|
|
344
|
-
padding: "4px 0",
|
|
345
|
-
alignSelf: "flex-start"
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
function AuthScreen({ theme, labels, onLogin }) {
|
|
349
|
-
const arbi = useArbi();
|
|
350
|
-
const [mode, setMode] = useState("login");
|
|
351
|
-
const [step, setStep] = useState("email");
|
|
352
|
-
const [email, setEmail] = useState("");
|
|
353
|
-
const [password, setPassword] = useState("");
|
|
354
|
-
const [confirmPw, setConfirmPw] = useState("");
|
|
355
|
-
const [code, setCode] = useState("");
|
|
356
|
-
const [firstName, setFirstName] = useState("");
|
|
357
|
-
const [lastName, setLastName] = useState("");
|
|
358
|
-
const [loading, setLoading] = useState(false);
|
|
359
|
-
const [error, setError] = useState("");
|
|
360
|
-
const resetForm = () => {
|
|
361
|
-
setPassword("");
|
|
362
|
-
setConfirmPw("");
|
|
363
|
-
setCode("");
|
|
364
|
-
setFirstName("");
|
|
365
|
-
setLastName("");
|
|
366
|
-
setError("");
|
|
367
|
-
setStep("email");
|
|
368
|
-
};
|
|
369
|
-
const switchMode = (next) => {
|
|
370
|
-
resetForm();
|
|
371
|
-
setMode(next);
|
|
372
|
-
};
|
|
373
|
-
const handleLogin = async (e) => {
|
|
374
|
-
e.preventDefault();
|
|
375
|
-
setLoading(true);
|
|
376
|
-
setError("");
|
|
377
|
-
try {
|
|
378
|
-
await arbi.login(email, password);
|
|
379
|
-
onLogin();
|
|
380
|
-
} catch (err) {
|
|
381
|
-
setError(err instanceof Error ? err.message : "Login failed");
|
|
382
|
-
} finally {
|
|
383
|
-
setLoading(false);
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
const handleHaveCode = () => {
|
|
387
|
-
setError("");
|
|
388
|
-
setStep("verify");
|
|
389
|
-
};
|
|
390
|
-
const handleEmailCode = async () => {
|
|
391
|
-
if (!email) return;
|
|
392
|
-
setLoading(true);
|
|
393
|
-
setError("");
|
|
394
|
-
try {
|
|
395
|
-
await arbi.requestVerification(email);
|
|
396
|
-
setStep("verify");
|
|
397
|
-
} catch (err) {
|
|
398
|
-
setError(err instanceof Error ? err.message : "Failed to send verification code");
|
|
399
|
-
} finally {
|
|
400
|
-
setLoading(false);
|
|
401
|
-
}
|
|
402
|
-
};
|
|
403
|
-
const handleRegister = async (e) => {
|
|
404
|
-
e.preventDefault();
|
|
405
|
-
if (password !== confirmPw) {
|
|
406
|
-
setError("Passwords do not match");
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
setLoading(true);
|
|
410
|
-
setError("");
|
|
411
|
-
try {
|
|
412
|
-
await arbi.register({ email, password, verificationCode: code, firstName, lastName });
|
|
413
|
-
await arbi.login(email, password);
|
|
414
|
-
onLogin();
|
|
415
|
-
} catch (err) {
|
|
416
|
-
setError(err instanceof Error ? err.message : "Registration failed");
|
|
417
|
-
} finally {
|
|
418
|
-
setLoading(false);
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
if (mode === "login") {
|
|
422
|
-
return /* @__PURE__ */ jsxs("form", { onSubmit: handleLogin, style: formContainerStyle(), children: [
|
|
423
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
424
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.email }),
|
|
425
|
-
/* @__PURE__ */ jsx(
|
|
426
|
-
"input",
|
|
427
|
-
{
|
|
428
|
-
type: "email",
|
|
429
|
-
value: email,
|
|
430
|
-
onChange: (e) => setEmail(e.target.value),
|
|
431
|
-
placeholder: "you@example.com",
|
|
432
|
-
autoComplete: "email",
|
|
433
|
-
required: true,
|
|
434
|
-
style: inputStyle(theme)
|
|
435
|
-
}
|
|
436
|
-
)
|
|
437
|
-
] }),
|
|
438
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
439
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.password }),
|
|
440
|
-
/* @__PURE__ */ jsx(
|
|
441
|
-
"input",
|
|
442
|
-
{
|
|
443
|
-
type: "password",
|
|
444
|
-
value: password,
|
|
445
|
-
onChange: (e) => setPassword(e.target.value),
|
|
446
|
-
autoComplete: "current-password",
|
|
447
|
-
required: true,
|
|
448
|
-
style: inputStyle(theme)
|
|
449
|
-
}
|
|
450
|
-
)
|
|
451
|
-
] }),
|
|
452
|
-
/* @__PURE__ */ jsx("button", { type: "submit", disabled: loading, style: buttonStyle(theme, loading), children: loading ? labels.loginButtonLoading : labels.loginButton }),
|
|
453
|
-
error && /* @__PURE__ */ jsx("div", { style: errorStyle(), children: error }),
|
|
454
|
-
/* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(
|
|
455
|
-
"button",
|
|
456
|
-
{
|
|
457
|
-
type: "button",
|
|
458
|
-
onClick: () => switchMode("register"),
|
|
459
|
-
style: linkButtonStyle(theme),
|
|
460
|
-
children: labels.switchToRegister
|
|
461
|
-
}
|
|
462
|
-
) })
|
|
463
|
-
] });
|
|
464
|
-
}
|
|
465
|
-
if (step === "email") {
|
|
466
|
-
const noEmail = !email.trim();
|
|
467
|
-
return /* @__PURE__ */ jsxs("div", { style: formContainerStyle(), children: [
|
|
468
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
469
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.email }),
|
|
470
|
-
/* @__PURE__ */ jsx(
|
|
471
|
-
"input",
|
|
472
|
-
{
|
|
473
|
-
type: "email",
|
|
474
|
-
value: email,
|
|
475
|
-
onChange: (e) => setEmail(e.target.value),
|
|
476
|
-
placeholder: "you@example.com",
|
|
477
|
-
autoComplete: "email",
|
|
478
|
-
style: inputStyle(theme)
|
|
479
|
-
}
|
|
480
|
-
)
|
|
481
|
-
] }),
|
|
482
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
483
|
-
/* @__PURE__ */ jsx(
|
|
484
|
-
"button",
|
|
485
|
-
{
|
|
486
|
-
type: "button",
|
|
487
|
-
onClick: handleHaveCode,
|
|
488
|
-
disabled: noEmail,
|
|
489
|
-
style: { ...buttonStyle(theme, noEmail), flex: 1 },
|
|
490
|
-
children: labels.haveCodeButton
|
|
491
|
-
}
|
|
492
|
-
),
|
|
493
|
-
/* @__PURE__ */ jsx(
|
|
494
|
-
"button",
|
|
495
|
-
{
|
|
496
|
-
type: "button",
|
|
497
|
-
onClick: handleEmailCode,
|
|
498
|
-
disabled: noEmail || loading,
|
|
499
|
-
style: { ...buttonStyle(theme, noEmail || loading), flex: 1 },
|
|
500
|
-
children: loading ? "..." : labels.sendCodeButton
|
|
501
|
-
}
|
|
502
|
-
)
|
|
503
|
-
] }),
|
|
504
|
-
error && /* @__PURE__ */ jsx("div", { style: errorStyle(), children: error }),
|
|
505
|
-
/* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx("button", { type: "button", onClick: () => switchMode("login"), style: linkButtonStyle(theme), children: labels.switchToLogin }) })
|
|
506
|
-
] });
|
|
507
|
-
}
|
|
508
|
-
return /* @__PURE__ */ jsxs("form", { onSubmit: handleRegister, style: formContainerStyle(), children: [
|
|
509
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
510
|
-
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
511
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.firstName }),
|
|
512
|
-
/* @__PURE__ */ jsx(
|
|
513
|
-
"input",
|
|
514
|
-
{
|
|
515
|
-
type: "text",
|
|
516
|
-
value: firstName,
|
|
517
|
-
onChange: (e) => setFirstName(e.target.value),
|
|
518
|
-
autoComplete: "given-name",
|
|
519
|
-
required: true,
|
|
520
|
-
style: inputStyle(theme)
|
|
521
|
-
}
|
|
522
|
-
)
|
|
523
|
-
] }),
|
|
524
|
-
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
525
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.lastName }),
|
|
526
|
-
/* @__PURE__ */ jsx(
|
|
527
|
-
"input",
|
|
528
|
-
{
|
|
529
|
-
type: "text",
|
|
530
|
-
value: lastName,
|
|
531
|
-
onChange: (e) => setLastName(e.target.value),
|
|
532
|
-
autoComplete: "family-name",
|
|
533
|
-
required: true,
|
|
534
|
-
style: inputStyle(theme)
|
|
535
|
-
}
|
|
536
|
-
)
|
|
537
|
-
] })
|
|
538
|
-
] }),
|
|
539
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
540
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.verificationCode }),
|
|
541
|
-
/* @__PURE__ */ jsx(
|
|
542
|
-
"input",
|
|
543
|
-
{
|
|
544
|
-
type: "text",
|
|
545
|
-
value: code,
|
|
546
|
-
onChange: (e) => setCode(e.target.value),
|
|
547
|
-
autoComplete: "one-time-code",
|
|
548
|
-
required: true,
|
|
549
|
-
style: inputStyle(theme)
|
|
550
|
-
}
|
|
551
|
-
)
|
|
552
|
-
] }),
|
|
553
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
554
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.password }),
|
|
555
|
-
/* @__PURE__ */ jsx(
|
|
556
|
-
"input",
|
|
557
|
-
{
|
|
558
|
-
type: "password",
|
|
559
|
-
value: password,
|
|
560
|
-
onChange: (e) => setPassword(e.target.value),
|
|
561
|
-
autoComplete: "new-password",
|
|
562
|
-
required: true,
|
|
563
|
-
style: inputStyle(theme)
|
|
564
|
-
}
|
|
565
|
-
)
|
|
566
|
-
] }),
|
|
567
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
568
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.confirmPassword }),
|
|
569
|
-
/* @__PURE__ */ jsx(
|
|
570
|
-
"input",
|
|
571
|
-
{
|
|
572
|
-
type: "password",
|
|
573
|
-
value: confirmPw,
|
|
574
|
-
onChange: (e) => setConfirmPw(e.target.value),
|
|
575
|
-
autoComplete: "new-password",
|
|
576
|
-
required: true,
|
|
577
|
-
style: inputStyle(theme)
|
|
578
|
-
}
|
|
579
|
-
)
|
|
580
|
-
] }),
|
|
581
|
-
/* @__PURE__ */ jsx("button", { type: "submit", disabled: loading, style: buttonStyle(theme, loading), children: loading ? "..." : labels.registerButton }),
|
|
582
|
-
error && /* @__PURE__ */ jsx("div", { style: errorStyle(), children: error }),
|
|
583
|
-
/* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx("button", { type: "button", onClick: () => switchMode("login"), style: linkButtonStyle(theme), children: labels.switchToLogin }) })
|
|
584
|
-
] });
|
|
37
|
+
function isUsageMetered(usage, subscription) {
|
|
38
|
+
const empty = usage.total_spend === 0 && usage.total_tokens === 0 && usage.total_requests === 0;
|
|
39
|
+
return !(empty && subscription === "dev");
|
|
585
40
|
}
|
|
41
|
+
|
|
42
|
+
// src/hooks.ts
|
|
586
43
|
var arbiQueryKeys = {
|
|
587
44
|
workspaces: () => ["arbi", "workspaces"],
|
|
588
45
|
documents: (workspaceId) => ["arbi", "documents", workspaceId],
|
|
@@ -600,7 +57,14 @@ var arbiQueryKeys = {
|
|
|
600
57
|
projects: () => ["arbi", "projects"],
|
|
601
58
|
projectUsage: (projectExtId, monthsBack) => ["arbi", "projectUsage", projectExtId, monthsBack],
|
|
602
59
|
projectInvoices: (projectExtId) => ["arbi", "projectInvoices", projectExtId],
|
|
603
|
-
userUsageToday: () => ["arbi", "userUsageToday"]
|
|
60
|
+
userUsageToday: () => ["arbi", "userUsageToday"],
|
|
61
|
+
contacts: () => ["arbi", "contacts"],
|
|
62
|
+
skills: () => ["arbi", "skills"],
|
|
63
|
+
taskRuns: (taskId) => ["arbi", "taskRuns", taskId],
|
|
64
|
+
/** An agent's pinned config; `undefined` = the library default config. */
|
|
65
|
+
agentConfig: (agentExtId) => ["arbi", "agentConfig", agentExtId ?? "default"],
|
|
66
|
+
agentWorkspaces: (agentExtId) => ["arbi", "agentWorkspaces", agentExtId],
|
|
67
|
+
models: () => ["arbi", "models"]
|
|
604
68
|
};
|
|
605
69
|
function useWorkspaces(options) {
|
|
606
70
|
const arbi = useArbi();
|
|
@@ -729,15 +193,20 @@ function useProjects(options) {
|
|
|
729
193
|
}
|
|
730
194
|
function useProjectUsage(projectExtId, monthsBack = 0, options) {
|
|
731
195
|
const arbi = useArbi();
|
|
732
|
-
|
|
196
|
+
const usage = useQuery({
|
|
733
197
|
queryKey: arbiQueryKeys.projectUsage(projectExtId ?? "", monthsBack),
|
|
734
198
|
queryFn: () => arbi.projects.usage(projectExtId, monthsBack),
|
|
735
199
|
enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn
|
|
736
200
|
});
|
|
201
|
+
const projects = useProjects({ enabled: !!projectExtId && (options?.enabled ?? true) });
|
|
202
|
+
const subscription = projects.data?.find((p) => p.external_id === projectExtId)?.subscription;
|
|
203
|
+
const metered = usage.data ? isUsageMetered(usage.data, subscription) : void 0;
|
|
204
|
+
return { ...usage, metered };
|
|
737
205
|
}
|
|
738
206
|
function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
739
207
|
const arbi = useArbi();
|
|
740
208
|
const enabled = (options?.enabled ?? true) && arbi.isLoggedIn;
|
|
209
|
+
const projects = useProjects({ enabled: enabled && projectExtIds.length > 0 });
|
|
741
210
|
const results = useQueries({
|
|
742
211
|
queries: projectExtIds.map((id) => ({
|
|
743
212
|
queryKey: arbiQueryKeys.projectUsage(id, monthsBack),
|
|
@@ -745,27 +214,34 @@ function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
|
745
214
|
enabled: enabled && !!id
|
|
746
215
|
}))
|
|
747
216
|
});
|
|
748
|
-
const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join("|")
|
|
217
|
+
const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join("|") + `#${projects.dataUpdatedAt}`;
|
|
749
218
|
return useMemo(() => {
|
|
750
219
|
const dailyMap = /* @__PURE__ */ new Map();
|
|
751
220
|
const modelMap = /* @__PURE__ */ new Map();
|
|
752
|
-
let
|
|
221
|
+
let totalCredits = 0;
|
|
222
|
+
let anyData = false;
|
|
223
|
+
let anyMetered = false;
|
|
753
224
|
let totalTokens = 0;
|
|
754
225
|
let totalRequests = 0;
|
|
755
|
-
|
|
226
|
+
results.forEach((r, i) => {
|
|
756
227
|
const d = r.data;
|
|
757
|
-
if (!d)
|
|
758
|
-
|
|
228
|
+
if (!d) return;
|
|
229
|
+
anyData = true;
|
|
230
|
+
const subscription = projects.data?.find(
|
|
231
|
+
(p) => p.external_id === projectExtIds[i]
|
|
232
|
+
)?.subscription;
|
|
233
|
+
if (isUsageMetered(d, subscription)) anyMetered = true;
|
|
234
|
+
totalCredits += d.total_spend ?? 0;
|
|
759
235
|
totalTokens += d.total_tokens ?? 0;
|
|
760
236
|
totalRequests += d.total_requests ?? 0;
|
|
761
237
|
for (const day of d.daily ?? []) {
|
|
762
238
|
const cur = dailyMap.get(day.date) ?? {
|
|
763
239
|
date: day.date,
|
|
764
|
-
|
|
240
|
+
credits: 0,
|
|
765
241
|
totalTokens: 0,
|
|
766
242
|
apiRequests: 0
|
|
767
243
|
};
|
|
768
|
-
cur.
|
|
244
|
+
cur.credits += day.spend ?? 0;
|
|
769
245
|
cur.totalTokens += day.total_tokens ?? 0;
|
|
770
246
|
cur.apiRequests += day.api_requests ?? 0;
|
|
771
247
|
dailyMap.set(day.date, cur);
|
|
@@ -773,567 +249,264 @@ function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
|
773
249
|
for (const [model, mg] of Object.entries(d.model_groups ?? {})) {
|
|
774
250
|
const cur = modelMap.get(model) ?? {
|
|
775
251
|
model,
|
|
776
|
-
|
|
252
|
+
credits: 0,
|
|
777
253
|
totalTokens: 0,
|
|
778
254
|
promptTokens: 0,
|
|
779
255
|
completionTokens: 0,
|
|
780
256
|
successfulRequests: 0
|
|
781
257
|
};
|
|
782
|
-
cur.
|
|
258
|
+
cur.credits += mg.spend ?? 0;
|
|
783
259
|
cur.totalTokens += mg.total_tokens ?? 0;
|
|
784
260
|
cur.promptTokens += mg.prompt_tokens ?? 0;
|
|
785
261
|
cur.completionTokens += mg.completion_tokens ?? 0;
|
|
786
262
|
cur.successfulRequests += mg.successful_requests ?? 0;
|
|
787
263
|
modelMap.set(model, cur);
|
|
788
264
|
}
|
|
789
|
-
}
|
|
265
|
+
});
|
|
790
266
|
return {
|
|
791
|
-
|
|
267
|
+
totalCredits,
|
|
792
268
|
totalTokens,
|
|
793
269
|
totalRequests,
|
|
794
|
-
daily: [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date)),
|
|
795
|
-
modelGroups: [...modelMap.values()].sort(
|
|
796
|
-
(a, b) => b.
|
|
797
|
-
),
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
}
|
|
803
|
-
function useProjectInvoices(projectExtId, options) {
|
|
804
|
-
const arbi = useArbi();
|
|
805
|
-
return useQuery({
|
|
806
|
-
queryKey: arbiQueryKeys.projectInvoices(projectExtId ?? ""),
|
|
807
|
-
queryFn: () => arbi.projects.invoices(projectExtId),
|
|
808
|
-
enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn
|
|
809
|
-
});
|
|
810
|
-
}
|
|
811
|
-
function useUserUsageToday(options) {
|
|
812
|
-
const arbi = useArbi();
|
|
813
|
-
return useQuery({
|
|
814
|
-
queryKey: arbiQueryKeys.userUsageToday(),
|
|
815
|
-
queryFn: () => arbi.user.usageToday(),
|
|
816
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
function WorkspaceScreen({ theme, labels, onSelect }) {
|
|
820
|
-
const arbi = useArbi();
|
|
821
|
-
const { data: workspaces, isLoading } = useWorkspaces();
|
|
822
|
-
const [mode, setMode] = useState("select");
|
|
823
|
-
const [selected, setSelected] = useState("");
|
|
824
|
-
const [newName, setNewName] = useState("");
|
|
825
|
-
const [loading, setLoading] = useState(false);
|
|
826
|
-
const [error, setError] = useState("");
|
|
827
|
-
if (isLoading) {
|
|
828
|
-
return /* @__PURE__ */ jsx("div", { style: loadingContainerStyle(), children: "Loading workspaces..." });
|
|
829
|
-
}
|
|
830
|
-
const handleConfirm = async () => {
|
|
831
|
-
if (!selected) return;
|
|
832
|
-
setLoading(true);
|
|
833
|
-
setError("");
|
|
834
|
-
try {
|
|
835
|
-
await arbi.selectWorkspace(selected);
|
|
836
|
-
onSelect(selected);
|
|
837
|
-
} catch (err) {
|
|
838
|
-
setError(err instanceof Error ? err.message : "Failed to select workspace");
|
|
839
|
-
} finally {
|
|
840
|
-
setLoading(false);
|
|
841
|
-
}
|
|
842
|
-
};
|
|
843
|
-
const handleCreate = async () => {
|
|
844
|
-
const name = newName.trim();
|
|
845
|
-
if (!name) return;
|
|
846
|
-
setLoading(true);
|
|
847
|
-
setError("");
|
|
848
|
-
try {
|
|
849
|
-
const projects = await arbi.projects.list();
|
|
850
|
-
const projectExtId = projects[0]?.external_id;
|
|
851
|
-
if (!projectExtId) {
|
|
852
|
-
throw new Error("No project available; create one before adding a workspace");
|
|
853
|
-
}
|
|
854
|
-
const ws = await arbi.workspaces.create(name, projectExtId);
|
|
855
|
-
await arbi.selectWorkspace(ws.external_id);
|
|
856
|
-
onSelect(ws.external_id);
|
|
857
|
-
} catch (err) {
|
|
858
|
-
setError(err instanceof Error ? err.message : "Failed to create workspace");
|
|
859
|
-
} finally {
|
|
860
|
-
setLoading(false);
|
|
861
|
-
}
|
|
862
|
-
};
|
|
863
|
-
if (mode === "create") {
|
|
864
|
-
return /* @__PURE__ */ jsxs("div", { style: formContainerStyle(), children: [
|
|
865
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
866
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.workspaceName }),
|
|
867
|
-
/* @__PURE__ */ jsx(
|
|
868
|
-
"input",
|
|
869
|
-
{
|
|
870
|
-
type: "text",
|
|
871
|
-
value: newName,
|
|
872
|
-
onChange: (e) => setNewName(e.target.value),
|
|
873
|
-
disabled: loading,
|
|
874
|
-
style: inputStyle(theme)
|
|
875
|
-
}
|
|
876
|
-
)
|
|
877
|
-
] }),
|
|
878
|
-
/* @__PURE__ */ jsx(
|
|
879
|
-
"button",
|
|
880
|
-
{
|
|
881
|
-
type: "button",
|
|
882
|
-
onClick: handleCreate,
|
|
883
|
-
disabled: !newName.trim() || loading,
|
|
884
|
-
style: buttonStyle(theme, !newName.trim() || loading),
|
|
885
|
-
children: loading ? "..." : labels.createButton
|
|
886
|
-
}
|
|
887
|
-
),
|
|
888
|
-
error && /* @__PURE__ */ jsx("div", { style: errorStyle(), children: error }),
|
|
889
|
-
/* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(
|
|
890
|
-
"button",
|
|
891
|
-
{
|
|
892
|
-
type: "button",
|
|
893
|
-
onClick: () => {
|
|
894
|
-
setError("");
|
|
895
|
-
setMode("select");
|
|
896
|
-
},
|
|
897
|
-
style: linkButtonStyle(theme),
|
|
898
|
-
children: "or select existing"
|
|
899
|
-
}
|
|
900
|
-
) })
|
|
901
|
-
] });
|
|
902
|
-
}
|
|
903
|
-
return /* @__PURE__ */ jsxs("div", { style: formContainerStyle(), children: [
|
|
904
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
905
|
-
/* @__PURE__ */ jsx("div", { style: labelStyle(theme), children: labels.selectWorkspace }),
|
|
906
|
-
/* @__PURE__ */ jsxs(
|
|
907
|
-
"select",
|
|
908
|
-
{
|
|
909
|
-
value: selected,
|
|
910
|
-
onChange: (e) => setSelected(e.target.value),
|
|
911
|
-
disabled: loading,
|
|
912
|
-
style: selectStyle(theme),
|
|
913
|
-
children: [
|
|
914
|
-
/* @__PURE__ */ jsx("option", { value: "", disabled: true, children: labels.workspacePlaceholder }),
|
|
915
|
-
workspaces?.map((ws) => /* @__PURE__ */ jsx("option", { value: ws.external_id, children: ws.name }, ws.external_id))
|
|
916
|
-
]
|
|
917
|
-
}
|
|
918
|
-
)
|
|
919
|
-
] }),
|
|
920
|
-
/* @__PURE__ */ jsx(
|
|
921
|
-
"button",
|
|
922
|
-
{
|
|
923
|
-
type: "button",
|
|
924
|
-
onClick: handleConfirm,
|
|
925
|
-
disabled: !selected || loading,
|
|
926
|
-
style: buttonStyle(theme, !selected || loading),
|
|
927
|
-
children: loading ? "Connecting..." : labels.continueButton
|
|
928
|
-
}
|
|
929
|
-
),
|
|
930
|
-
error && /* @__PURE__ */ jsx("div", { style: errorStyle(), children: error }),
|
|
931
|
-
/* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(
|
|
932
|
-
"button",
|
|
933
|
-
{
|
|
934
|
-
type: "button",
|
|
935
|
-
onClick: () => {
|
|
936
|
-
setError("");
|
|
937
|
-
setMode("create");
|
|
938
|
-
},
|
|
939
|
-
style: linkButtonStyle(theme),
|
|
940
|
-
children: labels.createWorkspace
|
|
941
|
-
}
|
|
942
|
-
) })
|
|
943
|
-
] });
|
|
944
|
-
}
|
|
945
|
-
var CITE_RE = /\[([^\]]+)\]\(#cite-(\d+)\)/g;
|
|
946
|
-
function MessageBubble({ message, theme }) {
|
|
947
|
-
const [expandedCite, setExpandedCite] = useState(null);
|
|
948
|
-
const hasCitations = message.role === "assistant" && message.metadata && CITE_RE.test(message.text);
|
|
949
|
-
CITE_RE.lastIndex = 0;
|
|
950
|
-
const resolved = hasCitations ? resolveCitations(message.metadata) : [];
|
|
951
|
-
const summaries = hasCitations ? summarizeCitations(resolved) : [];
|
|
952
|
-
const summaryMap = new Map(summaries.map((s) => [s.citationNum, s]));
|
|
953
|
-
const activeSummary = expandedCite ? summaryMap.get(expandedCite) : null;
|
|
954
|
-
const activeResolved = expandedCite ? resolved.find((r) => r.citationNum === expandedCite) : null;
|
|
955
|
-
const markdownComponents = useMemo(
|
|
956
|
-
() => ({
|
|
957
|
-
a: ({ href, children, ...props }) => {
|
|
958
|
-
if (href?.startsWith("#cite-")) {
|
|
959
|
-
const num = href.slice("#cite-".length);
|
|
960
|
-
return /* @__PURE__ */ jsxs("span", { children: [
|
|
961
|
-
children,
|
|
962
|
-
/* @__PURE__ */ jsx(
|
|
963
|
-
"sup",
|
|
964
|
-
{
|
|
965
|
-
onClick: (e) => {
|
|
966
|
-
e.stopPropagation();
|
|
967
|
-
setExpandedCite((prev) => prev === num ? null : num);
|
|
968
|
-
},
|
|
969
|
-
style: citeSupStyle(theme),
|
|
970
|
-
title: `Citation ${num}`,
|
|
971
|
-
children: num
|
|
972
|
-
}
|
|
973
|
-
)
|
|
974
|
-
] });
|
|
975
|
-
}
|
|
976
|
-
return /* @__PURE__ */ jsx(
|
|
977
|
-
"a",
|
|
978
|
-
{
|
|
979
|
-
href,
|
|
980
|
-
target: "_blank",
|
|
981
|
-
rel: "noopener noreferrer",
|
|
982
|
-
style: { color: theme.primaryColor },
|
|
983
|
-
...props,
|
|
984
|
-
children
|
|
985
|
-
}
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
}),
|
|
989
|
-
[theme]
|
|
990
|
-
);
|
|
991
|
-
return /* @__PURE__ */ jsxs("div", { children: [
|
|
992
|
-
/* @__PURE__ */ jsx("div", { style: messageBubbleStyle(theme, message.role), children: /* @__PURE__ */ jsx(MarkdownRenderer, { components: markdownComponents, children: message.text }) }),
|
|
993
|
-
activeSummary && activeResolved && /* @__PURE__ */ jsxs("div", { style: citePanelStyle(theme), children: [
|
|
994
|
-
/* @__PURE__ */ jsxs("div", { style: citePanelHeaderStyle(theme), children: [
|
|
995
|
-
/* @__PURE__ */ jsxs("strong", { children: [
|
|
996
|
-
"[",
|
|
997
|
-
activeSummary.citationNum,
|
|
998
|
-
"]"
|
|
999
|
-
] }),
|
|
1000
|
-
" ",
|
|
1001
|
-
activeSummary.docTitle,
|
|
1002
|
-
activeSummary.pageNumber != null && /* @__PURE__ */ jsxs("span", { style: { color: theme.mutedColor }, children: [
|
|
1003
|
-
" p.",
|
|
1004
|
-
activeSummary.pageNumber
|
|
1005
|
-
] })
|
|
1006
|
-
] }),
|
|
1007
|
-
activeResolved.chunks.map((chunk, i) => /* @__PURE__ */ jsx("div", { style: citeChunkStyle(theme), children: chunk.content }, i))
|
|
1008
|
-
] })
|
|
1009
|
-
] });
|
|
1010
|
-
}
|
|
1011
|
-
function citeSupStyle(theme) {
|
|
1012
|
-
return {
|
|
1013
|
-
display: "inline-flex",
|
|
1014
|
-
alignItems: "center",
|
|
1015
|
-
justifyContent: "center",
|
|
1016
|
-
fontSize: "10px",
|
|
1017
|
-
fontWeight: 600,
|
|
1018
|
-
color: theme.primaryColor,
|
|
1019
|
-
cursor: "pointer",
|
|
1020
|
-
marginLeft: "1px",
|
|
1021
|
-
minWidth: "14px",
|
|
1022
|
-
lineHeight: 1
|
|
1023
|
-
};
|
|
1024
|
-
}
|
|
1025
|
-
function citePanelStyle(theme) {
|
|
1026
|
-
return {
|
|
1027
|
-
marginTop: "4px",
|
|
1028
|
-
padding: "8px 10px",
|
|
1029
|
-
fontSize: "12px",
|
|
1030
|
-
lineHeight: "1.5",
|
|
1031
|
-
backgroundColor: theme.surfaceColor,
|
|
1032
|
-
border: `1px solid ${theme.borderColor}`,
|
|
1033
|
-
borderRadius: "8px",
|
|
1034
|
-
maxWidth: "85%"
|
|
1035
|
-
};
|
|
1036
|
-
}
|
|
1037
|
-
function citePanelHeaderStyle(theme) {
|
|
1038
|
-
return {
|
|
1039
|
-
fontSize: "12px",
|
|
1040
|
-
fontWeight: 500,
|
|
1041
|
-
color: theme.textColor,
|
|
1042
|
-
marginBottom: "4px"
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1045
|
-
function citeChunkStyle(theme) {
|
|
1046
|
-
return {
|
|
1047
|
-
fontSize: "11px",
|
|
1048
|
-
color: theme.mutedColor,
|
|
1049
|
-
borderLeft: `2px solid ${theme.borderColor}`,
|
|
1050
|
-
paddingLeft: "8px",
|
|
1051
|
-
marginTop: "4px",
|
|
1052
|
-
whiteSpace: "pre-wrap",
|
|
1053
|
-
wordBreak: "break-word"
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
function ChatView({ workspaceId, theme, labels }) {
|
|
1057
|
-
const arbi = useArbi();
|
|
1058
|
-
const { data: docs, refetch: refetchDocs } = useDocuments(workspaceId);
|
|
1059
|
-
const mutation = useAssistantQuery();
|
|
1060
|
-
const [messages, setMessages] = useState([]);
|
|
1061
|
-
const [input, setInput] = useState("");
|
|
1062
|
-
const [streaming, setStreaming] = useState("");
|
|
1063
|
-
const [agentStatus, setAgentStatus] = useState("");
|
|
1064
|
-
const [selectedDocs, setSelectedDocs] = useState([]);
|
|
1065
|
-
const [docsExpanded, setDocsExpanded] = useState(false);
|
|
1066
|
-
const [previousResponseId, setPreviousResponseId] = useState(null);
|
|
1067
|
-
const [uploading, setUploading] = useState(false);
|
|
1068
|
-
const messagesEndRef = useRef(null);
|
|
1069
|
-
const fileInputRef = useRef(null);
|
|
1070
|
-
useEffect(() => {
|
|
1071
|
-
if (docs && docs.length > 0 && selectedDocs.length === 0) {
|
|
1072
|
-
setSelectedDocs(docs.map((d) => d.external_id));
|
|
1073
|
-
}
|
|
1074
|
-
}, [docs, selectedDocs.length]);
|
|
1075
|
-
useEffect(() => {
|
|
1076
|
-
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1077
|
-
}, [messages, streaming, agentStatus]);
|
|
1078
|
-
const toggleDoc = (docId) => {
|
|
1079
|
-
setSelectedDocs(
|
|
1080
|
-
(prev) => prev.includes(docId) ? prev.filter((id) => id !== docId) : [...prev, docId]
|
|
1081
|
-
);
|
|
1082
|
-
};
|
|
1083
|
-
const handleUpload = useCallback(
|
|
1084
|
-
async (e) => {
|
|
1085
|
-
const files = e.target.files;
|
|
1086
|
-
if (!files || files.length === 0) return;
|
|
1087
|
-
setUploading(true);
|
|
1088
|
-
try {
|
|
1089
|
-
const newIds = [];
|
|
1090
|
-
for (const file of Array.from(files)) {
|
|
1091
|
-
const result = await arbi.documents.uploadFile(file, file.name);
|
|
1092
|
-
if (result.doc_ext_ids) newIds.push(...result.doc_ext_ids);
|
|
1093
|
-
}
|
|
1094
|
-
await refetchDocs();
|
|
1095
|
-
setSelectedDocs((prev) => [...prev, ...newIds]);
|
|
1096
|
-
} catch {
|
|
1097
|
-
} finally {
|
|
1098
|
-
setUploading(false);
|
|
1099
|
-
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
1100
|
-
}
|
|
1101
|
-
},
|
|
1102
|
-
[arbi, refetchDocs]
|
|
1103
|
-
);
|
|
1104
|
-
const handleSubmit = useCallback(
|
|
1105
|
-
(e) => {
|
|
1106
|
-
e.preventDefault();
|
|
1107
|
-
const question = input.trim();
|
|
1108
|
-
if (!question || selectedDocs.length === 0 || mutation.isPending) return;
|
|
1109
|
-
setMessages((prev) => [...prev, { role: "user", text: question }]);
|
|
1110
|
-
setInput("");
|
|
1111
|
-
setStreaming("");
|
|
1112
|
-
setAgentStatus("");
|
|
1113
|
-
mutation.mutate(
|
|
1114
|
-
{
|
|
1115
|
-
question,
|
|
1116
|
-
docIds: selectedDocs,
|
|
1117
|
-
previousResponseId,
|
|
1118
|
-
onToken: (t) => setStreaming((prev) => prev + t),
|
|
1119
|
-
onOutputItemDone: (ev) => {
|
|
1120
|
-
const item = ev.item;
|
|
1121
|
-
if (item.type === "function_call" || item.type === "reasoning") {
|
|
1122
|
-
setAgentStatus(item.arbi?.focus || item.arbi?.label || "");
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
},
|
|
1126
|
-
{
|
|
1127
|
-
onSuccess: (result) => {
|
|
1128
|
-
setStreaming("");
|
|
1129
|
-
setAgentStatus("");
|
|
1130
|
-
setMessages((prev) => [
|
|
1131
|
-
...prev,
|
|
1132
|
-
{ role: "assistant", text: result.text, metadata: result.metadata }
|
|
1133
|
-
]);
|
|
1134
|
-
setPreviousResponseId(result.assistantMessageExtId);
|
|
1135
|
-
},
|
|
1136
|
-
onError: (err) => {
|
|
1137
|
-
setStreaming("");
|
|
1138
|
-
setAgentStatus("");
|
|
1139
|
-
setMessages((prev) => [...prev, { role: "assistant", text: `Error: ${err.message}` }]);
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
);
|
|
1143
|
-
},
|
|
1144
|
-
[input, selectedDocs, previousResponseId, mutation]
|
|
1145
|
-
);
|
|
1146
|
-
const noDocs = !docs || docs.length === 0;
|
|
1147
|
-
const noDocsSelected = selectedDocs.length === 0;
|
|
1148
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1149
|
-
/* @__PURE__ */ jsx(
|
|
1150
|
-
"input",
|
|
1151
|
-
{
|
|
1152
|
-
ref: fileInputRef,
|
|
1153
|
-
type: "file",
|
|
1154
|
-
multiple: true,
|
|
1155
|
-
accept: ".pdf,.txt,.md,.html,.doc,.docx,.rtf,.ppt,.pptx,.xls,.xlsx",
|
|
1156
|
-
onChange: handleUpload,
|
|
1157
|
-
style: fileInputStyle()
|
|
1158
|
-
}
|
|
1159
|
-
),
|
|
1160
|
-
/* @__PURE__ */ jsxs("div", { style: docSelectorStyle(theme), children: [
|
|
1161
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
1162
|
-
/* @__PURE__ */ jsxs(
|
|
1163
|
-
"button",
|
|
1164
|
-
{
|
|
1165
|
-
type: "button",
|
|
1166
|
-
onClick: () => setDocsExpanded((prev) => !prev),
|
|
1167
|
-
style: docToggleStyle(theme),
|
|
1168
|
-
children: [
|
|
1169
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: "10px" }, children: docsExpanded ? "\u25BC" : "\u25B6" }),
|
|
1170
|
-
labels.documents,
|
|
1171
|
-
" (",
|
|
1172
|
-
selectedDocs.length,
|
|
1173
|
-
"/",
|
|
1174
|
-
docs?.length ?? 0,
|
|
1175
|
-
" in chat)"
|
|
1176
|
-
]
|
|
1177
|
-
}
|
|
1178
|
-
),
|
|
1179
|
-
/* @__PURE__ */ jsx(
|
|
1180
|
-
"button",
|
|
1181
|
-
{
|
|
1182
|
-
type: "button",
|
|
1183
|
-
onClick: () => fileInputRef.current?.click(),
|
|
1184
|
-
disabled: uploading,
|
|
1185
|
-
style: secondaryButtonStyle(theme, uploading),
|
|
1186
|
-
children: uploading ? labels.uploading : labels.uploadButton
|
|
1187
|
-
}
|
|
1188
|
-
)
|
|
1189
|
-
] }),
|
|
1190
|
-
docsExpanded && docs && docs.length > 0 && /* @__PURE__ */ jsx("div", { style: docListStyle(), children: docs.map((doc) => /* @__PURE__ */ jsxs("label", { style: docItemStyle(theme), children: [
|
|
1191
|
-
/* @__PURE__ */ jsx(
|
|
1192
|
-
"input",
|
|
1193
|
-
{
|
|
1194
|
-
type: "checkbox",
|
|
1195
|
-
checked: selectedDocs.includes(doc.external_id),
|
|
1196
|
-
onChange: () => toggleDoc(doc.external_id)
|
|
1197
|
-
}
|
|
1198
|
-
),
|
|
1199
|
-
doc.file_name
|
|
1200
|
-
] }, doc.external_id)) })
|
|
1201
|
-
] }),
|
|
1202
|
-
/* @__PURE__ */ jsxs("div", { style: messagesContainerStyle(), children: [
|
|
1203
|
-
messages.length === 0 && !streaming && /* @__PURE__ */ jsx("div", { style: emptyStateStyle(theme), children: noDocs ? labels.emptyNoDocs : noDocsSelected ? labels.emptyNoSelection : labels.emptyReady }),
|
|
1204
|
-
messages.map((msg, i) => /* @__PURE__ */ jsx(MessageBubble, { message: msg, theme }, i)),
|
|
1205
|
-
agentStatus && !streaming && /* @__PURE__ */ jsxs("div", { style: agentStatusStyle(theme), children: [
|
|
1206
|
-
agentStatus,
|
|
1207
|
-
"..."
|
|
1208
|
-
] }),
|
|
1209
|
-
streaming && /* @__PURE__ */ jsx(MessageBubble, { message: { role: "assistant", text: streaming }, theme }),
|
|
1210
|
-
/* @__PURE__ */ jsx("div", { ref: messagesEndRef })
|
|
1211
|
-
] }),
|
|
1212
|
-
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: inputBarStyle(theme), children: [
|
|
1213
|
-
/* @__PURE__ */ jsx(
|
|
1214
|
-
"input",
|
|
1215
|
-
{
|
|
1216
|
-
type: "text",
|
|
1217
|
-
value: input,
|
|
1218
|
-
onChange: (e) => setInput(e.target.value),
|
|
1219
|
-
placeholder: noDocs || noDocsSelected ? "Select documents first..." : labels.placeholder,
|
|
1220
|
-
disabled: noDocs || noDocsSelected || mutation.isPending,
|
|
1221
|
-
style: chatInputStyle(theme)
|
|
1222
|
-
}
|
|
1223
|
-
),
|
|
1224
|
-
/* @__PURE__ */ jsx(
|
|
1225
|
-
"button",
|
|
1226
|
-
{
|
|
1227
|
-
type: "submit",
|
|
1228
|
-
disabled: !input.trim() || noDocsSelected || mutation.isPending,
|
|
1229
|
-
style: sendButtonStyle(theme, !input.trim() || noDocsSelected || mutation.isPending),
|
|
1230
|
-
children: mutation.isPending ? "..." : labels.sendButton
|
|
1231
|
-
}
|
|
1232
|
-
)
|
|
1233
|
-
] })
|
|
1234
|
-
] });
|
|
270
|
+
daily: [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date)),
|
|
271
|
+
modelGroups: [...modelMap.values()].sort(
|
|
272
|
+
(a, b) => b.credits - a.credits || b.totalTokens - a.totalTokens
|
|
273
|
+
),
|
|
274
|
+
metered: !anyData || anyMetered,
|
|
275
|
+
isLoading: results.some((r) => r.isLoading),
|
|
276
|
+
isError: results.some((r) => r.isError)
|
|
277
|
+
};
|
|
278
|
+
}, [signature]);
|
|
1235
279
|
}
|
|
1236
|
-
function
|
|
280
|
+
function useProjectInvoices(projectExtId, options) {
|
|
1237
281
|
const arbi = useArbi();
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
282
|
+
return useQuery({
|
|
283
|
+
queryKey: arbiQueryKeys.projectInvoices(projectExtId ?? ""),
|
|
284
|
+
queryFn: () => arbi.projects.invoices(projectExtId),
|
|
285
|
+
enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function useUserUsageToday(options) {
|
|
289
|
+
const arbi = useArbi();
|
|
290
|
+
return useQuery({
|
|
291
|
+
queryKey: arbiQueryKeys.userUsageToday(),
|
|
292
|
+
queryFn: () => arbi.user.usageToday(),
|
|
293
|
+
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/chat/useArbiChat.ts
|
|
298
|
+
var counter = 0;
|
|
299
|
+
var nextId = (prefix) => `${prefix}-${Date.now().toString(36)}-${(counter++).toString(36)}`;
|
|
300
|
+
var emptyThread = () => ({
|
|
301
|
+
id: nextId("thread"),
|
|
302
|
+
title: "",
|
|
303
|
+
messages: [],
|
|
304
|
+
responseId: null
|
|
305
|
+
});
|
|
306
|
+
function titleFromQuestion(question, maxLength = 48) {
|
|
307
|
+
const flat = question.replace(/\s+/g, " ").trim();
|
|
308
|
+
if (flat.length <= maxLength) return flat;
|
|
309
|
+
const cut = flat.slice(0, maxLength);
|
|
310
|
+
const lastSpace = cut.lastIndexOf(" ");
|
|
311
|
+
const words = lastSpace > maxLength / 2 ? cut.slice(0, lastSpace) : cut;
|
|
312
|
+
return `${words.replace(/[\s,;:.\-–—]+$/, "")}\u2026`;
|
|
313
|
+
}
|
|
314
|
+
var messageOf = (e, fallback) => e instanceof Error ? e.message : fallback;
|
|
315
|
+
function useArbiChat(options = {}) {
|
|
316
|
+
const { workspaceId, model, titleLength = 48 } = options;
|
|
317
|
+
const arbi = useArbi();
|
|
318
|
+
const { data: docs = [], isLoading: isLoadingDocuments, refetch } = useDocuments(workspaceId);
|
|
319
|
+
const query = useAssistantQuery();
|
|
320
|
+
const { mutateAsync } = query;
|
|
321
|
+
const [threads, setThreads] = useState(() => [emptyThread()]);
|
|
322
|
+
const [activeId, setActiveId] = useState(() => threads[0].id);
|
|
323
|
+
const [deselected, setDeselected] = useState(/* @__PURE__ */ new Set());
|
|
324
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
325
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
326
|
+
const [uploadError, setUploadError] = useState(null);
|
|
327
|
+
const scopeRef = useRef(workspaceId);
|
|
1254
328
|
useEffect(() => {
|
|
1255
|
-
if (
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
329
|
+
if (scopeRef.current === workspaceId) return;
|
|
330
|
+
scopeRef.current = workspaceId;
|
|
331
|
+
const fresh = emptyThread();
|
|
332
|
+
setThreads([fresh]);
|
|
333
|
+
setActiveId(fresh.id);
|
|
334
|
+
setDeselected(/* @__PURE__ */ new Set());
|
|
335
|
+
setUploadError(null);
|
|
336
|
+
}, [workspaceId]);
|
|
337
|
+
const active = threads.find((t) => t.id === activeId) ?? threads[0];
|
|
338
|
+
const selectedIds = useMemo(
|
|
339
|
+
() => docs.map((d) => d.external_id).filter((id) => !!id && !deselected.has(id)),
|
|
340
|
+
[docs, deselected]
|
|
341
|
+
);
|
|
342
|
+
const documents = useMemo(
|
|
343
|
+
() => docs.filter((d) => !!d.external_id).map((d) => ({
|
|
344
|
+
id: d.external_id,
|
|
345
|
+
name: d.file_name ?? d.external_id,
|
|
346
|
+
isSelected: !deselected.has(d.external_id)
|
|
347
|
+
})),
|
|
348
|
+
[docs, deselected]
|
|
349
|
+
);
|
|
350
|
+
const patchThread = useCallback(
|
|
351
|
+
(id, patch) => setThreads((all) => all.map((t) => t.id === id ? patch(t) : t)),
|
|
352
|
+
[]
|
|
353
|
+
);
|
|
354
|
+
const patchMessage = useCallback(
|
|
355
|
+
(threadId, messageId, patch) => patchThread(threadId, (t) => ({
|
|
356
|
+
...t,
|
|
357
|
+
messages: t.messages.map((m) => m.id === messageId ? { ...m, ...patch } : m)
|
|
358
|
+
})),
|
|
359
|
+
[patchThread]
|
|
360
|
+
);
|
|
361
|
+
const ask = useCallback(
|
|
362
|
+
async (thread, text) => {
|
|
363
|
+
const userMessage = {
|
|
364
|
+
id: nextId("msg"),
|
|
365
|
+
role: "user",
|
|
366
|
+
content: text,
|
|
367
|
+
status: "complete"
|
|
368
|
+
};
|
|
369
|
+
const answer = {
|
|
370
|
+
id: nextId("msg"),
|
|
371
|
+
role: "assistant",
|
|
372
|
+
content: "",
|
|
373
|
+
status: "streaming"
|
|
374
|
+
};
|
|
375
|
+
patchThread(thread.id, (t) => ({
|
|
376
|
+
...t,
|
|
377
|
+
title: t.title || titleFromQuestion(text, titleLength),
|
|
378
|
+
messages: [...t.messages, userMessage, answer]
|
|
379
|
+
}));
|
|
380
|
+
setIsRunning(true);
|
|
381
|
+
let buffer = "";
|
|
382
|
+
let steps = 0;
|
|
383
|
+
let streamError = null;
|
|
384
|
+
try {
|
|
385
|
+
const result = await mutateAsync({
|
|
386
|
+
question: text,
|
|
387
|
+
docIds: selectedIds,
|
|
388
|
+
previousResponseId: thread.responseId,
|
|
389
|
+
model,
|
|
390
|
+
onToken: (token) => {
|
|
391
|
+
buffer += token;
|
|
392
|
+
patchMessage(thread.id, answer.id, { content: buffer });
|
|
393
|
+
},
|
|
394
|
+
onOutputItemDone: (ev) => {
|
|
395
|
+
const type = ev.item.type;
|
|
396
|
+
if (type === "function_call" || type === "reasoning") {
|
|
397
|
+
steps += 1;
|
|
398
|
+
patchMessage(thread.id, answer.id, { stepCount: steps });
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
onError: (message) => {
|
|
402
|
+
streamError = message;
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
const finalText = result.text || buffer;
|
|
406
|
+
const failure = streamError || result.errors[0] || null;
|
|
407
|
+
if (failure && !finalText) {
|
|
408
|
+
patchMessage(thread.id, answer.id, { status: "error", error: failure });
|
|
409
|
+
} else {
|
|
410
|
+
patchMessage(thread.id, answer.id, {
|
|
411
|
+
status: "complete",
|
|
412
|
+
content: finalText,
|
|
413
|
+
stepCount: result.agentSteps.length || steps || void 0
|
|
414
|
+
});
|
|
415
|
+
patchThread(thread.id, (t) => ({
|
|
416
|
+
...t,
|
|
417
|
+
responseId: result.assistantMessageExtId ?? t.responseId
|
|
418
|
+
}));
|
|
1285
419
|
}
|
|
1286
|
-
)
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
}) {
|
|
1297
|
-
const theme = useMemo(() => getTheme(themeOverrides), [themeOverrides]);
|
|
1298
|
-
const labels = useMemo(() => getLabels(labelOverrides), [labelOverrides]);
|
|
1299
|
-
return /* @__PURE__ */ jsx(
|
|
1300
|
-
ChatWidget,
|
|
1301
|
-
{
|
|
1302
|
-
theme,
|
|
1303
|
-
labels,
|
|
1304
|
-
initialWorkspaceId: workspaceId,
|
|
1305
|
-
width,
|
|
1306
|
-
height
|
|
1307
|
-
}
|
|
420
|
+
} catch (e) {
|
|
421
|
+
patchMessage(thread.id, answer.id, {
|
|
422
|
+
status: "error",
|
|
423
|
+
error: messageOf(e, "The assistant request failed.")
|
|
424
|
+
});
|
|
425
|
+
} finally {
|
|
426
|
+
setIsRunning(false);
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
[mutateAsync, patchMessage, patchThread, selectedIds, model, titleLength]
|
|
1308
430
|
);
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
431
|
+
const send = useCallback(
|
|
432
|
+
async (text) => {
|
|
433
|
+
const trimmed = text.trim();
|
|
434
|
+
if (!trimmed || isRunning) return;
|
|
435
|
+
await ask(active, trimmed);
|
|
436
|
+
},
|
|
437
|
+
[active, ask, isRunning]
|
|
438
|
+
);
|
|
439
|
+
const lastMessage = active.messages[active.messages.length - 1];
|
|
440
|
+
const error = lastMessage?.status === "error" ? lastMessage.error ?? null : null;
|
|
441
|
+
const retry = useCallback(async () => {
|
|
442
|
+
if (isRunning) return;
|
|
443
|
+
const messages = active.messages;
|
|
444
|
+
const failed = messages[messages.length - 1];
|
|
445
|
+
const question = messages[messages.length - 2];
|
|
446
|
+
if (failed?.status !== "error" || question?.role !== "user") return;
|
|
447
|
+
const trimmed = { ...active, messages: messages.slice(0, -2) };
|
|
448
|
+
patchThread(active.id, () => trimmed);
|
|
449
|
+
await ask(trimmed, question.content);
|
|
450
|
+
}, [active, ask, isRunning, patchThread]);
|
|
451
|
+
const newThread = useCallback(() => {
|
|
452
|
+
if (active.messages.length === 0) return;
|
|
453
|
+
const fresh = emptyThread();
|
|
454
|
+
setThreads((all) => [fresh, ...all]);
|
|
455
|
+
setActiveId(fresh.id);
|
|
456
|
+
}, [active.messages.length]);
|
|
457
|
+
const deleteThread = useCallback(
|
|
458
|
+
(id) => {
|
|
459
|
+
const rest = threads.filter((t) => t.id !== id);
|
|
460
|
+
const next = rest.length > 0 ? rest : [emptyThread()];
|
|
461
|
+
setThreads(next);
|
|
462
|
+
if (id === activeId) setActiveId(next[0].id);
|
|
463
|
+
},
|
|
464
|
+
[threads, activeId]
|
|
465
|
+
);
|
|
466
|
+
const toggleDocument = useCallback((id) => {
|
|
467
|
+
setDeselected((prev) => {
|
|
468
|
+
const next = new Set(prev);
|
|
469
|
+
if (next.has(id)) next.delete(id);
|
|
470
|
+
else next.add(id);
|
|
471
|
+
return next;
|
|
472
|
+
});
|
|
473
|
+
}, []);
|
|
474
|
+
const selectAllDocuments = useCallback(() => setDeselected(/* @__PURE__ */ new Set()), []);
|
|
475
|
+
const upload = useCallback(
|
|
476
|
+
async (files) => {
|
|
477
|
+
if (files.length === 0) return;
|
|
478
|
+
setIsUploading(true);
|
|
479
|
+
setUploadError(null);
|
|
480
|
+
try {
|
|
481
|
+
for (const file of files) await arbi.documents.uploadFile(file, file.name);
|
|
482
|
+
await refetch();
|
|
483
|
+
} catch (e) {
|
|
484
|
+
setUploadError(messageOf(e, "The upload failed."));
|
|
485
|
+
} finally {
|
|
486
|
+
setIsUploading(false);
|
|
1323
487
|
}
|
|
1324
|
-
}
|
|
1325
|
-
[]
|
|
488
|
+
},
|
|
489
|
+
[arbi, refetch]
|
|
1326
490
|
);
|
|
1327
|
-
return
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
491
|
+
return {
|
|
492
|
+
threads: threads.map(({ id, title }) => ({ id, title })),
|
|
493
|
+
activeThreadId: active.id,
|
|
494
|
+
messages: active.messages,
|
|
495
|
+
isRunning,
|
|
496
|
+
error,
|
|
497
|
+
documents,
|
|
498
|
+
isLoadingDocuments,
|
|
499
|
+
isUploading,
|
|
500
|
+
uploadError,
|
|
501
|
+
send,
|
|
502
|
+
retry,
|
|
503
|
+
selectThread: setActiveId,
|
|
504
|
+
newThread,
|
|
505
|
+
deleteThread,
|
|
506
|
+
toggleDocument,
|
|
507
|
+
selectAllDocuments,
|
|
508
|
+
upload
|
|
509
|
+
};
|
|
1337
510
|
}
|
|
1338
511
|
var TypingIndicator = memo(function TypingIndicator2() {
|
|
1339
512
|
return /* @__PURE__ */ jsx("div", { className: "flex w-full justify-start mb-2", "data-testid": "dm-typing-indicator", children: /* @__PURE__ */ jsx("div", { className: "bg-card border border-primary rounded-2xl rounded-bl-md px-4 py-2.5", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 items-center", children: [
|
|
@@ -1616,6 +789,324 @@ function useArbiDocumentSync(workspaceId) {
|
|
|
1616
789
|
}
|
|
1617
790
|
});
|
|
1618
791
|
}
|
|
792
|
+
|
|
793
|
+
// src/workspaces/shell-workspaces.ts
|
|
794
|
+
function getWorkspaceKind(workspace) {
|
|
795
|
+
if (workspace.is_public) return "common";
|
|
796
|
+
if ((workspace.users?.length ?? 0) > 1) return "shared";
|
|
797
|
+
return "private";
|
|
798
|
+
}
|
|
799
|
+
function memberName(user) {
|
|
800
|
+
const full = [user?.given_name, user?.family_name].filter(Boolean).join(" ").trim();
|
|
801
|
+
return full || user?.email || "";
|
|
802
|
+
}
|
|
803
|
+
function toShellWorkspace(workspace) {
|
|
804
|
+
const people = (workspace.users ?? []).filter((u) => !u.agent_ext_id);
|
|
805
|
+
return {
|
|
806
|
+
id: workspace.external_id,
|
|
807
|
+
name: workspace.name,
|
|
808
|
+
kind: getWorkspaceKind(workspace),
|
|
809
|
+
description: workspace.description,
|
|
810
|
+
projectName: workspace.project_name,
|
|
811
|
+
docCount: (workspace.shared_document_count ?? 0) + (workspace.private_document_count ?? 0),
|
|
812
|
+
memberCount: people.length,
|
|
813
|
+
members: people.map((u) => ({ name: memberName(u.user), picture: u.user?.picture })),
|
|
814
|
+
updatedAt: workspace.updated_at
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
function recency(workspace, lastOpened) {
|
|
818
|
+
const opened = lastOpened?.[workspace.id];
|
|
819
|
+
if (opened !== void 0) return opened;
|
|
820
|
+
const updated = Date.parse(workspace.updatedAt ?? "");
|
|
821
|
+
return Number.isNaN(updated) ? 0 : updated;
|
|
822
|
+
}
|
|
823
|
+
function resolveActiveWorkspace(items, selectedId, options = {}) {
|
|
824
|
+
const selected = selectedId ? items.find((w) => w.id === selectedId) : void 0;
|
|
825
|
+
if (selected) return selected;
|
|
826
|
+
if (options.isSeed && options.seedActiveId) {
|
|
827
|
+
const seeded = items.find((w) => w.id === options.seedActiveId);
|
|
828
|
+
if (seeded) return seeded;
|
|
829
|
+
}
|
|
830
|
+
return items[0];
|
|
831
|
+
}
|
|
832
|
+
function pickRecentWorkspaces(items, activeId, options = {}) {
|
|
833
|
+
const { limit = 4, lastOpened, formatLastSeen } = options;
|
|
834
|
+
return items.filter((w) => w.id !== activeId).map((w) => ({ w, at: recency(w, lastOpened) })).sort((a, b) => b.at - a.at).slice(0, limit).map(({ w, at }) => formatLastSeen ? { ...w, lastSeen: formatLastSeen(at) } : w);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// src/workspaces/useShellWorkspaces.ts
|
|
838
|
+
function useShellWorkspaces(options) {
|
|
839
|
+
const {
|
|
840
|
+
workspaces,
|
|
841
|
+
isLoading = false,
|
|
842
|
+
loadError,
|
|
843
|
+
selectedId,
|
|
844
|
+
seed,
|
|
845
|
+
decorate,
|
|
846
|
+
recentLimit,
|
|
847
|
+
lastOpened,
|
|
848
|
+
formatLastSeen
|
|
849
|
+
} = options;
|
|
850
|
+
const live = useMemo(
|
|
851
|
+
() => (workspaces ?? []).map((source) => {
|
|
852
|
+
const item = toShellWorkspace(source);
|
|
853
|
+
return decorate ? { ...item, ...decorate(item, source) } : item;
|
|
854
|
+
}),
|
|
855
|
+
[workspaces, decorate]
|
|
856
|
+
);
|
|
857
|
+
const isLive = live.length > 0;
|
|
858
|
+
const isSeed = !isLive && !isLoading && !!seed;
|
|
859
|
+
const items = useMemo(
|
|
860
|
+
() => isLive ? live : isSeed ? [...seed.workspaces] : [],
|
|
861
|
+
[isLive, live, isSeed, seed]
|
|
862
|
+
);
|
|
863
|
+
const active = useMemo(
|
|
864
|
+
() => resolveActiveWorkspace(items, selectedId, { isSeed, seedActiveId: seed?.activeId }),
|
|
865
|
+
[items, selectedId, isSeed, seed?.activeId]
|
|
866
|
+
);
|
|
867
|
+
const recent = useMemo(
|
|
868
|
+
() => pickRecentWorkspaces(items, active?.id, { limit: recentLimit, lastOpened, formatLastSeen }),
|
|
869
|
+
[items, active?.id, recentLimit, lastOpened, formatLastSeen]
|
|
870
|
+
);
|
|
871
|
+
const [openingId, setOpeningId] = useState(null);
|
|
872
|
+
const [openError, setOpenError] = useState(void 0);
|
|
873
|
+
const callbacks = useRef({
|
|
874
|
+
select: options.select,
|
|
875
|
+
onOpened: options.onOpened,
|
|
876
|
+
onOpenError: options.onOpenError
|
|
877
|
+
});
|
|
878
|
+
callbacks.current = {
|
|
879
|
+
select: options.select,
|
|
880
|
+
onOpened: options.onOpened,
|
|
881
|
+
onOpenError: options.onOpenError
|
|
882
|
+
};
|
|
883
|
+
const itemsRef = useRef(items);
|
|
884
|
+
itemsRef.current = items;
|
|
885
|
+
const open = useCallback(async (target) => {
|
|
886
|
+
const id = typeof target === "string" ? target : target.id;
|
|
887
|
+
const workspace = itemsRef.current.find((w) => w.id === id);
|
|
888
|
+
if (!workspace) return false;
|
|
889
|
+
setOpenError(void 0);
|
|
890
|
+
setOpeningId(id);
|
|
891
|
+
try {
|
|
892
|
+
await callbacks.current.select(workspace);
|
|
893
|
+
} catch (err) {
|
|
894
|
+
setOpenError(err);
|
|
895
|
+
setOpeningId(null);
|
|
896
|
+
callbacks.current.onOpenError?.(err, workspace);
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
setOpeningId(null);
|
|
900
|
+
callbacks.current.onOpened?.(workspace);
|
|
901
|
+
return true;
|
|
902
|
+
}, []);
|
|
903
|
+
return {
|
|
904
|
+
items,
|
|
905
|
+
active,
|
|
906
|
+
recent,
|
|
907
|
+
isLive,
|
|
908
|
+
isLoading,
|
|
909
|
+
error: openError ?? loadError ?? null,
|
|
910
|
+
openingId,
|
|
911
|
+
open
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
function useArbiShellWorkspaces(options = {}) {
|
|
915
|
+
const arbi = useArbi();
|
|
916
|
+
const query = useWorkspaces();
|
|
917
|
+
const { select, ...rest } = options;
|
|
918
|
+
const defaultSelect = useCallback(
|
|
919
|
+
(workspace) => arbi.selectWorkspace(workspace.id),
|
|
920
|
+
[arbi]
|
|
921
|
+
);
|
|
922
|
+
return useShellWorkspaces({
|
|
923
|
+
...rest,
|
|
924
|
+
workspaces: Array.isArray(query.data) ? query.data : void 0,
|
|
925
|
+
isLoading: query.isLoading,
|
|
926
|
+
loadError: query.error,
|
|
927
|
+
select: select ?? defaultSelect
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
function useCreateTask() {
|
|
931
|
+
const arbi = useArbi();
|
|
932
|
+
const qc = useQueryClient();
|
|
933
|
+
return useMutation({
|
|
934
|
+
mutationFn: (body) => arbi.tasks.create(body),
|
|
935
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() })
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
function useUpdateTask() {
|
|
939
|
+
const arbi = useArbi();
|
|
940
|
+
const qc = useQueryClient();
|
|
941
|
+
return useMutation({
|
|
942
|
+
mutationFn: ({ taskId, patch }) => arbi.tasks.update(taskId, patch),
|
|
943
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() })
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
function useRunTask() {
|
|
947
|
+
const arbi = useArbi();
|
|
948
|
+
const qc = useQueryClient();
|
|
949
|
+
return useMutation({
|
|
950
|
+
mutationFn: (taskId) => arbi.tasks.runWithAuth(taskId),
|
|
951
|
+
onSuccess: (_task, taskId) => Promise.all([
|
|
952
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() }),
|
|
953
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.taskRuns(taskId) })
|
|
954
|
+
])
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
function useDeleteTask() {
|
|
958
|
+
const arbi = useArbi();
|
|
959
|
+
const qc = useQueryClient();
|
|
960
|
+
return useMutation({
|
|
961
|
+
mutationFn: (taskId) => arbi.tasks.delete(taskId),
|
|
962
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() })
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
function useTaskRuns(taskId, options) {
|
|
966
|
+
const arbi = useArbi();
|
|
967
|
+
return useQuery({
|
|
968
|
+
queryKey: arbiQueryKeys.taskRuns(taskId ?? ""),
|
|
969
|
+
queryFn: () => arbi.tasks.listRuns(taskId),
|
|
970
|
+
enabled: (options?.enabled ?? true) && !!taskId && arbi.isLoggedIn,
|
|
971
|
+
refetchInterval: (q) => q.state.data?.some((r) => r.status === "running") ? 3e3 : false
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
function useCreateAgent() {
|
|
975
|
+
const arbi = useArbi();
|
|
976
|
+
const qc = useQueryClient();
|
|
977
|
+
return useMutation({
|
|
978
|
+
mutationFn: (name) => arbi.agents.create(name),
|
|
979
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.agents() })
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
function useAgentConfig(agentExtId, options) {
|
|
983
|
+
const arbi = useArbi();
|
|
984
|
+
return useQuery({
|
|
985
|
+
queryKey: arbiQueryKeys.agentConfig(agentExtId),
|
|
986
|
+
queryFn: async () => agentExtId ? await arbi.agents.getConfig(agentExtId) : await arbi.agentConfig.get("default"),
|
|
987
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
function useAgentModels(options) {
|
|
991
|
+
const arbi = useArbi();
|
|
992
|
+
return useQuery({
|
|
993
|
+
queryKey: arbiQueryKeys.models(),
|
|
994
|
+
queryFn: async () => (await arbi.agentConfig.getModels()).models.map((m) => m.model_name),
|
|
995
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
function useSaveAgentConfig() {
|
|
999
|
+
const arbi = useArbi();
|
|
1000
|
+
const qc = useQueryClient();
|
|
1001
|
+
return useMutation({
|
|
1002
|
+
mutationFn: async ({ agentExtId, title, sections }) => {
|
|
1003
|
+
const pinned = await arbi.agents.getConfig(agentExtId);
|
|
1004
|
+
const base = pinned ?? await arbi.agentConfig.get("default");
|
|
1005
|
+
const merged = structuredClone(base);
|
|
1006
|
+
for (const [section, params] of Object.entries(sections)) {
|
|
1007
|
+
merged[section] = { ...merged[section] ?? {}, ...params };
|
|
1008
|
+
}
|
|
1009
|
+
return arbi.agentConfig.save({
|
|
1010
|
+
...merged,
|
|
1011
|
+
agent_ext_id: agentExtId,
|
|
1012
|
+
title: title ?? `agent-${agentExtId}`
|
|
1013
|
+
});
|
|
1014
|
+
},
|
|
1015
|
+
onSuccess: (_saved, { agentExtId }) => Promise.all([
|
|
1016
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.configs() }),
|
|
1017
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.agentConfig(agentExtId) })
|
|
1018
|
+
])
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
function useAgentWorkspaces(agentExtId, options) {
|
|
1022
|
+
const arbi = useArbi();
|
|
1023
|
+
return useQuery({
|
|
1024
|
+
queryKey: arbiQueryKeys.agentWorkspaces(agentExtId ?? ""),
|
|
1025
|
+
queryFn: () => arbi.agents.listWorkspaces(agentExtId),
|
|
1026
|
+
enabled: (options?.enabled ?? true) && !!agentExtId && arbi.isLoggedIn
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
function useGrantAgentAccess() {
|
|
1030
|
+
const arbi = useArbi();
|
|
1031
|
+
const qc = useQueryClient();
|
|
1032
|
+
return useMutation({
|
|
1033
|
+
mutationFn: async ({
|
|
1034
|
+
agentExtId,
|
|
1035
|
+
workspaceId,
|
|
1036
|
+
mode = { kind: "standing" }
|
|
1037
|
+
}) => {
|
|
1038
|
+
if (mode.kind === "temporary") {
|
|
1039
|
+
return arbi.agents.grantTemporaryAccess(agentExtId, workspaceId, mode.ttlSeconds);
|
|
1040
|
+
}
|
|
1041
|
+
const agent = (await arbi.agents.list()).find((a) => a.external_id === agentExtId);
|
|
1042
|
+
if (!agent?.email) throw new Error("The agent's address is unknown.");
|
|
1043
|
+
return arbi.workspaces.grantAccess({ workspaceId, emails: [agent.email] });
|
|
1044
|
+
},
|
|
1045
|
+
onSuccess: (_res, { agentExtId }) => qc.invalidateQueries({ queryKey: arbiQueryKeys.agentWorkspaces(agentExtId) })
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
function useRevokeAgentAccess() {
|
|
1049
|
+
const arbi = useArbi();
|
|
1050
|
+
const qc = useQueryClient();
|
|
1051
|
+
return useMutation({
|
|
1052
|
+
mutationFn: async ({
|
|
1053
|
+
agentExtId,
|
|
1054
|
+
workspaceId
|
|
1055
|
+
}) => {
|
|
1056
|
+
const previous = arbi.hasWorkspace ? arbi.getWorkspaceId() : null;
|
|
1057
|
+
await arbi.selectWorkspace(workspaceId);
|
|
1058
|
+
try {
|
|
1059
|
+
await arbi.workspaces.removeUsers([agentExtId]);
|
|
1060
|
+
} finally {
|
|
1061
|
+
if (previous && previous !== workspaceId) await arbi.selectWorkspace(previous);
|
|
1062
|
+
}
|
|
1063
|
+
},
|
|
1064
|
+
onSuccess: (_res, { agentExtId }) => qc.invalidateQueries({ queryKey: arbiQueryKeys.agentWorkspaces(agentExtId) })
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
function useSkills(options) {
|
|
1068
|
+
const arbi = useArbi();
|
|
1069
|
+
return useQuery({
|
|
1070
|
+
queryKey: [...arbiQueryKeys.skills(), options?.includeHidden ?? false],
|
|
1071
|
+
queryFn: () => arbi.assistant.listSkills({ includeHidden: options?.includeHidden }),
|
|
1072
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn,
|
|
1073
|
+
staleTime: 3e4
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
function useContacts(options) {
|
|
1077
|
+
const arbi = useArbi();
|
|
1078
|
+
return useQuery({
|
|
1079
|
+
queryKey: arbiQueryKeys.contacts(),
|
|
1080
|
+
queryFn: () => arbi.contacts.list(),
|
|
1081
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function usePendingContacts(options) {
|
|
1085
|
+
const contacts = useContacts(options);
|
|
1086
|
+
const pending = useMemo(
|
|
1087
|
+
() => (contacts.data ?? []).filter(
|
|
1088
|
+
(c) => c.status === "invitation_pending" || c.status === "invitation_expired"
|
|
1089
|
+
),
|
|
1090
|
+
[contacts.data]
|
|
1091
|
+
);
|
|
1092
|
+
return { ...contacts, pending };
|
|
1093
|
+
}
|
|
1094
|
+
function useAddContacts() {
|
|
1095
|
+
const arbi = useArbi();
|
|
1096
|
+
const qc = useQueryClient();
|
|
1097
|
+
return useMutation({
|
|
1098
|
+
mutationFn: (emails) => arbi.contacts.add(emails),
|
|
1099
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.contacts() })
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
function useRemoveContacts() {
|
|
1103
|
+
const arbi = useArbi();
|
|
1104
|
+
const qc = useQueryClient();
|
|
1105
|
+
return useMutation({
|
|
1106
|
+
mutationFn: (contactIds) => arbi.contacts.remove(contactIds),
|
|
1107
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.contacts() })
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1619
1110
|
function useWorkspaceDocs(workspaceId) {
|
|
1620
1111
|
const { data: docs = [], isLoading, isError } = useDocuments(workspaceId);
|
|
1621
1112
|
const docIds = useMemo(
|
|
@@ -2753,7 +2244,11 @@ var CitationRendererComponent = ({
|
|
|
2753
2244
|
onDismissCitation,
|
|
2754
2245
|
notify2
|
|
2755
2246
|
]);
|
|
2756
|
-
return /* @__PURE__ */ jsx("div", { className: cn("citation-container", className), "data-testid": "citation-renderer", children: renderMarkdown({
|
|
2247
|
+
return /* @__PURE__ */ jsx("div", { className: cn("citation-container", className), "data-testid": "citation-renderer", children: renderMarkdown({
|
|
2248
|
+
components: markdownComponents,
|
|
2249
|
+
isStreaming,
|
|
2250
|
+
children: normalizeCitationMarkup(content)
|
|
2251
|
+
}) });
|
|
2757
2252
|
};
|
|
2758
2253
|
var CitationPopover = ({
|
|
2759
2254
|
citationNum,
|
|
@@ -3787,7 +3282,6 @@ function isAgentUser(user) {
|
|
|
3787
3282
|
return user.external_id.startsWith("agt-");
|
|
3788
3283
|
}
|
|
3789
3284
|
var DM_QUERY_KEY = ["arbi", "directMessages"];
|
|
3790
|
-
var CONTACTS_QUERY_KEY = ["arbi", "contacts"];
|
|
3791
3285
|
function mergeContacts(threads, contacts) {
|
|
3792
3286
|
const byPeer = /* @__PURE__ */ new Map();
|
|
3793
3287
|
for (const t of threads) byPeer.set(t.peer.external_id, t);
|
|
@@ -3853,7 +3347,7 @@ function useDirectMessages(options) {
|
|
|
3853
3347
|
enabled
|
|
3854
3348
|
});
|
|
3855
3349
|
const contactsQuery = useQuery({
|
|
3856
|
-
queryKey:
|
|
3350
|
+
queryKey: arbiQueryKeys.contacts(),
|
|
3857
3351
|
queryFn: () => arbi.contacts.list(),
|
|
3858
3352
|
enabled
|
|
3859
3353
|
});
|
|
@@ -3938,6 +3432,7 @@ function ConversationList({
|
|
|
3938
3432
|
classNames,
|
|
3939
3433
|
emptyState,
|
|
3940
3434
|
header,
|
|
3435
|
+
lead,
|
|
3941
3436
|
className
|
|
3942
3437
|
}) {
|
|
3943
3438
|
return /* @__PURE__ */ jsxs(
|
|
@@ -3957,6 +3452,7 @@ function ConversationList({
|
|
|
3957
3452
|
conversations.length === 1 ? "colleague" : "colleagues"
|
|
3958
3453
|
] })
|
|
3959
3454
|
] }) : header,
|
|
3455
|
+
lead,
|
|
3960
3456
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: conversations.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-xs text-muted-foreground", children: emptyState ?? "No conversations yet." }) : /* @__PURE__ */ jsx("ul", { className: "w-full", children: conversations.map((c, i) => {
|
|
3961
3457
|
const { peer, lastMessage, unreadCount } = c;
|
|
3962
3458
|
const newSection = c.sectionLabel && c.sectionLabel !== conversations[i - 1]?.sectionLabel;
|
|
@@ -4099,7 +3595,7 @@ function annotateThread(messages, accessors, runWindowMs = RUN_WINDOW_MS) {
|
|
|
4099
3595
|
function DateSeparator({ children }) {
|
|
4100
3596
|
return /* @__PURE__ */ jsx("div", { className: "my-3 flex justify-center", "data-testid": "dm-date-separator", children: /* @__PURE__ */ jsx("span", { className: "rounded-full bg-background/80 px-2 py-0.5 text-xs text-muted-foreground", children }) });
|
|
4101
3597
|
}
|
|
4102
|
-
function
|
|
3598
|
+
function MessageBubble({
|
|
4103
3599
|
message,
|
|
4104
3600
|
classNames,
|
|
4105
3601
|
isLastOfRun = true,
|
|
@@ -4165,7 +3661,7 @@ function MessageThread({
|
|
|
4165
3661
|
items.map(({ message: m, isLastOfRun, isFirstOfDay }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
4166
3662
|
isFirstOfDay && formatDay && /* @__PURE__ */ jsx(DateSeparator, { children: formatDay(m.createdAt) }),
|
|
4167
3663
|
/* @__PURE__ */ jsx(
|
|
4168
|
-
|
|
3664
|
+
MessageBubble,
|
|
4169
3665
|
{
|
|
4170
3666
|
message: m,
|
|
4171
3667
|
classNames,
|
|
@@ -4243,14 +3739,117 @@ function DmComposer({
|
|
|
4243
3739
|
error && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-destructive", "data-testid": "arbi-dm-error", children: error })
|
|
4244
3740
|
] });
|
|
4245
3741
|
}
|
|
3742
|
+
var DEFAULT_START_BY_EMAIL_LABELS = {
|
|
3743
|
+
email: "Email address",
|
|
3744
|
+
emailPlaceholder: "name@example.com",
|
|
3745
|
+
message: "Message",
|
|
3746
|
+
messagePlaceholder: "Write the first message\u2026",
|
|
3747
|
+
send: "Send",
|
|
3748
|
+
sending: "Sending\u2026",
|
|
3749
|
+
invalidEmail: "Enter a valid email address."
|
|
3750
|
+
};
|
|
3751
|
+
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3752
|
+
function StartByEmail({
|
|
3753
|
+
onStart,
|
|
3754
|
+
onStarted,
|
|
3755
|
+
classNames,
|
|
3756
|
+
labels,
|
|
3757
|
+
className
|
|
3758
|
+
}) {
|
|
3759
|
+
const l = { ...DEFAULT_START_BY_EMAIL_LABELS, ...labels };
|
|
3760
|
+
const uid = useId();
|
|
3761
|
+
const [email, setEmail] = useState("");
|
|
3762
|
+
const [text, setText] = useState("");
|
|
3763
|
+
const [busy, setBusy] = useState(false);
|
|
3764
|
+
const [error, setError] = useState(null);
|
|
3765
|
+
const address = email.trim().toLowerCase();
|
|
3766
|
+
const valid = EMAIL.test(address);
|
|
3767
|
+
const submit = async () => {
|
|
3768
|
+
if (!valid || !text.trim() || busy) return;
|
|
3769
|
+
setBusy(true);
|
|
3770
|
+
setError(null);
|
|
3771
|
+
try {
|
|
3772
|
+
const result = await onStart(address, text.trim());
|
|
3773
|
+
setEmail("");
|
|
3774
|
+
setText("");
|
|
3775
|
+
onStarted?.(result);
|
|
3776
|
+
} catch (e) {
|
|
3777
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
3778
|
+
} finally {
|
|
3779
|
+
setBusy(false);
|
|
3780
|
+
}
|
|
3781
|
+
};
|
|
3782
|
+
return /* @__PURE__ */ jsxs(
|
|
3783
|
+
"form",
|
|
3784
|
+
{
|
|
3785
|
+
"data-testid": "arbi-dm-start",
|
|
3786
|
+
className: cn("flex flex-col gap-2 border-b border-border px-4 py-3", className),
|
|
3787
|
+
onSubmit: (e) => {
|
|
3788
|
+
e.preventDefault();
|
|
3789
|
+
void submit();
|
|
3790
|
+
},
|
|
3791
|
+
children: [
|
|
3792
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `${uid}-email`, children: l.email }),
|
|
3793
|
+
/* @__PURE__ */ jsx(
|
|
3794
|
+
Input,
|
|
3795
|
+
{
|
|
3796
|
+
id: `${uid}-email`,
|
|
3797
|
+
type: "email",
|
|
3798
|
+
value: email,
|
|
3799
|
+
onChange: (e) => setEmail(e.target.value),
|
|
3800
|
+
placeholder: l.emailPlaceholder,
|
|
3801
|
+
"aria-invalid": email !== "" && !valid,
|
|
3802
|
+
"aria-describedby": email !== "" && !valid ? `${uid}-bad` : void 0,
|
|
3803
|
+
disabled: busy,
|
|
3804
|
+
"data-testid": "arbi-dm-start-email"
|
|
3805
|
+
}
|
|
3806
|
+
),
|
|
3807
|
+
email !== "" && !valid && /* @__PURE__ */ jsx("p", { id: `${uid}-bad`, className: "text-xs text-destructive", children: l.invalidEmail }),
|
|
3808
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `${uid}-text`, children: l.message }),
|
|
3809
|
+
/* @__PURE__ */ jsx(
|
|
3810
|
+
Textarea,
|
|
3811
|
+
{
|
|
3812
|
+
id: `${uid}-text`,
|
|
3813
|
+
value: text,
|
|
3814
|
+
onChange: (e) => setText(e.target.value),
|
|
3815
|
+
placeholder: l.messagePlaceholder,
|
|
3816
|
+
rows: 2,
|
|
3817
|
+
disabled: busy,
|
|
3818
|
+
"data-testid": "arbi-dm-start-message"
|
|
3819
|
+
}
|
|
3820
|
+
),
|
|
3821
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-xs text-destructive", "data-testid": "arbi-dm-start-error", children: error }),
|
|
3822
|
+
/* @__PURE__ */ jsxs(
|
|
3823
|
+
Button,
|
|
3824
|
+
{
|
|
3825
|
+
type: "submit",
|
|
3826
|
+
size: "sm",
|
|
3827
|
+
disabled: !valid || !text.trim() || busy,
|
|
3828
|
+
className: cn("self-end", classNames?.sendButton),
|
|
3829
|
+
"data-testid": "arbi-dm-start-send",
|
|
3830
|
+
children: [
|
|
3831
|
+
busy ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsx(Send, { className: "size-4", "aria-hidden": true }),
|
|
3832
|
+
busy ? l.sending : l.send
|
|
3833
|
+
]
|
|
3834
|
+
}
|
|
3835
|
+
)
|
|
3836
|
+
]
|
|
3837
|
+
}
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
4246
3840
|
function DirectMessages({
|
|
4247
3841
|
className,
|
|
4248
3842
|
classNames,
|
|
4249
|
-
emptyThread,
|
|
4250
|
-
emptyList
|
|
3843
|
+
emptyThread: emptyThread2,
|
|
3844
|
+
emptyList,
|
|
3845
|
+
listHeader,
|
|
3846
|
+
listLead,
|
|
3847
|
+
startByEmail,
|
|
3848
|
+
hideOwnContact
|
|
4251
3849
|
}) {
|
|
4252
3850
|
const {
|
|
4253
|
-
conversations,
|
|
3851
|
+
conversations: allConversations,
|
|
3852
|
+
myExtId,
|
|
4254
3853
|
isLoading,
|
|
4255
3854
|
isError,
|
|
4256
3855
|
error,
|
|
@@ -4260,6 +3859,14 @@ function DirectMessages({
|
|
|
4260
3859
|
markRead
|
|
4261
3860
|
} = useDirectMessages();
|
|
4262
3861
|
const [selectedPeerId, setSelectedPeerId] = useState(null);
|
|
3862
|
+
const conversations = useMemo(
|
|
3863
|
+
() => hideOwnContact && myExtId ? allConversations.filter((c) => c.peer.external_id !== myExtId) : allConversations,
|
|
3864
|
+
[allConversations, hideOwnContact, myExtId]
|
|
3865
|
+
);
|
|
3866
|
+
const openStarted = (created) => {
|
|
3867
|
+
const peer = Array.isArray(created) ? created[0]?.recipient?.external_id : void 0;
|
|
3868
|
+
if (peer) setSelectedPeerId(peer);
|
|
3869
|
+
};
|
|
4263
3870
|
const loadError = isError ? error instanceof Error ? error.message : "Couldn\u2019t load messages." : null;
|
|
4264
3871
|
const selected = useMemo(
|
|
4265
3872
|
() => conversations.find((c) => c.peer.external_id === selectedPeerId) ?? null,
|
|
@@ -4303,11 +3910,24 @@ function DirectMessages({
|
|
|
4303
3910
|
selectedPeerId: selected?.peer.external_id ?? null,
|
|
4304
3911
|
onSelect: setSelectedPeerId,
|
|
4305
3912
|
classNames,
|
|
4306
|
-
emptyState: isLoading ? "Loading messages\u2026" : emptyList
|
|
3913
|
+
emptyState: isLoading ? "Loading messages\u2026" : emptyList,
|
|
3914
|
+
header: listHeader,
|
|
3915
|
+
lead: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3916
|
+
listLead,
|
|
3917
|
+
startByEmail && /* @__PURE__ */ jsx(
|
|
3918
|
+
StartByEmail,
|
|
3919
|
+
{
|
|
3920
|
+
onStart: sendMessageTo,
|
|
3921
|
+
onStarted: openStarted,
|
|
3922
|
+
classNames,
|
|
3923
|
+
labels: typeof startByEmail === "object" ? startByEmail.labels : void 0
|
|
3924
|
+
}
|
|
3925
|
+
)
|
|
3926
|
+
] })
|
|
4307
3927
|
}
|
|
4308
3928
|
),
|
|
4309
3929
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
|
|
4310
|
-
/* @__PURE__ */ jsx(MessageThread, { conversation: selected, classNames, emptyState:
|
|
3930
|
+
/* @__PURE__ */ jsx(MessageThread, { conversation: selected, classNames, emptyState: emptyThread2 }),
|
|
4311
3931
|
selected ? /* @__PURE__ */ jsx(
|
|
4312
3932
|
DmComposer,
|
|
4313
3933
|
{
|
|
@@ -5712,6 +5332,6 @@ function hasVideoTrack(blob) {
|
|
|
5712
5332
|
});
|
|
5713
5333
|
}
|
|
5714
5334
|
|
|
5715
|
-
export { ActivityFeed, AiActionCard, AiAnswer, AppleIcon, ArbiBotIcon,
|
|
5335
|
+
export { ActivityFeed, AiActionCard, AiAnswer, AppleIcon, ArbiBotIcon, ArbiIcon, ArbiWebSocketProvider, ArtifactCanvas, ChatBubble, CitationRenderer, ClaudeIcon, CommandPalette, CommandPaletteProvider, ConversationList, DEFAULT_ASPECT_OPTIONS, DEFAULT_START_BY_EMAIL_LABELS, DEFAULT_USD_PER_CREDIT, DateSeparator, DirectMessages, DmAvatar, DmComposer, DocIcon, DocQaPanel, DocSearch, DocumentCardMenu, DocumentGallery, DocumentReview, DocumentTable, DraftTitleControls, FileIcon, FireworksIcon, GeminiIcon, GitHubIcon, GoogleIcon, HtmlIcon, ImageCropModal, ImageCropper, LinkedInIcon, MessageArtifactCard, MessageBubble, MessageThread, OpenAIIcon, PhotoCapture, ProviderIcon, RUN_WINDOW_MS, SemanticSearch, StartByEmail, TxtIcon, TypingIndicator, VideoCapture, VoiceNoteRecorder, XlsIcon, annotateThread, arbiQueryKeys, captureFrameAsBlob, creditsToUsd, cropImage, dayKey, describeActivity, formatCredits, getNotificationTypeMeta, getWorkspaceActionText, getWorkspaceKind, getWorkspaceSentPhrase, hasVideoTrack, isUsageMetered, isWorkspaceNotificationType, parseActivityContent, pickRecentWorkspaces, redlineStats, resolveActiveWorkspace, textToArtifact, titleFromQuestion, toRedlineMarkdown, toShellWorkspace, useActivity, useAddContacts, useAgentConfig, useAgentModels, useAgentWorkspaces, useAgents, useAiTask, useArbiChat, useArbiConnected, useArbiDocumentSync, useArbiShellWorkspaces, useArbiUiStore, useArbiWebSocket, useArbiWsContext, useArbiWsMessage, useArbiWsStatus, useArbiWsStore, useArbiWsTask, useArbiWsTasks, useAssistantQuery, useCameraStream, useCommandPalette, useConfigs, useContacts, useConversations, useCreateAgent, useCreateTask, useDeleteAgents, useDeleteTask, useDirectMessages, useDocuments, useFacts, useGrantAgentAccess, useHealth, useParsedDocument, usePendingContacts, useProjectInvoices, useProjectUsage, useProjects, useProjectsUsage, useRemoveContacts, useRevokeAgentAccess, useRunTask, useSaveAgentConfig, useSemanticSearch, useSessions, useShellWorkspaces, useSkills, useTags, useTaskRuns, useTasks, useThumbnails, useUpdateTask, useUserUsageToday, useVideoRecorder, useWorkspaceDocs, useWorkspaces, userDisplayName, userInitials };
|
|
5716
5336
|
//# sourceMappingURL=index.js.map
|
|
5717
5337
|
//# sourceMappingURL=index.js.map
|