lemma-sdk 0.2.14 → 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 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: "support_assistant",
199
+ assistantId: "uuid",
191
200
  podId: "pod_123",
192
201
  });
193
202
 
@@ -234,19 +243,21 @@ Useful UI primitives exported from `lemma-sdk/react`:
234
243
  - `AssistantAskOverlay`
235
244
  - `AssistantPendingFileChip`
236
245
  - `AssistantStatusPill`
246
+ - `AssistantThemeScope`
237
247
  - `MessageGroup`
238
248
  - `PlanSummaryStrip`
239
249
 
240
250
  For a direct plug-and-play component, `AssistantEmbedded` wires `useAssistantController` into the default assistant experience:
241
251
 
242
252
  ```tsx
253
+ import "lemma-sdk/react/styles.css";
243
254
  import { AssistantEmbedded } from "lemma-sdk/react";
244
255
 
245
256
  function SupportAssistant() {
246
257
  return (
247
258
  <AssistantEmbedded
248
259
  client={client}
249
- assistantId="support_assistant"
260
+ assistantId="uuid"
250
261
  podId="pod_123"
251
262
  title="Support Assistant"
252
263
  subtitle="Ask questions about this pod."
@@ -257,6 +268,39 @@ function SupportAssistant() {
257
268
  }
258
269
  ```
259
270
 
271
+ If you are composing your own shell with the SDK primitives, wrap it in `AssistantThemeScope` unless your app already provides matching theme tokens:
272
+
273
+ ```tsx
274
+ import "lemma-sdk/react/styles.css";
275
+ import {
276
+ AssistantComposer,
277
+ AssistantHeader,
278
+ AssistantMessageViewport,
279
+ AssistantShellLayout,
280
+ AssistantThemeScope,
281
+ } from "lemma-sdk/react";
282
+
283
+ function CustomAssistantShell() {
284
+ return (
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
+ }
298
+ />
299
+ </AssistantThemeScope>
300
+ );
301
+ }
302
+ ```
303
+
260
304
  ### Assistant names (resource key)
261
305
 
262
306
  Assistant CRUD is name-based:
@@ -1,5 +1,9 @@
1
1
  import { type ComponentPropsWithoutRef, type ReactNode } from "react";
2
2
  import type { AssistantConversationListItem, AssistantConversationRenderArgs } from "./assistant-types.js";
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;
3
7
  export interface AssistantHeaderProps {
4
8
  title: ReactNode;
5
9
  subtitle?: ReactNode;
@@ -3,52 +3,55 @@ import { forwardRef } from "react";
3
3
  function cx(...values) {
4
4
  return values.filter(Boolean).join(" ");
5
5
  }
6
+ export function AssistantThemeScope({ className, children, ...props }) {
7
+ return (_jsx("div", { className: cx("lemma-assistant-theme", className), ...props, children: children }));
8
+ }
6
9
  export const AssistantMessageViewport = forwardRef(function AssistantMessageViewport({ className, innerClassName, children, ...props }, ref) {
7
- return (_jsx("div", { ref: ref, className: cx("min-h-0 flex-1 overflow-y-auto bg-[var(--bg-surface)] px-4 py-4", className), ...props, children: _jsx("div", { className: cx("mx-auto flex w-full max-w-5xl flex-col gap-3", innerClassName), children: children }) }));
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 }) }));
8
11
  });
9
12
  export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, className, }) {
10
- return (_jsxs("div", { className: cx("mx-auto flex h-full w-full min-h-0 flex-col gap-3 font-sans antialiased", !!sidebar && sidebarVisible && "lg:grid lg:grid-cols-[280px_minmax(0,1fr)] lg:gap-3", className), children: [sidebar && sidebarVisible ? (_jsx("div", { className: "hidden h-full min-h-0 lg:block", children: sidebar })) : null, main] }));
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 })] }));
11
14
  }
12
15
  export function AssistantHeader({ title, subtitle, badge, controls, className, }) {
13
- return (_jsxs("div", { className: cx("flex items-center justify-between border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", className), children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [badge ? (_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] shadow-[var(--shadow-xs)]", children: badge })) : null, _jsxs("div", { children: [_jsx("h3", { className: "text-[13px] font-semibold leading-tight text-[var(--text-primary)]", children: title }), subtitle ? (_jsx("p", { className: "text-[11px] text-[var(--text-tertiary)]", children: subtitle })) : null] })] }), controls ? (_jsx("div", { className: "flex items-center gap-1", children: controls })) : null] }));
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] }));
14
17
  }
15
18
  export function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title = "Conversations", newLabel = "New", className, }) {
16
- return (_jsxs("aside", { className: cx("flex h-full min-h-0 flex-col overflow-hidden rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] shadow-[var(--shadow-lg)]", className), children: [_jsx("div", { className: "border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[13px] font-semibold text-[var(--text-primary)]", children: title }), _jsxs("div", { className: "mt-1 text-[11px] text-[var(--text-tertiary)]", children: [conversations.length, " total"] })] }), onNewConversation ? (_jsx("button", { type: "button", onClick: onNewConversation, className: "rounded-full border border-[var(--border-default)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]", children: newLabel })) : null] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-3 space-y-2", children: conversations.map((conversation) => {
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) => {
17
20
  const isActive = conversation.id === activeConversationId;
18
- return (_jsxs("button", { type: "button", onClick: () => onSelectConversation(conversation.id), className: cx("w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
19
- ? "border-[color:color-mix(in_srgb,_var(--brand-primary)_44%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_42%,_var(--bg-surface))]"
20
- : "border-[var(--border-default)] bg-[var(--bg-surface)] hover:bg-[var(--bg-subtle)]"), children: [_jsx("div", { className: "truncate text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel
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
21
24
  ? renderConversationLabel({ conversation, isActive })
22
- : (conversation.title || "Untitled conversation") }), _jsx("div", { className: "mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
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));
23
26
  }) })] }));
24
27
  }
25
28
  export function AssistantModelPicker({ value, options, disabled, autoLabel = "Auto", getOptionLabel, onChange, className, }) {
26
29
  const autoValue = "__AUTO__";
27
- return (_jsxs("select", { value: value ?? autoValue, onChange: (event) => onChange(event.target.value === autoValue ? null : event.target.value), disabled: disabled, className: cx("h-8 rounded-full border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] px-3 text-[11px] text-[var(--text-secondary)]", className), "aria-label": "Conversation model", title: "Conversation model", children: [_jsx("option", { value: autoValue, children: autoLabel }), options.map((option) => (_jsx("option", { value: option, children: getOptionLabel ? getOptionLabel(option) : option }, option)))] }));
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)))] }));
28
31
  }
29
32
  export function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode = "single_select", }) {
30
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "text-[11px] uppercase tracking-[0.12em] text-[var(--text-tertiary)]", children: ["Question ", questionNumber, " of ", totalQuestions] }), _jsx("p", { className: "mt-1 text-[14px] font-medium leading-6 text-[var(--text-primary)]", children: question })] }), onSkip ? (_jsx("button", { type: "button", onClick: onSkip, className: "rounded-md px-2 py-1 text-[12px] text-[var(--text-tertiary)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text-primary)]", children: "Skip" })) : null] }), _jsx("div", { className: "max-h-[260px] space-y-1.5 overflow-y-auto pr-1", children: options.map((option, optionIndex) => {
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) => {
31
34
  const isSelected = selectedOptions.includes(option);
32
35
  const rankLabel = mode === "rank_priorities" && isSelected
33
36
  ? selectedOptions.indexOf(option) + 1
34
37
  : null;
35
- 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
36
- ? "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)]"
37
- : "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
38
41
  ? "border-[var(--brand-primary)] bg-[var(--brand-primary)]"
39
42
  : "border-[var(--border-default)] bg-transparent") })), option] }) }, `${option}-${optionIndex}`));
40
- }) }), 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
41
44
  ? "bg-[var(--brand-primary)] text-[var(--text-on-brand)] hover:bg-[color:color-mix(in_srgb,_var(--brand-primary)_88%,_var(--text-primary))]"
42
45
  : "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), children: continueLabel }) })) : null] }));
43
46
  }
44
47
  export function AssistantComposer({ floating, status, pendingFiles, children, className, }) {
45
- return (_jsxs("div", { className: cx("relative rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] p-2 shadow-[var(--shadow-md)]", className), children: [floating ? (_jsx("div", { className: "absolute bottom-[calc(100%+8px)] left-0 right-0 z-20", children: floating })) : null, _jsx("div", { className: "min-h-[34px] px-2 pb-1", children: _jsx("div", { className: "flex min-h-[26px] items-center transition-opacity duration-200", children: status || _jsx("span", { "aria-hidden": "true", className: "inline-block h-[30px]" }) }) }), pendingFiles ? (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-1 pb-1.5", children: pendingFiles })) : null, children] }));
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 })] }));
46
49
  }
47
50
  export function AssistantPendingFileChip({ label, onRemove, className, }) {
48
- return (_jsxs("span", { className: cx("inline-flex max-w-full items-center gap-1.5 rounded-full bg-[var(--bg-subtle)] px-2 py-1 text-[11px] text-[var(--text-secondary)]", className), children: [_jsx("span", { className: "truncate max-w-[180px]", children: label }), onRemove ? (_jsx("button", { type: "button", onClick: onRemove, className: "inline-flex h-4 w-4 items-center justify-center rounded-full hover:bg-[var(--bg-canvas)]", title: "Remove file", children: "\u00D7" })) : null] }));
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] }));
49
52
  }
50
53
  export function AssistantStatusPill({ label, subtle = false, className, }) {
51
- return (_jsxs("div", { className: cx("inline-flex min-h-[30px] max-w-full items-center gap-2 rounded-full px-3 py-1.5 text-[12px] transition-all duration-200", subtle
52
- ? "border border-[color:color-mix(in_srgb,_var(--border-default)_72%,_transparent)] bg-[color:color-mix(in_srgb,_var(--bg-surface)_90%,_transparent)] text-[var(--text-tertiary)]"
53
- : "border border-[color:color-mix(in_srgb,_var(--brand-primary)_24%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_28%,_var(--bg-surface))] text-[var(--text-secondary)]", className), children: [_jsxs("span", { className: "relative inline-flex h-2.5 w-2.5 shrink-0", children: [_jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--brand-primary)]/45" }), _jsx("span", { className: "relative inline-flex h-2.5 w-2.5 rounded-full bg-[var(--brand-primary)]" })] }), _jsx("span", { className: "truncate", children: label })] }));
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 })] }));
54
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
  }
@@ -513,7 +513,7 @@ 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,7 +523,7 @@ 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 = [
@@ -532,10 +532,10 @@ export function EmptyState({ onSendMessage }) {
532
532
  { text: "Create a full React desk page for an executive dashboard", icon: "🧩" },
533
533
  { text: "Create a flow to process emails", icon: "⚡" },
534
534
  ];
535
- return (_jsxs("div", { className: "text-center py-5 px-2", children: [_jsxs("div", { className: "flex flex-col items-center justify-center mb-6", children: [_jsx("div", { className: "mb-3 flex h-10 w-10 items-center justify-center rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] shadow-[var(--shadow-xs)]", children: _jsx("span", { className: "text-[var(--text-on-brand)] text-lg", children: "\u2728" }) }), _jsx("h4", { className: "font-semibold text-[var(--text-primary)] text-[15px]", children: "What can I help you build?" }), _jsx("p", { className: "text-[13px] text-[var(--text-tertiary)] mt-1.5 max-w-sm leading-relaxed", children: "I can create agents, set up data stores, build pages, and automate workflows for your pod." })] }), _jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2.5 max-w-[500px] mx-auto", children: suggestions.map((suggestion, index) => (_jsxs("button", { onClick: () => onSendMessage(suggestion.text), className: "text-left px-3 py-2.5 rounded-lg border border-[var(--border-default)] bg-[var(--bg-surface)] text-xs text-[var(--text-secondary)] hover:border-[color:color-mix(in_srgb,_var(--brand-accent)_52%,_var(--border-subtle))] hover:bg-[color:color-mix(in_srgb,_var(--brand-glow)_72%,_var(--bg-surface))] hover:text-[var(--text-primary)] transition-all duration-200 flex items-center gap-2.5 group", children: [_jsx("span", { className: "text-base opacity-70 group-hover:opacity-100 transition-opacity", children: suggestion.icon }), _jsx("span", { className: "flex-1 leading-snug", children: suggestion.text }), _jsx("span", { className: "text-[var(--text-tertiary)] group-hover:text-[var(--state-warning)] group-hover:translate-x-0.5 transition-all opacity-0 group-hover:opacity-100", children: "\u203A" })] }, `${suggestion.text}-${index}`))) })] }));
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}`))) })] }));
536
536
  }
537
537
  function ReasoningPartCard({ text, isStreaming, durationMs, }) {
538
- return (_jsxs("details", { className: "group", open: isStreaming, children: [_jsxs("summary", { className: "list-none cursor-pointer inline-flex items-center gap-1.5 text-[12px] leading-5 text-[var(--text-tertiary)]", children: [_jsx("span", { className: "transition-transform group-open:rotate-90", children: "\u203A" }), _jsx("span", { className: cx("font-semibold", isStreaming && "text-transparent bg-clip-text bg-[linear-gradient(110deg,var(--text-secondary),35%,var(--brand-accent),50%,var(--text-secondary),65%)] bg-[length:250%_100%] animate-pulse"), children: isStreaming ? "Thinking" : `Thought${durationMs ? ` · ${Math.max(1, Math.round(durationMs / 1000))}s` : ""}` })] }), _jsx("div", { className: "mt-1 pl-4 border-l border-[var(--border-default)]", children: _jsx("pre", { className: "text-[11px] leading-5 text-[var(--text-tertiary)] whitespace-pre-wrap font-mono", children: text }) })] }));
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 }) })] }));
539
539
  }
540
540
  function PresentFilesCard({ filepaths, conversationId, renderPresentedFile, }) {
541
541
  const fakeMessage = {
@@ -549,7 +549,7 @@ function PresentFilesCard({ filepaths, conversationId, renderPresentedFile, }) {
549
549
  args: { filepaths },
550
550
  state: "result",
551
551
  };
552
- 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)({
553
553
  filepath,
554
554
  activeConversationId: conversationId ?? null,
555
555
  invocation: fakeInvocation,
@@ -603,13 +603,13 @@ function ToolActivityRollup({ detailParts, onNavigateResource, renderToolInvocat
603
603
  const summary = activeInvocation
604
604
  ? formatActiveToolSummary(activeInvocation.toolName, activeInvocation.args)
605
605
  : `Worked across ${toolParts.length} tool${toolParts.length === 1 ? "" : "s"}${failedCount > 0 ? ` · ${failedCount} failed` : ""}`;
606
- 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) => {
607
607
  if (part.type === "reasoning") {
608
- 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}`));
609
609
  }
610
610
  const invocation = part.toolInvocation;
611
611
  const isSelected = activeToolCallId === invocation.toolCallId;
612
- 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));
613
613
  }) })) : null] }));
614
614
  }
615
615
  function ShowWidgetToolCard({ invocation, onSendPrompt, }) {
@@ -649,9 +649,9 @@ function ShowWidgetToolCard({ invocation, onSendPrompt, }) {
649
649
  window.removeEventListener("message", handleMessage);
650
650
  };
651
651
  }, [onSendPrompt]);
652
- 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
653
653
  ? resultData.error
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: "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] }));
655
655
  }
656
656
  export function MessageGroup({ message, conversationId, onNavigateResource, onWidgetSendPrompt, isStreaming, showAssistantHeader, renderMessageContent, renderPresentedFile, renderToolInvocation, }) {
657
657
  const orderedParts = message.parts && message.parts.length > 0
@@ -710,7 +710,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
710
710
  .find((part) => part.type === "text" && part.text.trim().length > 0)
711
711
  ?.id;
712
712
  if (message.role === "user") {
713
- 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({
714
714
  message: {
715
715
  ...message,
716
716
  content: message.content,
@@ -719,7 +719,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
719
719
  },
720
720
  }) }) }));
721
721
  }
722
- 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) => {
723
723
  if (block.kind === "tools") {
724
724
  if (foldReasoningIntoToolRollup && block.id !== firstToolsBlockId) {
725
725
  return null;
@@ -737,7 +737,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
737
737
  if (trimmedText.length === 0) {
738
738
  return null;
739
739
  }
740
- 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({
741
741
  message: {
742
742
  ...message,
743
743
  content: trimmedText + (isStreaming && part.id === lastTextPartId ? " ▍" : ""),
@@ -993,27 +993,27 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
993
993
  ? effectiveAskOverlayState.answers[effectiveAskOverlayState.currentQuestionIndex] || []
994
994
  : [];
995
995
  const canContinueAsk = activeAskAnswers.length > 0;
996
- return (_jsxs("div", { className: cx("flex h-full min-h-0 flex-col gap-3 font-sans antialiased", showConversationList && "lg:grid lg:grid-cols-[280px_minmax(0,1fr)] lg:gap-3"), children: [showConversationList ? (_jsxs("aside", { className: "hidden min-h-0 overflow-hidden rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] shadow-[var(--shadow-lg)] lg:flex lg:flex-col", children: [_jsx("div", { className: "border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[13px] font-semibold text-[var(--text-primary)]", children: "Conversations" }), _jsxs("div", { className: "mt-1 text-[11px] text-[var(--text-tertiary)]", children: [controller.conversations.length, " total"] })] }), _jsx("button", { type: "button", onClick: controller.clearMessages, className: "rounded-full border border-[var(--border-default)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)]", children: "New" })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-3 space-y-2", children: controller.conversations.map((conversation) => {
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
997
  const isActive = conversation.id === controller.activeConversationId;
998
- return (_jsxs("button", { type: "button", onClick: () => controller.selectConversation(conversation.id), className: cx("w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
999
- ? "border-[color:color-mix(in_srgb,_var(--brand-primary)_44%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_42%,_var(--bg-surface))]"
1000
- : "border-[var(--border-default)] bg-[var(--bg-surface)] hover:bg-[var(--bg-subtle)]"), children: [_jsx("div", { className: "text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel({ conversation, isActive }) }), _jsx("div", { className: "mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
1001
- }) })] })) : null, _jsxs("div", { className: "flex h-full min-h-0 flex-col gap-3", children: [_jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] shadow-[var(--shadow-lg)]", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [_jsx("div", { className: "h-7 w-7 rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] flex items-center justify-center shadow-[var(--shadow-xs)]", children: _jsx("span", { className: "text-[var(--text-on-brand)] text-xs", children: "\u2728" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-[var(--text-primary)] text-[13px] leading-tight", children: title }), _jsx("p", { className: "text-[11px] text-[var(--text-tertiary)]", children: subtitle })] })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs("select", { value: controller.conversationModel || "", onChange: (event) => { void handleModelChange(event.target.value || null); }, disabled: isConversationBusy || isUpdatingModel, className: "h-8 rounded-full border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] px-3 text-[11px] text-[var(--text-secondary)]", children: [_jsx("option", { value: "", children: "Auto" }), availableModels.map((availableModel) => (_jsx("option", { value: availableModel, children: availableModel }, availableModel)))] }), _jsx("button", { type: "button", onClick: controller.clearMessages, title: "New conversation", className: "inline-flex h-8 w-8 items-center justify-center rounded-full text-[var(--text-tertiary)] hover:bg-[var(--bg-subtle)] hover:text-[var(--text-secondary)]", children: "\u21BA" })] })] }), _jsxs(AssistantMessageViewport, { className: "min-h-[180px]", ref: messagesContainerRef, onScroll: updatePinnedState, children: [controller.messages.length === 0 && !isConversationBusy ? (emptyState || _jsx(EmptyState, { onSendMessage: (message) => { void controller.sendMessage(message); } })) : null, (controller.isLoadingMessages && controller.messages.length === 0) ? (_jsx("div", { className: "flex justify-center py-6", children: _jsx("span", { className: "text-[var(--text-tertiary)] text-sm", children: "Loading\u2026" }) })) : null, (controller.isLoadingOlderMessages && controller.messages.length > 0) ? (_jsx("div", { className: "flex justify-center py-1", children: _jsx("span", { className: "text-[var(--text-tertiary)] text-xs", children: "Loading older\u2026" }) })) : null, displayMessageRows.map((row, index) => {
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) => {
1002
1002
  const previousRow = index > 0 ? displayMessageRows[index - 1] : null;
1003
1003
  const showAssistantHeader = row.message.role !== "assistant"
1004
1004
  ? false
1005
1005
  : previousRow?.message.role !== "assistant";
1006
1006
  const includesLastRawMessage = row.sourceIndexes.includes(controller.messages.length - 1);
1007
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));
1008
- }), isConversationBusy && controller.messages.length > 0 && !activeToolBanner && !lastMessageHasContent ? (_jsx(ThinkingIndicator, {})) : null, controller.error ? (_jsx("div", { className: "bg-[color:color-mix(in_srgb,_var(--state-error)_12%,_transparent)] border border-[color:color-mix(in_srgb,_var(--state-error)_48%,_var(--border-subtle))] rounded-lg p-3 text-xs text-[var(--state-error)] flex items-start gap-2.5", children: _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Something went wrong" }), _jsx("p", { className: "text-[var(--state-error)] mt-1", children: controller.error })] }) })) : null, (controller.messages.length > 0 || isConversationBusy || !!controller.error) ? (_jsx("div", { "aria-hidden": "true", className: "h-14 shrink-0" })) : null] })] }), _jsxs("div", { className: "relative rounded-2xl border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] p-2 shadow-[var(--shadow-md)]", children: [planSummary ? (_jsx("div", { className: "absolute bottom-[calc(100%+8px)] left-0 right-0 z-20", children: isPlanHidden ? (_jsxs("button", { type: "button", onClick: () => setIsPlanHidden(false), className: "inline-flex items-center gap-2 rounded-lg border border-[var(--border-default)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-subtle)] transition-colors", children: ["Show plan (", planSummary.completedCount, "/", planSummary.steps.length, ")"] })) : (_jsx(PlanSummaryStrip, { plan: planSummary, onHide: () => setIsPlanHidden(true) })) })) : null, isConversationBusy && activeToolBanner ? (_jsx("div", { className: "px-2 pb-1", children: _jsx("div", { className: "inline-flex max-w-full items-center gap-1.5 text-[11px] text-[var(--text-tertiary)] animate-in fade-in duration-200", children: _jsx("span", { className: "truncate", children: activeToolBanner.summary }) }) })) : null, activeAskQuestion && effectiveAskOverlayState && pendingAskUserInput ? (_jsx(AssistantAskOverlay, { questionNumber: effectiveAskOverlayState.currentQuestionIndex + 1, totalQuestions: pendingAskUserInput.questions.length, question: activeAskQuestion.question, options: activeAskQuestion.options, selectedOptions: activeAskAnswers, canContinue: canContinueAsk, continueLabel: effectiveAskOverlayState.currentQuestionIndex >= pendingAskUserInput.questions.length - 1 ? "Use answers" : "Continue", onSelectOption: updateAskAnswer, onContinue: activeAskQuestion.type !== "single_select" || pendingAskUserInput.questions.length > 1 ? continueAskQuestions : undefined, onSkip: () => dismissAskOverlay(effectiveAskOverlayState.toolCallId), mode: activeAskQuestion.type })) : (_jsxs("div", { className: "space-y-1.5", children: [controller.pendingFiles.length > 0 ? (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-1", children: controller.pendingFiles.map((file) => {
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
1009
  const fileKey = `${file.name}:${file.size}:${file.lastModified}`;
1010
1010
  return (_jsx("div", { children: renderPendingFile({
1011
1011
  file,
1012
1012
  remove: () => controller.removePendingFile(fileKey),
1013
1013
  }) }, fileKey));
1014
- }) })) : null, _jsxs("div", { className: "relative flex items-end gap-2", children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "hidden", onChange: (event) => { void handleUploadSelection(event.target.files); } }), _jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), disabled: isConversationBusy || controller.isUploadingFiles, className: cx("mb-1.5 ml-1 h-9 w-9 rounded-full flex items-center justify-center transition-colors", isConversationBusy || controller.isUploadingFiles
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
1015
  ? "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"
1016
- : "bg-[var(--bg-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-canvas)] hover:text-[var(--text-primary)]"), title: "Upload files", children: controller.isUploadingFiles ? "…" : "+" }), _jsx("textarea", { ref: inputRef, value: draft, onChange: (event) => setDraft(event.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, className: "flex-1 resize-none border-0 bg-transparent px-3 py-2.5 text-[14px] text-[var(--text-primary)] leading-6 focus:ring-0 focus:outline-none placeholder:text-[var(--text-tertiary)] min-h-[48px] max-h-[220px]", rows: 1, disabled: isConversationBusy }), _jsx("div", { className: "pb-1.5 pr-1.5", children: _jsx("button", { onClick: isConversationBusy ? controller.stop : () => { void handleSubmit(); }, disabled: !isConversationBusy && !draft.trim(), className: cx("h-9 w-9 rounded-full flex items-center justify-center transition-all duration-200", isConversationBusy
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
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
1018
  : draft.trim()
1019
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))]"
@@ -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, } from "./components/AssistantChrome.js";
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";
@@ -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, } from "./components/AssistantChrome.js";
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.14",
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",