@docyrus/ui-pro-ai-assistant 0.6.3 → 0.6.5

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 CHANGED
@@ -262,6 +262,9 @@ The main chat interface component.
262
262
  |------|------|---------|-------------|
263
263
  | `apiEndpoint` | `string` | `"/ai/agents/:agentId/chat"` | Chat endpoint template (`:agentId` is replaced at runtime) |
264
264
  | `hostEnvironment` | `string` | — | Host environment identifier sent to the chat endpoint as `hostEnvironment`. The backend uses this to filter the tool list bound to the agent so only tools available in the current environment are exposed. Common values: `"web"`, `"desktop"`, `"chrome"`, `"word"`, `"excel"`, `"powerpoint"`, `"outlook"` |
265
+ | `appId` | `string` | — | ID of the host app currently open in the page. Forwarded to the chat endpoint as `appId` so the agent can scope its behavior/tools to it. Renders a dismissable "Talking about <app>" chip above the input; once the user clears it, the id stops being sent |
266
+ | `appName` | `string` | — | Display name for the current host app, shown in the context chip |
267
+ | `appLogo` | `string` | — | Logo URL for the current host app, shown in the context chip |
265
268
 
266
269
  #### Callbacks
267
270
 
@@ -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, clientTools, ...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, appId, appName, appLogo, clientTools, ...props }: DocyAssistantProps & {
4
4
  ref?: RefObject<HTMLDivElement | null>;
5
5
  }) => import("react/jsx-runtime").JSX.Element;
package/dist/index.js CHANGED
@@ -12377,10 +12377,23 @@ function GenerativeActionButton({
12377
12377
  }
12378
12378
  );
12379
12379
  }
12380
+ var STREAMING_DEBOUNCE_MS = 250;
12381
+ var mermaidPromise = null;
12382
+ var loadMermaid = () => {
12383
+ if (!mermaidPromise) {
12384
+ mermaidPromise = import('mermaid').then((mod) => {
12385
+ mod.default.initialize({ startOnLoad: false, securityLevel: "loose" });
12386
+ return mod.default;
12387
+ });
12388
+ }
12389
+ return mermaidPromise;
12390
+ };
12380
12391
  function MermaidRender({ content, className }) {
12381
12392
  const containerRef = useRef(null);
12382
- const svgRef = useRef(null);
12383
- const [svg, setSvg] = useState("");
12393
+ const svgHostRef = useRef(null);
12394
+ const sandboxRef = useRef(null);
12395
+ const [status, setStatus] = useState("idle");
12396
+ const [errorMessage, setErrorMessage] = useState(null);
12384
12397
  const [zoom, setZoom] = useState(1);
12385
12398
  const [pan, setPan] = useState({ x: 0, y: 0 });
12386
12399
  const isDragging = useRef(false);
@@ -12388,20 +12401,34 @@ function MermaidRender({ content, className }) {
12388
12401
  useEffect(() => {
12389
12402
  if (!content) return;
12390
12403
  let cancelled = false;
12391
- const render = async () => {
12404
+ const debounce = window.setTimeout(async () => {
12392
12405
  try {
12393
- const { default: mermaid } = await import('mermaid');
12394
- mermaid.initialize({ startOnLoad: false, securityLevel: "loose" });
12406
+ const mermaid = await loadMermaid();
12407
+ if (cancelled) return;
12408
+ const valid = await mermaid.parse(content, { suppressErrors: true });
12409
+ if (cancelled) return;
12410
+ if (!valid) {
12411
+ setErrorMessage("Invalid mermaid syntax");
12412
+ setStatus("error");
12413
+ return;
12414
+ }
12395
12415
  const id = `mermaid-${Math.random().toString(36).slice(2)}`;
12396
- const { svg: rendered } = await mermaid.render(id, content);
12397
- if (!cancelled) setSvg(rendered);
12416
+ const sandbox = sandboxRef.current ?? void 0;
12417
+ const { svg } = await mermaid.render(id, content, sandbox);
12418
+ if (cancelled) return;
12419
+ if (svgHostRef.current) svgHostRef.current.innerHTML = svg;
12420
+ setErrorMessage(null);
12421
+ setStatus("rendered");
12398
12422
  } catch (err) {
12423
+ if (cancelled) return;
12399
12424
  console.error("Mermaid render error:", err);
12425
+ setErrorMessage("Failed to render diagram");
12426
+ setStatus("error");
12400
12427
  }
12401
- };
12402
- render();
12428
+ }, STREAMING_DEBOUNCE_MS);
12403
12429
  return () => {
12404
12430
  cancelled = true;
12431
+ window.clearTimeout(debounce);
12405
12432
  };
12406
12433
  }, [content]);
12407
12434
  const zoomIn = () => setZoom((z) => Math.min(z + 0.15, 4));
@@ -12449,13 +12476,13 @@ function MermaidRender({ content, className }) {
12449
12476
  onMouseUp,
12450
12477
  onMouseLeave: onMouseUp,
12451
12478
  children: [
12452
- /* @__PURE__ */ jsx(
12479
+ /* @__PURE__ */ jsx("div", { ref: sandboxRef, "aria-hidden": true, className: "absolute -left-[99999px] top-0 h-0 w-0 overflow-hidden" }),
12480
+ status === "error" ? /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center p-4 text-xs text-muted-foreground", children: errorMessage }) : /* @__PURE__ */ jsx(
12453
12481
  "div",
12454
12482
  {
12455
- ref: svgRef,
12483
+ ref: svgHostRef,
12456
12484
  className: "absolute inset-0 flex items-center justify-center",
12457
- style: { transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`, transformOrigin: "center" },
12458
- dangerouslySetInnerHTML: { __html: svg }
12485
+ style: { transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`, transformOrigin: "center" }
12459
12486
  }
12460
12487
  ),
12461
12488
  /* @__PURE__ */ jsxs("div", { className: "absolute bottom-3 left-3 z-10 flex gap-1", children: [
@@ -14989,8 +15016,27 @@ function ChatPanel({
14989
15016
  initialModelId,
14990
15017
  initialFeatures,
14991
15018
  subagents,
14992
- onManageMemories
15019
+ onManageMemories,
15020
+ appContext,
15021
+ onClearAppContext
14993
15022
  }) {
15023
+ const renderAppContextChip = () => {
15024
+ if (!appContext) return null;
15025
+ return /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2 self-start rounded-full border bg-muted/50 px-2 py-1 text-xs text-foreground", children: [
15026
+ appContext.logo ? /* @__PURE__ */ jsx("img", { src: appContext.logo, alt: "", className: "size-4 rounded" }) : null,
15027
+ /* @__PURE__ */ jsx("span", { className: "max-w-[200px] truncate", children: appContext.name ? `Talking about ${appContext.name}` : "App context attached" }),
15028
+ onClearAppContext ? /* @__PURE__ */ jsx(
15029
+ "button",
15030
+ {
15031
+ type: "button",
15032
+ "aria-label": "Remove app context",
15033
+ onClick: onClearAppContext,
15034
+ className: "text-muted-foreground hover:text-foreground",
15035
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
15036
+ }
15037
+ ) : null
15038
+ ] });
15039
+ };
14994
15040
  const renderInputArea = (hideFooter = false) => /* @__PURE__ */ jsx(
14995
15041
  AIInputArea,
14996
15042
  {
@@ -15045,7 +15091,10 @@ function ChatPanel({
15045
15091
  /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 pb-6", children: isLoadingAgent ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "p-2 bg-muted rounded-md", children: /* @__PURE__ */ jsx(Spinner, { className: "size-10 text-muted-foreground" }) }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
15046
15092
  hasAgentAnimations(tenantAiAgentId) ? /* @__PURE__ */ jsx(AssistantAnimations, { animationType: "opening", agentId: tenantAiAgentId, className: "w-10 h-10" }) : logo ? /* @__PURE__ */ jsx(AIMessageAvatar, { src: logo, name: title || "Assistant", className: "w-10 h-10" }) : /* @__PURE__ */ jsx(AssistantAnimations, { animationType: "opening", className: "w-10 h-10" }),
15047
15093
  /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground [&_h4]:text-foreground [&_*]:my-0 [&_*+*]:mt-2", children: welcomeMessage ? /* @__PURE__ */ jsx(MessageResponse, { children: welcomeMessage }) : /* @__PURE__ */ jsx("p", { children: description || "Your AI-powered assistant for all your document needs." }) }),
15048
- /* @__PURE__ */ jsx("div", { className: "mt-2", children: renderInputArea(true) })
15094
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-col", children: [
15095
+ renderAppContextChip(),
15096
+ renderInputArea(true)
15097
+ ] })
15049
15098
  ] }) }),
15050
15099
  recentSessions && recentSessions.length > 0 && !isLoadingAgent ? /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-3", children: [
15051
15100
  /* @__PURE__ */ jsx("h2", { className: "shrink-0 text-sm font-medium text-muted-foreground", children: "Recent Sessions" }),
@@ -15090,7 +15139,10 @@ function ChatPanel({
15090
15139
  className: messagesClassName
15091
15140
  }
15092
15141
  ),
15093
- /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 pt-2", children: renderInputArea() })
15142
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col px-3 pb-3 pt-2", children: [
15143
+ renderAppContextChip(),
15144
+ renderInputArea()
15145
+ ] })
15094
15146
  ] });
15095
15147
  }
15096
15148
  var ALLOWED_ORIGINS = ["https://shell.docy.work", "https://shell-docyrus.web.app"];
@@ -30194,6 +30246,8 @@ var AssistantView = ({ ref, ...props }) => {
30194
30246
  initialModelId: commonProps2.initialModelId,
30195
30247
  initialFeatures: commonProps2.initialFeatures,
30196
30248
  subagents: commonProps2.subagents,
30249
+ appContext: commonProps2.appContext,
30250
+ onClearAppContext: commonProps2.onClearAppContext,
30197
30251
  messagesClassName: "p-4"
30198
30252
  }
30199
30253
  );
@@ -30624,6 +30678,8 @@ var AssistantView = ({ ref, ...props }) => {
30624
30678
  initialModelId: commonProps.initialModelId,
30625
30679
  initialFeatures: commonProps.initialFeatures,
30626
30680
  subagents: commonProps.subagents,
30681
+ appContext: commonProps.appContext,
30682
+ onClearAppContext: commonProps.onClearAppContext,
30627
30683
  onManageMemories: onTabChange ? () => onTabChange(4) : void 0,
30628
30684
  compactToolbar: !isFullscreen
30629
30685
  }
@@ -31964,6 +32020,9 @@ var DocyAssistant = ({
31964
32020
  initialFeatures,
31965
32021
  initialFiles,
31966
32022
  hostEnvironment,
32023
+ appId,
32024
+ appName,
32025
+ appLogo,
31967
32026
  clientTools,
31968
32027
  ...props
31969
32028
  }) => {
@@ -32000,6 +32059,13 @@ var DocyAssistant = ({
32000
32059
  const [projectSearchQuery, setProjectSearchQuery] = useState("");
32001
32060
  const [isInlineFullscreen, setIsInlineFullscreen] = useState(defaultFullscreen);
32002
32061
  const [sharingEditorOpen, setSharingEditorOpen] = useState(false);
32062
+ const [appContext, setAppContext] = useState(
32063
+ appId ? { id: appId, name: appName, logo: appLogo } : null
32064
+ );
32065
+ useEffect(() => {
32066
+ setAppContext(appId ? { id: appId, name: appName, logo: appLogo } : null);
32067
+ }, [appId, appName, appLogo]);
32068
+ const clearAppContext = useCallback(() => setAppContext(null), []);
32003
32069
  const { isRecording, recognition, handleMicrophoneClick } = useSpeechRecognition({
32004
32070
  enabled: enableMicrophone,
32005
32071
  onTranscript: (transcript) => setInput((prev) => prev + (prev ? " " : "") + transcript),
@@ -32052,6 +32118,7 @@ var DocyAssistant = ({
32052
32118
  supportThinking: options3?.supportThinking,
32053
32119
  supportWorkCanvas: options3?.supportWorkCanvas,
32054
32120
  ...hostEnvironment ? { hostEnvironment } : {},
32121
+ ...appContext?.id ? { appId: appContext.id } : {},
32055
32122
  ...clientToolDefsRef.current.length ? { clientTools: clientToolDefsRef.current } : {},
32056
32123
  ...options3?.filePaths?.length ? { files: options3.filePaths } : {}
32057
32124
  }
@@ -32073,7 +32140,8 @@ var DocyAssistant = ({
32073
32140
  apiEndpoint,
32074
32141
  activeAgentId,
32075
32142
  deploymentId,
32076
- hostEnvironment
32143
+ hostEnvironment,
32144
+ appContext?.id
32077
32145
  ]);
32078
32146
  const {
32079
32147
  messages = [],
@@ -32591,6 +32659,8 @@ var DocyAssistant = ({
32591
32659
  deploymentId,
32592
32660
  tenantAiAgentId: activeAgentId,
32593
32661
  subagents,
32662
+ appContext,
32663
+ onClearAppContext: clearAppContext,
32594
32664
  initialModelId,
32595
32665
  initialFeatures,
32596
32666
  enableMicrophone,