lemma-sdk 0.2.0 → 0.2.2

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 (42) hide show
  1. package/README.md +108 -36
  2. package/dist/browser/lemma-client.js +2012 -1242
  3. package/dist/client.d.ts +23 -6
  4. package/dist/client.js +32 -11
  5. package/dist/http.d.ts +18 -5
  6. package/dist/http.js +77 -22
  7. package/dist/index.d.ts +16 -7
  8. package/dist/index.js +1 -0
  9. package/dist/namespaces/assistants.d.ts +61 -16
  10. package/dist/namespaces/assistants.js +130 -19
  11. package/dist/namespaces/icons.d.ts +7 -0
  12. package/dist/namespaces/icons.js +13 -0
  13. package/dist/namespaces/organizations.d.ts +46 -0
  14. package/dist/namespaces/organizations.js +51 -0
  15. package/dist/namespaces/pod-members.d.ts +15 -0
  16. package/dist/namespaces/pod-members.js +19 -0
  17. package/dist/namespaces/pod-surfaces.d.ts +16 -0
  18. package/dist/namespaces/pod-surfaces.js +22 -0
  19. package/dist/namespaces/pods.d.ts +26 -0
  20. package/dist/namespaces/pods.js +41 -0
  21. package/dist/namespaces/records.d.ts +7 -3
  22. package/dist/namespaces/records.js +34 -3
  23. package/dist/namespaces/resources.d.ts +16 -0
  24. package/dist/namespaces/resources.js +32 -0
  25. package/dist/namespaces/tables.d.ts +7 -1
  26. package/dist/namespaces/tables.js +11 -1
  27. package/dist/namespaces/tasks.d.ts +15 -9
  28. package/dist/namespaces/tasks.js +43 -11
  29. package/dist/namespaces/users.d.ts +9 -0
  30. package/dist/namespaces/users.js +16 -0
  31. package/dist/namespaces/workflows.d.ts +8 -1
  32. package/dist/namespaces/workflows.js +23 -1
  33. package/dist/react/index.d.ts +4 -0
  34. package/dist/react/index.js +2 -0
  35. package/dist/react/useAgentRun.d.ts +17 -0
  36. package/dist/react/useAgentRun.js +66 -0
  37. package/dist/react/useAssistantRun.d.ts +18 -0
  38. package/dist/react/useAssistantRun.js +82 -0
  39. package/dist/streams.d.ts +10 -0
  40. package/dist/streams.js +68 -0
  41. package/dist/types.d.ts +39 -1
  42. package/package.json +5 -5
@@ -1,9 +1,12 @@
1
+ import { ApiError } from "../http.js";
1
2
  import { WorkflowsService } from "../openapi_client/services/WorkflowsService.js";
2
3
  export class WorkflowsNamespace {
3
4
  client;
5
+ http;
4
6
  podId;
5
- constructor(client, podId) {
7
+ constructor(client, http, podId) {
6
8
  this.client = client;
9
+ this.http = http;
7
10
  this.podId = podId;
8
11
  }
9
12
  list(options = {}) {
@@ -21,6 +24,9 @@ export class WorkflowsNamespace {
21
24
  delete(workflowName) {
22
25
  return this.client.request(() => WorkflowsService.workflowDelete(this.podId(), workflowName));
23
26
  }
27
+ visualize(workflowName) {
28
+ return this.client.request(() => WorkflowsService.workflowVisualize(this.podId(), workflowName));
29
+ }
24
30
  graph = {
25
31
  update: (workflowName, graph) => this.client.request(() => WorkflowsService.workflowGraphUpdate(this.podId(), workflowName, graph)),
26
32
  };
@@ -28,10 +34,26 @@ export class WorkflowsNamespace {
28
34
  create: (workflowName, payload = {}) => this.client.request(() => WorkflowsService.workflowInstallCreate(this.podId(), workflowName, payload)),
29
35
  delete: (workflowName, installId) => this.client.request(() => WorkflowsService.workflowInstallDelete(this.podId(), workflowName, installId)),
30
36
  };
37
+ async postRunAction(runId, action, podId) {
38
+ const encodedPodId = encodeURIComponent(podId);
39
+ const encodedRunId = encodeURIComponent(runId);
40
+ try {
41
+ return await this.http.request("POST", `/pods/${encodedPodId}/workflow-runs/${encodedRunId}/${action}`, { body: {} });
42
+ }
43
+ catch (error) {
44
+ if (error instanceof ApiError && (error.statusCode === 404 || error.statusCode === 405)) {
45
+ return this.http.request("POST", `/pods/${encodedPodId}/flow-runs/${encodedRunId}/${action}`, { body: {} });
46
+ }
47
+ throw error;
48
+ }
49
+ }
31
50
  runs = {
32
51
  start: (workflowName, inputs = {}) => this.client.request(() => WorkflowsService.workflowStart(this.podId(), workflowName, inputs)),
33
52
  list: (workflowName, options = {}) => this.client.request(() => WorkflowsService.workflowRunList(this.podId(), workflowName, options.limit ?? 100, options.pageToken)),
34
53
  get: (runId, podId = this.podId()) => this.client.request(() => WorkflowsService.workflowRunGet(podId, runId)),
35
54
  resume: (runId, inputs = {}, podId = this.podId()) => this.client.request(() => WorkflowsService.workflowRunResume(podId, runId, inputs)),
55
+ visualize: (runId, podId = this.podId()) => this.client.request(() => WorkflowsService.workflowRunVisualize(podId, runId)),
56
+ cancel: (runId, podId = this.podId()) => this.postRunAction(runId, "cancel", podId),
57
+ retry: (runId, podId = this.podId()) => this.postRunAction(runId, "retry", podId),
36
58
  };
37
59
  }
@@ -2,3 +2,7 @@ export { AuthGuard } from "./AuthGuard.js";
2
2
  export type { AuthGuardProps } from "./AuthGuard.js";
3
3
  export { useAuth } from "./useAuth.js";
4
4
  export type { UseAuthResult } from "./useAuth.js";
5
+ export { useAgentRunStream } from "./useAgentRun.js";
6
+ export type { UseAgentRunStreamOptions, UseAgentRunStreamResult } from "./useAgentRun.js";
7
+ export { useAssistantRun } from "./useAssistantRun.js";
8
+ export type { UseAssistantRunOptions, UseAssistantRunResult } from "./useAssistantRun.js";
@@ -1,2 +1,4 @@
1
1
  export { AuthGuard } from "./AuthGuard.js";
2
2
  export { useAuth } from "./useAuth.js";
3
+ export { useAgentRunStream } from "./useAgentRun.js";
4
+ export { useAssistantRun } from "./useAssistantRun.js";
@@ -0,0 +1,17 @@
1
+ import type { LemmaClient } from "../client.js";
2
+ import { type SseRawEvent } from "../streams.js";
3
+ export interface UseAgentRunStreamOptions {
4
+ client: LemmaClient;
5
+ podId?: string;
6
+ taskId?: string | null;
7
+ autoConnect?: boolean;
8
+ onEvent?: (event: SseRawEvent, payload: unknown | null) => void;
9
+ onError?: (error: unknown) => void;
10
+ }
11
+ export interface UseAgentRunStreamResult {
12
+ isStreaming: boolean;
13
+ error: Error | null;
14
+ connect: () => Promise<void>;
15
+ disconnect: () => void;
16
+ }
17
+ export declare function useAgentRunStream({ client, podId, taskId, autoConnect, onEvent, onError, }: UseAgentRunStreamOptions): UseAgentRunStreamResult;
@@ -0,0 +1,66 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { parseSSEJson, readSSE } from "../streams.js";
3
+ function resolvePodId(client, podId) {
4
+ const resolved = podId ?? client.podId;
5
+ if (!resolved) {
6
+ throw new Error("podId is required. Pass podId or set it on LemmaClient.");
7
+ }
8
+ return resolved;
9
+ }
10
+ export function useAgentRunStream({ client, podId, taskId, autoConnect = true, onEvent, onError, }) {
11
+ const [isStreaming, setIsStreaming] = useState(false);
12
+ const [error, setError] = useState(null);
13
+ const abortRef = useRef(null);
14
+ const disconnect = useCallback(() => {
15
+ abortRef.current?.abort();
16
+ abortRef.current = null;
17
+ }, []);
18
+ const connect = useCallback(async () => {
19
+ if (!taskId) {
20
+ return;
21
+ }
22
+ disconnect();
23
+ const controller = new AbortController();
24
+ abortRef.current = controller;
25
+ setError(null);
26
+ setIsStreaming(true);
27
+ try {
28
+ client.setPodId(resolvePodId(client, podId));
29
+ const stream = await client.tasks.stream(taskId, { signal: controller.signal });
30
+ for await (const event of readSSE(stream)) {
31
+ if (controller.signal.aborted) {
32
+ break;
33
+ }
34
+ onEvent?.(event, parseSSEJson(event));
35
+ }
36
+ }
37
+ catch (streamError) {
38
+ if (!(streamError instanceof Error && streamError.name === "AbortError")) {
39
+ const normalized = streamError instanceof Error
40
+ ? streamError
41
+ : new Error("Failed to stream agent run.");
42
+ setError(normalized);
43
+ onError?.(streamError);
44
+ }
45
+ }
46
+ finally {
47
+ if (abortRef.current === controller) {
48
+ abortRef.current = null;
49
+ }
50
+ setIsStreaming(false);
51
+ }
52
+ }, [client, disconnect, onError, onEvent, podId, taskId]);
53
+ useEffect(() => {
54
+ if (!autoConnect || !taskId) {
55
+ return;
56
+ }
57
+ void connect();
58
+ return () => disconnect();
59
+ }, [autoConnect, connect, disconnect, taskId]);
60
+ return {
61
+ isStreaming,
62
+ error,
63
+ connect,
64
+ disconnect,
65
+ };
66
+ }
@@ -0,0 +1,18 @@
1
+ import type { LemmaClient } from "../client.js";
2
+ import { type SseRawEvent } from "../streams.js";
3
+ export interface UseAssistantRunOptions {
4
+ client: LemmaClient;
5
+ podId?: string;
6
+ conversationId?: string | null;
7
+ onEvent?: (event: SseRawEvent, payload: unknown | null) => void;
8
+ onError?: (error: unknown) => void;
9
+ }
10
+ export interface UseAssistantRunResult {
11
+ isStreaming: boolean;
12
+ error: Error | null;
13
+ sendMessage: (content: string) => Promise<void>;
14
+ resume: () => Promise<void>;
15
+ stop: () => Promise<void>;
16
+ cancel: () => void;
17
+ }
18
+ export declare function useAssistantRun({ client, podId, conversationId, onEvent, onError, }: UseAssistantRunOptions): UseAssistantRunResult;
@@ -0,0 +1,82 @@
1
+ import { useCallback, useRef, useState } from "react";
2
+ import { parseSSEJson, readSSE } from "../streams.js";
3
+ function requireConversationId(conversationId) {
4
+ if (!conversationId) {
5
+ throw new Error("conversationId is required.");
6
+ }
7
+ return conversationId;
8
+ }
9
+ function resolvePodId(client, podId) {
10
+ const resolved = podId ?? client.podId;
11
+ if (!resolved) {
12
+ throw new Error("podId is required. Pass podId or set it on LemmaClient.");
13
+ }
14
+ return resolved;
15
+ }
16
+ export function useAssistantRun({ client, podId, conversationId, onEvent, onError, }) {
17
+ const [isStreaming, setIsStreaming] = useState(false);
18
+ const [error, setError] = useState(null);
19
+ const abortRef = useRef(null);
20
+ const consume = useCallback(async (stream, controller) => {
21
+ setIsStreaming(true);
22
+ setError(null);
23
+ try {
24
+ for await (const event of readSSE(stream)) {
25
+ if (controller.signal.aborted) {
26
+ break;
27
+ }
28
+ onEvent?.(event, parseSSEJson(event));
29
+ }
30
+ }
31
+ catch (streamError) {
32
+ if (!(streamError instanceof Error && streamError.name === "AbortError")) {
33
+ const normalized = streamError instanceof Error
34
+ ? streamError
35
+ : new Error("Failed to stream assistant run.");
36
+ setError(normalized);
37
+ onError?.(streamError);
38
+ }
39
+ }
40
+ finally {
41
+ if (abortRef.current === controller) {
42
+ abortRef.current = null;
43
+ }
44
+ setIsStreaming(false);
45
+ }
46
+ }, [onError, onEvent]);
47
+ const cancel = useCallback(() => {
48
+ abortRef.current?.abort();
49
+ abortRef.current = null;
50
+ }, []);
51
+ const sendMessage = useCallback(async (content) => {
52
+ const id = requireConversationId(conversationId);
53
+ cancel();
54
+ const controller = new AbortController();
55
+ abortRef.current = controller;
56
+ client.setPodId(resolvePodId(client, podId));
57
+ const stream = await client.conversations.sendMessageStream(id, { content }, { signal: controller.signal });
58
+ await consume(stream, controller);
59
+ }, [cancel, client, consume, conversationId, podId]);
60
+ const resume = useCallback(async () => {
61
+ const id = requireConversationId(conversationId);
62
+ cancel();
63
+ const controller = new AbortController();
64
+ abortRef.current = controller;
65
+ client.setPodId(resolvePodId(client, podId));
66
+ const stream = await client.conversations.resumeStream(id, { signal: controller.signal });
67
+ await consume(stream, controller);
68
+ }, [cancel, client, consume, conversationId, podId]);
69
+ const stop = useCallback(async () => {
70
+ const id = requireConversationId(conversationId);
71
+ client.setPodId(resolvePodId(client, podId));
72
+ await client.conversations.stopRun(id);
73
+ }, [client, conversationId, podId]);
74
+ return {
75
+ isStreaming,
76
+ error,
77
+ sendMessage,
78
+ resume,
79
+ stop,
80
+ cancel,
81
+ };
82
+ }
@@ -0,0 +1,10 @@
1
+ export interface SseRawEvent {
2
+ event?: string;
3
+ data: string;
4
+ raw: string;
5
+ }
6
+ /**
7
+ * Async iterator over Server-Sent Event frames.
8
+ */
9
+ export declare function readSSE(stream: ReadableStream<Uint8Array>): AsyncGenerator<SseRawEvent, void, unknown>;
10
+ export declare function parseSSEJson<T = unknown>(event: SseRawEvent): T | null;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Async iterator over Server-Sent Event frames.
3
+ */
4
+ export async function* readSSE(stream) {
5
+ const reader = stream.getReader();
6
+ const decoder = new TextDecoder();
7
+ let buffer = "";
8
+ let eventName;
9
+ let dataLines = [];
10
+ const flush = () => {
11
+ if (dataLines.length === 0) {
12
+ eventName = undefined;
13
+ return null;
14
+ }
15
+ const data = dataLines.join("\n");
16
+ const raw = `${eventName ? `event: ${eventName}\n` : ""}${dataLines
17
+ .map((line) => `data: ${line}`)
18
+ .join("\n")}`;
19
+ const next = {
20
+ event: eventName,
21
+ data,
22
+ raw,
23
+ };
24
+ eventName = undefined;
25
+ dataLines = [];
26
+ return next;
27
+ };
28
+ while (true) {
29
+ const { done, value } = await reader.read();
30
+ if (done)
31
+ break;
32
+ buffer += decoder.decode(value, { stream: true });
33
+ const lines = buffer.split("\n");
34
+ buffer = lines.pop() || "";
35
+ for (const line of lines) {
36
+ const trimmed = line.endsWith("\r") ? line.slice(0, -1) : line;
37
+ if (trimmed === "") {
38
+ const event = flush();
39
+ if (event) {
40
+ yield event;
41
+ }
42
+ continue;
43
+ }
44
+ if (trimmed.startsWith("event:")) {
45
+ eventName = trimmed.slice("event:".length).trim();
46
+ continue;
47
+ }
48
+ if (trimmed.startsWith("data:")) {
49
+ dataLines.push(trimmed.slice("data:".length).trim());
50
+ }
51
+ }
52
+ }
53
+ const event = flush();
54
+ if (event) {
55
+ yield event;
56
+ }
57
+ }
58
+ export function parseSSEJson(event) {
59
+ if (!event.data || event.data === "[DONE]") {
60
+ return null;
61
+ }
62
+ try {
63
+ return JSON.parse(event.data);
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { RecordFilter as GeneratedRecordFilter } from "./openapi_client/models/RecordFilter.js";
2
2
  import type { RecordSort as GeneratedRecordSort } from "./openapi_client/models/RecordSort.js";
3
+ import type { AgentResponse, AssistantResponse, AvailableModels, ConversationMessageResponse, ConversationResponse, CreateAgentRequest, CreateAssistantRequest, IconUploadResponse, OrganizationInvitationResponse, OrganizationMemberResponse, OrganizationResponse, PodConfigResponse, PodMemberResponse, PodResponse, TaskMessageResponse, TaskResponse, UpdateAgentRequest, UpdateAssistantRequest, UserResponse } from "./openapi_client/index.js";
3
4
  /** Public ergonomic types. */
4
5
  export interface PageResult<T> {
5
6
  items: T[];
@@ -13,15 +14,52 @@ export interface ListRecordsOptions {
13
14
  sort?: RecordSort[];
14
15
  limit?: number;
15
16
  pageToken?: string;
17
+ offset?: number;
18
+ sortBy?: string;
19
+ order?: "asc" | "desc" | string;
20
+ params?: Record<string, string | number | boolean | undefined | null>;
16
21
  }
17
22
  export interface RunFunctionOptions {
18
23
  /** Input payload for the function */
19
24
  input?: Record<string, unknown>;
20
25
  }
21
26
  export interface CreateTaskOptions {
22
- agentName: string;
27
+ /** Preferred field in newer APIs */
28
+ agentId?: string;
29
+ /** Backward-compatible alias supported by older APIs */
30
+ agentName?: string;
23
31
  input?: Record<string, unknown>;
32
+ runtimeAccountIds?: string[];
24
33
  }
25
34
  export interface WorkflowRunInputs {
26
35
  [key: string]: unknown;
27
36
  }
37
+ export interface StreamOptions {
38
+ signal?: AbortSignal;
39
+ }
40
+ /** Ergonomic entity aliases (instead of *Response/*Request names). */
41
+ export type Agent = AgentResponse;
42
+ export type CreateAgentInput = CreateAgentRequest;
43
+ export type UpdateAgentInput = UpdateAgentRequest;
44
+ export type Assistant = AssistantResponse;
45
+ export type CreateAssistantInput = CreateAssistantRequest;
46
+ export type UpdateAssistantInput = UpdateAssistantRequest;
47
+ export type Conversation = ConversationResponse;
48
+ export type ConversationMessage = ConversationMessageResponse;
49
+ export type ConversationModel = `${AvailableModels}`;
50
+ export type Task = TaskResponse;
51
+ export type TaskMessage = TaskMessageResponse;
52
+ export type Pod = PodResponse;
53
+ export type PodConfig = PodConfigResponse;
54
+ export type PodMember = PodMemberResponse;
55
+ export type Organization = OrganizationResponse;
56
+ export type OrganizationMember = OrganizationMemberResponse;
57
+ export type OrganizationInvitation = OrganizationInvitationResponse;
58
+ export type User = UserResponse;
59
+ export type UploadedIcon = IconUploadResponse;
60
+ /** Generic cursor-style page shape used by many list endpoints. */
61
+ export interface CursorPage<T> {
62
+ items: T[];
63
+ limit: number;
64
+ next_page_token?: string | null;
65
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lemma-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Official TypeScript SDK for Lemma pod-scoped APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -41,15 +41,15 @@
41
41
  "build:bundle": "tsc -p tsconfig.bundle.json && node ./scripts/build_browser_bundle.mjs",
42
42
  "clean": "rm -rf dist",
43
43
  "prepublishOnly": "npm run build",
44
- "release:check": "npm run build && npm_config_cache=.npm-cache npm pack --dry-run",
45
- "docs:dev": "cd docs && npx mintlify dev",
46
- "docs:validate": "cd docs && npx mintlify validate"
44
+ "release:check": "npm run build && npm_config_cache=.npm-cache npm pack --dry-run"
47
45
  },
48
46
  "peerDependencies": {
49
47
  "react": ">=17"
50
48
  },
51
49
  "peerDependenciesMeta": {
52
- "react": { "optional": true }
50
+ "react": {
51
+ "optional": true
52
+ }
53
53
  },
54
54
  "dependencies": {
55
55
  "supertokens-web-js": "^0.16.0"