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.
- package/README.md +71 -33
- package/dist/auth.d.ts +42 -1
- package/dist/auth.js +43 -0
- package/dist/browser/lemma-client.js +49 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/namespaces/assistants.d.ts +2 -0
- package/dist/namespaces/assistants.js +3 -0
- package/dist/openapi_client/index.d.ts +3 -0
- package/dist/openapi_client/index.js +1 -0
- package/dist/openapi_client/models/AvailableModelInfo.d.ts +8 -0
- package/dist/openapi_client/models/AvailableModelInfo.js +1 -0
- package/dist/openapi_client/models/AvailableModels.d.ts +3 -4
- package/dist/openapi_client/models/AvailableModels.js +2 -3
- package/dist/openapi_client/models/AvailableModelsListResponse.d.ts +7 -0
- package/dist/openapi_client/models/AvailableModelsListResponse.js +1 -0
- package/dist/openapi_client/models/BulkCreateRecordsRequest.d.ts +4 -0
- package/dist/openapi_client/models/CreateFunctionRequest.d.ts +2 -0
- package/dist/openapi_client/models/FunctionResponse.d.ts +2 -0
- package/dist/openapi_client/models/FunctionRunResponse.d.ts +4 -0
- package/dist/openapi_client/models/FunctionType.d.ts +7 -0
- package/dist/openapi_client/models/FunctionType.js +12 -0
- package/dist/openapi_client/models/UpdateFunctionRequest.d.ts +2 -0
- package/dist/openapi_client/services/ConversationsService.d.ts +8 -0
- package/dist/openapi_client/services/ConversationsService.js +12 -0
- package/dist/react/components/AssistantChrome.js +13 -23
- package/dist/react/components/AssistantExperience.d.ts +12 -4
- package/dist/react/components/AssistantExperience.js +40 -40
- package/dist/react/components/assistant-types.d.ts +7 -0
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +1 -1
- package/dist/react/styles.css +1246 -5
- package/dist/react/useAssistantController.d.ts +2 -1
- package/dist/react/useAssistantController.js +34 -1
- package/dist/react/useAssistantRuntime.js +25 -4
- package/dist/react/useAssistantSession.js +14 -5
- package/dist/types.d.ts +1 -1
- 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",
|
|
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",
|
|
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",
|
|
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",
|
|
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", "
|
|
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
|
|
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",
|
|
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
|
|
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", "
|
|
40
|
-
|
|
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",
|
|
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",
|
|
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", "
|
|
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
|
|
73
|
+
export interface EmptyStateProps {
|
|
69
74
|
onSendMessage: (msg: string) => void;
|
|
70
|
-
|
|
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: "
|
|
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: "
|
|
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
|
|
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
|
|
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
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
return (_jsxs("div", { className: "lemma-assistant-empty-state
|
|
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
|
|
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
|
|
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: "
|
|
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: "
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(() =>
|
|
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:
|
|
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", "
|
|
1030
|
-
|
|
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
|
|
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
|
|
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;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/react/index.js
CHANGED
|
@@ -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";
|