lemma-sdk 0.2.10 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -169,6 +169,60 @@ Notes:
169
169
 
170
170
  ## Assistants + Agent Runs
171
171
 
172
+ ### React assistant controller + primitives
173
+
174
+ `lemma-sdk/react` now exposes the assistant controller plus the reusable UI primitives used by the app shell. A simple integration looks like this:
175
+
176
+ ```tsx
177
+ import {
178
+ MessageGroup,
179
+ PlanSummaryStrip,
180
+ ThinkingIndicator,
181
+ buildDisplayMessageRows,
182
+ getActiveToolBanner,
183
+ latestPlanSummary,
184
+ useAssistantController,
185
+ } from "lemma-sdk/react";
186
+
187
+ function AssistantSurface() {
188
+ const assistant = useAssistantController({
189
+ client,
190
+ assistantId: "support_assistant",
191
+ podId: "pod_123",
192
+ });
193
+
194
+ const rows = buildDisplayMessageRows(assistant.messages);
195
+ const plan = latestPlanSummary(assistant.messages);
196
+ const activeToolBanner = getActiveToolBanner(assistant.messages);
197
+
198
+ return (
199
+ <div>
200
+ {plan ? <PlanSummaryStrip plan={plan} onHide={() => {}} /> : null}
201
+ {activeToolBanner ? <div>{activeToolBanner.summary}</div> : null}
202
+
203
+ {rows.map((row, index) => (
204
+ <MessageGroup
205
+ key={row.id}
206
+ message={row.message}
207
+ conversationId={assistant.activeConversationId}
208
+ onWidgetSendPrompt={(text) => assistant.sendMessage(text)}
209
+ isStreaming={assistant.isActiveConversationRunning && row.sourceIndexes.includes(assistant.messages.length - 1)}
210
+ showAssistantHeader={index === 0 || rows[index - 1]?.message.role !== "assistant"}
211
+ renderMessageContent={({ message }) => <div>{message.content}</div>}
212
+ />
213
+ ))}
214
+
215
+ {assistant.isActiveConversationRunning ? <ThinkingIndicator /> : null}
216
+ </div>
217
+ );
218
+ }
219
+ ```
220
+
221
+ The intended split is:
222
+
223
+ - SDK: `useAssistantController`, message/tool normalization, plan parsing, tool rollups, and assistant UI primitives.
224
+ - App: modal shell, fullscreen behavior, route navigation, workspace/file viewers, and product-specific renderers.
225
+
172
226
  ### Assistant names (resource key)
173
227
 
174
228
  Assistant CRUD is name-based:
@@ -0,0 +1,79 @@
1
+ import { type ReactNode } from "react";
2
+ import type { AssistantRenderableMessage, AssistantToolInvocation } from "../useAssistantController.js";
3
+ import type { AssistantControllerView, AssistantConversationRenderArgs, AssistantMessageRenderArgs, AssistantPendingFileRenderArgs, AssistantPresentedFileRenderArgs, AssistantToolRenderArgs } from "./assistant-types.js";
4
+ type PlanStatus = "pending" | "in_progress" | "completed";
5
+ export interface PlanStepState {
6
+ step: string;
7
+ status: PlanStatus;
8
+ }
9
+ export interface PlanSummaryState {
10
+ steps: PlanStepState[];
11
+ completedCount: number;
12
+ inProgressCount: number;
13
+ running: boolean;
14
+ activeStep?: string;
15
+ }
16
+ type AskQuestionType = "single_select" | "multi_select" | "rank_priorities";
17
+ export interface AskUserInputQuestion {
18
+ question: string;
19
+ options: string[];
20
+ type: AskQuestionType;
21
+ }
22
+ export interface PendingAskUserInput {
23
+ toolCallId: string;
24
+ messageIndex: number;
25
+ questions: AskUserInputQuestion[];
26
+ }
27
+ export interface DisplayMessageRow {
28
+ id: string;
29
+ message: AssistantRenderableMessage;
30
+ sourceIndexes: number[];
31
+ }
32
+ export interface ActiveToolBanner {
33
+ summary: string;
34
+ activeCount: number;
35
+ }
36
+ export interface AssistantExperienceViewProps {
37
+ controller: AssistantControllerView;
38
+ title?: ReactNode;
39
+ subtitle?: ReactNode;
40
+ placeholder?: string;
41
+ emptyState?: ReactNode;
42
+ draft?: string;
43
+ onDraftChange?: (value: string) => void;
44
+ showConversationList?: boolean;
45
+ onNavigateResource?: (resourceType: string, resourceId: string, meta?: Record<string, unknown>) => void;
46
+ renderConversationLabel?: (args: AssistantConversationRenderArgs) => ReactNode;
47
+ renderMessageContent?: (args: AssistantMessageRenderArgs) => ReactNode;
48
+ renderPresentedFile?: (args: AssistantPresentedFileRenderArgs) => ReactNode;
49
+ renderPendingFile?: (args: AssistantPendingFileRenderArgs) => ReactNode;
50
+ renderToolInvocation?: (args: AssistantToolRenderArgs) => ReactNode;
51
+ }
52
+ export declare function dedupToolInvocations(message: AssistantRenderableMessage): AssistantToolInvocation[];
53
+ export declare function latestPlanSummary(messages: AssistantRenderableMessage[]): PlanSummaryState | null;
54
+ export declare function findPendingAskUserInput(messages: AssistantRenderableMessage[]): PendingAskUserInput | null;
55
+ export declare function formatAskUserInputAnswers(questions: AskUserInputQuestion[], answers: string[][]): string;
56
+ export declare function extractPresentFilePathsFromInvocation(invocation: AssistantToolInvocation): string[];
57
+ export declare function buildDisplayMessageRows(messages: AssistantRenderableMessage[]): DisplayMessageRow[];
58
+ export declare function getActiveToolBanner(messages: AssistantRenderableMessage[]): ActiveToolBanner | null;
59
+ export declare function PlanSummaryStrip({ plan, onHide }: {
60
+ plan: PlanSummaryState;
61
+ onHide: () => void;
62
+ }): import("react/jsx-runtime").JSX.Element;
63
+ export declare function ThinkingIndicator(): import("react/jsx-runtime").JSX.Element | null;
64
+ export declare function EmptyState({ onSendMessage }: {
65
+ onSendMessage: (msg: string) => void;
66
+ }): import("react/jsx-runtime").JSX.Element;
67
+ export declare function MessageGroup({ message, conversationId, onNavigateResource, onWidgetSendPrompt, isStreaming, showAssistantHeader, renderMessageContent, renderPresentedFile, renderToolInvocation, }: {
68
+ message: AssistantRenderableMessage;
69
+ conversationId?: string | null;
70
+ onNavigateResource?: (resourceType: string, resourceId: string, meta?: Record<string, unknown>) => void;
71
+ onWidgetSendPrompt: (text: string) => void | Promise<void>;
72
+ isStreaming: boolean;
73
+ showAssistantHeader: boolean;
74
+ renderMessageContent: (args: AssistantMessageRenderArgs) => ReactNode;
75
+ renderPresentedFile?: (args: AssistantPresentedFileRenderArgs) => ReactNode;
76
+ renderToolInvocation?: (args: AssistantToolRenderArgs) => ReactNode;
77
+ }): import("react/jsx-runtime").JSX.Element;
78
+ export declare function AssistantExperienceView({ controller, title, subtitle, placeholder, emptyState, draft: controlledDraft, onDraftChange, showConversationList, onNavigateResource, renderConversationLabel, renderMessageContent, renderPresentedFile, renderPendingFile, renderToolInvocation, }: AssistantExperienceViewProps): import("react/jsx-runtime").JSX.Element;
79
+ export {};