lemma-sdk 0.2.17 → 0.2.18
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 +157 -76
- package/dist/openapi_client/models/AssistantResponse.d.ts +2 -0
- package/dist/openapi_client/models/CreateAssistantRequest.d.ts +2 -0
- package/dist/openapi_client/models/DeskResponse.d.ts +1 -0
- package/dist/openapi_client/models/UpdateAssistantRequest.d.ts +2 -0
- package/dist/openapi_client/services/ConversationsService.d.ts +1 -2
- package/dist/openapi_client/services/ConversationsService.js +1 -3
- package/dist/react/components/AssistantChrome.d.ts +8 -3
- package/dist/react/components/AssistantChrome.js +6 -6
- package/dist/react/components/AssistantEmbedded.d.ts +3 -1
- package/dist/react/components/AssistantEmbedded.js +2 -2
- package/dist/react/components/AssistantExperience.d.ts +5 -1
- package/dist/react/components/AssistantExperience.js +56 -25
- package/dist/react/index.d.ts +2 -2
- package/dist/react/styles.css +339 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -169,106 +169,107 @@ Notes:
|
|
|
169
169
|
|
|
170
170
|
## Assistants + Agent Runs
|
|
171
171
|
|
|
172
|
-
### React assistant
|
|
172
|
+
### React assistant UI
|
|
173
173
|
|
|
174
|
-
`lemma-sdk/react`
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
186
|
-
import {
|
|
187
|
-
MessageGroup,
|
|
188
|
-
PlanSummaryStrip,
|
|
189
|
-
ThinkingIndicator,
|
|
190
|
-
buildDisplayMessageRows,
|
|
191
|
-
getActiveToolBanner,
|
|
192
|
-
latestPlanSummary,
|
|
193
|
-
useAssistantController,
|
|
194
|
-
} from "lemma-sdk/react";
|
|
184
|
+
The assistant UI renders markdown by default:
|
|
195
185
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
podId: "pod_123",
|
|
201
|
-
});
|
|
186
|
+
- GitHub-flavored markdown is enabled for assistant and user messages
|
|
187
|
+
- raw HTML is not rendered
|
|
188
|
+
- links open safely in a new tab by default
|
|
189
|
+
- lists, tables, blockquotes, inline code, and fenced code blocks are styled out of the box
|
|
202
190
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
191
|
+
#### Choose an integration level
|
|
192
|
+
|
|
193
|
+
##### 1. `AssistantEmbedded` for the fastest setup
|
|
194
|
+
|
|
195
|
+
Use `AssistantEmbedded` when you want a ready-made assistant surface with the SDK defaults.
|
|
206
196
|
|
|
197
|
+
```tsx
|
|
198
|
+
import "lemma-sdk/react/styles.css";
|
|
199
|
+
import { AssistantEmbedded } from "lemma-sdk/react";
|
|
200
|
+
|
|
201
|
+
function SupportAssistant() {
|
|
207
202
|
return (
|
|
208
|
-
<div>
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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}
|
|
203
|
+
<div style={{ height: 720, minHeight: 0 }}>
|
|
204
|
+
<AssistantEmbedded
|
|
205
|
+
client={client}
|
|
206
|
+
podId="pod_123"
|
|
207
|
+
assistantId="uuid"
|
|
208
|
+
title="Support Assistant"
|
|
209
|
+
subtitle="Ask questions about this pod."
|
|
210
|
+
placeholder="Message Support Assistant"
|
|
211
|
+
showConversationList
|
|
212
|
+
theme="auto"
|
|
213
|
+
/>
|
|
225
214
|
</div>
|
|
226
215
|
);
|
|
227
216
|
}
|
|
228
217
|
```
|
|
229
218
|
|
|
230
|
-
|
|
231
|
-
|
|
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.
|
|
219
|
+
Important notes:
|
|
234
220
|
|
|
235
|
-
|
|
221
|
+
- `theme` accepts `"auto" | "light" | "dark"`
|
|
222
|
+
- `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`
|
|
223
|
+
- the parent container must have a real height; if it lives inside flex/grid, `min-height: 0` is usually needed too
|
|
224
|
+
- attachments are queued into the composer and sent with the next message by default
|
|
236
225
|
|
|
237
|
-
|
|
238
|
-
- `AssistantConversationList`
|
|
239
|
-
- `AssistantModelPicker`
|
|
240
|
-
- `AssistantShellLayout`
|
|
241
|
-
- `AssistantComposer`
|
|
242
|
-
- `AssistantMessageViewport`
|
|
243
|
-
- `AssistantAskOverlay`
|
|
244
|
-
- `AssistantPendingFileChip`
|
|
245
|
-
- `AssistantStatusPill`
|
|
246
|
-
- `AssistantThemeScope`
|
|
247
|
-
- `MessageGroup`
|
|
248
|
-
- `PlanSummaryStrip`
|
|
226
|
+
##### 2. `AssistantExperienceView` for the default UI with your own controller
|
|
249
227
|
|
|
250
|
-
|
|
228
|
+
Use `AssistantExperienceView` when you want the built-in assistant layout, but you need to own the controller lifecycle yourself.
|
|
251
229
|
|
|
252
230
|
```tsx
|
|
253
231
|
import "lemma-sdk/react/styles.css";
|
|
254
|
-
import {
|
|
232
|
+
import {
|
|
233
|
+
AssistantExperienceView,
|
|
234
|
+
AssistantThemeScope,
|
|
235
|
+
useAssistantController,
|
|
236
|
+
} from "lemma-sdk/react";
|
|
237
|
+
|
|
238
|
+
function ControlledAssistant() {
|
|
239
|
+
const assistant = useAssistantController({
|
|
240
|
+
client,
|
|
241
|
+
podId: "pod_123",
|
|
242
|
+
assistantId: "uuid",
|
|
243
|
+
});
|
|
255
244
|
|
|
256
|
-
function SupportAssistant() {
|
|
257
245
|
return (
|
|
258
|
-
<
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
246
|
+
<AssistantThemeScope theme="dark" style={{ height: 720 }}>
|
|
247
|
+
<AssistantExperienceView
|
|
248
|
+
controller={assistant}
|
|
249
|
+
title="Support Assistant"
|
|
250
|
+
subtitle="Direct use of the default assistant experience."
|
|
251
|
+
placeholder="Message Support Assistant"
|
|
252
|
+
showConversationList
|
|
253
|
+
chromeStyle="subtle"
|
|
254
|
+
statusPlacement="inline"
|
|
255
|
+
/>
|
|
256
|
+
</AssistantThemeScope>
|
|
267
257
|
);
|
|
268
258
|
}
|
|
269
259
|
```
|
|
270
260
|
|
|
271
|
-
|
|
261
|
+
Useful props on `AssistantExperienceView`:
|
|
262
|
+
|
|
263
|
+
- `showConversationList`: show the built-in conversation sidebar
|
|
264
|
+
- `chromeStyle`: `"elevated" | "subtle" | "flat"`
|
|
265
|
+
- `statusPlacement`: `"inline" | "composer" | "none"`
|
|
266
|
+
- `renderMessageContent`: override markdown rendering for custom message content
|
|
267
|
+
- `renderToolInvocation`: replace the default tool activity renderer
|
|
268
|
+
- `renderPresentedFile` and `renderPendingFile`: customize attachment rendering
|
|
269
|
+
|
|
270
|
+
##### 3. `useAssistantController` + primitives for a custom shell
|
|
271
|
+
|
|
272
|
+
Use the primitives when you want full control over layout and app chrome.
|
|
272
273
|
|
|
273
274
|
```tsx
|
|
274
275
|
import "lemma-sdk/react/styles.css";
|
|
@@ -278,29 +279,109 @@ import {
|
|
|
278
279
|
AssistantMessageViewport,
|
|
279
280
|
AssistantShellLayout,
|
|
280
281
|
AssistantThemeScope,
|
|
282
|
+
MessageGroup,
|
|
283
|
+
PlanSummaryStrip,
|
|
284
|
+
ThinkingIndicator,
|
|
285
|
+
buildDisplayMessageRows,
|
|
286
|
+
getActiveToolBanner,
|
|
287
|
+
latestPlanSummary,
|
|
288
|
+
useAssistantController,
|
|
281
289
|
} from "lemma-sdk/react";
|
|
282
290
|
|
|
283
291
|
function CustomAssistantShell() {
|
|
292
|
+
const assistant = useAssistantController({
|
|
293
|
+
client,
|
|
294
|
+
podId: "pod_123",
|
|
295
|
+
assistantId: "uuid",
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const rows = buildDisplayMessageRows(assistant.messages);
|
|
299
|
+
const plan = latestPlanSummary(assistant.messages);
|
|
300
|
+
const activeToolBanner = getActiveToolBanner(assistant.messages);
|
|
301
|
+
|
|
284
302
|
return (
|
|
285
|
-
<AssistantThemeScope>
|
|
303
|
+
<AssistantThemeScope theme="auto" style={{ height: 720 }}>
|
|
286
304
|
<AssistantShellLayout
|
|
287
|
-
main={
|
|
305
|
+
main={(
|
|
288
306
|
<div className="flex min-h-0 flex-1 flex-col gap-3">
|
|
289
|
-
<AssistantHeader
|
|
307
|
+
<AssistantHeader
|
|
308
|
+
title="Lemma Assistant"
|
|
309
|
+
subtitle="Ask anything"
|
|
310
|
+
/>
|
|
311
|
+
|
|
312
|
+
{plan ? <PlanSummaryStrip plan={plan} onHide={() => {}} /> : null}
|
|
313
|
+
{activeToolBanner ? <div>{activeToolBanner.summary}</div> : null}
|
|
314
|
+
|
|
290
315
|
<AssistantMessageViewport>
|
|
291
|
-
|
|
316
|
+
{rows.map((row, index) => (
|
|
317
|
+
<MessageGroup
|
|
318
|
+
key={row.id}
|
|
319
|
+
message={row.message}
|
|
320
|
+
conversationId={assistant.activeConversationId}
|
|
321
|
+
onWidgetSendPrompt={(text) => assistant.sendMessage(text)}
|
|
322
|
+
isStreaming={assistant.isActiveConversationRunning && row.sourceIndexes.includes(assistant.messages.length - 1)}
|
|
323
|
+
showAssistantHeader={index === 0 || rows[index - 1]?.message.role !== "assistant"}
|
|
324
|
+
renderMessageContent={({ message }) => <div>{message.content}</div>}
|
|
325
|
+
/>
|
|
326
|
+
))}
|
|
327
|
+
|
|
328
|
+
{assistant.isActiveConversationRunning ? <ThinkingIndicator /> : null}
|
|
292
329
|
</AssistantMessageViewport>
|
|
330
|
+
|
|
293
331
|
<AssistantComposer>
|
|
294
332
|
<textarea placeholder="Message Lemma Assistant" />
|
|
295
333
|
</AssistantComposer>
|
|
296
334
|
</div>
|
|
297
|
-
}
|
|
335
|
+
)}
|
|
298
336
|
/>
|
|
299
337
|
</AssistantThemeScope>
|
|
300
338
|
);
|
|
301
339
|
}
|
|
302
340
|
```
|
|
303
341
|
|
|
342
|
+
Useful primitives exported from `lemma-sdk/react`:
|
|
343
|
+
|
|
344
|
+
- `AssistantThemeScope`
|
|
345
|
+
- `AssistantHeader`
|
|
346
|
+
- `AssistantConversationList`
|
|
347
|
+
- `AssistantModelPicker`
|
|
348
|
+
- `AssistantShellLayout`
|
|
349
|
+
- `AssistantComposer`
|
|
350
|
+
- `AssistantMessageViewport`
|
|
351
|
+
- `AssistantAskOverlay`
|
|
352
|
+
- `AssistantPendingFileChip`
|
|
353
|
+
- `AssistantStatusPill`
|
|
354
|
+
- `MessageGroup`
|
|
355
|
+
- `PlanSummaryStrip`
|
|
356
|
+
- `ThinkingIndicator`
|
|
357
|
+
|
|
358
|
+
#### Theming
|
|
359
|
+
|
|
360
|
+
Use `AssistantThemeScope` around custom assistant layouts:
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
import { AssistantThemeScope } from "lemma-sdk/react";
|
|
364
|
+
|
|
365
|
+
<AssistantThemeScope theme="light">
|
|
366
|
+
<YourAssistant />
|
|
367
|
+
</AssistantThemeScope>
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Theme behavior:
|
|
371
|
+
|
|
372
|
+
- `theme="auto"`: follows host dark-mode selectors and system color scheme
|
|
373
|
+
- `theme="light"`: forces the light SDK palette
|
|
374
|
+
- `theme="dark"`: forces the dark SDK palette
|
|
375
|
+
|
|
376
|
+
If you use `AssistantEmbedded`, pass `theme` directly on that component instead of wrapping it again.
|
|
377
|
+
|
|
378
|
+
#### What belongs in the SDK vs your app
|
|
379
|
+
|
|
380
|
+
The intended split is:
|
|
381
|
+
|
|
382
|
+
- SDK: `useAssistantController`, message/tool normalization, markdown rendering, plan parsing, tool rollups, and reusable assistant UI primitives
|
|
383
|
+
- App: modal shell, fullscreen/window controls, route navigation, workspace/file viewers, and product-specific renderers
|
|
384
|
+
|
|
304
385
|
### Assistant names (resource key)
|
|
305
386
|
|
|
306
387
|
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;
|
|
@@ -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,
|
|
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,
|
|
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
|
|
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: "
|
|
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(--
|
|
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-[
|
|
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-[
|
|
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-[
|
|
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
|
-
|
|
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
|
-
|
|
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: [
|
|
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
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
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
|
}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/react/styles.css
CHANGED
|
@@ -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,272 @@
|
|
|
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
|
+
}
|
|
90
|
+
|
|
91
|
+
:where(.dark, [data-theme="dark"], [data-color-scheme="dark"], [data-mode="dark"]) .lemma-assistant-theme:not([data-lemma-theme="light"]),
|
|
92
|
+
.lemma-assistant-theme[data-lemma-theme="dark"] {
|
|
93
|
+
color-scheme: dark;
|
|
94
|
+
--bg-canvas: #12100d;
|
|
95
|
+
--bg-surface: #1b1814;
|
|
96
|
+
--bg-subtle: #272118;
|
|
97
|
+
--border-default: #3d3428;
|
|
98
|
+
--border-subtle: #2d261d;
|
|
99
|
+
--text-primary: #f5ede0;
|
|
100
|
+
--text-secondary: #d0c3b1;
|
|
101
|
+
--text-tertiary: #988d7d;
|
|
102
|
+
--text-inverse: #15120f;
|
|
103
|
+
--text-on-brand: #15120f;
|
|
104
|
+
--brand-primary: #ead9b3;
|
|
105
|
+
--brand-secondary: #8daa73;
|
|
106
|
+
--brand-accent: #d9a44b;
|
|
107
|
+
--brand-glow: #2d2418;
|
|
108
|
+
--state-success: #7cbc72;
|
|
109
|
+
--state-error: #ec8d74;
|
|
110
|
+
--state-info: #7eb8f5;
|
|
111
|
+
--state-warning: #e0b45d;
|
|
112
|
+
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.32);
|
|
113
|
+
--shadow-sm: 0 10px 26px rgba(0, 0, 0, 0.32);
|
|
114
|
+
--shadow-md: 0 20px 40px rgba(0, 0, 0, 0.4);
|
|
115
|
+
--shadow-lg: 0 28px 56px rgba(0, 0, 0, 0.5);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.lemma-assistant-embedded {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
min-height: 0;
|
|
122
|
+
height: 100%;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.lemma-assistant-markdown {
|
|
126
|
+
color: inherit;
|
|
127
|
+
line-height: 1.7;
|
|
128
|
+
word-break: break-word;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.lemma-assistant-markdown > :first-child {
|
|
132
|
+
margin-top: 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.lemma-assistant-markdown > :last-child {
|
|
136
|
+
margin-bottom: 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.lemma-assistant-markdown p,
|
|
140
|
+
.lemma-assistant-markdown ul,
|
|
141
|
+
.lemma-assistant-markdown ol,
|
|
142
|
+
.lemma-assistant-markdown pre,
|
|
143
|
+
.lemma-assistant-markdown blockquote,
|
|
144
|
+
.lemma-assistant-markdown table,
|
|
145
|
+
.lemma-assistant-markdown hr {
|
|
146
|
+
margin: 0 0 0.95em;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.lemma-assistant-markdown h1,
|
|
150
|
+
.lemma-assistant-markdown h2,
|
|
151
|
+
.lemma-assistant-markdown h3,
|
|
152
|
+
.lemma-assistant-markdown h4 {
|
|
153
|
+
margin: 1.15em 0 0.55em;
|
|
154
|
+
line-height: 1.25;
|
|
155
|
+
color: var(--text-primary);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.lemma-assistant-markdown h1 {
|
|
159
|
+
font-size: 1.4rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.lemma-assistant-markdown h2 {
|
|
163
|
+
font-size: 1.2rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.lemma-assistant-markdown h3 {
|
|
167
|
+
font-size: 1.05rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.lemma-assistant-markdown h4 {
|
|
171
|
+
font-size: 0.95rem;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.lemma-assistant-markdown ul,
|
|
175
|
+
.lemma-assistant-markdown ol {
|
|
176
|
+
padding-left: 1.35rem;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.lemma-assistant-markdown ul {
|
|
180
|
+
list-style: disc;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.lemma-assistant-markdown ol {
|
|
184
|
+
list-style: decimal;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.lemma-assistant-markdown li + li {
|
|
188
|
+
margin-top: 0.3rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.lemma-assistant-markdown li > ul,
|
|
192
|
+
.lemma-assistant-markdown li > ol {
|
|
193
|
+
margin-top: 0.35rem;
|
|
194
|
+
margin-bottom: 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.lemma-assistant-markdown a {
|
|
198
|
+
color: var(--state-info);
|
|
199
|
+
text-decoration: underline;
|
|
200
|
+
text-decoration-color: color-mix(in srgb, var(--state-info) 56%, transparent);
|
|
201
|
+
text-underline-offset: 0.16em;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.lemma-assistant-markdown a:hover {
|
|
205
|
+
color: color-mix(in srgb, var(--state-info) 82%, var(--text-primary));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.lemma-assistant-markdown strong {
|
|
209
|
+
color: var(--text-primary);
|
|
210
|
+
font-weight: 650;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.lemma-assistant-markdown em {
|
|
214
|
+
color: var(--text-secondary);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.lemma-assistant-markdown hr {
|
|
218
|
+
border: 0;
|
|
219
|
+
border-top: 1px solid color-mix(in srgb, var(--border-default) 88%, transparent);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.lemma-assistant-markdown blockquote {
|
|
223
|
+
padding: 0.15rem 0 0.15rem 0.9rem;
|
|
224
|
+
border-left: 3px solid color-mix(in srgb, var(--brand-accent) 60%, var(--border-default));
|
|
225
|
+
color: var(--text-secondary);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.lemma-assistant-markdown :not(pre) > code {
|
|
229
|
+
display: inline-block;
|
|
230
|
+
margin: 0 0.08rem;
|
|
231
|
+
padding: 0.1rem 0.42rem;
|
|
232
|
+
border: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
|
|
233
|
+
border-radius: 999px;
|
|
234
|
+
background: color-mix(in srgb, var(--bg-subtle) 88%, transparent);
|
|
235
|
+
color: var(--text-primary);
|
|
236
|
+
font-size: 0.92em;
|
|
237
|
+
line-height: 1.45;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.lemma-assistant-markdown pre {
|
|
241
|
+
overflow-x: auto;
|
|
242
|
+
padding: 0.9rem 1rem;
|
|
243
|
+
border: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
|
|
244
|
+
border-radius: 16px;
|
|
245
|
+
background: color-mix(in srgb, var(--bg-canvas) 74%, var(--bg-surface));
|
|
246
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--bg-surface) 60%, transparent);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.lemma-assistant-markdown pre code {
|
|
250
|
+
padding: 0;
|
|
251
|
+
border: 0;
|
|
252
|
+
background: transparent;
|
|
253
|
+
color: inherit;
|
|
254
|
+
font-size: 0.92em;
|
|
255
|
+
line-height: 1.65;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.lemma-assistant-markdown table {
|
|
259
|
+
display: block;
|
|
260
|
+
width: 100%;
|
|
261
|
+
overflow-x: auto;
|
|
262
|
+
border-collapse: separate;
|
|
263
|
+
border-spacing: 0;
|
|
264
|
+
border: 1px solid color-mix(in srgb, var(--border-default) 82%, transparent);
|
|
265
|
+
border-radius: 16px;
|
|
266
|
+
background: color-mix(in srgb, var(--bg-surface) 96%, transparent);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.lemma-assistant-markdown thead {
|
|
270
|
+
background: color-mix(in srgb, var(--bg-subtle) 76%, transparent);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.lemma-assistant-markdown th,
|
|
274
|
+
.lemma-assistant-markdown td {
|
|
275
|
+
padding: 0.7rem 0.85rem;
|
|
276
|
+
border-bottom: 1px solid color-mix(in srgb, var(--border-default) 72%, transparent);
|
|
277
|
+
text-align: left;
|
|
278
|
+
vertical-align: top;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.lemma-assistant-markdown tr:last-child td {
|
|
282
|
+
border-bottom: 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.lemma-assistant-markdown img {
|
|
286
|
+
max-width: 100%;
|
|
287
|
+
border-radius: 14px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown,
|
|
291
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown h1,
|
|
292
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown h2,
|
|
293
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown h3,
|
|
294
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown h4,
|
|
295
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown strong,
|
|
296
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown em,
|
|
297
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown a,
|
|
298
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown code,
|
|
299
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown pre code {
|
|
300
|
+
color: inherit;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown a {
|
|
304
|
+
text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown blockquote {
|
|
308
|
+
border-left-color: color-mix(in srgb, currentColor 34%, transparent);
|
|
309
|
+
color: inherit;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown :not(pre) > code {
|
|
313
|
+
border-color: color-mix(in srgb, currentColor 18%, transparent);
|
|
314
|
+
background: color-mix(in srgb, currentColor 10%, transparent);
|
|
315
|
+
color: inherit;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.lemma-assistant-message-user-bubble .lemma-assistant-markdown pre {
|
|
319
|
+
border-color: color-mix(in srgb, currentColor 18%, transparent);
|
|
320
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
321
|
+
}
|
|
322
|
+
|
|
56
323
|
.lemma-assistant-shell,
|
|
57
324
|
.lemma-assistant-experience,
|
|
58
325
|
.lemma-assistant-shell-sidebar,
|
|
@@ -95,6 +362,24 @@
|
|
|
95
362
|
align-items: center;
|
|
96
363
|
justify-content: space-between;
|
|
97
364
|
gap: 12px;
|
|
365
|
+
background: transparent;
|
|
366
|
+
border-bottom: 0;
|
|
367
|
+
box-shadow: none;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
.lemma-assistant-header[data-tone="default"],
|
|
372
|
+
.lemma-assistant-experience-header[data-tone="default"] {
|
|
373
|
+
background: var(--bg-surface);
|
|
374
|
+
border-bottom: 1px solid var(--border-default);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.lemma-assistant-header[data-tone="flat"],
|
|
378
|
+
.lemma-assistant-experience-header[data-tone="flat"] {
|
|
379
|
+
background: transparent;
|
|
380
|
+
border-bottom: 0;
|
|
381
|
+
box-shadow: none;
|
|
382
|
+
padding-bottom: 0;
|
|
98
383
|
}
|
|
99
384
|
|
|
100
385
|
.lemma-assistant-header-copy,
|
|
@@ -177,6 +462,8 @@
|
|
|
177
462
|
.lemma-assistant-experience-model-picker {
|
|
178
463
|
appearance: none;
|
|
179
464
|
min-width: 132px;
|
|
465
|
+
border-color: transparent;
|
|
466
|
+
background: color-mix(in srgb, var(--bg-surface) 88%, transparent);
|
|
180
467
|
}
|
|
181
468
|
|
|
182
469
|
.lemma-assistant-viewport,
|
|
@@ -198,6 +485,22 @@
|
|
|
198
485
|
box-shadow: var(--shadow-md);
|
|
199
486
|
}
|
|
200
487
|
|
|
488
|
+
|
|
489
|
+
.lemma-assistant-composer[data-tone="subtle"],
|
|
490
|
+
.lemma-assistant-experience-composer[data-tone="subtle"] {
|
|
491
|
+
background: color-mix(in srgb, var(--bg-surface) 96%, transparent);
|
|
492
|
+
border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
|
|
493
|
+
box-shadow: var(--shadow-sm);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.lemma-assistant-composer[data-tone="flat"],
|
|
497
|
+
.lemma-assistant-experience-composer[data-tone="flat"] {
|
|
498
|
+
background: transparent;
|
|
499
|
+
border-color: transparent;
|
|
500
|
+
box-shadow: none;
|
|
501
|
+
padding: 0;
|
|
502
|
+
}
|
|
503
|
+
|
|
201
504
|
.lemma-assistant-composer-floating,
|
|
202
505
|
.lemma-assistant-experience-plan {
|
|
203
506
|
position: absolute;
|
|
@@ -205,6 +508,7 @@
|
|
|
205
508
|
right: 0;
|
|
206
509
|
bottom: calc(100% + 8px);
|
|
207
510
|
z-index: 20;
|
|
511
|
+
pointer-events: auto;
|
|
208
512
|
}
|
|
209
513
|
|
|
210
514
|
.lemma-assistant-composer-status-rail {
|
|
@@ -223,6 +527,41 @@
|
|
|
223
527
|
gap: 6px;
|
|
224
528
|
}
|
|
225
529
|
|
|
530
|
+
.lemma-assistant-conversation-list-new,
|
|
531
|
+
.lemma-assistant-experience-sidebar-new {
|
|
532
|
+
border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
.lemma-assistant-experience-new,
|
|
537
|
+
.lemma-assistant-conversation-list-new,
|
|
538
|
+
.lemma-assistant-experience-sidebar-new {
|
|
539
|
+
background: color-mix(in srgb, var(--bg-surface) 90%, transparent);
|
|
540
|
+
backdrop-filter: blur(12px);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.lemma-assistant-experience-new {
|
|
544
|
+
border: 0;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.lemma-assistant-experience[data-chrome-style="subtle"] .lemma-assistant-experience-card,
|
|
548
|
+
.lemma-assistant-experience[data-chrome-style="subtle"] .lemma-assistant-experience-sidebar {
|
|
549
|
+
box-shadow: var(--shadow-md);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.lemma-assistant-experience[data-chrome-style="flat"] .lemma-assistant-experience-card,
|
|
553
|
+
.lemma-assistant-experience[data-chrome-style="flat"] .lemma-assistant-experience-sidebar {
|
|
554
|
+
background: transparent;
|
|
555
|
+
border-color: transparent;
|
|
556
|
+
box-shadow: none;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.lemma-assistant-plan-strip {
|
|
560
|
+
background: var(--bg-surface);
|
|
561
|
+
border-color: color-mix(in srgb, var(--border-default) 88%, transparent);
|
|
562
|
+
box-shadow: var(--shadow-sm);
|
|
563
|
+
}
|
|
564
|
+
|
|
226
565
|
.lemma-assistant-pending-file-chip {
|
|
227
566
|
display: inline-flex;
|
|
228
567
|
align-items: center;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lemma-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.18",
|
|
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": {
|