@langgraph-js/sdk 4.5.0 → 4.6.1
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/.turbo/turbo-build.log +4 -0
- package/dist/History.d.ts +14 -4
- package/dist/History.js +9 -2
- package/dist/LangGraphClient.d.ts +22 -14
- package/dist/LangGraphClient.js +40 -11
- package/dist/TestKit.d.ts +1 -164
- package/dist/react/ChatContext.d.ts +9 -3
- package/dist/solid/ChatContext.d.ts +9 -3
- package/dist/ui-store/createChatStore.d.ts +20 -3
- package/dist/ui-store/createChatStore.js +102 -7
- package/dist/vue/ChatContext.d.ts +9 -3
- package/package.json +1 -1
- package/src/History.ts +23 -5
- package/src/LangGraphClient.ts +38 -14
- package/src/TestKit.ts +1 -1
- package/src/ui-store/createChatStore.ts +131 -8
package/.turbo/turbo-build.log
CHANGED
package/dist/History.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface SessionInfo {
|
|
|
9
9
|
thread?: Thread<any>;
|
|
10
10
|
/** Agent 名称 */
|
|
11
11
|
agentName: string;
|
|
12
|
+
/** 会话元数据 */
|
|
13
|
+
metadata?: Record<string, any>;
|
|
12
14
|
}
|
|
13
15
|
export interface CreateSessionOptions {
|
|
14
16
|
/** 会话 ID / Thread ID,不提供则自动生成 */
|
|
@@ -19,6 +21,8 @@ export interface CreateSessionOptions {
|
|
|
19
21
|
restore?: boolean;
|
|
20
22
|
/** Graph ID */
|
|
21
23
|
graphId?: string;
|
|
24
|
+
/** 会话元数据 */
|
|
25
|
+
metadata?: Record<string, any>;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
24
28
|
* @zh History 类用于管理多个 LangGraphClient 实例,支持多会话场景
|
|
@@ -94,11 +98,17 @@ export declare class History {
|
|
|
94
98
|
* @en Lists all sessions from remote
|
|
95
99
|
*/
|
|
96
100
|
listRemoteSessions(options?: {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
ids?: string[];
|
|
102
|
+
metadata?: Record<string, any>;
|
|
103
|
+
status?: "idle" | "busy" | "interrupted" | "error";
|
|
104
|
+
values?: any;
|
|
100
105
|
limit?: number;
|
|
101
|
-
|
|
106
|
+
offset?: number;
|
|
107
|
+
sortBy?: "thread_id" | "status" | "created_at" | "updated_at";
|
|
108
|
+
sortOrder?: "asc" | "desc";
|
|
109
|
+
select?: Array<"thread_id" | "created_at" | "updated_at" | "metadata" | "config" | "context" | "status" | "values" | "interrupts">;
|
|
110
|
+
withoutDetails?: boolean;
|
|
111
|
+
}): Promise<Thread<unknown, unknown>[]>;
|
|
102
112
|
/**
|
|
103
113
|
* @zh 从远程同步会话到本地(仅同步元数据,不创建 Client)
|
|
104
114
|
* @en Syncs sessions from remote to local (metadata only, no client created)
|
package/dist/History.js
CHANGED
|
@@ -32,6 +32,7 @@ export class History {
|
|
|
32
32
|
const sessionInfo = {
|
|
33
33
|
sessionId,
|
|
34
34
|
agentName,
|
|
35
|
+
metadata: options.metadata,
|
|
35
36
|
};
|
|
36
37
|
// 如果是从已有 Thread 恢复,则立即获取 Thread
|
|
37
38
|
if (options.restore) {
|
|
@@ -54,8 +55,14 @@ export class History {
|
|
|
54
55
|
if (!session.client) {
|
|
55
56
|
const client = new LangGraphClient(this.clientConfig);
|
|
56
57
|
await client.initAssistant(session.agentName);
|
|
57
|
-
//
|
|
58
|
-
|
|
58
|
+
// 如果有 metadata,立即创建 Thread 并带上 metadata
|
|
59
|
+
if (session.metadata && !session.thread) {
|
|
60
|
+
await client.createThread({
|
|
61
|
+
graphId: client.getCurrentAssistant()?.graph_id,
|
|
62
|
+
metadata: session.metadata,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// 如果已有 thread 或者必须重置,则从历史恢复
|
|
59
66
|
if (session.thread || mustResetStream) {
|
|
60
67
|
await client.resetThread(session.agentName, sessionId);
|
|
61
68
|
}
|
|
@@ -43,6 +43,7 @@ export type SendMessageOptions = {
|
|
|
43
43
|
};
|
|
44
44
|
command?: Command;
|
|
45
45
|
joinRunId?: string;
|
|
46
|
+
metadata?: Record<string, any>;
|
|
46
47
|
};
|
|
47
48
|
export interface LangGraphClientConfig {
|
|
48
49
|
apiUrl?: string;
|
|
@@ -153,18 +154,18 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
153
154
|
threadId?: string;
|
|
154
155
|
ifExists?: import("@langchain/langgraph-sdk").OnConflictBehavior;
|
|
155
156
|
graphId?: string;
|
|
156
|
-
}): Promise<Thread<TStateType>>;
|
|
157
|
+
}): Promise<Thread<TStateType, unknown>>;
|
|
157
158
|
search(query?: {
|
|
158
159
|
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
159
|
-
limit
|
|
160
|
+
limit? /** 自定义客户端实现,如果不提供则使用官方 Client */: number;
|
|
160
161
|
offset?: number;
|
|
161
162
|
status?: import("@langchain/langgraph-sdk").ThreadStatus;
|
|
162
163
|
sortBy?: import("@langgraph-js/pure-graph/dist/types.js").ThreadSortBy;
|
|
163
164
|
sortOrder?: import("@langgraph-js/pure-graph/dist/types.js").SortOrder;
|
|
164
|
-
}): Promise<Thread<TStateType>[]>;
|
|
165
|
-
get(threadId: string): Promise<Thread<TStateType>>;
|
|
165
|
+
}): Promise<Thread<TStateType, unknown>[]>;
|
|
166
|
+
get(threadId: string): Promise<Thread<TStateType, unknown>>;
|
|
166
167
|
delete(threadId: string): Promise<void>;
|
|
167
|
-
updateState(threadId: string, thread: Partial<Thread<TStateType>>): Promise<Pick<import("@langchain/langgraph-sdk").Config, "configurable">>;
|
|
168
|
+
updateState(threadId: string, thread: Partial<Thread<TStateType, unknown>>): Promise<Pick<import("@langchain/langgraph-sdk").Config, "configurable">>;
|
|
168
169
|
};
|
|
169
170
|
/** 代理 runs 属性到内部 client */
|
|
170
171
|
get runs(): ILangGraphClient["runs"];
|
|
@@ -182,27 +183,34 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
182
183
|
* @zh 创建一个新的 Thread。
|
|
183
184
|
* @en Creates a new Thread.
|
|
184
185
|
*/
|
|
185
|
-
createThread({ threadId, graphId }?: {
|
|
186
|
+
createThread({ threadId, graphId, metadata }?: {
|
|
186
187
|
threadId?: string;
|
|
187
188
|
graphId?: string;
|
|
188
|
-
|
|
189
|
+
metadata?: Record<string, any>;
|
|
190
|
+
}): Promise<Thread<TStateType, unknown>>;
|
|
189
191
|
graphVisualize(): Promise<import("@langchain/langgraph-sdk").AssistantGraph>;
|
|
190
192
|
/**
|
|
191
193
|
* @zh 列出所有的 Thread。
|
|
192
194
|
* @en Lists all Threads.
|
|
193
195
|
*/
|
|
194
196
|
listThreads(options?: {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
ids?: string[];
|
|
198
|
+
metadata?: Record<string, any>;
|
|
199
|
+
status?: "idle" | "busy" | "interrupted" | "error";
|
|
200
|
+
values?: any;
|
|
198
201
|
limit?: number;
|
|
199
|
-
|
|
202
|
+
offset?: number;
|
|
203
|
+
sortBy?: "thread_id" | "status" | "created_at" | "updated_at";
|
|
204
|
+
sortOrder?: "asc" | "desc";
|
|
205
|
+
select?: Array<"thread_id" | "created_at" | "updated_at" | "metadata" | "config" | "context" | "status" | "values" | "interrupts">;
|
|
206
|
+
withoutDetails?: boolean;
|
|
207
|
+
}): Promise<Thread<TStateType, unknown>[]>;
|
|
200
208
|
deleteThread(threadId: string): Promise<void>;
|
|
201
209
|
/**
|
|
202
210
|
* @zh 从历史中恢复 Thread 数据。
|
|
203
211
|
* @en Resets the Thread data from history.
|
|
204
212
|
*/
|
|
205
|
-
resetThread(agent: string, threadId: string): Promise<Thread<TStateType>>;
|
|
213
|
+
resetThread(agent: string, threadId: string): Promise<Thread<TStateType, unknown>>;
|
|
206
214
|
resetStream(): Promise<void>;
|
|
207
215
|
cloneMessage(message: Message): Message;
|
|
208
216
|
/**
|
|
@@ -241,7 +249,7 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
241
249
|
* @zh 发送消息到 LangGraph 后端。
|
|
242
250
|
* @en Sends a message to the LangGraph backend.
|
|
243
251
|
*/
|
|
244
|
-
sendMessage(input: string | Message[], { joinRunId, extraParams, _debug, command }?: SendMessageOptions): Promise<any[]>;
|
|
252
|
+
sendMessage(input: string | Message[], { joinRunId, extraParams, _debug, command, metadata }?: SendMessageOptions): Promise<any[]>;
|
|
245
253
|
/** 当前子图位置,但是依赖 stream,不太适合稳定使用*/
|
|
246
254
|
private graphPosition;
|
|
247
255
|
getGraphPosition(): {
|
|
@@ -283,7 +291,7 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
283
291
|
* @zh 获取当前的 Thread。
|
|
284
292
|
* @en Gets the current Thread.
|
|
285
293
|
*/
|
|
286
|
-
getCurrentThread(): Thread<TStateType> | null;
|
|
294
|
+
getCurrentThread(): Thread<TStateType, unknown> | null;
|
|
287
295
|
/**
|
|
288
296
|
* @zh 获取当前的 Assistant。
|
|
289
297
|
* @en Gets the current Assistant.
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -89,9 +89,10 @@ export class LangGraphClient extends EventEmitter {
|
|
|
89
89
|
* @zh 创建一个新的 Thread。
|
|
90
90
|
* @en Creates a new Thread.
|
|
91
91
|
*/
|
|
92
|
-
async createThread({ threadId, graphId } = {}) {
|
|
92
|
+
async createThread({ threadId, graphId, metadata } = {}) {
|
|
93
93
|
try {
|
|
94
94
|
this.currentThread = await this.threads.create({
|
|
95
|
+
metadata,
|
|
95
96
|
threadId,
|
|
96
97
|
graphId,
|
|
97
98
|
});
|
|
@@ -112,14 +113,39 @@ export class LangGraphClient extends EventEmitter {
|
|
|
112
113
|
* @en Lists all Threads.
|
|
113
114
|
*/
|
|
114
115
|
async listThreads(options = {}) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
const searchOptions = {};
|
|
117
|
+
if (options.ids)
|
|
118
|
+
searchOptions.ids = options.ids;
|
|
119
|
+
if (options.metadata)
|
|
120
|
+
searchOptions.metadata = options.metadata;
|
|
121
|
+
if (options.status)
|
|
122
|
+
searchOptions.status = options.status;
|
|
123
|
+
if (options.values)
|
|
124
|
+
searchOptions.values = options.values;
|
|
125
|
+
if (options.limit !== undefined)
|
|
126
|
+
searchOptions.limit = options.limit;
|
|
127
|
+
if (options.offset !== undefined)
|
|
128
|
+
searchOptions.offset = options.offset;
|
|
129
|
+
if (options.sortBy)
|
|
130
|
+
searchOptions.sortBy = options.sortBy;
|
|
131
|
+
if (options.sortOrder)
|
|
132
|
+
searchOptions.sortOrder = options.sortOrder;
|
|
133
|
+
if (options.select)
|
|
134
|
+
searchOptions.select = options.select;
|
|
135
|
+
if (options.withoutDetails !== undefined)
|
|
136
|
+
searchOptions.without_details = options.withoutDetails;
|
|
137
|
+
// 设置默认值
|
|
138
|
+
if (!options.sortBy)
|
|
139
|
+
searchOptions.sortBy = "updated_at";
|
|
140
|
+
if (!options.sortOrder)
|
|
141
|
+
searchOptions.sortOrder = "desc";
|
|
142
|
+
if (!options.limit)
|
|
143
|
+
searchOptions.limit = 10;
|
|
144
|
+
if (!options.offset)
|
|
145
|
+
searchOptions.offset = 0;
|
|
146
|
+
if (!options.withoutDetails)
|
|
147
|
+
searchOptions.without_details = true;
|
|
148
|
+
return this.threads.search(searchOptions);
|
|
123
149
|
}
|
|
124
150
|
async deleteThread(threadId) {
|
|
125
151
|
return this.threads.delete(threadId);
|
|
@@ -224,12 +250,15 @@ export class LangGraphClient extends EventEmitter {
|
|
|
224
250
|
* @zh 发送消息到 LangGraph 后端。
|
|
225
251
|
* @en Sends a message to the LangGraph backend.
|
|
226
252
|
*/
|
|
227
|
-
async sendMessage(input, { joinRunId, extraParams, _debug, command } = {}) {
|
|
253
|
+
async sendMessage(input, { joinRunId, extraParams, _debug, command, metadata } = {}) {
|
|
228
254
|
if (!this.currentAssistant) {
|
|
229
255
|
throw new Error("Thread or Assistant not initialized");
|
|
230
256
|
}
|
|
231
257
|
if (!this.currentThread) {
|
|
232
|
-
await this.createThread({
|
|
258
|
+
await this.createThread({
|
|
259
|
+
graphId: this.currentAssistant.graph_id,
|
|
260
|
+
metadata,
|
|
261
|
+
});
|
|
233
262
|
this.emit("thread", {
|
|
234
263
|
event: "thread/create",
|
|
235
264
|
data: {
|
package/dist/TestKit.d.ts
CHANGED
|
@@ -146,169 +146,6 @@ export declare class TestLangGraphChat {
|
|
|
146
146
|
*/
|
|
147
147
|
findLast(type: "human" | "ai" | "tool", options?: {
|
|
148
148
|
before?: (item: RenderMessage) => boolean;
|
|
149
|
-
}):
|
|
150
|
-
additional_kwargs?: {
|
|
151
|
-
[x: string]: unknown;
|
|
152
|
-
} | undefined;
|
|
153
|
-
content: string | ({
|
|
154
|
-
type: "text";
|
|
155
|
-
text: string;
|
|
156
|
-
} | {
|
|
157
|
-
type: "image_url";
|
|
158
|
-
image_url: string | {
|
|
159
|
-
url: string;
|
|
160
|
-
detail?: ("auto" | "low" | "high") | undefined;
|
|
161
|
-
};
|
|
162
|
-
})[];
|
|
163
|
-
id?: string | undefined;
|
|
164
|
-
name?: string | undefined;
|
|
165
|
-
response_metadata?: Record<string, unknown> | undefined;
|
|
166
|
-
} & {
|
|
167
|
-
type: "human";
|
|
168
|
-
example?: boolean | undefined;
|
|
169
|
-
} & {
|
|
170
|
-
name?: string;
|
|
171
|
-
node_name?: string;
|
|
172
|
-
tool_input?: string;
|
|
173
|
-
additional_kwargs?: {
|
|
174
|
-
create_time: string;
|
|
175
|
-
update_time: string;
|
|
176
|
-
done?: boolean;
|
|
177
|
-
tool_calls?: {
|
|
178
|
-
function: {
|
|
179
|
-
arguments: string;
|
|
180
|
-
};
|
|
181
|
-
}[];
|
|
182
|
-
};
|
|
183
|
-
usage_metadata?: {
|
|
184
|
-
total_tokens: number;
|
|
185
|
-
input_tokens: number;
|
|
186
|
-
output_tokens: number;
|
|
187
|
-
};
|
|
188
|
-
tool_call_id?: string;
|
|
189
|
-
sub_messages?: RenderMessage[];
|
|
190
|
-
spend_time?: number;
|
|
191
|
-
unique_id?: string;
|
|
192
|
-
done?: boolean;
|
|
193
|
-
}) | ({
|
|
194
|
-
additional_kwargs?: {
|
|
195
|
-
[x: string]: unknown;
|
|
196
|
-
} | undefined;
|
|
197
|
-
content: string | ({
|
|
198
|
-
type: "text";
|
|
199
|
-
text: string;
|
|
200
|
-
} | {
|
|
201
|
-
type: "image_url";
|
|
202
|
-
image_url: string | {
|
|
203
|
-
url: string;
|
|
204
|
-
detail?: ("auto" | "low" | "high") | undefined;
|
|
205
|
-
};
|
|
206
|
-
})[];
|
|
207
|
-
id?: string | undefined;
|
|
208
|
-
name?: string | undefined;
|
|
209
|
-
response_metadata?: Record<string, unknown> | undefined;
|
|
210
|
-
} & {
|
|
211
|
-
type: "ai";
|
|
212
|
-
example?: boolean | undefined;
|
|
213
|
-
tool_calls?: {
|
|
214
|
-
name: string;
|
|
215
|
-
args: {
|
|
216
|
-
[x: string]: any;
|
|
217
|
-
};
|
|
218
|
-
id?: string | undefined;
|
|
219
|
-
type?: "tool_call" | undefined;
|
|
220
|
-
}[] | undefined;
|
|
221
|
-
invalid_tool_calls?: {
|
|
222
|
-
name?: string | undefined;
|
|
223
|
-
args?: string | undefined;
|
|
224
|
-
id?: string | undefined;
|
|
225
|
-
error?: string | undefined;
|
|
226
|
-
type?: "invalid_tool_call" | undefined;
|
|
227
|
-
}[] | undefined;
|
|
228
|
-
usage_metadata?: {
|
|
229
|
-
input_tokens: number;
|
|
230
|
-
output_tokens: number;
|
|
231
|
-
total_tokens: number;
|
|
232
|
-
input_token_details?: {
|
|
233
|
-
audio?: number | undefined;
|
|
234
|
-
cache_read?: number | undefined;
|
|
235
|
-
cache_creation?: number | undefined;
|
|
236
|
-
} | undefined;
|
|
237
|
-
output_token_details?: {
|
|
238
|
-
audio?: number | undefined;
|
|
239
|
-
reasoning?: number | undefined;
|
|
240
|
-
} | undefined;
|
|
241
|
-
} | undefined;
|
|
242
|
-
} & {
|
|
243
|
-
name?: string;
|
|
244
|
-
node_name?: string;
|
|
245
|
-
tool_input?: string;
|
|
246
|
-
additional_kwargs?: {
|
|
247
|
-
create_time: string;
|
|
248
|
-
update_time: string;
|
|
249
|
-
done?: boolean;
|
|
250
|
-
tool_calls?: {
|
|
251
|
-
function: {
|
|
252
|
-
arguments: string;
|
|
253
|
-
};
|
|
254
|
-
}[];
|
|
255
|
-
};
|
|
256
|
-
usage_metadata?: {
|
|
257
|
-
total_tokens: number;
|
|
258
|
-
input_tokens: number;
|
|
259
|
-
output_tokens: number;
|
|
260
|
-
};
|
|
261
|
-
tool_call_id?: string;
|
|
262
|
-
sub_messages?: RenderMessage[];
|
|
263
|
-
spend_time?: number;
|
|
264
|
-
unique_id?: string;
|
|
265
|
-
done?: boolean;
|
|
266
|
-
}) | ({
|
|
267
|
-
additional_kwargs?: {
|
|
268
|
-
[x: string]: unknown;
|
|
269
|
-
} | undefined;
|
|
270
|
-
content: string | ({
|
|
271
|
-
type: "text";
|
|
272
|
-
text: string;
|
|
273
|
-
} | {
|
|
274
|
-
type: "image_url";
|
|
275
|
-
image_url: string | {
|
|
276
|
-
url: string;
|
|
277
|
-
detail?: ("auto" | "low" | "high") | undefined;
|
|
278
|
-
};
|
|
279
|
-
})[];
|
|
280
|
-
id?: string | undefined;
|
|
281
|
-
name?: string | undefined;
|
|
282
|
-
response_metadata?: Record<string, unknown> | undefined;
|
|
283
|
-
} & {
|
|
284
|
-
type: "tool";
|
|
285
|
-
status?: "error" | "success" | undefined;
|
|
286
|
-
tool_call_id: string;
|
|
287
|
-
artifact?: any;
|
|
288
|
-
} & {
|
|
289
|
-
name?: string;
|
|
290
|
-
node_name?: string;
|
|
291
|
-
tool_input?: string;
|
|
292
|
-
additional_kwargs?: {
|
|
293
|
-
create_time: string;
|
|
294
|
-
update_time: string;
|
|
295
|
-
done?: boolean;
|
|
296
|
-
tool_calls?: {
|
|
297
|
-
function: {
|
|
298
|
-
arguments: string;
|
|
299
|
-
};
|
|
300
|
-
}[];
|
|
301
|
-
};
|
|
302
|
-
usage_metadata?: {
|
|
303
|
-
total_tokens: number;
|
|
304
|
-
input_tokens: number;
|
|
305
|
-
output_tokens: number;
|
|
306
|
-
};
|
|
307
|
-
tool_call_id?: string;
|
|
308
|
-
sub_messages?: RenderMessage[];
|
|
309
|
-
spend_time?: number;
|
|
310
|
-
unique_id?: string;
|
|
311
|
-
done?: boolean;
|
|
312
|
-
});
|
|
149
|
+
}): RenderMessage;
|
|
313
150
|
}
|
|
314
151
|
export {};
|
|
@@ -26,7 +26,9 @@ export declare const useChat: () => UnionStore<{
|
|
|
26
26
|
showHistory: import("nanostores").PreinitializedWritableAtom<boolean> & object;
|
|
27
27
|
historyList: import("nanostores").PreinitializedWritableAtom<import("@langchain/langgraph-sdk").Thread<{
|
|
28
28
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
29
|
-
}>[]> & object;
|
|
29
|
+
}, unknown>[]> & object;
|
|
30
|
+
historyPagination: import("nanostores").PreinitializedWritableAtom<import("../ui-store/createChatStore.js").HistoryPagination> & object;
|
|
31
|
+
historyFilter: import("nanostores").PreinitializedWritableAtom<import("../ui-store/createChatStore.js").HistoryFilter> & object;
|
|
30
32
|
};
|
|
31
33
|
mutations: {
|
|
32
34
|
setCurrentArtifactById: (id: string, tool_id: string) => void;
|
|
@@ -38,7 +40,7 @@ export declare const useChat: () => UnionStore<{
|
|
|
38
40
|
createNewSession: () => Promise<void>;
|
|
39
41
|
refreshSessionList: () => Promise<void>;
|
|
40
42
|
refreshHistoryList: () => Promise<void>;
|
|
41
|
-
sendMessage: (message?: import("@langchain/langgraph-sdk").Message[],
|
|
43
|
+
sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], options?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean, isResume?: boolean) => Promise<void>;
|
|
42
44
|
stopGeneration: () => void;
|
|
43
45
|
setUserInput: (input: string) => void;
|
|
44
46
|
revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
|
|
@@ -55,13 +57,17 @@ export declare const useChat: () => UnionStore<{
|
|
|
55
57
|
addToHistory: (thread: import("@langchain/langgraph-sdk").Thread<{
|
|
56
58
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
57
59
|
}>) => void;
|
|
58
|
-
createNewChat
|
|
60
|
+
createNewChat(metadata?: Record<string, any>): Promise<void>;
|
|
59
61
|
toHistoryChat: (thread: import("@langchain/langgraph-sdk").Thread<{
|
|
60
62
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
61
63
|
}>) => Promise<void>;
|
|
62
64
|
deleteHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
|
|
63
65
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
64
66
|
}>): Promise<void>;
|
|
67
|
+
setHistoryPage(page: number): void;
|
|
68
|
+
setHistoryPageSize(pageSize: number): void;
|
|
69
|
+
setHistoryFilter(filter: Partial<import("../ui-store/createChatStore.js").HistoryFilter>): void;
|
|
70
|
+
resetHistoryFilter(): void;
|
|
65
71
|
};
|
|
66
72
|
}>;
|
|
67
73
|
interface ChatProviderProps {
|
|
@@ -26,7 +26,9 @@ export declare const useChat: () => UnionStoreSolid<{
|
|
|
26
26
|
showHistory: PreinitializedWritableAtom<boolean> & object;
|
|
27
27
|
historyList: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").Thread<{
|
|
28
28
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
29
|
-
}>[]> & object;
|
|
29
|
+
}, unknown>[]> & object;
|
|
30
|
+
historyPagination: PreinitializedWritableAtom<import("../ui-store/createChatStore.js").HistoryPagination> & object;
|
|
31
|
+
historyFilter: PreinitializedWritableAtom<import("../ui-store/createChatStore.js").HistoryFilter> & object;
|
|
30
32
|
};
|
|
31
33
|
mutations: {
|
|
32
34
|
setCurrentArtifactById: (id: string, tool_id: string) => void;
|
|
@@ -38,7 +40,7 @@ export declare const useChat: () => UnionStoreSolid<{
|
|
|
38
40
|
createNewSession: () => Promise<void>;
|
|
39
41
|
refreshSessionList: () => Promise<void>;
|
|
40
42
|
refreshHistoryList: () => Promise<void>;
|
|
41
|
-
sendMessage: (message?: import("@langchain/langgraph-sdk").Message[],
|
|
43
|
+
sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], options?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean, isResume?: boolean) => Promise<void>;
|
|
42
44
|
stopGeneration: () => void;
|
|
43
45
|
setUserInput: (input: string) => void;
|
|
44
46
|
revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
|
|
@@ -55,13 +57,17 @@ export declare const useChat: () => UnionStoreSolid<{
|
|
|
55
57
|
addToHistory: (thread: import("@langchain/langgraph-sdk").Thread<{
|
|
56
58
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
57
59
|
}>) => void;
|
|
58
|
-
createNewChat
|
|
60
|
+
createNewChat(metadata?: Record<string, any>): Promise<void>;
|
|
59
61
|
toHistoryChat: (thread: import("@langchain/langgraph-sdk").Thread<{
|
|
60
62
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
61
63
|
}>) => Promise<void>;
|
|
62
64
|
deleteHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
|
|
63
65
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
64
66
|
}>): Promise<void>;
|
|
67
|
+
setHistoryPage(page: number): void;
|
|
68
|
+
setHistoryPageSize(pageSize: number): void;
|
|
69
|
+
setHistoryFilter(filter: Partial<import("../ui-store/createChatStore.js").HistoryFilter>): void;
|
|
70
|
+
resetHistoryFilter(): void;
|
|
65
71
|
};
|
|
66
72
|
}>;
|
|
67
73
|
interface ChatProviderProps {
|
|
@@ -17,6 +17,17 @@ interface ChatStoreContext {
|
|
|
17
17
|
/** 初始化时是否自动激活最近的历史会话(默认 false,创建新会话) */
|
|
18
18
|
autoRestoreLastSession?: boolean;
|
|
19
19
|
}
|
|
20
|
+
export interface HistoryPagination {
|
|
21
|
+
page: number;
|
|
22
|
+
pageSize: number;
|
|
23
|
+
total: number;
|
|
24
|
+
}
|
|
25
|
+
export interface HistoryFilter {
|
|
26
|
+
metadata: Record<string, any> | null;
|
|
27
|
+
status: "idle" | "busy" | "interrupted" | "error" | null;
|
|
28
|
+
sortBy: "thread_id" | "status" | "created_at" | "updated_at";
|
|
29
|
+
sortOrder: "asc" | "desc";
|
|
30
|
+
}
|
|
20
31
|
export declare const createChatStore: (initClientName: string, config: Partial<LangGraphClientConfig>, context?: ChatStoreContext) => {
|
|
21
32
|
data: {
|
|
22
33
|
artifacts: import("nanostores").PreinitializedWritableAtom<import("../artifacts/index.js").ComposedArtifact[]> & object;
|
|
@@ -42,7 +53,9 @@ export declare const createChatStore: (initClientName: string, config: Partial<L
|
|
|
42
53
|
showHistory: import("nanostores").PreinitializedWritableAtom<boolean> & object;
|
|
43
54
|
historyList: import("nanostores").PreinitializedWritableAtom<Thread<{
|
|
44
55
|
messages: Message[];
|
|
45
|
-
}>[]> & object;
|
|
56
|
+
}, unknown>[]> & object;
|
|
57
|
+
historyPagination: import("nanostores").PreinitializedWritableAtom<HistoryPagination> & object;
|
|
58
|
+
historyFilter: import("nanostores").PreinitializedWritableAtom<HistoryFilter> & object;
|
|
46
59
|
};
|
|
47
60
|
mutations: {
|
|
48
61
|
setCurrentArtifactById: (id: string, tool_id: string) => void;
|
|
@@ -54,7 +67,7 @@ export declare const createChatStore: (initClientName: string, config: Partial<L
|
|
|
54
67
|
createNewSession: () => Promise<void>;
|
|
55
68
|
refreshSessionList: () => Promise<void>;
|
|
56
69
|
refreshHistoryList: () => Promise<void>;
|
|
57
|
-
sendMessage: (message?: Message[],
|
|
70
|
+
sendMessage: (message?: Message[], options?: SendMessageOptions, withoutCheck?: boolean, isResume?: boolean) => Promise<void>;
|
|
58
71
|
stopGeneration: () => void;
|
|
59
72
|
setUserInput: (input: string) => void;
|
|
60
73
|
revertChatTo(messageId: string, resend?: boolean, sendOptions?: SendMessageOptions & RevertChatToOptions): Promise<void>;
|
|
@@ -71,13 +84,17 @@ export declare const createChatStore: (initClientName: string, config: Partial<L
|
|
|
71
84
|
addToHistory: (thread: Thread<{
|
|
72
85
|
messages: Message[];
|
|
73
86
|
}>) => void;
|
|
74
|
-
createNewChat
|
|
87
|
+
createNewChat(metadata?: Record<string, any>): Promise<void>;
|
|
75
88
|
toHistoryChat: (thread: Thread<{
|
|
76
89
|
messages: Message[];
|
|
77
90
|
}>) => Promise<void>;
|
|
78
91
|
deleteHistoryChat(thread: Thread<{
|
|
79
92
|
messages: Message[];
|
|
80
93
|
}>): Promise<void>;
|
|
94
|
+
setHistoryPage(page: number): void;
|
|
95
|
+
setHistoryPageSize(pageSize: number): void;
|
|
96
|
+
setHistoryFilter(filter: Partial<HistoryFilter>): void;
|
|
97
|
+
resetHistoryFilter(): void;
|
|
81
98
|
};
|
|
82
99
|
};
|
|
83
100
|
export {};
|
|
@@ -70,6 +70,19 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
70
70
|
const showHistory = atom(context.showHistory ?? false);
|
|
71
71
|
const showGraph = atom(context.showGraph ?? false);
|
|
72
72
|
const graphVisualize = atom(null);
|
|
73
|
+
// 分页状态
|
|
74
|
+
const historyPagination = atom({
|
|
75
|
+
page: 1,
|
|
76
|
+
pageSize: 10,
|
|
77
|
+
total: 0,
|
|
78
|
+
});
|
|
79
|
+
// 历史记录筛选状态
|
|
80
|
+
const historyFilter = atom({
|
|
81
|
+
metadata: null,
|
|
82
|
+
status: null,
|
|
83
|
+
sortBy: "updated_at",
|
|
84
|
+
sortOrder: "desc",
|
|
85
|
+
});
|
|
73
86
|
// ============ 内部状态 ============
|
|
74
87
|
let cleanupCurrentClient = null;
|
|
75
88
|
// ============ 计算属性 ============
|
|
@@ -113,7 +126,6 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
113
126
|
});
|
|
114
127
|
await historyManager.init(currentAgent.get(), { fallbackToAvailableAssistants: context.fallbackToAvailableAssistants });
|
|
115
128
|
history.set(historyManager);
|
|
116
|
-
// 同步远程会话列表
|
|
117
129
|
// 根据配置决定初始化行为
|
|
118
130
|
if (context.autoRestoreLastSession) {
|
|
119
131
|
await refreshSessionList();
|
|
@@ -137,9 +149,36 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
137
149
|
if (!historyManager)
|
|
138
150
|
return;
|
|
139
151
|
try {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
const pagination = historyPagination.get();
|
|
153
|
+
const filter = historyFilter.get();
|
|
154
|
+
// 计算偏移量
|
|
155
|
+
const offset = (pagination.page - 1) * pagination.pageSize;
|
|
156
|
+
// 使用 listRemoteSessions 支持筛选
|
|
157
|
+
const threads = await historyManager.listRemoteSessions({
|
|
158
|
+
limit: pagination.pageSize,
|
|
159
|
+
offset,
|
|
160
|
+
metadata: filter.metadata || undefined,
|
|
161
|
+
status: filter.status || undefined,
|
|
162
|
+
sortBy: filter.sortBy,
|
|
163
|
+
sortOrder: filter.sortOrder,
|
|
164
|
+
withoutDetails: true,
|
|
165
|
+
});
|
|
166
|
+
// 注意:后端可能不返回总数,这里需要根据返回的记录数判断是否有下一页
|
|
167
|
+
// 如果返回的记录数小于 pageSize,说明没有更多数据了
|
|
168
|
+
const hasMore = threads.length === pagination.pageSize;
|
|
169
|
+
const estimatedTotal = (pagination.page - 1) * pagination.pageSize + threads.length;
|
|
170
|
+
sessions.set(threads.map((thread) => ({
|
|
171
|
+
sessionId: thread.thread_id,
|
|
172
|
+
thread,
|
|
173
|
+
agentName: currentAgent.get(),
|
|
174
|
+
metadata: thread.metadata,
|
|
175
|
+
})));
|
|
176
|
+
historyList.set(threads);
|
|
177
|
+
// 更新分页状态(注意:这里只是估计值,实际总数可能需要从后端获取)
|
|
178
|
+
historyPagination.set({
|
|
179
|
+
...pagination,
|
|
180
|
+
total: hasMore ? pagination.page * pagination.pageSize + 1 : estimatedTotal,
|
|
181
|
+
});
|
|
143
182
|
}
|
|
144
183
|
catch (error) {
|
|
145
184
|
console.error("Failed to sync sessions:", error);
|
|
@@ -286,7 +325,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
286
325
|
}
|
|
287
326
|
}
|
|
288
327
|
// ============ 消息和交互逻辑 ============
|
|
289
|
-
async function sendMessage(message,
|
|
328
|
+
async function sendMessage(message, options, withoutCheck = false, isResume = false) {
|
|
290
329
|
const c = client.get();
|
|
291
330
|
if ((!withoutCheck && !userInput.get().trim() && !message?.length) || !c)
|
|
292
331
|
return;
|
|
@@ -296,7 +335,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
296
335
|
inChatError.set(null);
|
|
297
336
|
try {
|
|
298
337
|
loading.set(true);
|
|
299
|
-
await c.sendMessage(message || userInput.get(),
|
|
338
|
+
await c.sendMessage(message || userInput.get(), options);
|
|
300
339
|
}
|
|
301
340
|
catch (e) {
|
|
302
341
|
const isThreadRunning = e.message.includes("422");
|
|
@@ -364,6 +403,9 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
364
403
|
// 历史记录
|
|
365
404
|
showHistory,
|
|
366
405
|
historyList,
|
|
406
|
+
// 分页和筛选
|
|
407
|
+
historyPagination,
|
|
408
|
+
historyFilter,
|
|
367
409
|
...artifactHook.data,
|
|
368
410
|
},
|
|
369
411
|
mutations: {
|
|
@@ -420,7 +462,20 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
420
462
|
},
|
|
421
463
|
// 历史记录(兼容旧 API)
|
|
422
464
|
addToHistory,
|
|
423
|
-
createNewChat
|
|
465
|
+
async createNewChat(metadata) {
|
|
466
|
+
const historyManager = history.get();
|
|
467
|
+
if (!historyManager)
|
|
468
|
+
return;
|
|
469
|
+
try {
|
|
470
|
+
const session = await historyManager.createSession({ metadata });
|
|
471
|
+
await refreshSessionList();
|
|
472
|
+
await activateSession(session.sessionId);
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
console.error("Failed to create new chat:", error);
|
|
476
|
+
inChatError.set(error.message);
|
|
477
|
+
}
|
|
478
|
+
},
|
|
424
479
|
toHistoryChat: (thread) => activateSession(thread.thread_id, true),
|
|
425
480
|
async deleteHistoryChat(thread) {
|
|
426
481
|
const historyManager = history.get();
|
|
@@ -429,6 +484,46 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
429
484
|
await refreshSessionList();
|
|
430
485
|
}
|
|
431
486
|
},
|
|
487
|
+
// 分页和筛选操作
|
|
488
|
+
setHistoryPage(page) {
|
|
489
|
+
historyPagination.set({
|
|
490
|
+
...historyPagination.get(),
|
|
491
|
+
page,
|
|
492
|
+
});
|
|
493
|
+
refreshSessionList();
|
|
494
|
+
},
|
|
495
|
+
setHistoryPageSize(pageSize) {
|
|
496
|
+
historyPagination.set({
|
|
497
|
+
...historyPagination.get(),
|
|
498
|
+
pageSize,
|
|
499
|
+
page: 1, // 重置到第一页
|
|
500
|
+
});
|
|
501
|
+
refreshSessionList();
|
|
502
|
+
},
|
|
503
|
+
setHistoryFilter(filter) {
|
|
504
|
+
historyFilter.set({
|
|
505
|
+
...historyFilter.get(),
|
|
506
|
+
...filter,
|
|
507
|
+
});
|
|
508
|
+
historyPagination.set({
|
|
509
|
+
...historyPagination.get(),
|
|
510
|
+
page: 1, // 筛选变更时重置到第一页
|
|
511
|
+
});
|
|
512
|
+
refreshSessionList();
|
|
513
|
+
},
|
|
514
|
+
resetHistoryFilter() {
|
|
515
|
+
historyFilter.set({
|
|
516
|
+
metadata: null,
|
|
517
|
+
status: null,
|
|
518
|
+
sortBy: "updated_at",
|
|
519
|
+
sortOrder: "desc",
|
|
520
|
+
});
|
|
521
|
+
historyPagination.set({
|
|
522
|
+
...historyPagination.get(),
|
|
523
|
+
page: 1,
|
|
524
|
+
});
|
|
525
|
+
refreshSessionList();
|
|
526
|
+
},
|
|
432
527
|
...artifactHook.mutation,
|
|
433
528
|
},
|
|
434
529
|
};
|
|
@@ -70,7 +70,9 @@ export declare const useChatProvider: (props: ChatProviderProps) => {
|
|
|
70
70
|
showHistory: PreinitializedWritableAtom<boolean> & object;
|
|
71
71
|
historyList: PreinitializedWritableAtom<import("@langchain/langgraph-sdk").Thread<{
|
|
72
72
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
73
|
-
}>[]> & object;
|
|
73
|
+
}, unknown>[]> & object;
|
|
74
|
+
historyPagination: PreinitializedWritableAtom<import("../ui-store/createChatStore.js").HistoryPagination> & object;
|
|
75
|
+
historyFilter: PreinitializedWritableAtom<import("../ui-store/createChatStore.js").HistoryFilter> & object;
|
|
74
76
|
};
|
|
75
77
|
mutations: {
|
|
76
78
|
setCurrentArtifactById: (id: string, tool_id: string) => void;
|
|
@@ -82,7 +84,7 @@ export declare const useChatProvider: (props: ChatProviderProps) => {
|
|
|
82
84
|
createNewSession: () => Promise<void>;
|
|
83
85
|
refreshSessionList: () => Promise<void>;
|
|
84
86
|
refreshHistoryList: () => Promise<void>;
|
|
85
|
-
sendMessage: (message?: import("@langchain/langgraph-sdk").Message[],
|
|
87
|
+
sendMessage: (message?: import("@langchain/langgraph-sdk").Message[], options?: import("../LangGraphClient.js").SendMessageOptions, withoutCheck?: boolean, isResume?: boolean) => Promise<void>;
|
|
86
88
|
stopGeneration: () => void;
|
|
87
89
|
setUserInput: (input: string) => void;
|
|
88
90
|
revertChatTo(messageId: string, resend?: boolean, sendOptions?: import("../LangGraphClient.js").SendMessageOptions & import("../time-travel/index.js").RevertChatToOptions): Promise<void>;
|
|
@@ -99,13 +101,17 @@ export declare const useChatProvider: (props: ChatProviderProps) => {
|
|
|
99
101
|
addToHistory: (thread: import("@langchain/langgraph-sdk").Thread<{
|
|
100
102
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
101
103
|
}>) => void;
|
|
102
|
-
createNewChat
|
|
104
|
+
createNewChat(metadata?: Record<string, any>): Promise<void>;
|
|
103
105
|
toHistoryChat: (thread: import("@langchain/langgraph-sdk").Thread<{
|
|
104
106
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
105
107
|
}>) => Promise<void>;
|
|
106
108
|
deleteHistoryChat(thread: import("@langchain/langgraph-sdk").Thread<{
|
|
107
109
|
messages: import("@langchain/langgraph-sdk").Message[];
|
|
108
110
|
}>): Promise<void>;
|
|
111
|
+
setHistoryPage(page: number): void;
|
|
112
|
+
setHistoryPageSize(pageSize: number): void;
|
|
113
|
+
setHistoryFilter(filter: Partial<import("../ui-store/createChatStore.js").HistoryFilter>): void;
|
|
114
|
+
resetHistoryFilter(): void;
|
|
109
115
|
};
|
|
110
116
|
}>;
|
|
111
117
|
};
|
package/package.json
CHANGED
package/src/History.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface SessionInfo {
|
|
|
10
10
|
thread?: Thread<any>;
|
|
11
11
|
/** Agent 名称 */
|
|
12
12
|
agentName: string;
|
|
13
|
+
/** 会话元数据 */
|
|
14
|
+
metadata?: Record<string, any>;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export interface CreateSessionOptions {
|
|
@@ -21,6 +23,8 @@ export interface CreateSessionOptions {
|
|
|
21
23
|
restore?: boolean;
|
|
22
24
|
/** Graph ID */
|
|
23
25
|
graphId?: string;
|
|
26
|
+
/** 会话元数据 */
|
|
27
|
+
metadata?: Record<string, any>;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
/**
|
|
@@ -61,6 +65,7 @@ export class History {
|
|
|
61
65
|
const sessionInfo: SessionInfo = {
|
|
62
66
|
sessionId,
|
|
63
67
|
agentName,
|
|
68
|
+
metadata: options.metadata,
|
|
64
69
|
};
|
|
65
70
|
|
|
66
71
|
// 如果是从已有 Thread 恢复,则立即获取 Thread
|
|
@@ -89,8 +94,15 @@ export class History {
|
|
|
89
94
|
const client = new LangGraphClient(this.clientConfig);
|
|
90
95
|
await client.initAssistant(session.agentName);
|
|
91
96
|
|
|
92
|
-
//
|
|
93
|
-
|
|
97
|
+
// 如果有 metadata,立即创建 Thread 并带上 metadata
|
|
98
|
+
if (session.metadata && !session.thread) {
|
|
99
|
+
await client.createThread({
|
|
100
|
+
graphId: client.getCurrentAssistant()?.graph_id,
|
|
101
|
+
metadata: session.metadata,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 如果已有 thread 或者必须重置,则从历史恢复
|
|
94
106
|
if (session.thread || mustResetStream) {
|
|
95
107
|
await client.resetThread(session.agentName, sessionId);
|
|
96
108
|
}
|
|
@@ -230,10 +242,16 @@ export class History {
|
|
|
230
242
|
*/
|
|
231
243
|
async listRemoteSessions(
|
|
232
244
|
options: {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
245
|
+
ids?: string[];
|
|
246
|
+
metadata?: Record<string, any>;
|
|
247
|
+
status?: "idle" | "busy" | "interrupted" | "error";
|
|
248
|
+
values?: any;
|
|
236
249
|
limit?: number;
|
|
250
|
+
offset?: number;
|
|
251
|
+
sortBy?: "thread_id" | "status" | "created_at" | "updated_at";
|
|
252
|
+
sortOrder?: "asc" | "desc";
|
|
253
|
+
select?: Array<"thread_id" | "created_at" | "updated_at" | "metadata" | "config" | "context" | "status" | "values" | "interrupts">;
|
|
254
|
+
withoutDetails?: boolean;
|
|
237
255
|
} = {}
|
|
238
256
|
) {
|
|
239
257
|
return this.virtualClient.listThreads(options);
|
package/src/LangGraphClient.ts
CHANGED
|
@@ -46,6 +46,7 @@ export type SendMessageOptions = {
|
|
|
46
46
|
_debug?: { streamResponse?: any };
|
|
47
47
|
command?: Command;
|
|
48
48
|
joinRunId?: string;
|
|
49
|
+
metadata?: Record<string, any>;
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
export interface LangGraphClientConfig {
|
|
@@ -188,9 +189,10 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
188
189
|
* @zh 创建一个新的 Thread。
|
|
189
190
|
* @en Creates a new Thread.
|
|
190
191
|
*/
|
|
191
|
-
async createThread({ threadId, graphId }: { threadId?: string; graphId?: string } = {}) {
|
|
192
|
+
async createThread({ threadId, graphId, metadata }: { threadId?: string; graphId?: string; metadata?: Record<string, any> } = {}) {
|
|
192
193
|
try {
|
|
193
194
|
this.currentThread = await this.threads.create({
|
|
195
|
+
metadata,
|
|
194
196
|
threadId,
|
|
195
197
|
graphId,
|
|
196
198
|
});
|
|
@@ -212,20 +214,39 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
212
214
|
*/
|
|
213
215
|
async listThreads(
|
|
214
216
|
options: {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
ids?: string[];
|
|
218
|
+
metadata?: Record<string, any>;
|
|
219
|
+
status?: "idle" | "busy" | "interrupted" | "error";
|
|
220
|
+
values?: any;
|
|
218
221
|
limit?: number;
|
|
222
|
+
offset?: number;
|
|
223
|
+
sortBy?: "thread_id" | "status" | "created_at" | "updated_at";
|
|
224
|
+
sortOrder?: "asc" | "desc";
|
|
225
|
+
select?: Array<"thread_id" | "created_at" | "updated_at" | "metadata" | "config" | "context" | "status" | "values" | "interrupts">;
|
|
226
|
+
withoutDetails?: boolean;
|
|
219
227
|
} = {}
|
|
220
228
|
) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
+
const searchOptions: any = {};
|
|
230
|
+
|
|
231
|
+
if (options.ids) searchOptions.ids = options.ids;
|
|
232
|
+
if (options.metadata) searchOptions.metadata = options.metadata;
|
|
233
|
+
if (options.status) searchOptions.status = options.status;
|
|
234
|
+
if (options.values) searchOptions.values = options.values;
|
|
235
|
+
if (options.limit !== undefined) searchOptions.limit = options.limit;
|
|
236
|
+
if (options.offset !== undefined) searchOptions.offset = options.offset;
|
|
237
|
+
if (options.sortBy) searchOptions.sortBy = options.sortBy;
|
|
238
|
+
if (options.sortOrder) searchOptions.sortOrder = options.sortOrder;
|
|
239
|
+
if (options.select) searchOptions.select = options.select;
|
|
240
|
+
if (options.withoutDetails !== undefined) searchOptions.without_details = options.withoutDetails;
|
|
241
|
+
|
|
242
|
+
// 设置默认值
|
|
243
|
+
if (!options.sortBy) searchOptions.sortBy = "updated_at";
|
|
244
|
+
if (!options.sortOrder) searchOptions.sortOrder = "desc";
|
|
245
|
+
if (!options.limit) searchOptions.limit = 10;
|
|
246
|
+
if (!options.offset) searchOptions.offset = 0;
|
|
247
|
+
if (!options.withoutDetails) searchOptions.without_details = true;
|
|
248
|
+
|
|
249
|
+
return this.threads.search(searchOptions);
|
|
229
250
|
}
|
|
230
251
|
async deleteThread(threadId: string) {
|
|
231
252
|
return this.threads.delete(threadId);
|
|
@@ -344,12 +365,15 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
344
365
|
* @zh 发送消息到 LangGraph 后端。
|
|
345
366
|
* @en Sends a message to the LangGraph backend.
|
|
346
367
|
*/
|
|
347
|
-
async sendMessage(input: string | Message[], { joinRunId, extraParams, _debug, command }: SendMessageOptions = {}) {
|
|
368
|
+
async sendMessage(input: string | Message[], { joinRunId, extraParams, _debug, command, metadata }: SendMessageOptions = {}) {
|
|
348
369
|
if (!this.currentAssistant) {
|
|
349
370
|
throw new Error("Thread or Assistant not initialized");
|
|
350
371
|
}
|
|
351
372
|
if (!this.currentThread) {
|
|
352
|
-
await this.createThread({
|
|
373
|
+
await this.createThread({
|
|
374
|
+
graphId: this.currentAssistant!.graph_id!,
|
|
375
|
+
metadata,
|
|
376
|
+
});
|
|
353
377
|
this.emit("thread", {
|
|
354
378
|
event: "thread/create",
|
|
355
379
|
data: {
|
package/src/TestKit.ts
CHANGED
|
@@ -292,7 +292,7 @@ export class TestLangGraphChat {
|
|
|
292
292
|
* const lastHuman = testChat.findLast("human");
|
|
293
293
|
* ```
|
|
294
294
|
*/
|
|
295
|
-
findLast(type: "human" | "ai" | "tool", options: { before?: (item: RenderMessage) => boolean } = {}) {
|
|
295
|
+
findLast(type: "human" | "ai" | "tool", options: { before?: (item: RenderMessage) => boolean } = {}): RenderMessage {
|
|
296
296
|
const messages = this.getMessages();
|
|
297
297
|
|
|
298
298
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -61,6 +61,21 @@ interface ChatStoreContext {
|
|
|
61
61
|
autoRestoreLastSession?: boolean;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// 分页状态类型
|
|
65
|
+
export interface HistoryPagination {
|
|
66
|
+
page: number;
|
|
67
|
+
pageSize: number;
|
|
68
|
+
total: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 历史记录筛选类型
|
|
72
|
+
export interface HistoryFilter {
|
|
73
|
+
metadata: Record<string, any> | null;
|
|
74
|
+
status: "idle" | "busy" | "interrupted" | "error" | null;
|
|
75
|
+
sortBy: "thread_id" | "status" | "created_at" | "updated_at";
|
|
76
|
+
sortOrder: "asc" | "desc";
|
|
77
|
+
}
|
|
78
|
+
|
|
64
79
|
// ============ Store 创建函数 ============
|
|
65
80
|
|
|
66
81
|
export const createChatStore = (initClientName: string, config: Partial<LangGraphClientConfig>, context: ChatStoreContext = {}) => {
|
|
@@ -91,6 +106,21 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
91
106
|
const showGraph = atom<boolean>(context.showGraph ?? false);
|
|
92
107
|
const graphVisualize = atom<AssistantGraph | null>(null);
|
|
93
108
|
|
|
109
|
+
// 分页状态
|
|
110
|
+
const historyPagination = atom<HistoryPagination>({
|
|
111
|
+
page: 1,
|
|
112
|
+
pageSize: 10,
|
|
113
|
+
total: 0,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// 历史记录筛选状态
|
|
117
|
+
const historyFilter = atom<HistoryFilter>({
|
|
118
|
+
metadata: null,
|
|
119
|
+
status: null,
|
|
120
|
+
sortBy: "updated_at",
|
|
121
|
+
sortOrder: "desc",
|
|
122
|
+
});
|
|
123
|
+
|
|
94
124
|
// ============ 内部状态 ============
|
|
95
125
|
|
|
96
126
|
let cleanupCurrentClient: (() => void) | null = null;
|
|
@@ -145,8 +175,6 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
145
175
|
await historyManager.init(currentAgent.get(), { fallbackToAvailableAssistants: context.fallbackToAvailableAssistants });
|
|
146
176
|
history.set(historyManager);
|
|
147
177
|
|
|
148
|
-
// 同步远程会话列表
|
|
149
|
-
|
|
150
178
|
// 根据配置决定初始化行为
|
|
151
179
|
if (context.autoRestoreLastSession) {
|
|
152
180
|
await refreshSessionList();
|
|
@@ -170,9 +198,47 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
170
198
|
if (!historyManager) return;
|
|
171
199
|
|
|
172
200
|
try {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
201
|
+
const pagination = historyPagination.get();
|
|
202
|
+
const filter = historyFilter.get();
|
|
203
|
+
|
|
204
|
+
// 计算偏移量
|
|
205
|
+
const offset = (pagination.page - 1) * pagination.pageSize;
|
|
206
|
+
|
|
207
|
+
// 使用 listRemoteSessions 支持筛选
|
|
208
|
+
const threads = await historyManager.listRemoteSessions({
|
|
209
|
+
limit: pagination.pageSize,
|
|
210
|
+
offset,
|
|
211
|
+
metadata: filter.metadata || undefined,
|
|
212
|
+
status: filter.status || undefined,
|
|
213
|
+
sortBy: filter.sortBy,
|
|
214
|
+
sortOrder: filter.sortOrder,
|
|
215
|
+
withoutDetails: true,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// 注意:后端可能不返回总数,这里需要根据返回的记录数判断是否有下一页
|
|
219
|
+
// 如果返回的记录数小于 pageSize,说明没有更多数据了
|
|
220
|
+
const hasMore = threads.length === pagination.pageSize;
|
|
221
|
+
const estimatedTotal = (pagination.page - 1) * pagination.pageSize + threads.length;
|
|
222
|
+
|
|
223
|
+
sessions.set(
|
|
224
|
+
threads.map(
|
|
225
|
+
(thread) =>
|
|
226
|
+
({
|
|
227
|
+
sessionId: thread.thread_id,
|
|
228
|
+
thread,
|
|
229
|
+
agentName: currentAgent.get(),
|
|
230
|
+
metadata: thread.metadata as Record<string, any> | undefined,
|
|
231
|
+
}) as SessionInfo
|
|
232
|
+
)
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
historyList.set(threads as Thread<{ messages: Message[] }>[]);
|
|
236
|
+
|
|
237
|
+
// 更新分页状态(注意:这里只是估计值,实际总数可能需要从后端获取)
|
|
238
|
+
historyPagination.set({
|
|
239
|
+
...pagination,
|
|
240
|
+
total: hasMore ? pagination.page * pagination.pageSize + 1 : estimatedTotal,
|
|
241
|
+
});
|
|
176
242
|
} catch (error) {
|
|
177
243
|
console.error("Failed to sync sessions:", error);
|
|
178
244
|
}
|
|
@@ -340,7 +406,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
340
406
|
|
|
341
407
|
// ============ 消息和交互逻辑 ============
|
|
342
408
|
|
|
343
|
-
async function sendMessage(message?: Message[],
|
|
409
|
+
async function sendMessage(message?: Message[], options?: SendMessageOptions, withoutCheck = false, isResume = false) {
|
|
344
410
|
const c = client.get();
|
|
345
411
|
if ((!withoutCheck && !userInput.get().trim() && !message?.length) || !c) return;
|
|
346
412
|
|
|
@@ -350,7 +416,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
350
416
|
inChatError.set(null);
|
|
351
417
|
try {
|
|
352
418
|
loading.set(true);
|
|
353
|
-
await c.sendMessage(message || userInput.get(),
|
|
419
|
+
await c.sendMessage(message || userInput.get(), options);
|
|
354
420
|
} catch (e) {
|
|
355
421
|
const isThreadRunning = (e as Error).message.includes("422");
|
|
356
422
|
if (isThreadRunning) {
|
|
@@ -427,6 +493,10 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
427
493
|
showHistory,
|
|
428
494
|
historyList,
|
|
429
495
|
|
|
496
|
+
// 分页和筛选
|
|
497
|
+
historyPagination,
|
|
498
|
+
historyFilter,
|
|
499
|
+
|
|
430
500
|
...artifactHook.data,
|
|
431
501
|
},
|
|
432
502
|
mutations: {
|
|
@@ -490,7 +560,19 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
490
560
|
},
|
|
491
561
|
// 历史记录(兼容旧 API)
|
|
492
562
|
addToHistory,
|
|
493
|
-
createNewChat
|
|
563
|
+
async createNewChat(metadata?: Record<string, any>) {
|
|
564
|
+
const historyManager = history.get();
|
|
565
|
+
if (!historyManager) return;
|
|
566
|
+
|
|
567
|
+
try {
|
|
568
|
+
const session = await historyManager.createSession({ metadata });
|
|
569
|
+
await refreshSessionList();
|
|
570
|
+
await activateSession(session.sessionId);
|
|
571
|
+
} catch (error) {
|
|
572
|
+
console.error("Failed to create new chat:", error);
|
|
573
|
+
inChatError.set((error as Error).message);
|
|
574
|
+
}
|
|
575
|
+
},
|
|
494
576
|
toHistoryChat: (thread: Thread<{ messages: Message[] }>) => activateSession(thread.thread_id, true),
|
|
495
577
|
async deleteHistoryChat(thread: Thread<{ messages: Message[] }>) {
|
|
496
578
|
const historyManager = history.get();
|
|
@@ -500,6 +582,47 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
500
582
|
}
|
|
501
583
|
},
|
|
502
584
|
|
|
585
|
+
// 分页和筛选操作
|
|
586
|
+
setHistoryPage(page: number) {
|
|
587
|
+
historyPagination.set({
|
|
588
|
+
...historyPagination.get(),
|
|
589
|
+
page,
|
|
590
|
+
});
|
|
591
|
+
refreshSessionList();
|
|
592
|
+
},
|
|
593
|
+
setHistoryPageSize(pageSize: number) {
|
|
594
|
+
historyPagination.set({
|
|
595
|
+
...historyPagination.get(),
|
|
596
|
+
pageSize,
|
|
597
|
+
page: 1, // 重置到第一页
|
|
598
|
+
});
|
|
599
|
+
refreshSessionList();
|
|
600
|
+
},
|
|
601
|
+
setHistoryFilter(filter: Partial<HistoryFilter>) {
|
|
602
|
+
historyFilter.set({
|
|
603
|
+
...historyFilter.get(),
|
|
604
|
+
...filter,
|
|
605
|
+
});
|
|
606
|
+
historyPagination.set({
|
|
607
|
+
...historyPagination.get(),
|
|
608
|
+
page: 1, // 筛选变更时重置到第一页
|
|
609
|
+
});
|
|
610
|
+
refreshSessionList();
|
|
611
|
+
},
|
|
612
|
+
resetHistoryFilter() {
|
|
613
|
+
historyFilter.set({
|
|
614
|
+
metadata: null,
|
|
615
|
+
status: null,
|
|
616
|
+
sortBy: "updated_at",
|
|
617
|
+
sortOrder: "desc",
|
|
618
|
+
});
|
|
619
|
+
historyPagination.set({
|
|
620
|
+
...historyPagination.get(),
|
|
621
|
+
page: 1,
|
|
622
|
+
});
|
|
623
|
+
refreshSessionList();
|
|
624
|
+
},
|
|
625
|
+
|
|
503
626
|
...artifactHook.mutation,
|
|
504
627
|
},
|
|
505
628
|
};
|