@langchain/langgraph-sdk 0.1.7 → 0.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @langchain/langgraph-sdk
2
2
 
3
+ ## 0.1.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 02beb41: Add support for creating stateless runs
8
+
9
+ ## 0.1.8
10
+
11
+ ### Patch Changes
12
+
13
+ - 90dcb8b: Add support for managing thread state manually outside of useStream hook via `experimental_thread` option
14
+
3
15
  ## 0.1.7
4
16
 
5
17
  ### Patch Changes
package/dist/client.cjs CHANGED
@@ -788,7 +788,8 @@ class RunsClient extends BaseClient {
788
788
  }
789
789
  : undefined,
790
790
  };
791
- const [run, response] = await this.fetch(`/threads/${threadId}/runs`, {
791
+ const endpoint = threadId === null ? "/runs" : `/threads/${threadId}/runs`;
792
+ const [run, response] = await this.fetch(endpoint, {
792
793
  method: "POST",
793
794
  json,
794
795
  signal: payload?.signal,
package/dist/client.d.ts CHANGED
@@ -417,7 +417,7 @@ export declare class RunsClient<TStateType = DefaultValues, TUpdateType = TState
417
417
  * @param payload Payload for creating a run.
418
418
  * @returns The created run.
419
419
  */
420
- create(threadId: string, assistantId: string, payload?: RunsCreatePayload): Promise<Run>;
420
+ create(threadId: string | null, assistantId: string, payload?: RunsCreatePayload): Promise<Run>;
421
421
  /**
422
422
  * Create a batch of stateless background runs.
423
423
  *
package/dist/client.js CHANGED
@@ -780,7 +780,8 @@ export class RunsClient extends BaseClient {
780
780
  }
781
781
  : undefined,
782
782
  };
783
- const [run, response] = await this.fetch(`/threads/${threadId}/runs`, {
783
+ const endpoint = threadId === null ? "/runs" : `/threads/${threadId}/runs`;
784
+ const [run, response] = await this.fetch(endpoint, {
784
785
  method: "POST",
785
786
  json,
786
787
  signal: payload?.signal,
@@ -1,3 +1,3 @@
1
1
  export { useStream } from "./stream.js";
2
2
  export { FetchStreamTransport } from "./stream.custom.js";
3
- export type { MessageMetadata, UseStream, UseStreamOptions, UseStreamCustom, UseStreamCustomOptions, UseStreamTransport, } from "./types.js";
3
+ export type { MessageMetadata, UseStream, UseStreamOptions, UseStreamCustom, UseStreamCustomOptions, UseStreamTransport, UseStreamThread, } from "./types.js";
@@ -39,6 +39,9 @@ function useThreadHistory(client, threadId, limit, options) {
39
39
  const onErrorRef = (0, react_1.useRef)(options?.onError);
40
40
  onErrorRef.current = options?.onError;
41
41
  const fetcher = (0, react_1.useCallback)((threadId, limit) => {
42
+ // If only passthrough is enabled, don't fetch history
43
+ if (options.passthrough)
44
+ return Promise.resolve([]);
42
45
  const client = clientRef.current;
43
46
  const key = getFetchHistoryKey(client, threadId, limit);
44
47
  if (threadId != null) {
@@ -66,7 +69,7 @@ function useThreadHistory(client, threadId, limit, options) {
66
69
  }
67
70
  setState({ key, data: undefined, error: undefined, isLoading: false });
68
71
  return Promise.resolve([]);
69
- }, []);
72
+ }, [options.passthrough]);
70
73
  (0, react_1.useEffect)(() => {
71
74
  // Skip if a stream is already in progress, no need to fetch history
72
75
  if (options.submittingRef.current != null &&
@@ -166,10 +169,12 @@ function useStreamLGP(options) {
166
169
  options.fetchStateHistory != null
167
170
  ? options.fetchStateHistory.limit ?? false
168
171
  : options.fetchStateHistory ?? false;
169
- const history = useThreadHistory(client, threadId, historyLimit, {
172
+ const builtInHistory = useThreadHistory(client, threadId, historyLimit, {
173
+ passthrough: options.experimental_thread != null,
170
174
  submittingRef: threadIdStreamingRef,
171
175
  onError: options.onError,
172
176
  });
177
+ const history = options.experimental_thread ?? builtInHistory;
173
178
  const getMessages = (value) => {
174
179
  const messagesKey = options.messagesKey ?? "messages";
175
180
  return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
@@ -179,7 +184,7 @@ function useStreamLGP(options) {
179
184
  return { ...current, [messagesKey]: messages };
180
185
  };
181
186
  const [branch, setBranch] = (0, react_1.useState)("");
182
- const branchContext = (0, branching_js_1.getBranchContext)(branch, history.data);
187
+ const branchContext = (0, branching_js_1.getBranchContext)(branch, history.data ?? undefined);
183
188
  const historyValues = branchContext.threadHead?.values ??
184
189
  options.initialValues ??
185
190
  {};
@@ -344,7 +349,7 @@ function useStreamLGP(options) {
344
349
  includeImplicitBranch;
345
350
  if (shouldRefetch) {
346
351
  const newHistory = await history.mutate(usableThreadId);
347
- const lastHead = newHistory.at(0);
352
+ const lastHead = newHistory?.at(0);
348
353
  if (lastHead) {
349
354
  // We now have the latest update from /history
350
355
  // Thus we can clear the local stream state
@@ -386,7 +391,7 @@ function useStreamLGP(options) {
386
391
  async onSuccess() {
387
392
  runMetadataStorage?.removeItem(`lg:stream:${threadId}`);
388
393
  const newHistory = await history.mutate(threadId);
389
- const lastHead = newHistory.at(0);
394
+ const lastHead = newHistory?.at(0);
390
395
  if (lastHead)
391
396
  options.onFinish?.(lastHead, callbackMeta);
392
397
  },
@@ -35,6 +35,9 @@ function useThreadHistory(client, threadId, limit, options) {
35
35
  const onErrorRef = useRef(options?.onError);
36
36
  onErrorRef.current = options?.onError;
37
37
  const fetcher = useCallback((threadId, limit) => {
38
+ // If only passthrough is enabled, don't fetch history
39
+ if (options.passthrough)
40
+ return Promise.resolve([]);
38
41
  const client = clientRef.current;
39
42
  const key = getFetchHistoryKey(client, threadId, limit);
40
43
  if (threadId != null) {
@@ -62,7 +65,7 @@ function useThreadHistory(client, threadId, limit, options) {
62
65
  }
63
66
  setState({ key, data: undefined, error: undefined, isLoading: false });
64
67
  return Promise.resolve([]);
65
- }, []);
68
+ }, [options.passthrough]);
66
69
  useEffect(() => {
67
70
  // Skip if a stream is already in progress, no need to fetch history
68
71
  if (options.submittingRef.current != null &&
@@ -162,10 +165,12 @@ export function useStreamLGP(options) {
162
165
  options.fetchStateHistory != null
163
166
  ? options.fetchStateHistory.limit ?? false
164
167
  : options.fetchStateHistory ?? false;
165
- const history = useThreadHistory(client, threadId, historyLimit, {
168
+ const builtInHistory = useThreadHistory(client, threadId, historyLimit, {
169
+ passthrough: options.experimental_thread != null,
166
170
  submittingRef: threadIdStreamingRef,
167
171
  onError: options.onError,
168
172
  });
173
+ const history = options.experimental_thread ?? builtInHistory;
169
174
  const getMessages = (value) => {
170
175
  const messagesKey = options.messagesKey ?? "messages";
171
176
  return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
@@ -175,7 +180,7 @@ export function useStreamLGP(options) {
175
180
  return { ...current, [messagesKey]: messages };
176
181
  };
177
182
  const [branch, setBranch] = useState("");
178
- const branchContext = getBranchContext(branch, history.data);
183
+ const branchContext = getBranchContext(branch, history.data ?? undefined);
179
184
  const historyValues = branchContext.threadHead?.values ??
180
185
  options.initialValues ??
181
186
  {};
@@ -340,7 +345,7 @@ export function useStreamLGP(options) {
340
345
  includeImplicitBranch;
341
346
  if (shouldRefetch) {
342
347
  const newHistory = await history.mutate(usableThreadId);
343
- const lastHead = newHistory.at(0);
348
+ const lastHead = newHistory?.at(0);
344
349
  if (lastHead) {
345
350
  // We now have the latest update from /history
346
351
  // Thus we can clear the local stream state
@@ -382,7 +387,7 @@ export function useStreamLGP(options) {
382
387
  async onSuccess() {
383
388
  runMetadataStorage?.removeItem(`lg:stream:${threadId}`);
384
389
  const newHistory = await history.mutate(threadId);
385
- const lastHead = newHistory.at(0);
390
+ const lastHead = newHistory?.at(0);
386
391
  if (lastHead)
387
392
  options.onFinish?.(lastHead, callbackMeta);
388
393
  },
@@ -50,6 +50,12 @@ export interface RunCallbackMeta {
50
50
  run_id: string;
51
51
  thread_id: string;
52
52
  }
53
+ export interface UseStreamThread<StateType extends Record<string, unknown>> {
54
+ data: ThreadState<StateType>[] | null | undefined;
55
+ error: unknown;
56
+ isLoading: boolean;
57
+ mutate: (mutateId?: string) => Promise<ThreadState<StateType>[] | null | undefined>;
58
+ }
53
59
  export interface UseStreamOptions<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> {
54
60
  /**
55
61
  * The ID of the assistant to use.
@@ -187,6 +193,11 @@ export interface UseStreamOptions<StateType extends Record<string, unknown> = Re
187
193
  fetchStateHistory?: boolean | {
188
194
  limit: number;
189
195
  };
196
+ /**
197
+ * Manage the thread state externally.
198
+ * @experimental
199
+ */
200
+ experimental_thread?: UseStreamThread<StateType>;
190
201
  }
191
202
  interface RunMetadataStorage {
192
203
  getItem(key: `lg:stream:${string}`): string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "scripts": {