@langgraph-js/sdk 3.7.0 → 3.8.0

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 (45) hide show
  1. package/README.md +29 -0
  2. package/dist/History.d.ts +115 -0
  3. package/dist/History.js +226 -0
  4. package/dist/LangGraphClient.d.ts +23 -2
  5. package/dist/LangGraphClient.js +118 -80
  6. package/dist/MessageProcessor.js +18 -24
  7. package/dist/SpendTime.js +4 -9
  8. package/dist/TestKit.d.ts +1 -1
  9. package/dist/TestKit.js +16 -15
  10. package/dist/ToolManager.js +4 -7
  11. package/dist/artifacts/index.js +1 -1
  12. package/dist/client/LanggraphServer.js +1 -1
  13. package/dist/client/LowJSServer.d.ts +3 -0
  14. package/dist/client/LowJSServer.js +80 -0
  15. package/dist/client/index.d.ts +2 -0
  16. package/dist/client/index.js +2 -0
  17. package/dist/client/utils/sse.d.ts +8 -0
  18. package/dist/client/utils/sse.js +151 -0
  19. package/dist/client/utils/stream.d.ts +15 -0
  20. package/dist/client/utils/stream.js +104 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +2 -0
  23. package/dist/react/ChatContext.d.ts +31 -20
  24. package/dist/react/ChatContext.js +10 -4
  25. package/dist/tool/ToolUI.js +3 -2
  26. package/dist/tool/createTool.js +3 -6
  27. package/dist/tool/utils.js +3 -4
  28. package/dist/ui-store/createChatStore.d.ts +33 -66
  29. package/dist/ui-store/createChatStore.js +261 -247
  30. package/dist/vue/ChatContext.d.ts +41 -21
  31. package/dist/vue/ChatContext.js +8 -2
  32. package/package.json +3 -1
  33. package/src/History.ts +294 -0
  34. package/src/LangGraphClient.ts +98 -48
  35. package/src/client/LanggraphServer.ts +1 -2
  36. package/src/client/LowJSServer.ts +80 -0
  37. package/src/client/index.ts +2 -0
  38. package/src/client/utils/sse.ts +176 -0
  39. package/src/client/utils/stream.ts +114 -0
  40. package/src/index.ts +2 -0
  41. package/src/react/ChatContext.ts +25 -16
  42. package/src/ui-store/createChatStore.ts +310 -236
  43. package/src/vue/ChatContext.ts +12 -0
  44. package/test/TestKit.test.ts +10 -2
  45. package/tsconfig.json +1 -1
@@ -0,0 +1,80 @@
1
+ import { BytesLineDecoder, SSEDecoder } from "./utils/sse.js";
2
+ const REGEX_RUN_METADATA = /(\/threads\/(?<thread_id>.+))?\/runs\/(?<run_id>.+)/;
3
+ function getRunMetadataFromResponse(response) {
4
+ const contentLocation = response.headers.get("Content-Location");
5
+ if (!contentLocation)
6
+ return void 0;
7
+ const match = REGEX_RUN_METADATA.exec(contentLocation);
8
+ if (!match?.groups?.run_id)
9
+ return void 0;
10
+ return {
11
+ run_id: match.groups.run_id,
12
+ thread_id: match.groups.thread_id || void 0,
13
+ };
14
+ }
15
+ import { Client } from "@langchain/langgraph-sdk";
16
+ export const createLowerJSClient = (config) => {
17
+ const client = new Client(config);
18
+ /** @ts-ignore */
19
+ client.runs.joinStream = async function (threadId, runId, options) {
20
+ const opts = typeof options === "object" && options != null && options instanceof AbortSignal ? { signal: options } : options;
21
+ let [url, init] = this.prepareFetchOptions(threadId != null ? `/threads/${threadId}/runs/${runId}/stream` : `/runs/${runId}/stream`, {
22
+ method: "GET",
23
+ timeoutMs: null,
24
+ signal: opts?.signal,
25
+ headers: opts?.lastEventId ? { "Last-Event-ID": opts.lastEventId } : void 0,
26
+ params: {
27
+ cancel_on_disconnect: opts?.cancelOnDisconnect ? "1" : "0",
28
+ stream_mode: opts?.streamMode,
29
+ },
30
+ });
31
+ if (this.onRequest != null)
32
+ init = await this.onRequest(url, init);
33
+ const response = await this.asyncCaller.fetch(url, init);
34
+ const stream = (response.body || new ReadableStream({ start: (ctrl) => ctrl.close() })).pipeThrough(BytesLineDecoder()).pipeThrough(SSEDecoder());
35
+ return stream.pipeTo(new WritableStream({ write: (chunk) => options.onCallback?.(chunk) }));
36
+ }.bind(client.runs);
37
+ /** @ts-ignore */
38
+ client.runs.stream = async function (threadId, assistantId, payload) {
39
+ const json = {
40
+ input: payload?.input,
41
+ command: payload?.command,
42
+ config: payload?.config,
43
+ context: payload?.context,
44
+ metadata: payload?.metadata,
45
+ stream_mode: payload?.streamMode,
46
+ stream_subgraphs: payload?.streamSubgraphs,
47
+ stream_resumable: payload?.streamResumable,
48
+ feedback_keys: payload?.feedbackKeys,
49
+ assistant_id: assistantId,
50
+ interrupt_before: payload?.interruptBefore,
51
+ interrupt_after: payload?.interruptAfter,
52
+ checkpoint: payload?.checkpoint,
53
+ checkpoint_id: payload?.checkpointId,
54
+ webhook: payload?.webhook,
55
+ multitask_strategy: payload?.multitaskStrategy,
56
+ on_completion: payload?.onCompletion,
57
+ on_disconnect: payload?.onDisconnect,
58
+ after_seconds: payload?.afterSeconds,
59
+ if_not_exists: payload?.ifNotExists,
60
+ checkpoint_during: payload?.checkpointDuring,
61
+ durability: payload?.durability,
62
+ };
63
+ const endpoint = threadId == null ? `/runs/stream` : `/threads/${threadId}/runs/stream`;
64
+ let [url, init] = this.prepareFetchOptions(endpoint, {
65
+ method: "POST",
66
+ json,
67
+ timeoutMs: null,
68
+ signal: payload?.signal,
69
+ });
70
+ if (this.onRequest != null)
71
+ init = await this.onRequest(url, init);
72
+ const response = await this.asyncCaller.fetch(url, init);
73
+ const runMetadata = getRunMetadataFromResponse(response);
74
+ if (runMetadata)
75
+ payload?.onRunCreated?.(runMetadata);
76
+ const stream = (response.body || new ReadableStream({ start: (ctrl) => ctrl.close() })).pipeThrough(BytesLineDecoder()).pipeThrough(SSEDecoder());
77
+ return stream.pipeTo(new WritableStream({ write: (chunk) => payload.onCallback?.(chunk) }));
78
+ }.bind(client.runs);
79
+ return client;
80
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./LanggraphServer.js";
2
+ export * from "./LowJSServer.js";
@@ -0,0 +1,2 @@
1
+ export * from "./LanggraphServer.js";
2
+ export * from "./LowJSServer.js";
@@ -0,0 +1,8 @@
1
+ export declare function BytesLineDecoder(): TransformStream<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>;
2
+ interface StreamPart {
3
+ id: string | undefined;
4
+ event: string;
5
+ data: unknown;
6
+ }
7
+ export declare function SSEDecoder(): TransformStream<Uint8Array<ArrayBufferLike>, StreamPart>;
8
+ export {};
@@ -0,0 +1,151 @@
1
+ /** copied from https://github.com/langchain-ai/langgraphjs/tree/main/libs/sdk/src/utils */
2
+ const CR = "\r".charCodeAt(0);
3
+ const LF = "\n".charCodeAt(0);
4
+ const NULL = "\0".charCodeAt(0);
5
+ const COLON = ":".charCodeAt(0);
6
+ const SPACE = " ".charCodeAt(0);
7
+ const TRAILING_NEWLINE = [CR, LF];
8
+ export function BytesLineDecoder() {
9
+ let buffer = [];
10
+ let trailingCr = false;
11
+ return new TransformStream({
12
+ start() {
13
+ buffer = [];
14
+ trailingCr = false;
15
+ },
16
+ transform(chunk, controller) {
17
+ // See https://docs.python.org/3/glossary.html#term-universal-newlines
18
+ let text = chunk;
19
+ // Handle trailing CR from previous chunk
20
+ if (trailingCr) {
21
+ text = joinArrays([[CR], text]);
22
+ trailingCr = false;
23
+ }
24
+ // Check for trailing CR in current chunk
25
+ if (text.length > 0 && text.at(-1) === CR) {
26
+ trailingCr = true;
27
+ text = text.subarray(0, -1);
28
+ }
29
+ if (!text.length)
30
+ return;
31
+ const trailingNewline = TRAILING_NEWLINE.includes(text.at(-1));
32
+ const lastIdx = text.length - 1;
33
+ const { lines } = text.reduce((acc, cur, idx) => {
34
+ if (acc.from > idx)
35
+ return acc;
36
+ if (cur === CR || cur === LF) {
37
+ acc.lines.push(text.subarray(acc.from, idx));
38
+ if (cur === CR && text[idx + 1] === LF) {
39
+ acc.from = idx + 2;
40
+ }
41
+ else {
42
+ acc.from = idx + 1;
43
+ }
44
+ }
45
+ if (idx === lastIdx && acc.from <= lastIdx) {
46
+ acc.lines.push(text.subarray(acc.from));
47
+ }
48
+ return acc;
49
+ }, { lines: [], from: 0 });
50
+ if (lines.length === 1 && !trailingNewline) {
51
+ buffer.push(lines[0]);
52
+ return;
53
+ }
54
+ if (buffer.length) {
55
+ // Include existing buffer in first line
56
+ buffer.push(lines[0]);
57
+ lines[0] = joinArrays(buffer);
58
+ buffer = [];
59
+ }
60
+ if (!trailingNewline) {
61
+ // If the last segment is not newline terminated,
62
+ // buffer it for the next chunk
63
+ if (lines.length)
64
+ buffer = [lines.pop()];
65
+ }
66
+ // Enqueue complete lines
67
+ for (const line of lines) {
68
+ controller.enqueue(line);
69
+ }
70
+ },
71
+ flush(controller) {
72
+ if (buffer.length) {
73
+ controller.enqueue(joinArrays(buffer));
74
+ }
75
+ },
76
+ });
77
+ }
78
+ export function SSEDecoder() {
79
+ let event = "";
80
+ let data = [];
81
+ let lastEventId = "";
82
+ let retry = null;
83
+ const decoder = new TextDecoder();
84
+ return new TransformStream({
85
+ transform(chunk, controller) {
86
+ // Handle empty line case
87
+ if (!chunk.length) {
88
+ if (!event && !data.length && !lastEventId && retry == null)
89
+ return;
90
+ const sse = {
91
+ id: lastEventId || undefined,
92
+ event,
93
+ data: data.length ? decodeArraysToJson(decoder, data) : null,
94
+ };
95
+ // NOTE: as per the SSE spec, do not reset lastEventId
96
+ event = "";
97
+ data = [];
98
+ retry = null;
99
+ controller.enqueue(sse);
100
+ return;
101
+ }
102
+ // Ignore comments
103
+ if (chunk[0] === COLON)
104
+ return;
105
+ const sepIdx = chunk.indexOf(COLON);
106
+ if (sepIdx === -1)
107
+ return;
108
+ const fieldName = decoder.decode(chunk.subarray(0, sepIdx));
109
+ let value = chunk.subarray(sepIdx + 1);
110
+ if (value[0] === SPACE)
111
+ value = value.subarray(1);
112
+ if (fieldName === "event") {
113
+ event = decoder.decode(value);
114
+ }
115
+ else if (fieldName === "data") {
116
+ data.push(value);
117
+ }
118
+ else if (fieldName === "id") {
119
+ if (value.indexOf(NULL) === -1)
120
+ lastEventId = decoder.decode(value);
121
+ }
122
+ else if (fieldName === "retry") {
123
+ const retryNum = Number.parseInt(decoder.decode(value), 10);
124
+ if (!Number.isNaN(retryNum))
125
+ retry = retryNum;
126
+ }
127
+ },
128
+ flush(controller) {
129
+ if (event) {
130
+ controller.enqueue({
131
+ id: lastEventId || undefined,
132
+ event,
133
+ data: data.length ? decodeArraysToJson(decoder, data) : null,
134
+ });
135
+ }
136
+ },
137
+ });
138
+ }
139
+ function joinArrays(data) {
140
+ const totalLength = data.reduce((acc, curr) => acc + curr.length, 0);
141
+ const merged = new Uint8Array(totalLength);
142
+ let offset = 0;
143
+ for (const c of data) {
144
+ merged.set(c, offset);
145
+ offset += c.length;
146
+ }
147
+ return merged;
148
+ }
149
+ function decodeArraysToJson(decoder, data) {
150
+ return JSON.parse(decoder.decode(joinArrays(data)));
151
+ }
@@ -0,0 +1,15 @@
1
+ /** copied from https://github.com/langchain-ai/langgraphjs/tree/main/libs/sdk/src/utils */
2
+ type IterableReadableStreamInterface<T> = ReadableStream<T> & AsyncIterable<T>;
3
+ export declare class IterableReadableStream<T> extends ReadableStream<T> implements IterableReadableStreamInterface<T> {
4
+ [Symbol.asyncDispose]: () => Promise<void>;
5
+ /** @ts-ignore */
6
+ reader: ReadableStreamDefaultReader<T>;
7
+ ensureReader(): void;
8
+ next(): Promise<IteratorResult<T>>;
9
+ return(): Promise<IteratorResult<T>>;
10
+ throw(e: any): Promise<IteratorResult<T>>;
11
+ [Symbol.asyncIterator](): this;
12
+ static fromReadableStream<T>(stream: ReadableStream<T>): IterableReadableStream<T>;
13
+ static fromAsyncGenerator<T>(generator: AsyncGenerator<T>): IterableReadableStream<T>;
14
+ }
15
+ export {};
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Support async iterator syntax for ReadableStreams in all environments.
3
+ * Source: https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
4
+ */
5
+ export class IterableReadableStream extends ReadableStream {
6
+ /** @ts-ignore */
7
+ reader;
8
+ ensureReader() {
9
+ if (!this.reader) {
10
+ this.reader = this.getReader();
11
+ }
12
+ }
13
+ async next() {
14
+ this.ensureReader();
15
+ try {
16
+ const result = await this.reader.read();
17
+ if (result.done) {
18
+ this.reader.releaseLock(); // release lock when stream becomes closed
19
+ return {
20
+ done: true,
21
+ value: undefined,
22
+ };
23
+ }
24
+ else {
25
+ return {
26
+ done: false,
27
+ value: result.value,
28
+ };
29
+ }
30
+ }
31
+ catch (e) {
32
+ this.reader.releaseLock(); // release lock when stream becomes errored
33
+ throw e;
34
+ }
35
+ }
36
+ async return() {
37
+ this.ensureReader();
38
+ // If wrapped in a Node stream, cancel is already called.
39
+ if (this.locked) {
40
+ const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet
41
+ this.reader.releaseLock(); // release lock first
42
+ await cancelPromise; // now await it
43
+ }
44
+ return { done: true, value: undefined };
45
+ }
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ async throw(e) {
48
+ this.ensureReader();
49
+ if (this.locked) {
50
+ const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet
51
+ this.reader.releaseLock(); // release lock first
52
+ await cancelPromise; // now await it
53
+ }
54
+ throw e;
55
+ }
56
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
57
+ // @ts-ignore Not present in Node 18 types, required in latest Node 22
58
+ async [Symbol.asyncDispose]() {
59
+ await this.return();
60
+ }
61
+ [Symbol.asyncIterator]() {
62
+ return this;
63
+ }
64
+ static fromReadableStream(stream) {
65
+ // From https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams#reading_the_stream
66
+ const reader = stream.getReader();
67
+ return new IterableReadableStream({
68
+ start(controller) {
69
+ return pump();
70
+ function pump() {
71
+ return reader.read().then(({ done, value }) => {
72
+ // When no more data needs to be consumed, close the stream
73
+ if (done) {
74
+ controller.close();
75
+ return;
76
+ }
77
+ // Enqueue the next data chunk into our target stream
78
+ controller.enqueue(value);
79
+ return pump();
80
+ });
81
+ }
82
+ },
83
+ cancel() {
84
+ reader.releaseLock();
85
+ },
86
+ });
87
+ }
88
+ static fromAsyncGenerator(generator) {
89
+ return new IterableReadableStream({
90
+ async pull(controller) {
91
+ const { value, done } = await generator.next();
92
+ // When no more data needs to be consumed, close the stream
93
+ if (done) {
94
+ controller.close();
95
+ }
96
+ // Fix: `else if (value)` will hang the streaming when nullish value (e.g. empty string) is pulled
97
+ controller.enqueue(value);
98
+ },
99
+ async cancel(reason) {
100
+ await generator.return(reason);
101
+ },
102
+ });
103
+ }
104
+ }
package/dist/index.d.ts CHANGED
@@ -6,3 +6,5 @@ export * from "./ui-store/index.js";
6
6
  export * from "./ToolManager.js";
7
7
  export * from "./TestKit.js";
8
8
  export * from "./artifacts/index.js";
9
+ export * from "./client/index.js";
10
+ export * from "./History.js";
package/dist/index.js CHANGED
@@ -6,3 +6,5 @@ export * from "./ui-store/index.js";
6
6
  export * from "./ToolManager.js";
7
7
  export * from "./TestKit.js";
8
8
  export * from "./artifacts/index.js";
9
+ export * from "./client/index.js";
10
+ export * from "./History.js";
@@ -1,56 +1,63 @@
1
1
  import { ReactNode } from "react";
2
2
  import { UnionStore } from "../ui-store/index.js";
3
+ import { ILangGraphClient } from "@langgraph-js/pure-graph/dist/types.js";
3
4
  export declare const useChat: () => UnionStore<{
4
5
  data: {
5
6
  artifacts: import("nanostores").PreinitializedWritableAtom<import("../index.js").ComposedArtifact[]> & object;
6
7
  currentArtifactId: import("nanostores").PreinitializedWritableAtom<[string, string] | null> & object;
7
8
  showArtifact: import("nanostores").PreinitializedWritableAtom<boolean> & object;
8
9
  client: import("nanostores").PreinitializedWritableAtom<import("../LangGraphClient.js").LangGraphClient<unknown> | null> & object;
10
+ history: import("nanostores").PreinitializedWritableAtom<import("../History.js").History | null> & object;
11
+ sessions: import("nanostores").PreinitializedWritableAtom<import("../History.js").SessionInfo[]> & object;
9
12
  renderMessages: import("nanostores").PreinitializedWritableAtom<import("../LangGraphClient.js").RenderMessage[]> & object;
10
13
  userInput: import("nanostores").PreinitializedWritableAtom<string> & object;
11
14
  loading: import("nanostores").PreinitializedWritableAtom<boolean> & object;
12
15
  inChatError: import("nanostores").PreinitializedWritableAtom<string | null> & object;
13
16
  currentAgent: import("nanostores").PreinitializedWritableAtom<string> & object;
17
+ currentChatId: import("nanostores").PreinitializedWritableAtom<string | null> & object;
18
+ currentNodeName: import("nanostores").PreinitializedWritableAtom<string> & object;
19
+ tools: import("nanostores").PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
14
20
  collapsedTools: import("nanostores").PreinitializedWritableAtom<string[]> & object;
21
+ showGraph: import("nanostores").PreinitializedWritableAtom<boolean> & object;
22
+ graphVisualize: import("nanostores").PreinitializedWritableAtom<import("@langchain/langgraph-sdk").AssistantGraph | null> & object;
15
23
  showHistory: import("nanostores").PreinitializedWritableAtom<boolean> & object;
16
24
  historyList: import("nanostores").PreinitializedWritableAtom<import("@langchain/langgraph-sdk").Thread<{
17
25
  messages: import("@langchain/langgraph-sdk").Message[];
18
26
  }>[]> & object;
19
- currentChatId: import("nanostores").PreinitializedWritableAtom<string | null> & object;
20
- showGraph: import("nanostores").PreinitializedWritableAtom<boolean> & object;
21
- graphVisualize: import("nanostores").PreinitializedWritableAtom<import("@langchain/langgraph-sdk").AssistantGraph | null> & object;
22
- currentNodeName: import("nanostores").PreinitializedWritableAtom<string> & object;
23
- tools: import("nanostores").PreinitializedWritableAtom<import("../index.js").UnionTool<any, Object, any>[]> & object;
24
27
  };
25
28
  mutations: {
26
29
  setCurrentArtifactById: (id: string, tool_id: string) => void;
27
30
  setShowArtifact: (show: boolean) => void;
28
- refreshTools: () => Promise<void>;
29
- setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
30
- isFELocking(): boolean | undefined;
31
- getClient(): import("../LangGraphClient.js").LangGraphClient<unknown> | null;
32
- initClient: () => Promise<import("../LangGraphClient.js").LangGraphClient<unknown>>;
31
+ initClient: () => Promise<import("../History.js").History>;
32
+ getClient: () => import("../LangGraphClient.js").LangGraphClient<unknown> | null;
33
+ getHistory: () => import("../History.js").History | null;
34
+ activateSession: (sessionId: string) => Promise<void>;
35
+ createNewSession: () => Promise<void>;
36
+ refreshSessionList: () => Promise<void>;
37
+ refreshHistoryList: () => Promise<void>;
33
38
  sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], extraData?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean) => Promise<void>;
34
39
  stopGeneration: () => void;
40
+ setUserInput: (input: string) => void;
41
+ revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
42
+ refreshTools: () => Promise<void>;
43
+ setTools(new_tools: import("../index.js").UnionTool<any>[]): void;
35
44
  toggleToolCollapse: (toolId: string) => void;
45
+ getToolUIRender: (tool_name: string) => ((message: import("../LangGraphClient.js").RenderMessage) => Object) | null;
46
+ isFELocking: () => boolean | undefined;
36
47
  toggleHistoryVisible: () => void;
37
- refreshHistoryList: () => Promise<void>;
48
+ toggleGraphVisible(): void;
49
+ refreshGraph: () => Promise<void>;
50
+ setCurrentAgent(agent: string): Promise<import("../History.js").History>;
38
51
  addToHistory: (thread: import("@langchain/langgraph-sdk").Thread<{
39
52
  messages: import("@langchain/langgraph-sdk").Message[];
40
53
  }>) => void;
41
- revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
42
- setUserInput(input: string): void;
43
- setCurrentAgent(agent: string): Promise<void>;
44
- toggleGraphVisible(): void;
45
- refreshGraph: () => Promise<void>;
46
- createNewChat(): void;
47
- toHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
54
+ createNewChat: () => Promise<void>;
55
+ toHistoryChat: (thread: import("@langchain/langgraph-sdk").Thread<{
48
56
  messages: import("@langchain/langgraph-sdk").Message[];
49
- }>): Promise<import("@langchain/langgraph-sdk").Thread<unknown> | undefined>;
57
+ }>) => Promise<void>;
50
58
  deleteHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
51
59
  messages: import("@langchain/langgraph-sdk").Message[];
52
60
  }>): Promise<void>;
53
- getToolUIRender: (tool_name: string) => ((message: import("../LangGraphClient.js").RenderMessage) => Object) | null;
54
61
  };
55
62
  }>;
56
63
  interface ChatProviderProps {
@@ -62,7 +69,11 @@ interface ChatProviderProps {
62
69
  showHistory?: boolean;
63
70
  showGraph?: boolean;
64
71
  fallbackToAvailableAssistants?: boolean;
72
+ /** 初始化时是否自动激活最近的历史会话(默认 false,创建新会话) */
73
+ autoRestoreLastSession?: boolean;
65
74
  onInitError?: (error: any, currentAgent: string) => void;
75
+ client?: ILangGraphClient;
76
+ legacyMode?: boolean;
66
77
  }
67
78
  export declare const ChatProvider: React.FC<ChatProviderProps>;
68
79
  export {};
@@ -9,7 +9,7 @@ export const useChat = () => {
9
9
  }
10
10
  return context;
11
11
  };
12
- export const ChatProvider = ({ children, defaultAgent = "", apiUrl = "http://localhost:8123", defaultHeaders, withCredentials = false, showHistory = false, showGraph = false, fallbackToAvailableAssistants = false, onInitError, }) => {
12
+ export const ChatProvider = ({ children, defaultAgent = "", apiUrl = "http://localhost:8123", defaultHeaders, withCredentials = false, showHistory = false, showGraph = false, fallbackToAvailableAssistants = false, autoRestoreLastSession = false, onInitError, client, legacyMode = false, }) => {
13
13
  // 使用 useMemo 稳定 defaultHeaders 的引用
14
14
  const stableHeaders = useMemo(() => defaultHeaders || {}, [defaultHeaders]);
15
15
  // 使用 useRef 保存 onInitError 的最新引用
@@ -24,19 +24,25 @@ export const ChatProvider = ({ children, defaultAgent = "", apiUrl = "http://loc
24
24
  return fetch(url, options);
25
25
  }
26
26
  : fetch;
27
- return createChatStore(defaultAgent, {
27
+ const config = {
28
28
  apiUrl,
29
29
  defaultHeaders: stableHeaders,
30
30
  callerOptions: {
31
31
  fetch: F,
32
32
  maxRetries: 1,
33
33
  },
34
- }, {
34
+ legacyMode,
35
+ };
36
+ /** @ts-ignore */
37
+ if (client)
38
+ config.client = client;
39
+ return createChatStore(defaultAgent, config, {
35
40
  showHistory,
36
41
  showGraph,
37
42
  fallbackToAvailableAssistants,
43
+ autoRestoreLastSession,
38
44
  });
39
- }, [defaultAgent, apiUrl, stableHeaders, withCredentials, showHistory, showGraph, fallbackToAvailableAssistants]);
45
+ }, [defaultAgent, apiUrl, stableHeaders, withCredentials, showHistory, showGraph, fallbackToAvailableAssistants, autoRestoreLastSession]);
40
46
  const unionStore = useUnionStore(store, useStore);
41
47
  // 使用 ref 标记是否已初始化
42
48
  const initializedRef = useRef(false);
@@ -1,13 +1,14 @@
1
1
  import { getMessageContent } from "../ui-store/createChatStore.js";
2
2
  import { jsonrepair } from "jsonrepair";
3
3
  export class ToolRenderData {
4
+ message;
5
+ client;
4
6
  constructor(message, client) {
5
7
  this.message = message;
6
8
  this.client = client;
7
9
  }
8
10
  get state() {
9
- var _a, _b;
10
- if (this.message.type === "tool" && ((_b = (_a = this.message) === null || _a === void 0 ? void 0 : _a.additional_kwargs) === null || _b === void 0 ? void 0 : _b.done)) {
11
+ if (this.message.type === "tool" && this.message?.additional_kwargs?.done) {
11
12
  return "done";
12
13
  }
13
14
  if (this.message.tool_input) {
@@ -11,9 +11,8 @@ export const createTool = (tool) => {
11
11
  export const createUITool = (tool) => {
12
12
  const execute = tool.execute ||
13
13
  (async (args, context) => {
14
- var _a;
15
14
  try {
16
- const result = await ((_a = tool.handler) === null || _a === void 0 ? void 0 : _a.call(tool, args, context));
15
+ const result = await tool.handler?.(args, context);
17
16
  if (typeof result === "string") {
18
17
  return [{ type: "text", text: result }];
19
18
  }
@@ -47,9 +46,8 @@ export const createFETool = (tool) => {
47
46
  allowAgent: tool.allowAgent,
48
47
  allowGraph: tool.allowGraph,
49
48
  async execute(args, context) {
50
- var _a;
51
49
  try {
52
- const result = await ((_a = tool.handler) === null || _a === void 0 ? void 0 : _a.call(tool, args, context));
50
+ const result = await tool.handler?.(args, context);
53
51
  if (typeof result === "string") {
54
52
  return [{ type: "text", text: result }];
55
53
  }
@@ -75,9 +73,8 @@ export const createMCPTool = (tool) => {
75
73
  tool.description,
76
74
  tool.parameters,
77
75
  async (args) => {
78
- var _a;
79
76
  try {
80
- const result = await ((_a = tool.execute) === null || _a === void 0 ? void 0 : _a.call(tool, args));
77
+ const result = await tool.execute?.(args);
81
78
  if (typeof result === "string") {
82
79
  return { content: [{ type: "text", text: result }] };
83
80
  }
@@ -25,7 +25,6 @@ export function actionParametersToJsonSchema(actionParameters) {
25
25
  };
26
26
  }
27
27
  function convertAttribute(attribute) {
28
- var _a, _b, _c;
29
28
  switch (attribute.type) {
30
29
  case "string":
31
30
  return {
@@ -41,11 +40,11 @@ function convertAttribute(attribute) {
41
40
  };
42
41
  case "object":
43
42
  case "object[]":
44
- const properties = (_a = attribute.attributes) === null || _a === void 0 ? void 0 : _a.reduce((acc, attr) => {
43
+ const properties = attribute.attributes?.reduce((acc, attr) => {
45
44
  acc[attr.name] = convertAttribute(attr);
46
45
  return acc;
47
46
  }, {});
48
- const required = (_b = attribute.attributes) === null || _b === void 0 ? void 0 : _b.filter((attr) => attr.required !== false).map((attr) => attr.name);
47
+ const required = attribute.attributes?.filter((attr) => attr.required !== false).map((attr) => attr.name);
49
48
  if (attribute.type === "object[]") {
50
49
  return {
51
50
  type: "array",
@@ -65,7 +64,7 @@ function convertAttribute(attribute) {
65
64
  };
66
65
  default:
67
66
  // Handle arrays of primitive types and undefined attribute.type
68
- if ((_c = attribute.type) === null || _c === void 0 ? void 0 : _c.endsWith("[]")) {
67
+ if (attribute.type?.endsWith("[]")) {
69
68
  const itemType = attribute.type.slice(0, -2);
70
69
  return {
71
70
  type: "array",