@blueking/chat-helper 0.0.12-beta.2 → 0.0.12-beta.21
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/README.md +21 -7
- package/dist/agent/type.d.ts +69 -0
- package/dist/agent/type.ts.js +1 -1
- package/dist/agent/use-agent.d.ts +1484 -8
- package/dist/agent/use-agent.ts.js +452 -30
- package/dist/event/ag-ui.d.ts +18 -3
- package/dist/event/ag-ui.ts.js +175 -8
- package/dist/event/type.d.ts +104 -26
- package/dist/event/type.ts.js +46 -16
- package/dist/http/fetch/fetch.ts.js +104 -24
- package/dist/http/index.d.ts +15 -4
- package/dist/http/module/agent.d.ts +2 -0
- package/dist/http/module/agent.ts.js +19 -2
- package/dist/http/module/index.d.ts +15 -4
- package/dist/http/module/message.d.ts +7 -4
- package/dist/http/module/message.ts.js +22 -4
- package/dist/http/module/session.d.ts +9 -2
- package/dist/http/module/session.ts.js +55 -3
- package/dist/http/transform/agent.d.ts +9 -1
- package/dist/http/transform/agent.ts.js +27 -0
- package/dist/http/transform/message.ts.js +25 -5
- package/dist/index.d.ts +9971 -31
- package/dist/message/type.d.ts +53 -7
- package/dist/message/type.ts.js +24 -0
- package/dist/message/use-message.d.ts +2820 -4
- package/dist/session/type.d.ts +33 -0
- package/dist/session/use-session.d.ts +5650 -11
- package/dist/session/use-session.ts.js +77 -8
- package/package.json +4 -1
|
@@ -79,10 +79,63 @@ function _object_spread(target) {
|
|
|
79
79
|
}
|
|
80
80
|
return target;
|
|
81
81
|
}
|
|
82
|
+
function ownKeys(object, enumerableOnly) {
|
|
83
|
+
var keys = Object.keys(object);
|
|
84
|
+
if (Object.getOwnPropertySymbols) {
|
|
85
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
86
|
+
if (enumerableOnly) {
|
|
87
|
+
symbols = symbols.filter(function(sym) {
|
|
88
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
keys.push.apply(keys, symbols);
|
|
92
|
+
}
|
|
93
|
+
return keys;
|
|
94
|
+
}
|
|
95
|
+
function _object_spread_props(target, source) {
|
|
96
|
+
source = source != null ? source : {};
|
|
97
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
98
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
99
|
+
} else {
|
|
100
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
101
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return target;
|
|
105
|
+
}
|
|
82
106
|
import { ref } from 'vue';
|
|
83
|
-
import { AGUIProtocol } from '../event/index.ts.js';
|
|
84
|
-
import { MessageRole, MessageStatus } from '../message/index.ts.js';
|
|
107
|
+
import { AGUIProtocol, ApprovalInterruptTicketStatus, EventType, ResumeStatus, RunFinishedOutcomeType } from '../event/index.ts.js';
|
|
108
|
+
import { MessageRole, MessageStatus, UserOperation } from '../message/index.ts.js';
|
|
85
109
|
import { SessionStatus } from '../session/type.ts.js';
|
|
110
|
+
/** SSE 静默重连最大次数(退避总时长约 23s,落在后端 orphan grace ~30s 内) */ const MAX_RECONNECT_ATTEMPTS = 5;
|
|
111
|
+
const RECONNECT_BASE_DELAY_MS = 1000;
|
|
112
|
+
const RECONNECT_MAX_DELAY_MS = 8000;
|
|
113
|
+
const getReconnectDelayMs = (attempt)=>Math.min(RECONNECT_BASE_DELAY_MS * Math.pow(2, attempt - 1), RECONNECT_MAX_DELAY_MS);
|
|
114
|
+
/**
|
|
115
|
+
* 判断流式错误是否可静默重连。
|
|
116
|
+
* 不重试:Abort、401/403 等业务 4xx(408/429 除外);可重试:网络错误、5xx、无状态码的中断。
|
|
117
|
+
*/ const isRecoverableStreamError = (error)=>{
|
|
118
|
+
var _requestError_response;
|
|
119
|
+
if (error.name === 'AbortError') {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const requestError = error;
|
|
123
|
+
const statusFromResponse = (_requestError_response = requestError.response) === null || _requestError_response === void 0 ? void 0 : _requestError_response.status;
|
|
124
|
+
const statusFromMessage = error.message.match(/status code (\d+)/i);
|
|
125
|
+
const status = statusFromResponse !== null && statusFromResponse !== void 0 ? statusFromResponse : statusFromMessage ? Number(statusFromMessage[1]) : undefined;
|
|
126
|
+
if (status !== undefined) {
|
|
127
|
+
if (status === 408 || status === 429) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (status >= 400 && status < 500) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
if (status >= 500) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
};
|
|
86
139
|
/**
|
|
87
140
|
* Agent 模块
|
|
88
141
|
* @param options - 配置选项
|
|
@@ -91,8 +144,40 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
91
144
|
const info = ref(null);
|
|
92
145
|
const isInfoLoading = ref(false);
|
|
93
146
|
const isChatting = ref(false);
|
|
147
|
+
const models = ref([]);
|
|
148
|
+
const isModelsLoading = ref(false);
|
|
94
149
|
let usedProtocol = protocol || new AGUIProtocol();
|
|
95
|
-
let
|
|
150
|
+
let chatAbortController = null;
|
|
151
|
+
let resumeAbortController = null;
|
|
152
|
+
let longPollTimer = null;
|
|
153
|
+
/** 用户主动中止(abortChat),禁止自动重连 */ let manualAbort = false;
|
|
154
|
+
/** 当前轮次已静默重连次数 */ let reconnectAttempt = 0;
|
|
155
|
+
/** 本轮流是否已收到 RUN_FINISHED */ let runFinished = false;
|
|
156
|
+
/** 流世代号:新开流时递增,用于忽略已被替换的旧 SSE 回调 */ let activeStreamId = 0;
|
|
157
|
+
let reconnectTimer = null;
|
|
158
|
+
let reconnectWaitResolve = null;
|
|
159
|
+
let activeStreamContext = null;
|
|
160
|
+
/**
|
|
161
|
+
* 获取可用模型列表,写入 models;失败时清空列表并抛出
|
|
162
|
+
*/ const getLlms = (params, config)=>{
|
|
163
|
+
var _mediator_http;
|
|
164
|
+
isModelsLoading.value = true;
|
|
165
|
+
const request = (_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.agent.getLlms(params, config);
|
|
166
|
+
if (!request) {
|
|
167
|
+
isModelsLoading.value = false;
|
|
168
|
+
models.value = [];
|
|
169
|
+
return Promise.resolve([]);
|
|
170
|
+
}
|
|
171
|
+
return request.then((res)=>{
|
|
172
|
+
models.value = res;
|
|
173
|
+
return res;
|
|
174
|
+
})['catch']((error)=>{
|
|
175
|
+
models.value = [];
|
|
176
|
+
throw error;
|
|
177
|
+
})['finally'](()=>{
|
|
178
|
+
isModelsLoading.value = false;
|
|
179
|
+
});
|
|
180
|
+
};
|
|
96
181
|
const getAgentInfo = ()=>{
|
|
97
182
|
var _mediator_http;
|
|
98
183
|
isInfoLoading.value = true;
|
|
@@ -121,55 +206,295 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
121
206
|
});
|
|
122
207
|
}
|
|
123
208
|
};
|
|
209
|
+
const userOperationStreamRequest = (sessionCode, operation, payload, config, model)=>{
|
|
210
|
+
var _mediator_http;
|
|
211
|
+
return (_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.message.userOperation(sessionCode, operation, payload, config).then(()=>{
|
|
212
|
+
if (operation !== UserOperation.ApprovalCancel) {
|
|
213
|
+
streamRequest({
|
|
214
|
+
sessionCode,
|
|
215
|
+
config,
|
|
216
|
+
model
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
clearLongPollTimer();
|
|
220
|
+
pollResumeSession(sessionCode, model);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
const clearReconnectTimer = (continued = false)=>{
|
|
225
|
+
if (reconnectTimer) {
|
|
226
|
+
clearTimeout(reconnectTimer);
|
|
227
|
+
reconnectTimer = null;
|
|
228
|
+
}
|
|
229
|
+
if (reconnectWaitResolve) {
|
|
230
|
+
const resolve = reconnectWaitResolve;
|
|
231
|
+
reconnectWaitResolve = null;
|
|
232
|
+
resolve(continued);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const waitForReconnectDelay = (ms)=>new Promise((resolve)=>{
|
|
236
|
+
reconnectWaitResolve = resolve;
|
|
237
|
+
reconnectTimer = setTimeout(()=>{
|
|
238
|
+
reconnectTimer = null;
|
|
239
|
+
reconnectWaitResolve = null;
|
|
240
|
+
resolve(true);
|
|
241
|
+
}, ms);
|
|
242
|
+
});
|
|
243
|
+
const resetStreamReconnectState = ()=>{
|
|
244
|
+
manualAbort = false;
|
|
245
|
+
reconnectAttempt = 0;
|
|
246
|
+
runFinished = false;
|
|
247
|
+
clearReconnectTimer(false);
|
|
248
|
+
};
|
|
249
|
+
/** 裁掉尾部尚未完成的非用户消息,避免断线重放时重复气泡 */ const pruneTrailingIncompleteMessages = ()=>{
|
|
250
|
+
var _mediator_message;
|
|
251
|
+
const list = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value;
|
|
252
|
+
if (!(list === null || list === void 0 ? void 0 : list.length)) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
while(list.length > 0){
|
|
256
|
+
const last = list[list.length - 1];
|
|
257
|
+
if (last.role === MessageRole.User) {
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
if (last.status === MessageStatus.Streaming || last.status === MessageStatus.Pending) {
|
|
261
|
+
list.pop();
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const isSameActiveSession = (sessionCode)=>{
|
|
268
|
+
var _mediator_session_current_value, _mediator_session_current, _mediator_session;
|
|
269
|
+
return sessionCode === ((_mediator_session = mediator.session) === null || _mediator_session === void 0 ? void 0 : (_mediator_session_current = _mediator_session.current) === null || _mediator_session_current === void 0 ? void 0 : (_mediator_session_current_value = _mediator_session_current.value) === null || _mediator_session_current_value === void 0 ? void 0 : _mediator_session_current_value.sessionCode);
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* 尝试静默重连。
|
|
273
|
+
* @param streamId - 发起重连的流世代;任一 await 后若已被新流/abort 取代则立即退出,避免 abort 掉更新流
|
|
274
|
+
* @returns reconnected | finished(服务端已结束)| failed(需对外报错或中止)
|
|
275
|
+
*/ const attemptSilentReconnect = function() {
|
|
276
|
+
var _ref = _async_to_generator(function*(sessionCode, streamId) {
|
|
277
|
+
var _mediator_session_current_value, _mediator_session, _mediator_session_current_value1, _mediator_session1, _mediator_message_list_value_at, _mediator_message;
|
|
278
|
+
const isOwnerStream = ()=>streamId === activeStreamId && !manualAbort;
|
|
279
|
+
if (!isOwnerStream() || !isSameActiveSession(sessionCode)) {
|
|
280
|
+
return 'failed';
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
var _mediator_session2;
|
|
284
|
+
yield (_mediator_session2 = mediator.session) === null || _mediator_session2 === void 0 ? void 0 : _mediator_session2.getSession(sessionCode);
|
|
285
|
+
} catch (e) {
|
|
286
|
+
// 状态刷新失败时沿用本地 session.status
|
|
287
|
+
}
|
|
288
|
+
if (!isOwnerStream() || !isSameActiveSession(sessionCode)) {
|
|
289
|
+
return 'failed';
|
|
290
|
+
}
|
|
291
|
+
if (((_mediator_session = mediator.session) === null || _mediator_session === void 0 ? void 0 : (_mediator_session_current_value = _mediator_session.current.value) === null || _mediator_session_current_value === void 0 ? void 0 : _mediator_session_current_value.status) !== SessionStatus.Running) {
|
|
292
|
+
return 'finished';
|
|
293
|
+
}
|
|
294
|
+
if (reconnectAttempt >= MAX_RECONNECT_ATTEMPTS) {
|
|
295
|
+
return 'failed';
|
|
296
|
+
}
|
|
297
|
+
reconnectAttempt += 1;
|
|
298
|
+
// 静默重连期间保持「生成中」态
|
|
299
|
+
isChatting.value = true;
|
|
300
|
+
const delayMs = getReconnectDelayMs(reconnectAttempt);
|
|
301
|
+
const waited = yield waitForReconnectDelay(delayMs);
|
|
302
|
+
if (!waited || !isOwnerStream() || !isSameActiveSession(sessionCode)) {
|
|
303
|
+
return 'failed';
|
|
304
|
+
}
|
|
305
|
+
if (((_mediator_session1 = mediator.session) === null || _mediator_session1 === void 0 ? void 0 : (_mediator_session_current_value1 = _mediator_session1.current.value) === null || _mediator_session_current_value1 === void 0 ? void 0 : _mediator_session_current_value1.status) !== SessionStatus.Running) {
|
|
306
|
+
return 'finished';
|
|
307
|
+
}
|
|
308
|
+
// 发起新流前再校验一次:防止 await 后窗口期被新用户请求抢走 activeStreamId
|
|
309
|
+
if (!isOwnerStream()) {
|
|
310
|
+
return 'failed';
|
|
311
|
+
}
|
|
312
|
+
pruneTrailingIncompleteMessages();
|
|
313
|
+
const lastMessageId = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : (_mediator_message_list_value_at = _mediator_message.list.value.at(-1)) === null || _mediator_message_list_value_at === void 0 ? void 0 : _mediator_message_list_value_at.id;
|
|
314
|
+
const ctx = activeStreamContext;
|
|
315
|
+
streamRequest({
|
|
316
|
+
sessionCode,
|
|
317
|
+
model: ctx === null || ctx === void 0 ? void 0 : ctx.model,
|
|
318
|
+
url: ctx === null || ctx === void 0 ? void 0 : ctx.url,
|
|
319
|
+
config: ctx === null || ctx === void 0 ? void 0 : ctx.config,
|
|
320
|
+
lastMessageId: lastMessageId !== undefined ? String(lastMessageId) : undefined,
|
|
321
|
+
isReconnect: true
|
|
322
|
+
});
|
|
323
|
+
return 'reconnected';
|
|
324
|
+
});
|
|
325
|
+
return function attemptSilentReconnect(sessionCode, streamId) {
|
|
326
|
+
return _ref.apply(this, arguments);
|
|
327
|
+
};
|
|
328
|
+
}();
|
|
124
329
|
const streamRequest = function() {
|
|
125
|
-
var _ref = _async_to_generator(function*(sessionCode, url, config) {
|
|
126
|
-
var _mediator_http;
|
|
330
|
+
var _ref = _async_to_generator(function*({ sessionCode, model, url, config, resume, input, lastMessageId, isReconnect = false }) {
|
|
331
|
+
var _previousController_abort, _mediator_http;
|
|
332
|
+
if (!isReconnect) {
|
|
333
|
+
resetStreamReconnectState();
|
|
334
|
+
}
|
|
335
|
+
activeStreamContext = {
|
|
336
|
+
sessionCode,
|
|
337
|
+
model: model,
|
|
338
|
+
url,
|
|
339
|
+
config
|
|
340
|
+
};
|
|
341
|
+
// 先递增世代再 abort 旧连接,避免旧流 onDone 误触发二次重连
|
|
342
|
+
const streamId = ++activeStreamId;
|
|
343
|
+
const previousController = chatAbortController;
|
|
344
|
+
chatAbortController = new AbortController();
|
|
345
|
+
previousController === null || previousController === void 0 ? void 0 : (_previousController_abort = previousController.abort) === null || _previousController_abort === void 0 ? void 0 : _previousController_abort.call(previousController);
|
|
346
|
+
const isActiveStream = ()=>streamId === activeStreamId;
|
|
127
347
|
// ag-ui 协议需要注入消息模块
|
|
128
348
|
if (usedProtocol instanceof AGUIProtocol) {
|
|
129
349
|
usedProtocol.injectMessageModule(mediator.message);
|
|
130
350
|
}
|
|
131
|
-
|
|
132
|
-
|
|
351
|
+
if (input) {
|
|
352
|
+
var // 列表新增一个用户消息
|
|
353
|
+
_mediator_message;
|
|
354
|
+
(_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value.push({
|
|
355
|
+
role: MessageRole.User,
|
|
356
|
+
content: input,
|
|
357
|
+
status: MessageStatus.Complete,
|
|
358
|
+
sessionCode
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
const finishSuccessfully = ()=>{
|
|
133
362
|
var _usedProtocol_onDone;
|
|
363
|
+
if (!isActiveStream()) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
134
366
|
isChatting.value = false;
|
|
135
367
|
(_usedProtocol_onDone = usedProtocol.onDone) === null || _usedProtocol_onDone === void 0 ? void 0 : _usedProtocol_onDone.call(usedProtocol);
|
|
368
|
+
if (input) {
|
|
369
|
+
var // 刷新列表,获取前端 mock message 的 id,并更新到列表中
|
|
370
|
+
_mediator_http_message, _mediator_http;
|
|
371
|
+
(_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : (_mediator_http_message = _mediator_http.message) === null || _mediator_http_message === void 0 ? void 0 : _mediator_http_message.getMessages(sessionCode).then((res)=>{
|
|
372
|
+
var _mediator_message;
|
|
373
|
+
const lastUserMessage = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value.findLast((item)=>item.role === MessageRole.User);
|
|
374
|
+
const lastApiUserMessage = res.findLast((item)=>item.role === MessageRole.User);
|
|
375
|
+
if (lastUserMessage && lastApiUserMessage) {
|
|
376
|
+
lastUserMessage.id = lastApiUserMessage.id;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
// 轮询接口,判断是否可以继续聊天
|
|
381
|
+
pollResumeSession(sessionCode);
|
|
136
382
|
};
|
|
137
|
-
const
|
|
383
|
+
const failWithError = (error)=>{
|
|
138
384
|
var _usedProtocol_onError;
|
|
385
|
+
if (!isActiveStream()) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
139
388
|
isChatting.value = false;
|
|
140
389
|
(_usedProtocol_onError = usedProtocol.onError) === null || _usedProtocol_onError === void 0 ? void 0 : _usedProtocol_onError.call(usedProtocol, error);
|
|
141
390
|
};
|
|
391
|
+
// 事件代理
|
|
392
|
+
const onDone = ()=>{
|
|
393
|
+
if (!isActiveStream()) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
// 用户 abort:本地状态已在 abortChat 结算,勿走 completion/poll
|
|
397
|
+
if (manualAbort) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (runFinished) {
|
|
401
|
+
finishSuccessfully();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
// 连接被干净掐断且未收到终端事件(RUN_FINISHED / RUN_ERROR):尝试静默重连
|
|
405
|
+
void attemptSilentReconnect(sessionCode, streamId).then((result)=>{
|
|
406
|
+
if (!isActiveStream()) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (result === 'reconnected') {
|
|
410
|
+
// 保持 isChatting=true,不展示错误
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (result === 'finished') {
|
|
414
|
+
finishSuccessfully();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
// abort / 切会话导致的失败:静默结束,不展示错误气泡
|
|
418
|
+
if (manualAbort || !isSameActiveSession(sessionCode)) {
|
|
419
|
+
isChatting.value = false;
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
failWithError(new Error('Connection lost, please try again'));
|
|
423
|
+
});
|
|
424
|
+
};
|
|
425
|
+
const onError = (error)=>{
|
|
426
|
+
if (!isActiveStream() || manualAbort) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (!isRecoverableStreamError(error)) {
|
|
430
|
+
failWithError(error);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
void attemptSilentReconnect(sessionCode, streamId).then((result)=>{
|
|
434
|
+
if (!isActiveStream()) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (result === 'reconnected') {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (result === 'finished') {
|
|
441
|
+
finishSuccessfully();
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (manualAbort || !isSameActiveSession(sessionCode)) {
|
|
445
|
+
isChatting.value = false;
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
failWithError(error);
|
|
449
|
+
});
|
|
450
|
+
};
|
|
142
451
|
const onMessage = (event)=>{
|
|
143
452
|
var _usedProtocol_onMessage;
|
|
453
|
+
if (!isActiveStream()) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const typedEvent = event;
|
|
457
|
+
// RUN_FINISHED / RUN_ERROR 均为终端事件:关流后走正常收尾,勿静默重连
|
|
458
|
+
// (用户 stop 后后端推 RUN_ERROR「用户已取消」,而非 RUN_FINISHED)
|
|
459
|
+
if ((typedEvent === null || typedEvent === void 0 ? void 0 : typedEvent.type) === EventType.RunFinished || (typedEvent === null || typedEvent === void 0 ? void 0 : typedEvent.type) === EventType.RunError) {
|
|
460
|
+
runFinished = true;
|
|
461
|
+
}
|
|
144
462
|
(_usedProtocol_onMessage = usedProtocol.onMessage) === null || _usedProtocol_onMessage === void 0 ? void 0 : _usedProtocol_onMessage.call(usedProtocol, event);
|
|
145
463
|
};
|
|
146
464
|
const onStart = ()=>{
|
|
147
465
|
var _usedProtocol_onStart;
|
|
466
|
+
if (!isActiveStream()) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
148
469
|
isChatting.value = true;
|
|
149
470
|
(_usedProtocol_onStart = usedProtocol.onStart) === null || _usedProtocol_onStart === void 0 ? void 0 : _usedProtocol_onStart.call(usedProtocol);
|
|
150
471
|
};
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
// 发起聊天
|
|
154
|
-
void ((_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.fetchClient.streamRequest(_object_spread({
|
|
472
|
+
// 发起聊天(controller / 回调必须在 ...config 之后,防止被覆盖)
|
|
473
|
+
void ((_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.fetchClient.streamRequest(_object_spread_props(_object_spread({
|
|
155
474
|
url: url || 'chat_completion/',
|
|
156
475
|
method: 'POST',
|
|
157
476
|
data: {
|
|
158
477
|
session_code: sessionCode,
|
|
478
|
+
model,
|
|
479
|
+
input,
|
|
159
480
|
execute_kwargs: {
|
|
160
|
-
stream: true
|
|
481
|
+
stream: true,
|
|
482
|
+
persist_input: !!input,
|
|
483
|
+
last_message_id: lastMessageId,
|
|
484
|
+
resume
|
|
161
485
|
}
|
|
162
|
-
}
|
|
163
|
-
|
|
486
|
+
}
|
|
487
|
+
}, config), {
|
|
488
|
+
controller: chatAbortController,
|
|
164
489
|
onDone,
|
|
165
490
|
onError,
|
|
166
491
|
onMessage,
|
|
167
492
|
onStart
|
|
168
|
-
}
|
|
493
|
+
})).catch(()=>{
|
|
169
494
|
// 非 abort 错误已通过 onError 回调处理;abort 为正常结束
|
|
170
495
|
}));
|
|
171
496
|
});
|
|
172
|
-
return function streamRequest(
|
|
497
|
+
return function streamRequest(_) {
|
|
173
498
|
return _ref.apply(this, arguments);
|
|
174
499
|
};
|
|
175
500
|
}();
|
|
@@ -180,8 +505,9 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
180
505
|
* @param url - 请求 URL(可选)
|
|
181
506
|
* @param config - 请求配置(可选)
|
|
182
507
|
* @param property - 消息属性,用于传递引用内容或快捷键相关信息(可选)
|
|
508
|
+
* @param model - 模型标识(可选)
|
|
183
509
|
*/ const chat = function() {
|
|
184
|
-
var _ref = _async_to_generator(function*(userInput, sessionCode, url, config, property) {
|
|
510
|
+
var _ref = _async_to_generator(function*(userInput, sessionCode, url, config, property, model) {
|
|
185
511
|
var _mediator_message;
|
|
186
512
|
// 先新增一个 message
|
|
187
513
|
yield (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.createAndPlusMessage(_object_spread({
|
|
@@ -193,9 +519,14 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
193
519
|
property
|
|
194
520
|
}));
|
|
195
521
|
// 发起聊天
|
|
196
|
-
streamRequest(
|
|
522
|
+
streamRequest({
|
|
523
|
+
sessionCode,
|
|
524
|
+
model,
|
|
525
|
+
url,
|
|
526
|
+
config
|
|
527
|
+
});
|
|
197
528
|
});
|
|
198
|
-
return function chat(userInput, sessionCode, url, config, property) {
|
|
529
|
+
return function chat(userInput, sessionCode, url, config, property, model) {
|
|
199
530
|
return _ref.apply(this, arguments);
|
|
200
531
|
};
|
|
201
532
|
}();
|
|
@@ -205,18 +536,89 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
205
536
|
* @param sessionCode - 会话代码
|
|
206
537
|
* @param url - 请求 URL(可选)
|
|
207
538
|
* @param config - 请求配置(可选)
|
|
208
|
-
|
|
539
|
+
* @param model - 模型标识(可选)
|
|
540
|
+
*/ const resumeStreamingChat = (sessionCode, url, config, model)=>{
|
|
209
541
|
var _mediator_session_current_value, _mediator_session;
|
|
210
542
|
if (((_mediator_session = mediator.session) === null || _mediator_session === void 0 ? void 0 : (_mediator_session_current_value = _mediator_session.current.value) === null || _mediator_session_current_value === void 0 ? void 0 : _mediator_session_current_value.status) === SessionStatus.Running) {
|
|
211
|
-
|
|
543
|
+
var _mediator_message_list_value_at, _mediator_message;
|
|
544
|
+
const lastMessageId = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : (_mediator_message_list_value_at = _mediator_message.list.value.at(-1)) === null || _mediator_message_list_value_at === void 0 ? void 0 : _mediator_message_list_value_at.id;
|
|
545
|
+
streamRequest({
|
|
546
|
+
sessionCode,
|
|
547
|
+
model,
|
|
548
|
+
url,
|
|
549
|
+
config,
|
|
550
|
+
lastMessageId
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
/**
|
|
555
|
+
* 轮询接口,判断是否可以继续聊天
|
|
556
|
+
* @param sessionCode - 会话编码
|
|
557
|
+
* @returns 是否可以继续聊天
|
|
558
|
+
*/ const pollResumeSession = (sessionCode, model)=>{
|
|
559
|
+
var _mediator_message, _lastMessage_content_outcome, _lastMessage_content;
|
|
560
|
+
const lastMessage = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value.at(-1);
|
|
561
|
+
const pendingApprovalInterrupt = (lastMessage === null || lastMessage === void 0 ? void 0 : (_lastMessage_content = lastMessage.content) === null || _lastMessage_content === void 0 ? void 0 : (_lastMessage_content_outcome = _lastMessage_content.outcome) === null || _lastMessage_content_outcome === void 0 ? void 0 : _lastMessage_content_outcome.type) === RunFinishedOutcomeType.Interrupt ? lastMessage.content.outcome.interrupts.find((interrupt)=>{
|
|
562
|
+
var _interrupt_metadata_ticket, _interrupt_metadata;
|
|
563
|
+
return [
|
|
564
|
+
ApprovalInterruptTicketStatus.Pending,
|
|
565
|
+
ApprovalInterruptTicketStatus.Draft
|
|
566
|
+
].includes((_interrupt_metadata = interrupt.metadata) === null || _interrupt_metadata === void 0 ? void 0 : (_interrupt_metadata_ticket = _interrupt_metadata.ticket) === null || _interrupt_metadata_ticket === void 0 ? void 0 : _interrupt_metadata_ticket.status);
|
|
567
|
+
}) : undefined;
|
|
568
|
+
const getIsTicketLoading = ()=>{
|
|
569
|
+
const isInterruptMessage = (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) === MessageRole.Interrupt;
|
|
570
|
+
return isInterruptMessage && !!pendingApprovalInterrupt;
|
|
571
|
+
};
|
|
572
|
+
if (getIsTicketLoading()) {
|
|
573
|
+
var // 轮询接口,判断是否可以继续聊天
|
|
574
|
+
_mediator_http;
|
|
575
|
+
// 清除轮询定时器和中断轮询控制器
|
|
576
|
+
clearLongPollTimer();
|
|
577
|
+
resumeAbortController = new AbortController();
|
|
578
|
+
(_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.session.isResumeSession(sessionCode, {
|
|
579
|
+
controller: resumeAbortController
|
|
580
|
+
}).then((res)=>{
|
|
581
|
+
if (res) {
|
|
582
|
+
// 可以继续聊天,重新发起聊天(携带 execute_kwargs.resume 通知后端恢复中断)
|
|
583
|
+
streamRequest({
|
|
584
|
+
sessionCode,
|
|
585
|
+
model,
|
|
586
|
+
resume: {
|
|
587
|
+
interruptId: pendingApprovalInterrupt.id,
|
|
588
|
+
status: ResumeStatus.Resolved
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
} else {
|
|
592
|
+
longPollTimer = setTimeout(()=>{
|
|
593
|
+
var _mediator_session_current_value, _mediator_session_current, _mediator_session;
|
|
594
|
+
// 如果会话不匹配,则不继续轮询
|
|
595
|
+
if (sessionCode !== ((_mediator_session = mediator.session) === null || _mediator_session === void 0 ? void 0 : (_mediator_session_current = _mediator_session.current) === null || _mediator_session_current === void 0 ? void 0 : (_mediator_session_current_value = _mediator_session_current.value) === null || _mediator_session_current_value === void 0 ? void 0 : _mediator_session_current_value.sessionCode)) return;
|
|
596
|
+
pollResumeSession(sessionCode, model);
|
|
597
|
+
}, 10000);
|
|
598
|
+
}
|
|
599
|
+
});
|
|
212
600
|
}
|
|
213
601
|
};
|
|
602
|
+
const clearLongPollTimer = ()=>{
|
|
603
|
+
var _resumeAbortController_abort;
|
|
604
|
+
clearTimeout(longPollTimer);
|
|
605
|
+
longPollTimer = null;
|
|
606
|
+
resumeAbortController === null || resumeAbortController === void 0 ? void 0 : (_resumeAbortController_abort = resumeAbortController.abort) === null || _resumeAbortController_abort === void 0 ? void 0 : _resumeAbortController_abort.call(resumeAbortController);
|
|
607
|
+
resumeAbortController = null;
|
|
608
|
+
};
|
|
214
609
|
/**
|
|
215
610
|
* 中止聊天(纯前端中止,后端继续处理)
|
|
611
|
+
* 会使当前流世代失效,避免 abort 后的 onDone 误触发 finishSuccessfully / pollResumeSession
|
|
216
612
|
*/ const abortChat = ()=>{
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
|
|
613
|
+
var _chatAbortController_abort;
|
|
614
|
+
manualAbort = true;
|
|
615
|
+
// 先失效世代,再 abort:FetchClient 同步触发的 onDone 会因 isActiveStream=false 直接返回
|
|
616
|
+
activeStreamId += 1;
|
|
617
|
+
clearReconnectTimer(false);
|
|
618
|
+
clearLongPollTimer();
|
|
619
|
+
isChatting.value = false;
|
|
620
|
+
chatAbortController === null || chatAbortController === void 0 ? void 0 : (_chatAbortController_abort = chatAbortController.abort) === null || _chatAbortController_abort === void 0 ? void 0 : _chatAbortController_abort.call(chatAbortController);
|
|
621
|
+
chatAbortController = null;
|
|
220
622
|
};
|
|
221
623
|
/**
|
|
222
624
|
* 停止会话,后端中止
|
|
@@ -239,8 +641,9 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
239
641
|
* @param newContent - 新内容(可选,不传则使用原消息内容;支持多模态)
|
|
240
642
|
* @param url - 请求 URL(可选)
|
|
241
643
|
* @param config - 请求配置(可选)
|
|
644
|
+
* @param model - 模型标识(可选)
|
|
242
645
|
*/ const resendMessage = function() {
|
|
243
|
-
var _ref = _async_to_generator(function*(messageId, sessionCode, newContent, url, config) {
|
|
646
|
+
var _ref = _async_to_generator(function*(messageId, sessionCode, newContent, url, config, model) {
|
|
244
647
|
var _mediator_message, _mediator_message1, _mediator_message2;
|
|
245
648
|
const messages = ((_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value) || [];
|
|
246
649
|
// 1. 找到目标用户消息
|
|
@@ -271,7 +674,12 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
271
674
|
property: originalProperty
|
|
272
675
|
}));
|
|
273
676
|
// 6. 立即发起流式请求(不等待删除和创建的 API 完成)
|
|
274
|
-
streamRequest(
|
|
677
|
+
streamRequest({
|
|
678
|
+
sessionCode,
|
|
679
|
+
model,
|
|
680
|
+
url,
|
|
681
|
+
config
|
|
682
|
+
});
|
|
275
683
|
// 7. 在后台等待 API 完成,处理可能的错误
|
|
276
684
|
Promise.all([
|
|
277
685
|
deletePromise,
|
|
@@ -280,20 +688,29 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
280
688
|
console.error('[resendMessage] API error:', error);
|
|
281
689
|
});
|
|
282
690
|
});
|
|
283
|
-
return function resendMessage(messageId, sessionCode, newContent, url, config) {
|
|
691
|
+
return function resendMessage(messageId, sessionCode, newContent, url, config, model) {
|
|
284
692
|
return _ref.apply(this, arguments);
|
|
285
693
|
};
|
|
286
694
|
}();
|
|
287
695
|
const reset = (protocol)=>{
|
|
288
|
-
|
|
696
|
+
abortChat();
|
|
697
|
+
// 重置状态(保留 manualAbort=true,避免 abort 异步 onDone 误触发重连;下次 streamRequest 会复位)
|
|
289
698
|
usedProtocol = protocol || new AGUIProtocol();
|
|
290
699
|
info.value = null;
|
|
291
700
|
isInfoLoading.value = false;
|
|
701
|
+
isChatting.value = false;
|
|
702
|
+
models.value = [];
|
|
703
|
+
isModelsLoading.value = false;
|
|
704
|
+
activeStreamContext = null;
|
|
705
|
+
reconnectAttempt = 0;
|
|
706
|
+
runFinished = false;
|
|
292
707
|
};
|
|
293
708
|
return {
|
|
294
709
|
info,
|
|
295
710
|
isInfoLoading,
|
|
296
711
|
isChatting,
|
|
712
|
+
models,
|
|
713
|
+
isModelsLoading,
|
|
297
714
|
chat,
|
|
298
715
|
handleRole,
|
|
299
716
|
resendMessage,
|
|
@@ -301,6 +718,11 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
301
718
|
abortChat,
|
|
302
719
|
stopChat,
|
|
303
720
|
getAgentInfo,
|
|
304
|
-
|
|
721
|
+
getLlms,
|
|
722
|
+
reset,
|
|
723
|
+
pollResumeSession,
|
|
724
|
+
clearLongPollTimer,
|
|
725
|
+
userOperationStreamRequest,
|
|
726
|
+
streamRequest
|
|
305
727
|
};
|
|
306
728
|
};
|
package/dist/event/ag-ui.d.ts
CHANGED
|
@@ -26,7 +26,8 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
26
26
|
* 处理活动快照事件
|
|
27
27
|
* 记录活动的完整状态
|
|
28
28
|
*/
|
|
29
|
-
handleActivitySnapshotEvent(
|
|
29
|
+
handleActivitySnapshotEvent(event: IActivitySnapshotEvent): void;
|
|
30
|
+
handleArtifactsGeneratedCustomEvent(event: ICustomEvent): void;
|
|
30
31
|
/**
|
|
31
32
|
* 处理自定义事件
|
|
32
33
|
*/
|
|
@@ -35,6 +36,10 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
35
36
|
* 自定义事件 处理流程编排任务结束
|
|
36
37
|
*/
|
|
37
38
|
handleFlowAgentEndCustomEvent(event: ICustomEvent): void;
|
|
39
|
+
/**
|
|
40
|
+
* 自定义事件 处理流程编排任务重启
|
|
41
|
+
*/
|
|
42
|
+
handleFlowAgentRestartCustomEvent(event: ICustomEvent): void;
|
|
38
43
|
/**
|
|
39
44
|
* 自定义事件 处理流程编排任务结果(增量更新节点状态)
|
|
40
45
|
*/
|
|
@@ -43,6 +48,11 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
43
48
|
* 自定义事件 处理流程编排任务开始
|
|
44
49
|
*/
|
|
45
50
|
handleFlowAgentStartCustomEvent(event: ICustomEvent): void;
|
|
51
|
+
/**
|
|
52
|
+
* 自定义事件 处理流程编排任务更新
|
|
53
|
+
*/
|
|
54
|
+
handleFlowAgentUpdateCustomEvent(event: ICustomEvent): void;
|
|
55
|
+
handleInfoCustomEvent(event: ICustomEvent): void;
|
|
46
56
|
/**
|
|
47
57
|
* 自定义事件 处理意图识别结束
|
|
48
58
|
*/
|
|
@@ -61,7 +71,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
61
71
|
handleKnowledgeRagTextContentCustomEvent(event: ICustomEvent): void;
|
|
62
72
|
/**
|
|
63
73
|
* 处理消息快照事件
|
|
64
|
-
*
|
|
74
|
+
* 用于同步多端消息状态;chat_completion 首帧会全量返回历史消息(含 created_at)
|
|
65
75
|
*/
|
|
66
76
|
handleMessagesSnapshotEvent(event: IMessagesSnapshotEvent): void;
|
|
67
77
|
/**
|
|
@@ -80,7 +90,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
80
90
|
/**
|
|
81
91
|
* 处理运行完成事件
|
|
82
92
|
*/
|
|
83
|
-
handleRunFinishedEvent(
|
|
93
|
+
handleRunFinishedEvent(event: IRunFinishedEvent): void;
|
|
84
94
|
/**
|
|
85
95
|
* 处理运行开始事件
|
|
86
96
|
*/
|
|
@@ -105,6 +115,10 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
105
115
|
* 自定义事件 处理临时消息,转换为 AI 文本消息
|
|
106
116
|
*/
|
|
107
117
|
handleTempMessageCustomEvent(event: ICustomEvent): void;
|
|
118
|
+
/**
|
|
119
|
+
* 自定义事件 处理审批结果
|
|
120
|
+
*/
|
|
121
|
+
handleApprovalResultCustomEvent(event: ICustomEvent): void;
|
|
108
122
|
/**
|
|
109
123
|
* 处理文本消息块事件
|
|
110
124
|
*/
|
|
@@ -119,6 +133,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
119
133
|
handleTextMessageEndEvent(event: ITextMessageEndEvent): void;
|
|
120
134
|
/**
|
|
121
135
|
* 处理文本消息开始事件
|
|
136
|
+
* 断线续传时会重放缓存事件:同 messageId 已存在则重置内容,避免重复气泡/文本翻倍
|
|
122
137
|
*/
|
|
123
138
|
handleTextMessageStartEvent(event: ITextMessageStartEvent): void;
|
|
124
139
|
/**
|