@langgraph-js/sdk 4.3.0 → 4.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LangGraphClient.d.ts +3 -7
- package/dist/LangGraphClient.js +1 -0
- package/dist/MessageProcessor.d.ts +2 -0
- package/dist/MessageProcessor.js +8 -2
- package/dist/TestKit.d.ts +6 -9
- package/dist/ui-store/createChatStore.d.ts +1 -0
- package/dist/ui-store/createChatStore.js +11 -0
- package/package.json +1 -1
- package/src/LangGraphClient.ts +5 -3
- package/src/MessageProcessor.ts +9 -4
- package/src/artifacts/README.md +71 -0
- package/src/ui-store/createChatStore.ts +11 -0
|
@@ -13,6 +13,8 @@ export type RenderMessage = Message & {
|
|
|
13
13
|
/** 工具入参 ,聚合而来*/
|
|
14
14
|
tool_input?: string;
|
|
15
15
|
additional_kwargs?: {
|
|
16
|
+
create_time: string;
|
|
17
|
+
update_time: string;
|
|
16
18
|
done?: boolean;
|
|
17
19
|
tool_calls?: {
|
|
18
20
|
function: {
|
|
@@ -26,9 +28,6 @@ export type RenderMessage = Message & {
|
|
|
26
28
|
output_tokens: number;
|
|
27
29
|
};
|
|
28
30
|
tool_call_id?: string;
|
|
29
|
-
response_metadata?: {
|
|
30
|
-
create_time: string;
|
|
31
|
-
};
|
|
32
31
|
sub_messages?: RenderMessage[];
|
|
33
32
|
/** 耗时 */
|
|
34
33
|
spend_time?: number;
|
|
@@ -136,10 +135,7 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
136
135
|
/** 代理 assistants 属性到内部 client */
|
|
137
136
|
get assistants(): {
|
|
138
137
|
search(query?: {
|
|
139
|
-
graphId
|
|
140
|
-
* The maximum number of retries that can be made for a single call,
|
|
141
|
-
* with an exponential backoff between each attempt. Defaults to 6.
|
|
142
|
-
*/: string;
|
|
138
|
+
graphId?: string;
|
|
143
139
|
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
144
140
|
limit?: number;
|
|
145
141
|
offset?: number;
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -341,6 +341,7 @@ export class LangGraphClient extends EventEmitter {
|
|
|
341
341
|
else if (chunk.event === "messages/partial" || chunk.event === "messages/complete") {
|
|
342
342
|
for (const message of chunk.data) {
|
|
343
343
|
this.messageProcessor.updateStreamingMessage(message);
|
|
344
|
+
this.messageProcessor.spendTime.setSpendTime(message.id);
|
|
344
345
|
}
|
|
345
346
|
this.emit("message", chunk);
|
|
346
347
|
return true;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Message, AIMessage, ToolMessage } from "@langchain/langgraph-sdk";
|
|
2
2
|
import { RenderMessage } from "./LangGraphClient.js";
|
|
3
|
+
import { SpendTime } from "./SpendTime.js";
|
|
3
4
|
/**
|
|
4
5
|
* @zh StreamingMessageType 类用于判断消息的类型。
|
|
5
6
|
* @en The StreamingMessageType class is used to determine the type of a message.
|
|
@@ -17,6 +18,7 @@ export declare class MessageProcessor {
|
|
|
17
18
|
private streamingMessage;
|
|
18
19
|
/** 图发过来的更新信息 */
|
|
19
20
|
private graphMessages;
|
|
21
|
+
spendTime: SpendTime;
|
|
20
22
|
constructor();
|
|
21
23
|
/**
|
|
22
24
|
* @zh 获取流式消息
|
package/dist/MessageProcessor.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SpendTime } from "./SpendTime.js";
|
|
2
|
+
import { formatFullTime } from "./ui-store/createChatStore.js";
|
|
1
3
|
/**
|
|
2
4
|
* @zh StreamingMessageType 类用于判断消息的类型。
|
|
3
5
|
* @en The StreamingMessageType class is used to determine the type of a message.
|
|
@@ -20,6 +22,7 @@ export class MessageProcessor {
|
|
|
20
22
|
streamingMessage = [];
|
|
21
23
|
/** 图发过来的更新信息 */
|
|
22
24
|
graphMessages = [];
|
|
25
|
+
spendTime = new SpendTime();
|
|
23
26
|
constructor() { }
|
|
24
27
|
/**
|
|
25
28
|
* @zh 获取流式消息
|
|
@@ -101,10 +104,13 @@ export class MessageProcessor {
|
|
|
101
104
|
let lastMessage = null;
|
|
102
105
|
const result = [...messages]; // 创建副本避免修改原数组
|
|
103
106
|
for (const message of result) {
|
|
104
|
-
const createTime = message.
|
|
107
|
+
const createTime = message.additional_kwargs?.create_time || formatFullTime(this.spendTime.getStartTime(message.id));
|
|
108
|
+
const updateTime = message.additional_kwargs?.update_time || formatFullTime(this.spendTime.getEndTime(message.id));
|
|
109
|
+
message.additional_kwargs.create_time = createTime;
|
|
110
|
+
message.additional_kwargs.update_time = updateTime;
|
|
105
111
|
// 工具必须要使用 tool_call_id 来保证一致性
|
|
106
112
|
message.unique_id = message.tool_call_id || message.id;
|
|
107
|
-
message.spend_time = new Date(
|
|
113
|
+
message.spend_time = new Date(updateTime).getTime() - new Date(createTime).getTime();
|
|
108
114
|
if (!message.usage_metadata && message.response_metadata?.usage) {
|
|
109
115
|
const usage = message.response_metadata.usage;
|
|
110
116
|
message.usage_metadata = {
|
package/dist/TestKit.d.ts
CHANGED
|
@@ -171,6 +171,8 @@ export declare class TestLangGraphChat {
|
|
|
171
171
|
node_name?: string;
|
|
172
172
|
tool_input?: string;
|
|
173
173
|
additional_kwargs?: {
|
|
174
|
+
create_time: string;
|
|
175
|
+
update_time: string;
|
|
174
176
|
done?: boolean;
|
|
175
177
|
tool_calls?: {
|
|
176
178
|
function: {
|
|
@@ -184,9 +186,6 @@ export declare class TestLangGraphChat {
|
|
|
184
186
|
output_tokens: number;
|
|
185
187
|
};
|
|
186
188
|
tool_call_id?: string;
|
|
187
|
-
response_metadata?: {
|
|
188
|
-
create_time: string;
|
|
189
|
-
};
|
|
190
189
|
sub_messages?: RenderMessage[];
|
|
191
190
|
spend_time?: number;
|
|
192
191
|
unique_id?: string;
|
|
@@ -245,6 +244,8 @@ export declare class TestLangGraphChat {
|
|
|
245
244
|
node_name?: string;
|
|
246
245
|
tool_input?: string;
|
|
247
246
|
additional_kwargs?: {
|
|
247
|
+
create_time: string;
|
|
248
|
+
update_time: string;
|
|
248
249
|
done?: boolean;
|
|
249
250
|
tool_calls?: {
|
|
250
251
|
function: {
|
|
@@ -258,9 +259,6 @@ export declare class TestLangGraphChat {
|
|
|
258
259
|
output_tokens: number;
|
|
259
260
|
};
|
|
260
261
|
tool_call_id?: string;
|
|
261
|
-
response_metadata?: {
|
|
262
|
-
create_time: string;
|
|
263
|
-
};
|
|
264
262
|
sub_messages?: RenderMessage[];
|
|
265
263
|
spend_time?: number;
|
|
266
264
|
unique_id?: string;
|
|
@@ -292,6 +290,8 @@ export declare class TestLangGraphChat {
|
|
|
292
290
|
node_name?: string;
|
|
293
291
|
tool_input?: string;
|
|
294
292
|
additional_kwargs?: {
|
|
293
|
+
create_time: string;
|
|
294
|
+
update_time: string;
|
|
295
295
|
done?: boolean;
|
|
296
296
|
tool_calls?: {
|
|
297
297
|
function: {
|
|
@@ -305,9 +305,6 @@ export declare class TestLangGraphChat {
|
|
|
305
305
|
output_tokens: number;
|
|
306
306
|
};
|
|
307
307
|
tool_call_id?: string;
|
|
308
|
-
response_metadata?: {
|
|
309
|
-
create_time: string;
|
|
310
|
-
};
|
|
311
308
|
sub_messages?: RenderMessage[];
|
|
312
309
|
spend_time?: number;
|
|
313
310
|
unique_id?: string;
|
|
@@ -5,6 +5,7 @@ import { RevertChatToOptions } from "../time-travel/index.js";
|
|
|
5
5
|
import { History, SessionInfo } from "../History.js";
|
|
6
6
|
import { InterruptData } from "../humanInTheLoop.js";
|
|
7
7
|
export declare const formatTime: (date: Date) => string;
|
|
8
|
+
export declare const formatFullTime: (date: Date) => string;
|
|
8
9
|
export declare const formatTokens: (tokens: number) => string;
|
|
9
10
|
export declare const getMessageContent: (content: any) => string;
|
|
10
11
|
export declare const getHistoryContent: (thread: Thread) => string | any[];
|
|
@@ -6,6 +6,16 @@ import { useArtifacts } from "../artifacts/index.js";
|
|
|
6
6
|
import { History } from "../History.js";
|
|
7
7
|
// ============ 工具函数 ============
|
|
8
8
|
export const formatTime = (date) => date.toLocaleTimeString();
|
|
9
|
+
export const formatFullTime = (date) => {
|
|
10
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
11
|
+
const yyyy = date.getFullYear();
|
|
12
|
+
const mm = pad(date.getMonth() + 1);
|
|
13
|
+
const dd = pad(date.getDate());
|
|
14
|
+
const hh = pad(date.getHours());
|
|
15
|
+
const mi = pad(date.getMinutes());
|
|
16
|
+
const ss = pad(date.getSeconds());
|
|
17
|
+
return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`;
|
|
18
|
+
};
|
|
9
19
|
export const formatTokens = (tokens) => tokens.toLocaleString("en");
|
|
10
20
|
export const getMessageContent = (content) => {
|
|
11
21
|
if (typeof content === "string")
|
|
@@ -277,6 +287,7 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
277
287
|
return;
|
|
278
288
|
inChatError.set(null);
|
|
279
289
|
try {
|
|
290
|
+
loading.set(true);
|
|
280
291
|
await c.sendMessage(message || userInput.get(), extraData);
|
|
281
292
|
}
|
|
282
293
|
catch (e) {
|
package/package.json
CHANGED
package/src/LangGraphClient.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Thread, Message, Assistant, HumanMessage, AIMessage, ToolMessage,
|
|
|
2
2
|
import { EventEmitter } from "eventemitter3";
|
|
3
3
|
import { ToolManager } from "./ToolManager.js";
|
|
4
4
|
import { CallToolResult } from "./tool/createTool.js";
|
|
5
|
+
import { SpendTime } from "./SpendTime.js";
|
|
5
6
|
import { createActionRequestID, HumanInTheLoopDecision, HumanInTheLoopState, InterruptData } from "./humanInTheLoop.js";
|
|
6
7
|
import { type ILangGraphClient } from "@langgraph-js/pure-graph/dist/types.js";
|
|
7
8
|
import { MessageProcessor } from "./MessageProcessor.js";
|
|
@@ -16,6 +17,8 @@ export type RenderMessage = Message & {
|
|
|
16
17
|
/** 工具入参 ,聚合而来*/
|
|
17
18
|
tool_input?: string;
|
|
18
19
|
additional_kwargs?: {
|
|
20
|
+
create_time: string;
|
|
21
|
+
update_time: string;
|
|
19
22
|
done?: boolean;
|
|
20
23
|
tool_calls?: {
|
|
21
24
|
function: {
|
|
@@ -29,9 +32,6 @@ export type RenderMessage = Message & {
|
|
|
29
32
|
output_tokens: number;
|
|
30
33
|
};
|
|
31
34
|
tool_call_id?: string;
|
|
32
|
-
response_metadata?: {
|
|
33
|
-
create_time: string;
|
|
34
|
-
};
|
|
35
35
|
// 子消息
|
|
36
36
|
sub_messages?: RenderMessage[];
|
|
37
37
|
/** 耗时 */
|
|
@@ -105,6 +105,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
105
105
|
private currentAssistant: Assistant | null = null;
|
|
106
106
|
private currentThread: Thread<TStateType> | null = null;
|
|
107
107
|
tools: ToolManager = new ToolManager();
|
|
108
|
+
|
|
108
109
|
availableAssistants: Assistant[] = [];
|
|
109
110
|
graphState: any = {};
|
|
110
111
|
currentRun?: { run_id: string };
|
|
@@ -459,6 +460,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
459
460
|
} else if (chunk.event === "messages/partial" || chunk.event === "messages/complete") {
|
|
460
461
|
for (const message of chunk.data) {
|
|
461
462
|
this.messageProcessor.updateStreamingMessage(message);
|
|
463
|
+
this.messageProcessor.spendTime.setSpendTime(message.id!);
|
|
462
464
|
}
|
|
463
465
|
this.emit("message", chunk);
|
|
464
466
|
return true;
|
package/src/MessageProcessor.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Message, AIMessage, ToolMessage } from "@langchain/langgraph-sdk";
|
|
2
2
|
import { RenderMessage } from "./LangGraphClient.js";
|
|
3
|
+
import { SpendTime } from "./SpendTime.js";
|
|
4
|
+
import { formatFullTime, formatTime } from "./ui-store/createChatStore.js";
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* @zh StreamingMessageType 类用于判断消息的类型。
|
|
@@ -25,7 +27,7 @@ export class MessageProcessor {
|
|
|
25
27
|
private streamingMessage: RenderMessage[] = [];
|
|
26
28
|
/** 图发过来的更新信息 */
|
|
27
29
|
private graphMessages: RenderMessage[] = [];
|
|
28
|
-
|
|
30
|
+
public spendTime = new SpendTime();
|
|
29
31
|
constructor() {}
|
|
30
32
|
|
|
31
33
|
/**
|
|
@@ -117,11 +119,14 @@ export class MessageProcessor {
|
|
|
117
119
|
const result = [...messages]; // 创建副本避免修改原数组
|
|
118
120
|
|
|
119
121
|
for (const message of result) {
|
|
120
|
-
const createTime = message.
|
|
122
|
+
const createTime = message.additional_kwargs?.create_time || formatFullTime(this.spendTime.getStartTime(message.id!));
|
|
123
|
+
const updateTime = message.additional_kwargs?.update_time || formatFullTime(this.spendTime.getEndTime(message.id!));
|
|
124
|
+
message.additional_kwargs!.create_time = createTime;
|
|
125
|
+
message.additional_kwargs!.update_time = updateTime;
|
|
121
126
|
// 工具必须要使用 tool_call_id 来保证一致性
|
|
122
127
|
message.unique_id = message.tool_call_id! || message.id!;
|
|
123
128
|
|
|
124
|
-
message.spend_time = new Date(
|
|
129
|
+
message.spend_time = new Date(updateTime).getTime() - new Date(createTime).getTime();
|
|
125
130
|
if (!message.usage_metadata && (message as AIMessage).response_metadata?.usage) {
|
|
126
131
|
const usage = (message as AIMessage).response_metadata!.usage as {
|
|
127
132
|
prompt_tokens: number;
|
|
@@ -170,7 +175,7 @@ export class MessageProcessor {
|
|
|
170
175
|
...(parentMessage?.additional_kwargs || {}),
|
|
171
176
|
...(message.additional_kwargs || {}),
|
|
172
177
|
done: isDone,
|
|
173
|
-
};
|
|
178
|
+
} as RenderMessage["additional_kwargs"];
|
|
174
179
|
}
|
|
175
180
|
if (parentMessage) {
|
|
176
181
|
message.usage_metadata = parentMessage.usage_metadata;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# ArtifactViewer 实现说明
|
|
2
|
+
|
|
3
|
+
`ArtifactViewer` 组件主要负责与 `langgraph-js` SDK 的状态同步,并集成 `ai-artifacts` Web Component 来展示 AI 生成的内容。
|
|
4
|
+
|
|
5
|
+
## 核心功能
|
|
6
|
+
|
|
7
|
+
1. **状态同步**: 监听 `useChat` hook 中的 `artifacts` 变化。
|
|
8
|
+
2. **沙箱渲染**: 使用 `<ai-artifacts>` Web Component 加载远程渲染引擎。
|
|
9
|
+
3. **交互反馈**: 通过 `eventCenter` 捕获沙箱内的 `sendBackToAI` 事件,支持 Human-in-the-loop 流程。
|
|
10
|
+
|
|
11
|
+
## 核心实现步骤
|
|
12
|
+
|
|
13
|
+
### 1. 同步 Artifacts 状态
|
|
14
|
+
|
|
15
|
+
利用 `useEffect` 监听 SDK 的 `artifacts` 和 `loading` 状态。当数据更新且加载完成后,使用 `setArtifactStore` 将数据推送到 `ai-artifacts` 的全局存储中。
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (loading) return;
|
|
20
|
+
setArtifactStore({
|
|
21
|
+
artifacts: { default: artifacts as ArtifactType[] },
|
|
22
|
+
});
|
|
23
|
+
}, [artifacts, loading]);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. 集成渲染引擎 (Web Component)
|
|
27
|
+
|
|
28
|
+
在 JSX 中使用 `ai-artifacts` 标签。需要提供 `src` (渲染引擎地址)、`store-id` (默认为 `default`) 以及当前选中的 `group-id` 和 `version-id`。
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<ai-artifacts src={artifactsUrl} store-id="default" group-id={currentArtifactId?.[0] || ""} version-id={currentArtifactId?.[1] || ""} className="w-full min-h-[400px]"></ai-artifacts>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. 事件处理 (Human-in-the-loop)
|
|
35
|
+
|
|
36
|
+
监听来自渲染沙箱的 `sendBackToAI` 事件。这通常发生在用户点击“修复”或“修改”按钮时,将相关的错误信息或修改建议传回给 AI。
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const handleSendBackToAI = (data: any) => {
|
|
41
|
+
onSendBackToAI(data);
|
|
42
|
+
};
|
|
43
|
+
eventCenter.on("sendBackToAI", handleSendBackToAI);
|
|
44
|
+
return () => {
|
|
45
|
+
eventCenter.off("sendBackToAI", handleSendBackToAI);
|
|
46
|
+
};
|
|
47
|
+
}, [onSendBackToAI]);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 4. TypeScript 声明
|
|
51
|
+
|
|
52
|
+
为了让 React 识别自定义的 Web Component 标签,需要添加类型声明:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
declare module "react" {
|
|
56
|
+
namespace JSX {
|
|
57
|
+
interface IntrinsicElements {
|
|
58
|
+
"ai-artifacts": React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
|
|
59
|
+
src?: string;
|
|
60
|
+
"store-id"?: string;
|
|
61
|
+
"group-id"?: string;
|
|
62
|
+
"version-id"?: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 配置项
|
|
70
|
+
|
|
71
|
+
- `artifactsUrl`: 渲染沙箱的 URL 地址,建议通过 `localStorage` 或环境变量进行配置,以便灵活切换(例如:`https://langgraph-artifacts.netlify.app/`)。
|
|
@@ -13,6 +13,16 @@ import { InterruptData, InterruptResponse } from "../humanInTheLoop.js";
|
|
|
13
13
|
// ============ 工具函数 ============
|
|
14
14
|
|
|
15
15
|
export const formatTime = (date: Date) => date.toLocaleTimeString();
|
|
16
|
+
export const formatFullTime = (date: Date) => {
|
|
17
|
+
const pad = (n: number) => n.toString().padStart(2, "0");
|
|
18
|
+
const yyyy = date.getFullYear();
|
|
19
|
+
const mm = pad(date.getMonth() + 1);
|
|
20
|
+
const dd = pad(date.getDate());
|
|
21
|
+
const hh = pad(date.getHours());
|
|
22
|
+
const mi = pad(date.getMinutes());
|
|
23
|
+
const ss = pad(date.getSeconds());
|
|
24
|
+
return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`;
|
|
25
|
+
};
|
|
16
26
|
export const formatTokens = (tokens: number) => tokens.toLocaleString("en");
|
|
17
27
|
|
|
18
28
|
export const getMessageContent = (content: any) => {
|
|
@@ -334,6 +344,7 @@ export const createChatStore = (initClientName: string, config: Partial<LangGrap
|
|
|
334
344
|
|
|
335
345
|
inChatError.set(null);
|
|
336
346
|
try {
|
|
347
|
+
loading.set(true);
|
|
337
348
|
await c.sendMessage(message || userInput.get(), extraData);
|
|
338
349
|
} catch (e) {
|
|
339
350
|
const isThreadRunning = (e as Error).message.includes("422");
|