@datum-cloud/datum-ui 1.5.0 → 1.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.
@@ -3,7 +3,7 @@ import { t as Icon } from "../icon-wrapper-DKfJlJd0.mjs";
3
3
  import { a as DropdownMenuRadioGroup, c as DropdownMenuTrigger, i as DropdownMenuLabel, o as DropdownMenuRadioItem, r as DropdownMenuContent, s as DropdownMenuSeparator, t as DropdownMenu } from "../dropdown-menu-b8zY5Cs6.mjs";
4
4
  import { t as Tooltip } from "../tooltip-BhatUaar.mjs";
5
5
  import { ArrowDown, ArrowRight, ArrowUp, Brain, Check, ChevronDown, Copy, Download, MessagesSquare, Mic, MicOff, PanelLeft, Plus, RotateCw, Square, Trash2 } from "lucide-react";
6
- import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react";
6
+ import { Fragment, createContext, useCallback, useContext, useMemo, useRef, useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { AnimatePresence, motion } from "motion/react";
9
9
  import { EditorContent } from "@tiptap/react";
@@ -102,29 +102,34 @@ function ModelSelector({ modelId, effortId, onModelChange, onEffortChange, disab
102
102
  })
103
103
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
104
104
  align: "end",
105
- className: "w-44",
105
+ collisionPadding: 16,
106
+ className: "flex w-56 max-h-[min(24rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden",
106
107
  children: [
107
108
  /* @__PURE__ */ jsx(DropdownMenuLabel, {
108
- className: "text-muted-foreground text-[10px] tracking-wide uppercase",
109
+ className: "text-muted-foreground shrink-0 text-[10px] tracking-wide uppercase",
109
110
  children: "Model"
110
111
  }),
111
- /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
112
- value: modelId,
113
- onValueChange: onModelChange,
114
- children: models.map((m) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
115
- value: m.id,
116
- className: "text-sm",
117
- children: m.label
118
- }, m.id))
112
+ /* @__PURE__ */ jsx("div", {
113
+ className: "min-h-0 flex-1 overflow-y-auto",
114
+ children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
115
+ value: modelId,
116
+ onValueChange: onModelChange,
117
+ children: models.map((m) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
118
+ value: m.id,
119
+ className: "text-sm",
120
+ children: m.label
121
+ }, m.id))
122
+ })
119
123
  }),
120
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
124
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "shrink-0" }),
121
125
  /* @__PURE__ */ jsx(DropdownMenuLabel, {
122
- className: "text-muted-foreground text-[10px] tracking-wide uppercase",
126
+ className: "text-muted-foreground shrink-0 text-[10px] tracking-wide uppercase",
123
127
  children: "Effort"
124
128
  }),
125
129
  /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
126
130
  value: effortId,
127
131
  onValueChange: (v) => onEffortChange(v),
132
+ className: "shrink-0",
128
133
  children: efforts.map((e) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
129
134
  value: e.id,
130
135
  className: "text-sm",
@@ -389,7 +394,7 @@ function messageText(msg) {
389
394
  return msg.parts.filter(isTextUIPart).map((p) => p.text).join("\n\n");
390
395
  }
391
396
  function AssistantMessage({ msg, isLastMessage, status }) {
392
- const { toolLabels, showReasoning, messageActions, renderLink } = useAssistantConfig();
397
+ const { toolLabels, showReasoning, messageActions, renderLink, renderToolOutput } = useAssistantConfig();
393
398
  const isStreaming = isLastMessage && status === "streaming";
394
399
  const hasText = msg.parts.some((p) => isTextUIPart(p) && p.text);
395
400
  const activeToolPart = msg.parts.find((p) => isToolUIPart(p) && (p.state === "input-streaming" || p.state === "input-available"));
@@ -432,6 +437,10 @@ function AssistantMessage({ msg, isLastMessage, status }) {
432
437
  },
433
438
  children: part.text
434
439
  }, i);
440
+ if (isToolUIPart(part) && part.state === "output-available" && renderToolOutput) {
441
+ const rendered = renderToolOutput(part, msg);
442
+ if (rendered) return /* @__PURE__ */ jsx(Fragment, { children: rendered }, i);
443
+ }
435
444
  return null;
436
445
  }),
437
446
  showInitialLoading && /* @__PURE__ */ jsx("div", {
@@ -824,7 +833,7 @@ function downloadChat(chat) {
824
833
  a.click();
825
834
  URL.revokeObjectURL(url);
826
835
  }
827
- function HistoryPanel({ chatList, currentChatId, onLoadChat, onDeleteChat }) {
836
+ function HistoryPanel({ chatList, currentChatId, onLoadChat, onDeleteChat, header }) {
828
837
  const [query, setQuery] = useState("");
829
838
  const filtered = useMemo(() => {
830
839
  const q = query.trim().toLowerCase();
@@ -833,6 +842,10 @@ function HistoryPanel({ chatList, currentChatId, onLoadChat, onDeleteChat }) {
833
842
  return /* @__PURE__ */ jsxs("div", {
834
843
  className: "bg-background flex h-full w-64 shrink-0 flex-col border-r",
835
844
  children: [
845
+ header && /* @__PURE__ */ jsx("div", {
846
+ className: "shrink-0 border-b px-3 py-2",
847
+ children: header
848
+ }),
836
849
  /* @__PURE__ */ jsx("div", {
837
850
  className: "flex h-12 items-center border-b px-2",
838
851
  children: /* @__PURE__ */ jsx("input", {
@@ -894,7 +907,7 @@ function HistoryPanel({ chatList, currentChatId, onLoadChat, onDeleteChat }) {
894
907
  }
895
908
  //#endregion
896
909
  //#region src/components/features/assistant/components/assistant-workspace.tsx
897
- function AssistantWorkspace({ config, userName, title, messages, status, error, isReady, chatList, currentChatId, editor, htmlByUserMsgIndex, bottomRef, containerRef, userScrolledUpRef, onSend, onStop, onRetry, onNewChat, onLoadChat, onDeleteChat, onSuggestion, modelId, effortId, onModelChange, onEffortChange, micSupported, micListening, micFrequencyData, onMicToggle, historyOpen, onToggleHistory }) {
910
+ function AssistantWorkspace({ config, userName, title, messages, status, error, isReady, chatList, currentChatId, sidebarHeader, editor, htmlByUserMsgIndex, bottomRef, containerRef, userScrolledUpRef, onSend, onStop, onRetry, onNewChat, onLoadChat, onDeleteChat, onSuggestion, modelId, effortId, onModelChange, onEffortChange, micSupported, micListening, micFrequencyData, onMicToggle, historyOpen, onToggleHistory }) {
898
911
  const hasMessages = messages.length > 0;
899
912
  const promptCard = /* @__PURE__ */ jsx(PromptCard, {
900
913
  editor,
@@ -937,6 +950,7 @@ function AssistantWorkspace({ config, userName, title, messages, status, error,
937
950
  children: /* @__PURE__ */ jsx(HistoryPanel, {
938
951
  chatList,
939
952
  currentChatId,
953
+ header: sidebarHeader,
940
954
  onLoadChat,
941
955
  onDeleteChat
942
956
  })
@@ -1,6 +1,6 @@
1
1
  import type { Editor } from '@tiptap/react';
2
2
  import type { UIMessage } from 'ai';
3
- import type { MouseEvent as ReactMouseEvent, RefObject } from 'react';
3
+ import type { MouseEvent as ReactMouseEvent, ReactNode, RefObject } from 'react';
4
4
  import type { AssistantConfig, ChatSummary, EffortId } from '../types';
5
5
  /**
6
6
  * Presentational, props-driven assistant layout: left rail + collapsible
@@ -21,6 +21,11 @@ export interface AssistantWorkspaceProps {
21
21
  isReady: boolean;
22
22
  chatList: ChatSummary[];
23
23
  currentChatId: string;
24
+ /**
25
+ * Optional block pinned above the history search input, naming the scope the
26
+ * listed chats belong to (cloud-portal shows the current project).
27
+ */
28
+ sidebarHeader?: ReactNode;
24
29
  editor: Editor | null;
25
30
  /** Sanitized HTML per user message index (for exact-render of the user's input). */
26
31
  htmlByUserMsgIndex: RefObject<string[]>;
@@ -45,4 +50,4 @@ export interface AssistantWorkspaceProps {
45
50
  historyOpen: boolean;
46
51
  onToggleHistory: () => void;
47
52
  }
48
- export declare function AssistantWorkspace({ config, userName, title, messages, status, error, isReady, chatList, currentChatId, editor, htmlByUserMsgIndex, bottomRef, containerRef, userScrolledUpRef, onSend, onStop, onRetry, onNewChat, onLoadChat, onDeleteChat, onSuggestion, modelId, effortId, onModelChange, onEffortChange, micSupported, micListening, micFrequencyData, onMicToggle, historyOpen, onToggleHistory, }: AssistantWorkspaceProps): import("react").JSX.Element;
53
+ export declare function AssistantWorkspace({ config, userName, title, messages, status, error, isReady, chatList, currentChatId, sidebarHeader, editor, htmlByUserMsgIndex, bottomRef, containerRef, userScrolledUpRef, onSend, onStop, onRetry, onNewChat, onLoadChat, onDeleteChat, onSuggestion, modelId, effortId, onModelChange, onEffortChange, micSupported, micListening, micFrequencyData, onMicToggle, historyOpen, onToggleHistory, }: AssistantWorkspaceProps): import("react").JSX.Element;
@@ -1,9 +1,16 @@
1
+ import type { ReactNode } from 'react';
1
2
  import type { ChatSummary } from '../../types';
2
3
  interface HistoryPanelProps {
3
4
  chatList: ChatSummary[];
4
5
  currentChatId: string;
5
6
  onLoadChat: (chat: ChatSummary) => void;
6
7
  onDeleteChat: (e: React.MouseEvent, chatId: string) => void;
8
+ /**
9
+ * Optional host-supplied block pinned above the search input, naming the scope
10
+ * the listed chats belong to — cloud-portal shows the current project. Hosts
11
+ * whose history isn't scoped to anything (staff-portal) omit it.
12
+ */
13
+ header?: ReactNode;
7
14
  }
8
- export declare function HistoryPanel({ chatList, currentChatId, onLoadChat, onDeleteChat, }: HistoryPanelProps): import("react").JSX.Element;
15
+ export declare function HistoryPanel({ chatList, currentChatId, onLoadChat, onDeleteChat, header, }: HistoryPanelProps): import("react").JSX.Element;
9
16
  export {};
@@ -1,4 +1,4 @@
1
- import type { UIMessage } from 'ai';
1
+ import type { DynamicToolUIPart, ToolUIPart, UIMessage } from 'ai';
2
2
  import type { ReactNode } from 'react';
3
3
  export type EffortId = 'low' | 'medium' | 'high';
4
4
  export interface ModelOption {
@@ -46,6 +46,13 @@ export interface AssistantConfig {
46
46
  renderLink: (props: LinkRenderProps) => ReactNode;
47
47
  /** Override the per-message action toolbar (defaults to copy + download). */
48
48
  messageActions?: (msg: UIMessage) => ReactNode;
49
+ /**
50
+ * Renders a completed tool call inline, in message order. Return a falsy value
51
+ * to leave that tool invisible — the default for every tool, since most only
52
+ * feed the model. Hosts use this to surface a result as UI (cloud-portal turns
53
+ * an `openSupportTicket` result into a button).
54
+ */
55
+ renderToolOutput?: (part: ToolUIPart | DynamicToolUIPart, msg: UIMessage) => ReactNode;
49
56
  }
50
57
  /**
51
58
  * Minimal shape the history list needs. Host apps pass their own richer chat
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datum-cloud/datum-ui",
3
3
  "type": "module",
4
- "version": "1.5.0",
4
+ "version": "1.6.1",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "url": "https://github.com/datum-cloud/datum-ui"