lemma-sdk 0.2.7 → 0.2.9

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.
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useRef, useState } from "react";
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
2
  import { parseSSEJson, readSSE } from "../streams.js";
3
3
  import { parseAssistantStreamEvent, upsertConversationMessage } from "../assistant-events.js";
4
4
  function resolveOptionalPodId(client, podId) {
@@ -22,15 +22,15 @@ function normalizeError(error, fallback) {
22
22
  return error;
23
23
  return new Error(fallback);
24
24
  }
25
- function normalizeScope(client, options, override) {
25
+ function normalizeScope(client, defaults, override) {
26
26
  return {
27
- podId: override?.podId ?? options.podId ?? client.podId ?? null,
28
- assistantId: override?.assistantId ?? options.assistantId ?? null,
29
- organizationId: override?.organizationId ?? options.organizationId ?? null,
27
+ podId: override?.podId ?? defaults.podId ?? client.podId ?? null,
28
+ assistantId: override?.assistantId ?? defaults.assistantId ?? null,
29
+ organizationId: override?.organizationId ?? defaults.organizationId ?? null,
30
30
  };
31
31
  }
32
32
  export function useAssistantSession(options) {
33
- const { client, conversationId: externalConversationId = null, autoLoad = true, onEvent, onStatus, onMessage, onError, } = options;
33
+ const { client, podId: defaultPodId, assistantId: defaultAssistantId, organizationId: defaultOrganizationId, conversationId: externalConversationId = null, autoLoad = true, onEvent, onStatus, onMessage, onError, } = options;
34
34
  const [conversationId, setConversationIdState] = useState(externalConversationId);
35
35
  const [conversation, setConversation] = useState(null);
36
36
  const [status, setStatus] = useState(undefined);
@@ -53,9 +53,14 @@ export function useAssistantSession(options) {
53
53
  abortRef.current?.abort();
54
54
  abortRef.current = null;
55
55
  }, []);
56
+ const defaultScope = useMemo(() => ({
57
+ podId: defaultPodId ?? null,
58
+ assistantId: defaultAssistantId ?? null,
59
+ organizationId: defaultOrganizationId ?? null,
60
+ }), [defaultAssistantId, defaultOrganizationId, defaultPodId]);
56
61
  const listConversations = useCallback(async (input = {}) => {
57
62
  try {
58
- const scope = normalizeScope(client, options, input.scope);
63
+ const scope = normalizeScope(client, defaultScope, input.scope);
59
64
  applyPodScope(client, scope.podId);
60
65
  const response = await client.conversations.list({
61
66
  pod_id: scope.podId ?? undefined,
@@ -80,14 +85,14 @@ export function useAssistantSession(options) {
80
85
  next_page_token: null,
81
86
  };
82
87
  }
83
- }, [client, onError, options]);
88
+ }, [client, defaultScope, onError]);
84
89
  const createConversation = useCallback(async (input = {}) => {
85
- applyPodScope(client, input.podId ?? options.podId ?? null);
90
+ applyPodScope(client, input.podId ?? defaultPodId ?? null);
86
91
  const payload = {
87
92
  title: input.title ?? undefined,
88
- pod_id: input.podId ?? options.podId ?? client.podId ?? undefined,
89
- assistant_id: input.assistantId ?? options.assistantId ?? undefined,
90
- organization_id: input.organizationId ?? options.organizationId ?? undefined,
93
+ pod_id: input.podId ?? defaultPodId ?? client.podId ?? undefined,
94
+ assistant_id: input.assistantId ?? defaultAssistantId ?? undefined,
95
+ organization_id: input.organizationId ?? defaultOrganizationId ?? undefined,
91
96
  model: typeof input.model === "undefined"
92
97
  ? undefined
93
98
  : input.model,
@@ -100,13 +105,13 @@ export function useAssistantSession(options) {
100
105
  setMessages([]);
101
106
  }
102
107
  return created;
103
- }, [client, options.assistantId, options.organizationId, options.podId]);
108
+ }, [client, defaultAssistantId, defaultOrganizationId, defaultPodId]);
104
109
  const refreshConversation = useCallback(async (explicitConversationId) => {
105
110
  const id = explicitConversationId ?? conversationId;
106
111
  if (!id)
107
112
  return null;
108
113
  try {
109
- const scope = normalizeScope(client, options);
114
+ const scope = normalizeScope(client, defaultScope);
110
115
  applyPodScope(client, scope.podId);
111
116
  const nextConversation = await client.conversations.get(id, {
112
117
  pod_id: scope.podId ?? undefined,
@@ -127,14 +132,14 @@ export function useAssistantSession(options) {
127
132
  onError?.(refreshError);
128
133
  return null;
129
134
  }
130
- }, [client, conversationId, onError, onStatus, options]);
135
+ }, [client, conversationId, defaultScope, onError, onStatus]);
131
136
  const loadMessages = useCallback(async (input = {}) => {
132
137
  const id = input.conversationId ?? conversationId;
133
138
  if (!id) {
134
139
  return { items: [], limit: input.limit ?? 20, next_page_token: null };
135
140
  }
136
141
  try {
137
- const scope = normalizeScope(client, options);
142
+ const scope = normalizeScope(client, defaultScope);
138
143
  applyPodScope(client, scope.podId);
139
144
  const response = await client.conversations.messages.list(id, {
140
145
  pod_id: scope.podId ?? undefined,
@@ -159,7 +164,7 @@ export function useAssistantSession(options) {
159
164
  next_page_token: null,
160
165
  };
161
166
  }
162
- }, [client, conversationId, onError, options]);
167
+ }, [client, conversationId, defaultScope, onError]);
163
168
  const consume = useCallback(async (stream, controller) => {
164
169
  setIsStreaming(true);
165
170
  setError(null);
@@ -198,6 +203,10 @@ export function useAssistantSession(options) {
198
203
  const ensureConversation = useCallback(async (overrideConversationId, options) => {
199
204
  const existingId = overrideConversationId ?? conversationId;
200
205
  if (existingId) {
206
+ // Avoid a network roundtrip on every send when we already have this conversation in state.
207
+ if (conversation?.id === existingId) {
208
+ return conversation;
209
+ }
201
210
  const existing = await refreshConversation(existingId);
202
211
  if (existing)
203
212
  return existing;
@@ -210,14 +219,14 @@ export function useAssistantSession(options) {
210
219
  ...(options.createConversation ?? {}),
211
220
  setActive: true,
212
221
  });
213
- }, [conversationId, createConversation, refreshConversation]);
222
+ }, [conversation, conversationId, createConversation, refreshConversation]);
214
223
  const sendMessage = useCallback(async (content, input = {}) => {
215
224
  const resolvedConversation = await ensureConversation(input.conversationId, input);
216
225
  const resolvedConversationId = requireConversationId(resolvedConversation.id);
217
226
  cancel();
218
227
  const controller = new AbortController();
219
228
  abortRef.current = controller;
220
- const scope = normalizeScope(client, options, input.createConversation);
229
+ const scope = normalizeScope(client, defaultScope, input.createConversation);
221
230
  applyPodScope(client, scope.podId);
222
231
  const stream = await client.conversations.sendMessageStream(resolvedConversationId, { content }, {
223
232
  pod_id: scope.podId ?? undefined,
@@ -225,28 +234,28 @@ export function useAssistantSession(options) {
225
234
  });
226
235
  await consume(stream, controller);
227
236
  return resolvedConversation;
228
- }, [cancel, client, consume, ensureConversation, options]);
237
+ }, [cancel, client, consume, defaultScope, ensureConversation]);
229
238
  const resume = useCallback(async (explicitConversationId) => {
230
239
  const id = requireConversationId(explicitConversationId ?? conversationId);
231
240
  cancel();
232
241
  const controller = new AbortController();
233
242
  abortRef.current = controller;
234
- const scope = normalizeScope(client, options);
243
+ const scope = normalizeScope(client, defaultScope);
235
244
  applyPodScope(client, scope.podId);
236
245
  const stream = await client.conversations.resumeStream(id, {
237
246
  pod_id: scope.podId ?? undefined,
238
247
  signal: controller.signal,
239
248
  });
240
249
  await consume(stream, controller);
241
- }, [cancel, client, consume, conversationId, options]);
250
+ }, [cancel, client, consume, conversationId, defaultScope]);
242
251
  const stop = useCallback(async (explicitConversationId) => {
243
252
  const id = requireConversationId(explicitConversationId ?? conversationId);
244
- const scope = normalizeScope(client, options);
253
+ const scope = normalizeScope(client, defaultScope);
245
254
  applyPodScope(client, scope.podId);
246
255
  await client.conversations.stopRun(id, {
247
256
  pod_id: scope.podId ?? undefined,
248
257
  });
249
- }, [client, conversationId, options]);
258
+ }, [client, conversationId, defaultScope]);
250
259
  const clearMessages = useCallback(() => {
251
260
  setMessages([]);
252
261
  }, []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lemma-sdk",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Official TypeScript SDK for Lemma pod-scoped APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",