lemma-sdk 0.2.17 → 0.2.19

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
@@ -169,85 +169,86 @@ Notes:
169
169
 
170
170
  ## Assistants + Agent Runs
171
171
 
172
- ### React assistant controller + primitives
172
+ ### React assistant UI
173
173
 
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:
174
+ `lemma-sdk/react` ships the assistant controller, the default assistant experience, and the lower-level UI primitives used to build custom shells.
175
175
 
176
- If you want the SDK UI to look correct outside the Lemma app, import the bundled stylesheet once:
176
+ Import the bundled stylesheet once anywhere in your app:
177
177
 
178
178
  ```tsx
179
179
  import "lemma-sdk/react/styles.css";
180
180
  ```
181
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.
182
+ The stylesheet includes the SDK theme tokens and semantic assistant classes. You do not need the Lemma app's internal Tailwind setup just to render the assistant correctly.
184
183
 
185
- ```tsx
186
- import {
187
- MessageGroup,
188
- PlanSummaryStrip,
189
- ThinkingIndicator,
190
- buildDisplayMessageRows,
191
- getActiveToolBanner,
192
- latestPlanSummary,
193
- useAssistantController,
194
- } from "lemma-sdk/react";
184
+ #### Important for Tailwind apps
195
185
 
196
- function AssistantSurface() {
197
- const assistant = useAssistantController({
198
- client,
199
- assistantId: "uuid",
200
- podId: "pod_123",
201
- });
186
+ If your app uses Tailwind and installs `lemma-sdk` from npm, Tailwind must scan the SDK package too. Otherwise the assistant can look half-styled: native file inputs may appear, layouts can collapse, spacing disappears, and buttons/header chrome look wrong.
202
187
 
203
- const rows = buildDisplayMessageRows(assistant.messages);
204
- const plan = latestPlanSummary(assistant.messages);
205
- const activeToolBanner = getActiveToolBanner(assistant.messages);
188
+ For Tailwind v3, add the SDK package to `content`:
206
189
 
207
- return (
208
- <div>
209
- {plan ? <PlanSummaryStrip plan={plan} onHide={() => {}} /> : null}
210
- {activeToolBanner ? <div>{activeToolBanner.summary}</div> : null}
211
-
212
- {rows.map((row, index) => (
213
- <MessageGroup
214
- key={row.id}
215
- message={row.message}
216
- conversationId={assistant.activeConversationId}
217
- onWidgetSendPrompt={(text) => assistant.sendMessage(text)}
218
- isStreaming={assistant.isActiveConversationRunning && row.sourceIndexes.includes(assistant.messages.length - 1)}
219
- showAssistantHeader={index === 0 || rows[index - 1]?.message.role !== "assistant"}
220
- renderMessageContent={({ message }) => <div>{message.content}</div>}
221
- />
222
- ))}
223
-
224
- {assistant.isActiveConversationRunning ? <ThinkingIndicator /> : null}
225
- </div>
226
- );
190
+ ```js
191
+ // tailwind.config.js
192
+ export default {
193
+ content: [
194
+ "./index.html",
195
+ "./src/**/*.{js,ts,jsx,tsx}",
196
+ "./node_modules/lemma-sdk/dist/react/**/*.{js,mjs}",
197
+ ],
227
198
  }
228
199
  ```
229
200
 
230
- The intended split is:
201
+ If you are developing against a local checkout of the SDK source instead of the published npm package, scan the source files too:
231
202
 
232
- - SDK: `useAssistantController`, message/tool normalization, plan parsing, tool rollups, and assistant UI primitives.
233
- - App: modal shell, fullscreen behavior, route navigation, workspace/file viewers, and product-specific renderers.
203
+ ```js
204
+ // tailwind.config.js
205
+ export default {
206
+ content: [
207
+ "./index.html",
208
+ "./src/**/*.{js,ts,jsx,tsx}",
209
+ "../lemma-typescript/src/react/**/*.{ts,tsx}",
210
+ ],
211
+ }
212
+ ```
234
213
 
235
- Useful UI primitives exported from `lemma-sdk/react`:
214
+ If you alias the package to local SDK source in Vite, make sure the alias points at the React source and stylesheet:
236
215
 
237
- - `AssistantHeader`
238
- - `AssistantConversationList`
239
- - `AssistantModelPicker`
240
- - `AssistantShellLayout`
241
- - `AssistantComposer`
242
- - `AssistantMessageViewport`
243
- - `AssistantAskOverlay`
244
- - `AssistantPendingFileChip`
245
- - `AssistantStatusPill`
246
- - `AssistantThemeScope`
247
- - `MessageGroup`
248
- - `PlanSummaryStrip`
216
+ ```ts
217
+ // vite.config.ts
218
+ import path from "node:path";
219
+
220
+ export default {
221
+ resolve: {
222
+ alias: {
223
+ "lemma-sdk/react/styles.css": path.resolve(__dirname, "../lemma-typescript/src/react/styles.css"),
224
+ "lemma-sdk/react": path.resolve(__dirname, "../lemma-typescript/src/react/index.ts"),
225
+ "lemma-sdk": path.resolve(__dirname, "../lemma-typescript/src/index.ts"),
226
+ },
227
+ },
228
+ };
229
+ ```
230
+
231
+ Quick checklist for developers:
232
+
233
+ - import `lemma-sdk/react/styles.css` once
234
+ - give the assistant container a real height
235
+ - if the assistant is inside flex/grid, add `min-height: 0` on the relevant parent
236
+ - if you use Tailwind, scan the SDK package or SDK source
237
+ - if you use `AssistantEmbedded`, pass `theme` directly there
238
+ - if you use `AssistantExperienceView`, wrap it in `AssistantThemeScope`
239
+
240
+ The assistant UI renders markdown by default:
241
+
242
+ - GitHub-flavored markdown is enabled for assistant and user messages
243
+ - raw HTML is not rendered
244
+ - links open safely in a new tab by default
245
+ - lists, tables, blockquotes, inline code, and fenced code blocks are styled out of the box
249
246
 
250
- For a direct plug-and-play component, `AssistantEmbedded` wires `useAssistantController` into the default assistant experience:
247
+ #### Choose an integration level
248
+
249
+ ##### 1. `AssistantEmbedded` for the fastest setup
250
+
251
+ Use `AssistantEmbedded` when you want a ready-made assistant surface with the SDK defaults.
251
252
 
252
253
  ```tsx
253
254
  import "lemma-sdk/react/styles.css";
@@ -255,20 +256,76 @@ import { AssistantEmbedded } from "lemma-sdk/react";
255
256
 
256
257
  function SupportAssistant() {
257
258
  return (
258
- <AssistantEmbedded
259
- client={client}
260
- assistantId="uuid"
261
- podId="pod_123"
262
- title="Support Assistant"
263
- subtitle="Ask questions about this pod."
264
- placeholder="Message Support Assistant"
265
- showConversationList
266
- />
259
+ <div style={{ height: 720, minHeight: 0 }}>
260
+ <AssistantEmbedded
261
+ client={client}
262
+ podId="pod_123"
263
+ assistantId="uuid"
264
+ title="Support Assistant"
265
+ subtitle="Ask questions about this pod."
266
+ placeholder="Message Support Assistant"
267
+ showConversationList
268
+ theme="auto"
269
+ />
270
+ </div>
271
+ );
272
+ }
273
+ ```
274
+
275
+ Important notes:
276
+
277
+ - `theme` accepts `"auto" | "light" | "dark"`
278
+ - `theme="auto"` follows the host app when it uses common selectors like `.dark`, `[data-theme="dark"]`, `[data-mode="dark"]`, and also falls back to `prefers-color-scheme`
279
+ - the parent container must have a real height; if it lives inside flex/grid, `min-height: 0` is usually needed too
280
+ - attachments are queued into the composer and sent with the next message by default
281
+
282
+ ##### 2. `AssistantExperienceView` for the default UI with your own controller
283
+
284
+ Use `AssistantExperienceView` when you want the built-in assistant layout, but you need to own the controller lifecycle yourself.
285
+
286
+ ```tsx
287
+ import "lemma-sdk/react/styles.css";
288
+ import {
289
+ AssistantExperienceView,
290
+ AssistantThemeScope,
291
+ useAssistantController,
292
+ } from "lemma-sdk/react";
293
+
294
+ function ControlledAssistant() {
295
+ const assistant = useAssistantController({
296
+ client,
297
+ podId: "pod_123",
298
+ assistantId: "uuid",
299
+ });
300
+
301
+ return (
302
+ <AssistantThemeScope theme="dark" style={{ height: 720 }}>
303
+ <AssistantExperienceView
304
+ controller={assistant}
305
+ title="Support Assistant"
306
+ subtitle="Direct use of the default assistant experience."
307
+ placeholder="Message Support Assistant"
308
+ showConversationList
309
+ chromeStyle="subtle"
310
+ statusPlacement="inline"
311
+ />
312
+ </AssistantThemeScope>
267
313
  );
268
314
  }
269
315
  ```
270
316
 
271
- If you are composing your own shell with the SDK primitives, wrap it in `AssistantThemeScope` unless your app already provides matching theme tokens:
317
+ Useful props on `AssistantExperienceView`:
318
+
319
+ - `showConversationList`: show the built-in conversation sidebar
320
+ - `chromeStyle`: `"elevated" | "subtle" | "flat"`
321
+ - `statusPlacement`: `"inline" | "composer" | "none"`
322
+ - `renderMessageContent`: override markdown rendering for custom message content
323
+ - `renderToolInvocation`: replace the default tool activity renderer
324
+ - `renderPresentedFile` and `renderPendingFile`: customize attachment rendering
325
+
326
+ ##### 3. `useAssistantController` + primitives for a custom shell
327
+
328
+ Use the primitives when you want full control over layout and app chrome.
272
329
 
273
330
  ```tsx
274
331
  import "lemma-sdk/react/styles.css";
@@ -278,29 +335,109 @@ import {
278
335
  AssistantMessageViewport,
279
336
  AssistantShellLayout,
280
337
  AssistantThemeScope,
338
+ MessageGroup,
339
+ PlanSummaryStrip,
340
+ ThinkingIndicator,
341
+ buildDisplayMessageRows,
342
+ getActiveToolBanner,
343
+ latestPlanSummary,
344
+ useAssistantController,
281
345
  } from "lemma-sdk/react";
282
346
 
283
347
  function CustomAssistantShell() {
348
+ const assistant = useAssistantController({
349
+ client,
350
+ podId: "pod_123",
351
+ assistantId: "uuid",
352
+ });
353
+
354
+ const rows = buildDisplayMessageRows(assistant.messages);
355
+ const plan = latestPlanSummary(assistant.messages);
356
+ const activeToolBanner = getActiveToolBanner(assistant.messages);
357
+
284
358
  return (
285
- <AssistantThemeScope>
359
+ <AssistantThemeScope theme="auto" style={{ height: 720 }}>
286
360
  <AssistantShellLayout
287
- main={
361
+ main={(
288
362
  <div className="flex min-h-0 flex-1 flex-col gap-3">
289
- <AssistantHeader title="Lemma Assistant" subtitle="Ask anything" />
363
+ <AssistantHeader
364
+ title="Lemma Assistant"
365
+ subtitle="Ask anything"
366
+ />
367
+
368
+ {plan ? <PlanSummaryStrip plan={plan} onHide={() => {}} /> : null}
369
+ {activeToolBanner ? <div>{activeToolBanner.summary}</div> : null}
370
+
290
371
  <AssistantMessageViewport>
291
- <div>Messages go here</div>
372
+ {rows.map((row, index) => (
373
+ <MessageGroup
374
+ key={row.id}
375
+ message={row.message}
376
+ conversationId={assistant.activeConversationId}
377
+ onWidgetSendPrompt={(text) => assistant.sendMessage(text)}
378
+ isStreaming={assistant.isActiveConversationRunning && row.sourceIndexes.includes(assistant.messages.length - 1)}
379
+ showAssistantHeader={index === 0 || rows[index - 1]?.message.role !== "assistant"}
380
+ renderMessageContent={({ message }) => <div>{message.content}</div>}
381
+ />
382
+ ))}
383
+
384
+ {assistant.isActiveConversationRunning ? <ThinkingIndicator /> : null}
292
385
  </AssistantMessageViewport>
386
+
293
387
  <AssistantComposer>
294
388
  <textarea placeholder="Message Lemma Assistant" />
295
389
  </AssistantComposer>
296
390
  </div>
297
- }
391
+ )}
298
392
  />
299
393
  </AssistantThemeScope>
300
394
  );
301
395
  }
302
396
  ```
303
397
 
398
+ Useful primitives exported from `lemma-sdk/react`:
399
+
400
+ - `AssistantThemeScope`
401
+ - `AssistantHeader`
402
+ - `AssistantConversationList`
403
+ - `AssistantModelPicker`
404
+ - `AssistantShellLayout`
405
+ - `AssistantComposer`
406
+ - `AssistantMessageViewport`
407
+ - `AssistantAskOverlay`
408
+ - `AssistantPendingFileChip`
409
+ - `AssistantStatusPill`
410
+ - `MessageGroup`
411
+ - `PlanSummaryStrip`
412
+ - `ThinkingIndicator`
413
+
414
+ #### Theming
415
+
416
+ Use `AssistantThemeScope` around custom assistant layouts:
417
+
418
+ ```tsx
419
+ import { AssistantThemeScope } from "lemma-sdk/react";
420
+
421
+ <AssistantThemeScope theme="light">
422
+ <YourAssistant />
423
+ </AssistantThemeScope>
424
+ ```
425
+
426
+ Theme behavior:
427
+
428
+ - `theme="auto"`: follows host dark-mode selectors and system color scheme
429
+ - `theme="light"`: forces the light SDK palette
430
+ - `theme="dark"`: forces the dark SDK palette
431
+
432
+ If you use `AssistantEmbedded`, pass `theme` directly on that component instead of wrapping it again.
433
+
434
+ #### What belongs in the SDK vs your app
435
+
436
+ The intended split is:
437
+
438
+ - SDK: `useAssistantController`, message/tool normalization, markdown rendering, plan parsing, tool rollups, and reusable assistant UI primitives
439
+ - App: modal shell, fullscreen/window controls, route navigation, workspace/file viewers, and product-specific renderers
440
+
304
441
  ### Assistant names (resource key)
305
442
 
306
443
  Assistant CRUD is name-based:
@@ -8,8 +8,10 @@ export type AssistantResponse = {
8
8
  accessible_applications: Array<ApplicationAccessConfig>;
9
9
  accessible_folders: Array<string>;
10
10
  accessible_tables: Array<TableAccessEntry>;
11
+ agent_names: Array<string>;
11
12
  created_at: any;
12
13
  description: (string | null);
14
+ function_names: Array<string>;
13
15
  icon_url: (string | null);
14
16
  id: string;
15
17
  instruction: string;
@@ -8,7 +8,9 @@ export type CreateAssistantRequest = {
8
8
  accessible_applications?: Array<ApplicationAccessConfig>;
9
9
  accessible_folders?: Array<string>;
10
10
  accessible_tables?: Array<TableAccessEntry>;
11
+ agent_names?: Array<string>;
11
12
  description?: (string | null);
13
+ function_names?: Array<string>;
12
14
  icon_url?: (string | null);
13
15
  instruction: string;
14
16
  name: string;
@@ -10,5 +10,6 @@ export type DeskResponse = {
10
10
  source_archive_path?: (string | null);
11
11
  status: DeskStatus;
12
12
  updated_at: any;
13
+ readonly url: string;
13
14
  user_id: string;
14
15
  };
@@ -8,7 +8,9 @@ export type UpdateAssistantRequest = {
8
8
  accessible_applications?: (Array<ApplicationAccessConfig> | null);
9
9
  accessible_folders?: (Array<string> | null);
10
10
  accessible_tables?: (Array<TableAccessEntry> | null);
11
+ agent_names?: (Array<string> | null);
11
12
  description?: (string | null);
13
+ function_names?: (Array<string> | null);
12
14
  icon_url?: (string | null);
13
15
  instruction?: (string | null);
14
16
  tool_sets?: (Array<ToolSet> | null);
@@ -45,13 +45,12 @@ export declare class ConversationsService {
45
45
  * List Messages
46
46
  * List messages in a conversation with token pagination. Use `page_token` to fetch older messages.
47
47
  * @param conversationId
48
- * @param podId
49
48
  * @param pageToken
50
49
  * @param limit
51
50
  * @returns ConversationMessageListResponse Successful Response
52
51
  * @throws ApiError
53
52
  */
54
- static conversationMessageList(conversationId: string, podId?: (string | null), pageToken?: (string | null), limit?: number): CancelablePromise<ConversationMessageListResponse>;
53
+ static conversationMessageList(conversationId: string, pageToken?: (string | null), limit?: number): CancelablePromise<ConversationMessageListResponse>;
55
54
  /**
56
55
  * Send Message (Stream)
57
56
  * @param conversationId
@@ -95,13 +95,12 @@ export class ConversationsService {
95
95
  * List Messages
96
96
  * List messages in a conversation with token pagination. Use `page_token` to fetch older messages.
97
97
  * @param conversationId
98
- * @param podId
99
98
  * @param pageToken
100
99
  * @param limit
101
100
  * @returns ConversationMessageListResponse Successful Response
102
101
  * @throws ApiError
103
102
  */
104
- static conversationMessageList(conversationId, podId, pageToken, limit = 20) {
103
+ static conversationMessageList(conversationId, pageToken, limit = 20) {
105
104
  return __request(OpenAPI, {
106
105
  method: 'GET',
107
106
  url: '/conversations/{conversation_id}/messages',
@@ -109,7 +108,6 @@ export class ConversationsService {
109
108
  'conversation_id': conversationId,
110
109
  },
111
110
  query: {
112
- 'pod_id': podId,
113
111
  'page_token': pageToken,
114
112
  'limit': limit,
115
113
  },
@@ -1,14 +1,18 @@
1
1
  import { type ComponentPropsWithoutRef, type ReactNode } from "react";
2
2
  import type { AssistantConversationListItem, AssistantConversationRenderArgs } from "./assistant-types.js";
3
+ export type AssistantSurfaceTone = "default" | "subtle" | "flat";
4
+ export type AssistantThemeMode = "auto" | "light" | "dark";
3
5
  export interface AssistantThemeScopeProps extends ComponentPropsWithoutRef<"div"> {
4
6
  children: ReactNode;
7
+ theme?: AssistantThemeMode;
5
8
  }
6
- export declare function AssistantThemeScope({ className, children, ...props }: AssistantThemeScopeProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function AssistantThemeScope({ className, children, theme, ...props }: AssistantThemeScopeProps): import("react/jsx-runtime").JSX.Element;
7
10
  export interface AssistantHeaderProps {
8
11
  title: ReactNode;
9
12
  subtitle?: ReactNode;
10
13
  badge?: ReactNode;
11
14
  controls?: ReactNode;
15
+ tone?: AssistantSurfaceTone;
12
16
  className?: string;
13
17
  }
14
18
  export interface AssistantMessageViewportProps extends ComponentPropsWithoutRef<"div"> {
@@ -23,7 +27,7 @@ export interface AssistantShellLayoutProps {
23
27
  className?: string;
24
28
  }
25
29
  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;
30
+ export declare function AssistantHeader({ title, subtitle, badge, controls, tone, className, }: AssistantHeaderProps): import("react/jsx-runtime").JSX.Element;
27
31
  export interface AssistantConversationListProps {
28
32
  conversations: AssistantConversationListItem[];
29
33
  activeConversationId: string | null;
@@ -69,9 +73,10 @@ export interface AssistantComposerProps {
69
73
  status?: ReactNode;
70
74
  pendingFiles?: ReactNode;
71
75
  children: ReactNode;
76
+ tone?: AssistantSurfaceTone;
72
77
  className?: string;
73
78
  }
74
- export declare function AssistantComposer({ floating, status, pendingFiles, children, className, }: AssistantComposerProps): import("react/jsx-runtime").JSX.Element;
79
+ export declare function AssistantComposer({ floating, status, pendingFiles, children, tone, className, }: AssistantComposerProps): import("react/jsx-runtime").JSX.Element;
75
80
  export declare function AssistantPendingFileChip({ label, onRemove, className, }: AssistantPendingFileChipProps): import("react/jsx-runtime").JSX.Element;
76
81
  export interface AssistantStatusPillProps {
77
82
  label: ReactNode;
@@ -3,8 +3,8 @@ 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 }));
6
+ export function AssistantThemeScope({ className, children, theme = "auto", ...props }) {
7
+ return (_jsx("div", { "data-lemma-theme": theme, className: cx("lemma-assistant-theme", className), ...props, children: children }));
8
8
  }
9
9
  export const AssistantMessageViewport = forwardRef(function AssistantMessageViewport({ className, innerClassName, children, ...props }, ref) {
10
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 }) }));
@@ -13,8 +13,8 @@ export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, cl
13
13
  const hasSidebar = !!sidebar;
14
14
  return (_jsxs("div", { className: cx("lemma-assistant-shell", hasSidebar && "lemma-assistant-shell--with-sidebar", hasSidebar && sidebarVisible && "lemma-assistant-shell--sidebar-visible", "mx-auto h-full w-full min-h-0 font-sans antialiased", className), children: [sidebar && sidebarVisible ? (_jsx("div", { className: "lemma-assistant-shell-sidebar", children: sidebar })) : null, main] }));
15
15
  }
16
- export function AssistantHeader({ title, subtitle, badge, controls, className, }) {
17
- 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] }));
16
+ export function AssistantHeader({ title, subtitle, badge, controls, tone = "subtle", className, }) {
17
+ return (_jsxs("div", { "data-tone": tone, 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] }));
18
18
  }
19
19
  export function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title = "Conversations", newLabel = "New", className, }) {
20
20
  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) => {
@@ -45,8 +45,8 @@ export function AssistantAskOverlay({ questionNumber, totalQuestions, question,
45
45
  ? "bg-[var(--brand-primary)] text-[var(--text-on-brand)] hover:bg-[color:color-mix(in_srgb,_var(--brand-primary)_88%,_var(--text-primary))]"
46
46
  : "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), children: continueLabel }) })) : null] }));
47
47
  }
48
- export function AssistantComposer({ floating, status, pendingFiles, children, className, }) {
49
- 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 })] }));
48
+ export function AssistantComposer({ floating, status, pendingFiles, children, tone = "default", className, }) {
49
+ return (_jsxs("div", { "data-tone": tone, "data-has-status": status ? "true" : "false", "data-has-pending-files": pendingFiles ? "true" : "false", "data-has-floating": floating ? "true" : "false", 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, status ? (_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 }) })) : null, 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 })] }));
50
50
  }
51
51
  export function AssistantPendingFileChip({ label, onRemove, className, }) {
52
52
  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] }));
@@ -1,8 +1,10 @@
1
1
  import type { LemmaClient } from "../../client.js";
2
2
  import { type AssistantConversationScope } from "../useAssistantController.js";
3
+ import { type AssistantThemeMode } from "./AssistantChrome.js";
3
4
  import { type AssistantExperienceViewProps } from "./AssistantExperience.js";
4
5
  export interface AssistantEmbeddedProps extends Omit<AssistantExperienceViewProps, "controller">, AssistantConversationScope {
5
6
  client: LemmaClient;
6
7
  enabled?: boolean;
8
+ theme?: AssistantThemeMode;
7
9
  }
8
- export declare function AssistantEmbedded({ client, podId, assistantId, organizationId, enabled, ...props }: AssistantEmbeddedProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function AssistantEmbedded({ client, podId, assistantId, organizationId, enabled, theme, ...props }: AssistantEmbeddedProps): import("react/jsx-runtime").JSX.Element;
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useAssistantController } from "../useAssistantController.js";
3
3
  import { AssistantThemeScope } from "./AssistantChrome.js";
4
4
  import { AssistantExperienceView } from "./AssistantExperience.js";
5
- export function AssistantEmbedded({ client, podId, assistantId, organizationId, enabled = true, ...props }) {
5
+ export function AssistantEmbedded({ client, podId, assistantId, organizationId, enabled = true, theme = "auto", ...props }) {
6
6
  const controller = useAssistantController({
7
7
  client,
8
8
  podId: podId ?? undefined,
@@ -10,5 +10,5 @@ export function AssistantEmbedded({ client, podId, assistantId, organizationId,
10
10
  organizationId: organizationId ?? undefined,
11
11
  enabled,
12
12
  });
13
- return (_jsx(AssistantThemeScope, { children: _jsx(AssistantExperienceView, { controller: controller, ...props }) }));
13
+ return (_jsx(AssistantThemeScope, { className: "lemma-assistant-embedded", theme: theme, children: _jsx(AssistantExperienceView, { controller: controller, ...props }) }));
14
14
  }
@@ -33,6 +33,8 @@ export interface ActiveToolBanner {
33
33
  summary: string;
34
34
  activeCount: number;
35
35
  }
36
+ export type AssistantChromeStyle = "elevated" | "subtle" | "flat";
37
+ export type AssistantStatusPlacement = "inline" | "composer" | "none";
36
38
  export interface AssistantExperienceViewProps {
37
39
  controller: AssistantControllerView;
38
40
  title?: ReactNode;
@@ -42,6 +44,8 @@ export interface AssistantExperienceViewProps {
42
44
  draft?: string;
43
45
  onDraftChange?: (value: string) => void;
44
46
  showConversationList?: boolean;
47
+ chromeStyle?: AssistantChromeStyle;
48
+ statusPlacement?: AssistantStatusPlacement;
45
49
  onNavigateResource?: (resourceType: string, resourceId: string, meta?: Record<string, unknown>) => void;
46
50
  renderConversationLabel?: (args: AssistantConversationRenderArgs) => ReactNode;
47
51
  renderMessageContent?: (args: AssistantMessageRenderArgs) => ReactNode;
@@ -75,5 +79,5 @@ export declare function MessageGroup({ message, conversationId, onNavigateResour
75
79
  renderPresentedFile?: (args: AssistantPresentedFileRenderArgs) => ReactNode;
76
80
  renderToolInvocation?: (args: AssistantToolRenderArgs) => ReactNode;
77
81
  }): import("react/jsx-runtime").JSX.Element;
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;
82
+ export declare function AssistantExperienceView({ controller, title, subtitle, placeholder, emptyState, draft: controlledDraft, onDraftChange, showConversationList, chromeStyle, statusPlacement, onNavigateResource, renderConversationLabel, renderMessageContent, renderPresentedFile, renderPendingFile, renderToolInvocation, }: AssistantExperienceViewProps): import("react/jsx-runtime").JSX.Element;
79
83
  export {};
@@ -1,7 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
3
+ import ReactMarkdown from "react-markdown";
4
+ import remarkGfm from "remark-gfm";
3
5
  import { AvailableModels } from "../../types.js";
4
- import { AssistantAskOverlay, AssistantMessageViewport, } from "./AssistantChrome.js";
6
+ import { AssistantAskOverlay, AssistantComposer, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantStatusPill, } from "./AssistantChrome.js";
5
7
  function cx(...values) {
6
8
  return values.filter(Boolean).join(" ");
7
9
  }
@@ -500,8 +502,11 @@ function useControllableDraft(controlledValue, onChange) {
500
502
  function defaultConversationLabel({ conversation }) {
501
503
  return conversation.title || "Untitled conversation";
502
504
  }
505
+ const markdownComponents = {
506
+ a: ({ node: _node, ...props }) => (_jsx("a", { ...props, target: props.target || "_blank", rel: props.rel || "noreferrer noopener" })),
507
+ };
503
508
  function defaultMessageContent({ message }) {
504
- return _jsx("div", { className: "whitespace-pre-wrap", children: message.content });
509
+ return (_jsx("div", { className: "lemma-assistant-markdown", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], skipHtml: true, components: markdownComponents, children: message.content }) }));
505
510
  }
506
511
  function defaultPresentedFile({ filepath }) {
507
512
  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 })] }));
@@ -513,7 +518,7 @@ export function PlanSummaryStrip({ plan, onHide }) {
513
518
  const [showAll, setShowAll] = useState(false);
514
519
  const visibleSteps = showAll ? plan.steps : plan.steps.slice(0, 5);
515
520
  const hiddenCount = Math.max(0, plan.steps.length - visibleSteps.length);
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] })] }));
521
+ return (_jsxs("div", { className: "lemma-assistant-plan-strip rounded-xl border border-[color:color-mix(in_srgb,_var(--border-default)_88%,_transparent)] bg-[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
522
  }
518
523
  export function ThinkingIndicator() {
519
524
  const [show, setShow] = useState(false);
@@ -575,7 +580,7 @@ function ToolDetailsPanel({ toolName, args, state, result, onNavigateResource, r
575
580
  activeConversationId,
576
581
  }) }));
577
582
  }
578
- return (_jsxs("div", { className: "pl-4 border-l border-[var(--border-default)] space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("div", { className: "text-[11px] font-medium text-[var(--text-secondary)]", children: formatToolDisplayName(toolName) }), canNavigate && onNavigateResource ? (_jsx("button", { type: "button", onClick: () => onNavigateResource(resultData.resourceType, resultData.resourceId, resultData), className: "inline-flex items-center gap-1 text-[10px] font-medium text-[var(--state-success)] hover:text-[var(--state-success)] transition-colors", children: "Open \u203A" })) : null] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[10px] font-medium uppercase tracking-[0.1em] text-[var(--text-tertiary)] mb-1", children: "Input" }), _jsx("div", { className: "p-2 rounded bg-[color:color-mix(in_srgb,_var(--bg-canvas)_70%,_transparent)] font-mono text-[11px] max-h-24 overflow-auto", children: _jsx("pre", { className: "text-[var(--text-secondary)] whitespace-pre-wrap", children: JSON.stringify(args, null, 2) }) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-[10px] font-medium uppercase tracking-[0.1em] text-[var(--text-tertiary)] mb-1", children: "Output" }), _jsx("div", { className: "p-2 rounded bg-[color:color-mix(in_srgb,_var(--bg-canvas)_70%,_transparent)] font-mono text-[11px] max-h-24 overflow-auto", children: _jsx("pre", { className: "text-[var(--text-secondary)] whitespace-pre-wrap", children: Object.keys(resultData).length > 0 ? JSON.stringify(resultData, null, 2) : "No output yet" }) })] })] })] }));
583
+ return (_jsxs("div", { className: "pl-4 border-l border-[var(--border-default)] space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("div", { className: "text-[10px] font-medium uppercase tracking-[0.04em] text-[var(--text-tertiary)]", children: formatToolDisplayName(toolName) }), canNavigate && onNavigateResource ? (_jsx("button", { type: "button", onClick: () => onNavigateResource(resultData.resourceType, resultData.resourceId, resultData), className: "inline-flex items-center gap-1 text-[10px] font-medium text-[var(--state-success)] hover:text-[var(--state-success)] transition-colors", children: "Open \u203A" })) : null] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-[10px] font-medium uppercase tracking-[0.1em] text-[var(--text-tertiary)] mb-1", children: "Input" }), _jsx("div", { className: "p-2 rounded bg-[color:color-mix(in_srgb,_var(--bg-canvas)_70%,_transparent)] font-mono text-[11px] max-h-24 overflow-auto", children: _jsx("pre", { className: "text-[var(--text-secondary)] whitespace-pre-wrap", children: JSON.stringify(args, null, 2) }) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-[10px] font-medium uppercase tracking-[0.1em] text-[var(--text-tertiary)] mb-1", children: "Output" }), _jsx("div", { className: "p-2 rounded bg-[color:color-mix(in_srgb,_var(--bg-canvas)_70%,_transparent)] font-mono text-[11px] max-h-24 overflow-auto", children: _jsx("pre", { className: "text-[var(--text-secondary)] whitespace-pre-wrap", children: Object.keys(resultData).length > 0 ? JSON.stringify(resultData, null, 2) : "No output yet" }) })] })] })] }));
579
584
  }
580
585
  function InlineToolCall({ invocation, isSelected, onClick, }) {
581
586
  const resultData = (invocation.result || {});
@@ -587,7 +592,7 @@ function InlineToolCall({ invocation, isSelected, onClick, }) {
587
592
  : isFailed
588
593
  ? (typeof resultData.error === "string" ? resultData.error : "Tool failed")
589
594
  : (formatToolResultSummary(invocation.toolName, invocation.args, resultData) || "Completed");
590
- return (_jsxs("button", { type: "button", onClick: onClick, className: cx("w-full text-left inline-flex items-center gap-1.5 text-[12px] leading-5 transition-colors hover:text-[var(--text-primary)]", isExecuting && "text-[var(--state-info)]", isComplete && "text-[var(--state-success)]", isFailed && "text-[var(--state-error)]", !isExecuting && !isComplete && !isFailed && "text-[var(--text-secondary)]"), children: [_jsx("span", { className: "font-medium whitespace-nowrap", children: formatToolDisplayName(invocation.toolName) }), _jsx("span", { className: "text-current/80 truncate", children: summary }), _jsx("span", { className: "ml-auto transition-transform", children: isSelected ? "⌄" : "›" })] }));
595
+ return (_jsxs("button", { type: "button", onClick: onClick, className: cx("w-full text-left inline-flex items-center gap-1.5 text-[11px] leading-5 transition-colors hover:text-[var(--text-primary)]", isExecuting && "text-[var(--state-info)]", isComplete && "text-[var(--state-success)]", isFailed && "text-[var(--state-error)]", !isExecuting && !isComplete && !isFailed && "text-[var(--text-secondary)]"), children: [_jsx("span", { className: "font-medium whitespace-nowrap", children: formatToolDisplayName(invocation.toolName) }), _jsx("span", { className: "text-current/80 truncate", children: summary }), _jsx("span", { className: "ml-auto transition-transform", children: isSelected ? "⌄" : "›" })] }));
591
596
  }
592
597
  function ToolActivityRollup({ detailParts, onNavigateResource, renderToolInvocation, message, activeConversationId, }) {
593
598
  const [activeToolCallId, setActiveToolCallId] = useState(null);
@@ -603,7 +608,7 @@ function ToolActivityRollup({ detailParts, onNavigateResource, renderToolInvocat
603
608
  const summary = activeInvocation
604
609
  ? formatActiveToolSummary(activeInvocation.toolName, activeInvocation.args)
605
610
  : `Worked across ${toolParts.length} tool${toolParts.length === 1 ? "" : "s"}${failedCount > 0 ? ` · ${failedCount} failed` : ""}`;
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) => {
611
+ 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-[11px] 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
612
  if (part.type === "reasoning") {
608
613
  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
614
  }
@@ -755,7 +760,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
755
760
  return null;
756
761
  }), presentableFilepaths.length > 0 ? (_jsx(PresentFilesCard, { filepaths: presentableFilepaths, conversationId: conversationId, renderPresentedFile: renderPresentedFile })) : null] })] }));
757
762
  }
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, }) {
763
+ export function AssistantExperienceView({ controller, title = "Lemma Assistant", subtitle = "Ask across your workspace and organization.", placeholder = "Message Lemma Assistant", emptyState, draft: controlledDraft, onDraftChange, showConversationList = false, chromeStyle = "subtle", statusPlacement = "inline", onNavigateResource, renderConversationLabel = defaultConversationLabel, renderMessageContent = defaultMessageContent, renderPresentedFile, renderPendingFile = defaultPendingFile, renderToolInvocation, }) {
759
764
  const [draft, setDraft] = useControllableDraft(controlledDraft, onDraftChange);
760
765
  const [isPlanHidden, setIsPlanHidden] = useState(false);
761
766
  const [dismissedAskToolCallIds, setDismissedAskToolCallIds] = useState([]);
@@ -764,6 +769,7 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
764
769
  const messagesContainerRef = useRef(null);
765
770
  const inputRef = useRef(null);
766
771
  const fileInputRef = useRef(null);
772
+ const bottomAnchorRef = useRef(null);
767
773
  const isPinnedToBottomRef = useRef(true);
768
774
  const loadingOlderFromScrollRef = useRef(false);
769
775
  const isConversationBusy = controller.isLoading || controller.isActiveConversationRunning;
@@ -780,6 +786,15 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
780
786
  textarea.style.overflowY = textarea.scrollHeight > maxHeight ? "auto" : "hidden";
781
787
  }, []);
782
788
  const scrollToLatest = useCallback((behavior = "auto") => {
789
+ const anchor = bottomAnchorRef.current;
790
+ if (anchor) {
791
+ anchor.scrollIntoView({
792
+ block: "end",
793
+ behavior,
794
+ });
795
+ isPinnedToBottomRef.current = true;
796
+ return;
797
+ }
783
798
  const el = messagesContainerRef.current;
784
799
  if (!el)
785
800
  return;
@@ -825,10 +840,18 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
825
840
  return;
826
841
  if (isPinnedToBottomRef.current) {
827
842
  requestAnimationFrame(() => {
828
- scrollToLatest(isConversationBusy ? "auto" : "smooth");
843
+ requestAnimationFrame(() => {
844
+ scrollToLatest(isConversationBusy ? "auto" : "smooth");
845
+ });
829
846
  });
830
847
  }
831
848
  }, [controller.messages, isConversationBusy, scrollToLatest]);
849
+ useEffect(() => {
850
+ isPinnedToBottomRef.current = true;
851
+ requestAnimationFrame(() => {
852
+ scrollToLatest("auto");
853
+ });
854
+ }, [controller.activeConversationId, scrollToLatest]);
832
855
  useEffect(() => {
833
856
  resizeComposer();
834
857
  }, [draft, resizeComposer]);
@@ -959,7 +982,10 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
959
982
  if (selectedFiles.length === 0)
960
983
  return;
961
984
  try {
962
- await controller.uploadFiles(selectedFiles);
985
+ await controller.uploadFiles(selectedFiles, { deferUntilSend: true });
986
+ requestAnimationFrame(() => {
987
+ inputRef.current?.focus();
988
+ });
963
989
  }
964
990
  finally {
965
991
  if (fileInputRef.current) {
@@ -993,29 +1019,34 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
993
1019
  ? effectiveAskOverlayState.answers[effectiveAskOverlayState.currentQuestionIndex] || []
994
1020
  : [];
995
1021
  const canContinueAsk = activeAskAnswers.length > 0;
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) => {
1022
+ const liveStatusLabel = activeToolBanner?.summary || "Thinking through this...";
1023
+ const headerTone = chromeStyle === "elevated" ? "default" : chromeStyle === "flat" ? "flat" : "subtle";
1024
+ const composerTone = chromeStyle === "flat" ? "flat" : chromeStyle === "subtle" ? "subtle" : "default";
1025
+ const showInlineStatus = statusPlacement === "inline" && isConversationBusy;
1026
+ const showComposerStatus = statusPlacement === "composer" && isConversationBusy;
1027
+ 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"), "data-chrome-style": chromeStyle, "data-status-placement": statusPlacement, "data-busy": isConversationBusy ? "true" : "false", "data-has-plan": planSummary ? "true" : "false", "data-has-pending-files": controller.pendingFiles.length > 0 ? "true" : "false", "data-show-conversation-list": showConversationList ? "true" : "false", 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
1028
  const isActive = conversation.id === controller.activeConversationId;
998
1029
  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
1030
  ? "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
1031
  : "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) => {
1032
+ }) })] })) : 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: [_jsx(AssistantHeader, { className: "lemma-assistant-experience-header", tone: headerTone, title: title, subtitle: subtitle, badge: _jsx("span", { className: "text-[var(--text-on-brand)] text-xs", children: "\u2728" }), controls: (_jsxs(_Fragment, { children: [_jsx(AssistantModelPicker, { value: controller.conversationModel, options: availableModels, onChange: (nextModel) => { void handleModelChange(nextModel); }, disabled: isConversationBusy || isUpdatingModel, autoLabel: "Auto", className: "lemma-assistant-experience-model-picker" }), _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
1033
  const previousRow = index > 0 ? displayMessageRows[index - 1] : null;
1003
1034
  const showAssistantHeader = row.message.role !== "assistant"
1004
1035
  ? false
1005
1036
  : previousRow?.message.role !== "assistant";
1006
1037
  const includesLastRawMessage = row.sourceIndexes.includes(controller.messages.length - 1);
1007
1038
  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
- }), 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, 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 ? "■" : "→" }) })] })] }))] })] })] }));
1039
+ }), showInlineStatus ? (_jsx("div", { className: "lemma-assistant-experience-inline-status flex min-h-[38px] items-center px-1", children: _jsx("div", { className: cx("transition-all duration-200", lastMessageHasContent ? "opacity-80" : "opacity-100"), children: _jsx(AssistantStatusPill, { label: liveStatusLabel, subtle: lastMessageHasContent }) }) })) : 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, _jsx("div", { ref: bottomAnchorRef, "aria-hidden": "true", className: "lemma-assistant-experience-bottom-anchor h-px" })] })] }), _jsx(AssistantComposer, { className: "lemma-assistant-experience-composer", tone: composerTone, floating: planSummary ? (isPlanHidden ? (_jsxs("button", { type: "button", onClick: () => setIsPlanHidden(false), className: "inline-flex items-center gap-2 rounded-full border border-[color:color-mix(in_srgb,_var(--border-default)_88%,_transparent)] bg-[var(--bg-surface)] px-3 py-1.5 text-[11px] font-medium text-[var(--text-secondary)] shadow-[var(--shadow-xs)] 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) }))) : undefined, status: showComposerStatus ? (_jsx(AssistantStatusPill, { label: liveStatusLabel, subtle: true })) : undefined, pendingFiles: controller.pendingFiles.length > 0 ? (_jsx(_Fragment, { children: controller.pendingFiles.map((file) => {
1040
+ const fileKey = `${file.name}:${file.size}:${file.lastModified}`;
1041
+ return (_jsx("div", { children: renderPendingFile({
1042
+ file,
1043
+ remove: () => controller.removePendingFile(fileKey),
1044
+ }) }, fileKey));
1045
+ }) })) : undefined, children: 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 })) : (_jsx("div", { className: "lemma-assistant-experience-composer-body space-y-1.5", children: _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
1046
+ ? "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"
1047
+ : "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
1048
+ ? "bg-[var(--text-primary)] text-[var(--text-inverse)] hover:bg-[color:color-mix(in_srgb,_var(--text-primary)_80%,_transparent)] hover:scale-105"
1049
+ : draft.trim()
1050
+ ? "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))]"
1051
+ : "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), title: isConversationBusy ? "Stop generating" : "Send message", children: isConversationBusy ? "■" : "→" }) })] }) })) })] })] }));
1021
1052
  }
@@ -14,9 +14,9 @@ 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
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";
17
+ export type { AssistantAskOverlayProps, AssistantComposerProps, AssistantConversationListProps, AssistantHeaderProps, AssistantMessageViewportProps, AssistantModelPickerProps, AssistantPendingFileChipProps, AssistantShellLayoutProps, AssistantStatusPillProps, AssistantSurfaceTone, AssistantThemeMode, AssistantThemeScopeProps, } from "./components/AssistantChrome.js";
18
18
  export { AssistantExperienceView } from "./components/AssistantExperience.js";
19
- export type { ActiveToolBanner, AskUserInputQuestion, AssistantExperienceViewProps, DisplayMessageRow, PendingAskUserInput, PlanStepState, PlanSummaryState, } from "./components/AssistantExperience.js";
19
+ export type { ActiveToolBanner, AskUserInputQuestion, AssistantChromeStyle, AssistantExperienceViewProps, AssistantStatusPlacement, DisplayMessageRow, PendingAskUserInput, PlanStepState, PlanSummaryState, } from "./components/AssistantExperience.js";
20
20
  export { AssistantEmbedded } from "./components/AssistantEmbedded.js";
21
21
  export type { AssistantEmbeddedProps } from "./components/AssistantEmbedded.js";
22
22
  export { buildDisplayMessageRows, dedupToolInvocations, EmptyState, findPendingAskUserInput, formatAskUserInputAnswers, getActiveToolBanner, extractPresentFilePathsFromInvocation, latestPlanSummary, MessageGroup, PlanSummaryStrip, ThinkingIndicator, } from "./components/AssistantExperience.js";
@@ -1,4 +1,5 @@
1
1
  .lemma-assistant-theme {
2
+ color-scheme: light;
2
3
  --bg-canvas: #f6f2ea;
3
4
  --bg-surface: #fffdf9;
4
5
  --bg-subtle: #f1ebde;
@@ -53,6 +54,294 @@
53
54
  color: var(--text-tertiary);
54
55
  }
55
56
 
57
+ @media (prefers-color-scheme: dark) {
58
+ .lemma-assistant-theme:not([data-lemma-theme="light"]):not([data-lemma-theme="dark"]),
59
+ .lemma-assistant-theme[data-lemma-theme="auto"] {
60
+ color-scheme: dark;
61
+ --bg-canvas: #12100d;
62
+ --bg-surface: #1b1814;
63
+ --bg-subtle: #272118;
64
+ --border-default: #3d3428;
65
+ --border-subtle: #2d261d;
66
+ --text-primary: #f5ede0;
67
+ --text-secondary: #d0c3b1;
68
+ --text-tertiary: #988d7d;
69
+ --text-inverse: #15120f;
70
+ --text-on-brand: #15120f;
71
+ --brand-primary: #ead9b3;
72
+ --brand-secondary: #8daa73;
73
+ --brand-accent: #d9a44b;
74
+ --brand-glow: #2d2418;
75
+ --state-success: #7cbc72;
76
+ --state-error: #ec8d74;
77
+ --state-info: #7eb8f5;
78
+ --state-warning: #e0b45d;
79
+ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.32);
80
+ --shadow-sm: 0 10px 26px rgba(0, 0, 0, 0.32);
81
+ --shadow-md: 0 20px 40px rgba(0, 0, 0, 0.4);
82
+ --shadow-lg: 0 28px 56px rgba(0, 0, 0, 0.5);
83
+ }
84
+ }
85
+
86
+ :where(.light, [data-theme="light"], [data-color-scheme="light"], [data-mode="light"]) .lemma-assistant-theme:not([data-lemma-theme="dark"]),
87
+ .lemma-assistant-theme[data-lemma-theme="light"] {
88
+ color-scheme: light;
89
+ --bg-canvas: #f6f2ea;
90
+ --bg-surface: #fffdf9;
91
+ --bg-subtle: #f1ebde;
92
+ --border-default: #ddd2bb;
93
+ --border-subtle: #ebe2d0;
94
+ --text-primary: #241f16;
95
+ --text-secondary: #5c5344;
96
+ --text-tertiary: #8a7f6f;
97
+ --text-inverse: #fffdf9;
98
+ --text-on-brand: #fffdf9;
99
+ --brand-primary: #202418;
100
+ --brand-secondary: #6e8c56;
101
+ --brand-accent: #c78a2c;
102
+ --brand-glow: #efe3c7;
103
+ --state-success: #3e7a3c;
104
+ --state-error: #b44d36;
105
+ --state-info: #2f6fb2;
106
+ --state-warning: #c78a2c;
107
+ --shadow-xs: 0 1px 2px rgba(36, 31, 22, 0.08);
108
+ --shadow-sm: 0 8px 24px rgba(36, 31, 22, 0.08);
109
+ --shadow-md: 0 18px 36px rgba(36, 31, 22, 0.1);
110
+ --shadow-lg: 0 24px 48px rgba(36, 31, 22, 0.14);
111
+ }
112
+
113
+ :where(.dark, [data-theme="dark"], [data-color-scheme="dark"], [data-mode="dark"]) .lemma-assistant-theme:not([data-lemma-theme="light"]),
114
+ .lemma-assistant-theme[data-lemma-theme="dark"] {
115
+ color-scheme: dark;
116
+ --bg-canvas: #12100d;
117
+ --bg-surface: #1b1814;
118
+ --bg-subtle: #272118;
119
+ --border-default: #3d3428;
120
+ --border-subtle: #2d261d;
121
+ --text-primary: #f5ede0;
122
+ --text-secondary: #d0c3b1;
123
+ --text-tertiary: #988d7d;
124
+ --text-inverse: #15120f;
125
+ --text-on-brand: #15120f;
126
+ --brand-primary: #ead9b3;
127
+ --brand-secondary: #8daa73;
128
+ --brand-accent: #d9a44b;
129
+ --brand-glow: #2d2418;
130
+ --state-success: #7cbc72;
131
+ --state-error: #ec8d74;
132
+ --state-info: #7eb8f5;
133
+ --state-warning: #e0b45d;
134
+ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.32);
135
+ --shadow-sm: 0 10px 26px rgba(0, 0, 0, 0.32);
136
+ --shadow-md: 0 20px 40px rgba(0, 0, 0, 0.4);
137
+ --shadow-lg: 0 28px 56px rgba(0, 0, 0, 0.5);
138
+ }
139
+
140
+ .lemma-assistant-embedded {
141
+ display: flex;
142
+ flex-direction: column;
143
+ min-height: 0;
144
+ height: 100%;
145
+ }
146
+
147
+ .lemma-assistant-markdown {
148
+ color: inherit;
149
+ line-height: 1.7;
150
+ word-break: break-word;
151
+ }
152
+
153
+ .lemma-assistant-markdown > :first-child {
154
+ margin-top: 0;
155
+ }
156
+
157
+ .lemma-assistant-markdown > :last-child {
158
+ margin-bottom: 0;
159
+ }
160
+
161
+ .lemma-assistant-markdown p,
162
+ .lemma-assistant-markdown ul,
163
+ .lemma-assistant-markdown ol,
164
+ .lemma-assistant-markdown pre,
165
+ .lemma-assistant-markdown blockquote,
166
+ .lemma-assistant-markdown table,
167
+ .lemma-assistant-markdown hr {
168
+ margin: 0 0 0.95em;
169
+ }
170
+
171
+ .lemma-assistant-markdown h1,
172
+ .lemma-assistant-markdown h2,
173
+ .lemma-assistant-markdown h3,
174
+ .lemma-assistant-markdown h4 {
175
+ margin: 1.15em 0 0.55em;
176
+ line-height: 1.25;
177
+ color: var(--text-primary);
178
+ }
179
+
180
+ .lemma-assistant-markdown h1 {
181
+ font-size: 1.4rem;
182
+ }
183
+
184
+ .lemma-assistant-markdown h2 {
185
+ font-size: 1.2rem;
186
+ }
187
+
188
+ .lemma-assistant-markdown h3 {
189
+ font-size: 1.05rem;
190
+ }
191
+
192
+ .lemma-assistant-markdown h4 {
193
+ font-size: 0.95rem;
194
+ }
195
+
196
+ .lemma-assistant-markdown ul,
197
+ .lemma-assistant-markdown ol {
198
+ padding-left: 1.35rem;
199
+ }
200
+
201
+ .lemma-assistant-markdown ul {
202
+ list-style: disc;
203
+ }
204
+
205
+ .lemma-assistant-markdown ol {
206
+ list-style: decimal;
207
+ }
208
+
209
+ .lemma-assistant-markdown li + li {
210
+ margin-top: 0.3rem;
211
+ }
212
+
213
+ .lemma-assistant-markdown li > ul,
214
+ .lemma-assistant-markdown li > ol {
215
+ margin-top: 0.35rem;
216
+ margin-bottom: 0;
217
+ }
218
+
219
+ .lemma-assistant-markdown a {
220
+ color: var(--state-info);
221
+ text-decoration: underline;
222
+ text-decoration-color: color-mix(in srgb, var(--state-info) 56%, transparent);
223
+ text-underline-offset: 0.16em;
224
+ }
225
+
226
+ .lemma-assistant-markdown a:hover {
227
+ color: color-mix(in srgb, var(--state-info) 82%, var(--text-primary));
228
+ }
229
+
230
+ .lemma-assistant-markdown strong {
231
+ color: var(--text-primary);
232
+ font-weight: 650;
233
+ }
234
+
235
+ .lemma-assistant-markdown em {
236
+ color: var(--text-secondary);
237
+ }
238
+
239
+ .lemma-assistant-markdown hr {
240
+ border: 0;
241
+ border-top: 1px solid color-mix(in srgb, var(--border-default) 88%, transparent);
242
+ }
243
+
244
+ .lemma-assistant-markdown blockquote {
245
+ padding: 0.15rem 0 0.15rem 0.9rem;
246
+ border-left: 3px solid color-mix(in srgb, var(--brand-accent) 60%, var(--border-default));
247
+ color: var(--text-secondary);
248
+ }
249
+
250
+ .lemma-assistant-markdown :not(pre) > code {
251
+ display: inline-block;
252
+ margin: 0 0.08rem;
253
+ padding: 0.1rem 0.42rem;
254
+ border: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
255
+ border-radius: 999px;
256
+ background: color-mix(in srgb, var(--bg-subtle) 88%, transparent);
257
+ color: var(--text-primary);
258
+ font-size: 0.92em;
259
+ line-height: 1.45;
260
+ }
261
+
262
+ .lemma-assistant-markdown pre {
263
+ overflow-x: auto;
264
+ padding: 0.9rem 1rem;
265
+ border: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
266
+ border-radius: 16px;
267
+ background: color-mix(in srgb, var(--bg-canvas) 74%, var(--bg-surface));
268
+ box-shadow: inset 0 1px 0 color-mix(in srgb, var(--bg-surface) 60%, transparent);
269
+ }
270
+
271
+ .lemma-assistant-markdown pre code {
272
+ padding: 0;
273
+ border: 0;
274
+ background: transparent;
275
+ color: inherit;
276
+ font-size: 0.92em;
277
+ line-height: 1.65;
278
+ }
279
+
280
+ .lemma-assistant-markdown table {
281
+ display: block;
282
+ width: 100%;
283
+ overflow-x: auto;
284
+ border-collapse: separate;
285
+ border-spacing: 0;
286
+ border: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
287
+ border-radius: 16px;
288
+ background: color-mix(in srgb, var(--bg-surface) 96%, transparent);
289
+ }
290
+
291
+ .lemma-assistant-markdown thead {
292
+ background: color-mix(in srgb, var(--bg-subtle) 76%, transparent);
293
+ }
294
+
295
+ .lemma-assistant-markdown th,
296
+ .lemma-assistant-markdown td {
297
+ padding: 0.7rem 0.85rem;
298
+ border-bottom: 1px solid color-mix(in srgb, var(--border-default) 72%, transparent);
299
+ text-align: left;
300
+ vertical-align: top;
301
+ }
302
+
303
+ .lemma-assistant-markdown tr:last-child td {
304
+ border-bottom: 0;
305
+ }
306
+
307
+ .lemma-assistant-markdown img {
308
+ max-width: 100%;
309
+ border-radius: 14px;
310
+ }
311
+
312
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown,
313
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown h1,
314
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown h2,
315
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown h3,
316
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown h4,
317
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown strong,
318
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown em,
319
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown a,
320
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown code,
321
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown pre code {
322
+ color: inherit;
323
+ }
324
+
325
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown a {
326
+ text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
327
+ }
328
+
329
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown blockquote {
330
+ border-left-color: color-mix(in srgb, currentColor 34%, transparent);
331
+ color: inherit;
332
+ }
333
+
334
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown :not(pre) > code {
335
+ border-color: color-mix(in srgb, currentColor 18%, transparent);
336
+ background: color-mix(in srgb, currentColor 10%, transparent);
337
+ color: inherit;
338
+ }
339
+
340
+ .lemma-assistant-message-user-bubble .lemma-assistant-markdown pre {
341
+ border-color: color-mix(in srgb, currentColor 18%, transparent);
342
+ background: color-mix(in srgb, currentColor 8%, transparent);
343
+ }
344
+
56
345
  .lemma-assistant-shell,
57
346
  .lemma-assistant-experience,
58
347
  .lemma-assistant-shell-sidebar,
@@ -95,6 +384,24 @@
95
384
  align-items: center;
96
385
  justify-content: space-between;
97
386
  gap: 12px;
387
+ background: transparent;
388
+ border-bottom: 0;
389
+ box-shadow: none;
390
+ }
391
+
392
+
393
+ .lemma-assistant-header[data-tone="default"],
394
+ .lemma-assistant-experience-header[data-tone="default"] {
395
+ background: var(--bg-surface);
396
+ border-bottom: 1px solid var(--border-default);
397
+ }
398
+
399
+ .lemma-assistant-header[data-tone="flat"],
400
+ .lemma-assistant-experience-header[data-tone="flat"] {
401
+ background: transparent;
402
+ border-bottom: 0;
403
+ box-shadow: none;
404
+ padding-bottom: 0;
98
405
  }
99
406
 
100
407
  .lemma-assistant-header-copy,
@@ -177,6 +484,8 @@
177
484
  .lemma-assistant-experience-model-picker {
178
485
  appearance: none;
179
486
  min-width: 132px;
487
+ border-color: transparent;
488
+ background: color-mix(in srgb, var(--bg-surface) 88%, transparent);
180
489
  }
181
490
 
182
491
  .lemma-assistant-viewport,
@@ -198,6 +507,22 @@
198
507
  box-shadow: var(--shadow-md);
199
508
  }
200
509
 
510
+
511
+ .lemma-assistant-composer[data-tone="subtle"],
512
+ .lemma-assistant-experience-composer[data-tone="subtle"] {
513
+ background: color-mix(in srgb, var(--bg-surface) 96%, transparent);
514
+ border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
515
+ box-shadow: var(--shadow-sm);
516
+ }
517
+
518
+ .lemma-assistant-composer[data-tone="flat"],
519
+ .lemma-assistant-experience-composer[data-tone="flat"] {
520
+ background: transparent;
521
+ border-color: transparent;
522
+ box-shadow: none;
523
+ padding: 0;
524
+ }
525
+
201
526
  .lemma-assistant-composer-floating,
202
527
  .lemma-assistant-experience-plan {
203
528
  position: absolute;
@@ -205,6 +530,7 @@
205
530
  right: 0;
206
531
  bottom: calc(100% + 8px);
207
532
  z-index: 20;
533
+ pointer-events: auto;
208
534
  }
209
535
 
210
536
  .lemma-assistant-composer-status-rail {
@@ -223,6 +549,41 @@
223
549
  gap: 6px;
224
550
  }
225
551
 
552
+ .lemma-assistant-conversation-list-new,
553
+ .lemma-assistant-experience-sidebar-new {
554
+ border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
555
+ }
556
+
557
+
558
+ .lemma-assistant-experience-new,
559
+ .lemma-assistant-conversation-list-new,
560
+ .lemma-assistant-experience-sidebar-new {
561
+ background: color-mix(in srgb, var(--bg-surface) 90%, transparent);
562
+ backdrop-filter: blur(12px);
563
+ }
564
+
565
+ .lemma-assistant-experience-new {
566
+ border: 0;
567
+ }
568
+
569
+ .lemma-assistant-experience[data-chrome-style="subtle"] .lemma-assistant-experience-card,
570
+ .lemma-assistant-experience[data-chrome-style="subtle"] .lemma-assistant-experience-sidebar {
571
+ box-shadow: var(--shadow-md);
572
+ }
573
+
574
+ .lemma-assistant-experience[data-chrome-style="flat"] .lemma-assistant-experience-card,
575
+ .lemma-assistant-experience[data-chrome-style="flat"] .lemma-assistant-experience-sidebar {
576
+ background: transparent;
577
+ border-color: transparent;
578
+ box-shadow: none;
579
+ }
580
+
581
+ .lemma-assistant-plan-strip {
582
+ background: var(--bg-surface);
583
+ border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
584
+ box-shadow: var(--shadow-sm);
585
+ }
586
+
226
587
  .lemma-assistant-pending-file-chip {
227
588
  display: inline-flex;
228
589
  align-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lemma-sdk",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "Official TypeScript SDK for Lemma pod-scoped APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -53,6 +53,8 @@
53
53
  }
54
54
  },
55
55
  "dependencies": {
56
+ "react-markdown": "^10.1.0",
57
+ "remark-gfm": "^4.0.1",
56
58
  "supertokens-web-js": "^0.16.0"
57
59
  },
58
60
  "devDependencies": {