@blueking/chat-helper 0.0.12-beta.9 → 0.0.13-dev.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/README.md +21 -7
- package/dist/agent/type.d.ts +82 -0
- package/dist/agent/type.ts.js +5 -1
- package/dist/agent/use-agent.d.ts +229 -10
- package/dist/agent/use-agent.ts.js +365 -25
- package/dist/event/ag-ui.d.ts +4 -1
- package/dist/event/ag-ui.ts.js +76 -6
- package/dist/event/type.d.ts +14 -2
- package/dist/event/type.ts.js +2 -0
- package/dist/http/fetch/fetch.spec.d.ts +1 -0
- package/dist/http/fetch/fetch.ts.js +106 -22
- package/dist/http/index.d.ts +11 -5
- 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 +11 -5
- package/dist/http/module/message.d.ts +1 -1
- package/dist/http/module/message.ts.js +4 -3
- package/dist/http/module/session.d.ts +10 -5
- package/dist/http/module/session.ts.js +60 -3
- package/dist/http/transform/agent.d.ts +9 -1
- package/dist/http/transform/agent.spec.d.ts +1 -0
- package/dist/http/transform/agent.ts.js +29 -0
- package/dist/http/transform/message.spec.d.ts +1 -0
- package/dist/http/transform/message.ts.js +19 -5
- package/dist/index.d.ts +1194 -16
- package/dist/message/type.d.ts +35 -3
- package/dist/message/type.ts.js +16 -0
- package/dist/message/use-message.d.ts +316 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.ts.js +2 -1
- package/dist/session/pv-file-upload.d.ts +7 -0
- package/dist/session/pv-file-upload.spec.d.ts +1 -0
- package/dist/session/pv-file-upload.ts.js +64 -0
- package/dist/session/type.d.ts +57 -0
- package/dist/session/use-session.d.ts +644 -6
- package/dist/session/use-session.spec.d.ts +1 -0
- package/dist/session/use-session.ts.js +117 -10
- package/package.json +4 -2
|
@@ -79,10 +79,67 @@ 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, ApprovalInterruptTicketStatus, ResumeStatus, RunFinishedOutcomeType } from '../event/index.ts.js';
|
|
107
|
+
import { AGUIProtocol, ApprovalInterruptTicketStatus, EventType, ResumeStatus, RunFinishedOutcomeType } from '../event/index.ts.js';
|
|
84
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
|
+
/** 后端 attach_only 且无可接管流时抛出(见 StreamAttachUnavailableError) */ const isStreamAttachUnavailableError = (error)=>/No active or replayable stream/i.test(error.message);
|
|
115
|
+
/**
|
|
116
|
+
* 判断流式错误是否可静默重连。
|
|
117
|
+
* 不重试:Abort、attach 无流、401/403 等业务 4xx(408/429 除外);可重试:网络错误、5xx、无状态码的中断。
|
|
118
|
+
*/ const isRecoverableStreamError = (error)=>{
|
|
119
|
+
var _requestError_response;
|
|
120
|
+
if (error.name === 'AbortError') {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
if (isStreamAttachUnavailableError(error)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const requestError = error;
|
|
127
|
+
const statusFromResponse = (_requestError_response = requestError.response) === null || _requestError_response === void 0 ? void 0 : _requestError_response.status;
|
|
128
|
+
const statusFromMessage = error.message.match(/status code (\d+)/i);
|
|
129
|
+
const status = statusFromResponse !== null && statusFromResponse !== void 0 ? statusFromResponse : statusFromMessage ? Number(statusFromMessage[1]) : undefined;
|
|
130
|
+
if (status !== undefined) {
|
|
131
|
+
if (status === 408 || status === 429) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (status >= 400 && status < 500) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if (status >= 500) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
86
143
|
/**
|
|
87
144
|
* Agent 模块
|
|
88
145
|
* @param options - 配置选项
|
|
@@ -91,10 +148,40 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
91
148
|
const info = ref(null);
|
|
92
149
|
const isInfoLoading = ref(false);
|
|
93
150
|
const isChatting = ref(false);
|
|
151
|
+
const models = ref([]);
|
|
152
|
+
const isModelsLoading = ref(false);
|
|
94
153
|
let usedProtocol = protocol || new AGUIProtocol();
|
|
95
154
|
let chatAbortController = null;
|
|
96
155
|
let resumeAbortController = null;
|
|
97
156
|
let longPollTimer = null;
|
|
157
|
+
/** 用户主动中止(abortChat),禁止自动重连 */ let manualAbort = false;
|
|
158
|
+
/** 当前轮次已静默重连次数 */ let reconnectAttempt = 0;
|
|
159
|
+
/** 本轮流是否已收到 RUN_FINISHED */ let runFinished = false;
|
|
160
|
+
/** 流世代号:新开流时递增,用于忽略已被替换的旧 SSE 回调 */ let activeStreamId = 0;
|
|
161
|
+
let reconnectTimer = null;
|
|
162
|
+
let reconnectWaitResolve = null;
|
|
163
|
+
let activeStreamContext = null;
|
|
164
|
+
/**
|
|
165
|
+
* 获取可用模型列表,写入 models;失败时清空列表并抛出
|
|
166
|
+
*/ const getLlms = (params, config)=>{
|
|
167
|
+
var _mediator_http;
|
|
168
|
+
isModelsLoading.value = true;
|
|
169
|
+
const request = (_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.agent.getLlms(params, config);
|
|
170
|
+
if (!request) {
|
|
171
|
+
isModelsLoading.value = false;
|
|
172
|
+
models.value = [];
|
|
173
|
+
return Promise.resolve([]);
|
|
174
|
+
}
|
|
175
|
+
return request.then((res)=>{
|
|
176
|
+
models.value = res;
|
|
177
|
+
return res;
|
|
178
|
+
})['catch']((error)=>{
|
|
179
|
+
models.value = [];
|
|
180
|
+
throw error;
|
|
181
|
+
})['finally'](()=>{
|
|
182
|
+
isModelsLoading.value = false;
|
|
183
|
+
});
|
|
184
|
+
};
|
|
98
185
|
const getAgentInfo = ()=>{
|
|
99
186
|
var _mediator_http;
|
|
100
187
|
isInfoLoading.value = true;
|
|
@@ -123,23 +210,146 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
123
210
|
});
|
|
124
211
|
}
|
|
125
212
|
};
|
|
126
|
-
const userOperationStreamRequest = (sessionCode, operation, payload, config)=>{
|
|
213
|
+
const userOperationStreamRequest = (sessionCode, operation, payload, config, model)=>{
|
|
127
214
|
var _mediator_http;
|
|
128
215
|
return (_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.message.userOperation(sessionCode, operation, payload, config).then(()=>{
|
|
129
216
|
if (operation !== UserOperation.ApprovalCancel) {
|
|
130
217
|
streamRequest({
|
|
131
218
|
sessionCode,
|
|
132
|
-
config
|
|
219
|
+
config,
|
|
220
|
+
model
|
|
133
221
|
});
|
|
134
222
|
} else {
|
|
135
223
|
clearLongPollTimer();
|
|
136
|
-
pollResumeSession(sessionCode);
|
|
224
|
+
pollResumeSession(sessionCode, model);
|
|
137
225
|
}
|
|
138
226
|
});
|
|
139
227
|
};
|
|
228
|
+
const clearReconnectTimer = (continued = false)=>{
|
|
229
|
+
if (reconnectTimer) {
|
|
230
|
+
clearTimeout(reconnectTimer);
|
|
231
|
+
reconnectTimer = null;
|
|
232
|
+
}
|
|
233
|
+
if (reconnectWaitResolve) {
|
|
234
|
+
const resolve = reconnectWaitResolve;
|
|
235
|
+
reconnectWaitResolve = null;
|
|
236
|
+
resolve(continued);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const waitForReconnectDelay = (ms)=>new Promise((resolve)=>{
|
|
240
|
+
reconnectWaitResolve = resolve;
|
|
241
|
+
reconnectTimer = setTimeout(()=>{
|
|
242
|
+
reconnectTimer = null;
|
|
243
|
+
reconnectWaitResolve = null;
|
|
244
|
+
resolve(true);
|
|
245
|
+
}, ms);
|
|
246
|
+
});
|
|
247
|
+
const resetStreamReconnectState = ()=>{
|
|
248
|
+
manualAbort = false;
|
|
249
|
+
reconnectAttempt = 0;
|
|
250
|
+
runFinished = false;
|
|
251
|
+
clearReconnectTimer(false);
|
|
252
|
+
};
|
|
253
|
+
/** 裁掉尾部尚未完成的非用户消息,避免断线重放时重复气泡 */ const pruneTrailingIncompleteMessages = ()=>{
|
|
254
|
+
var _mediator_message;
|
|
255
|
+
const list = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value;
|
|
256
|
+
if (!(list === null || list === void 0 ? void 0 : list.length)) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
while(list.length > 0){
|
|
260
|
+
const last = list[list.length - 1];
|
|
261
|
+
if (last.role === MessageRole.User) {
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
if (last.status === MessageStatus.Streaming || last.status === MessageStatus.Pending) {
|
|
265
|
+
list.pop();
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const isSameActiveSession = (sessionCode)=>{
|
|
272
|
+
var _mediator_session_current_value, _mediator_session_current, _mediator_session;
|
|
273
|
+
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);
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* 尝试静默重连。
|
|
277
|
+
* @param streamId - 发起重连的流世代;任一 await 后若已被新流/abort 取代则立即退出,避免 abort 掉更新流
|
|
278
|
+
* @returns reconnected | finished(服务端已结束)| failed(需对外报错或中止)
|
|
279
|
+
*/ const attemptSilentReconnect = function() {
|
|
280
|
+
var _ref = _async_to_generator(function*(sessionCode, streamId) {
|
|
281
|
+
var _mediator_session_current_value, _mediator_session, _mediator_session_current_value1, _mediator_session1, _mediator_message_list_value_at, _mediator_message;
|
|
282
|
+
const isOwnerStream = ()=>streamId === activeStreamId && !manualAbort;
|
|
283
|
+
if (!isOwnerStream() || !isSameActiveSession(sessionCode)) {
|
|
284
|
+
return 'failed';
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
var _mediator_session2;
|
|
288
|
+
yield (_mediator_session2 = mediator.session) === null || _mediator_session2 === void 0 ? void 0 : _mediator_session2.getSession(sessionCode);
|
|
289
|
+
} catch (e) {
|
|
290
|
+
// 状态刷新失败时沿用本地 session.status
|
|
291
|
+
}
|
|
292
|
+
if (!isOwnerStream() || !isSameActiveSession(sessionCode)) {
|
|
293
|
+
return 'failed';
|
|
294
|
+
}
|
|
295
|
+
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) {
|
|
296
|
+
return 'finished';
|
|
297
|
+
}
|
|
298
|
+
if (reconnectAttempt >= MAX_RECONNECT_ATTEMPTS) {
|
|
299
|
+
return 'failed';
|
|
300
|
+
}
|
|
301
|
+
reconnectAttempt += 1;
|
|
302
|
+
// 静默重连期间保持「生成中」态
|
|
303
|
+
isChatting.value = true;
|
|
304
|
+
const delayMs = getReconnectDelayMs(reconnectAttempt);
|
|
305
|
+
const waited = yield waitForReconnectDelay(delayMs);
|
|
306
|
+
if (!waited || !isOwnerStream() || !isSameActiveSession(sessionCode)) {
|
|
307
|
+
return 'failed';
|
|
308
|
+
}
|
|
309
|
+
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) {
|
|
310
|
+
return 'finished';
|
|
311
|
+
}
|
|
312
|
+
// 发起新流前再校验一次:防止 await 后窗口期被新用户请求抢走 activeStreamId
|
|
313
|
+
if (!isOwnerStream()) {
|
|
314
|
+
return 'failed';
|
|
315
|
+
}
|
|
316
|
+
pruneTrailingIncompleteMessages();
|
|
317
|
+
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;
|
|
318
|
+
const ctx = activeStreamContext;
|
|
319
|
+
streamRequest({
|
|
320
|
+
sessionCode,
|
|
321
|
+
model: ctx === null || ctx === void 0 ? void 0 : ctx.model,
|
|
322
|
+
url: ctx === null || ctx === void 0 ? void 0 : ctx.url,
|
|
323
|
+
config: ctx === null || ctx === void 0 ? void 0 : ctx.config,
|
|
324
|
+
lastMessageId: lastMessageId !== undefined ? String(lastMessageId) : undefined,
|
|
325
|
+
isReconnect: true,
|
|
326
|
+
/** 静默重连:仅接管已有流,禁止后端新建 producer */ streamMode: 'attach'
|
|
327
|
+
});
|
|
328
|
+
return 'reconnected';
|
|
329
|
+
});
|
|
330
|
+
return function attemptSilentReconnect(sessionCode, streamId) {
|
|
331
|
+
return _ref.apply(this, arguments);
|
|
332
|
+
};
|
|
333
|
+
}();
|
|
140
334
|
const streamRequest = function() {
|
|
141
|
-
var _ref = _async_to_generator(function*({ sessionCode, url, config, resume, input, lastMessageId }) {
|
|
142
|
-
var _mediator_http;
|
|
335
|
+
var _ref = _async_to_generator(function*({ sessionCode, model, url, config, resume, input, lastMessageId, isReconnect = false, /** start 可启动新一轮执行;attach 仅接管/回放已有流 */ streamMode = 'start' }) {
|
|
336
|
+
var _previousController_abort, _mediator_http;
|
|
337
|
+
if (!isReconnect) {
|
|
338
|
+
resetStreamReconnectState();
|
|
339
|
+
}
|
|
340
|
+
activeStreamContext = {
|
|
341
|
+
sessionCode,
|
|
342
|
+
model,
|
|
343
|
+
url,
|
|
344
|
+
config,
|
|
345
|
+
streamMode
|
|
346
|
+
};
|
|
347
|
+
// 先递增世代再 abort 旧连接,避免旧流 onDone 误触发二次重连
|
|
348
|
+
const streamId = ++activeStreamId;
|
|
349
|
+
const previousController = chatAbortController;
|
|
350
|
+
chatAbortController = new AbortController();
|
|
351
|
+
previousController === null || previousController === void 0 ? void 0 : (_previousController_abort = previousController.abort) === null || _previousController_abort === void 0 ? void 0 : _previousController_abort.call(previousController);
|
|
352
|
+
const isActiveStream = ()=>streamId === activeStreamId;
|
|
143
353
|
// ag-ui 协议需要注入消息模块
|
|
144
354
|
if (usedProtocol instanceof AGUIProtocol) {
|
|
145
355
|
usedProtocol.injectMessageModule(mediator.message);
|
|
@@ -154,9 +364,11 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
154
364
|
sessionCode
|
|
155
365
|
});
|
|
156
366
|
}
|
|
157
|
-
|
|
158
|
-
const onDone = ()=>{
|
|
367
|
+
const finishSuccessfully = ()=>{
|
|
159
368
|
var _usedProtocol_onDone;
|
|
369
|
+
if (!isActiveStream()) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
160
372
|
isChatting.value = false;
|
|
161
373
|
(_usedProtocol_onDone = usedProtocol.onDone) === null || _usedProtocol_onDone === void 0 ? void 0 : _usedProtocol_onDone.call(usedProtocol);
|
|
162
374
|
if (input) {
|
|
@@ -166,48 +378,151 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
166
378
|
var _mediator_message;
|
|
167
379
|
const lastUserMessage = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value.findLast((item)=>item.role === MessageRole.User);
|
|
168
380
|
const lastApiUserMessage = res.findLast((item)=>item.role === MessageRole.User);
|
|
169
|
-
lastUserMessage
|
|
381
|
+
if (lastUserMessage && lastApiUserMessage) {
|
|
382
|
+
lastUserMessage.id = lastApiUserMessage.id;
|
|
383
|
+
}
|
|
170
384
|
});
|
|
171
385
|
}
|
|
172
386
|
// 轮询接口,判断是否可以继续聊天
|
|
173
387
|
pollResumeSession(sessionCode);
|
|
174
388
|
};
|
|
175
|
-
const
|
|
389
|
+
const failWithError = (error)=>{
|
|
176
390
|
var _usedProtocol_onError;
|
|
391
|
+
if (!isActiveStream()) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
177
394
|
isChatting.value = false;
|
|
178
395
|
(_usedProtocol_onError = usedProtocol.onError) === null || _usedProtocol_onError === void 0 ? void 0 : _usedProtocol_onError.call(usedProtocol, error);
|
|
179
396
|
};
|
|
397
|
+
// 事件代理
|
|
398
|
+
const onDone = ()=>{
|
|
399
|
+
if (!isActiveStream()) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
// 用户 abort:本地状态已在 abortChat 结算,勿走 completion/poll
|
|
403
|
+
if (manualAbort) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (runFinished) {
|
|
407
|
+
finishSuccessfully();
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
// 连接被干净掐断且未收到终端事件(RUN_FINISHED / RUN_ERROR):尝试静默重连
|
|
411
|
+
void attemptSilentReconnect(sessionCode, streamId).then((result)=>{
|
|
412
|
+
if (!isActiveStream()) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (result === 'reconnected') {
|
|
416
|
+
// 保持 isChatting=true,不展示错误
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (result === 'finished') {
|
|
420
|
+
finishSuccessfully();
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
// abort / 切会话导致的失败:静默结束,不展示错误气泡
|
|
424
|
+
if (manualAbort || !isSameActiveSession(sessionCode)) {
|
|
425
|
+
isChatting.value = false;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
failWithError(new Error('Connection lost, please try again'));
|
|
429
|
+
});
|
|
430
|
+
};
|
|
431
|
+
const onError = (error)=>{
|
|
432
|
+
if (!isActiveStream() || manualAbort) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
// attach 时后端无可接管流:视为本轮已结束,勿静默重连空转
|
|
436
|
+
if (streamMode === 'attach' && isStreamAttachUnavailableError(error)) {
|
|
437
|
+
var _mediator_session;
|
|
438
|
+
const settleAttachUnavailable = ()=>{
|
|
439
|
+
var _mediator_session_current_value, _mediator_session;
|
|
440
|
+
if (!isActiveStream() || manualAbort || !isSameActiveSession(sessionCode)) {
|
|
441
|
+
if (isActiveStream()) {
|
|
442
|
+
isChatting.value = false;
|
|
443
|
+
}
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
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) {
|
|
447
|
+
finishSuccessfully();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
isChatting.value = false;
|
|
451
|
+
};
|
|
452
|
+
const refresh = (_mediator_session = mediator.session) === null || _mediator_session === void 0 ? void 0 : _mediator_session.getSession(sessionCode);
|
|
453
|
+
if (refresh) {
|
|
454
|
+
void refresh.catch(()=>undefined).then(settleAttachUnavailable);
|
|
455
|
+
} else {
|
|
456
|
+
settleAttachUnavailable();
|
|
457
|
+
}
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (!isRecoverableStreamError(error)) {
|
|
461
|
+
failWithError(error);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
void attemptSilentReconnect(sessionCode, streamId).then((result)=>{
|
|
465
|
+
if (!isActiveStream()) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (result === 'reconnected') {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (result === 'finished') {
|
|
472
|
+
finishSuccessfully();
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (manualAbort || !isSameActiveSession(sessionCode)) {
|
|
476
|
+
isChatting.value = false;
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
failWithError(error);
|
|
480
|
+
});
|
|
481
|
+
};
|
|
180
482
|
const onMessage = (event)=>{
|
|
181
483
|
var _usedProtocol_onMessage;
|
|
484
|
+
if (!isActiveStream()) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const typedEvent = event;
|
|
488
|
+
// RUN_FINISHED / RUN_ERROR 均为终端事件:关流后走正常收尾,勿静默重连
|
|
489
|
+
// (用户 stop 后后端推 RUN_ERROR「用户已取消」,而非 RUN_FINISHED)
|
|
490
|
+
if ((typedEvent === null || typedEvent === void 0 ? void 0 : typedEvent.type) === EventType.RunFinished || (typedEvent === null || typedEvent === void 0 ? void 0 : typedEvent.type) === EventType.RunError) {
|
|
491
|
+
runFinished = true;
|
|
492
|
+
}
|
|
182
493
|
(_usedProtocol_onMessage = usedProtocol.onMessage) === null || _usedProtocol_onMessage === void 0 ? void 0 : _usedProtocol_onMessage.call(usedProtocol, event);
|
|
183
494
|
};
|
|
184
495
|
const onStart = ()=>{
|
|
185
496
|
var _usedProtocol_onStart;
|
|
497
|
+
if (!isActiveStream()) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
186
500
|
isChatting.value = true;
|
|
187
501
|
(_usedProtocol_onStart = usedProtocol.onStart) === null || _usedProtocol_onStart === void 0 ? void 0 : _usedProtocol_onStart.call(usedProtocol);
|
|
188
502
|
};
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
// 发起聊天
|
|
192
|
-
void ((_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.fetchClient.streamRequest(_object_spread({
|
|
503
|
+
// 发起聊天(controller / 回调必须在 ...config 之后,防止被覆盖)
|
|
504
|
+
void ((_mediator_http = mediator.http) === null || _mediator_http === void 0 ? void 0 : _mediator_http.fetchClient.streamRequest(_object_spread_props(_object_spread({
|
|
193
505
|
url: url || 'chat_completion/',
|
|
194
506
|
method: 'POST',
|
|
195
507
|
data: {
|
|
196
508
|
session_code: sessionCode,
|
|
509
|
+
model,
|
|
197
510
|
input,
|
|
198
511
|
execute_kwargs: {
|
|
199
512
|
stream: true,
|
|
513
|
+
stream_mode: streamMode,
|
|
200
514
|
persist_input: !!input,
|
|
201
515
|
last_message_id: lastMessageId,
|
|
202
516
|
resume
|
|
203
517
|
}
|
|
204
|
-
}
|
|
518
|
+
}
|
|
519
|
+
}, config), {
|
|
205
520
|
controller: chatAbortController,
|
|
206
521
|
onDone,
|
|
207
522
|
onError,
|
|
208
523
|
onMessage,
|
|
209
524
|
onStart
|
|
210
|
-
}
|
|
525
|
+
})).catch(()=>{
|
|
211
526
|
// 非 abort 错误已通过 onError 回调处理;abort 为正常结束
|
|
212
527
|
}));
|
|
213
528
|
});
|
|
@@ -222,8 +537,9 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
222
537
|
* @param url - 请求 URL(可选)
|
|
223
538
|
* @param config - 请求配置(可选)
|
|
224
539
|
* @param property - 消息属性,用于传递引用内容或快捷键相关信息(可选)
|
|
540
|
+
* @param model - 模型标识(可选)
|
|
225
541
|
*/ const chat = function() {
|
|
226
|
-
var _ref = _async_to_generator(function*(userInput, sessionCode, url, config, property) {
|
|
542
|
+
var _ref = _async_to_generator(function*(userInput, sessionCode, url, config, property, model) {
|
|
227
543
|
var _mediator_message;
|
|
228
544
|
// 先新增一个 message
|
|
229
545
|
yield (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.createAndPlusMessage(_object_spread({
|
|
@@ -237,11 +553,12 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
237
553
|
// 发起聊天
|
|
238
554
|
streamRequest({
|
|
239
555
|
sessionCode,
|
|
556
|
+
model,
|
|
240
557
|
url,
|
|
241
558
|
config
|
|
242
559
|
});
|
|
243
560
|
});
|
|
244
|
-
return function chat(userInput, sessionCode, url, config, property) {
|
|
561
|
+
return function chat(userInput, sessionCode, url, config, property, model) {
|
|
245
562
|
return _ref.apply(this, arguments);
|
|
246
563
|
};
|
|
247
564
|
}();
|
|
@@ -251,16 +568,19 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
251
568
|
* @param sessionCode - 会话代码
|
|
252
569
|
* @param url - 请求 URL(可选)
|
|
253
570
|
* @param config - 请求配置(可选)
|
|
254
|
-
|
|
571
|
+
* @param model - 模型标识(可选)
|
|
572
|
+
*/ const resumeStreamingChat = (sessionCode, url, config, model)=>{
|
|
255
573
|
var _mediator_session_current_value, _mediator_session;
|
|
256
574
|
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) {
|
|
257
575
|
var _mediator_message_list_value_at, _mediator_message;
|
|
258
576
|
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;
|
|
259
577
|
streamRequest({
|
|
260
578
|
sessionCode,
|
|
579
|
+
model,
|
|
261
580
|
url,
|
|
262
581
|
config,
|
|
263
|
-
lastMessageId
|
|
582
|
+
lastMessageId,
|
|
583
|
+
/** 切会话/刷新恢复:仅接管已有流 */ streamMode: 'attach'
|
|
264
584
|
});
|
|
265
585
|
}
|
|
266
586
|
};
|
|
@@ -268,7 +588,7 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
268
588
|
* 轮询接口,判断是否可以继续聊天
|
|
269
589
|
* @param sessionCode - 会话编码
|
|
270
590
|
* @returns 是否可以继续聊天
|
|
271
|
-
*/ const pollResumeSession = (sessionCode)=>{
|
|
591
|
+
*/ const pollResumeSession = (sessionCode, model)=>{
|
|
272
592
|
var _mediator_message, _lastMessage_content_outcome, _lastMessage_content;
|
|
273
593
|
const lastMessage = (_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value.at(-1);
|
|
274
594
|
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)=>{
|
|
@@ -295,6 +615,7 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
295
615
|
// 可以继续聊天,重新发起聊天(携带 execute_kwargs.resume 通知后端恢复中断)
|
|
296
616
|
streamRequest({
|
|
297
617
|
sessionCode,
|
|
618
|
+
model,
|
|
298
619
|
resume: {
|
|
299
620
|
interruptId: pendingApprovalInterrupt.id,
|
|
300
621
|
status: ResumeStatus.Resolved
|
|
@@ -305,7 +626,7 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
305
626
|
var _mediator_session_current_value, _mediator_session_current, _mediator_session;
|
|
306
627
|
// 如果会话不匹配,则不继续轮询
|
|
307
628
|
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;
|
|
308
|
-
pollResumeSession(sessionCode);
|
|
629
|
+
pollResumeSession(sessionCode, model);
|
|
309
630
|
}, 10000);
|
|
310
631
|
}
|
|
311
632
|
});
|
|
@@ -320,8 +641,15 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
320
641
|
};
|
|
321
642
|
/**
|
|
322
643
|
* 中止聊天(纯前端中止,后端继续处理)
|
|
644
|
+
* 会使当前流世代失效,避免 abort 后的 onDone 误触发 finishSuccessfully / pollResumeSession
|
|
323
645
|
*/ const abortChat = ()=>{
|
|
324
646
|
var _chatAbortController_abort;
|
|
647
|
+
manualAbort = true;
|
|
648
|
+
// 先失效世代,再 abort:FetchClient 同步触发的 onDone 会因 isActiveStream=false 直接返回
|
|
649
|
+
activeStreamId += 1;
|
|
650
|
+
clearReconnectTimer(false);
|
|
651
|
+
clearLongPollTimer();
|
|
652
|
+
isChatting.value = false;
|
|
325
653
|
chatAbortController === null || chatAbortController === void 0 ? void 0 : (_chatAbortController_abort = chatAbortController.abort) === null || _chatAbortController_abort === void 0 ? void 0 : _chatAbortController_abort.call(chatAbortController);
|
|
326
654
|
chatAbortController = null;
|
|
327
655
|
};
|
|
@@ -346,8 +674,9 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
346
674
|
* @param newContent - 新内容(可选,不传则使用原消息内容;支持多模态)
|
|
347
675
|
* @param url - 请求 URL(可选)
|
|
348
676
|
* @param config - 请求配置(可选)
|
|
677
|
+
* @param model - 模型标识(可选)
|
|
349
678
|
*/ const resendMessage = function() {
|
|
350
|
-
var _ref = _async_to_generator(function*(messageId, sessionCode, newContent, url, config) {
|
|
679
|
+
var _ref = _async_to_generator(function*(messageId, sessionCode, newContent, url, config, model) {
|
|
351
680
|
var _mediator_message, _mediator_message1, _mediator_message2;
|
|
352
681
|
const messages = ((_mediator_message = mediator.message) === null || _mediator_message === void 0 ? void 0 : _mediator_message.list.value) || [];
|
|
353
682
|
// 1. 找到目标用户消息
|
|
@@ -380,6 +709,7 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
380
709
|
// 6. 立即发起流式请求(不等待删除和创建的 API 完成)
|
|
381
710
|
streamRequest({
|
|
382
711
|
sessionCode,
|
|
712
|
+
model,
|
|
383
713
|
url,
|
|
384
714
|
config
|
|
385
715
|
});
|
|
@@ -391,20 +721,29 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
391
721
|
console.error('[resendMessage] API error:', error);
|
|
392
722
|
});
|
|
393
723
|
});
|
|
394
|
-
return function resendMessage(messageId, sessionCode, newContent, url, config) {
|
|
724
|
+
return function resendMessage(messageId, sessionCode, newContent, url, config, model) {
|
|
395
725
|
return _ref.apply(this, arguments);
|
|
396
726
|
};
|
|
397
727
|
}();
|
|
398
728
|
const reset = (protocol)=>{
|
|
399
|
-
|
|
729
|
+
abortChat();
|
|
730
|
+
// 重置状态(保留 manualAbort=true,避免 abort 异步 onDone 误触发重连;下次 streamRequest 会复位)
|
|
400
731
|
usedProtocol = protocol || new AGUIProtocol();
|
|
401
732
|
info.value = null;
|
|
402
733
|
isInfoLoading.value = false;
|
|
734
|
+
isChatting.value = false;
|
|
735
|
+
models.value = [];
|
|
736
|
+
isModelsLoading.value = false;
|
|
737
|
+
activeStreamContext = null;
|
|
738
|
+
reconnectAttempt = 0;
|
|
739
|
+
runFinished = false;
|
|
403
740
|
};
|
|
404
741
|
return {
|
|
405
742
|
info,
|
|
406
743
|
isInfoLoading,
|
|
407
744
|
isChatting,
|
|
745
|
+
models,
|
|
746
|
+
isModelsLoading,
|
|
408
747
|
chat,
|
|
409
748
|
handleRole,
|
|
410
749
|
resendMessage,
|
|
@@ -412,6 +751,7 @@ import { SessionStatus } from '../session/type.ts.js';
|
|
|
412
751
|
abortChat,
|
|
413
752
|
stopChat,
|
|
414
753
|
getAgentInfo,
|
|
754
|
+
getLlms,
|
|
415
755
|
reset,
|
|
416
756
|
pollResumeSession,
|
|
417
757
|
clearLongPollTimer,
|
package/dist/event/ag-ui.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
27
27
|
* 记录活动的完整状态
|
|
28
28
|
*/
|
|
29
29
|
handleActivitySnapshotEvent(event: IActivitySnapshotEvent): void;
|
|
30
|
+
handleArtifactsGeneratedCustomEvent(event: ICustomEvent): void;
|
|
30
31
|
/**
|
|
31
32
|
* 处理自定义事件
|
|
32
33
|
*/
|
|
@@ -51,6 +52,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
51
52
|
* 自定义事件 处理流程编排任务更新
|
|
52
53
|
*/
|
|
53
54
|
handleFlowAgentUpdateCustomEvent(event: ICustomEvent): void;
|
|
55
|
+
handleInfoCustomEvent(event: ICustomEvent): void;
|
|
54
56
|
/**
|
|
55
57
|
* 自定义事件 处理意图识别结束
|
|
56
58
|
*/
|
|
@@ -69,7 +71,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
69
71
|
handleKnowledgeRagTextContentCustomEvent(event: ICustomEvent): void;
|
|
70
72
|
/**
|
|
71
73
|
* 处理消息快照事件
|
|
72
|
-
*
|
|
74
|
+
* 用于同步多端消息状态;chat_completion 首帧会全量返回历史消息(含 created_at)
|
|
73
75
|
*/
|
|
74
76
|
handleMessagesSnapshotEvent(event: IMessagesSnapshotEvent): void;
|
|
75
77
|
/**
|
|
@@ -131,6 +133,7 @@ export declare class AGUIProtocol implements ISSEProtocol {
|
|
|
131
133
|
handleTextMessageEndEvent(event: ITextMessageEndEvent): void;
|
|
132
134
|
/**
|
|
133
135
|
* 处理文本消息开始事件
|
|
136
|
+
* 断线续传时会重放缓存事件:同 messageId 已存在则重置内容,避免重复气泡/文本翻倍
|
|
134
137
|
*/
|
|
135
138
|
handleTextMessageStartEvent(event: ITextMessageStartEvent): void;
|
|
136
139
|
/**
|