@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.
package/dist/assistant/index.mjs
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|