lemma-sdk 0.2.13 → 0.2.14
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 +0 -69
- package/dist/react/components/AssistantChrome.d.ts +9 -19
- package/dist/react/components/AssistantChrome.js +23 -64
- package/dist/react/components/AssistantExperience.d.ts +2 -4
- package/dist/react/components/AssistantExperience.js +28 -39
- package/dist/react/components/assistant-types.d.ts +1 -3
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -218,14 +218,6 @@ function AssistantSurface() {
|
|
|
218
218
|
}
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
The assistant UI now ships with built-in fallback theme tokens and a sensible default shell height, so it does not need app-specific CSS variables just to look presentable. If your app already defines the same CSS custom properties (`--bg-surface`, `--brand-primary`, etc.), your values will override the defaults.
|
|
222
|
-
|
|
223
|
-
Practical expectations:
|
|
224
|
-
|
|
225
|
-
- The components are React components styled with utility class names, so your app should already compile those class names (for example with Tailwind or the same utility CSS pipeline used by the app shell).
|
|
226
|
-
- `AssistantEmbedded` and `AssistantExperienceView` render with a default minimum height of about 640px. You can still place them in a taller container when you want a full-page assistant.
|
|
227
|
-
- Host apps are still responsible for auth, `LemmaClient` setup, and any product-specific renderers for files, widgets, or navigation.
|
|
228
|
-
|
|
229
221
|
The intended split is:
|
|
230
222
|
|
|
231
223
|
- SDK: `useAssistantController`, message/tool normalization, plan parsing, tool rollups, and assistant UI primitives.
|
|
@@ -265,67 +257,6 @@ function SupportAssistant() {
|
|
|
265
257
|
}
|
|
266
258
|
```
|
|
267
259
|
|
|
268
|
-
If you want the default embedded assistant to fill a page section cleanly, this is a good starting point:
|
|
269
|
-
|
|
270
|
-
```tsx
|
|
271
|
-
function AssistantPanel() {
|
|
272
|
-
return (
|
|
273
|
-
<section style={{ minHeight: 720 }}>
|
|
274
|
-
<AssistantEmbedded
|
|
275
|
-
client={client}
|
|
276
|
-
assistantId="support_assistant"
|
|
277
|
-
podId="pod_123"
|
|
278
|
-
title="Support Assistant"
|
|
279
|
-
subtitle="Answer questions, inspect files, and help with pod changes."
|
|
280
|
-
placeholder="Ask Support Assistant"
|
|
281
|
-
showConversationList
|
|
282
|
-
/>
|
|
283
|
-
</section>
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### Styling the assistant chrome directly
|
|
289
|
-
|
|
290
|
-
If you are composing your own shell from the exported primitives, you can reuse the same built-in theme values:
|
|
291
|
-
|
|
292
|
-
```tsx
|
|
293
|
-
import {
|
|
294
|
-
AssistantComposer,
|
|
295
|
-
AssistantHeader,
|
|
296
|
-
AssistantMessageViewport,
|
|
297
|
-
assistantThemeStyles,
|
|
298
|
-
} from "lemma-sdk/react";
|
|
299
|
-
|
|
300
|
-
function CustomAssistantChrome() {
|
|
301
|
-
return (
|
|
302
|
-
<div style={{ ...assistantThemeStyles, minHeight: 640 }}>
|
|
303
|
-
<AssistantHeader
|
|
304
|
-
title="Workspace Assistant"
|
|
305
|
-
subtitle="Custom shell using SDK primitives"
|
|
306
|
-
/>
|
|
307
|
-
<AssistantMessageViewport>
|
|
308
|
-
{/* messages */}
|
|
309
|
-
</AssistantMessageViewport>
|
|
310
|
-
<AssistantComposer>
|
|
311
|
-
{/* composer */}
|
|
312
|
-
</AssistantComposer>
|
|
313
|
-
</div>
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
You can also merge your own overrides:
|
|
319
|
-
|
|
320
|
-
```tsx
|
|
321
|
-
import { withAssistantThemeStyles } from "lemma-sdk/react";
|
|
322
|
-
|
|
323
|
-
const style = withAssistantThemeStyles({
|
|
324
|
-
"--brand-primary": "#0f766e",
|
|
325
|
-
"--brand-secondary": "#34d399",
|
|
326
|
-
});
|
|
327
|
-
```
|
|
328
|
-
|
|
329
260
|
### Assistant names (resource key)
|
|
330
261
|
|
|
331
262
|
Assistant CRUD is name-based:
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { type ComponentPropsWithoutRef, type
|
|
1
|
+
import { type ComponentPropsWithoutRef, type ReactNode } from "react";
|
|
2
2
|
import type { AssistantConversationListItem, AssistantConversationRenderArgs } from "./assistant-types.js";
|
|
3
|
-
export declare const assistantThemeStyles: CSSProperties;
|
|
4
|
-
export declare function withAssistantThemeStyles(style?: CSSProperties): CSSProperties;
|
|
5
3
|
export interface AssistantHeaderProps {
|
|
6
4
|
title: ReactNode;
|
|
7
5
|
subtitle?: ReactNode;
|
|
8
6
|
badge?: ReactNode;
|
|
9
7
|
controls?: ReactNode;
|
|
10
8
|
className?: string;
|
|
11
|
-
style?: CSSProperties;
|
|
12
9
|
}
|
|
13
10
|
export interface AssistantMessageViewportProps extends ComponentPropsWithoutRef<"div"> {
|
|
14
11
|
innerClassName?: string;
|
|
@@ -20,10 +17,9 @@ export interface AssistantShellLayoutProps {
|
|
|
20
17
|
sidebarVisible?: boolean;
|
|
21
18
|
main: ReactNode;
|
|
22
19
|
className?: string;
|
|
23
|
-
style?: CSSProperties;
|
|
24
20
|
}
|
|
25
|
-
export declare function AssistantShellLayout({ sidebar, sidebarVisible, main, className,
|
|
26
|
-
export declare function AssistantHeader({ title, subtitle, badge, controls, className,
|
|
21
|
+
export declare function AssistantShellLayout({ sidebar, sidebarVisible, main, className, }: AssistantShellLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function AssistantHeader({ title, subtitle, badge, controls, className, }: AssistantHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
27
23
|
export interface AssistantConversationListProps {
|
|
28
24
|
conversations: AssistantConversationListItem[];
|
|
29
25
|
activeConversationId: string | null;
|
|
@@ -33,9 +29,8 @@ export interface AssistantConversationListProps {
|
|
|
33
29
|
title?: ReactNode;
|
|
34
30
|
newLabel?: ReactNode;
|
|
35
31
|
className?: string;
|
|
36
|
-
style?: CSSProperties;
|
|
37
32
|
}
|
|
38
|
-
export declare function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title, newLabel, className,
|
|
33
|
+
export declare function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title, newLabel, className, }: AssistantConversationListProps): import("react/jsx-runtime").JSX.Element;
|
|
39
34
|
export interface AssistantModelPickerProps<TValue extends string = string> {
|
|
40
35
|
value: TValue | null;
|
|
41
36
|
options: TValue[];
|
|
@@ -44,9 +39,8 @@ export interface AssistantModelPickerProps<TValue extends string = string> {
|
|
|
44
39
|
getOptionLabel?: (value: TValue) => ReactNode;
|
|
45
40
|
onChange: (value: TValue | null) => void;
|
|
46
41
|
className?: string;
|
|
47
|
-
style?: CSSProperties;
|
|
48
42
|
}
|
|
49
|
-
export declare function AssistantModelPicker<TValue extends string = string>({ value, options, disabled, autoLabel, getOptionLabel, onChange, className,
|
|
43
|
+
export declare function AssistantModelPicker<TValue extends string = string>({ value, options, disabled, autoLabel, getOptionLabel, onChange, className, }: AssistantModelPickerProps<TValue>): import("react/jsx-runtime").JSX.Element;
|
|
50
44
|
export interface AssistantAskOverlayProps {
|
|
51
45
|
questionNumber: number;
|
|
52
46
|
totalQuestions: number;
|
|
@@ -59,14 +53,12 @@ export interface AssistantAskOverlayProps {
|
|
|
59
53
|
onContinue?: () => void;
|
|
60
54
|
onSkip?: () => void;
|
|
61
55
|
mode?: "single_select" | "multi_select" | "rank_priorities";
|
|
62
|
-
style?: CSSProperties;
|
|
63
56
|
}
|
|
64
|
-
export declare function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode,
|
|
57
|
+
export declare function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode, }: AssistantAskOverlayProps): import("react/jsx-runtime").JSX.Element;
|
|
65
58
|
export interface AssistantPendingFileChipProps {
|
|
66
59
|
label: ReactNode;
|
|
67
60
|
onRemove?: () => void;
|
|
68
61
|
className?: string;
|
|
69
|
-
style?: CSSProperties;
|
|
70
62
|
}
|
|
71
63
|
export interface AssistantComposerProps {
|
|
72
64
|
floating?: ReactNode;
|
|
@@ -74,14 +66,12 @@ export interface AssistantComposerProps {
|
|
|
74
66
|
pendingFiles?: ReactNode;
|
|
75
67
|
children: ReactNode;
|
|
76
68
|
className?: string;
|
|
77
|
-
style?: CSSProperties;
|
|
78
69
|
}
|
|
79
|
-
export declare function AssistantComposer({ floating, status, pendingFiles, children, className,
|
|
80
|
-
export declare function AssistantPendingFileChip({ label, onRemove, className,
|
|
70
|
+
export declare function AssistantComposer({ floating, status, pendingFiles, children, className, }: AssistantComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
71
|
+
export declare function AssistantPendingFileChip({ label, onRemove, className, }: AssistantPendingFileChipProps): import("react/jsx-runtime").JSX.Element;
|
|
81
72
|
export interface AssistantStatusPillProps {
|
|
82
73
|
label: ReactNode;
|
|
83
74
|
subtle?: boolean;
|
|
84
75
|
className?: string;
|
|
85
|
-
style?: CSSProperties;
|
|
86
76
|
}
|
|
87
|
-
export declare function AssistantStatusPill({ label, subtle, className,
|
|
77
|
+
export declare function AssistantStatusPill({ label, subtle, className, }: AssistantStatusPillProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,72 +3,31 @@ import { forwardRef } from "react";
|
|
|
3
3
|
function cx(...values) {
|
|
4
4
|
return values.filter(Boolean).join(" ");
|
|
5
5
|
}
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
if (Number.isNaN(parsed.valueOf())) {
|
|
9
|
-
return "";
|
|
10
|
-
}
|
|
11
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
12
|
-
month: "short",
|
|
13
|
-
day: "numeric",
|
|
14
|
-
timeZone: "UTC",
|
|
15
|
-
}).format(parsed);
|
|
16
|
-
}
|
|
17
|
-
export const assistantThemeStyles = {
|
|
18
|
-
"--bg-canvas": "#f4ede6",
|
|
19
|
-
"--bg-surface": "#fffaf4",
|
|
20
|
-
"--bg-subtle": "#efe4d8",
|
|
21
|
-
"--border-default": "#d8c4b2",
|
|
22
|
-
"--border-subtle": "#eadacc",
|
|
23
|
-
"--text-primary": "#23160f",
|
|
24
|
-
"--text-secondary": "#5f4838",
|
|
25
|
-
"--text-tertiary": "#8d715b",
|
|
26
|
-
"--text-on-brand": "#fff7f0",
|
|
27
|
-
"--text-inverse": "#fffaf4",
|
|
28
|
-
"--brand-primary": "#c45a2f",
|
|
29
|
-
"--brand-secondary": "#f2a65e",
|
|
30
|
-
"--brand-accent": "#df7a38",
|
|
31
|
-
"--brand-glow": "#f4d6b5",
|
|
32
|
-
"--state-success": "#1c8c63",
|
|
33
|
-
"--state-info": "#2e78b7",
|
|
34
|
-
"--state-error": "#be4637",
|
|
35
|
-
"--state-warning": "#a86811",
|
|
36
|
-
"--shadow-xs": "0 6px 18px -12px rgba(46, 27, 15, 0.35)",
|
|
37
|
-
"--shadow-sm": "0 12px 28px -20px rgba(46, 27, 15, 0.28)",
|
|
38
|
-
"--shadow-md": "0 20px 44px -28px rgba(46, 27, 15, 0.34)",
|
|
39
|
-
"--shadow-lg": "0 28px 64px -34px rgba(46, 27, 15, 0.4)",
|
|
40
|
-
};
|
|
41
|
-
export function withAssistantThemeStyles(style) {
|
|
42
|
-
return {
|
|
43
|
-
...assistantThemeStyles,
|
|
44
|
-
...style,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export const AssistantMessageViewport = forwardRef(function AssistantMessageViewport({ className, innerClassName, children, style, ...props }, ref) {
|
|
48
|
-
return (_jsx("div", { ref: ref, className: cx("min-h-0 flex-1 overflow-y-auto bg-[var(--bg-surface)] px-4 py-4", className), style: withAssistantThemeStyles(style), ...props, children: _jsx("div", { className: cx("mx-auto flex w-full max-w-5xl flex-col gap-3", innerClassName), children: children }) }));
|
|
6
|
+
export const AssistantMessageViewport = forwardRef(function AssistantMessageViewport({ className, innerClassName, children, ...props }, ref) {
|
|
7
|
+
return (_jsx("div", { ref: ref, className: cx("min-h-0 flex-1 overflow-y-auto bg-[var(--bg-surface)] px-4 py-4", className), ...props, children: _jsx("div", { className: cx("mx-auto flex w-full max-w-5xl flex-col gap-3", innerClassName), children: children }) }));
|
|
49
8
|
});
|
|
50
|
-
export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, className,
|
|
51
|
-
return (_jsxs("div", { className: cx("mx-auto flex h-full w-full min-h-
|
|
9
|
+
export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, className, }) {
|
|
10
|
+
return (_jsxs("div", { className: cx("mx-auto flex h-full w-full min-h-0 flex-col gap-3 font-sans antialiased", !!sidebar && sidebarVisible && "lg:grid lg:grid-cols-[280px_minmax(0,1fr)] lg:gap-3", className), children: [sidebar && sidebarVisible ? (_jsx("div", { className: "hidden h-full min-h-0 lg:block", children: sidebar })) : null, main] }));
|
|
52
11
|
}
|
|
53
|
-
export function AssistantHeader({ title, subtitle, badge, controls, className,
|
|
54
|
-
return (_jsxs("div", { className: cx("flex items-center justify-between border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3
|
|
12
|
+
export function AssistantHeader({ title, subtitle, badge, controls, className, }) {
|
|
13
|
+
return (_jsxs("div", { className: cx("flex items-center justify-between border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", className), children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [badge ? (_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] shadow-[var(--shadow-xs)]", children: badge })) : null, _jsxs("div", { children: [_jsx("h3", { className: "text-[13px] font-semibold leading-tight text-[var(--text-primary)]", children: title }), subtitle ? (_jsx("p", { className: "text-[11px] text-[var(--text-tertiary)]", children: subtitle })) : null] })] }), controls ? (_jsx("div", { className: "flex items-center gap-1", children: controls })) : null] }));
|
|
55
14
|
}
|
|
56
|
-
export function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title = "Conversations", newLabel = "New", className,
|
|
57
|
-
return (_jsxs("aside", { className: cx("flex h-full min-h-
|
|
15
|
+
export function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title = "Conversations", newLabel = "New", className, }) {
|
|
16
|
+
return (_jsxs("aside", { className: cx("flex h-full min-h-0 flex-col overflow-hidden rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] shadow-[var(--shadow-lg)]", className), children: [_jsx("div", { className: "border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[13px] font-semibold text-[var(--text-primary)]", children: title }), _jsxs("div", { className: "mt-1 text-[11px] text-[var(--text-tertiary)]", children: [conversations.length, " total"] })] }), onNewConversation ? (_jsx("button", { type: "button", onClick: onNewConversation, className: "rounded-full border border-[var(--border-default)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]", children: newLabel })) : null] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-3 space-y-2", children: conversations.map((conversation) => {
|
|
58
17
|
const isActive = conversation.id === activeConversationId;
|
|
59
|
-
return (_jsxs("button", { type: "button", onClick: () => onSelectConversation(conversation.id), className: cx("w-full rounded-
|
|
60
|
-
? "border-[color:color-mix(in_srgb,_var(--brand-primary)_44%,_var(--border-default))] bg-[
|
|
61
|
-
: "border-[var(--border-default)] bg-[
|
|
18
|
+
return (_jsxs("button", { type: "button", onClick: () => onSelectConversation(conversation.id), className: cx("w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
|
|
19
|
+
? "border-[color:color-mix(in_srgb,_var(--brand-primary)_44%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_42%,_var(--bg-surface))]"
|
|
20
|
+
: "border-[var(--border-default)] bg-[var(--bg-surface)] hover:bg-[var(--bg-subtle)]"), children: [_jsx("div", { className: "truncate text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel
|
|
62
21
|
? renderConversationLabel({ conversation, isActive })
|
|
63
|
-
: (conversation.title || "Untitled conversation") }),
|
|
22
|
+
: (conversation.title || "Untitled conversation") }), _jsx("div", { className: "mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
|
|
64
23
|
}) })] }));
|
|
65
24
|
}
|
|
66
|
-
export function AssistantModelPicker({ value, options, disabled, autoLabel = "Auto", getOptionLabel, onChange, className,
|
|
25
|
+
export function AssistantModelPicker({ value, options, disabled, autoLabel = "Auto", getOptionLabel, onChange, className, }) {
|
|
67
26
|
const autoValue = "__AUTO__";
|
|
68
|
-
return (_jsxs("select", { value: value ?? autoValue, onChange: (event) => onChange(event.target.value === autoValue ? null : event.target.value), disabled: disabled, className: cx("h-
|
|
27
|
+
return (_jsxs("select", { value: value ?? autoValue, onChange: (event) => onChange(event.target.value === autoValue ? null : event.target.value), disabled: disabled, className: cx("h-8 rounded-full border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] px-3 text-[11px] text-[var(--text-secondary)]", className), "aria-label": "Conversation model", title: "Conversation model", children: [_jsx("option", { value: autoValue, children: autoLabel }), options.map((option) => (_jsx("option", { value: option, children: getOptionLabel ? getOptionLabel(option) : option }, option)))] }));
|
|
69
28
|
}
|
|
70
|
-
export function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode = "single_select",
|
|
71
|
-
return (_jsxs("div", { className: "space-y-2
|
|
29
|
+
export function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode = "single_select", }) {
|
|
30
|
+
return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "text-[11px] uppercase tracking-[0.12em] text-[var(--text-tertiary)]", children: ["Question ", questionNumber, " of ", totalQuestions] }), _jsx("p", { className: "mt-1 text-[14px] font-medium leading-6 text-[var(--text-primary)]", children: question })] }), onSkip ? (_jsx("button", { type: "button", onClick: onSkip, className: "rounded-md px-2 py-1 text-[12px] text-[var(--text-tertiary)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text-primary)]", children: "Skip" })) : null] }), _jsx("div", { className: "max-h-[260px] space-y-1.5 overflow-y-auto pr-1", children: options.map((option, optionIndex) => {
|
|
72
31
|
const isSelected = selectedOptions.includes(option);
|
|
73
32
|
const rankLabel = mode === "rank_priorities" && isSelected
|
|
74
33
|
? selectedOptions.indexOf(option) + 1
|
|
@@ -82,14 +41,14 @@ export function AssistantAskOverlay({ questionNumber, totalQuestions, question,
|
|
|
82
41
|
? "bg-[var(--brand-primary)] text-[var(--text-on-brand)] hover:bg-[color:color-mix(in_srgb,_var(--brand-primary)_88%,_var(--text-primary))]"
|
|
83
42
|
: "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), children: continueLabel }) })) : null] }));
|
|
84
43
|
}
|
|
85
|
-
export function AssistantComposer({ floating, status, pendingFiles, children, className,
|
|
86
|
-
return (_jsxs("div", { className: cx("relative rounded-
|
|
44
|
+
export function AssistantComposer({ floating, status, pendingFiles, children, className, }) {
|
|
45
|
+
return (_jsxs("div", { className: cx("relative rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] p-2 shadow-[var(--shadow-md)]", className), children: [floating ? (_jsx("div", { className: "absolute bottom-[calc(100%+8px)] left-0 right-0 z-20", children: floating })) : null, _jsx("div", { className: "min-h-[34px] px-2 pb-1", children: _jsx("div", { className: "flex min-h-[26px] items-center transition-opacity duration-200", children: status || _jsx("span", { "aria-hidden": "true", className: "inline-block h-[30px]" }) }) }), pendingFiles ? (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-1 pb-1.5", children: pendingFiles })) : null, children] }));
|
|
87
46
|
}
|
|
88
|
-
export function AssistantPendingFileChip({ label, onRemove, className,
|
|
89
|
-
return (_jsxs("span", { className: cx("inline-flex max-w-full items-center gap-1.5 rounded-full
|
|
47
|
+
export function AssistantPendingFileChip({ label, onRemove, className, }) {
|
|
48
|
+
return (_jsxs("span", { className: cx("inline-flex max-w-full items-center gap-1.5 rounded-full bg-[var(--bg-subtle)] px-2 py-1 text-[11px] text-[var(--text-secondary)]", className), children: [_jsx("span", { className: "truncate max-w-[180px]", children: label }), onRemove ? (_jsx("button", { type: "button", onClick: onRemove, className: "inline-flex h-4 w-4 items-center justify-center rounded-full hover:bg-[var(--bg-canvas)]", title: "Remove file", children: "\u00D7" })) : null] }));
|
|
90
49
|
}
|
|
91
|
-
export function AssistantStatusPill({ label, subtle = false, className,
|
|
92
|
-
return (_jsxs("div", { className: cx("inline-flex min-h-[
|
|
50
|
+
export function AssistantStatusPill({ label, subtle = false, className, }) {
|
|
51
|
+
return (_jsxs("div", { className: cx("inline-flex min-h-[30px] max-w-full items-center gap-2 rounded-full px-3 py-1.5 text-[12px] transition-all duration-200", subtle
|
|
93
52
|
? "border border-[color:color-mix(in_srgb,_var(--border-default)_72%,_transparent)] bg-[color:color-mix(in_srgb,_var(--bg-surface)_90%,_transparent)] text-[var(--text-tertiary)]"
|
|
94
|
-
: "border border-[color:color-mix(in_srgb,_var(--brand-primary)_24%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_28%,_var(--bg-surface))] text-[var(--text-secondary)]", className),
|
|
53
|
+
: "border border-[color:color-mix(in_srgb,_var(--brand-primary)_24%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_28%,_var(--bg-surface))] text-[var(--text-secondary)]", className), children: [_jsxs("span", { className: "relative inline-flex h-2.5 w-2.5 shrink-0", children: [_jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--brand-primary)]/45" }), _jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-[var(--brand-primary)]" })] }), _jsx("span", { className: "truncate", children: label })] }));
|
|
95
54
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
2
|
import type { AssistantRenderableMessage, AssistantToolInvocation } from "../useAssistantController.js";
|
|
3
3
|
import type { AssistantControllerView, AssistantConversationRenderArgs, AssistantMessageRenderArgs, AssistantPendingFileRenderArgs, AssistantPresentedFileRenderArgs, AssistantToolRenderArgs } from "./assistant-types.js";
|
|
4
4
|
type PlanStatus = "pending" | "in_progress" | "completed";
|
|
@@ -39,8 +39,6 @@ export interface AssistantExperienceViewProps {
|
|
|
39
39
|
subtitle?: ReactNode;
|
|
40
40
|
placeholder?: string;
|
|
41
41
|
emptyState?: ReactNode;
|
|
42
|
-
className?: string;
|
|
43
|
-
style?: CSSProperties;
|
|
44
42
|
draft?: string;
|
|
45
43
|
onDraftChange?: (value: string) => void;
|
|
46
44
|
showConversationList?: boolean;
|
|
@@ -77,5 +75,5 @@ export declare function MessageGroup({ message, conversationId, onNavigateResour
|
|
|
77
75
|
renderPresentedFile?: (args: AssistantPresentedFileRenderArgs) => ReactNode;
|
|
78
76
|
renderToolInvocation?: (args: AssistantToolRenderArgs) => ReactNode;
|
|
79
77
|
}): import("react/jsx-runtime").JSX.Element;
|
|
80
|
-
export declare function AssistantExperienceView({ controller, title, subtitle, placeholder, emptyState,
|
|
78
|
+
export declare function AssistantExperienceView({ controller, title, subtitle, placeholder, emptyState, draft: controlledDraft, onDraftChange, showConversationList, onNavigateResource, renderConversationLabel, renderMessageContent, renderPresentedFile, renderPendingFile, renderToolInvocation, }: AssistantExperienceViewProps): import("react/jsx-runtime").JSX.Element;
|
|
81
79
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
3
|
import { AvailableModels } from "../../types.js";
|
|
4
|
-
import {
|
|
4
|
+
import { AssistantAskOverlay, AssistantMessageViewport, } from "./AssistantChrome.js";
|
|
5
5
|
function cx(...values) {
|
|
6
6
|
return values.filter(Boolean).join(" ");
|
|
7
7
|
}
|
|
@@ -507,7 +507,7 @@ function defaultPresentedFile({ filepath }) {
|
|
|
507
507
|
return (_jsxs("div", { className: "rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_78%,_transparent)] bg-[linear-gradient(180deg,color-mix(in_srgb,var(--bg-surface)_96%,transparent),color-mix(in_srgb,var(--bg-canvas)_76%,transparent))] px-3 py-2.5", children: [_jsx("div", { className: "text-[14px] font-medium text-[var(--text-primary)]", children: fileNameFromPath(filepath) }), _jsx("div", { className: "mt-1 text-[12px] text-[var(--text-tertiary)]", children: filepath })] }));
|
|
508
508
|
}
|
|
509
509
|
function defaultPendingFile({ file, remove }) {
|
|
510
|
-
return (_jsx(
|
|
510
|
+
return (_jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-full bg-[var(--bg-subtle)] px-2 py-1 text-[11px] text-[var(--text-secondary)]", children: [_jsx("span", { className: "truncate max-w-[180px]", children: file.name }), _jsx("button", { type: "button", onClick: remove, className: "inline-flex h-4 w-4 items-center justify-center rounded-full hover:bg-[var(--bg-canvas)]", title: "Remove file", children: "\u00D7" })] }));
|
|
511
511
|
}
|
|
512
512
|
export function PlanSummaryStrip({ plan, onHide }) {
|
|
513
513
|
const [showAll, setShowAll] = useState(false);
|
|
@@ -527,28 +527,12 @@ export function ThinkingIndicator() {
|
|
|
527
527
|
}
|
|
528
528
|
export function EmptyState({ onSendMessage }) {
|
|
529
529
|
const suggestions = [
|
|
530
|
-
{
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
},
|
|
535
|
-
{
|
|
536
|
-
label: "Build a CRM table",
|
|
537
|
-
text: "Create a table for leads with useful columns, sample views, and suggested automation hooks.",
|
|
538
|
-
accent: "Data",
|
|
539
|
-
},
|
|
540
|
-
{
|
|
541
|
-
label: "Draft a support workflow",
|
|
542
|
-
text: "Design a support triage workflow with an assistant, a queue, and follow-up tasks.",
|
|
543
|
-
accent: "Ops",
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
label: "Create a dashboard page",
|
|
547
|
-
text: "Build a React desk page for an executive dashboard with KPIs, trends, and recent activity.",
|
|
548
|
-
accent: "UI",
|
|
549
|
-
},
|
|
530
|
+
{ text: "Create an agent that summarizes documents", icon: "🤖" },
|
|
531
|
+
{ text: "Add a table for tracking leads", icon: "📊" },
|
|
532
|
+
{ text: "Create a full React desk page for an executive dashboard", icon: "🧩" },
|
|
533
|
+
{ text: "Create a flow to process emails", icon: "⚡" },
|
|
550
534
|
];
|
|
551
|
-
return (_jsxs("div", { className: "
|
|
535
|
+
return (_jsxs("div", { className: "text-center py-5 px-2", children: [_jsxs("div", { className: "flex flex-col items-center justify-center mb-6", children: [_jsx("div", { className: "mb-3 flex h-10 w-10 items-center justify-center rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] shadow-[var(--shadow-xs)]", children: _jsx("span", { className: "text-[var(--text-on-brand)] text-lg", children: "\u2728" }) }), _jsx("h4", { className: "font-semibold text-[var(--text-primary)] text-[15px]", children: "What can I help you build?" }), _jsx("p", { className: "text-[13px] text-[var(--text-tertiary)] mt-1.5 max-w-sm leading-relaxed", children: "I can create agents, set up data stores, build pages, and automate workflows for your pod." })] }), _jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2.5 max-w-[500px] mx-auto", children: suggestions.map((suggestion, index) => (_jsxs("button", { onClick: () => onSendMessage(suggestion.text), className: "text-left px-3 py-2.5 rounded-lg border border-[var(--border-default)] bg-[var(--bg-surface)] text-xs text-[var(--text-secondary)] hover:border-[color:color-mix(in_srgb,_var(--brand-accent)_52%,_var(--border-subtle))] hover:bg-[color:color-mix(in_srgb,_var(--brand-glow)_72%,_var(--bg-surface))] hover:text-[var(--text-primary)] transition-all duration-200 flex items-center gap-2.5 group", children: [_jsx("span", { className: "text-base opacity-70 group-hover:opacity-100 transition-opacity", children: suggestion.icon }), _jsx("span", { className: "flex-1 leading-snug", children: suggestion.text }), _jsx("span", { className: "text-[var(--text-tertiary)] group-hover:text-[var(--state-warning)] group-hover:translate-x-0.5 transition-all opacity-0 group-hover:opacity-100", children: "\u203A" })] }, `${suggestion.text}-${index}`))) })] }));
|
|
552
536
|
}
|
|
553
537
|
function ReasoningPartCard({ text, isStreaming, durationMs, }) {
|
|
554
538
|
return (_jsxs("details", { className: "group", open: isStreaming, children: [_jsxs("summary", { className: "list-none cursor-pointer inline-flex items-center gap-1.5 text-[12px] leading-5 text-[var(--text-tertiary)]", children: [_jsx("span", { className: "transition-transform group-open:rotate-90", children: "\u203A" }), _jsx("span", { className: cx("font-semibold", isStreaming && "text-transparent bg-clip-text bg-[linear-gradient(110deg,var(--text-secondary),35%,var(--brand-accent),50%,var(--text-secondary),65%)] bg-[length:250%_100%] animate-pulse"), children: isStreaming ? "Thinking" : `Thought${durationMs ? ` · ${Math.max(1, Math.round(durationMs / 1000))}s` : ""}` })] }), _jsx("div", { className: "mt-1 pl-4 border-l border-[var(--border-default)]", children: _jsx("pre", { className: "text-[11px] leading-5 text-[var(--text-tertiary)] whitespace-pre-wrap font-mono", children: text }) })] }));
|
|
@@ -771,7 +755,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
|
|
|
771
755
|
return null;
|
|
772
756
|
}), presentableFilepaths.length > 0 ? (_jsx(PresentFilesCard, { filepaths: presentableFilepaths, conversationId: conversationId, renderPresentedFile: renderPresentedFile })) : null] })] }));
|
|
773
757
|
}
|
|
774
|
-
export function AssistantExperienceView({ controller, title = "Lemma Assistant", subtitle = "Ask across your workspace and organization.", placeholder = "Message Lemma Assistant", emptyState,
|
|
758
|
+
export function AssistantExperienceView({ controller, title = "Lemma Assistant", subtitle = "Ask across your workspace and organization.", placeholder = "Message Lemma Assistant", emptyState, draft: controlledDraft, onDraftChange, showConversationList = false, onNavigateResource, renderConversationLabel = defaultConversationLabel, renderMessageContent = defaultMessageContent, renderPresentedFile, renderPendingFile = defaultPendingFile, renderToolInvocation, }) {
|
|
775
759
|
const [draft, setDraft] = useControllableDraft(controlledDraft, onDraftChange);
|
|
776
760
|
const [isPlanHidden, setIsPlanHidden] = useState(false);
|
|
777
761
|
const [dismissedAskToolCallIds, setDismissedAskToolCallIds] = useState([]);
|
|
@@ -1009,24 +993,29 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
|
|
|
1009
993
|
? effectiveAskOverlayState.answers[effectiveAskOverlayState.currentQuestionIndex] || []
|
|
1010
994
|
: [];
|
|
1011
995
|
const canContinueAsk = activeAskAnswers.length > 0;
|
|
1012
|
-
return (_jsxs("div", { className: cx("
|
|
996
|
+
return (_jsxs("div", { className: cx("flex h-full min-h-0 flex-col gap-3 font-sans antialiased", showConversationList && "lg:grid lg:grid-cols-[280px_minmax(0,1fr)] lg:gap-3"), children: [showConversationList ? (_jsxs("aside", { className: "hidden min-h-0 overflow-hidden rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] shadow-[var(--shadow-lg)] lg:flex lg:flex-col", children: [_jsx("div", { className: "border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[13px] font-semibold text-[var(--text-primary)]", children: "Conversations" }), _jsxs("div", { className: "mt-1 text-[11px] text-[var(--text-tertiary)]", children: [controller.conversations.length, " total"] })] }), _jsx("button", { type: "button", onClick: controller.clearMessages, className: "rounded-full border border-[var(--border-default)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]", children: "New" })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-3 space-y-2", children: controller.conversations.map((conversation) => {
|
|
997
|
+
const isActive = conversation.id === controller.activeConversationId;
|
|
998
|
+
return (_jsxs("button", { type: "button", onClick: () => controller.selectConversation(conversation.id), className: cx("w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
|
|
999
|
+
? "border-[color:color-mix(in_srgb,_var(--brand-primary)_44%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_42%,_var(--bg-surface))]"
|
|
1000
|
+
: "border-[var(--border-default)] bg-[var(--bg-surface)] hover:bg-[var(--bg-subtle)]"), children: [_jsx("div", { className: "text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel({ conversation, isActive }) }), _jsx("div", { className: "mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
|
|
1001
|
+
}) })] })) : null, _jsxs("div", { className: "flex h-full min-h-0 flex-col gap-3", children: [_jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] shadow-[var(--shadow-lg)]", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [_jsx("div", { className: "h-7 w-7 rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] flex items-center justify-center shadow-[var(--shadow-xs)]", children: _jsx("span", { className: "text-[var(--text-on-brand)] text-xs", children: "\u2728" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-[var(--text-primary)] text-[13px] leading-tight", children: title }), _jsx("p", { className: "text-[11px] text-[var(--text-tertiary)]", children: subtitle })] })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs("select", { value: controller.conversationModel || "", onChange: (event) => { void handleModelChange(event.target.value || null); }, disabled: isConversationBusy || isUpdatingModel, className: "h-8 rounded-full border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] px-3 text-[11px] text-[var(--text-secondary)]", children: [_jsx("option", { value: "", children: "Auto" }), availableModels.map((availableModel) => (_jsx("option", { value: availableModel, children: availableModel }, availableModel)))] }), _jsx("button", { type: "button", onClick: controller.clearMessages, title: "New conversation", className: "inline-flex h-8 w-8 items-center justify-center rounded-full text-[var(--text-tertiary)] hover:bg-[var(--bg-subtle)] hover:text-[var(--text-secondary)]", children: "\u21BA" })] })] }), _jsxs(AssistantMessageViewport, { className: "min-h-[180px]", ref: messagesContainerRef, onScroll: updatePinnedState, children: [controller.messages.length === 0 && !isConversationBusy ? (emptyState || _jsx(EmptyState, { onSendMessage: (message) => { void controller.sendMessage(message); } })) : null, (controller.isLoadingMessages && controller.messages.length === 0) ? (_jsx("div", { className: "flex justify-center py-6", children: _jsx("span", { className: "text-[var(--text-tertiary)] text-sm", children: "Loading\u2026" }) })) : null, (controller.isLoadingOlderMessages && controller.messages.length > 0) ? (_jsx("div", { className: "flex justify-center py-1", children: _jsx("span", { className: "text-[var(--text-tertiary)] text-xs", children: "Loading older\u2026" }) })) : null, displayMessageRows.map((row, index) => {
|
|
1013
1002
|
const previousRow = index > 0 ? displayMessageRows[index - 1] : null;
|
|
1014
1003
|
const showAssistantHeader = row.message.role !== "assistant"
|
|
1015
1004
|
? false
|
|
1016
1005
|
: previousRow?.message.role !== "assistant";
|
|
1017
1006
|
const includesLastRawMessage = row.sourceIndexes.includes(controller.messages.length - 1);
|
|
1018
1007
|
return (_jsx(MessageGroup, { message: row.message, onNavigateResource: onNavigateResource, onWidgetSendPrompt: handleWidgetSendPrompt, conversationId: controller.activeConversationId, isStreaming: isConversationBusy && includesLastRawMessage && row.message.role === "assistant", showAssistantHeader: showAssistantHeader, renderMessageContent: renderMessageContent, renderPresentedFile: renderPresentedFile, renderToolInvocation: renderToolInvocation }, row.id || index));
|
|
1019
|
-
}), isConversationBusy && controller.messages.length > 0 && !activeToolBanner && !lastMessageHasContent ? (_jsx(ThinkingIndicator, {})) : null, controller.error ? (_jsx("div", { className: "bg-[color:color-mix(in_srgb,_var(--state-error)_12%,_transparent)] border border-[color:color-mix(in_srgb,_var(--state-error)_48%,_var(--border-subtle))] rounded-lg p-3 text-xs text-[var(--state-error)] flex items-start gap-2.5", children: _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Something went wrong" }), _jsx("p", { className: "text-[var(--state-error)] mt-1", children: controller.error })] }) })) : null, (controller.messages.length > 0 || isConversationBusy || !!controller.error) ? (_jsx("div", { "aria-hidden": "true", className: "h-14 shrink-0" })) : null] })] }),
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1008
|
+
}), isConversationBusy && controller.messages.length > 0 && !activeToolBanner && !lastMessageHasContent ? (_jsx(ThinkingIndicator, {})) : null, controller.error ? (_jsx("div", { className: "bg-[color:color-mix(in_srgb,_var(--state-error)_12%,_transparent)] border border-[color:color-mix(in_srgb,_var(--state-error)_48%,_var(--border-subtle))] rounded-lg p-3 text-xs text-[var(--state-error)] flex items-start gap-2.5", children: _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Something went wrong" }), _jsx("p", { className: "text-[var(--state-error)] mt-1", children: controller.error })] }) })) : null, (controller.messages.length > 0 || isConversationBusy || !!controller.error) ? (_jsx("div", { "aria-hidden": "true", className: "h-14 shrink-0" })) : null] })] }), _jsxs("div", { className: "relative rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] p-2 shadow-[var(--shadow-md)]", children: [planSummary ? (_jsx("div", { className: "absolute bottom-[calc(100%+8px)] left-0 right-0 z-20", children: isPlanHidden ? (_jsxs("button", { type: "button", onClick: () => setIsPlanHidden(false), className: "inline-flex items-center gap-2 rounded-lg border border-[var(--border-default)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-subtle)] transition-colors", children: ["Show plan (", planSummary.completedCount, "/", planSummary.steps.length, ")"] })) : (_jsx(PlanSummaryStrip, { plan: planSummary, onHide: () => setIsPlanHidden(true) })) })) : null, isConversationBusy && activeToolBanner ? (_jsx("div", { className: "px-2 pb-1", children: _jsx("div", { className: "inline-flex max-w-full items-center gap-1.5 text-[11px] text-[var(--text-tertiary)] animate-in fade-in duration-200", children: _jsx("span", { className: "truncate", children: activeToolBanner.summary }) }) })) : null, activeAskQuestion && effectiveAskOverlayState && pendingAskUserInput ? (_jsx(AssistantAskOverlay, { questionNumber: effectiveAskOverlayState.currentQuestionIndex + 1, totalQuestions: pendingAskUserInput.questions.length, question: activeAskQuestion.question, options: activeAskQuestion.options, selectedOptions: activeAskAnswers, canContinue: canContinueAsk, continueLabel: effectiveAskOverlayState.currentQuestionIndex >= pendingAskUserInput.questions.length - 1 ? "Use answers" : "Continue", onSelectOption: updateAskAnswer, onContinue: activeAskQuestion.type !== "single_select" || pendingAskUserInput.questions.length > 1 ? continueAskQuestions : undefined, onSkip: () => dismissAskOverlay(effectiveAskOverlayState.toolCallId), mode: activeAskQuestion.type })) : (_jsxs("div", { className: "space-y-1.5", children: [controller.pendingFiles.length > 0 ? (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-1", children: controller.pendingFiles.map((file) => {
|
|
1009
|
+
const fileKey = `${file.name}:${file.size}:${file.lastModified}`;
|
|
1010
|
+
return (_jsx("div", { children: renderPendingFile({
|
|
1011
|
+
file,
|
|
1012
|
+
remove: () => controller.removePendingFile(fileKey),
|
|
1013
|
+
}) }, fileKey));
|
|
1014
|
+
}) })) : null, _jsxs("div", { className: "relative flex items-end gap-2", children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "hidden", onChange: (event) => { void handleUploadSelection(event.target.files); } }), _jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), disabled: isConversationBusy || controller.isUploadingFiles, className: cx("mb-1.5 ml-1 h-9 w-9 rounded-full flex items-center justify-center transition-colors", isConversationBusy || controller.isUploadingFiles
|
|
1015
|
+
? "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"
|
|
1016
|
+
: "bg-[var(--bg-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-canvas)] hover:text-[var(--text-primary)]"), title: "Upload files", children: controller.isUploadingFiles ? "…" : "+" }), _jsx("textarea", { ref: inputRef, value: draft, onChange: (event) => setDraft(event.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, className: "flex-1 resize-none border-0 bg-transparent px-3 py-2.5 text-[14px] text-[var(--text-primary)] leading-6 focus:ring-0 focus:outline-none placeholder:text-[var(--text-tertiary)] min-h-[48px] max-h-[220px]", rows: 1, disabled: isConversationBusy }), _jsx("div", { className: "pb-1.5 pr-1.5", children: _jsx("button", { onClick: isConversationBusy ? controller.stop : () => { void handleSubmit(); }, disabled: !isConversationBusy && !draft.trim(), className: cx("h-9 w-9 rounded-full flex items-center justify-center transition-all duration-200", isConversationBusy
|
|
1017
|
+
? "bg-[var(--text-primary)] text-[var(--text-inverse)] hover:bg-[color:color-mix(in_srgb,_var(--text-primary)_80%,_transparent)] hover:scale-105"
|
|
1018
|
+
: draft.trim()
|
|
1019
|
+
? "bg-[var(--brand-primary)] text-[var(--text-on-brand)] shadow-[var(--shadow-xs)] hover:bg-[color:color-mix(in_srgb,_var(--brand-primary)_88%,_var(--text-primary))]"
|
|
1020
|
+
: "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), title: isConversationBusy ? "Stop generating" : "Send message", children: isConversationBusy ? "■" : "→" }) })] })] }))] })] })] }));
|
|
1032
1021
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
2
|
import type { AssistantRenderableMessage, AssistantToolInvocation } from "../useAssistantController.js";
|
|
3
3
|
export interface AssistantConversationListItem {
|
|
4
4
|
id: string;
|
|
@@ -61,8 +61,6 @@ export interface AssistantExperienceCustomizationProps {
|
|
|
61
61
|
subtitle?: ReactNode;
|
|
62
62
|
placeholder?: string;
|
|
63
63
|
emptyState?: ReactNode;
|
|
64
|
-
className?: string;
|
|
65
|
-
style?: CSSProperties;
|
|
66
64
|
draft?: string;
|
|
67
65
|
onDraftChange?: (value: string) => void;
|
|
68
66
|
showConversationList?: boolean;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type { UseAssistantRuntimeOptions, UseAssistantRuntimeResult, } from "./u
|
|
|
13
13
|
export { useAssistantController } from "./useAssistantController.js";
|
|
14
14
|
export type { AssistantAction, AssistantConversationScope, AssistantMessagePart, AssistantRenderableMessage, AssistantToolInvocation, UseAssistantControllerOptions, UseAssistantControllerResult, } from "./useAssistantController.js";
|
|
15
15
|
export type { AssistantConversationRenderArgs, AssistantControllerView, AssistantExperienceCustomizationProps, AssistantMessageRenderArgs, AssistantPendingFileRenderArgs, AssistantPresentedFileRenderArgs, AssistantToolRenderArgs, } from "./components/assistant-types.js";
|
|
16
|
-
export { AssistantAskOverlay, AssistantComposer, AssistantConversationList, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantPendingFileChip, AssistantShellLayout, AssistantStatusPill,
|
|
16
|
+
export { AssistantAskOverlay, AssistantComposer, AssistantConversationList, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantPendingFileChip, AssistantShellLayout, AssistantStatusPill, } from "./components/AssistantChrome.js";
|
|
17
17
|
export type { AssistantAskOverlayProps, AssistantComposerProps, AssistantConversationListProps, AssistantHeaderProps, AssistantMessageViewportProps, AssistantModelPickerProps, AssistantPendingFileChipProps, AssistantShellLayoutProps, AssistantStatusPillProps, } from "./components/AssistantChrome.js";
|
|
18
18
|
export { AssistantExperienceView } from "./components/AssistantExperience.js";
|
|
19
19
|
export type { ActiveToolBanner, AskUserInputQuestion, AssistantExperienceViewProps, DisplayMessageRow, PendingAskUserInput, PlanStepState, PlanSummaryState, } from "./components/AssistantExperience.js";
|
package/dist/react/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { useAssistantRun } from "./useAssistantRun.js";
|
|
|
5
5
|
export { useAssistantSession } from "./useAssistantSession.js";
|
|
6
6
|
export { useAssistantRuntime } from "./useAssistantRuntime.js";
|
|
7
7
|
export { useAssistantController } from "./useAssistantController.js";
|
|
8
|
-
export { AssistantAskOverlay, AssistantComposer, AssistantConversationList, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantPendingFileChip, AssistantShellLayout, AssistantStatusPill,
|
|
8
|
+
export { AssistantAskOverlay, AssistantComposer, AssistantConversationList, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantPendingFileChip, AssistantShellLayout, AssistantStatusPill, } from "./components/AssistantChrome.js";
|
|
9
9
|
export { AssistantExperienceView } from "./components/AssistantExperience.js";
|
|
10
10
|
export { AssistantEmbedded } from "./components/AssistantEmbedded.js";
|
|
11
11
|
export { buildDisplayMessageRows, dedupToolInvocations, EmptyState, findPendingAskUserInput, formatAskUserInputAnswers, getActiveToolBanner, extractPresentFilePathsFromInvocation, latestPlanSummary, MessageGroup, PlanSummaryStrip, ThinkingIndicator, } from "./components/AssistantExperience.js";
|