lemma-sdk 0.2.13 → 0.2.15
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 +32 -57
- package/dist/react/components/AssistantChrome.d.ts +13 -19
- package/dist/react/components/AssistantChrome.js +30 -68
- package/dist/react/components/AssistantEmbedded.js +2 -1
- package/dist/react/components/AssistantExperience.d.ts +2 -4
- package/dist/react/components/AssistantExperience.js +40 -51
- package/dist/react/components/assistant-types.d.ts +1 -3
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -1
- package/dist/react/styles.css +448 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -173,6 +173,15 @@ Notes:
|
|
|
173
173
|
|
|
174
174
|
`lemma-sdk/react` now exposes the assistant controller plus the reusable UI primitives used by the app shell. A simple integration looks like this:
|
|
175
175
|
|
|
176
|
+
If you want the SDK UI to look correct outside the Lemma app, import the bundled stylesheet once:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import "lemma-sdk/react/styles.css";
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The stylesheet provides the default Lemma assistant theme tokens used by the SDK UI. Without it, components may render with missing colors, borders, and spacing in apps that do not already define the same CSS variables.
|
|
183
|
+
The SDK UI now ships its own semantic assistant classes and default styling, so consumers should not need the Lemma app's internal theme setup or Tailwind config just to render the assistant correctly.
|
|
184
|
+
|
|
176
185
|
```tsx
|
|
177
186
|
import {
|
|
178
187
|
MessageGroup,
|
|
@@ -187,7 +196,7 @@ import {
|
|
|
187
196
|
function AssistantSurface() {
|
|
188
197
|
const assistant = useAssistantController({
|
|
189
198
|
client,
|
|
190
|
-
assistantId: "
|
|
199
|
+
assistantId: "uuid",
|
|
191
200
|
podId: "pod_123",
|
|
192
201
|
});
|
|
193
202
|
|
|
@@ -218,14 +227,6 @@ function AssistantSurface() {
|
|
|
218
227
|
}
|
|
219
228
|
```
|
|
220
229
|
|
|
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
230
|
The intended split is:
|
|
230
231
|
|
|
231
232
|
- SDK: `useAssistantController`, message/tool normalization, plan parsing, tool rollups, and assistant UI primitives.
|
|
@@ -242,19 +243,21 @@ Useful UI primitives exported from `lemma-sdk/react`:
|
|
|
242
243
|
- `AssistantAskOverlay`
|
|
243
244
|
- `AssistantPendingFileChip`
|
|
244
245
|
- `AssistantStatusPill`
|
|
246
|
+
- `AssistantThemeScope`
|
|
245
247
|
- `MessageGroup`
|
|
246
248
|
- `PlanSummaryStrip`
|
|
247
249
|
|
|
248
250
|
For a direct plug-and-play component, `AssistantEmbedded` wires `useAssistantController` into the default assistant experience:
|
|
249
251
|
|
|
250
252
|
```tsx
|
|
253
|
+
import "lemma-sdk/react/styles.css";
|
|
251
254
|
import { AssistantEmbedded } from "lemma-sdk/react";
|
|
252
255
|
|
|
253
256
|
function SupportAssistant() {
|
|
254
257
|
return (
|
|
255
258
|
<AssistantEmbedded
|
|
256
259
|
client={client}
|
|
257
|
-
assistantId="
|
|
260
|
+
assistantId="uuid"
|
|
258
261
|
podId="pod_123"
|
|
259
262
|
title="Support Assistant"
|
|
260
263
|
subtitle="Ask questions about this pod."
|
|
@@ -265,67 +268,39 @@ function SupportAssistant() {
|
|
|
265
268
|
}
|
|
266
269
|
```
|
|
267
270
|
|
|
268
|
-
If you
|
|
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:
|
|
271
|
+
If you are composing your own shell with the SDK primitives, wrap it in `AssistantThemeScope` unless your app already provides matching theme tokens:
|
|
291
272
|
|
|
292
273
|
```tsx
|
|
274
|
+
import "lemma-sdk/react/styles.css";
|
|
293
275
|
import {
|
|
294
276
|
AssistantComposer,
|
|
295
277
|
AssistantHeader,
|
|
296
278
|
AssistantMessageViewport,
|
|
297
|
-
|
|
279
|
+
AssistantShellLayout,
|
|
280
|
+
AssistantThemeScope,
|
|
298
281
|
} from "lemma-sdk/react";
|
|
299
282
|
|
|
300
|
-
function
|
|
283
|
+
function CustomAssistantShell() {
|
|
301
284
|
return (
|
|
302
|
-
<
|
|
303
|
-
<
|
|
304
|
-
|
|
305
|
-
|
|
285
|
+
<AssistantThemeScope>
|
|
286
|
+
<AssistantShellLayout
|
|
287
|
+
main={
|
|
288
|
+
<div className="flex min-h-0 flex-1 flex-col gap-3">
|
|
289
|
+
<AssistantHeader title="Lemma Assistant" subtitle="Ask anything" />
|
|
290
|
+
<AssistantMessageViewport>
|
|
291
|
+
<div>Messages go here</div>
|
|
292
|
+
</AssistantMessageViewport>
|
|
293
|
+
<AssistantComposer>
|
|
294
|
+
<textarea placeholder="Message Lemma Assistant" />
|
|
295
|
+
</AssistantComposer>
|
|
296
|
+
</div>
|
|
297
|
+
}
|
|
306
298
|
/>
|
|
307
|
-
|
|
308
|
-
{/* messages */}
|
|
309
|
-
</AssistantMessageViewport>
|
|
310
|
-
<AssistantComposer>
|
|
311
|
-
{/* composer */}
|
|
312
|
-
</AssistantComposer>
|
|
313
|
-
</div>
|
|
299
|
+
</AssistantThemeScope>
|
|
314
300
|
);
|
|
315
301
|
}
|
|
316
302
|
```
|
|
317
303
|
|
|
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
304
|
### Assistant names (resource key)
|
|
330
305
|
|
|
331
306
|
Assistant CRUD is name-based:
|
|
@@ -1,14 +1,15 @@
|
|
|
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
|
|
4
|
-
|
|
3
|
+
export interface AssistantThemeScopeProps extends ComponentPropsWithoutRef<"div"> {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function AssistantThemeScope({ className, children, ...props }: AssistantThemeScopeProps): import("react/jsx-runtime").JSX.Element;
|
|
5
7
|
export interface AssistantHeaderProps {
|
|
6
8
|
title: ReactNode;
|
|
7
9
|
subtitle?: ReactNode;
|
|
8
10
|
badge?: ReactNode;
|
|
9
11
|
controls?: ReactNode;
|
|
10
12
|
className?: string;
|
|
11
|
-
style?: CSSProperties;
|
|
12
13
|
}
|
|
13
14
|
export interface AssistantMessageViewportProps extends ComponentPropsWithoutRef<"div"> {
|
|
14
15
|
innerClassName?: string;
|
|
@@ -20,10 +21,9 @@ export interface AssistantShellLayoutProps {
|
|
|
20
21
|
sidebarVisible?: boolean;
|
|
21
22
|
main: ReactNode;
|
|
22
23
|
className?: string;
|
|
23
|
-
style?: CSSProperties;
|
|
24
24
|
}
|
|
25
|
-
export declare function AssistantShellLayout({ sidebar, sidebarVisible, main, className,
|
|
26
|
-
export declare function AssistantHeader({ title, subtitle, badge, controls, className,
|
|
25
|
+
export declare function AssistantShellLayout({ sidebar, sidebarVisible, main, className, }: AssistantShellLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare function AssistantHeader({ title, subtitle, badge, controls, className, }: AssistantHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
27
27
|
export interface AssistantConversationListProps {
|
|
28
28
|
conversations: AssistantConversationListItem[];
|
|
29
29
|
activeConversationId: string | null;
|
|
@@ -33,9 +33,8 @@ export interface AssistantConversationListProps {
|
|
|
33
33
|
title?: ReactNode;
|
|
34
34
|
newLabel?: ReactNode;
|
|
35
35
|
className?: string;
|
|
36
|
-
style?: CSSProperties;
|
|
37
36
|
}
|
|
38
|
-
export declare function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title, newLabel, className,
|
|
37
|
+
export declare function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title, newLabel, className, }: AssistantConversationListProps): import("react/jsx-runtime").JSX.Element;
|
|
39
38
|
export interface AssistantModelPickerProps<TValue extends string = string> {
|
|
40
39
|
value: TValue | null;
|
|
41
40
|
options: TValue[];
|
|
@@ -44,9 +43,8 @@ export interface AssistantModelPickerProps<TValue extends string = string> {
|
|
|
44
43
|
getOptionLabel?: (value: TValue) => ReactNode;
|
|
45
44
|
onChange: (value: TValue | null) => void;
|
|
46
45
|
className?: string;
|
|
47
|
-
style?: CSSProperties;
|
|
48
46
|
}
|
|
49
|
-
export declare function AssistantModelPicker<TValue extends string = string>({ value, options, disabled, autoLabel, getOptionLabel, onChange, className,
|
|
47
|
+
export declare function AssistantModelPicker<TValue extends string = string>({ value, options, disabled, autoLabel, getOptionLabel, onChange, className, }: AssistantModelPickerProps<TValue>): import("react/jsx-runtime").JSX.Element;
|
|
50
48
|
export interface AssistantAskOverlayProps {
|
|
51
49
|
questionNumber: number;
|
|
52
50
|
totalQuestions: number;
|
|
@@ -59,14 +57,12 @@ export interface AssistantAskOverlayProps {
|
|
|
59
57
|
onContinue?: () => void;
|
|
60
58
|
onSkip?: () => void;
|
|
61
59
|
mode?: "single_select" | "multi_select" | "rank_priorities";
|
|
62
|
-
style?: CSSProperties;
|
|
63
60
|
}
|
|
64
|
-
export declare function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode,
|
|
61
|
+
export declare function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode, }: AssistantAskOverlayProps): import("react/jsx-runtime").JSX.Element;
|
|
65
62
|
export interface AssistantPendingFileChipProps {
|
|
66
63
|
label: ReactNode;
|
|
67
64
|
onRemove?: () => void;
|
|
68
65
|
className?: string;
|
|
69
|
-
style?: CSSProperties;
|
|
70
66
|
}
|
|
71
67
|
export interface AssistantComposerProps {
|
|
72
68
|
floating?: ReactNode;
|
|
@@ -74,14 +70,12 @@ export interface AssistantComposerProps {
|
|
|
74
70
|
pendingFiles?: ReactNode;
|
|
75
71
|
children: ReactNode;
|
|
76
72
|
className?: string;
|
|
77
|
-
style?: CSSProperties;
|
|
78
73
|
}
|
|
79
|
-
export declare function AssistantComposer({ floating, status, pendingFiles, children, className,
|
|
80
|
-
export declare function AssistantPendingFileChip({ label, onRemove, className,
|
|
74
|
+
export declare function AssistantComposer({ floating, status, pendingFiles, children, className, }: AssistantComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
75
|
+
export declare function AssistantPendingFileChip({ label, onRemove, className, }: AssistantPendingFileChipProps): import("react/jsx-runtime").JSX.Element;
|
|
81
76
|
export interface AssistantStatusPillProps {
|
|
82
77
|
label: ReactNode;
|
|
83
78
|
subtle?: boolean;
|
|
84
79
|
className?: string;
|
|
85
|
-
style?: CSSProperties;
|
|
86
80
|
}
|
|
87
|
-
export declare function AssistantStatusPill({ label, subtle, className,
|
|
81
|
+
export declare function AssistantStatusPill({ label, subtle, className, }: AssistantStatusPillProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,93 +3,55 @@ 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);
|
|
6
|
+
export function AssistantThemeScope({ className, children, ...props }) {
|
|
7
|
+
return (_jsx("div", { className: cx("lemma-assistant-theme", className), ...props, children: children }));
|
|
16
8
|
}
|
|
17
|
-
export const
|
|
18
|
-
"--bg-
|
|
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 }) }));
|
|
9
|
+
export const AssistantMessageViewport = forwardRef(function AssistantMessageViewport({ className, innerClassName, children, ...props }, ref) {
|
|
10
|
+
return (_jsx("div", { ref: ref, className: cx("lemma-assistant-viewport", "min-h-0 flex-1 overflow-y-auto bg-[var(--bg-surface)] px-4 py-4", className), ...props, children: _jsx("div", { className: cx("lemma-assistant-viewport-inner", "mx-auto flex w-full max-w-5xl flex-col gap-3", innerClassName), children: children }) }));
|
|
49
11
|
});
|
|
50
|
-
export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, className,
|
|
51
|
-
return (_jsxs("div", { className: cx("mx-auto flex h-full w-full min-h-
|
|
12
|
+
export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, className, }) {
|
|
13
|
+
return (_jsxs("div", { className: cx("lemma-assistant-shell", "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: "lemma-assistant-shell-sidebar hidden h-full min-h-0 lg:block", children: sidebar })) : null, _jsx("div", { className: "lemma-assistant-shell-main min-h-0", children: main })] }));
|
|
52
14
|
}
|
|
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
|
|
15
|
+
export function AssistantHeader({ title, subtitle, badge, controls, className, }) {
|
|
16
|
+
return (_jsxs("div", { className: cx("lemma-assistant-header", "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: "lemma-assistant-header-copy flex items-center gap-2.5", children: [badge ? (_jsx("div", { className: "lemma-assistant-header-badge 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", { className: "lemma-assistant-header-titles", children: [_jsx("h3", { className: "lemma-assistant-header-title text-[13px] font-semibold leading-tight text-[var(--text-primary)]", children: title }), subtitle ? (_jsx("p", { className: "lemma-assistant-header-subtitle text-[11px] text-[var(--text-tertiary)]", children: subtitle })) : null] })] }), controls ? (_jsx("div", { className: "lemma-assistant-header-controls flex items-center gap-1", children: controls })) : null] }));
|
|
55
17
|
}
|
|
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-
|
|
18
|
+
export function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title = "Conversations", newLabel = "New", className, }) {
|
|
19
|
+
return (_jsxs("aside", { className: cx("lemma-assistant-conversation-list", "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: "lemma-assistant-conversation-list-header border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: _jsxs("div", { className: "lemma-assistant-conversation-list-header-row flex items-center justify-between gap-3", children: [_jsxs("div", { className: "lemma-assistant-conversation-list-copy", children: [_jsx("div", { className: "lemma-assistant-conversation-list-title text-[13px] font-semibold text-[var(--text-primary)]", children: title }), _jsxs("div", { className: "lemma-assistant-conversation-list-meta mt-1 text-[11px] text-[var(--text-tertiary)]", children: [conversations.length, " total"] })] }), onNewConversation ? (_jsx("button", { type: "button", onClick: onNewConversation, className: "lemma-assistant-conversation-list-new 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: "lemma-assistant-conversation-list-items min-h-0 flex-1 overflow-y-auto p-3 space-y-2", children: conversations.map((conversation) => {
|
|
58
20
|
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-[
|
|
21
|
+
return (_jsxs("button", { type: "button", onClick: () => onSelectConversation(conversation.id), className: cx("lemma-assistant-conversation-list-item", "w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
|
|
22
|
+
? "lemma-assistant-conversation-list-item-active 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))]"
|
|
23
|
+
: "border-[var(--border-default)] bg-[var(--bg-surface)] hover:bg-[var(--bg-subtle)]"), children: [_jsx("div", { className: "lemma-assistant-conversation-list-item-title truncate text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel
|
|
62
24
|
? renderConversationLabel({ conversation, isActive })
|
|
63
|
-
: (conversation.title || "Untitled conversation") }),
|
|
25
|
+
: (conversation.title || "Untitled conversation") }), _jsx("div", { className: "lemma-assistant-conversation-list-item-status mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
|
|
64
26
|
}) })] }));
|
|
65
27
|
}
|
|
66
|
-
export function AssistantModelPicker({ value, options, disabled, autoLabel = "Auto", getOptionLabel, onChange, className,
|
|
28
|
+
export function AssistantModelPicker({ value, options, disabled, autoLabel = "Auto", getOptionLabel, onChange, className, }) {
|
|
67
29
|
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-
|
|
30
|
+
return (_jsxs("select", { value: value ?? autoValue, onChange: (event) => onChange(event.target.value === autoValue ? null : event.target.value), disabled: disabled, className: cx("lemma-assistant-model-picker", "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
31
|
}
|
|
70
|
-
export function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode = "single_select",
|
|
71
|
-
return (_jsxs("div", { className: "
|
|
32
|
+
export function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode = "single_select", }) {
|
|
33
|
+
return (_jsxs("div", { className: "lemma-assistant-ask-overlay space-y-2", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-header flex items-start justify-between gap-3", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-copy", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-kicker text-[11px] uppercase tracking-[0.12em] text-[var(--text-tertiary)]", children: ["Question ", questionNumber, " of ", totalQuestions] }), _jsx("p", { className: "lemma-assistant-ask-overlay-question mt-1 text-[14px] font-medium leading-6 text-[var(--text-primary)]", children: question })] }), onSkip ? (_jsx("button", { type: "button", onClick: onSkip, className: "lemma-assistant-ask-overlay-skip 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: "lemma-assistant-ask-overlay-options max-h-[260px] space-y-1.5 overflow-y-auto pr-1", children: options.map((option, optionIndex) => {
|
|
72
34
|
const isSelected = selectedOptions.includes(option);
|
|
73
35
|
const rankLabel = mode === "rank_priorities" && isSelected
|
|
74
36
|
? selectedOptions.indexOf(option) + 1
|
|
75
37
|
: null;
|
|
76
|
-
return (_jsx("button", { type: "button", onClick: () => onSelectOption(option), className: cx("w-full rounded-lg border px-2.5 py-2 text-left text-[13px] transition-colors", isSelected
|
|
77
|
-
? "border-[color:color-mix(in_srgb,_var(--brand-primary)_64%,_var(--border-subtle))] bg-[color:color-mix(in_srgb,_var(--brand-primary)_14%,_transparent)] text-[var(--text-primary)]"
|
|
78
|
-
: "border-[var(--border-default)] bg-[var(--bg-canvas)] text-[var(--text-secondary)] hover:bg-[var(--bg-subtle)] hover:text-[var(--text-primary)]"), children: _jsxs("span", { className: "inline-flex items-center gap-2", children: [rankLabel ? (_jsx("span", { className: "inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-[var(--brand-primary)] px-1 text-[10px] font-semibold text-[var(--text-on-brand)]", children: rankLabel })) : (_jsx("span", { className: cx("inline-block h-2.5 w-2.5 rounded-full border", isSelected
|
|
38
|
+
return (_jsx("button", { type: "button", onClick: () => onSelectOption(option), className: cx("lemma-assistant-ask-overlay-option", "w-full rounded-lg border px-2.5 py-2 text-left text-[13px] transition-colors", isSelected
|
|
39
|
+
? "lemma-assistant-ask-overlay-option-selected border-[color:color-mix(in_srgb,_var(--brand-primary)_64%,_var(--border-subtle))] bg-[color:color-mix(in_srgb,_var(--brand-primary)_14%,_transparent)] text-[var(--text-primary)]"
|
|
40
|
+
: "border-[var(--border-default)] bg-[var(--bg-canvas)] text-[var(--text-secondary)] hover:bg-[var(--bg-subtle)] hover:text-[var(--text-primary)]"), children: _jsxs("span", { className: "lemma-assistant-ask-overlay-option-label inline-flex items-center gap-2", children: [rankLabel ? (_jsx("span", { className: "inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-[var(--brand-primary)] px-1 text-[10px] font-semibold text-[var(--text-on-brand)]", children: rankLabel })) : (_jsx("span", { className: cx("inline-block h-2.5 w-2.5 rounded-full border", isSelected
|
|
79
41
|
? "border-[var(--brand-primary)] bg-[var(--brand-primary)]"
|
|
80
42
|
: "border-[var(--border-default)] bg-transparent") })), option] }) }, `${option}-${optionIndex}`));
|
|
81
|
-
}) }), onContinue ? (_jsx("div", { className: "flex justify-end", children: _jsx("button", { type: "button", onClick: onContinue, disabled: !canContinue, className: cx("rounded-md px-2.5 py-1.5 text-[12px] font-medium transition-colors", canContinue
|
|
43
|
+
}) }), onContinue ? (_jsx("div", { className: "lemma-assistant-ask-overlay-actions flex justify-end", children: _jsx("button", { type: "button", onClick: onContinue, disabled: !canContinue, className: cx("lemma-assistant-ask-overlay-continue", "rounded-md px-2.5 py-1.5 text-[12px] font-medium transition-colors", canContinue
|
|
82
44
|
? "bg-[var(--brand-primary)] text-[var(--text-on-brand)] hover:bg-[color:color-mix(in_srgb,_var(--brand-primary)_88%,_var(--text-primary))]"
|
|
83
45
|
: "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), children: continueLabel }) })) : null] }));
|
|
84
46
|
}
|
|
85
|
-
export function AssistantComposer({ floating, status, pendingFiles, children, className,
|
|
86
|
-
return (_jsxs("div", { className: cx("relative rounded-
|
|
47
|
+
export function AssistantComposer({ floating, status, pendingFiles, children, className, }) {
|
|
48
|
+
return (_jsxs("div", { className: cx("lemma-assistant-composer", "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: "lemma-assistant-composer-floating absolute bottom-[calc(100%+8px)] left-0 right-0 z-20", children: floating })) : null, _jsx("div", { className: "lemma-assistant-composer-status-rail min-h-[34px] px-2 pb-1", children: _jsx("div", { className: "lemma-assistant-composer-status 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: "lemma-assistant-composer-pending flex flex-wrap items-center gap-1.5 px-1 pb-1.5", children: pendingFiles })) : null, _jsx("div", { className: "lemma-assistant-composer-body", children: children })] }));
|
|
87
49
|
}
|
|
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
|
|
50
|
+
export function AssistantPendingFileChip({ label, onRemove, className, }) {
|
|
51
|
+
return (_jsxs("span", { className: cx("lemma-assistant-pending-file-chip", "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: "lemma-assistant-pending-file-chip-label truncate max-w-[180px]", children: label }), onRemove ? (_jsx("button", { type: "button", onClick: onRemove, className: "lemma-assistant-pending-file-chip-remove inline-flex h-4 w-4 items-center justify-center rounded-full hover:bg-[var(--bg-canvas)]", title: "Remove file", children: "\u00D7" })) : null] }));
|
|
90
52
|
}
|
|
91
|
-
export function AssistantStatusPill({ label, subtle = false, className,
|
|
92
|
-
return (_jsxs("div", { className: cx("inline-flex min-h-[
|
|
93
|
-
? "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
|
+
export function AssistantStatusPill({ label, subtle = false, className, }) {
|
|
54
|
+
return (_jsxs("div", { className: cx("lemma-assistant-status-pill", "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
|
|
55
|
+
? "lemma-assistant-status-pill-subtle 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)]"
|
|
56
|
+
: "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: "lemma-assistant-status-pill-dot relative inline-flex h-2.5 w-2.5 shrink-0", children: [_jsx("span", { className: "lemma-assistant-status-pill-dot-ping absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--brand-primary)]/45" }), _jsx("span", { className: "lemma-assistant-status-pill-dot-core relative inline-flex h-2.5 w-2.5 rounded-full bg-[var(--brand-primary)]" })] }), _jsx("span", { className: "lemma-assistant-status-pill-label truncate", children: label })] }));
|
|
95
57
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useAssistantController } from "../useAssistantController.js";
|
|
3
|
+
import { AssistantThemeScope } from "./AssistantChrome.js";
|
|
3
4
|
import { AssistantExperienceView } from "./AssistantExperience.js";
|
|
4
5
|
export function AssistantEmbedded({ client, podId, assistantId, organizationId, enabled = true, ...props }) {
|
|
5
6
|
const controller = useAssistantController({
|
|
@@ -9,5 +10,5 @@ export function AssistantEmbedded({ client, podId, assistantId, organizationId,
|
|
|
9
10
|
organizationId: organizationId ?? undefined,
|
|
10
11
|
enabled,
|
|
11
12
|
});
|
|
12
|
-
return _jsx(AssistantExperienceView, { controller: controller, ...props });
|
|
13
|
+
return (_jsx(AssistantThemeScope, { children: _jsx(AssistantExperienceView, { controller: controller, ...props }) }));
|
|
13
14
|
}
|
|
@@ -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,13 +507,13 @@ 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);
|
|
514
514
|
const visibleSteps = showAll ? plan.steps : plan.steps.slice(0, 5);
|
|
515
515
|
const hiddenCount = Math.max(0, plan.steps.length - visibleSteps.length);
|
|
516
|
-
return (_jsxs("div", { className: "rounded-xl border border-[color:color-mix(in_srgb,_var(--brand-primary)_24%,_var(--border-subtle))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_18%,_var(--bg-surface))] px-3 py-2.5 shadow-[var(--shadow-sm)]", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "text-[12px] font-semibold text-[var(--text-primary)]", children: "Task plan" }), _jsxs("span", { className: "text-[11px] text-[var(--text-tertiary)]", children: [plan.completedCount, "/", plan.steps.length, " complete"] }), plan.inProgressCount > 0 ? (_jsxs("span", { className: "rounded-full bg-[color:color-mix(in_srgb,_var(--brand-primary)_16%,_transparent)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--brand-primary)]", children: [plan.inProgressCount, " active"] })) : null] }), _jsx("button", { type: "button", onClick: onHide, className: "text-[11px] font-medium text-[var(--text-tertiary)] hover:text-[var(--text-primary)] transition-colors", children: "Hide" })] }), plan.activeStep ? (_jsxs("div", { className: "mt-1.5 truncate text-[11px] text-[var(--text-secondary)]", title: plan.activeStep, children: [plan.running ? "Running:" : "Current:", " ", plan.activeStep] })) : null, _jsxs("div", { className: "mt-2 space-y-1", children: [visibleSteps.map((step, index) => (_jsxs("div", { className: "flex items-start gap-2 text-[11px]", children: [_jsx("span", { className: cx("mt-1 inline-block h-2 w-2 shrink-0 rounded-full", step.status === "completed" && "bg-[var(--state-success)]", step.status === "in_progress" && "bg-[var(--brand-primary)]", step.status === "pending" && "bg-[var(--border-default)]") }), _jsx("span", { className: cx("leading-5", step.status === "completed" && "text-[var(--text-tertiary)] line-through", step.status === "in_progress" && "text-[var(--brand-primary)] font-medium", step.status === "pending" && "text-[var(--text-secondary)]"), children: step.step })] }, `${step.step}-${index}`))), plan.steps.length > 5 ? (_jsxs("div", { className: "flex items-center gap-2 pt-0.5", children: [_jsx("button", { type: "button", onClick: () => setShowAll((prev) => !prev), className: "text-[10px] font-medium text-[var(--brand-primary)] hover:text-[var(--text-primary)] transition-colors", children: showAll ? "Show less" : `See all ${plan.steps.length} steps` }), !showAll && hiddenCount > 0 ? (_jsxs("span", { className: "text-[10px] text-[var(--text-tertiary)]", children: ["+", hiddenCount, " more"] })) : null] })) : null] })] }));
|
|
516
|
+
return (_jsxs("div", { className: "lemma-assistant-plan-strip rounded-xl border border-[color:color-mix(in_srgb,_var(--brand-primary)_24%,_var(--border-subtle))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_18%,_var(--bg-surface))] px-3 py-2.5 shadow-[var(--shadow-sm)]", children: [_jsxs("div", { className: "lemma-assistant-plan-strip-header flex items-center justify-between gap-2", children: [_jsxs("div", { className: "lemma-assistant-plan-strip-summary inline-flex items-center gap-2", children: [_jsx("span", { className: "lemma-assistant-plan-strip-title text-[12px] font-semibold text-[var(--text-primary)]", children: "Task plan" }), _jsxs("span", { className: "lemma-assistant-plan-strip-count text-[11px] text-[var(--text-tertiary)]", children: [plan.completedCount, "/", plan.steps.length, " complete"] }), plan.inProgressCount > 0 ? (_jsxs("span", { className: "lemma-assistant-plan-strip-active rounded-full bg-[color:color-mix(in_srgb,_var(--brand-primary)_16%,_transparent)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--brand-primary)]", children: [plan.inProgressCount, " active"] })) : null] }), _jsx("button", { type: "button", onClick: onHide, className: "text-[11px] font-medium text-[var(--text-tertiary)] hover:text-[var(--text-primary)] transition-colors", children: "Hide" })] }), plan.activeStep ? (_jsxs("div", { className: "mt-1.5 truncate text-[11px] text-[var(--text-secondary)]", title: plan.activeStep, children: [plan.running ? "Running:" : "Current:", " ", plan.activeStep] })) : null, _jsxs("div", { className: "lemma-assistant-plan-strip-steps mt-2 space-y-1", children: [visibleSteps.map((step, index) => (_jsxs("div", { className: "lemma-assistant-plan-strip-step flex items-start gap-2 text-[11px]", children: [_jsx("span", { className: cx("mt-1 inline-block h-2 w-2 shrink-0 rounded-full", step.status === "completed" && "bg-[var(--state-success)]", step.status === "in_progress" && "bg-[var(--brand-primary)]", step.status === "pending" && "bg-[var(--border-default)]") }), _jsx("span", { className: cx("leading-5", step.status === "completed" && "text-[var(--text-tertiary)] line-through", step.status === "in_progress" && "text-[var(--brand-primary)] font-medium", step.status === "pending" && "text-[var(--text-secondary)]"), children: step.step })] }, `${step.step}-${index}`))), plan.steps.length > 5 ? (_jsxs("div", { className: "flex items-center gap-2 pt-0.5", children: [_jsx("button", { type: "button", onClick: () => setShowAll((prev) => !prev), className: "text-[10px] font-medium text-[var(--brand-primary)] hover:text-[var(--text-primary)] transition-colors", children: showAll ? "Show less" : `See all ${plan.steps.length} steps` }), !showAll && hiddenCount > 0 ? (_jsxs("span", { className: "text-[10px] text-[var(--text-tertiary)]", children: ["+", hiddenCount, " more"] })) : null] })) : null] })] }));
|
|
517
517
|
}
|
|
518
518
|
export function ThinkingIndicator() {
|
|
519
519
|
const [show, setShow] = useState(false);
|
|
@@ -523,35 +523,19 @@ export function ThinkingIndicator() {
|
|
|
523
523
|
}, []);
|
|
524
524
|
if (!show)
|
|
525
525
|
return null;
|
|
526
|
-
return (_jsx("div", { className: "px-1 animate-in fade-in duration-300", children: _jsxs("div", { className: "inline-flex items-center gap-2.5 text-[12px] leading-5 text-[var(--text-tertiary)]", children: [_jsx("span", { className: "inline-flex h-2 w-2 rounded-full bg-[var(--brand-accent)]" }), _jsx("span", { className: "font-semibold 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: "Thinking..." })] }) }));
|
|
526
|
+
return (_jsx("div", { className: "lemma-assistant-thinking px-1 animate-in fade-in duration-300", children: _jsxs("div", { className: "lemma-assistant-thinking-label inline-flex items-center gap-2.5 text-[12px] leading-5 text-[var(--text-tertiary)]", children: [_jsx("span", { className: "lemma-assistant-thinking-dot inline-flex h-2 w-2 rounded-full bg-[var(--brand-accent)]" }), _jsx("span", { className: "lemma-assistant-thinking-text font-semibold 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: "Thinking..." })] }) }));
|
|
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: "lemma-assistant-empty-state text-center py-5 px-2", children: [_jsxs("div", { className: "lemma-assistant-empty-state-hero flex flex-col items-center justify-center mb-6", children: [_jsx("div", { className: "lemma-assistant-empty-state-badge 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: "lemma-assistant-empty-state-title font-semibold text-[var(--text-primary)] text-[15px]", children: "What can I help you build?" }), _jsx("p", { className: "lemma-assistant-empty-state-copy 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: "lemma-assistant-empty-state-suggestions 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: "lemma-assistant-empty-state-suggestion 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
|
-
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 }) })] }));
|
|
538
|
+
return (_jsxs("details", { className: "lemma-assistant-reasoning group", open: isStreaming, children: [_jsxs("summary", { className: "lemma-assistant-reasoning-summary 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: "lemma-assistant-reasoning-body mt-1 pl-4 border-l border-[var(--border-default)]", children: _jsx("pre", { className: "lemma-assistant-reasoning-text text-[11px] leading-5 text-[var(--text-tertiary)] whitespace-pre-wrap font-mono", children: text }) })] }));
|
|
555
539
|
}
|
|
556
540
|
function PresentFilesCard({ filepaths, conversationId, renderPresentedFile, }) {
|
|
557
541
|
const fakeMessage = {
|
|
@@ -565,7 +549,7 @@ function PresentFilesCard({ filepaths, conversationId, renderPresentedFile, }) {
|
|
|
565
549
|
args: { filepaths },
|
|
566
550
|
state: "result",
|
|
567
551
|
};
|
|
568
|
-
return (_jsx("div", { className: "pt-1 space-y-2", children: filepaths.map((filepath) => (_jsx("div", { children: (renderPresentedFile || defaultPresentedFile)({
|
|
552
|
+
return (_jsx("div", { className: "lemma-assistant-presented-files pt-1 space-y-2", children: filepaths.map((filepath) => (_jsx("div", { className: "lemma-assistant-presented-file", children: (renderPresentedFile || defaultPresentedFile)({
|
|
569
553
|
filepath,
|
|
570
554
|
activeConversationId: conversationId ?? null,
|
|
571
555
|
invocation: fakeInvocation,
|
|
@@ -619,13 +603,13 @@ function ToolActivityRollup({ detailParts, onNavigateResource, renderToolInvocat
|
|
|
619
603
|
const summary = activeInvocation
|
|
620
604
|
? formatActiveToolSummary(activeInvocation.toolName, activeInvocation.args)
|
|
621
605
|
: `Worked across ${toolParts.length} tool${toolParts.length === 1 ? "" : "s"}${failedCount > 0 ? ` · ${failedCount} failed` : ""}`;
|
|
622
|
-
return (_jsxs("div", { className: "space-y-1", children: [_jsxs("button", { type: "button", onClick: () => setIsExpanded((prev) => !prev), className: "inline-flex items-center gap-1.5 text-[12px] leading-5 text-[var(--text-tertiary)] hover:text-[var(--text-secondary)] transition-colors", children: [_jsx("span", { className: cx("transition-transform", isExpanded && "rotate-90"), children: "\u203A" }), isWorking ? _jsx("span", { className: "inline-flex h-2 w-2 rounded-full bg-[var(--brand-accent)]" }) : null, _jsx("span", { className: cx("text-[var(--text-secondary)]", isWorking && "font-medium"), children: summary })] }), isExpanded ? (_jsx("div", { className: "pl-4 border-l border-[var(--border-default)] space-y-1.5", children: detailParts.map((part) => {
|
|
606
|
+
return (_jsxs("div", { className: "lemma-assistant-tool-rollup space-y-1", children: [_jsxs("button", { type: "button", onClick: () => setIsExpanded((prev) => !prev), className: "lemma-assistant-tool-rollup-toggle inline-flex items-center gap-1.5 text-[12px] leading-5 text-[var(--text-tertiary)] hover:text-[var(--text-secondary)] transition-colors", children: [_jsx("span", { className: cx("transition-transform", isExpanded && "rotate-90"), children: "\u203A" }), isWorking ? _jsx("span", { className: "inline-flex h-2 w-2 rounded-full bg-[var(--brand-accent)]" }) : null, _jsx("span", { className: cx("text-[var(--text-secondary)]", isWorking && "font-medium"), children: summary })] }), isExpanded ? (_jsx("div", { className: "lemma-assistant-tool-rollup-details pl-4 border-l border-[var(--border-default)] space-y-1.5", children: detailParts.map((part) => {
|
|
623
607
|
if (part.type === "reasoning") {
|
|
624
|
-
return (_jsxs("div", { className: "rounded-md bg-[var(--bg-canvas)] px-2.5 py-2", children: [_jsx("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-[0.1em] text-[var(--text-tertiary)]", children: part.state === "streaming" ? "Thinking" : "Thought" }), _jsx("pre", { className: "text-[11px] leading-5 text-[var(--text-secondary)] whitespace-pre-wrap font-mono max-h-40 overflow-auto", children: part.text })] }, `thinking-${part.id}`));
|
|
608
|
+
return (_jsxs("div", { className: "lemma-assistant-tool-rollup-thinking rounded-md bg-[var(--bg-canvas)] px-2.5 py-2", children: [_jsx("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-[0.1em] text-[var(--text-tertiary)]", children: part.state === "streaming" ? "Thinking" : "Thought" }), _jsx("pre", { className: "text-[11px] leading-5 text-[var(--text-secondary)] whitespace-pre-wrap font-mono max-h-40 overflow-auto", children: part.text })] }, `thinking-${part.id}`));
|
|
625
609
|
}
|
|
626
610
|
const invocation = part.toolInvocation;
|
|
627
611
|
const isSelected = activeToolCallId === invocation.toolCallId;
|
|
628
|
-
return (_jsxs("div", { className: "space-y-1", children: [_jsx(InlineToolCall, { invocation: invocation, isSelected: isSelected, onClick: () => setActiveToolCallId((prev) => (prev === invocation.toolCallId ? null : invocation.toolCallId)) }), isSelected ? (_jsx(ToolDetailsPanel, { toolName: invocation.toolName, args: invocation.args, state: invocation.state, result: invocation.result, onNavigateResource: onNavigateResource, renderToolInvocation: renderToolInvocation, message: message, activeConversationId: activeConversationId })) : null] }, part.id));
|
|
612
|
+
return (_jsxs("div", { className: "lemma-assistant-tool-rollup-item space-y-1", children: [_jsx(InlineToolCall, { invocation: invocation, isSelected: isSelected, onClick: () => setActiveToolCallId((prev) => (prev === invocation.toolCallId ? null : invocation.toolCallId)) }), isSelected ? (_jsx(ToolDetailsPanel, { toolName: invocation.toolName, args: invocation.args, state: invocation.state, result: invocation.result, onNavigateResource: onNavigateResource, renderToolInvocation: renderToolInvocation, message: message, activeConversationId: activeConversationId })) : null] }, part.id));
|
|
629
613
|
}) })) : null] }));
|
|
630
614
|
}
|
|
631
615
|
function ShowWidgetToolCard({ invocation, onSendPrompt, }) {
|
|
@@ -665,9 +649,9 @@ function ShowWidgetToolCard({ invocation, onSendPrompt, }) {
|
|
|
665
649
|
window.removeEventListener("message", handleMessage);
|
|
666
650
|
};
|
|
667
651
|
}, [onSendPrompt]);
|
|
668
|
-
return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("div", { className: "text-[11px] font-semibold text-[var(--state-info)]", children: displayName }), _jsx("span", { className: cx("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-medium", isExecuting && "bg-[color:color-mix(in_srgb,_var(--state-info)_16%,_transparent)] text-[var(--state-info)]", isFailed && "bg-[color:color-mix(in_srgb,_var(--state-error)_12%,_transparent)] text-[var(--state-error)]", !isExecuting && !isFailed && "bg-[color:color-mix(in_srgb,_var(--state-success)_12%,_transparent)] text-[var(--state-success)]"), children: isExecuting ? "Rendering" : isFailed ? "Failed" : "Ready" })] }), isFailed ? (_jsx("p", { className: "text-[11px] text-[var(--state-error)]", children: typeof resultData.error === "string" && resultData.error.length > 0
|
|
652
|
+
return (_jsxs("div", { className: "lemma-assistant-widget-card space-y-2", children: [_jsxs("div", { className: "lemma-assistant-widget-card-header flex items-center justify-between gap-2", children: [_jsx("div", { className: "lemma-assistant-widget-card-title text-[11px] font-semibold text-[var(--state-info)]", children: displayName }), _jsx("span", { className: cx("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-medium", isExecuting && "bg-[color:color-mix(in_srgb,_var(--state-info)_16%,_transparent)] text-[var(--state-info)]", isFailed && "bg-[color:color-mix(in_srgb,_var(--state-error)_12%,_transparent)] text-[var(--state-error)]", !isExecuting && !isFailed && "bg-[color:color-mix(in_srgb,_var(--state-success)_12%,_transparent)] text-[var(--state-success)]"), children: isExecuting ? "Rendering" : isFailed ? "Failed" : "Ready" })] }), isFailed ? (_jsx("p", { className: "text-[11px] text-[var(--state-error)]", children: typeof resultData.error === "string" && resultData.error.length > 0
|
|
669
653
|
? resultData.error
|
|
670
|
-
: "Failed to render widget." })) : null, !isFailed && payload ? (_jsx("iframe", { ref: iframeRef, title: displayName, srcDoc: iframeDocument, sandbox: "allow-scripts allow-forms allow-popups allow-downloads", height: height, className: "w-full border-0 bg-transparent rounded-xl" })) : null, !isFailed && !payload ? (_jsx("p", { className: "text-[11px] text-[var(--text-secondary)]", children: "Widget output is missing `widget_code`." })) : null] }));
|
|
654
|
+
: "Failed to render widget." })) : null, !isFailed && payload ? (_jsx("iframe", { ref: iframeRef, title: displayName, srcDoc: iframeDocument, sandbox: "allow-scripts allow-forms allow-popups allow-downloads", height: height, className: "lemma-assistant-widget-card-frame w-full border-0 bg-transparent rounded-xl" })) : null, !isFailed && !payload ? (_jsx("p", { className: "text-[11px] text-[var(--text-secondary)]", children: "Widget output is missing `widget_code`." })) : null] }));
|
|
671
655
|
}
|
|
672
656
|
export function MessageGroup({ message, conversationId, onNavigateResource, onWidgetSendPrompt, isStreaming, showAssistantHeader, renderMessageContent, renderPresentedFile, renderToolInvocation, }) {
|
|
673
657
|
const orderedParts = message.parts && message.parts.length > 0
|
|
@@ -726,7 +710,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
|
|
|
726
710
|
.find((part) => part.type === "text" && part.text.trim().length > 0)
|
|
727
711
|
?.id;
|
|
728
712
|
if (message.role === "user") {
|
|
729
|
-
return (_jsx("div", { className: "flex justify-end", children: _jsx("div", { className: "max-w-[72ch] rounded-xl bg-[var(--brand-primary)] text-[var(--text-on-brand)] px-3.5 py-2.5", children: renderMessageContent({
|
|
713
|
+
return (_jsx("div", { className: "lemma-assistant-message lemma-assistant-message-user flex justify-end", children: _jsx("div", { className: "lemma-assistant-message-user-bubble max-w-[72ch] rounded-xl bg-[var(--brand-primary)] text-[var(--text-on-brand)] px-3.5 py-2.5", children: renderMessageContent({
|
|
730
714
|
message: {
|
|
731
715
|
...message,
|
|
732
716
|
content: message.content,
|
|
@@ -735,7 +719,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
|
|
|
735
719
|
},
|
|
736
720
|
}) }) }));
|
|
737
721
|
}
|
|
738
|
-
return (_jsxs("div", { className: "px-1 py-0.5 space-y-1.5 max-w-[78ch]", children: [showAssistantHeader ? (_jsxs("div", { className: "inline-flex items-center gap-1.5 text-[11px] text-[var(--text-tertiary)]", children: [_jsx("span", { className: "inline-block h-1.5 w-1.5 rounded-full bg-[color:color-mix(in_srgb,_var(--brand-primary)_40%,_transparent)]" }), "Lemma"] })) : null, _jsxs("div", { className: "space-y-2", children: [blocks.map((block) => {
|
|
722
|
+
return (_jsxs("div", { className: "lemma-assistant-message lemma-assistant-message-assistant px-1 py-0.5 space-y-1.5 max-w-[78ch]", children: [showAssistantHeader ? (_jsxs("div", { className: "lemma-assistant-message-header inline-flex items-center gap-1.5 text-[11px] text-[var(--text-tertiary)]", children: [_jsx("span", { className: "lemma-assistant-message-header-dot inline-block h-1.5 w-1.5 rounded-full bg-[color:color-mix(in_srgb,_var(--brand-primary)_40%,_transparent)]" }), "Lemma"] })) : null, _jsxs("div", { className: "lemma-assistant-message-body space-y-2", children: [blocks.map((block) => {
|
|
739
723
|
if (block.kind === "tools") {
|
|
740
724
|
if (foldReasoningIntoToolRollup && block.id !== firstToolsBlockId) {
|
|
741
725
|
return null;
|
|
@@ -753,7 +737,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
|
|
|
753
737
|
if (trimmedText.length === 0) {
|
|
754
738
|
return null;
|
|
755
739
|
}
|
|
756
|
-
return (_jsx("div", { className: "text-[13px] text-[var(--text-secondary)] leading-6", children: renderMessageContent({
|
|
740
|
+
return (_jsx("div", { className: "lemma-assistant-message-text text-[13px] text-[var(--text-secondary)] leading-6", children: renderMessageContent({
|
|
757
741
|
message: {
|
|
758
742
|
...message,
|
|
759
743
|
content: trimmedText + (isStreaming && part.id === lastTextPartId ? " ▍" : ""),
|
|
@@ -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("lemma-assistant-experience", "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: "lemma-assistant-experience-sidebar 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: "lemma-assistant-experience-sidebar-header border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: _jsxs("div", { className: "lemma-assistant-experience-sidebar-header-row flex items-center justify-between gap-3", children: [_jsxs("div", { className: "lemma-assistant-experience-sidebar-copy", children: [_jsx("div", { className: "lemma-assistant-experience-sidebar-title text-[13px] font-semibold text-[var(--text-primary)]", children: "Conversations" }), _jsxs("div", { className: "lemma-assistant-experience-sidebar-meta mt-1 text-[11px] text-[var(--text-tertiary)]", children: [controller.conversations.length, " total"] })] }), _jsx("button", { type: "button", onClick: controller.clearMessages, className: "lemma-assistant-experience-sidebar-new 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: "lemma-assistant-experience-sidebar-items 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("lemma-assistant-experience-sidebar-item", "w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
|
|
999
|
+
? "lemma-assistant-experience-sidebar-item-active 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: "lemma-assistant-experience-sidebar-item-title text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel({ conversation, isActive }) }), _jsx("div", { className: "lemma-assistant-experience-sidebar-item-status mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
|
|
1001
|
+
}) })] })) : null, _jsxs("div", { className: "lemma-assistant-experience-main flex h-full min-h-0 flex-col gap-3", children: [_jsxs("div", { className: "lemma-assistant-experience-card 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: "lemma-assistant-experience-header 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: "lemma-assistant-experience-header-copy flex items-center gap-2.5", children: [_jsx("div", { className: "lemma-assistant-experience-header-badge 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", { className: "lemma-assistant-experience-header-titles", children: [_jsx("h3", { className: "lemma-assistant-experience-header-title font-semibold text-[var(--text-primary)] text-[13px] leading-tight", children: title }), _jsx("p", { className: "lemma-assistant-experience-header-subtitle text-[11px] text-[var(--text-tertiary)]", children: subtitle })] })] }), _jsxs("div", { className: "lemma-assistant-experience-header-controls flex items-center gap-1", children: [_jsxs("select", { value: controller.conversationModel || "", onChange: (event) => { void handleModelChange(event.target.value || null); }, disabled: isConversationBusy || isUpdatingModel, className: "lemma-assistant-experience-model-picker 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: "lemma-assistant-experience-new 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: "lemma-assistant-experience-viewport 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: "lemma-assistant-experience-loading flex justify-center py-6", children: _jsx("span", { className: "lemma-assistant-experience-loading-text text-[var(--text-tertiary)] text-sm", children: "Loading\u2026" }) })) : null, (controller.isLoadingOlderMessages && controller.messages.length > 0) ? (_jsx("div", { className: "lemma-assistant-experience-loading-older flex justify-center py-1", children: _jsx("span", { className: "lemma-assistant-experience-loading-older-text 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: "lemma-assistant-experience-error 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: "lemma-assistant-experience-composer 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: "lemma-assistant-experience-plan 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: "lemma-assistant-experience-status px-2 pb-1", children: _jsx("div", { className: "lemma-assistant-experience-status-pill 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: "lemma-assistant-experience-composer-body space-y-1.5", children: [controller.pendingFiles.length > 0 ? (_jsx("div", { className: "lemma-assistant-experience-pending 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: "lemma-assistant-experience-input-row relative flex items-end gap-2", children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "lemma-assistant-experience-file-input hidden", onChange: (event) => { void handleUploadSelection(event.target.files); } }), _jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), disabled: isConversationBusy || controller.isUploadingFiles, className: cx("lemma-assistant-experience-upload", "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: "lemma-assistant-experience-textarea 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: "lemma-assistant-experience-send-wrap pb-1.5 pr-1.5", children: _jsx("button", { onClick: isConversationBusy ? controller.stop : () => { void handleSubmit(); }, disabled: !isConversationBusy && !draft.trim(), className: cx("lemma-assistant-experience-send", "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,8 +13,8 @@ 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,
|
|
17
|
-
export type { AssistantAskOverlayProps, AssistantComposerProps, AssistantConversationListProps, AssistantHeaderProps, AssistantMessageViewportProps, AssistantModelPickerProps, AssistantPendingFileChipProps, AssistantShellLayoutProps, AssistantStatusPillProps, } from "./components/AssistantChrome.js";
|
|
16
|
+
export { AssistantAskOverlay, AssistantComposer, AssistantConversationList, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantPendingFileChip, AssistantShellLayout, AssistantStatusPill, AssistantThemeScope, } from "./components/AssistantChrome.js";
|
|
17
|
+
export type { AssistantAskOverlayProps, AssistantComposerProps, AssistantConversationListProps, AssistantHeaderProps, AssistantMessageViewportProps, AssistantModelPickerProps, AssistantPendingFileChipProps, AssistantShellLayoutProps, AssistantStatusPillProps, AssistantThemeScopeProps, } 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";
|
|
20
20
|
export { AssistantEmbedded } from "./components/AssistantEmbedded.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, AssistantThemeScope, } 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";
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
.lemma-assistant-theme {
|
|
2
|
+
--bg-canvas: #f6f2ea;
|
|
3
|
+
--bg-surface: #fffdf9;
|
|
4
|
+
--bg-subtle: #f1ebde;
|
|
5
|
+
--border-default: #ddd2bb;
|
|
6
|
+
--border-subtle: #ebe2d0;
|
|
7
|
+
--text-primary: #241f16;
|
|
8
|
+
--text-secondary: #5c5344;
|
|
9
|
+
--text-tertiary: #8a7f6f;
|
|
10
|
+
--text-inverse: #fffdf9;
|
|
11
|
+
--text-on-brand: #fffdf9;
|
|
12
|
+
--brand-primary: #202418;
|
|
13
|
+
--brand-secondary: #6e8c56;
|
|
14
|
+
--brand-accent: #c78a2c;
|
|
15
|
+
--brand-glow: #efe3c7;
|
|
16
|
+
--state-success: #3e7a3c;
|
|
17
|
+
--state-error: #b44d36;
|
|
18
|
+
--state-info: #2f6fb2;
|
|
19
|
+
--state-warning: #c78a2c;
|
|
20
|
+
--shadow-xs: 0 1px 2px rgba(36, 31, 22, 0.08);
|
|
21
|
+
--shadow-sm: 0 8px 24px rgba(36, 31, 22, 0.08);
|
|
22
|
+
--shadow-md: 0 18px 36px rgba(36, 31, 22, 0.1);
|
|
23
|
+
--shadow-lg: 0 24px 48px rgba(36, 31, 22, 0.14);
|
|
24
|
+
color: var(--text-primary);
|
|
25
|
+
font-family:
|
|
26
|
+
"Inter",
|
|
27
|
+
"Segoe UI",
|
|
28
|
+
ui-sans-serif,
|
|
29
|
+
system-ui,
|
|
30
|
+
-apple-system,
|
|
31
|
+
BlinkMacSystemFont,
|
|
32
|
+
sans-serif;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.lemma-assistant-theme,
|
|
36
|
+
.lemma-assistant-theme * {
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.lemma-assistant-theme button,
|
|
41
|
+
.lemma-assistant-theme input,
|
|
42
|
+
.lemma-assistant-theme select,
|
|
43
|
+
.lemma-assistant-theme textarea {
|
|
44
|
+
font: inherit;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.lemma-assistant-theme a {
|
|
48
|
+
color: inherit;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.lemma-assistant-theme textarea::placeholder,
|
|
52
|
+
.lemma-assistant-theme input::placeholder {
|
|
53
|
+
color: var(--text-tertiary);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.lemma-assistant-shell,
|
|
57
|
+
.lemma-assistant-experience {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
gap: 12px;
|
|
61
|
+
width: 100%;
|
|
62
|
+
min-height: 0;
|
|
63
|
+
height: 100%;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.lemma-assistant-shell-main,
|
|
67
|
+
.lemma-assistant-experience-main {
|
|
68
|
+
min-width: 0;
|
|
69
|
+
min-height: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.lemma-assistant-shell-sidebar,
|
|
73
|
+
.lemma-assistant-experience-sidebar {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (min-width: 1024px) {
|
|
78
|
+
.lemma-assistant-shell:has(.lemma-assistant-shell-sidebar) {
|
|
79
|
+
display: grid;
|
|
80
|
+
grid-template-columns: 280px minmax(0, 1fr);
|
|
81
|
+
align-items: stretch;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.lemma-assistant-shell-sidebar,
|
|
85
|
+
.lemma-assistant-experience-sidebar {
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.lemma-assistant-experience:has(.lemma-assistant-experience-sidebar) {
|
|
91
|
+
display: grid;
|
|
92
|
+
grid-template-columns: 280px minmax(0, 1fr);
|
|
93
|
+
align-items: stretch;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.lemma-assistant-header,
|
|
98
|
+
.lemma-assistant-experience-header {
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: space-between;
|
|
102
|
+
gap: 12px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.lemma-assistant-header-copy,
|
|
106
|
+
.lemma-assistant-experience-header-copy {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 10px;
|
|
110
|
+
min-width: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.lemma-assistant-header-titles,
|
|
114
|
+
.lemma-assistant-experience-header-titles,
|
|
115
|
+
.lemma-assistant-conversation-list-copy,
|
|
116
|
+
.lemma-assistant-experience-sidebar-copy {
|
|
117
|
+
min-width: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.lemma-assistant-header-title,
|
|
121
|
+
.lemma-assistant-header-subtitle,
|
|
122
|
+
.lemma-assistant-experience-header-title,
|
|
123
|
+
.lemma-assistant-experience-header-subtitle {
|
|
124
|
+
margin: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.lemma-assistant-header-controls,
|
|
128
|
+
.lemma-assistant-experience-header-controls {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
gap: 6px;
|
|
132
|
+
flex-wrap: wrap;
|
|
133
|
+
justify-content: flex-end;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.lemma-assistant-conversation-list,
|
|
137
|
+
.lemma-assistant-experience-sidebar,
|
|
138
|
+
.lemma-assistant-experience-card,
|
|
139
|
+
.lemma-assistant-composer,
|
|
140
|
+
.lemma-assistant-experience-composer {
|
|
141
|
+
background: var(--bg-surface);
|
|
142
|
+
border: 1px solid var(--border-default);
|
|
143
|
+
border-radius: 20px;
|
|
144
|
+
box-shadow: var(--shadow-lg);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.lemma-assistant-conversation-list-header,
|
|
148
|
+
.lemma-assistant-experience-sidebar-header {
|
|
149
|
+
border-bottom: 1px solid var(--border-default);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.lemma-assistant-conversation-list-header-row,
|
|
153
|
+
.lemma-assistant-experience-sidebar-header-row {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
justify-content: space-between;
|
|
157
|
+
gap: 12px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.lemma-assistant-conversation-list-items,
|
|
161
|
+
.lemma-assistant-experience-sidebar-items {
|
|
162
|
+
flex: 1 1 auto;
|
|
163
|
+
min-height: 0;
|
|
164
|
+
overflow-y: auto;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.lemma-assistant-conversation-list-item,
|
|
168
|
+
.lemma-assistant-experience-sidebar-item {
|
|
169
|
+
display: block;
|
|
170
|
+
width: 100%;
|
|
171
|
+
border-radius: 16px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.lemma-assistant-conversation-list-item-title,
|
|
175
|
+
.lemma-assistant-experience-sidebar-item-title {
|
|
176
|
+
white-space: nowrap;
|
|
177
|
+
overflow: hidden;
|
|
178
|
+
text-overflow: ellipsis;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.lemma-assistant-model-picker,
|
|
182
|
+
.lemma-assistant-experience-model-picker {
|
|
183
|
+
appearance: none;
|
|
184
|
+
min-width: 132px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.lemma-assistant-viewport,
|
|
188
|
+
.lemma-assistant-experience-viewport {
|
|
189
|
+
overflow-y: auto;
|
|
190
|
+
min-height: 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.lemma-assistant-viewport-inner {
|
|
194
|
+
width: 100%;
|
|
195
|
+
max-width: 80rem;
|
|
196
|
+
margin: 0 auto;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.lemma-assistant-composer,
|
|
200
|
+
.lemma-assistant-experience-composer {
|
|
201
|
+
position: relative;
|
|
202
|
+
padding: 8px;
|
|
203
|
+
box-shadow: var(--shadow-md);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.lemma-assistant-composer-floating,
|
|
207
|
+
.lemma-assistant-experience-plan {
|
|
208
|
+
position: absolute;
|
|
209
|
+
left: 0;
|
|
210
|
+
right: 0;
|
|
211
|
+
bottom: calc(100% + 8px);
|
|
212
|
+
z-index: 20;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.lemma-assistant-composer-status-rail {
|
|
216
|
+
min-height: 34px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.lemma-assistant-composer-status,
|
|
220
|
+
.lemma-assistant-experience-status {
|
|
221
|
+
min-height: 26px;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.lemma-assistant-composer-pending,
|
|
225
|
+
.lemma-assistant-experience-pending {
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-wrap: wrap;
|
|
228
|
+
gap: 6px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.lemma-assistant-pending-file-chip {
|
|
232
|
+
display: inline-flex;
|
|
233
|
+
align-items: center;
|
|
234
|
+
gap: 6px;
|
|
235
|
+
max-width: 100%;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.lemma-assistant-pending-file-chip-label {
|
|
239
|
+
overflow: hidden;
|
|
240
|
+
text-overflow: ellipsis;
|
|
241
|
+
white-space: nowrap;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.lemma-assistant-pending-file-chip-remove {
|
|
245
|
+
border: 0;
|
|
246
|
+
background: transparent;
|
|
247
|
+
color: inherit;
|
|
248
|
+
cursor: pointer;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.lemma-assistant-status-pill {
|
|
252
|
+
display: inline-flex;
|
|
253
|
+
align-items: center;
|
|
254
|
+
gap: 8px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.lemma-assistant-status-pill-dot {
|
|
258
|
+
position: relative;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.lemma-assistant-status-pill-dot-ping {
|
|
262
|
+
animation: lemma-assistant-ping 1.4s ease-out infinite;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.lemma-assistant-ask-overlay-header,
|
|
266
|
+
.lemma-assistant-ask-overlay-actions,
|
|
267
|
+
.lemma-assistant-experience-input-row {
|
|
268
|
+
display: flex;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.lemma-assistant-ask-overlay-header {
|
|
272
|
+
align-items: flex-start;
|
|
273
|
+
justify-content: space-between;
|
|
274
|
+
gap: 12px;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.lemma-assistant-ask-overlay-options {
|
|
278
|
+
overflow-y: auto;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.lemma-assistant-ask-overlay-option {
|
|
282
|
+
display: block;
|
|
283
|
+
width: 100%;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.lemma-assistant-ask-overlay-option-label {
|
|
287
|
+
display: inline-flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
gap: 8px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.lemma-assistant-plan-strip-header,
|
|
293
|
+
.lemma-assistant-plan-strip-summary,
|
|
294
|
+
.lemma-assistant-thinking-label,
|
|
295
|
+
.lemma-assistant-widget-card-header,
|
|
296
|
+
.lemma-assistant-message-header,
|
|
297
|
+
.lemma-assistant-tool-rollup-toggle {
|
|
298
|
+
display: flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.lemma-assistant-plan-strip-header,
|
|
303
|
+
.lemma-assistant-widget-card-header {
|
|
304
|
+
justify-content: space-between;
|
|
305
|
+
gap: 8px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.lemma-assistant-plan-strip-steps,
|
|
309
|
+
.lemma-assistant-message-body,
|
|
310
|
+
.lemma-assistant-presented-files,
|
|
311
|
+
.lemma-assistant-tool-rollup,
|
|
312
|
+
.lemma-assistant-tool-rollup-details,
|
|
313
|
+
.lemma-assistant-widget-card,
|
|
314
|
+
.lemma-assistant-reasoning,
|
|
315
|
+
.lemma-assistant-empty-state {
|
|
316
|
+
min-width: 0;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.lemma-assistant-message {
|
|
320
|
+
max-width: 78ch;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.lemma-assistant-message-user {
|
|
324
|
+
display: flex;
|
|
325
|
+
justify-content: flex-end;
|
|
326
|
+
max-width: none;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.lemma-assistant-message-user-bubble {
|
|
330
|
+
max-width: 72ch;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.lemma-assistant-message-text {
|
|
334
|
+
line-height: 1.65;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.lemma-assistant-tool-rollup-toggle,
|
|
338
|
+
.lemma-assistant-message-header,
|
|
339
|
+
.lemma-assistant-thinking-label,
|
|
340
|
+
.lemma-assistant-reasoning-summary {
|
|
341
|
+
gap: 6px;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.lemma-assistant-tool-rollup-details,
|
|
345
|
+
.lemma-assistant-reasoning-body {
|
|
346
|
+
border-left: 1px solid var(--border-default);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.lemma-assistant-tool-rollup-thinking,
|
|
350
|
+
.lemma-assistant-widget-card-frame,
|
|
351
|
+
.lemma-assistant-presented-file > *:first-child {
|
|
352
|
+
border-radius: 12px;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.lemma-assistant-widget-card-frame {
|
|
356
|
+
width: 100%;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.lemma-assistant-empty-state {
|
|
360
|
+
padding: 20px 8px;
|
|
361
|
+
text-align: center;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.lemma-assistant-empty-state-hero {
|
|
365
|
+
display: flex;
|
|
366
|
+
flex-direction: column;
|
|
367
|
+
align-items: center;
|
|
368
|
+
justify-content: center;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.lemma-assistant-empty-state-suggestions {
|
|
372
|
+
display: grid;
|
|
373
|
+
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
374
|
+
gap: 10px;
|
|
375
|
+
max-width: 500px;
|
|
376
|
+
margin: 0 auto;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
@media (min-width: 640px) {
|
|
380
|
+
.lemma-assistant-empty-state-suggestions {
|
|
381
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.lemma-assistant-empty-state-suggestion {
|
|
386
|
+
display: flex;
|
|
387
|
+
align-items: center;
|
|
388
|
+
gap: 10px;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.lemma-assistant-experience-main {
|
|
392
|
+
display: flex;
|
|
393
|
+
flex-direction: column;
|
|
394
|
+
gap: 12px;
|
|
395
|
+
height: 100%;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.lemma-assistant-experience-card {
|
|
399
|
+
display: flex;
|
|
400
|
+
flex: 1 1 auto;
|
|
401
|
+
flex-direction: column;
|
|
402
|
+
min-height: 0;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.lemma-assistant-experience-composer-body,
|
|
406
|
+
.lemma-assistant-composer-body {
|
|
407
|
+
min-width: 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.lemma-assistant-experience-input-row {
|
|
411
|
+
align-items: flex-end;
|
|
412
|
+
gap: 8px;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.lemma-assistant-experience-textarea {
|
|
416
|
+
width: 100%;
|
|
417
|
+
resize: none;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.lemma-assistant-experience-upload,
|
|
421
|
+
.lemma-assistant-experience-send,
|
|
422
|
+
.lemma-assistant-experience-new,
|
|
423
|
+
.lemma-assistant-conversation-list-new {
|
|
424
|
+
cursor: pointer;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.lemma-assistant-experience-upload:disabled,
|
|
428
|
+
.lemma-assistant-experience-send:disabled,
|
|
429
|
+
.lemma-assistant-model-picker:disabled {
|
|
430
|
+
cursor: default;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
@keyframes lemma-assistant-ping {
|
|
434
|
+
0% {
|
|
435
|
+
opacity: 0.55;
|
|
436
|
+
transform: scale(0.8);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
70% {
|
|
440
|
+
opacity: 0;
|
|
441
|
+
transform: scale(1.8);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
100% {
|
|
445
|
+
opacity: 0;
|
|
446
|
+
transform: scale(1.8);
|
|
447
|
+
}
|
|
448
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lemma-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15",
|
|
4
4
|
"description": "Official TypeScript SDK for Lemma pod-scoped APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"types": "./dist/react/index.d.ts",
|
|
30
30
|
"default": "./dist/react/index.js"
|
|
31
31
|
},
|
|
32
|
+
"./react/styles.css": "./dist/react/styles.css",
|
|
32
33
|
"./browser-bundle": "./dist/browser/lemma-client.js"
|
|
33
34
|
},
|
|
34
35
|
"unpkg": "dist/browser/lemma-client.js",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
],
|
|
38
39
|
"scripts": {
|
|
39
40
|
"generate:client": "./scripts/generate_openapi_client.sh",
|
|
40
|
-
"build": "npm run clean && tsc -p tsconfig.json && npm run build:bundle",
|
|
41
|
+
"build": "npm run clean && tsc -p tsconfig.json && node ./scripts/copy_react_styles.mjs && npm run build:bundle",
|
|
41
42
|
"build:bundle": "tsc -p tsconfig.bundle.json && node ./scripts/build_browser_bundle.mjs",
|
|
42
43
|
"clean": "rm -rf dist",
|
|
43
44
|
"prepublishOnly": "npm run build",
|