@yeaft/webchat-agent 0.0.75 → 0.0.77
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/crew.js +89 -4
- package/package.json +1 -1
package/crew.js
CHANGED
|
@@ -111,6 +111,15 @@ async function saveSessionMeta(session) {
|
|
|
111
111
|
username: session.username
|
|
112
112
|
};
|
|
113
113
|
await fs.writeFile(join(session.sharedDir, 'session.json'), JSON.stringify(meta, null, 2));
|
|
114
|
+
// 保存 UI 消息历史(用于恢复时重放)
|
|
115
|
+
if (session.uiMessages && session.uiMessages.length > 0) {
|
|
116
|
+
// 清理 _streaming 标记后保存
|
|
117
|
+
const cleaned = session.uiMessages.map(m => {
|
|
118
|
+
const { _streaming, ...rest } = m;
|
|
119
|
+
return rest;
|
|
120
|
+
});
|
|
121
|
+
await fs.writeFile(join(session.sharedDir, 'messages.json'), JSON.stringify(cleaned));
|
|
122
|
+
}
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
async function loadSessionMeta(sharedDir) {
|
|
@@ -118,6 +127,11 @@ async function loadSessionMeta(sharedDir) {
|
|
|
118
127
|
catch { return null; }
|
|
119
128
|
}
|
|
120
129
|
|
|
130
|
+
async function loadSessionMessages(sharedDir) {
|
|
131
|
+
try { return JSON.parse(await fs.readFile(join(sharedDir, 'messages.json'), 'utf-8')); }
|
|
132
|
+
catch { return []; }
|
|
133
|
+
}
|
|
134
|
+
|
|
121
135
|
// =====================================================================
|
|
122
136
|
// List & Resume Crew Sessions
|
|
123
137
|
// =====================================================================
|
|
@@ -155,6 +169,10 @@ export async function resumeCrewSession(msg) {
|
|
|
155
169
|
if (crewSessions.has(sessionId)) {
|
|
156
170
|
const session = crewSessions.get(sessionId);
|
|
157
171
|
const roles = Array.from(session.roles.values());
|
|
172
|
+
// 如果内存中没有 uiMessages,尝试从磁盘加载
|
|
173
|
+
if ((!session.uiMessages || session.uiMessages.length === 0) && session.sharedDir) {
|
|
174
|
+
session.uiMessages = await loadSessionMessages(session.sharedDir);
|
|
175
|
+
}
|
|
158
176
|
sendCrewMessage({
|
|
159
177
|
type: 'crew_session_restored',
|
|
160
178
|
sessionId,
|
|
@@ -168,7 +186,8 @@ export async function resumeCrewSession(msg) {
|
|
|
168
186
|
decisionMaker: session.decisionMaker,
|
|
169
187
|
maxRounds: session.maxRounds,
|
|
170
188
|
userId: session.userId,
|
|
171
|
-
username: session.username
|
|
189
|
+
username: session.username,
|
|
190
|
+
uiMessages: session.uiMessages || []
|
|
172
191
|
});
|
|
173
192
|
sendStatusUpdate(session);
|
|
174
193
|
return;
|
|
@@ -205,6 +224,7 @@ export async function resumeCrewSession(msg) {
|
|
|
205
224
|
maxRounds: meta.maxRounds || 20,
|
|
206
225
|
costUsd: 0,
|
|
207
226
|
messageHistory: [],
|
|
227
|
+
uiMessages: [], // will be loaded from messages.json
|
|
208
228
|
humanMessageQueue: [],
|
|
209
229
|
waitingHumanContext: null,
|
|
210
230
|
pendingRoute: null,
|
|
@@ -214,6 +234,9 @@ export async function resumeCrewSession(msg) {
|
|
|
214
234
|
};
|
|
215
235
|
crewSessions.set(sessionId, session);
|
|
216
236
|
|
|
237
|
+
// 加载 UI 消息历史
|
|
238
|
+
session.uiMessages = await loadSessionMessages(session.sharedDir);
|
|
239
|
+
|
|
217
240
|
// 通知 server
|
|
218
241
|
sendCrewMessage({
|
|
219
242
|
type: 'crew_session_restored',
|
|
@@ -228,7 +251,8 @@ export async function resumeCrewSession(msg) {
|
|
|
228
251
|
decisionMaker,
|
|
229
252
|
maxRounds: session.maxRounds,
|
|
230
253
|
userId: session.userId,
|
|
231
|
-
username: session.username
|
|
254
|
+
username: session.username,
|
|
255
|
+
uiMessages: session.uiMessages
|
|
232
256
|
});
|
|
233
257
|
sendStatusUpdate(session);
|
|
234
258
|
|
|
@@ -283,6 +307,7 @@ export async function createCrewSession(msg) {
|
|
|
283
307
|
maxRounds,
|
|
284
308
|
costUsd: 0,
|
|
285
309
|
messageHistory: [], // 群聊消息历史
|
|
310
|
+
uiMessages: [], // 精简的 UI 消息历史(用于恢复时重放)
|
|
286
311
|
humanMessageQueue: [], // 人的消息排队
|
|
287
312
|
waitingHumanContext: null, // { fromRole, reason, message }
|
|
288
313
|
pendingRoute: null, // { fromRole, route } — 暂停时未完成的路由
|
|
@@ -764,6 +789,10 @@ async function processRoleOutput(session, roleName, roleQuery, roleState) {
|
|
|
764
789
|
// ★ Turn 完成!
|
|
765
790
|
console.log(`[Crew] ${roleName} turn completed`);
|
|
766
791
|
|
|
792
|
+
// 结束 uiMessages 中最后一条的 streaming 标记
|
|
793
|
+
const lastUi = session.uiMessages[session.uiMessages.length - 1];
|
|
794
|
+
if (lastUi && lastUi._streaming) delete lastUi._streaming;
|
|
795
|
+
|
|
767
796
|
// 更新费用
|
|
768
797
|
if (message.total_cost_usd) {
|
|
769
798
|
session.costUsd += message.total_cost_usd;
|
|
@@ -1003,6 +1032,12 @@ export async function handleCrewHumanInput(msg) {
|
|
|
1003
1032
|
}
|
|
1004
1033
|
|
|
1005
1034
|
// 注意:不在这里发送人的消息到 Web(前端已本地添加,避免重复)
|
|
1035
|
+
// 但需要记录到 uiMessages 用于恢复时重放
|
|
1036
|
+
session.uiMessages.push({
|
|
1037
|
+
role: 'human', roleIcon: 'H', roleName: '你',
|
|
1038
|
+
type: 'text', content,
|
|
1039
|
+
timestamp: Date.now()
|
|
1040
|
+
});
|
|
1006
1041
|
|
|
1007
1042
|
// 如果在等待人工介入
|
|
1008
1043
|
if (session.status === 'waiting_human') {
|
|
@@ -1246,17 +1281,67 @@ function sendCrewMessage(msg) {
|
|
|
1246
1281
|
*/
|
|
1247
1282
|
function sendCrewOutput(session, roleName, outputType, rawMessage, extra = {}) {
|
|
1248
1283
|
const role = session.roles.get(roleName);
|
|
1284
|
+
const roleIcon = role?.icon || (roleName === 'human' ? 'H' : roleName === 'system' ? 'S' : 'A');
|
|
1285
|
+
const displayName = role?.displayName || roleName;
|
|
1249
1286
|
|
|
1250
1287
|
sendCrewMessage({
|
|
1251
1288
|
type: 'crew_output',
|
|
1252
1289
|
sessionId: session.id,
|
|
1253
1290
|
role: roleName,
|
|
1254
|
-
roleIcon
|
|
1255
|
-
roleName:
|
|
1291
|
+
roleIcon,
|
|
1292
|
+
roleName: displayName,
|
|
1256
1293
|
outputType, // 'text' | 'tool_use' | 'tool_result' | 'route' | 'system'
|
|
1257
1294
|
data: rawMessage,
|
|
1258
1295
|
...extra
|
|
1259
1296
|
});
|
|
1297
|
+
|
|
1298
|
+
// ★ 记录精简 UI 消息用于恢复(跳过 tool_use/tool_result,只记录可见内容)
|
|
1299
|
+
if (outputType === 'text') {
|
|
1300
|
+
const content = rawMessage?.message?.content;
|
|
1301
|
+
let text = '';
|
|
1302
|
+
if (typeof content === 'string') {
|
|
1303
|
+
text = content;
|
|
1304
|
+
} else if (Array.isArray(content)) {
|
|
1305
|
+
text = content.filter(b => b.type === 'text').map(b => b.text).join('');
|
|
1306
|
+
}
|
|
1307
|
+
if (!text) return;
|
|
1308
|
+
// 合并同一角色的连续文本
|
|
1309
|
+
const last = session.uiMessages[session.uiMessages.length - 1];
|
|
1310
|
+
if (last && last.role === roleName && last.type === 'text' && last._streaming) {
|
|
1311
|
+
last.content += text;
|
|
1312
|
+
} else {
|
|
1313
|
+
session.uiMessages.push({
|
|
1314
|
+
role: roleName, roleIcon, roleName: displayName,
|
|
1315
|
+
type: 'text', content: text, _streaming: true,
|
|
1316
|
+
timestamp: Date.now()
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
} else if (outputType === 'route') {
|
|
1320
|
+
// 结束前一条消息的 streaming
|
|
1321
|
+
const last = session.uiMessages[session.uiMessages.length - 1];
|
|
1322
|
+
if (last && last._streaming) delete last._streaming;
|
|
1323
|
+
session.uiMessages.push({
|
|
1324
|
+
role: roleName, roleIcon, roleName: displayName,
|
|
1325
|
+
type: 'route', routeTo: extra.routeTo,
|
|
1326
|
+
content: `→ @${extra.routeTo} ${extra.routeSummary || ''}`,
|
|
1327
|
+
timestamp: Date.now()
|
|
1328
|
+
});
|
|
1329
|
+
} else if (outputType === 'system') {
|
|
1330
|
+
const content = rawMessage?.message?.content;
|
|
1331
|
+
let text = '';
|
|
1332
|
+
if (typeof content === 'string') {
|
|
1333
|
+
text = content;
|
|
1334
|
+
} else if (Array.isArray(content)) {
|
|
1335
|
+
text = content.filter(b => b.type === 'text').map(b => b.text).join('');
|
|
1336
|
+
}
|
|
1337
|
+
if (!text) return;
|
|
1338
|
+
session.uiMessages.push({
|
|
1339
|
+
role: roleName, roleIcon, roleName: displayName,
|
|
1340
|
+
type: 'system', content: text,
|
|
1341
|
+
timestamp: Date.now()
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
// tool_use 和 tool_result 不记录(太大,恢复时不需要)
|
|
1260
1345
|
}
|
|
1261
1346
|
|
|
1262
1347
|
/**
|