@yeaft/webchat-agent 0.1.377 → 0.1.378
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/control.js +14 -4
- package/crew/human-interaction.js +14 -4
- package/crew/role-management.js +28 -8
- package/crew/routing.js +25 -4
- package/package.json +1 -1
package/crew/control.js
CHANGED
|
@@ -19,13 +19,23 @@ import { processHumanQueue } from './human-interaction.js';
|
|
|
19
19
|
*/
|
|
20
20
|
export async function handleCrewControl(msg) {
|
|
21
21
|
// Lazy import to avoid circular dependency
|
|
22
|
-
const { crewSessions } = await import('./session.js');
|
|
22
|
+
const { crewSessions, resumeCrewSession } = await import('./session.js');
|
|
23
23
|
|
|
24
24
|
const { sessionId, action, targetRole } = msg;
|
|
25
|
-
|
|
25
|
+
let session = crewSessions.get(sessionId);
|
|
26
26
|
if (!session) {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
// Auto-resume: try to restore from disk before giving up
|
|
28
|
+
console.log(`[Crew] Session ${sessionId} not in memory, attempting auto-resume...`);
|
|
29
|
+
try {
|
|
30
|
+
await resumeCrewSession({ sessionId });
|
|
31
|
+
session = crewSessions.get(sessionId);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.warn(`[Crew] Auto-resume failed for ${sessionId}:`, e.message);
|
|
34
|
+
}
|
|
35
|
+
if (!session) {
|
|
36
|
+
console.warn(`[Crew] Session not found: ${sessionId} (even after auto-resume)`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
switch (action) {
|
|
@@ -11,13 +11,23 @@ import { debouncedSaveSessionMeta } from './persistence.js';
|
|
|
11
11
|
*/
|
|
12
12
|
export async function handleCrewHumanInput(msg) {
|
|
13
13
|
// Lazy import to avoid circular dependency
|
|
14
|
-
const { crewSessions } = await import('./session.js');
|
|
14
|
+
const { crewSessions, resumeCrewSession } = await import('./session.js');
|
|
15
15
|
|
|
16
16
|
const { sessionId, content, targetRole, files } = msg;
|
|
17
|
-
|
|
17
|
+
let session = crewSessions.get(sessionId);
|
|
18
18
|
if (!session) {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
// Auto-resume: try to restore from disk before giving up
|
|
20
|
+
console.log(`[Crew] Session ${sessionId} not in memory, attempting auto-resume...`);
|
|
21
|
+
try {
|
|
22
|
+
await resumeCrewSession({ sessionId });
|
|
23
|
+
session = crewSessions.get(sessionId);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.warn(`[Crew] Auto-resume failed for ${sessionId}:`, e.message);
|
|
26
|
+
}
|
|
27
|
+
if (!session) {
|
|
28
|
+
console.warn(`[Crew] Session not found: ${sessionId} (even after auto-resume)`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
// Build dispatch content (supports image attachments)
|
package/crew/role-management.js
CHANGED
|
@@ -17,13 +17,23 @@ function roleLabel(r) {
|
|
|
17
17
|
*/
|
|
18
18
|
export async function addRoleToSession(msg) {
|
|
19
19
|
// Lazy import to avoid circular dependency
|
|
20
|
-
const { crewSessions, expandRoles } = await import('./session.js');
|
|
20
|
+
const { crewSessions, expandRoles, resumeCrewSession } = await import('./session.js');
|
|
21
21
|
|
|
22
22
|
const { sessionId, role } = msg;
|
|
23
|
-
|
|
23
|
+
let session = crewSessions.get(sessionId);
|
|
24
24
|
if (!session) {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// Auto-resume: try to restore from disk before giving up
|
|
26
|
+
console.log(`[Crew] Session ${sessionId} not in memory, attempting auto-resume...`);
|
|
27
|
+
try {
|
|
28
|
+
await resumeCrewSession({ sessionId });
|
|
29
|
+
session = crewSessions.get(sessionId);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.warn(`[Crew] Auto-resume failed for ${sessionId}:`, e.message);
|
|
32
|
+
}
|
|
33
|
+
if (!session) {
|
|
34
|
+
console.warn(`[Crew] Session not found: ${sessionId} (even after auto-resume)`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
const rolesToAdd = expandRoles([role]);
|
|
@@ -104,13 +114,23 @@ export async function addRoleToSession(msg) {
|
|
|
104
114
|
* 从 session 移除角色
|
|
105
115
|
*/
|
|
106
116
|
export async function removeRoleFromSession(msg) {
|
|
107
|
-
const { crewSessions } = await import('./session.js');
|
|
117
|
+
const { crewSessions, resumeCrewSession } = await import('./session.js');
|
|
108
118
|
|
|
109
119
|
const { sessionId, roleName } = msg;
|
|
110
|
-
|
|
120
|
+
let session = crewSessions.get(sessionId);
|
|
111
121
|
if (!session) {
|
|
112
|
-
|
|
113
|
-
|
|
122
|
+
// Auto-resume: try to restore from disk before giving up
|
|
123
|
+
console.log(`[Crew] Session ${sessionId} not in memory, attempting auto-resume...`);
|
|
124
|
+
try {
|
|
125
|
+
await resumeCrewSession({ sessionId });
|
|
126
|
+
session = crewSessions.get(sessionId);
|
|
127
|
+
} catch (e) {
|
|
128
|
+
console.warn(`[Crew] Auto-resume failed for ${sessionId}:`, e.message);
|
|
129
|
+
}
|
|
130
|
+
if (!session) {
|
|
131
|
+
console.warn(`[Crew] Session not found: ${sessionId} (even after auto-resume)`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
const role = session.roles.get(roleName);
|
package/crew/routing.js
CHANGED
|
@@ -50,7 +50,8 @@ export function parseRoutes(text) {
|
|
|
50
50
|
// ★ Clean `to` value: take only the first word (strip parenthetical notes, extra text)
|
|
51
51
|
// e.g. "pm (决策者)" → "pm", "dev-1 // main dev" → "dev-1"
|
|
52
52
|
const toRaw = toMatch[1].trim().toLowerCase();
|
|
53
|
-
|
|
53
|
+
// Strip trailing punctuation (commas, semicolons, colons, etc.)
|
|
54
|
+
const toClean = toRaw.split(/[\s(]/)[0].replace(/[,;:!?。,;:!?]+$/, '');
|
|
54
55
|
|
|
55
56
|
// ★ summary: match until next known field (task:/taskTitle:) or end of block
|
|
56
57
|
const summaryMatch = block.match(/summary:\s*([\s\S]+?)(?=\n\s*(?:task|taskTitle)\s*:|$)/i);
|
|
@@ -114,9 +115,28 @@ export function resolveRoleName(to, session, fromRole) {
|
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
// 4. displayName match (e.g. "乔布斯" → pm)
|
|
119
|
+
if (candidates.length === 0) {
|
|
120
|
+
for (const [name, config] of session.roles) {
|
|
121
|
+
if (config.displayName && config.displayName.toLowerCase() === to) {
|
|
122
|
+
candidates.push({ name, groupIndex: config.groupIndex || 0 });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 5. name-displayName compound match (e.g. "pm-乔布斯" → pm)
|
|
128
|
+
// Claude sometimes concatenates role name + display name with a hyphen
|
|
129
|
+
if (candidates.length === 0) {
|
|
130
|
+
for (const [name, config] of session.roles) {
|
|
131
|
+
if (to.startsWith(name + '-') && to.length > name.length + 1) {
|
|
132
|
+
candidates.push({ name, groupIndex: config.groupIndex || 0 });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
117
137
|
if (candidates.length === 0) return null;
|
|
118
138
|
|
|
119
|
-
//
|
|
139
|
+
// 6. Prefer same groupIndex as sender
|
|
120
140
|
if (fromGroupIndex > 0) {
|
|
121
141
|
const sameGroup = candidates.find(c => c.groupIndex === fromGroupIndex);
|
|
122
142
|
if (sameGroup) return sameGroup.name;
|
|
@@ -215,8 +235,9 @@ export async function executeRoute(session, fromRole, route, turnImages = []) {
|
|
|
215
235
|
await dispatchToRole(session, resolvedTo, taskPrompt, fromRole, taskId, taskTitle);
|
|
216
236
|
}
|
|
217
237
|
} else {
|
|
218
|
-
|
|
219
|
-
|
|
238
|
+
const availableRoles = Array.from(session.roles.keys()).join(', ');
|
|
239
|
+
console.warn(`[Crew] Unknown route target: ${to} (available: ${availableRoles})`);
|
|
240
|
+
const errorMsg = `路由目标 "${to}" 不存在。可用角色: ${availableRoles}\n来自 ${fromRole} 的消息: ${summary}`;
|
|
220
241
|
await dispatchToRole(session, session.decisionMaker, errorMsg, 'system');
|
|
221
242
|
}
|
|
222
243
|
}
|