agent-chat-sdk-core 0.1.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.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +492 -0
- package/dist/cjs/client.js +199 -0
- package/dist/cjs/index.js +21 -0
- package/dist/cjs/knowledge-label.js +71 -0
- package/dist/cjs/normalizer.js +257 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/parser.js +294 -0
- package/dist/cjs/react-flow.js +42 -0
- package/dist/cjs/session.js +100 -0
- package/dist/cjs/types.js +2 -0
- package/dist/esm/client.d.ts +45 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +195 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/knowledge-label.d.ts +49 -0
- package/dist/esm/knowledge-label.d.ts.map +1 -0
- package/dist/esm/knowledge-label.js +67 -0
- package/dist/esm/normalizer.d.ts +22 -0
- package/dist/esm/normalizer.d.ts.map +1 -0
- package/dist/esm/normalizer.js +252 -0
- package/dist/esm/parser.d.ts +12 -0
- package/dist/esm/parser.d.ts.map +1 -0
- package/dist/esm/parser.js +289 -0
- package/dist/esm/react-flow.d.ts +40 -0
- package/dist/esm/react-flow.d.ts.map +1 -0
- package/dist/esm/react-flow.js +39 -0
- package/dist/esm/session.d.ts +7 -0
- package/dist/esm/session.d.ts.map +1 -0
- package/dist/esm/session.js +96 -0
- package/dist/esm/types.d.ts +151 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
const STREAM_END_TYPES = new Set(['done', 'end', 'finish', 'completed', 'stop']);
|
|
2
|
+
const TOOL_LIKE_TYPES = new Set([
|
|
3
|
+
'tool',
|
|
4
|
+
'knowledge',
|
|
5
|
+
'plugin',
|
|
6
|
+
'mcp',
|
|
7
|
+
'memory_var_update',
|
|
8
|
+
'workflow',
|
|
9
|
+
]);
|
|
10
|
+
function extractWorkflowResponse(parsed) {
|
|
11
|
+
const response = parsed.response;
|
|
12
|
+
if (response === undefined || response === null)
|
|
13
|
+
return '';
|
|
14
|
+
if (typeof response === 'object' && response !== null) {
|
|
15
|
+
const output = response.output;
|
|
16
|
+
if (output !== undefined && output !== null)
|
|
17
|
+
return String(output);
|
|
18
|
+
return JSON.stringify(response);
|
|
19
|
+
}
|
|
20
|
+
const text = String(response);
|
|
21
|
+
try {
|
|
22
|
+
const json = JSON.parse(text);
|
|
23
|
+
if (json.output !== undefined && json.output !== null)
|
|
24
|
+
return String(json.output);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// response 为纯文本
|
|
28
|
+
}
|
|
29
|
+
return text;
|
|
30
|
+
}
|
|
31
|
+
function asRecord(value) {
|
|
32
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
function stringifyOutputValue(value) {
|
|
38
|
+
if (value === undefined || value === null)
|
|
39
|
+
return '';
|
|
40
|
+
if (typeof value === 'string')
|
|
41
|
+
return value;
|
|
42
|
+
if (typeof value === 'object')
|
|
43
|
+
return JSON.stringify(value, null, 2);
|
|
44
|
+
return String(value);
|
|
45
|
+
}
|
|
46
|
+
/** 从 outputs 对象中提取首选文本字段 */
|
|
47
|
+
function extractOutputsContent(outputs) {
|
|
48
|
+
const preferredKeys = ['output', 'text', 'result', 'answer', 'content'];
|
|
49
|
+
for (const key of preferredKeys) {
|
|
50
|
+
const text = stringifyOutputValue(outputs[key]).trim();
|
|
51
|
+
if (text)
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
const entries = Object.entries(outputs).filter(([, v]) => stringifyOutputValue(v).trim());
|
|
55
|
+
if (entries.length === 0)
|
|
56
|
+
return '';
|
|
57
|
+
return entries.map(([k, v]) => `${k}:\n${stringifyOutputValue(v)}`).join('\n\n');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 工作流直连 Invoke 的 SSE 事件(event: workflow_* / node_* / text_chunk)
|
|
61
|
+
*/
|
|
62
|
+
function extractWorkflowInvokeContent(parsed, eventType) {
|
|
63
|
+
const data = asRecord(parsed.data);
|
|
64
|
+
// 累积型 answer(常见于 message / agent_message)
|
|
65
|
+
if ((eventType === 'message' || eventType === 'agent_message') &&
|
|
66
|
+
parsed.answer !== undefined &&
|
|
67
|
+
parsed.answer !== null) {
|
|
68
|
+
return String(parsed.answer);
|
|
69
|
+
}
|
|
70
|
+
// 流式增量:data.text / delta / chunk
|
|
71
|
+
if (data && eventType !== 'workflow_started' && eventType !== 'workflow_finished') {
|
|
72
|
+
const streamDelta = data.text ?? data.delta ?? data.chunk ?? data.answer;
|
|
73
|
+
if (streamDelta !== undefined && streamDelta !== null) {
|
|
74
|
+
const text = String(streamDelta);
|
|
75
|
+
if (text)
|
|
76
|
+
return text;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (eventType === 'text_chunk' || eventType === 'message' || eventType === 'agent_message') {
|
|
80
|
+
const text = data?.text ?? data?.answer ?? data?.content ?? parsed.text ?? parsed.answer;
|
|
81
|
+
if (text !== undefined && text !== null)
|
|
82
|
+
return String(text);
|
|
83
|
+
}
|
|
84
|
+
if (eventType === 'node_finished' || eventType === 'node_started') {
|
|
85
|
+
const text = data?.text ?? data?.title;
|
|
86
|
+
if (text)
|
|
87
|
+
return String(text);
|
|
88
|
+
}
|
|
89
|
+
if (data?.outputs && eventType !== 'workflow_started') {
|
|
90
|
+
const fromOutputs = extractOutputsContent(asRecord(data.outputs) ?? {});
|
|
91
|
+
if (fromOutputs)
|
|
92
|
+
return fromOutputs;
|
|
93
|
+
}
|
|
94
|
+
if (eventType === 'workflow_finished' && data) {
|
|
95
|
+
const outputs = asRecord(data.outputs);
|
|
96
|
+
if (outputs) {
|
|
97
|
+
const fromOutputs = extractOutputsContent(outputs);
|
|
98
|
+
if (fromOutputs)
|
|
99
|
+
return fromOutputs;
|
|
100
|
+
}
|
|
101
|
+
if (data.error)
|
|
102
|
+
return String(data.error);
|
|
103
|
+
}
|
|
104
|
+
if (eventType === 'workflow_failed' && data?.error) {
|
|
105
|
+
return String(data.error);
|
|
106
|
+
}
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
function isWorkflowInvokeEvent(type) {
|
|
110
|
+
return (type.startsWith('workflow_') ||
|
|
111
|
+
type.startsWith('node_') ||
|
|
112
|
+
type === 'text_chunk' ||
|
|
113
|
+
type === 'message' ||
|
|
114
|
+
type === 'agent_message' ||
|
|
115
|
+
type === 'agent_thought' ||
|
|
116
|
+
type === 'llm_chunk' ||
|
|
117
|
+
type === 'generation' ||
|
|
118
|
+
type.includes('_chunk') ||
|
|
119
|
+
type.includes('_delta'));
|
|
120
|
+
}
|
|
121
|
+
/** 预审工作流流式输出:event=answer 且 text 在 data.text */
|
|
122
|
+
function isWorkflowStreamAnswer(parsed, type) {
|
|
123
|
+
return type === 'answer' && typeof parsed.workflow_run_id === 'string';
|
|
124
|
+
}
|
|
125
|
+
function extractChunkContent(parsed, type) {
|
|
126
|
+
if (type === 'workflow') {
|
|
127
|
+
const fromResponse = extractWorkflowResponse(parsed);
|
|
128
|
+
if (fromResponse)
|
|
129
|
+
return fromResponse;
|
|
130
|
+
const direct = parsed.content ?? parsed.text ?? parsed.delta;
|
|
131
|
+
if (direct !== undefined && direct !== null && String(direct) !== '') {
|
|
132
|
+
return String(direct);
|
|
133
|
+
}
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
if (type === 'memory_var_update') {
|
|
137
|
+
const content = parsed.content ?? parsed.text ?? parsed.delta;
|
|
138
|
+
if (content !== undefined && content !== null && String(content) !== '') {
|
|
139
|
+
return String(content);
|
|
140
|
+
}
|
|
141
|
+
if (parsed.description !== undefined && parsed.description !== null) {
|
|
142
|
+
return String(parsed.description);
|
|
143
|
+
}
|
|
144
|
+
return '';
|
|
145
|
+
}
|
|
146
|
+
const direct = parsed.content ?? parsed.text ?? parsed.delta;
|
|
147
|
+
if (direct !== undefined && direct !== null && String(direct) !== '') {
|
|
148
|
+
return String(direct);
|
|
149
|
+
}
|
|
150
|
+
if (TOOL_LIKE_TYPES.has(type)) {
|
|
151
|
+
if (parsed.response !== undefined && parsed.response !== null) {
|
|
152
|
+
return String(parsed.response);
|
|
153
|
+
}
|
|
154
|
+
if (parsed.arg !== undefined && parsed.arg !== null) {
|
|
155
|
+
return String(parsed.arg);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
export function isStreamEndSignal(type, dataStr) {
|
|
161
|
+
return dataStr === '[DONE]' || STREAM_END_TYPES.has(type);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 解析单行 SSE 文本
|
|
165
|
+
* @returns 原始分片 | 'end' 流结束 | null 跳过
|
|
166
|
+
*/
|
|
167
|
+
export function parseSSELine(line) {
|
|
168
|
+
const trimmed = line.trim();
|
|
169
|
+
if (!trimmed || trimmed.startsWith(':'))
|
|
170
|
+
return null;
|
|
171
|
+
if (trimmed.startsWith('event:')) {
|
|
172
|
+
const eventName = trimmed.slice(6).trim();
|
|
173
|
+
if (STREAM_END_TYPES.has(eventName))
|
|
174
|
+
return 'end';
|
|
175
|
+
if (eventName === 'error') {
|
|
176
|
+
return { type: 'error', content: '执行出错,请稍后重试' };
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const dataStr = trimmed.startsWith('data: ') ? trimmed.slice(6).trim() : trimmed;
|
|
181
|
+
if (!dataStr)
|
|
182
|
+
return null;
|
|
183
|
+
if (isStreamEndSignal('', dataStr))
|
|
184
|
+
return 'end';
|
|
185
|
+
try {
|
|
186
|
+
const parsed = JSON.parse(dataStr);
|
|
187
|
+
const type = String(parsed.type ?? parsed.event ?? 'answer');
|
|
188
|
+
if (isStreamEndSignal(type, ''))
|
|
189
|
+
return 'end';
|
|
190
|
+
if (isWorkflowStreamAnswer(parsed, type)) {
|
|
191
|
+
const data = asRecord(parsed.data);
|
|
192
|
+
const text = data?.text;
|
|
193
|
+
if (text === undefined || text === null)
|
|
194
|
+
return null;
|
|
195
|
+
return {
|
|
196
|
+
type: 'workflow_answer',
|
|
197
|
+
content: String(text),
|
|
198
|
+
raw: parsed,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (isWorkflowInvokeEvent(type)) {
|
|
202
|
+
if (type === 'workflow_failed') {
|
|
203
|
+
const errMsg = extractWorkflowInvokeContent(parsed, type) ||
|
|
204
|
+
String(asRecord(parsed.data)?.error ?? '工作流执行失败');
|
|
205
|
+
return {
|
|
206
|
+
type: 'error',
|
|
207
|
+
content: errMsg,
|
|
208
|
+
error: errMsg,
|
|
209
|
+
raw: parsed,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const content = extractWorkflowInvokeContent(parsed, type);
|
|
213
|
+
if (type === 'workflow_started' || type === 'workflow_finished' || content) {
|
|
214
|
+
return { type, content, raw: parsed };
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
if (type === 'error') {
|
|
219
|
+
return {
|
|
220
|
+
type: 'error',
|
|
221
|
+
content: String(parsed.error ?? parsed.message ?? '执行出错,请稍后重试'),
|
|
222
|
+
error: parsed.error,
|
|
223
|
+
error_detail: (parsed.error_detail ?? parsed.errorDetail),
|
|
224
|
+
raw: parsed,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const chunk = {
|
|
228
|
+
type,
|
|
229
|
+
content: extractChunkContent(parsed, type),
|
|
230
|
+
role: parsed.role,
|
|
231
|
+
running_time: parsed.running_time,
|
|
232
|
+
raw: parsed,
|
|
233
|
+
};
|
|
234
|
+
if (chunk.content ||
|
|
235
|
+
chunk.type === 'thinking' ||
|
|
236
|
+
TOOL_LIKE_TYPES.has(chunk.type) ||
|
|
237
|
+
(chunk.type === 'workflow' && chunk.running_time)) {
|
|
238
|
+
return chunk;
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return dataStr ? { type: 'answer', content: dataStr } : null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 从 ReadableStream 读取并解析 SSE,逐条回调
|
|
248
|
+
*/
|
|
249
|
+
export async function readSSEStream(body, onChunk, signal) {
|
|
250
|
+
const reader = body.getReader();
|
|
251
|
+
const decoder = new TextDecoder('utf-8');
|
|
252
|
+
let buffer = '';
|
|
253
|
+
try {
|
|
254
|
+
streamLoop: while (true) {
|
|
255
|
+
if (signal?.aborted) {
|
|
256
|
+
await reader.cancel();
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
const { done, value } = await reader.read();
|
|
260
|
+
if (done)
|
|
261
|
+
break;
|
|
262
|
+
buffer += decoder.decode(value, { stream: true });
|
|
263
|
+
const lines = buffer.split('\n');
|
|
264
|
+
buffer = lines.pop() || '';
|
|
265
|
+
for (const line of lines) {
|
|
266
|
+
const parsed = parseSSELine(line);
|
|
267
|
+
if (parsed === 'end') {
|
|
268
|
+
try {
|
|
269
|
+
await reader.cancel();
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// 连接可能已由服务端关闭
|
|
273
|
+
}
|
|
274
|
+
break streamLoop;
|
|
275
|
+
}
|
|
276
|
+
if (parsed)
|
|
277
|
+
onChunk(parsed);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (buffer.trim()) {
|
|
281
|
+
const parsed = parseSSELine(buffer);
|
|
282
|
+
if (parsed && parsed !== 'end')
|
|
283
|
+
onChunk(parsed);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
reader.releaseLock();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReAct 智能体流式交互时序说明
|
|
3
|
+
*
|
|
4
|
+
* ┌─────────────┐
|
|
5
|
+
* │ 用户点击发送 │
|
|
6
|
+
* └──────┬──────┘
|
|
7
|
+
* ▼
|
|
8
|
+
* ┌─────────────────────┐ SSE POST
|
|
9
|
+
* │ 展示回复气泡 + Loading │ ◄──────────── 接口
|
|
10
|
+
* └──────┬──────────────┘
|
|
11
|
+
* ▼ 首个 SSE 字段
|
|
12
|
+
* ┌──────────────────────────────────────────────────┐
|
|
13
|
+
* │ ReAct 循环(可多轮) │
|
|
14
|
+
* │ ① thinking_start │
|
|
15
|
+
* │ ② thinking_delta* → UI: 「深度思考中...」(不展示内容)│
|
|
16
|
+
* │ ③ thinking_end → UI: 「深度思考成功,用时 Xs」 │
|
|
17
|
+
* │ ④ tool_call_start → UI: 「工具/知识库调用中...」 │
|
|
18
|
+
* │ ⑤ tool_call_end → UI: 「XX成功,用时 Xs」 │
|
|
19
|
+
* │ └── 可能回到 ① 继续思考 │
|
|
20
|
+
* └──────────────────────┬───────────────────────────┘
|
|
21
|
+
* ▼
|
|
22
|
+
* answer_delta* → 流式输出最终回复
|
|
23
|
+
* ▼
|
|
24
|
+
* stream_end
|
|
25
|
+
*
|
|
26
|
+
* 对应 SSE type 字段:
|
|
27
|
+
* - thinking / tool / knowledge / plugin / mcp / memory_var_update / answer / error / done
|
|
28
|
+
*/
|
|
29
|
+
export declare const REACT_SSE_TYPE_MAP: {
|
|
30
|
+
readonly thinking: "思考阶段";
|
|
31
|
+
readonly tool: "工具调用";
|
|
32
|
+
readonly knowledge: "知识库调用";
|
|
33
|
+
readonly plugin: "插件调用";
|
|
34
|
+
readonly mcp: "MCP 调用";
|
|
35
|
+
readonly memory_var_update: "记忆变量更新";
|
|
36
|
+
readonly workflow: "工作流调用";
|
|
37
|
+
readonly answer: "最终回答";
|
|
38
|
+
readonly error: "错误";
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=react-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-flow.d.ts","sourceRoot":"","sources":["../../src/react-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;CAUrB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReAct 智能体流式交互时序说明
|
|
3
|
+
*
|
|
4
|
+
* ┌─────────────┐
|
|
5
|
+
* │ 用户点击发送 │
|
|
6
|
+
* └──────┬──────┘
|
|
7
|
+
* ▼
|
|
8
|
+
* ┌─────────────────────┐ SSE POST
|
|
9
|
+
* │ 展示回复气泡 + Loading │ ◄──────────── 接口
|
|
10
|
+
* └──────┬──────────────┘
|
|
11
|
+
* ▼ 首个 SSE 字段
|
|
12
|
+
* ┌──────────────────────────────────────────────────┐
|
|
13
|
+
* │ ReAct 循环(可多轮) │
|
|
14
|
+
* │ ① thinking_start │
|
|
15
|
+
* │ ② thinking_delta* → UI: 「深度思考中...」(不展示内容)│
|
|
16
|
+
* │ ③ thinking_end → UI: 「深度思考成功,用时 Xs」 │
|
|
17
|
+
* │ ④ tool_call_start → UI: 「工具/知识库调用中...」 │
|
|
18
|
+
* │ ⑤ tool_call_end → UI: 「XX成功,用时 Xs」 │
|
|
19
|
+
* │ └── 可能回到 ① 继续思考 │
|
|
20
|
+
* └──────────────────────┬───────────────────────────┘
|
|
21
|
+
* ▼
|
|
22
|
+
* answer_delta* → 流式输出最终回复
|
|
23
|
+
* ▼
|
|
24
|
+
* stream_end
|
|
25
|
+
*
|
|
26
|
+
* 对应 SSE type 字段:
|
|
27
|
+
* - thinking / tool / knowledge / plugin / mcp / memory_var_update / answer / error / done
|
|
28
|
+
*/
|
|
29
|
+
export const REACT_SSE_TYPE_MAP = {
|
|
30
|
+
thinking: '思考阶段',
|
|
31
|
+
tool: '工具调用',
|
|
32
|
+
knowledge: '知识库调用',
|
|
33
|
+
plugin: '插件调用',
|
|
34
|
+
mcp: 'MCP 调用',
|
|
35
|
+
memory_var_update: '记忆变量更新',
|
|
36
|
+
workflow: '工作流调用',
|
|
37
|
+
answer: '最终回答',
|
|
38
|
+
error: '错误',
|
|
39
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AgentChatSessionState, AgentStreamEvent } from './types.js';
|
|
2
|
+
export declare function createSessionState(query: string): AgentChatSessionState;
|
|
3
|
+
/**
|
|
4
|
+
* 根据标准化事件更新会话聚合状态(ReAct 多轮)
|
|
5
|
+
*/
|
|
6
|
+
export declare function applyEventToSession(state: AgentChatSessionState, event: AgentStreamEvent): AgentChatSessionState;
|
|
7
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE3F,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB,CASvE;AAuBD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,qBAAqB,EAC5B,KAAK,EAAE,gBAAgB,GACtB,qBAAqB,CAoEvB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export function createSessionState(query) {
|
|
2
|
+
return {
|
|
3
|
+
status: 'streaming',
|
|
4
|
+
query,
|
|
5
|
+
thinkingContent: '',
|
|
6
|
+
isThinking: false,
|
|
7
|
+
answerContent: '',
|
|
8
|
+
processes: [],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
let processIdSeq = 0;
|
|
12
|
+
function nextProcessId() {
|
|
13
|
+
processIdSeq += 1;
|
|
14
|
+
return `proc_${processIdSeq}_${Date.now()}`;
|
|
15
|
+
}
|
|
16
|
+
function upsertProcess(processes, id, item) {
|
|
17
|
+
const index = processes.findIndex((p) => p.id === id);
|
|
18
|
+
if (index >= 0) {
|
|
19
|
+
const next = [...processes];
|
|
20
|
+
next[index] = { ...next[index], ...item };
|
|
21
|
+
return next;
|
|
22
|
+
}
|
|
23
|
+
return [...processes, item];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 根据标准化事件更新会话聚合状态(ReAct 多轮)
|
|
27
|
+
*/
|
|
28
|
+
export function applyEventToSession(state, event) {
|
|
29
|
+
switch (event.type) {
|
|
30
|
+
case 'stream_start':
|
|
31
|
+
return { ...state, status: 'streaming', query: event.query };
|
|
32
|
+
case 'thinking_start':
|
|
33
|
+
return { ...state, isThinking: true, thinkingContent: '' };
|
|
34
|
+
case 'thinking_delta':
|
|
35
|
+
return { ...state, isThinking: true, thinkingContent: event.content };
|
|
36
|
+
case 'thinking_end':
|
|
37
|
+
return {
|
|
38
|
+
...state,
|
|
39
|
+
isThinking: false,
|
|
40
|
+
thinkingContent: event.content,
|
|
41
|
+
processes: event.content
|
|
42
|
+
? [
|
|
43
|
+
...state.processes,
|
|
44
|
+
{
|
|
45
|
+
id: nextProcessId(),
|
|
46
|
+
type: 'thinking',
|
|
47
|
+
title: '深度思考',
|
|
48
|
+
time: event.runningTime || '0',
|
|
49
|
+
content: event.content,
|
|
50
|
+
status: 'completed',
|
|
51
|
+
},
|
|
52
|
+
]
|
|
53
|
+
: state.processes,
|
|
54
|
+
};
|
|
55
|
+
case 'tool_call_start':
|
|
56
|
+
case 'knowledge_call_start':
|
|
57
|
+
return {
|
|
58
|
+
...state,
|
|
59
|
+
isThinking: false,
|
|
60
|
+
processes: upsertProcess(state.processes, event.toolId, {
|
|
61
|
+
id: event.toolId,
|
|
62
|
+
type: event.callKind,
|
|
63
|
+
title: event.title,
|
|
64
|
+
time: '0',
|
|
65
|
+
content: '',
|
|
66
|
+
status: 'running',
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
case 'tool_call_end':
|
|
70
|
+
case 'knowledge_call_end':
|
|
71
|
+
return {
|
|
72
|
+
...state,
|
|
73
|
+
processes: upsertProcess(state.processes, event.toolId, {
|
|
74
|
+
id: event.toolId,
|
|
75
|
+
type: event.callKind,
|
|
76
|
+
title: event.title,
|
|
77
|
+
time: event.runningTime || '0',
|
|
78
|
+
content: event.content,
|
|
79
|
+
status: 'completed',
|
|
80
|
+
}),
|
|
81
|
+
};
|
|
82
|
+
case 'answer_delta':
|
|
83
|
+
return { ...state, answerContent: event.content };
|
|
84
|
+
case 'error':
|
|
85
|
+
return {
|
|
86
|
+
...state,
|
|
87
|
+
status: 'error',
|
|
88
|
+
isThinking: false,
|
|
89
|
+
error: { message: event.message, detail: event.detail },
|
|
90
|
+
};
|
|
91
|
+
case 'stream_end':
|
|
92
|
+
return { ...state, status: state.status === 'error' ? 'error' : 'completed', isThinking: false };
|
|
93
|
+
default:
|
|
94
|
+
return state;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK 配置项
|
|
3
|
+
*
|
|
4
|
+
* 对话接口地址由调用方传入完整 `url`,SDK 不负责拼接路径(各项目自行处理代理、路由等)。
|
|
5
|
+
*/
|
|
6
|
+
export interface AgentChatClientConfig {
|
|
7
|
+
/** 流式对话完整请求 URL */
|
|
8
|
+
url: string;
|
|
9
|
+
/** 应用 ID(默认写入请求体 id 字段) */
|
|
10
|
+
appId: string;
|
|
11
|
+
/** 鉴权 Key,对应 Authorization: Bearer {appKey} */
|
|
12
|
+
appKey?: string;
|
|
13
|
+
/** 自定义 fetch 实现 */
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
/** 自定义请求体 */
|
|
16
|
+
buildRequestBody?: (query: string, config: AgentChatClientConfig) => Record<string, unknown>;
|
|
17
|
+
/** 自定义请求头 */
|
|
18
|
+
buildHeaders?: (config: AgentChatClientConfig) => Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 服务端原始 SSE 分片
|
|
22
|
+
*/
|
|
23
|
+
export interface RawSSEChunk {
|
|
24
|
+
type: string;
|
|
25
|
+
content: string;
|
|
26
|
+
role?: string;
|
|
27
|
+
running_time?: string;
|
|
28
|
+
error?: string;
|
|
29
|
+
error_detail?: string;
|
|
30
|
+
/** 保留原始 JSON,便于自定义解析 */
|
|
31
|
+
raw?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* SDK 标准化流式事件(与 UI 解耦,由使用方决定如何渲染)
|
|
35
|
+
*/
|
|
36
|
+
export type AgentStreamEventType = 'stream_start' | 'stream_end' | 'thinking_start' | 'thinking_delta' | 'thinking_end' | 'answer_delta' | 'tool_call_start' | 'tool_call_end'
|
|
37
|
+
/** @deprecated 使用 tool_call_end */
|
|
38
|
+
| 'tool_call' | 'knowledge_call_start' | 'knowledge_call_end'
|
|
39
|
+
/** @deprecated 使用 knowledge_call_end */
|
|
40
|
+
| 'knowledge_call' | 'error' | 'raw';
|
|
41
|
+
export interface AgentStreamEventBase {
|
|
42
|
+
type: AgentStreamEventType;
|
|
43
|
+
timestamp: number;
|
|
44
|
+
}
|
|
45
|
+
export interface StreamStartEvent extends AgentStreamEventBase {
|
|
46
|
+
type: 'stream_start';
|
|
47
|
+
query: string;
|
|
48
|
+
}
|
|
49
|
+
export interface StreamEndEvent extends AgentStreamEventBase {
|
|
50
|
+
type: 'stream_end';
|
|
51
|
+
}
|
|
52
|
+
export interface ThinkingStartEvent extends AgentStreamEventBase {
|
|
53
|
+
type: 'thinking_start';
|
|
54
|
+
/** ReAct 轮次,从 1 开始 */
|
|
55
|
+
round: number;
|
|
56
|
+
}
|
|
57
|
+
export interface ThinkingDeltaEvent extends AgentStreamEventBase {
|
|
58
|
+
type: 'thinking_delta';
|
|
59
|
+
delta: string;
|
|
60
|
+
/** 当前思考累积全文(UI 默认不展示,仅用于调试或可选展开) */
|
|
61
|
+
content: string;
|
|
62
|
+
round: number;
|
|
63
|
+
}
|
|
64
|
+
export interface ThinkingEndEvent extends AgentStreamEventBase {
|
|
65
|
+
type: 'thinking_end';
|
|
66
|
+
/** 思考全文,UI 默认不展示 */
|
|
67
|
+
content: string;
|
|
68
|
+
runningTime?: string;
|
|
69
|
+
round: number;
|
|
70
|
+
}
|
|
71
|
+
export interface AnswerDeltaEvent extends AgentStreamEventBase {
|
|
72
|
+
type: 'answer_delta';
|
|
73
|
+
delta: string;
|
|
74
|
+
/** 当前回复累积全文 */
|
|
75
|
+
content: string;
|
|
76
|
+
}
|
|
77
|
+
/** 工具类调用细分(与 UI 步骤文案对应) */
|
|
78
|
+
export type ProcessCallKind = 'knowledge' | 'tool' | 'plugin' | 'mcp' | 'memory' | 'workflow';
|
|
79
|
+
export interface ToolCallStartEvent extends AgentStreamEventBase {
|
|
80
|
+
type: 'tool_call_start' | 'knowledge_call_start';
|
|
81
|
+
toolId: string;
|
|
82
|
+
title: string;
|
|
83
|
+
callKind: ProcessCallKind;
|
|
84
|
+
}
|
|
85
|
+
export interface ToolCallEndEvent extends AgentStreamEventBase {
|
|
86
|
+
type: 'tool_call_end' | 'knowledge_call_end';
|
|
87
|
+
toolId: string;
|
|
88
|
+
title: string;
|
|
89
|
+
content: string;
|
|
90
|
+
runningTime?: string;
|
|
91
|
+
callKind: ProcessCallKind;
|
|
92
|
+
}
|
|
93
|
+
export interface ErrorEvent extends AgentStreamEventBase {
|
|
94
|
+
type: 'error';
|
|
95
|
+
message: string;
|
|
96
|
+
detail?: string;
|
|
97
|
+
}
|
|
98
|
+
export interface RawEvent extends AgentStreamEventBase {
|
|
99
|
+
type: 'raw';
|
|
100
|
+
chunk: RawSSEChunk;
|
|
101
|
+
}
|
|
102
|
+
export type AgentStreamEvent = StreamStartEvent | StreamEndEvent | ThinkingStartEvent | ThinkingDeltaEvent | ThinkingEndEvent | AnswerDeltaEvent | ToolCallStartEvent | ToolCallEndEvent | ErrorEvent | RawEvent;
|
|
103
|
+
/**
|
|
104
|
+
* 数据推送模式
|
|
105
|
+
* - normalized:推送标准化事件(推荐)
|
|
106
|
+
* - raw:仅推送原始 SSE 分片
|
|
107
|
+
* - both:同时推送两种数据
|
|
108
|
+
*/
|
|
109
|
+
export type AgentChatDataMode = 'normalized' | 'raw' | 'both';
|
|
110
|
+
export interface AgentChatStreamOptions {
|
|
111
|
+
query: string;
|
|
112
|
+
signal?: AbortSignal;
|
|
113
|
+
/** 数据推送模式,默认 normalized */
|
|
114
|
+
dataMode?: AgentChatDataMode;
|
|
115
|
+
/** 额外请求体字段 */
|
|
116
|
+
extraBody?: Record<string, unknown>;
|
|
117
|
+
/** 额外请求头 */
|
|
118
|
+
extraHeaders?: Record<string, string>;
|
|
119
|
+
}
|
|
120
|
+
export interface AgentChatStreamHandlers {
|
|
121
|
+
/** 标准化事件回调 */
|
|
122
|
+
onEvent?: (event: AgentStreamEvent) => void;
|
|
123
|
+
/** 原始分片回调 */
|
|
124
|
+
onRawChunk?: (chunk: RawSSEChunk) => void;
|
|
125
|
+
onError?: (error: Error) => void;
|
|
126
|
+
onComplete?: () => void;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 可选:会话聚合状态,供使用方直接绑定 UI 或自行转换
|
|
130
|
+
*/
|
|
131
|
+
export interface AgentChatSessionState {
|
|
132
|
+
status: 'idle' | 'streaming' | 'completed' | 'error';
|
|
133
|
+
query: string;
|
|
134
|
+
thinkingContent: string;
|
|
135
|
+
isThinking: boolean;
|
|
136
|
+
answerContent: string;
|
|
137
|
+
processes: AgentChatProcessItem[];
|
|
138
|
+
error?: {
|
|
139
|
+
message: string;
|
|
140
|
+
detail?: string;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
export interface AgentChatProcessItem {
|
|
144
|
+
id: string;
|
|
145
|
+
type: 'thinking' | 'tool' | 'knowledge' | 'plugin' | 'mcp' | 'memory' | 'workflow';
|
|
146
|
+
title: string;
|
|
147
|
+
time: string;
|
|
148
|
+
content: string;
|
|
149
|
+
status: 'running' | 'completed';
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|