lemma-sdk 0.2.19 → 0.2.21

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.
Files changed (40) hide show
  1. package/README.md +71 -33
  2. package/dist/auth.d.ts +42 -1
  3. package/dist/auth.js +43 -0
  4. package/dist/browser/lemma-client.js +49 -1
  5. package/dist/browser.d.ts +1 -1
  6. package/dist/browser.js +1 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +1 -1
  9. package/dist/namespaces/assistants.d.ts +2 -0
  10. package/dist/namespaces/assistants.js +3 -0
  11. package/dist/openapi_client/index.d.ts +3 -0
  12. package/dist/openapi_client/index.js +1 -0
  13. package/dist/openapi_client/models/AvailableModelInfo.d.ts +8 -0
  14. package/dist/openapi_client/models/AvailableModelInfo.js +1 -0
  15. package/dist/openapi_client/models/AvailableModels.d.ts +3 -4
  16. package/dist/openapi_client/models/AvailableModels.js +2 -3
  17. package/dist/openapi_client/models/AvailableModelsListResponse.d.ts +7 -0
  18. package/dist/openapi_client/models/AvailableModelsListResponse.js +1 -0
  19. package/dist/openapi_client/models/BulkCreateRecordsRequest.d.ts +4 -0
  20. package/dist/openapi_client/models/CreateFunctionRequest.d.ts +2 -0
  21. package/dist/openapi_client/models/FunctionResponse.d.ts +2 -0
  22. package/dist/openapi_client/models/FunctionRunResponse.d.ts +4 -0
  23. package/dist/openapi_client/models/FunctionType.d.ts +7 -0
  24. package/dist/openapi_client/models/FunctionType.js +12 -0
  25. package/dist/openapi_client/models/UpdateFunctionRequest.d.ts +2 -0
  26. package/dist/openapi_client/services/ConversationsService.d.ts +8 -0
  27. package/dist/openapi_client/services/ConversationsService.js +12 -0
  28. package/dist/react/components/AssistantChrome.js +13 -23
  29. package/dist/react/components/AssistantExperience.d.ts +12 -4
  30. package/dist/react/components/AssistantExperience.js +40 -40
  31. package/dist/react/components/assistant-types.d.ts +7 -0
  32. package/dist/react/index.d.ts +3 -3
  33. package/dist/react/index.js +1 -1
  34. package/dist/react/styles.css +1246 -5
  35. package/dist/react/useAssistantController.d.ts +2 -1
  36. package/dist/react/useAssistantController.js +34 -1
  37. package/dist/react/useAssistantRuntime.js +25 -4
  38. package/dist/react/useAssistantSession.js +14 -5
  39. package/dist/types.d.ts +1 -1
  40. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import type { ApplicationAccessConfig } from './ApplicationAccessConfig.js';
2
+ import type { FunctionType } from './FunctionType.js';
2
3
  import type { TableAccessEntry } from './TableAccessEntry.js';
3
4
  /**
4
5
  * Request to update a function.
@@ -11,4 +12,5 @@ export type UpdateFunctionRequest = {
11
12
  config?: (Record<string, any> | null);
12
13
  description?: (string | null);
13
14
  icon_url?: (string | null);
15
+ type?: (FunctionType | null);
14
16
  };
@@ -1,3 +1,4 @@
1
+ import type { AvailableModelsListResponse } from '../models/AvailableModelsListResponse.js';
1
2
  import type { ConversationListResponse } from '../models/ConversationListResponse.js';
2
3
  import type { ConversationMessageListResponse } from '../models/ConversationMessageListResponse.js';
3
4
  import type { ConversationResponse } from '../models/ConversationResponse.js';
@@ -76,4 +77,11 @@ export declare class ConversationsService {
76
77
  * @throws ApiError
77
78
  */
78
79
  static conversationStreamResume(conversationId: string, podId?: (string | null)): CancelablePromise<any>;
80
+ /**
81
+ * List Available Models
82
+ * Get list of all available models in the system.
83
+ * @returns AvailableModelsListResponse Successful Response
84
+ * @throws ApiError
85
+ */
86
+ static conversationModelsList(): CancelablePromise<AvailableModelsListResponse>;
79
87
  }
@@ -185,4 +185,16 @@ export class ConversationsService {
185
185
  },
186
186
  });
187
187
  }
188
+ /**
189
+ * List Available Models
190
+ * Get list of all available models in the system.
191
+ * @returns AvailableModelsListResponse Successful Response
192
+ * @throws ApiError
193
+ */
194
+ static conversationModelsList() {
195
+ return __request(OpenAPI, {
196
+ method: 'GET',
197
+ url: '/models',
198
+ });
199
+ }
188
200
  }
@@ -7,52 +7,42 @@ export function AssistantThemeScope({ className, children, theme = "auto", ...pr
7
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
- 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 }) }));
10
+ return (_jsx("div", { ref: ref, className: cx("lemma-assistant-viewport", className), ...props, children: _jsx("div", { className: cx("lemma-assistant-viewport-inner", innerClassName), children: children }) }));
11
11
  });
12
12
  export function AssistantShellLayout({ sidebar, sidebarVisible = false, main, className, }) {
13
13
  const hasSidebar = !!sidebar;
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] }));
14
+ return (_jsxs("div", { className: cx("lemma-assistant-shell", hasSidebar && "lemma-assistant-shell--with-sidebar", hasSidebar && sidebarVisible && "lemma-assistant-shell--sidebar-visible", className), children: [sidebar && sidebarVisible ? (_jsx("div", { className: "lemma-assistant-shell-sidebar", children: sidebar })) : null, main] }));
15
15
  }
16
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] }));
17
+ return (_jsxs("div", { "data-tone": tone, className: cx("lemma-assistant-header", className), children: [_jsxs("div", { className: "lemma-assistant-header-copy", children: [badge ? (_jsx("div", { className: "lemma-assistant-header-badge", children: badge })) : null, _jsxs("div", { className: "lemma-assistant-header-titles", children: [_jsx("h3", { className: "lemma-assistant-header-title", children: title }), subtitle ? (_jsx("p", { className: "lemma-assistant-header-subtitle", children: subtitle })) : null] })] }), controls ? (_jsx("div", { className: "lemma-assistant-header-controls", children: controls })) : null] }));
18
18
  }
19
19
  export function AssistantConversationList({ conversations, activeConversationId, onSelectConversation, onNewConversation, renderConversationLabel, title = "Conversations", newLabel = "New", className, }) {
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) => {
20
+ return (_jsxs("aside", { className: cx("lemma-assistant-conversation-list", className), children: [_jsx("div", { className: "lemma-assistant-conversation-list-header", children: _jsxs("div", { className: "lemma-assistant-conversation-list-header-row", children: [_jsxs("div", { className: "lemma-assistant-conversation-list-copy", children: [_jsx("div", { className: "lemma-assistant-conversation-list-title", children: title }), _jsxs("div", { className: "lemma-assistant-conversation-list-meta", children: [conversations.length, " total"] })] }), onNewConversation ? (_jsx("button", { type: "button", onClick: onNewConversation, className: "lemma-assistant-conversation-list-new", children: newLabel })) : null] }) }), _jsx("div", { className: "lemma-assistant-conversation-list-items", children: conversations.map((conversation) => {
21
21
  const isActive = conversation.id === activeConversationId;
22
- return (_jsxs("button", { type: "button", onClick: () => onSelectConversation(conversation.id), className: cx("lemma-assistant-conversation-list-item", "w-full rounded-xl border px-3 py-2.5 text-left transition-colors", isActive
23
- ? "lemma-assistant-conversation-list-item-active border-[color:color-mix(in_srgb,_var(--brand-primary)_44%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_42%,_var(--bg-surface))]"
24
- : "border-[var(--border-default)] bg-[var(--bg-surface)] hover:bg-[var(--bg-subtle)]"), children: [_jsx("div", { className: "lemma-assistant-conversation-list-item-title truncate text-[12px] font-medium text-[var(--text-primary)]", children: renderConversationLabel
22
+ return (_jsxs("button", { type: "button", onClick: () => onSelectConversation(conversation.id), className: cx("lemma-assistant-conversation-list-item", isActive && "lemma-assistant-conversation-list-item-active"), children: [_jsx("div", { className: "lemma-assistant-conversation-list-item-title", children: renderConversationLabel
25
23
  ? renderConversationLabel({ conversation, isActive })
26
- : (conversation.title || "Untitled conversation") }), _jsx("div", { className: "lemma-assistant-conversation-list-item-status mt-1 text-[10px] uppercase tracking-[0.08em] text-[var(--text-tertiary)]", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
24
+ : (conversation.title || "Untitled conversation") }), _jsx("div", { className: "lemma-assistant-conversation-list-item-status", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
27
25
  }) })] }));
28
26
  }
29
27
  export function AssistantModelPicker({ value, options, disabled, autoLabel = "Auto", getOptionLabel, onChange, className, }) {
30
28
  const autoValue = "__AUTO__";
31
- return (_jsxs("select", { value: value ?? autoValue, onChange: (event) => onChange(event.target.value === autoValue ? null : event.target.value), disabled: disabled, className: cx("lemma-assistant-model-picker", "h-8 rounded-full border border-[color:color-mix(in_srgb,_var(--border-default)_80%,_transparent)] bg-[var(--bg-surface)] px-3 text-[11px] text-[var(--text-secondary)]", className), "aria-label": "Conversation model", title: "Conversation model", children: [_jsx("option", { value: autoValue, children: autoLabel }), options.map((option) => (_jsx("option", { value: option, children: getOptionLabel ? getOptionLabel(option) : option }, option)))] }));
29
+ return (_jsxs("select", { value: value ?? autoValue, onChange: (event) => onChange(event.target.value === autoValue ? null : event.target.value), disabled: disabled, className: cx("lemma-assistant-model-picker", className), "aria-label": "Conversation model", title: "Conversation model", children: [_jsx("option", { value: autoValue, children: autoLabel }), options.map((option) => (_jsx("option", { value: option, children: getOptionLabel ? getOptionLabel(option) : option }, option)))] }));
32
30
  }
33
31
  export function AssistantAskOverlay({ questionNumber, totalQuestions, question, options, selectedOptions, canContinue, continueLabel, onSelectOption, onContinue, onSkip, mode = "single_select", }) {
34
- return (_jsxs("div", { className: "lemma-assistant-ask-overlay space-y-2", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-header flex items-start justify-between gap-3", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-copy", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-kicker text-[11px] uppercase tracking-[0.12em] text-[var(--text-tertiary)]", children: ["Question ", questionNumber, " of ", totalQuestions] }), _jsx("p", { className: "lemma-assistant-ask-overlay-question mt-1 text-[14px] font-medium leading-6 text-[var(--text-primary)]", children: question })] }), onSkip ? (_jsx("button", { type: "button", onClick: onSkip, className: "lemma-assistant-ask-overlay-skip rounded-md px-2 py-1 text-[12px] text-[var(--text-tertiary)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text-primary)]", children: "Skip" })) : null] }), _jsx("div", { className: "lemma-assistant-ask-overlay-options max-h-[260px] space-y-1.5 overflow-y-auto pr-1", children: options.map((option, optionIndex) => {
32
+ return (_jsxs("div", { className: "lemma-assistant-ask-overlay", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-header", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-copy", children: [_jsxs("div", { className: "lemma-assistant-ask-overlay-kicker", children: ["Question ", questionNumber, " of ", totalQuestions] }), _jsx("p", { className: "lemma-assistant-ask-overlay-question", children: question })] }), onSkip ? (_jsx("button", { type: "button", onClick: onSkip, className: "lemma-assistant-ask-overlay-skip", children: "Skip" })) : null] }), _jsx("div", { className: "lemma-assistant-ask-overlay-options", children: options.map((option, optionIndex) => {
35
33
  const isSelected = selectedOptions.includes(option);
36
34
  const rankLabel = mode === "rank_priorities" && isSelected
37
35
  ? selectedOptions.indexOf(option) + 1
38
36
  : null;
39
- return (_jsx("button", { type: "button", onClick: () => onSelectOption(option), className: cx("lemma-assistant-ask-overlay-option", "w-full rounded-lg border px-2.5 py-2 text-left text-[13px] transition-colors", isSelected
40
- ? "lemma-assistant-ask-overlay-option-selected border-[color:color-mix(in_srgb,_var(--brand-primary)_64%,_var(--border-subtle))] bg-[color:color-mix(in_srgb,_var(--brand-primary)_14%,_transparent)] text-[var(--text-primary)]"
41
- : "border-[var(--border-default)] bg-[var(--bg-canvas)] text-[var(--text-secondary)] hover:bg-[var(--bg-subtle)] hover:text-[var(--text-primary)]"), children: _jsxs("span", { className: "lemma-assistant-ask-overlay-option-label inline-flex items-center gap-2", children: [rankLabel ? (_jsx("span", { className: "inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-[var(--brand-primary)] px-1 text-[10px] font-semibold text-[var(--text-on-brand)]", children: rankLabel })) : (_jsx("span", { className: cx("inline-block h-2.5 w-2.5 rounded-full border", isSelected
42
- ? "border-[var(--brand-primary)] bg-[var(--brand-primary)]"
43
- : "border-[var(--border-default)] bg-transparent") })), option] }) }, `${option}-${optionIndex}`));
44
- }) }), onContinue ? (_jsx("div", { className: "lemma-assistant-ask-overlay-actions flex justify-end", children: _jsx("button", { type: "button", onClick: onContinue, disabled: !canContinue, className: cx("lemma-assistant-ask-overlay-continue", "rounded-md px-2.5 py-1.5 text-[12px] font-medium transition-colors", canContinue
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
- : "bg-[var(--bg-subtle)] text-[var(--text-tertiary)]"), children: continueLabel }) })) : null] }));
37
+ return (_jsx("button", { type: "button", onClick: () => onSelectOption(option), className: cx("lemma-assistant-ask-overlay-option", isSelected && "lemma-assistant-ask-overlay-option-selected"), children: _jsxs("span", { className: "lemma-assistant-ask-overlay-option-label", children: [rankLabel ? (_jsx("span", { className: "lemma-assistant-ask-overlay-option-rank", children: rankLabel })) : (_jsx("span", { className: cx("lemma-assistant-ask-overlay-option-indicator", isSelected && "lemma-assistant-ask-overlay-option-indicator-selected") })), option] }) }, `${option}-${optionIndex}`));
38
+ }) }), onContinue ? (_jsx("div", { className: "lemma-assistant-ask-overlay-actions", children: _jsx("button", { type: "button", onClick: onContinue, disabled: !canContinue, className: cx("lemma-assistant-ask-overlay-continue", canContinue && "lemma-assistant-ask-overlay-continue-enabled"), children: continueLabel }) })) : null] }));
47
39
  }
48
40
  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 })] }));
41
+ 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", className), children: [floating ? (_jsx("div", { className: "lemma-assistant-composer-floating", children: floating })) : null, status ? (_jsx("div", { className: "lemma-assistant-composer-status-rail", children: _jsx("div", { className: "lemma-assistant-composer-status", children: status }) })) : null, pendingFiles ? (_jsx("div", { className: "lemma-assistant-composer-pending", children: pendingFiles })) : null, _jsx("div", { className: "lemma-assistant-composer-body", children: children })] }));
50
42
  }
51
43
  export function AssistantPendingFileChip({ label, onRemove, className, }) {
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] }));
44
+ return (_jsxs("span", { className: cx("lemma-assistant-pending-file-chip", className), children: [_jsx("span", { className: "lemma-assistant-pending-file-chip-label", children: label }), onRemove ? (_jsx("button", { type: "button", onClick: onRemove, className: "lemma-assistant-pending-file-chip-remove", title: "Remove file", children: "\u00D7" })) : null] }));
53
45
  }
54
46
  export function AssistantStatusPill({ label, subtle = false, className, }) {
55
- return (_jsxs("div", { className: cx("lemma-assistant-status-pill", "inline-flex min-h-[30px] max-w-full items-center gap-2 rounded-full px-3 py-1.5 text-[12px] transition-all duration-200", subtle
56
- ? "lemma-assistant-status-pill-subtle border border-[color:color-mix(in_srgb,_var(--border-default)_72%,_transparent)] bg-[color:color-mix(in_srgb,_var(--bg-surface)_90%,_transparent)] text-[var(--text-tertiary)]"
57
- : "border border-[color:color-mix(in_srgb,_var(--brand-primary)_24%,_var(--border-default))] bg-[color:color-mix(in_srgb,_var(--brand-glow)_28%,_var(--bg-surface))] text-[var(--text-secondary)]", className), children: [_jsxs("span", { className: "lemma-assistant-status-pill-dot relative inline-flex h-2.5 w-2.5 shrink-0", children: [_jsx("span", { className: "lemma-assistant-status-pill-dot-ping absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--brand-primary)]/45" }), _jsx("span", { className: "lemma-assistant-status-pill-dot-core relative inline-flex h-2.5 w-2.5 rounded-full bg-[var(--brand-primary)]" })] }), _jsx("span", { className: "lemma-assistant-status-pill-label truncate", children: label })] }));
47
+ return (_jsxs("div", { className: cx("lemma-assistant-status-pill", subtle && "lemma-assistant-status-pill-subtle", className), children: [_jsxs("span", { className: "lemma-assistant-status-pill-dot", children: [_jsx("span", { className: "lemma-assistant-status-pill-dot-ping" }), _jsx("span", { className: "lemma-assistant-status-pill-dot-core" })] }), _jsx("span", { className: "lemma-assistant-status-pill-label", children: label })] }));
58
48
  }
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
2
  import type { AssistantRenderableMessage, AssistantToolInvocation } from "../useAssistantController.js";
3
- import type { AssistantControllerView, AssistantConversationRenderArgs, AssistantMessageRenderArgs, AssistantPendingFileRenderArgs, AssistantPresentedFileRenderArgs, AssistantToolRenderArgs } from "./assistant-types.js";
3
+ import type { AssistantControllerView, AssistantConversationRenderArgs, AssistantMessageRenderArgs, AssistantPendingFileRenderArgs, AssistantPresentedFileRenderArgs, AssistantToolRenderArgs, EmptyStateSuggestion } from "./assistant-types.js";
4
4
  type PlanStatus = "pending" | "in_progress" | "completed";
5
5
  export interface PlanStepState {
6
6
  step: string;
@@ -35,17 +35,22 @@ export interface ActiveToolBanner {
35
35
  }
36
36
  export type AssistantChromeStyle = "elevated" | "subtle" | "flat";
37
37
  export type AssistantStatusPlacement = "inline" | "composer" | "none";
38
+ export type AssistantRadiusScale = "none" | "sm" | "md" | "lg" | "xl";
38
39
  export interface AssistantExperienceViewProps {
39
40
  controller: AssistantControllerView;
40
41
  title?: ReactNode;
41
42
  subtitle?: ReactNode;
42
43
  placeholder?: string;
43
44
  emptyState?: ReactNode;
45
+ emptyStateSuggestions?: EmptyStateSuggestion[];
44
46
  draft?: string;
45
47
  onDraftChange?: (value: string) => void;
46
48
  showConversationList?: boolean;
47
49
  chromeStyle?: AssistantChromeStyle;
48
50
  statusPlacement?: AssistantStatusPlacement;
51
+ radius?: AssistantRadiusScale;
52
+ showModelPicker?: boolean;
53
+ showNewConversationButton?: boolean;
49
54
  onNavigateResource?: (resourceType: string, resourceId: string, meta?: Record<string, unknown>) => void;
50
55
  renderConversationLabel?: (args: AssistantConversationRenderArgs) => ReactNode;
51
56
  renderMessageContent?: (args: AssistantMessageRenderArgs) => ReactNode;
@@ -65,9 +70,12 @@ export declare function PlanSummaryStrip({ plan, onHide }: {
65
70
  onHide: () => void;
66
71
  }): import("react/jsx-runtime").JSX.Element;
67
72
  export declare function ThinkingIndicator(): import("react/jsx-runtime").JSX.Element | null;
68
- export declare function EmptyState({ onSendMessage }: {
73
+ export interface EmptyStateProps {
69
74
  onSendMessage: (msg: string) => void;
70
- }): import("react/jsx-runtime").JSX.Element;
75
+ suggestions?: EmptyStateSuggestion[];
76
+ }
77
+ export declare const DEFAULT_EMPTY_STATE_SUGGESTIONS: EmptyStateSuggestion[];
78
+ export declare function EmptyState({ onSendMessage, suggestions, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
71
79
  export declare function MessageGroup({ message, conversationId, onNavigateResource, onWidgetSendPrompt, isStreaming, showAssistantHeader, renderMessageContent, renderPresentedFile, renderToolInvocation, }: {
72
80
  message: AssistantRenderableMessage;
73
81
  conversationId?: string | null;
@@ -79,5 +87,5 @@ export declare function MessageGroup({ message, conversationId, onNavigateResour
79
87
  renderPresentedFile?: (args: AssistantPresentedFileRenderArgs) => ReactNode;
80
88
  renderToolInvocation?: (args: AssistantToolRenderArgs) => ReactNode;
81
89
  }): 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;
90
+ export declare function AssistantExperienceView({ controller, title, subtitle, placeholder, emptyState, emptyStateSuggestions, draft: controlledDraft, onDraftChange, showConversationList, chromeStyle, statusPlacement, radius, showModelPicker, showNewConversationButton, onNavigateResource, renderConversationLabel, renderMessageContent, renderPresentedFile, renderPendingFile, renderToolInvocation, }: AssistantExperienceViewProps): import("react/jsx-runtime").JSX.Element;
83
91
  export {};
@@ -509,16 +509,16 @@ function defaultMessageContent({ message }) {
509
509
  return (_jsx("div", { className: "lemma-assistant-markdown", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], skipHtml: true, components: markdownComponents, children: message.content }) }));
510
510
  }
511
511
  function defaultPresentedFile({ filepath }) {
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 })] }));
512
+ return (_jsxs("div", { className: "lemma-assistant-presented-file-card", children: [_jsx("div", { className: "lemma-assistant-presented-file-name", children: fileNameFromPath(filepath) }), _jsx("div", { className: "lemma-assistant-presented-file-path", children: filepath })] }));
513
513
  }
514
514
  function defaultPendingFile({ file, remove }) {
515
- return (_jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-full bg-[var(--bg-subtle)] px-2 py-1 text-[11px] text-[var(--text-secondary)]", children: [_jsx("span", { className: "truncate max-w-[180px]", children: file.name }), _jsx("button", { type: "button", onClick: remove, className: "inline-flex h-4 w-4 items-center justify-center rounded-full hover:bg-[var(--bg-canvas)]", title: "Remove file", children: "\u00D7" })] }));
515
+ return (_jsxs("span", { className: "lemma-assistant-pending-file-chip", children: [_jsx("span", { className: "lemma-assistant-pending-file-chip-label", children: file.name }), _jsx("button", { type: "button", onClick: remove, className: "lemma-assistant-pending-file-chip-remove", title: "Remove file", children: "\u00D7" })] }));
516
516
  }
517
517
  export function PlanSummaryStrip({ plan, onHide }) {
518
518
  const [showAll, setShowAll] = useState(false);
519
519
  const visibleSteps = showAll ? plan.steps : plan.steps.slice(0, 5);
520
520
  const hiddenCount = Math.max(0, plan.steps.length - visibleSteps.length);
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] })] }));
521
+ return (_jsxs("div", { className: "lemma-assistant-plan-strip", children: [_jsxs("div", { className: "lemma-assistant-plan-strip-header", children: [_jsxs("div", { className: "lemma-assistant-plan-strip-summary", children: [_jsx("span", { className: "lemma-assistant-plan-strip-title", children: "Task plan" }), _jsxs("span", { className: "lemma-assistant-plan-strip-count", children: [plan.completedCount, "/", plan.steps.length, " complete"] }), plan.inProgressCount > 0 ? (_jsxs("span", { className: "lemma-assistant-plan-strip-active", children: [plan.inProgressCount, " active"] })) : null] }), _jsx("button", { type: "button", onClick: onHide, className: "lemma-assistant-plan-strip-hide", children: "Hide" })] }), plan.activeStep ? (_jsxs("div", { className: "lemma-assistant-plan-strip-current", title: plan.activeStep, children: [plan.running ? "Running:" : "Current:", " ", plan.activeStep] })) : null, _jsxs("div", { className: "lemma-assistant-plan-strip-steps", children: [visibleSteps.map((step, index) => (_jsxs("div", { className: "lemma-assistant-plan-strip-step", "data-status": step.status, children: [_jsx("span", { className: cx("lemma-assistant-plan-strip-step-dot", step.status === "completed" && "lemma-assistant-plan-strip-step-dot-completed", step.status === "in_progress" && "lemma-assistant-plan-strip-step-dot-in-progress", step.status === "pending" && "lemma-assistant-plan-strip-step-dot-pending") }), _jsx("span", { className: cx("lemma-assistant-plan-strip-step-label", step.status === "completed" && "lemma-assistant-plan-strip-step-label-completed", step.status === "in_progress" && "lemma-assistant-plan-strip-step-label-in-progress", step.status === "pending" && "lemma-assistant-plan-strip-step-label-pending"), children: step.step })] }, `${step.step}-${index}`))), plan.steps.length > 5 ? (_jsxs("div", { className: "lemma-assistant-plan-strip-footer", children: [_jsx("button", { type: "button", onClick: () => setShowAll((prev) => !prev), className: "lemma-assistant-plan-strip-toggle", children: showAll ? "Show less" : `See all ${plan.steps.length} steps` }), !showAll && hiddenCount > 0 ? (_jsxs("span", { className: "lemma-assistant-plan-strip-hidden-count", children: ["+", hiddenCount, " more"] })) : null] })) : null] })] }));
522
522
  }
523
523
  export function ThinkingIndicator() {
524
524
  const [show, setShow] = useState(false);
@@ -528,19 +528,19 @@ export function ThinkingIndicator() {
528
528
  }, []);
529
529
  if (!show)
530
530
  return null;
531
- return (_jsx("div", { className: "lemma-assistant-thinking px-1 animate-in fade-in duration-300", children: _jsxs("div", { className: "lemma-assistant-thinking-label inline-flex items-center gap-2.5 text-[12px] leading-5 text-[var(--text-tertiary)]", children: [_jsx("span", { className: "lemma-assistant-thinking-dot inline-flex h-2 w-2 rounded-full bg-[var(--brand-accent)]" }), _jsx("span", { className: "lemma-assistant-thinking-text font-semibold text-transparent bg-clip-text bg-[linear-gradient(110deg,var(--text-secondary),35%,var(--brand-accent),50%,var(--text-secondary),65%)] bg-[length:250%_100%] animate-pulse", children: "Thinking..." })] }) }));
531
+ return (_jsx("div", { className: "lemma-assistant-thinking", children: _jsxs("div", { className: "lemma-assistant-thinking-label", children: [_jsx("span", { className: "lemma-assistant-thinking-dot" }), _jsx("span", { className: "lemma-assistant-thinking-text", children: "Thinking..." })] }) }));
532
532
  }
533
- export function EmptyState({ onSendMessage }) {
534
- const suggestions = [
535
- { text: "Create an agent that summarizes documents", icon: "🤖" },
536
- { text: "Add a table for tracking leads", icon: "📊" },
537
- { text: "Create a full React desk page for an executive dashboard", icon: "🧩" },
538
- { text: "Create a flow to process emails", icon: "⚡" },
539
- ];
540
- return (_jsxs("div", { className: "lemma-assistant-empty-state text-center py-5 px-2", children: [_jsxs("div", { className: "lemma-assistant-empty-state-hero flex flex-col items-center justify-center mb-6", children: [_jsx("div", { className: "lemma-assistant-empty-state-badge mb-3 flex h-10 w-10 items-center justify-center rounded-full bg-[linear-gradient(135deg,var(--brand-primary),var(--brand-secondary))] shadow-[var(--shadow-xs)]", children: _jsx("span", { className: "text-[var(--text-on-brand)] text-lg", children: "\u2728" }) }), _jsx("h4", { className: "lemma-assistant-empty-state-title font-semibold text-[var(--text-primary)] text-[15px]", children: "What can I help you build?" }), _jsx("p", { className: "lemma-assistant-empty-state-copy text-[13px] text-[var(--text-tertiary)] mt-1.5 max-w-sm leading-relaxed", children: "I can create agents, set up data stores, build pages, and automate workflows for your pod." })] }), _jsx("div", { className: "lemma-assistant-empty-state-suggestions grid grid-cols-1 sm:grid-cols-2 gap-2.5 max-w-[500px] mx-auto", children: suggestions.map((suggestion, index) => (_jsxs("button", { onClick: () => onSendMessage(suggestion.text), className: "lemma-assistant-empty-state-suggestion text-left px-3 py-2.5 rounded-lg border border-[var(--border-default)] bg-[var(--bg-surface)] text-xs text-[var(--text-secondary)] hover:border-[color:color-mix(in_srgb,_var(--brand-accent)_52%,_var(--border-subtle))] hover:bg-[color:color-mix(in_srgb,_var(--brand-glow)_72%,_var(--bg-surface))] hover:text-[var(--text-primary)] transition-all duration-200 flex items-center gap-2.5 group", children: [_jsx("span", { className: "text-base opacity-70 group-hover:opacity-100 transition-opacity", children: suggestion.icon }), _jsx("span", { className: "flex-1 leading-snug", children: suggestion.text }), _jsx("span", { className: "text-[var(--text-tertiary)] group-hover:text-[var(--state-warning)] group-hover:translate-x-0.5 transition-all opacity-0 group-hover:opacity-100", children: "\u203A" })] }, `${suggestion.text}-${index}`))) })] }));
533
+ export const DEFAULT_EMPTY_STATE_SUGGESTIONS = [
534
+ { text: "Help me get started", icon: "→" },
535
+ { text: "Summarize this for me", icon: "" },
536
+ { text: "Help me draft a reply", icon: "" },
537
+ { text: "Brainstorm next steps", icon: "" },
538
+ ];
539
+ export function EmptyState({ onSendMessage, suggestions = DEFAULT_EMPTY_STATE_SUGGESTIONS, }) {
540
+ return (_jsxs("div", { className: "lemma-assistant-empty-state", children: [_jsxs("div", { className: "lemma-assistant-empty-state-hero", children: [_jsx("div", { className: "lemma-assistant-empty-state-badge", children: _jsx("span", { className: "lemma-assistant-empty-state-badge-icon", children: "\u2728" }) }), _jsx("h4", { className: "lemma-assistant-empty-state-title", children: "How can I help?" }), _jsx("p", { className: "lemma-assistant-empty-state-copy", children: "Ask a question, share context, or start with one of these prompts." })] }), _jsx("div", { className: "lemma-assistant-empty-state-suggestions", children: suggestions.map((suggestion, index) => (_jsxs("button", { onClick: () => onSendMessage(suggestion.text), className: "lemma-assistant-empty-state-suggestion", children: [suggestion.icon ? (_jsx("span", { className: "lemma-assistant-empty-state-suggestion-icon", children: suggestion.icon })) : null, _jsx("span", { className: "lemma-assistant-empty-state-suggestion-text", children: suggestion.text }), _jsx("span", { className: "lemma-assistant-empty-state-suggestion-arrow", children: "\u203A" })] }, `${suggestion.text}-${index}`))) })] }));
541
541
  }
542
542
  function ReasoningPartCard({ text, isStreaming, durationMs, }) {
543
- return (_jsxs("details", { className: "lemma-assistant-reasoning group", open: isStreaming, children: [_jsxs("summary", { className: "lemma-assistant-reasoning-summary list-none cursor-pointer inline-flex items-center gap-1.5 text-[12px] leading-5 text-[var(--text-tertiary)]", children: [_jsx("span", { className: "transition-transform group-open:rotate-90", children: "\u203A" }), _jsx("span", { className: cx("font-semibold", isStreaming && "text-transparent bg-clip-text bg-[linear-gradient(110deg,var(--text-secondary),35%,var(--brand-accent),50%,var(--text-secondary),65%)] bg-[length:250%_100%] animate-pulse"), children: isStreaming ? "Thinking" : `Thought${durationMs ? ` · ${Math.max(1, Math.round(durationMs / 1000))}s` : ""}` })] }), _jsx("div", { className: "lemma-assistant-reasoning-body mt-1 pl-4 border-l border-[var(--border-default)]", children: _jsx("pre", { className: "lemma-assistant-reasoning-text text-[11px] leading-5 text-[var(--text-tertiary)] whitespace-pre-wrap font-mono", children: text }) })] }));
543
+ return (_jsxs("details", { className: "lemma-assistant-reasoning", open: isStreaming, children: [_jsxs("summary", { className: "lemma-assistant-reasoning-summary", children: [_jsx("span", { className: "lemma-assistant-reasoning-caret", children: "\u203A" }), _jsx("span", { className: cx("lemma-assistant-reasoning-label", isStreaming && "lemma-assistant-reasoning-label-streaming"), children: isStreaming ? "Thinking" : `Thought${durationMs ? ` · ${Math.max(1, Math.round(durationMs / 1000))}s` : ""}` })] }), _jsx("div", { className: "lemma-assistant-reasoning-body", children: _jsx("pre", { className: "lemma-assistant-reasoning-text", children: text }) })] }));
544
544
  }
545
545
  function PresentFilesCard({ filepaths, conversationId, renderPresentedFile, }) {
546
546
  const fakeMessage = {
@@ -554,7 +554,7 @@ function PresentFilesCard({ filepaths, conversationId, renderPresentedFile, }) {
554
554
  args: { filepaths },
555
555
  state: "result",
556
556
  };
557
- return (_jsx("div", { className: "lemma-assistant-presented-files pt-1 space-y-2", children: filepaths.map((filepath) => (_jsx("div", { className: "lemma-assistant-presented-file", children: (renderPresentedFile || defaultPresentedFile)({
557
+ return (_jsx("div", { className: "lemma-assistant-presented-files", children: filepaths.map((filepath) => (_jsx("div", { className: "lemma-assistant-presented-file", children: (renderPresentedFile || defaultPresentedFile)({
558
558
  filepath,
559
559
  activeConversationId: conversationId ?? null,
560
560
  invocation: fakeInvocation,
@@ -568,7 +568,7 @@ function ToolDetailsPanel({ toolName, args, state, result, onNavigateResource, r
568
568
  && typeof resultData.resourceType === "string"
569
569
  && typeof resultData.resourceId === "string";
570
570
  if (renderToolInvocation) {
571
- return (_jsx("div", { className: "pl-4 border-l border-[var(--border-default)]", children: renderToolInvocation({
571
+ return (_jsx("div", { className: "lemma-assistant-tool-details-panel lemma-assistant-tool-details-panel-custom", children: renderToolInvocation({
572
572
  invocation: {
573
573
  toolCallId: "detail-tool",
574
574
  toolName,
@@ -580,7 +580,7 @@ function ToolDetailsPanel({ toolName, args, state, result, onNavigateResource, r
580
580
  activeConversationId,
581
581
  }) }));
582
582
  }
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" }) })] })] })] }));
583
+ return (_jsxs("div", { className: "lemma-assistant-tool-details-panel", children: [_jsxs("div", { className: "lemma-assistant-tool-details-header", children: [_jsx("div", { className: "lemma-assistant-tool-details-title", children: formatToolDisplayName(toolName) }), canNavigate && onNavigateResource ? (_jsx("button", { type: "button", onClick: () => onNavigateResource(resultData.resourceType, resultData.resourceId, resultData), className: "lemma-assistant-tool-details-link", children: "Open \u203A" })) : null] }), _jsxs("div", { className: "lemma-assistant-tool-details-grid", children: [_jsxs("div", { className: "lemma-assistant-tool-details-section", children: [_jsx("div", { className: "lemma-assistant-tool-details-label", children: "Input" }), _jsx("div", { className: "lemma-assistant-tool-details-code", children: _jsx("pre", { className: "lemma-assistant-tool-details-code-text", children: JSON.stringify(args, null, 2) }) })] }), _jsxs("div", { className: "lemma-assistant-tool-details-section", children: [_jsx("div", { className: "lemma-assistant-tool-details-label", children: "Output" }), _jsx("div", { className: "lemma-assistant-tool-details-code", children: _jsx("pre", { className: "lemma-assistant-tool-details-code-text", children: Object.keys(resultData).length > 0 ? JSON.stringify(resultData, null, 2) : "No output yet" }) })] })] })] }));
584
584
  }
585
585
  function InlineToolCall({ invocation, isSelected, onClick, }) {
586
586
  const resultData = (invocation.result || {});
@@ -592,7 +592,7 @@ function InlineToolCall({ invocation, isSelected, onClick, }) {
592
592
  : isFailed
593
593
  ? (typeof resultData.error === "string" ? resultData.error : "Tool failed")
594
594
  : (formatToolResultSummary(invocation.toolName, invocation.args, resultData) || "Completed");
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 ? "⌄" : "›" })] }));
595
+ return (_jsxs("button", { type: "button", onClick: onClick, className: "lemma-assistant-inline-tool-call", "data-state": isExecuting ? "executing" : isComplete ? "complete" : isFailed ? "failed" : "idle", "data-selected": isSelected ? "true" : "false", children: [_jsx("span", { className: "lemma-assistant-inline-tool-call-name", children: formatToolDisplayName(invocation.toolName) }), _jsx("span", { className: "lemma-assistant-inline-tool-call-summary", children: summary }), _jsx("span", { className: "lemma-assistant-inline-tool-call-caret", children: isSelected ? "⌄" : "›" })] }));
596
596
  }
597
597
  function ToolActivityRollup({ detailParts, onNavigateResource, renderToolInvocation, message, activeConversationId, }) {
598
598
  const [activeToolCallId, setActiveToolCallId] = useState(null);
@@ -608,13 +608,13 @@ function ToolActivityRollup({ detailParts, onNavigateResource, renderToolInvocat
608
608
  const summary = activeInvocation
609
609
  ? formatActiveToolSummary(activeInvocation.toolName, activeInvocation.args)
610
610
  : `Worked across ${toolParts.length} tool${toolParts.length === 1 ? "" : "s"}${failedCount > 0 ? ` · ${failedCount} failed` : ""}`;
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) => {
611
+ return (_jsxs("div", { className: "lemma-assistant-tool-rollup", children: [_jsxs("button", { type: "button", onClick: () => setIsExpanded((prev) => !prev), className: "lemma-assistant-tool-rollup-toggle", "data-expanded": isExpanded ? "true" : "false", children: [_jsx("span", { className: "lemma-assistant-tool-rollup-caret", children: "\u203A" }), isWorking ? _jsx("span", { className: "lemma-assistant-tool-rollup-dot" }) : null, _jsx("span", { className: cx("lemma-assistant-tool-rollup-summary", isWorking && "lemma-assistant-tool-rollup-summary-working"), children: summary })] }), isExpanded ? (_jsx("div", { className: "lemma-assistant-tool-rollup-details", children: detailParts.map((part) => {
612
612
  if (part.type === "reasoning") {
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}`));
613
+ return (_jsxs("div", { className: "lemma-assistant-tool-rollup-thinking", children: [_jsx("div", { className: "lemma-assistant-tool-rollup-thinking-title", children: part.state === "streaming" ? "Thinking" : "Thought" }), _jsx("pre", { className: "lemma-assistant-tool-rollup-thinking-text", children: part.text })] }, `thinking-${part.id}`));
614
614
  }
615
615
  const invocation = part.toolInvocation;
616
616
  const isSelected = activeToolCallId === invocation.toolCallId;
617
- return (_jsxs("div", { className: "lemma-assistant-tool-rollup-item space-y-1", children: [_jsx(InlineToolCall, { invocation: invocation, isSelected: isSelected, onClick: () => setActiveToolCallId((prev) => (prev === invocation.toolCallId ? null : invocation.toolCallId)) }), isSelected ? (_jsx(ToolDetailsPanel, { toolName: invocation.toolName, args: invocation.args, state: invocation.state, result: invocation.result, onNavigateResource: onNavigateResource, renderToolInvocation: renderToolInvocation, message: message, activeConversationId: activeConversationId })) : null] }, part.id));
617
+ return (_jsxs("div", { className: "lemma-assistant-tool-rollup-item", children: [_jsx(InlineToolCall, { invocation: invocation, isSelected: isSelected, onClick: () => setActiveToolCallId((prev) => (prev === invocation.toolCallId ? null : invocation.toolCallId)) }), isSelected ? (_jsx(ToolDetailsPanel, { toolName: invocation.toolName, args: invocation.args, state: invocation.state, result: invocation.result, onNavigateResource: onNavigateResource, renderToolInvocation: renderToolInvocation, message: message, activeConversationId: activeConversationId })) : null] }, part.id));
618
618
  }) })) : null] }));
619
619
  }
620
620
  function ShowWidgetToolCard({ invocation, onSendPrompt, }) {
@@ -654,9 +654,9 @@ function ShowWidgetToolCard({ invocation, onSendPrompt, }) {
654
654
  window.removeEventListener("message", handleMessage);
655
655
  };
656
656
  }, [onSendPrompt]);
657
- return (_jsxs("div", { className: "lemma-assistant-widget-card space-y-2", children: [_jsxs("div", { className: "lemma-assistant-widget-card-header flex items-center justify-between gap-2", children: [_jsx("div", { className: "lemma-assistant-widget-card-title text-[11px] font-semibold text-[var(--state-info)]", children: displayName }), _jsx("span", { className: cx("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-medium", isExecuting && "bg-[color:color-mix(in_srgb,_var(--state-info)_16%,_transparent)] text-[var(--state-info)]", isFailed && "bg-[color:color-mix(in_srgb,_var(--state-error)_12%,_transparent)] text-[var(--state-error)]", !isExecuting && !isFailed && "bg-[color:color-mix(in_srgb,_var(--state-success)_12%,_transparent)] text-[var(--state-success)]"), children: isExecuting ? "Rendering" : isFailed ? "Failed" : "Ready" })] }), isFailed ? (_jsx("p", { className: "text-[11px] text-[var(--state-error)]", children: typeof resultData.error === "string" && resultData.error.length > 0
657
+ return (_jsxs("div", { className: "lemma-assistant-widget-card", children: [_jsxs("div", { className: "lemma-assistant-widget-card-header", children: [_jsx("div", { className: "lemma-assistant-widget-card-title", children: displayName }), _jsx("span", { className: cx("lemma-assistant-widget-card-badge", isExecuting && "lemma-assistant-widget-card-badge-rendering", isFailed && "lemma-assistant-widget-card-badge-failed", !isExecuting && !isFailed && "lemma-assistant-widget-card-badge-ready"), children: isExecuting ? "Rendering" : isFailed ? "Failed" : "Ready" })] }), isFailed ? (_jsx("p", { className: "lemma-assistant-widget-card-error", children: typeof resultData.error === "string" && resultData.error.length > 0
658
658
  ? resultData.error
659
- : "Failed to render widget." })) : null, !isFailed && payload ? (_jsx("iframe", { ref: iframeRef, title: displayName, srcDoc: iframeDocument, sandbox: "allow-scripts allow-forms allow-popups allow-downloads", height: height, className: "lemma-assistant-widget-card-frame w-full border-0 bg-transparent rounded-xl" })) : null, !isFailed && !payload ? (_jsx("p", { className: "text-[11px] text-[var(--text-secondary)]", children: "Widget output is missing `widget_code`." })) : null] }));
659
+ : "Failed to render widget." })) : null, !isFailed && payload ? (_jsx("iframe", { ref: iframeRef, title: displayName, srcDoc: iframeDocument, sandbox: "allow-scripts allow-forms allow-popups allow-downloads", height: height, className: "lemma-assistant-widget-card-frame" })) : null, !isFailed && !payload ? (_jsx("p", { className: "lemma-assistant-widget-card-missing", children: "Widget output is missing `widget_code`." })) : null] }));
660
660
  }
661
661
  export function MessageGroup({ message, conversationId, onNavigateResource, onWidgetSendPrompt, isStreaming, showAssistantHeader, renderMessageContent, renderPresentedFile, renderToolInvocation, }) {
662
662
  const orderedParts = message.parts && message.parts.length > 0
@@ -715,7 +715,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
715
715
  .find((part) => part.type === "text" && part.text.trim().length > 0)
716
716
  ?.id;
717
717
  if (message.role === "user") {
718
- return (_jsx("div", { className: "lemma-assistant-message lemma-assistant-message-user flex justify-end", children: _jsx("div", { className: "lemma-assistant-message-user-bubble max-w-[72ch] rounded-xl bg-[var(--brand-primary)] text-[var(--text-on-brand)] px-3.5 py-2.5", children: renderMessageContent({
718
+ return (_jsx("div", { className: "lemma-assistant-message lemma-assistant-message-user", children: _jsx("div", { className: "lemma-assistant-message-user-bubble", children: renderMessageContent({
719
719
  message: {
720
720
  ...message,
721
721
  content: message.content,
@@ -724,7 +724,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
724
724
  },
725
725
  }) }) }));
726
726
  }
727
- return (_jsxs("div", { className: "lemma-assistant-message lemma-assistant-message-assistant px-1 py-0.5 space-y-1.5 max-w-[78ch]", children: [showAssistantHeader ? (_jsxs("div", { className: "lemma-assistant-message-header inline-flex items-center gap-1.5 text-[11px] text-[var(--text-tertiary)]", children: [_jsx("span", { className: "lemma-assistant-message-header-dot inline-block h-1.5 w-1.5 rounded-full bg-[color:color-mix(in_srgb,_var(--brand-primary)_40%,_transparent)]" }), "Lemma"] })) : null, _jsxs("div", { className: "lemma-assistant-message-body space-y-2", children: [blocks.map((block) => {
727
+ return (_jsxs("div", { className: "lemma-assistant-message lemma-assistant-message-assistant", children: [showAssistantHeader ? (_jsxs("div", { className: "lemma-assistant-message-header", children: [_jsx("span", { className: "lemma-assistant-message-header-dot" }), "Lemma"] })) : null, _jsxs("div", { className: "lemma-assistant-message-body", children: [blocks.map((block) => {
728
728
  if (block.kind === "tools") {
729
729
  if (foldReasoningIntoToolRollup && block.id !== firstToolsBlockId) {
730
730
  return null;
@@ -742,7 +742,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
742
742
  if (trimmedText.length === 0) {
743
743
  return null;
744
744
  }
745
- return (_jsx("div", { className: "lemma-assistant-message-text text-[13px] text-[var(--text-secondary)] leading-6", children: renderMessageContent({
745
+ return (_jsx("div", { className: "lemma-assistant-message-text", children: renderMessageContent({
746
746
  message: {
747
747
  ...message,
748
748
  content: trimmedText + (isStreaming && part.id === lastTextPartId ? " ▍" : ""),
@@ -760,7 +760,7 @@ export function MessageGroup({ message, conversationId, onNavigateResource, onWi
760
760
  return null;
761
761
  }), presentableFilepaths.length > 0 ? (_jsx(PresentFilesCard, { filepaths: presentableFilepaths, conversationId: conversationId, renderPresentedFile: renderPresentedFile })) : null] })] }));
762
762
  }
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, }) {
763
+ export function AssistantExperienceView({ controller, title = "Lemma Assistant", subtitle = "Ask across your workspace and organization.", placeholder = "Message Lemma Assistant", emptyState, emptyStateSuggestions, draft: controlledDraft, onDraftChange, showConversationList = false, chromeStyle = "subtle", statusPlacement = "inline", radius = "md", showModelPicker = true, showNewConversationButton = true, onNavigateResource, renderConversationLabel = defaultConversationLabel, renderMessageContent = defaultMessageContent, renderPresentedFile, renderPendingFile = defaultPendingFile, renderToolInvocation, }) {
764
764
  const [draft, setDraft] = useControllableDraft(controlledDraft, onDraftChange);
765
765
  const [isPlanHidden, setIsPlanHidden] = useState(false);
766
766
  const [dismissedAskToolCallIds, setDismissedAskToolCallIds] = useState([]);
@@ -773,7 +773,15 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
773
773
  const isPinnedToBottomRef = useRef(true);
774
774
  const loadingOlderFromScrollRef = useRef(false);
775
775
  const isConversationBusy = controller.isLoading || controller.isActiveConversationRunning;
776
- const availableModels = useMemo(() => Object.values(AvailableModels), []);
776
+ const availableModels = useMemo(() => {
777
+ const dynamicModels = controller.availableModels
778
+ .map((model) => model.id)
779
+ .filter((model) => model.trim().length > 0);
780
+ return dynamicModels.length > 0
781
+ ? dynamicModels
782
+ : Object.values(AvailableModels);
783
+ }, [controller.availableModels]);
784
+ const availableModelLabels = useMemo(() => new Map(controller.availableModels.map((model) => [model.id, model.name])), [controller.availableModels]);
777
785
  const resizeComposer = useCallback(() => {
778
786
  const textarea = inputRef.current;
779
787
  if (!textarea)
@@ -1024,29 +1032,21 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
1024
1032
  const composerTone = chromeStyle === "flat" ? "flat" : chromeStyle === "subtle" ? "subtle" : "default";
1025
1033
  const showInlineStatus = statusPlacement === "inline" && isConversationBusy;
1026
1034
  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) => {
1035
+ return (_jsxs("div", { className: "lemma-assistant-experience", "data-chrome-style": chromeStyle, "data-status-placement": statusPlacement, "data-radius": radius, "data-show-model-picker": showModelPicker ? "true" : "false", "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", children: [_jsx("div", { className: "lemma-assistant-experience-sidebar-header", children: _jsxs("div", { className: "lemma-assistant-experience-sidebar-header-row", children: [_jsxs("div", { className: "lemma-assistant-experience-sidebar-copy", children: [_jsx("div", { className: "lemma-assistant-experience-sidebar-title", children: "Conversations" }), _jsxs("div", { className: "lemma-assistant-experience-sidebar-meta", children: [controller.conversations.length, " total"] })] }), showNewConversationButton ? (_jsx("button", { type: "button", onClick: controller.clearMessages, className: "lemma-assistant-experience-sidebar-new", children: "New" })) : null] }) }), _jsx("div", { className: "lemma-assistant-experience-sidebar-items", children: controller.conversations.map((conversation) => {
1028
1036
  const isActive = conversation.id === controller.activeConversationId;
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
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))]"
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));
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) => {
1037
+ return (_jsxs("button", { type: "button", onClick: () => controller.selectConversation(conversation.id), className: cx("lemma-assistant-experience-sidebar-item", isActive && "lemma-assistant-experience-sidebar-item-active"), children: [_jsx("div", { className: "lemma-assistant-experience-sidebar-item-title", children: renderConversationLabel({ conversation, isActive }) }), _jsx("div", { className: "lemma-assistant-experience-sidebar-item-status", children: (conversation.status || "waiting").toLowerCase() })] }, conversation.id));
1038
+ }) })] })) : null, _jsxs("div", { className: "lemma-assistant-experience-main", children: [_jsxs("div", { className: "lemma-assistant-experience-card", children: [_jsx(AssistantHeader, { className: "lemma-assistant-experience-header", tone: headerTone, title: title, subtitle: subtitle, badge: _jsx("span", { className: "lemma-assistant-experience-header-badge-icon", children: "\u2728" }), controls: showModelPicker || showNewConversationButton ? (_jsxs(_Fragment, { children: [showModelPicker ? (_jsx(AssistantModelPicker, { value: controller.conversationModel, options: availableModels, getOptionLabel: (model) => availableModelLabels.get(model) ?? model, onChange: (nextModel) => { void handleModelChange(nextModel); }, disabled: isConversationBusy || isUpdatingModel, autoLabel: "Auto", className: "lemma-assistant-experience-model-picker" })) : null, showNewConversationButton ? (_jsx("button", { type: "button", onClick: controller.clearMessages, title: "New conversation", className: "lemma-assistant-experience-new", children: "\u21BA" })) : null] })) : undefined }), _jsxs(AssistantMessageViewport, { className: "lemma-assistant-experience-viewport", ref: messagesContainerRef, onScroll: updatePinnedState, children: [controller.messages.length === 0 && !isConversationBusy ? (emptyState || (_jsx(EmptyState, { onSendMessage: (message) => { void controller.sendMessage(message); }, suggestions: emptyStateSuggestions }))) : null, (controller.isLoadingMessages && controller.messages.length === 0) ? (_jsx("div", { className: "lemma-assistant-experience-loading", children: _jsx("span", { className: "lemma-assistant-experience-loading-text", children: "Loading\u2026" }) })) : null, (controller.isLoadingOlderMessages && controller.messages.length > 0) ? (_jsx("div", { className: "lemma-assistant-experience-loading-older", children: _jsx("span", { className: "lemma-assistant-experience-loading-older-text", children: "Loading older\u2026" }) })) : null, displayMessageRows.map((row, index) => {
1033
1039
  const previousRow = index > 0 ? displayMessageRows[index - 1] : null;
1034
1040
  const showAssistantHeader = row.message.role !== "assistant"
1035
1041
  ? false
1036
1042
  : previousRow?.message.role !== "assistant";
1037
1043
  const includesLastRawMessage = row.sourceIndexes.includes(controller.messages.length - 1);
1038
1044
  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));
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) => {
1045
+ }), showInlineStatus ? (_jsx("div", { className: "lemma-assistant-experience-inline-status", children: _jsx("div", { className: "lemma-assistant-experience-inline-status-pill", "data-has-content": lastMessageHasContent ? "true" : "false", children: _jsx(AssistantStatusPill, { label: liveStatusLabel, subtle: lastMessageHasContent }) }) })) : null, controller.error ? (_jsx("div", { className: "lemma-assistant-experience-error", children: _jsxs("div", { children: [_jsx("p", { className: "lemma-assistant-experience-error-title", children: "Something went wrong" }), _jsx("p", { className: "lemma-assistant-experience-error-copy", children: controller.error })] }) })) : null, (controller.messages.length > 0 || isConversationBusy || !!controller.error) ? (_jsx("div", { "aria-hidden": "true", className: "lemma-assistant-experience-bottom-spacer" })) : null, _jsx("div", { ref: bottomAnchorRef, "aria-hidden": "true", className: "lemma-assistant-experience-bottom-anchor" })] })] }), _jsx(AssistantComposer, { className: "lemma-assistant-experience-composer", tone: composerTone, floating: planSummary ? (isPlanHidden ? (_jsxs("button", { type: "button", onClick: () => setIsPlanHidden(false), className: "lemma-assistant-experience-plan-button", 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
1046
  const fileKey = `${file.name}:${file.size}:${file.lastModified}`;
1041
1047
  return (_jsx("div", { children: renderPendingFile({
1042
1048
  file,
1043
1049
  remove: () => controller.removePendingFile(fileKey),
1044
1050
  }) }, 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 ? "■" : "→" }) })] }) })) })] })] }));
1051
+ }) })) : 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", children: _jsxs("div", { className: "lemma-assistant-experience-input-row", children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "lemma-assistant-experience-file-input", onChange: (event) => { void handleUploadSelection(event.target.files); } }), _jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), disabled: isConversationBusy || controller.isUploadingFiles, className: "lemma-assistant-experience-upload", "data-disabled": isConversationBusy || controller.isUploadingFiles ? "true" : "false", 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", rows: 1, disabled: isConversationBusy }), _jsx("div", { className: "lemma-assistant-experience-send-wrap", children: _jsx("button", { onClick: isConversationBusy ? controller.stop : () => { void handleSubmit(); }, disabled: !isConversationBusy && !draft.trim(), className: "lemma-assistant-experience-send", "data-state": isConversationBusy ? "busy" : draft.trim() ? "ready" : "idle", title: isConversationBusy ? "Stop generating" : "Send message", children: isConversationBusy ? "■" : "→" }) })] }) })) })] })] }));
1052
1052
  }
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
+ import type { AvailableModelInfo } from "../../types.js";
2
3
  import type { AssistantRenderableMessage, AssistantToolInvocation } from "../useAssistantController.js";
3
4
  export interface AssistantConversationListItem {
4
5
  id: string;
@@ -11,6 +12,7 @@ export interface AssistantControllerView {
11
12
  messages: AssistantRenderableMessage[];
12
13
  conversations: AssistantConversationListItem[];
13
14
  activeConversationId: string | null;
15
+ availableModels: AvailableModelInfo[];
14
16
  conversationModel: string | null;
15
17
  setConversationModel(model: string | null): Promise<void>;
16
18
  isActiveConversationRunning: boolean;
@@ -56,11 +58,16 @@ export interface AssistantPendingFileRenderArgs {
56
58
  file: File;
57
59
  remove: () => void;
58
60
  }
61
+ export interface EmptyStateSuggestion {
62
+ text: string;
63
+ icon?: ReactNode;
64
+ }
59
65
  export interface AssistantExperienceCustomizationProps {
60
66
  title?: ReactNode;
61
67
  subtitle?: ReactNode;
62
68
  placeholder?: string;
63
69
  emptyState?: ReactNode;
70
+ emptyStateSuggestions?: EmptyStateSuggestion[];
64
71
  draft?: string;
65
72
  onDraftChange?: (value: string) => void;
66
73
  showConversationList?: boolean;
@@ -12,14 +12,14 @@ export { useAssistantRuntime } from "./useAssistantRuntime.js";
12
12
  export type { UseAssistantRuntimeOptions, UseAssistantRuntimeResult, } from "./useAssistantRuntime.js";
13
13
  export { useAssistantController } from "./useAssistantController.js";
14
14
  export type { AssistantAction, AssistantConversationScope, AssistantMessagePart, AssistantRenderableMessage, AssistantToolInvocation, UseAssistantControllerOptions, UseAssistantControllerResult, } from "./useAssistantController.js";
15
- export type { AssistantConversationRenderArgs, AssistantControllerView, AssistantExperienceCustomizationProps, AssistantMessageRenderArgs, AssistantPendingFileRenderArgs, AssistantPresentedFileRenderArgs, AssistantToolRenderArgs, } from "./components/assistant-types.js";
15
+ export type { AssistantConversationRenderArgs, AssistantControllerView, AssistantExperienceCustomizationProps, AssistantMessageRenderArgs, EmptyStateSuggestion, 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
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, AssistantChromeStyle, AssistantExperienceViewProps, AssistantStatusPlacement, DisplayMessageRow, PendingAskUserInput, PlanStepState, PlanSummaryState, } from "./components/AssistantExperience.js";
19
+ export type { ActiveToolBanner, AskUserInputQuestion, AssistantChromeStyle, AssistantExperienceViewProps, AssistantRadiusScale, AssistantStatusPlacement, DisplayMessageRow, EmptyStateProps, 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
- export { buildDisplayMessageRows, dedupToolInvocations, EmptyState, findPendingAskUserInput, formatAskUserInputAnswers, getActiveToolBanner, extractPresentFilePathsFromInvocation, latestPlanSummary, MessageGroup, PlanSummaryStrip, ThinkingIndicator, } from "./components/AssistantExperience.js";
22
+ export { buildDisplayMessageRows, DEFAULT_EMPTY_STATE_SUGGESTIONS, dedupToolInvocations, EmptyState, findPendingAskUserInput, formatAskUserInputAnswers, getActiveToolBanner, extractPresentFilePathsFromInvocation, latestPlanSummary, MessageGroup, PlanSummaryStrip, ThinkingIndicator, } from "./components/AssistantExperience.js";
23
23
  export { useTaskSession } from "./useTaskSession.js";
24
24
  export type { CreateTaskInput, UseTaskSessionOptions, UseTaskSessionResult, } from "./useTaskSession.js";
25
25
  export { useFunctionSession } from "./useFunctionSession.js";
@@ -8,7 +8,7 @@ export { useAssistantController } from "./useAssistantController.js";
8
8
  export { AssistantAskOverlay, AssistantComposer, AssistantConversationList, AssistantHeader, AssistantMessageViewport, AssistantModelPicker, AssistantPendingFileChip, AssistantShellLayout, AssistantStatusPill, AssistantThemeScope, } from "./components/AssistantChrome.js";
9
9
  export { AssistantExperienceView } from "./components/AssistantExperience.js";
10
10
  export { AssistantEmbedded } from "./components/AssistantEmbedded.js";
11
- export { buildDisplayMessageRows, dedupToolInvocations, EmptyState, findPendingAskUserInput, formatAskUserInputAnswers, getActiveToolBanner, extractPresentFilePathsFromInvocation, latestPlanSummary, MessageGroup, PlanSummaryStrip, ThinkingIndicator, } from "./components/AssistantExperience.js";
11
+ export { buildDisplayMessageRows, DEFAULT_EMPTY_STATE_SUGGESTIONS, dedupToolInvocations, EmptyState, findPendingAskUserInput, formatAskUserInputAnswers, getActiveToolBanner, extractPresentFilePathsFromInvocation, latestPlanSummary, MessageGroup, PlanSummaryStrip, ThinkingIndicator, } from "./components/AssistantExperience.js";
12
12
  export { useTaskSession } from "./useTaskSession.js";
13
13
  export { useFunctionSession } from "./useFunctionSession.js";
14
14
  export { useFlowSession } from "./useFlowSession.js";