@docyrus/ui-pro-ai-assistant 0.5.7 → 0.6.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.
@@ -48,6 +48,7 @@ interface AIInputAreaProps {
48
48
  tenantAiProjectId?: string;
49
49
  initialModelId?: string;
50
50
  initialFeatures?: InitialFeatureFlags;
51
+ onManageMemories?: () => void;
51
52
  }
52
53
  export declare const AIInputArea: FC<AIInputAreaProps>;
53
54
  export {};
@@ -1,5 +1,5 @@
1
1
  import { type RefObject } from 'react';
2
2
  import { type DocyAssistantProps } from './types';
3
- export declare const DocyAssistant: ({ ref, isOpen, onClose, supportWebSearch, supportThinking, supportFiles, supportDocumentSearch, supportDeepResearch, supportMultiModels, supportWorkCanvas, apiEndpoint, title: titleProp, description: descriptionProp, placeholder: placeholderProp, logo, footerText: footerTextProp, variant, renderMode, enableSidebar, enableNavDropdown, enableVoice, enableMicrophone, enableWelcomePage, tenantAiAgentId, onMessageSend, onVoiceStart, onVoiceEnd, className, defaultFullscreen, hideExpand, hideCloseButton, hideAgentSelector, hideBorder, showHeader, hideHeaderOnWelcome, agentSelectorUrl, baseAgentSelectorUrl, onAgentChange, enableSharing, onShare: onShareProp, initialPrompt, initialModelId, initialFeatures, initialFiles, hostEnvironment, ...props }: DocyAssistantProps & {
3
+ export declare const DocyAssistant: ({ ref, isOpen, onClose, supportWebSearch, supportThinking, supportFiles, supportDocumentSearch, supportDeepResearch, supportMultiModels, supportWorkCanvas, apiEndpoint, title: titleProp, description: descriptionProp, placeholder: placeholderProp, logo, footerText: footerTextProp, variant, renderMode, enableSidebar, enableNavDropdown, enableVoice, enableMicrophone, enableWelcomePage, tenantAiAgentId, onMessageSend, onVoiceStart, onVoiceEnd, className, defaultFullscreen, hideExpand, hideCloseButton, hideAgentSelector, hideBorder, showHeader, hideHeaderOnWelcome, agentSelectorUrl, baseAgentSelectorUrl, onAgentChange, enableSharing, onShare: onShareProp, initialPrompt, initialModelId, initialFeatures, initialFiles, hostEnvironment, clientTools, ...props }: DocyAssistantProps & {
4
4
  ref?: RefObject<HTMLDivElement | null>;
5
5
  }) => import("react/jsx-runtime").JSX.Element;
package/dist/index.d.ts CHANGED
@@ -3,5 +3,5 @@ export { type AssistantConfig, AssistantProvider, type AssistantUser, type DataS
3
3
  export { AssistantI18nProvider, useAssistantTranslation } from './i18n';
4
4
  export { AgentTriggerWidget, type AgentTriggerWidgetProps } from './components/agent-trigger-widget';
5
5
  export { type PromptFeatureFlags } from './components/agent-trigger-widget/agent-trigger-prompt';
6
- export type { InitialFeatureFlags, Principal, PrincipalType, Project, ShareItem, Work, WorkTypes } from './types';
6
+ export type { ClientTool, ClientToolExecuteContext, InitialFeatureFlags, Principal, PrincipalType, Project, ShareItem, Work, WorkTypes } from './types';
7
7
  export { BASE_DATA_SOURCE_ID, SHARE_PERMISSIONS, SHARE_PERMISSION_LEVELS } from './types';
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { Input } from '@docyrus/ui-pro-shared/components/input';
9
9
  import { Tabs as Tabs$1, TabsList as TabsList$1, TabsTrigger as TabsTrigger$1, TabsContent as TabsContent$1 } from '@docyrus/ui-pro-shared/components/tabs';
10
10
  import { cn } from '@docyrus/ui-pro-shared/lib/utils';
11
11
  import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
12
- import { Pencil, PilcrowIcon, Heading1Icon, Heading2Icon, Heading3Icon, SquareIcon, ListIcon, ListOrderedIcon, ChevronDownIcon, Code2Icon, QuoteIcon, LightbulbIcon, Columns3Icon, GripVertical, FileUpIcon, TableIcon, ImageIcon, FilmIcon, AudioLinesIcon, TableOfContentsIcon, RadicalIcon, RectangleVerticalIcon, CalendarIcon, PlusIcon, FileCodeIcon, MinusIcon, ChevronRightIcon, ListTree, PenToolIcon, Link2Icon, Check, X, Copy, FilesIcon, Link, Text, ExternalLink, Unlink, Bold, Italic, Underline, Strikethrough, Code2, MoreHorizontal, ArrowLeftIcon, ArrowRightIcon, Minus, Plus, CircleArrowDown, Minimize2, Trash2, FileUp, CheckCircle2, FileText, Loader2, CornerDownLeftIcon, PencilLineIcon, MessageSquareTextIcon, MessagesSquareIcon, ArrowUpIcon, CheckIcon, CaptionsIcon, ZoomInIcon, CircleArrowDownIcon, MoveUpRightIcon, MoreHorizontalIcon, Eye, PlusCircle, HelpCircle, Maximize2, Download, FileSpreadsheet, ChevronDown, ChevronLeft, ChevronRight, CheckCircle, XCircle, Search, Globe, User, ArrowRight, MapPin, CalendarClock, List, RefreshCw, FilePlus, XIcon, CornerUpLeftIcon, AlbumIcon, FeatherIcon, ListMinusIcon, ListPlusIcon, ListEnd, Wand, LanguagesIcon, BadgeHelpIcon, PenLineIcon, SearchIcon, MusicIcon, CompassIcon, SmileIcon, LeafIcon, ClockIcon, AppleIcon, FlagIcon, StarIcon, DeleteIcon, AlignLeft, AlignCenter, AlignRight, RotateCcw, AlertTriangle, AlertCircle, ArrowUpDown, ArrowDownToLine, PenLine, PencilIcon, TrashIcon, FileIcon, Star, ChevronsUpDown, FolderIcon, MessageSquare, Hash, Table, CheckSquare, Calendar as Calendar$1, Clock, Phone, Mail, Send, RefreshCcw, Undo2, ChevronsUpDownIcon, ChevronsRight, ChevronsLeft, CalendarDays, RefreshCwIcon, PaintRoller, MessageSquareText, ArrowLeft, Users, Bot, Brain, Lightbulb, BookOpen, PenTool, SlidersHorizontal, Wand2, Mic, Code, Trash, Edit, Share, FolderInput, Archive, Building2, ShieldCheck, Sparkles, PanelLeft, NotebookText, CirclePlus, MoreVertical, FileSearch, Microscope, Ruler, AudioLines, BrainCircuit, File as File$1, Plug, Inbox, Menu, FolderOpen, LayoutDashboard, Table2, WandSparklesIcon, ArrowUpToLineIcon, BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, HighlighterIcon, Undo2Icon, Redo2Icon, ArrowDownToLineIcon, AlignLeftIcon, AlignCenterIcon, AlignRightIcon, AlignJustifyIcon, ListOrdered, ListTodoIcon, ListCollapseIcon, Grid3x3Icon, Combine, Ungroup, ArrowUp, ArrowDown, Trash2Icon, LinkIcon, WrapText, OutdentIcon, IndentIcon, EyeIcon, PenIcon } from 'lucide-react';
12
+ import { Pencil, PilcrowIcon, Heading1Icon, Heading2Icon, Heading3Icon, SquareIcon, ListIcon, ListOrderedIcon, ChevronDownIcon, Code2Icon, QuoteIcon, LightbulbIcon, Columns3Icon, GripVertical, FileUpIcon, TableIcon, ImageIcon, FilmIcon, AudioLinesIcon, TableOfContentsIcon, RadicalIcon, RectangleVerticalIcon, CalendarIcon, PlusIcon, FileCodeIcon, MinusIcon, ChevronRightIcon, ListTree, PenToolIcon, Link2Icon, Check, X, Copy, FilesIcon, Link, Text, ExternalLink, Unlink, Bold, Italic, Underline, Strikethrough, Code2, MoreHorizontal, ArrowLeftIcon, ArrowRightIcon, Minus, Plus, CircleArrowDown, Minimize2, Trash2, FileUp, CheckCircle2, FileText, Loader2, Wrench, CornerDownLeftIcon, PencilLineIcon, MessageSquareTextIcon, MessagesSquareIcon, ArrowUpIcon, CheckIcon, CaptionsIcon, ZoomInIcon, CircleArrowDownIcon, MoveUpRightIcon, MoreHorizontalIcon, Eye, PlusCircle, HelpCircle, Maximize2, Download, FileSpreadsheet, ChevronDown, ChevronLeft, ChevronRight, CheckCircle, XCircle, Search, Globe, User, ArrowRight, MapPin, CalendarClock, List, RefreshCw, FilePlus, XIcon, CornerUpLeftIcon, AlbumIcon, FeatherIcon, ListMinusIcon, ListPlusIcon, ListEnd, Wand, LanguagesIcon, BadgeHelpIcon, PenLineIcon, SearchIcon, MusicIcon, CompassIcon, SmileIcon, LeafIcon, ClockIcon, AppleIcon, FlagIcon, StarIcon, DeleteIcon, AlignLeft, AlignCenter, AlignRight, RotateCcw, AlertTriangle, AlertCircle, ArrowUpDown, ArrowDownToLine, PenLine, PencilIcon, TrashIcon, FileIcon, Star, ChevronsUpDown, FolderIcon, MessageSquare, Hash, Table, CheckSquare, Calendar as Calendar$1, Clock, Phone, Mail, Send, RefreshCcw, Undo2, ChevronsUpDownIcon, ChevronsRight, ChevronsLeft, CalendarDays, RefreshCwIcon, PaintRoller, MessageSquareText, ArrowLeft, Users, Bot, Brain, Lightbulb, BookOpen, PenTool, SlidersHorizontal, Wand2, Mic, Code, Trash, Edit, Share, FolderInput, Archive, Building2, ShieldCheck, Sparkles, PanelLeft, NotebookText, CirclePlus, MoreVertical, FileSearch, Microscope, Ruler, AudioLines, BrainCircuit, File as File$1, Plug, Inbox, Menu, FolderOpen, LayoutDashboard, Table2, WandSparklesIcon, ArrowUpToLineIcon, BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, HighlighterIcon, Undo2Icon, Redo2Icon, ArrowDownToLineIcon, AlignLeftIcon, AlignCenterIcon, AlignRightIcon, AlignJustifyIcon, ListOrdered, ListTodoIcon, ListCollapseIcon, Grid3x3Icon, Combine, Ungroup, ArrowUp, ArrowDown, Trash2Icon, LinkIcon, WrapText, OutdentIcon, IndentIcon, EyeIcon, PenIcon } from 'lucide-react';
13
13
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
14
14
  import { ScrollArea as ScrollArea$1 } from '@docyrus/ui-pro-shared/components/scroll-area';
15
15
  import { AsyncTokenManager, RestApiClient } from '@docyrus/api-client';
@@ -5522,7 +5522,8 @@ var AIInputArea = ({
5522
5522
  hideFooter = false,
5523
5523
  tenantAiProjectId,
5524
5524
  initialModelId,
5525
- initialFeatures
5525
+ initialFeatures,
5526
+ onManageMemories
5526
5527
  }) => {
5527
5528
  const { t } = useAssistantTranslation();
5528
5529
  const apiClient = useApiClient();
@@ -6237,20 +6238,38 @@ var AIInputArea = ({
6237
6238
  ),
6238
6239
  !hideFooter && /* @__PURE__ */ jsxs("div", { className: "relative mt-2 flex items-center px-1", children: [
6239
6240
  footerText && /* @__PURE__ */ jsx("span", { className: "flex-1 text-center text-xs text-muted-foreground", children: footerText }),
6240
- /* @__PURE__ */ jsxs(Tooltip$2, { children: [
6241
- /* @__PURE__ */ jsx(TooltipTrigger$1, { asChild: true, children: /* @__PURE__ */ jsx(
6242
- Button,
6243
- {
6244
- type: "button",
6245
- variant: "ghost",
6246
- size: "icon",
6247
- className: "absolute right-0 h-6 w-6 text-muted-foreground",
6248
- disabled: !threadId || !hasMessages,
6249
- onClick: handleExtractMemories,
6250
- children: /* @__PURE__ */ jsx(BrainCircuit, { className: "h-3.5 w-3.5" })
6251
- }
6252
- ) }),
6253
- /* @__PURE__ */ jsx(TooltipContent$1, { side: "top", children: t("tools.extract_memories") })
6241
+ /* @__PURE__ */ jsxs(DropdownMenu$1, { children: [
6242
+ /* @__PURE__ */ jsxs(Tooltip$2, { children: [
6243
+ /* @__PURE__ */ jsx(TooltipTrigger$1, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6244
+ Button,
6245
+ {
6246
+ type: "button",
6247
+ variant: "ghost",
6248
+ size: "icon",
6249
+ className: "absolute right-0 h-6 w-6 text-muted-foreground",
6250
+ children: /* @__PURE__ */ jsx(BrainCircuit, { className: "h-3.5 w-3.5" })
6251
+ }
6252
+ ) }) }),
6253
+ /* @__PURE__ */ jsx(TooltipContent$1, { side: "top", children: t("tools.extract_memories") })
6254
+ ] }),
6255
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", side: "top", className: "w-60", children: [
6256
+ /* @__PURE__ */ jsx(
6257
+ DropdownMenuItem,
6258
+ {
6259
+ disabled: !threadId || !hasMessages,
6260
+ onClick: handleExtractMemories,
6261
+ children: "Extract Memories from Session"
6262
+ }
6263
+ ),
6264
+ /* @__PURE__ */ jsx(
6265
+ DropdownMenuItem,
6266
+ {
6267
+ disabled: !onManageMemories,
6268
+ onClick: () => onManageMemories?.(),
6269
+ children: "Manage Memories"
6270
+ }
6271
+ )
6272
+ ] })
6254
6273
  ] })
6255
6274
  ] }),
6256
6275
  /* @__PURE__ */ jsx(
@@ -14520,6 +14539,78 @@ function GenerativeUIObject({
14520
14539
  }
14521
14540
  return null;
14522
14541
  }
14542
+ var EMPTY_MAP = /* @__PURE__ */ new Map();
14543
+ var ClientToolsContext = createContext(EMPTY_MAP);
14544
+ function ClientToolsProvider({
14545
+ tools,
14546
+ children
14547
+ }) {
14548
+ return /* @__PURE__ */ jsx(ClientToolsContext, { value: tools, children });
14549
+ }
14550
+ function useClientToolMap() {
14551
+ return use(ClientToolsContext);
14552
+ }
14553
+ function buildClientToolMap(tools) {
14554
+ const map = /* @__PURE__ */ new Map();
14555
+ for (const tool of tools ?? []) {
14556
+ if (tool?.name && !map.has(tool.name)) {
14557
+ map.set(tool.name, tool);
14558
+ }
14559
+ }
14560
+ return map;
14561
+ }
14562
+ function serializeClientTools(tools) {
14563
+ return (tools ?? []).filter((tool) => !!tool?.name).map((tool) => ({
14564
+ name: tool.name,
14565
+ description: tool.description,
14566
+ parameters: tool.parameters ?? {
14567
+ $schema: "http://json-schema.org/draft-07/schema#",
14568
+ type: "object",
14569
+ additionalProperties: false,
14570
+ properties: {}
14571
+ }
14572
+ }));
14573
+ }
14574
+ async function runClientTool(tool, input, context) {
14575
+ try {
14576
+ const result = await tool.execute(input, context);
14577
+ return { success: true, result: result ?? null };
14578
+ } catch (error) {
14579
+ return {
14580
+ success: false,
14581
+ error: error instanceof Error ? error.message : String(error)
14582
+ };
14583
+ }
14584
+ }
14585
+ function resolveStatus(part) {
14586
+ if (part.state === "output-error") return "error";
14587
+ if (part.state === "output-available") {
14588
+ return part.output && part.output.success === false ? "error" : "success";
14589
+ }
14590
+ return "running";
14591
+ }
14592
+ function ClientToolCall({ tool, part }) {
14593
+ const status = resolveStatus(part);
14594
+ const title = status === "running" ? tool.progressMessage ?? `Running ${tool.name}\u2026` : status === "success" ? tool.successMessage ?? `${tool.name} completed` : tool.failMessage ?? `${tool.name} failed`;
14595
+ const errorDetail = status === "error" ? part.output?.error || part.errorText || void 0 : void 0;
14596
+ return /* @__PURE__ */ jsxs(
14597
+ "div",
14598
+ {
14599
+ className: cn(
14600
+ "my-2 flex items-center gap-2.5 rounded-lg border px-3 py-2 text-sm",
14601
+ status === "error" ? "border-destructive/40 bg-destructive/5" : "border-border bg-muted/40"
14602
+ ),
14603
+ children: [
14604
+ /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center text-muted-foreground", children: status === "running" ? /* @__PURE__ */ jsx(Spinner, { className: "h-4 w-4" }) : status === "success" ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-emerald-600 dark:text-emerald-500" }) : /* @__PURE__ */ jsx(X, { className: "h-4 w-4 text-destructive" }) }),
14605
+ /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center text-muted-foreground", children: tool.icon ?? /* @__PURE__ */ jsx(Wrench, { className: "h-4 w-4" }) }),
14606
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
14607
+ /* @__PURE__ */ jsx("div", { className: "truncate font-medium text-foreground", children: title }),
14608
+ errorDetail ? /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-destructive", children: errorDetail }) : null
14609
+ ] })
14610
+ ]
14611
+ }
14612
+ );
14613
+ }
14523
14614
  var isToolPart = (part) => part.type?.startsWith("tool-") || part.type === "dynamic-tool";
14524
14615
  var DISPLAY_ONLY_TOOLS = /* @__PURE__ */ new Set([
14525
14616
  "generateChart",
@@ -14590,6 +14681,7 @@ var MessageItem = memo(({
14590
14681
  onEditPrompt
14591
14682
  }) => {
14592
14683
  const { t } = useAssistantTranslation();
14684
+ const clientToolMap = useClientToolMap();
14593
14685
  const isAssistantMessage = message.role === "assistant";
14594
14686
  const isUserMessage = message.role === "user";
14595
14687
  const [isEditing, setIsEditing] = useState(false);
@@ -14618,6 +14710,23 @@ var MessageItem = memo(({
14618
14710
  }, [message.parts]);
14619
14711
  const renderToolPart = (part, messageId, idx) => {
14620
14712
  const toolName = part.type === "dynamic-tool" ? part.toolName : part.type?.startsWith("tool-") ? part.type.replace(/^tool-/, "") : part.toolName || "Unknown Tool";
14713
+ const clientTool = clientToolMap.get(toolName);
14714
+ if (clientTool) {
14715
+ return /* @__PURE__ */ jsx(
14716
+ ClientToolCall,
14717
+ {
14718
+ tool: clientTool,
14719
+ part: {
14720
+ state: part.state || "input-available",
14721
+ input: part.args || part.input,
14722
+ output: part.output,
14723
+ errorText: part.errorText,
14724
+ toolCallId: part.toolCallId || `${messageId}-${idx}`
14725
+ }
14726
+ },
14727
+ `${messageId}-clienttool-${idx}`
14728
+ );
14729
+ }
14621
14730
  const isSubagentTool = toolName.startsWith("call") && toolName.endsWith("Agent");
14622
14731
  const isGenerativeTool = DISPLAY_ONLY_TOOLS.has(toolName) || INTERACTIVE_GENERATIVE_TOOLS.has(toolName) && !!onToolAction || isSubagentTool && (part.state === "input-available" || part.state === "input-streaming" || part.state === "output-available");
14623
14732
  if (isGenerativeTool) {
@@ -14875,7 +14984,8 @@ function ChatPanel({
14875
14984
  threadId,
14876
14985
  initialModelId,
14877
14986
  initialFeatures,
14878
- subagents
14987
+ subagents,
14988
+ onManageMemories
14879
14989
  }) {
14880
14990
  const renderInputArea = (hideFooter = false) => /* @__PURE__ */ jsx(
14881
14991
  AIInputArea,
@@ -14907,7 +15017,8 @@ function ChatPanel({
14907
15017
  hasMessages: messages.length > 0,
14908
15018
  hideFooter,
14909
15019
  initialModelId,
14910
- initialFeatures
15020
+ initialFeatures,
15021
+ onManageMemories
14911
15022
  }
14912
15023
  );
14913
15024
  const isWelcome = showWelcome && messages.length === 0;
@@ -30332,21 +30443,7 @@ var AssistantView = ({ ref, ...props }) => {
30332
30443
  children: /* @__PURE__ */ jsx(PanelLeft, { className: "w-4 h-4" })
30333
30444
  }
30334
30445
  ),
30335
- onTabChange && /* @__PURE__ */ jsx(
30336
- Button,
30337
- {
30338
- variant: "ghost",
30339
- size: "icon",
30340
- onClick: () => onTabChange(activeTab === 4 ? 0 : 4),
30341
- className: cn(
30342
- "h-8 w-8 text-foreground hover:bg-accent hover:text-accent-foreground rounded-md",
30343
- activeTab === 4 && "bg-background text-foreground shadow"
30344
- ),
30345
- title: t("tabs.memories"),
30346
- children: /* @__PURE__ */ jsx(Brain, { className: "w-4 h-4" })
30347
- }
30348
- ),
30349
- isFullscreen && onNewChat && /* @__PURE__ */ jsx(
30446
+ onNewChat && /* @__PURE__ */ jsx(
30350
30447
  Button,
30351
30448
  {
30352
30449
  variant: "ghost",
@@ -30397,32 +30494,16 @@ var AssistantView = ({ ref, ...props }) => {
30397
30494
  isSidebarOpen ? "w-72" : "w-0"
30398
30495
  ),
30399
30496
  children: /* @__PURE__ */ jsxs("div", { className: "w-72 h-full flex flex-col relative", children: [
30400
- isSidebarOpen && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 z-10 flex flex-col gap-1", children: [
30401
- onToggleSidebar && /* @__PURE__ */ jsx(
30402
- Button,
30403
- {
30404
- variant: "ghost",
30405
- size: "icon",
30406
- onClick: onToggleSidebar,
30407
- className: "h-8 w-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground rounded-md",
30408
- children: /* @__PURE__ */ jsx(PanelLeft, { className: "w-4 h-4" })
30409
- }
30410
- ),
30411
- onTabChange && /* @__PURE__ */ jsx(
30412
- Button,
30413
- {
30414
- variant: "ghost",
30415
- size: "icon",
30416
- onClick: () => onTabChange(activeTab === 4 ? 0 : 4),
30417
- className: cn(
30418
- "h-8 w-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground rounded-md",
30419
- activeTab === 4 && "bg-accent text-accent-foreground"
30420
- ),
30421
- title: t("tabs.memories"),
30422
- children: /* @__PURE__ */ jsx(Brain, { className: "w-4 h-4" })
30423
- }
30424
- )
30425
- ] }),
30497
+ isSidebarOpen && /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2 z-10 flex flex-col gap-1", children: onToggleSidebar && /* @__PURE__ */ jsx(
30498
+ Button,
30499
+ {
30500
+ variant: "ghost",
30501
+ size: "icon",
30502
+ onClick: onToggleSidebar,
30503
+ className: "h-8 w-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground rounded-md",
30504
+ children: /* @__PURE__ */ jsx(PanelLeft, { className: "w-4 h-4" })
30505
+ }
30506
+ ) }),
30426
30507
  /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4 flex flex-col min-h-0 overflow-hidden", children: [
30427
30508
  !showHeader && agentSelectorElement && /* @__PURE__ */ jsx("div", { className: "mb-3 shrink-0", children: agentSelectorElement }),
30428
30509
  renderSidebar(false)
@@ -30539,6 +30620,7 @@ var AssistantView = ({ ref, ...props }) => {
30539
30620
  initialModelId: commonProps.initialModelId,
30540
30621
  initialFeatures: commonProps.initialFeatures,
30541
30622
  subagents: commonProps.subagents,
30623
+ onManageMemories: onTabChange ? () => onTabChange(4) : void 0,
30542
30624
  compactToolbar: !isFullscreen
30543
30625
  }
30544
30626
  )
@@ -31878,6 +31960,7 @@ var DocyAssistant = ({
31878
31960
  initialFeatures,
31879
31961
  initialFiles,
31880
31962
  hostEnvironment,
31963
+ clientTools,
31881
31964
  ...props
31882
31965
  }) => {
31883
31966
  const config3 = useAssistantConfig();
@@ -31923,6 +32006,14 @@ var DocyAssistant = ({
31923
32006
  const authTokenRef = useRef("");
31924
32007
  const messageOptionsRef = useRef(null);
31925
32008
  const initialPromptSentRef = useRef(false);
32009
+ const clientToolMap = useMemo(() => buildClientToolMap(clientTools), [clientTools]);
32010
+ const clientToolDefs = useMemo(() => serializeClientTools(clientTools), [clientTools]);
32011
+ const clientToolMapRef = useRef(clientToolMap);
32012
+ clientToolMapRef.current = clientToolMap;
32013
+ const clientToolDefsRef = useRef(clientToolDefs);
32014
+ clientToolDefsRef.current = clientToolDefs;
32015
+ const addToolOutputRef = useRef(null);
32016
+ const executedClientToolCallsRef = useRef(/* @__PURE__ */ new Set());
31926
32017
  useEffect(() => {
31927
32018
  selectedSessionIdRef.current = sessionState.selectedSessionId;
31928
32019
  }, [sessionState.selectedSessionId]);
@@ -31956,6 +32047,7 @@ var DocyAssistant = ({
31956
32047
  supportThinking: options3?.supportThinking,
31957
32048
  supportWorkCanvas: options3?.supportWorkCanvas,
31958
32049
  ...hostEnvironment ? { hostEnvironment } : {},
32050
+ ...clientToolDefsRef.current.length ? { clientTools: clientToolDefsRef.current } : {},
31959
32051
  ...options3?.filePaths?.length ? { files: options3.filePaths } : {}
31960
32052
  }
31961
32053
  };
@@ -32007,8 +32099,20 @@ var DocyAssistant = ({
32007
32099
  },
32008
32100
  onError: (error) => {
32009
32101
  console.error("[AI] Chat error:", error);
32102
+ },
32103
+ onToolCall: async ({ toolCall }) => {
32104
+ const name = toolCall?.toolName;
32105
+ const tool = name ? clientToolMapRef.current.get(name) : void 0;
32106
+ if (!tool) return;
32107
+ const { toolCallId } = toolCall;
32108
+ if (executedClientToolCallsRef.current.has(toolCallId)) return;
32109
+ executedClientToolCallsRef.current.add(toolCallId);
32110
+ const input2 = toolCall.input ?? toolCall.args ?? {};
32111
+ const output = await runClientTool(tool, input2, { toolCallId });
32112
+ addToolOutputRef.current?.({ tool: name, toolCallId, output });
32010
32113
  }
32011
32114
  });
32115
+ addToolOutputRef.current = addToolOutput;
32012
32116
  const isStreaming = status === "streaming";
32013
32117
  const isSubmitting = status === "submitted";
32014
32118
  const isLoading = isStreaming || isSubmitting;
@@ -32875,7 +32979,7 @@ var DocyAssistant = ({
32875
32979
  )
32876
32980
  ] });
32877
32981
  if (isInlineMode) {
32878
- return /* @__PURE__ */ jsxs(Fragment, { children: [
32982
+ return /* @__PURE__ */ jsxs(ClientToolsProvider, { tools: clientToolMap, children: [
32879
32983
  renderInlineViewContent({
32880
32984
  isFullscreen: isInlineFullscreen,
32881
32985
  enableSidebar: isInlineFullscreen ? true : enableSidebar,
@@ -32888,7 +32992,7 @@ var DocyAssistant = ({
32888
32992
  assistantDialogs
32889
32993
  ] });
32890
32994
  }
32891
- return /* @__PURE__ */ jsxs(Fragment, { children: [
32995
+ return /* @__PURE__ */ jsxs(ClientToolsProvider, { tools: clientToolMap, children: [
32892
32996
  /* @__PURE__ */ jsxs(Dialog$1, { open: isOpen, onOpenChange: (o) => {
32893
32997
  if (!o) onClose?.();
32894
32998
  }, children: [