lemma-sdk 0.2.24 → 0.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +175 -506
  2. package/dist/browser/lemma-client.js +207 -12
  3. package/dist/client.d.ts +2 -0
  4. package/dist/client.js +3 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/namespaces/pod-join-requests.d.ts +16 -0
  7. package/dist/namespaces/pod-join-requests.js +24 -0
  8. package/dist/namespaces/pod-members.d.ts +1 -0
  9. package/dist/namespaces/pod-members.js +3 -0
  10. package/dist/openapi_client/index.d.ts +10 -3
  11. package/dist/openapi_client/index.js +4 -2
  12. package/dist/openapi_client/models/ColumnSchema.d.ts +4 -0
  13. package/dist/openapi_client/models/CreateTableRequest.d.ts +1 -1
  14. package/dist/openapi_client/models/DataStoreFlowStart.d.ts +3 -6
  15. package/dist/openapi_client/models/DatastoreOperation.d.ts +5 -0
  16. package/dist/openapi_client/models/DatastoreOperation.js +10 -0
  17. package/dist/openapi_client/models/DatastoreQueryRequest.d.ts +1 -1
  18. package/dist/openapi_client/models/FlowInstallEntity.d.ts +2 -2
  19. package/dist/openapi_client/models/FlowResponse.d.ts +4 -3
  20. package/dist/openapi_client/models/{FlowStart.d.ts → FlowStart_Input.d.ts} +1 -1
  21. package/dist/openapi_client/models/FlowStart_Output.d.ts +14 -0
  22. package/dist/openapi_client/models/FlowStart_Output.js +1 -0
  23. package/dist/openapi_client/models/PodCreateRequest.d.ts +0 -4
  24. package/dist/openapi_client/models/PodJoinRequestApproveRequest.d.ts +6 -0
  25. package/dist/openapi_client/models/PodJoinRequestApproveRequest.js +1 -0
  26. package/dist/openapi_client/models/PodJoinRequestCreateResponse.d.ts +17 -0
  27. package/dist/openapi_client/models/PodJoinRequestCreateResponse.js +1 -0
  28. package/dist/openapi_client/models/PodJoinRequestListResponse.d.ts +7 -0
  29. package/dist/openapi_client/models/PodJoinRequestListResponse.js +1 -0
  30. package/dist/openapi_client/models/PodJoinRequestStatus.d.ts +5 -0
  31. package/dist/openapi_client/models/PodJoinRequestStatus.js +10 -0
  32. package/dist/openapi_client/models/PodMemberDetailResponse.d.ts +14 -0
  33. package/dist/openapi_client/models/PodMemberDetailResponse.js +1 -0
  34. package/dist/openapi_client/models/PodMemberResponse.d.ts +3 -3
  35. package/dist/openapi_client/models/PodResponse.d.ts +0 -5
  36. package/dist/openapi_client/models/PodUpdateRequest.d.ts +0 -4
  37. package/dist/openapi_client/models/WorkflowCreateRequest.d.ts +7 -6
  38. package/dist/openapi_client/models/WorkflowGraphUpdateRequest.d.ts +2 -2
  39. package/dist/openapi_client/models/WorkflowInstallMode.d.ts +7 -0
  40. package/dist/openapi_client/models/WorkflowInstallMode.js +12 -0
  41. package/dist/openapi_client/models/WorkflowUpdateRequest.d.ts +5 -4
  42. package/dist/openapi_client/services/FilesService.d.ts +1 -1
  43. package/dist/openapi_client/services/FilesService.js +1 -1
  44. package/dist/openapi_client/services/PodJoinRequestsService.d.ts +44 -0
  45. package/dist/openapi_client/services/PodJoinRequestsService.js +93 -0
  46. package/dist/openapi_client/services/PodMembersService.d.ts +14 -4
  47. package/dist/openapi_client/services/PodMembersService.js +29 -8
  48. package/dist/openapi_client/services/RecordsService.d.ts +2 -2
  49. package/dist/openapi_client/services/RecordsService.js +2 -2
  50. package/dist/openapi_client/services/WorkflowsService.d.ts +1 -1
  51. package/dist/openapi_client/services/WorkflowsService.js +1 -1
  52. package/dist/react/AuthGuard.d.ts +5 -2
  53. package/dist/react/AuthGuard.js +126 -3
  54. package/dist/react/components/AssistantChrome.js +1 -1
  55. package/dist/react/components/AssistantExperience.d.ts +7 -2
  56. package/dist/react/components/AssistantExperience.js +272 -32
  57. package/dist/react/components/assistant-types.d.ts +1 -0
  58. package/dist/react/index.d.ts +0 -2
  59. package/dist/react/index.js +0 -1
  60. package/dist/react/styles.css +594 -224
  61. package/dist/react/useAssistantController.js +2 -1
  62. package/dist/react/useAssistantRuntime.d.ts +2 -1
  63. package/dist/react/useAssistantRuntime.js +7 -3
  64. package/dist/react/useTaskSession.js +145 -73
  65. package/dist/task-events.d.ts +2 -1
  66. package/dist/task-events.js +38 -1
  67. package/dist/types.d.ts +2 -1
  68. package/package.json +1 -1
  69. package/dist/openapi_client/models/PodStatus.d.ts +0 -4
  70. package/dist/openapi_client/models/PodStatus.js +0 -9
  71. package/dist/openapi_client/models/PodType.d.ts +0 -6
  72. package/dist/openapi_client/models/PodType.js +0 -11
  73. package/dist/react/useAgentRun.d.ts +0 -17
  74. package/dist/react/useAgentRun.js +0 -66
  75. /package/dist/openapi_client/models/{FlowStart.js → FlowStart_Input.js} +0 -0
package/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # Lemma TypeScript SDK (`lemma-sdk`)
2
2
 
3
- Official TypeScript SDK for Lemma APIs with pod-scoped namespaces, auth helpers, streaming support, and reusable React hooks.
3
+ Official TypeScript SDK for Lemma APIs with:
4
+
5
+ - Pod-scoped namespaces (`tables`, `records`, `files`, `assistants`,`agents` , `workflows`, `tasks`, .)
6
+ - Built-in auth/session handling
7
+ - SSE streaming helpers
8
+ - React hooks and assistant UI components
4
9
 
5
10
  ## Install
6
11
 
@@ -8,26 +13,14 @@ Official TypeScript SDK for Lemma APIs with pod-scoped namespaces, auth helpers,
8
13
  npm i lemma-sdk
9
14
  ```
10
15
 
11
- For local workspace development against the checked-out SDK instead of npm:
12
-
13
- ```bash
14
- npm i file:../lemma-typescript
15
- ```
16
-
17
- If you want to import as `lemma`, use npm aliasing:
18
-
19
- ```bash
20
- npm i lemma@npm:lemma-sdk
21
- ```
22
-
23
16
  ## Quick Start
24
17
 
25
18
  ```ts
26
19
  import { LemmaClient } from "lemma-sdk";
27
20
 
28
21
  const client = new LemmaClient({
29
- apiUrl: "https://api-next.asur.work",
30
- authUrl: "https://auth.asur.work/auth",
22
+ apiUrl: "https://api.lemma.work",
23
+ authUrl: "https://auth.lemma.work/auth",
31
24
  podId: "<pod-id>",
32
25
  });
33
26
 
@@ -38,588 +31,264 @@ const assistants = await client.assistants.list({ limit: 20 });
38
31
  const supportAssistant = await client.assistants.get("support_assistant");
39
32
  ```
40
33
 
41
- ## Core Concepts
42
-
43
- - `LemmaClient`: entrypoint with auth + API transport.
44
- - Namespace APIs (`client.agents`, `client.tasks`, `client.conversations`, etc.) for typed operations.
45
- - `client.request(method, path, options)` escape hatch for endpoints not yet modeled.
46
- - `client.resources` for generic file resource APIs (`conversation`, `assistant`, `task`, etc.).
47
- - Ergonomic type aliases exported at top level: `Agent`, `Assistant`, `Conversation`, `Task`, `TaskMessage`, `CreateAgentInput`, `CreateAssistantInput`, etc.
48
- - `client.withPod(podId)` returns a pod-scoped client that shares auth state with the parent client.
49
-
50
- ## Table Access Grants (`accessible_tables`)
51
-
52
- For function, agent, and assistant payloads, `accessible_tables` must be an array of objects:
53
-
54
- - `table_name`: target table
55
- - `mode`: `READ` or `WRITE`
56
-
57
- `accessible_tables: ["table_name"]` is no longer valid.
58
-
59
- You do not pass a datastore name in SDK calls. Table and file operations are pod-scoped (`client.tables`, `client.records`, `client.files`) and take table/file identifiers directly.
60
-
61
- Examples:
62
-
63
- ```ts
64
- import {
65
- TableAccessMode,
66
- type CreateFunctionRequest,
67
- type CreateAgentInput,
68
- type CreateAssistantInput,
69
- } from "lemma-sdk";
70
-
71
- const functionPayload: CreateFunctionRequest = {
72
- name: "expense_summary",
73
- code: "def handler(ctx):\n return {'ok': True}",
74
- config: {},
75
- accessible_tables: [
76
- { table_name: "expenses", mode: TableAccessMode.READ },
77
- { table_name: "expense_summaries", mode: TableAccessMode.WRITE },
78
- ],
79
- accessible_folders: ["/reports"],
80
- accessible_applications: [],
81
- };
82
-
83
- const agentPayload: CreateAgentInput = {
84
- name: "expense-summarizer",
85
- instruction: "Summarize expenses without mutating data.",
86
- tool_sets: [],
87
- accessible_tables: [
88
- { table_name: "expenses", mode: TableAccessMode.READ },
89
- { table_name: "expense_notes", mode: TableAccessMode.WRITE },
90
- ],
91
- accessible_folders: [],
92
- accessible_applications: [],
93
- };
94
-
95
- const assistantPayload: CreateAssistantInput = {
96
- name: "expense_assistant",
97
- instruction: "Answer expense questions and save approved notes.",
98
- tool_sets: [],
99
- accessible_tables: [
100
- { table_name: "expenses", mode: TableAccessMode.READ },
101
- { table_name: "expense_notes", mode: TableAccessMode.WRITE },
102
- ],
103
- accessible_folders: ["/notes"],
104
- accessible_applications: [],
105
- };
106
- ```
107
-
108
- ## Auth Helpers
34
+ ## Configuration
109
35
 
110
- ```ts
111
- import {
112
- LemmaClient,
113
- buildAuthUrl,
114
- buildFederatedLogoutUrl,
115
- resolveSafeRedirectUri,
116
- } from "lemma-sdk";
36
+ `LemmaClient` config resolution order:
117
37
 
118
- const client = new LemmaClient({
119
- apiUrl: "https://api-next.asur.work",
120
- authUrl: "https://auth.asur.work/auth",
121
- });
38
+ 1. Constructor overrides
39
+ 2. `window.__LEMMA_CONFIG__`
40
+ 3. Environment variables
41
+ 4. Defaults
122
42
 
123
- // Build auth URLs (server/client)
124
- const loginUrl = buildAuthUrl(client.authUrl, { redirectUri: "https://app.asur.work/" });
125
- const signupUrl = buildAuthUrl(client.authUrl, { mode: "signup", redirectUri: "https://app.asur.work/" });
43
+ Supported env keys:
126
44
 
127
- // Redirect safety helper for auth route handlers
128
- const safeRedirect = resolveSafeRedirectUri("/pod/123", {
129
- siteOrigin: "https://app.asur.work",
130
- fallback: "/",
131
- });
45
+ - `VITE_LEMMA_API_URL`, `REACT_APP_LEMMA_API_URL`, `LEMMA_API_URL`
46
+ - `VITE_LEMMA_AUTH_URL`, `REACT_APP_LEMMA_AUTH_URL`, `LEMMA_AUTH_URL`
47
+ - `VITE_LEMMA_POD_ID`, `REACT_APP_LEMMA_POD_ID`, `LEMMA_POD_ID`
132
48
 
133
- // Browser helpers
134
- await client.auth.checkAuth();
135
- await client.auth.signOut();
136
- const token = await client.auth.getAccessToken();
137
- const refreshed = await client.auth.refreshAccessToken();
138
- client.auth.redirectToAuth({ mode: "signup", redirectUri: safeRedirect });
49
+ Defaults when unset:
139
50
 
140
- // Build upstream logout URL (server/client)
141
- const federatedLogoutUrl = buildFederatedLogoutUrl(client.authUrl, {
142
- redirectUri: safeRedirect,
143
- });
51
+ - `apiUrl`: `http://localhost:8000`
52
+ - `authUrl`: `http://localhost:3000`
144
53
 
145
- // Browser: sign out locally, then clear upstream SSO and return to app
146
- await client.auth.redirectToFederatedLogout({ redirectUri: safeRedirect });
147
- ```
54
+ ## Pod Scoping
148
55
 
149
- ### Browser Testing With Injected Token
150
-
151
- For desk and app testing, the SDK supports a fixed bearer token injected through localStorage.
152
- This is the only supported browser token-injection path.
56
+ Most namespaces are pod-scoped. You can set pod scope in three ways:
153
57
 
154
58
  ```ts
155
- import { LemmaClient, setTestingToken, clearTestingToken } from "lemma-sdk";
156
-
157
- setTestingToken("<access-token>");
158
-
159
- const client = new LemmaClient({
160
- apiUrl: "/api",
161
- authUrl: "http://localhost:4173",
162
- podId: "<pod-id>",
163
- });
164
-
165
- await client.initialize();
59
+ client.setPodId("pod_a");
166
60
 
167
- clearTestingToken();
168
- ```
61
+ const podBClient = client.withPod("pod_b");
169
62
 
170
- Equivalent manual browser setup:
171
-
172
- ```js
173
- localStorage.setItem("lemma_token", "<access-token>");
174
- window.location.reload();
63
+ const conversations = await client.conversations.list({ pod_id: "pod_c" });
175
64
  ```
176
65
 
177
- Notes:
178
-
179
- - do not pass testing tokens in query parameters
180
- - prefer a same-origin dev proxy such as Vite `/api` during local browser testing to avoid CORS on `/users/me`
181
- - production auth should use the normal cookie/session flow
66
+ ## Namespace Overview
182
67
 
183
- ## Assistants + Agent Runs
68
+ Common pod-scoped namespaces:
184
69
 
185
- ### React assistant UI
70
+ - `client.tables`
71
+ - `client.records`
72
+ - `client.files`
73
+ - `client.functions`
74
+ - `client.agents`
75
+ - `client.tasks`
76
+ - `client.assistants`
77
+ - `client.workflows`
78
+ - `client.desks`
79
+ - `client.integrations`
80
+ - `client.resources`
186
81
 
187
- `lemma-sdk/react` ships the assistant controller, the default assistant experience, and the lower-level UI primitives used to build custom shells.
82
+ Org/user-level namespaces:
188
83
 
189
- Import the bundled stylesheet once anywhere in your app:
190
-
191
- ```tsx
192
- import "lemma-sdk/react/styles.css";
193
- ```
84
+ - `client.users`
85
+ - `client.icons`
86
+ - `client.pods`
87
+ - `client.podMembers`
88
+ - `client.podJoinRequests`
89
+ - `client.organizations`
90
+ - `client.podSurfaces`
194
91
 
195
- The stylesheet includes the SDK theme tokens and the complete semantic assistant UI. The assistant components do not depend on the host app's Tailwind version or Tailwind content scanning.
196
-
197
- If you alias the package to local SDK source in Vite, make sure the alias points at the React source and stylesheet:
92
+ Escape hatch for unmapped endpoints:
198
93
 
199
94
  ```ts
200
- // vite.config.ts
201
- import path from "node:path";
202
-
203
- export default {
204
- resolve: {
205
- alias: {
206
- "lemma-sdk/react/styles.css": path.resolve(__dirname, "../lemma-typescript/src/react/styles.css"),
207
- "lemma-sdk/react": path.resolve(__dirname, "../lemma-typescript/src/react/index.ts"),
208
- "lemma-sdk": path.resolve(__dirname, "../lemma-typescript/src/index.ts"),
209
- },
210
- },
211
- };
212
- ```
213
-
214
- Quick checklist for developers:
215
-
216
- - import `lemma-sdk/react/styles.css` once
217
- - give the assistant container a real height
218
- - if the assistant is inside flex/grid, add `min-height: 0` on the relevant parent
219
- - if you use `AssistantEmbedded`, pass `theme` directly there
220
- - if you use `AssistantExperienceView`, wrap it in `AssistantThemeScope`
221
-
222
- The assistant UI renders markdown by default:
223
-
224
- - GitHub-flavored markdown is enabled for assistant and user messages
225
- - raw HTML is not rendered
226
- - links open safely in a new tab by default
227
- - lists, tables, blockquotes, inline code, and fenced code blocks are styled out of the box
228
-
229
- #### Recommended path
230
-
231
- For most apps, start with `AssistantEmbedded`.
232
-
233
- - use `AssistantEmbedded` when you want the SDK to handle the controller lifecycle and render the ready-made assistant UI
234
- - use `AssistantExperienceView` when you still want the SDK's default assistant UI, but you need to own the controller lifecycle yourself
235
- - use `useAssistantController` plus primitives only when you are intentionally building a custom shell or custom layout
236
-
237
- If you are unsure, use `AssistantEmbedded` first. It is the path we recommend and the one we expect most SDK consumers to ship.
238
-
239
- #### Choose an integration level
240
-
241
- ##### 1. `AssistantEmbedded` for the fastest setup
242
-
243
- Use `AssistantEmbedded` when you want a ready-made assistant surface with the SDK defaults.
244
- This is the recommended integration for most users.
245
-
246
- ```tsx
247
- import "lemma-sdk/react/styles.css";
248
- import { AssistantEmbedded } from "lemma-sdk/react";
249
-
250
- function SupportAssistant() {
251
- return (
252
- <div style={{ height: 720, minHeight: 0 }}>
253
- <AssistantEmbedded
254
- client={client}
255
- podId="pod_123"
256
- assistantName="support_assistant"
257
- title="Support Assistant"
258
- subtitle="Ask questions about this pod."
259
- placeholder="Message Support Assistant"
260
- emptyStateSuggestions={[
261
- { text: "Summarize this conversation", icon: "✦" },
262
- { text: "Help me draft a response", icon: "✎" },
263
- { text: "List the next steps", icon: "→" },
264
- ]}
265
- showConversationList
266
- showModelPicker={false}
267
- radius="lg"
268
- theme="auto"
269
- />
270
- </div>
271
- );
272
- }
95
+ const result = await client.request("GET", "/models");
273
96
  ```
274
97
 
275
- Important notes:
98
+ ## CRUD Examples
276
99
 
277
- - `theme` accepts `"auto" | "light" | "dark"`
278
- - `radius` lets you pick the built-in rounding scale from `"none"` through `"xl"`
279
- - `showModelPicker={false}` hides the built-in model chooser when you do not want model controls visible
280
- - `theme="auto"` follows the host app when it uses common selectors like `.dark`, `[data-theme="dark"]`, `[data-mode="dark"]`, and also falls back to `prefers-color-scheme`
281
- - the parent container must have a real height; if it lives inside flex/grid, `min-height: 0` is usually needed too
282
- - attachments are queued into the composer and sent with the next message by default
283
- - `emptyStateSuggestions` lets you replace the built-in prompt chips shown before the first message
284
- - prefer this component unless you specifically need to own controller state or replace the built-in layout
100
+ ### Tables + Records
285
101
 
286
- ##### 2. `AssistantExperienceView` for the default UI with your own controller
287
-
288
- Use `AssistantExperienceView` when you want the built-in assistant layout, but you need to own the controller lifecycle yourself.
289
- This is the second-best default when `AssistantEmbedded` is too opinionated for your integration.
102
+ ```ts
103
+ await client.tables.create({ name: "todos" });
290
104
 
291
- ```tsx
292
- import "lemma-sdk/react/styles.css";
293
- import {
294
- AssistantExperienceView,
295
- AssistantThemeScope,
296
- useAssistantController,
297
- } from "lemma-sdk/react";
298
-
299
- function ControlledAssistant() {
300
- const assistant = useAssistantController({
301
- client,
302
- podId: "pod_123",
303
- assistantName: "support_assistant",
304
- });
105
+ await client.records.create("todos", {
106
+ title: "Ship docs rewrite",
107
+ status: "todo",
108
+ });
305
109
 
306
- return (
307
- <AssistantThemeScope theme="dark" style={{ height: 720 }}>
308
- <AssistantExperienceView
309
- controller={assistant}
310
- title="Support Assistant"
311
- subtitle="Direct use of the default assistant experience."
312
- placeholder="Message Support Assistant"
313
- emptyStateSuggestions={[
314
- { text: "Summarize the current context" },
315
- { text: "Help me write a reply" },
316
- { text: "What should I do next?" },
317
- ]}
318
- showConversationList
319
- chromeStyle="subtle"
320
- statusPlacement="inline"
321
- />
322
- </AssistantThemeScope>
323
- );
324
- }
110
+ const page = await client.records.list("todos", {
111
+ limit: 20,
112
+ sort: [{ field: "created_at", direction: "desc" }],
113
+ });
325
114
  ```
326
115
 
327
- Useful props on `AssistantExperienceView`:
328
-
329
- - `showConversationList`: show the built-in conversation sidebar
330
- - `chromeStyle`: `"elevated" | "subtle" | "flat"`
331
- - `statusPlacement`: `"inline" | "composer" | "none"`
332
- - `radius`: `"none" | "sm" | "md" | "lg" | "xl"`
333
- - `showModelPicker`: show or hide the built-in model selector
334
- - `showNewConversationButton`: show or hide the built-in reset/new-conversation button
335
- - `emptyStateSuggestions`: replace the built-in generic prompt suggestions used by the default empty state
336
- - `renderMessageContent`: override markdown rendering for custom message content
337
- - `renderToolInvocation`: replace the default tool activity renderer
338
- - `renderPresentedFile` and `renderPendingFile`: customize attachment rendering
339
- - prefer this over building from primitives if you still want the SDK's default assistant experience
340
-
341
- ##### 3. `useAssistantController` + primitives for a custom shell
116
+ ### Files (Datastore)
342
117
 
343
- Use the primitives when you want full control over layout and app chrome.
344
- This is the advanced path and should be the exception, not the starting point.
345
-
346
- ```tsx
347
- import "lemma-sdk/react/styles.css";
348
- import {
349
- AssistantComposer,
350
- AssistantHeader,
351
- AssistantMessageViewport,
352
- AssistantShellLayout,
353
- AssistantThemeScope,
354
- EmptyState,
355
- MessageGroup,
356
- PlanSummaryStrip,
357
- ThinkingIndicator,
358
- buildDisplayMessageRows,
359
- getActiveToolBanner,
360
- latestPlanSummary,
361
- useAssistantController,
362
- } from "lemma-sdk/react";
363
-
364
- function CustomAssistantShell() {
365
- const assistant = useAssistantController({
366
- client,
367
- podId: "pod_123",
368
- assistantName: "support_assistant",
369
- });
118
+ ```ts
119
+ await client.files.folder.create("reports", { directoryPath: "/" });
120
+ await client.files.upload(fileBlob, { directoryPath: "/reports", name: "q1.pdf" });
370
121
 
371
- const rows = buildDisplayMessageRows(assistant.messages);
372
- const plan = latestPlanSummary(assistant.messages);
373
- const activeToolBanner = getActiveToolBanner(assistant.messages);
374
-
375
- return (
376
- <AssistantThemeScope theme="auto" style={{ height: 720 }}>
377
- <AssistantShellLayout
378
- main={(
379
- <div className="flex min-h-0 flex-1 flex-col gap-3">
380
- <AssistantHeader
381
- title="Lemma Assistant"
382
- subtitle="Ask anything"
383
- />
384
-
385
- {plan ? <PlanSummaryStrip plan={plan} onHide={() => {}} /> : null}
386
- {activeToolBanner ? <div>{activeToolBanner.summary}</div> : null}
387
-
388
- <AssistantMessageViewport>
389
- {assistant.messages.length === 0 ? (
390
- <EmptyState
391
- suggestions={[
392
- { text: "Summarize this for me" },
393
- { text: "Help me draft a reply" },
394
- { text: "Brainstorm next steps" },
395
- ]}
396
- onSendMessage={(text) => {
397
- void assistant.sendMessage(text);
398
- }}
399
- />
400
- ) : null}
401
-
402
- {rows.map((row, index) => (
403
- <MessageGroup
404
- key={row.id}
405
- message={row.message}
406
- conversationId={assistant.activeConversationId}
407
- onWidgetSendPrompt={(text) => assistant.sendMessage(text)}
408
- isStreaming={assistant.isActiveConversationRunning && row.sourceIndexes.includes(assistant.messages.length - 1)}
409
- showAssistantHeader={index === 0 || rows[index - 1]?.message.role !== "assistant"}
410
- renderMessageContent={({ message }) => <div>{message.content}</div>}
411
- />
412
- ))}
413
-
414
- {assistant.isActiveConversationRunning ? <ThinkingIndicator /> : null}
415
- </AssistantMessageViewport>
416
-
417
- <AssistantComposer>
418
- <textarea placeholder="Message Lemma Assistant" />
419
- </AssistantComposer>
420
- </div>
421
- )}
422
- />
423
- </AssistantThemeScope>
424
- );
425
- }
122
+ const listing = await client.files.list({ directoryPath: "/reports" });
123
+ const downloaded = await client.files.download("/reports/q1.pdf");
426
124
  ```
427
125
 
428
- Useful primitives exported from `lemma-sdk/react`:
429
-
430
- - `AssistantThemeScope`
431
- - `AssistantHeader`
432
- - `AssistantConversationList`
433
- - `AssistantModelPicker`
434
- - `AssistantShellLayout`
435
- - `AssistantComposer`
436
- - `AssistantMessageViewport`
437
- - `AssistantAskOverlay`
438
- - `AssistantPendingFileChip`
439
- - `AssistantStatusPill`
440
- - `MessageGroup`
441
- - `PlanSummaryStrip`
442
- - `ThinkingIndicator`
443
-
444
- Guidance:
126
+ ### Assistants + Conversations
445
127
 
446
- - prefer `AssistantEmbedded` over this path when the SDK layout is acceptable
447
- - prefer `AssistantExperienceView` over this path when you only need controller ownership, theming control, or a few render overrides
448
- - reach for primitives only when you are replacing the layout itself or deeply integrating the assistant into app-specific chrome
449
-
450
- Default empty-state suggestions are intentionally generic so they work across support, internal tools, content, and general assistant use cases. Override them with `emptyStateSuggestions` when you want task-specific prompts.
451
-
452
- #### Theming
453
-
454
- Use `AssistantThemeScope` around custom assistant layouts:
128
+ ```ts
129
+ await client.assistants.create({
130
+ name: "support_assistant",
131
+ instruction: "Help with support triage.",
132
+ });
455
133
 
456
- ```tsx
457
- import { AssistantThemeScope } from "lemma-sdk/react";
134
+ const conversation = await client.conversations.createForAssistant("support_assistant", {
135
+ title: "Ticket review",
136
+ });
458
137
 
459
- <AssistantThemeScope theme="light">
460
- <YourAssistant />
461
- </AssistantThemeScope>
138
+ await client.conversations.messages.send(conversation.id, {
139
+ content: "Summarize unresolved issues from today.",
140
+ });
462
141
  ```
463
142
 
464
- Theme behavior:
465
-
466
- - `theme="auto"`: follows host dark-mode selectors and system color scheme
467
- - `theme="light"`: forces the light SDK palette
468
- - `theme="dark"`: forces the dark SDK palette
469
-
470
- If you use `AssistantEmbedded`, pass `theme` directly on that component instead of wrapping it again.
471
-
472
- #### What belongs in the SDK vs your app
473
-
474
- The intended split is:
475
-
476
- - SDK: `useAssistantController`, message/tool normalization, markdown rendering, plan parsing, tool rollups, and reusable assistant UI primitives
477
- - App: modal shell, fullscreen/window controls, route navigation, workspace/file viewers, and product-specific renderers
478
-
479
- ### Assistant names (resource key)
480
-
481
- Assistant CRUD is name-based:
143
+ ### Pod Join Requests
482
144
 
483
145
  ```ts
484
- await client.assistants.get("support_assistant");
485
- await client.assistants.update("support_assistant", { description: "Handles support triage" });
486
- await client.assistants.delete("old_assistant");
487
- ```
146
+ // Current user requests access to a pod
147
+ await client.podJoinRequests.create("pod_123");
488
148
 
489
- ### Conversation scoping by assistant name
149
+ // Current user's pending request (or null)
150
+ const mine = await client.podJoinRequests.me("pod_123");
490
151
 
491
- ```ts
492
- const conversations = await client.conversations.list({
493
- assistantName: "support_assistant",
494
- limit: 20,
152
+ // Admin view of requests for a pod
153
+ const requests = await client.podJoinRequests.list("pod_123", {
154
+ status: "PENDING",
155
+ limit: 50,
495
156
  });
496
157
 
497
- const conversation = await client.conversations.createForAssistant("support_assistant", {
498
- title: "Ticket triage",
158
+ // Admin approval (defaults: ORG_MEMBER + POD_USER)
159
+ await client.podJoinRequests.approve("pod_123", "join_req_abc", {
160
+ org_role: "ORG_MEMBER",
161
+ pod_role: "POD_USER",
499
162
  });
500
163
  ```
501
164
 
502
- ### Conversations with SSE streaming
165
+ ## Streaming (SSE)
166
+
167
+ Use `readSSE` + `parseSSEJson` for incremental events.
503
168
 
504
169
  ```ts
170
+ import { readSSE, parseSSEJson } from "lemma-sdk";
171
+
505
172
  const stream = await client.conversations.sendMessageStream(conversationId, {
506
- content: "Find open support tickets from yesterday",
173
+ content: "Analyze recent incidents",
507
174
  });
508
175
 
509
176
  for await (const event of readSSE(stream)) {
510
177
  const payload = parseSSEJson(event);
511
178
  if (!payload) continue;
512
- console.log(payload);
179
+ console.log(event.event, payload);
513
180
  }
514
181
  ```
515
182
 
516
- ### Task runs with SSE streaming
183
+ Task stream example:
517
184
 
518
185
  ```ts
519
186
  const task = await client.tasks.create({
520
- agentId: "triage-agent",
521
- input: { ticketId: "TCK-1042" },
522
- runtimeAccountIds: ["acc_123"],
187
+ agent_name: "triage_agent",
188
+ input_data: { ticketId: "TCK-1042" },
523
189
  });
524
190
 
525
- const stream = await client.tasks.stream(task.id);
526
- for await (const event of readSSE(stream)) {
527
- const payload = parseSSEJson(event);
528
- if (!payload) continue;
529
- console.log(payload);
530
- }
191
+ const taskStream = await client.tasks.stream(task.id);
531
192
  ```
532
193
 
533
- ## React Helpers
194
+ ## Access Grants (`accessible_tables`)
534
195
 
535
- Import from `lemma-sdk/react`:
196
+ When creating agents/functions/assistants, `accessible_tables` must use object entries:
536
197
 
537
- - `useAuth(client)`
538
- - `AuthGuard`
539
- - `useAgentRunStream(...)`
540
- - `useAssistantRun(...)`
541
- - `useAssistantSession(...)`
542
- - `useTaskSession(...)`
543
- - `useFunctionSession(...)`
544
- - `useFlowSession(...)`
545
-
546
- Core run helpers from `lemma-sdk`:
547
-
548
- - `normalizeRunStatus(...)`
549
- - `isTerminalTaskStatus(...)`
550
- - `isTerminalFunctionStatus(...)`
551
- - `isTerminalFlowStatus(...)`
552
- - `parseTaskStreamEvent(...)`
553
- - `upsertTaskMessage(...)`
554
- - `parseAssistantStreamEvent(...)`
555
- - `upsertConversationMessage(...)`
556
-
557
- Example:
198
+ ```ts
199
+ import { TableAccessMode } from "lemma-sdk";
558
200
 
559
- ```tsx
560
- import { useAssistantRun } from "lemma-sdk/react";
561
-
562
- const { sendMessage, stop, isStreaming } = useAssistantRun({
563
- client,
564
- podId,
565
- conversationId,
566
- onEvent: (event, payload) => {
567
- console.log(event.event, payload);
568
- },
569
- });
201
+ accessible_tables: [
202
+ { table_name: "expenses", mode: TableAccessMode.READ },
203
+ { table_name: "expense_notes", mode: TableAccessMode.WRITE },
204
+ ];
570
205
  ```
571
206
 
572
- For the SDK consumption UI roadmap (AssistantChat / FunctionInvokeForm / FlowRunExperience / RunPanel), see:
207
+ `["expenses"]` is not valid.
208
+
209
+ ## Auth
573
210
 
574
- - `docs/sdk-consumption-ui-v2.md`
211
+ Default mode is cookie/session auth (`credentials: "include"`).
575
212
 
576
- ## File Resources
213
+ For local browser testing, token injection is supported via local storage key `lemma_token`:
577
214
 
578
215
  ```ts
579
- await client.resources.upload("conversation", conversationId, file);
580
- const files = await client.resources.list("conversation", conversationId);
216
+ import { setTestingToken, clearTestingToken } from "lemma-sdk";
217
+
218
+ setTestingToken("<access-token>");
219
+ clearTestingToken();
581
220
  ```
582
221
 
583
- ## Migration Tips
222
+ Auth helpers:
584
223
 
585
- When migrating from direct `fetch`/custom API clients:
224
+ - `buildAuthUrl(...)`
225
+ - `buildFederatedLogoutUrl(...)`
226
+ - `resolveSafeRedirectUri(...)`
227
+ - `client.auth.redirectToAuth(...)`
228
+ - `client.auth.redirectToFederatedLogout(...)`
586
229
 
587
- 1. Replace auth/session bootstrapping with `LemmaClient`.
588
- 2. Move pod-scoped calls into namespaces (`tasks`, `assistants`, `conversations`, etc.).
589
- 3. Keep rare/unmodeled endpoints on `client.request(...)` temporarily.
590
- 4. Replace SSE parsing code with `readSSE` + `parseSSEJson`.
591
- 5. Gradually lift app-specific run/chat logic into reusable hooks in `lemma-sdk/react`.
230
+ ## React Package (`lemma-sdk/react`)
592
231
 
593
- ## Development
232
+ Includes auth helpers, run hooks, and assistant UI primitives.
594
233
 
595
- ### Regenerate OpenAPI client
234
+ Install React peer dependency in your app if not already installed:
596
235
 
597
236
  ```bash
598
- bash scripts/generate_openapi_client.sh
237
+ npm i react react-dom
599
238
  ```
600
239
 
601
- ### Build SDK
240
+ Import stylesheet once:
602
241
 
603
- ```bash
604
- npm run build
242
+ ```tsx
243
+ import "lemma-sdk/react/styles.css";
605
244
  ```
606
245
 
607
- Output:
608
-
609
- - `dist/` npm package artifacts
610
- - `dist/browser/lemma-client.js` standalone browser bundle
611
- - `public/lemma-client.js` committed copy for static serving
246
+ Fastest assistant integration:
612
247
 
613
- ### Release check
248
+ ```tsx
249
+ import { AssistantEmbedded } from "lemma-sdk/react";
614
250
 
615
- ```bash
616
- npm run release:check
251
+ <div style={{ height: 720, minHeight: 0 }}>
252
+ <AssistantEmbedded
253
+ client={client}
254
+ podId="<pod-id>"
255
+ assistantName="support_assistant"
256
+ title="Support Assistant"
257
+ placeholder="Message Support Assistant"
258
+ showConversationList
259
+ />
260
+ </div>;
617
261
  ```
618
262
 
619
- ### Publish
263
+ Auth guard example:
620
264
 
621
- ```bash
622
- npm publish
265
+ ```tsx
266
+ import { AuthGuard } from "lemma-sdk/react";
267
+
268
+ <AuthGuard client={client}>
269
+ <App />
270
+ </AuthGuard>;
623
271
  ```
624
272
 
625
- As of March 26, 2026, npm package name `lemma` is already taken. This package publishes as `lemma-sdk`.
273
+ When `client.podId` is set and the signed-in user is not a pod member, `AuthGuard` automatically renders a request-access state and can create/view pod join requests.
274
+
275
+ ## Browser Bundle
276
+
277
+ The package also ships a standalone browser bundle:
278
+
279
+ - npm artifact path: `dist/browser/lemma-client.js`
280
+ - export path: `lemma-sdk/browser-bundle`
281
+ - global: `window.LemmaClient.LemmaClient`
282
+
283
+ Example:
284
+
285
+ ```html
286
+ <script src="https://unpkg.com/lemma-sdk@latest/dist/browser/lemma-client.js"></script>
287
+ <script>
288
+ const client = new window.LemmaClient.LemmaClient({
289
+ apiUrl: "https://api.lemma.work",
290
+ authUrl: "https://auth.lemma.work/auth",
291
+ podId: "<pod-id>"
292
+ });
293
+ </script>
294
+ ```