@docyrus/ui-pro-ai-assistant 0.5.8 → 0.6.1

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.
@@ -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';
@@ -14539,6 +14539,78 @@ function GenerativeUIObject({
14539
14539
  }
14540
14540
  return null;
14541
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
+ }
14542
14614
  var isToolPart = (part) => part.type?.startsWith("tool-") || part.type === "dynamic-tool";
14543
14615
  var DISPLAY_ONLY_TOOLS = /* @__PURE__ */ new Set([
14544
14616
  "generateChart",
@@ -14609,6 +14681,7 @@ var MessageItem = memo(({
14609
14681
  onEditPrompt
14610
14682
  }) => {
14611
14683
  const { t } = useAssistantTranslation();
14684
+ const clientToolMap = useClientToolMap();
14612
14685
  const isAssistantMessage = message.role === "assistant";
14613
14686
  const isUserMessage = message.role === "user";
14614
14687
  const [isEditing, setIsEditing] = useState(false);
@@ -14637,6 +14710,23 @@ var MessageItem = memo(({
14637
14710
  }, [message.parts]);
14638
14711
  const renderToolPart = (part, messageId, idx) => {
14639
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
+ }
14640
14730
  const isSubagentTool = toolName.startsWith("call") && toolName.endsWith("Agent");
14641
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");
14642
14732
  if (isGenerativeTool) {
@@ -31870,6 +31960,7 @@ var DocyAssistant = ({
31870
31960
  initialFeatures,
31871
31961
  initialFiles,
31872
31962
  hostEnvironment,
31963
+ clientTools,
31873
31964
  ...props
31874
31965
  }) => {
31875
31966
  const config3 = useAssistantConfig();
@@ -31915,6 +32006,14 @@ var DocyAssistant = ({
31915
32006
  const authTokenRef = useRef("");
31916
32007
  const messageOptionsRef = useRef(null);
31917
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());
31918
32017
  useEffect(() => {
31919
32018
  selectedSessionIdRef.current = sessionState.selectedSessionId;
31920
32019
  }, [sessionState.selectedSessionId]);
@@ -31948,6 +32047,7 @@ var DocyAssistant = ({
31948
32047
  supportThinking: options3?.supportThinking,
31949
32048
  supportWorkCanvas: options3?.supportWorkCanvas,
31950
32049
  ...hostEnvironment ? { hostEnvironment } : {},
32050
+ ...clientToolDefsRef.current.length ? { clientTools: clientToolDefsRef.current } : {},
31951
32051
  ...options3?.filePaths?.length ? { files: options3.filePaths } : {}
31952
32052
  }
31953
32053
  };
@@ -31999,8 +32099,20 @@ var DocyAssistant = ({
31999
32099
  },
32000
32100
  onError: (error) => {
32001
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 });
32002
32113
  }
32003
32114
  });
32115
+ addToolOutputRef.current = addToolOutput;
32004
32116
  const isStreaming = status === "streaming";
32005
32117
  const isSubmitting = status === "submitted";
32006
32118
  const isLoading = isStreaming || isSubmitting;
@@ -32867,7 +32979,7 @@ var DocyAssistant = ({
32867
32979
  )
32868
32980
  ] });
32869
32981
  if (isInlineMode) {
32870
- return /* @__PURE__ */ jsxs(Fragment, { children: [
32982
+ return /* @__PURE__ */ jsxs(ClientToolsProvider, { tools: clientToolMap, children: [
32871
32983
  renderInlineViewContent({
32872
32984
  isFullscreen: isInlineFullscreen,
32873
32985
  enableSidebar: isInlineFullscreen ? true : enableSidebar,
@@ -32880,7 +32992,7 @@ var DocyAssistant = ({
32880
32992
  assistantDialogs
32881
32993
  ] });
32882
32994
  }
32883
- return /* @__PURE__ */ jsxs(Fragment, { children: [
32995
+ return /* @__PURE__ */ jsxs(ClientToolsProvider, { tools: clientToolMap, children: [
32884
32996
  /* @__PURE__ */ jsxs(Dialog$1, { open: isOpen, onOpenChange: (o) => {
32885
32997
  if (!o) onClose?.();
32886
32998
  }, children: [