lemma-sdk 0.2.18 → 0.2.20
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 +82 -1
- package/dist/openapi_client/index.d.ts +1 -0
- package/dist/openapi_client/index.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 +2 -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/react/components/AssistantChrome.js +13 -23
- package/dist/react/components/AssistantExperience.d.ts +12 -4
- package/dist/react/components/AssistantExperience.js +31 -39
- package/dist/react/components/assistant-types.d.ts +5 -0
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +1 -1
- package/dist/react/styles.css +1268 -5
- package/package.json +1 -1
|
@@ -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([]);
|
|
@@ -1024,29 +1024,21 @@ export function AssistantExperienceView({ controller, title = "Lemma Assistant",
|
|
|
1024
1024
|
const composerTone = chromeStyle === "flat" ? "flat" : chromeStyle === "subtle" ? "subtle" : "default";
|
|
1025
1025
|
const showInlineStatus = statusPlacement === "inline" && isConversationBusy;
|
|
1026
1026
|
const showComposerStatus = statusPlacement === "composer" && isConversationBusy;
|
|
1027
|
-
return (_jsxs("div", { className:
|
|
1027
|
+
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
1028
|
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) => {
|
|
1029
|
+
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));
|
|
1030
|
+
}) })] })) : 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, 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
1031
|
const previousRow = index > 0 ? displayMessageRows[index - 1] : null;
|
|
1034
1032
|
const showAssistantHeader = row.message.role !== "assistant"
|
|
1035
1033
|
? false
|
|
1036
1034
|
: previousRow?.message.role !== "assistant";
|
|
1037
1035
|
const includesLastRawMessage = row.sourceIndexes.includes(controller.messages.length - 1);
|
|
1038
1036
|
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
|
|
1037
|
+
}), 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
1038
|
const fileKey = `${file.name}:${file.size}:${file.lastModified}`;
|
|
1041
1039
|
return (_jsx("div", { children: renderPendingFile({
|
|
1042
1040
|
file,
|
|
1043
1041
|
remove: () => controller.removePendingFile(fileKey),
|
|
1044
1042
|
}) }, 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 ? "■" : "→" }) })] }) })) })] })] }));
|
|
1043
|
+
}) })) : 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
1044
|
}
|
|
@@ -56,11 +56,16 @@ export interface AssistantPendingFileRenderArgs {
|
|
|
56
56
|
file: File;
|
|
57
57
|
remove: () => void;
|
|
58
58
|
}
|
|
59
|
+
export interface EmptyStateSuggestion {
|
|
60
|
+
text: string;
|
|
61
|
+
icon?: ReactNode;
|
|
62
|
+
}
|
|
59
63
|
export interface AssistantExperienceCustomizationProps {
|
|
60
64
|
title?: ReactNode;
|
|
61
65
|
subtitle?: ReactNode;
|
|
62
66
|
placeholder?: string;
|
|
63
67
|
emptyState?: ReactNode;
|
|
68
|
+
emptyStateSuggestions?: EmptyStateSuggestion[];
|
|
64
69
|
draft?: string;
|
|
65
70
|
onDraftChange?: (value: string) => void;
|
|
66
71
|
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";
|