multiclaws 0.4.0 → 0.4.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/dist/gateway/handlers.js
CHANGED
|
@@ -18,6 +18,10 @@ const sessionReplySchema = zod_1.z.object({
|
|
|
18
18
|
});
|
|
19
19
|
const sessionStatusSchema = zod_1.z.object({ sessionId: zod_1.z.string().trim().min(1).optional() });
|
|
20
20
|
const sessionEndSchema = zod_1.z.object({ sessionId: nonEmptyString });
|
|
21
|
+
const sessionWaitAllSchema = zod_1.z.object({
|
|
22
|
+
sessionIds: zod_1.z.array(nonEmptyString).min(1),
|
|
23
|
+
timeoutMs: zod_1.z.number().positive().optional(),
|
|
24
|
+
});
|
|
21
25
|
const profileSetSchema = zod_1.z.object({
|
|
22
26
|
ownerName: zod_1.z.string().trim().optional(),
|
|
23
27
|
bio: zod_1.z.string().optional(),
|
|
@@ -106,6 +110,17 @@ function createGatewayHandlers(getService) {
|
|
|
106
110
|
safeHandle(respond, "session_status_failed", error);
|
|
107
111
|
}
|
|
108
112
|
},
|
|
113
|
+
"multiclaws.session.wait_all": async ({ params, respond }) => {
|
|
114
|
+
try {
|
|
115
|
+
const parsed = sessionWaitAllSchema.parse(params);
|
|
116
|
+
const service = getService();
|
|
117
|
+
const result = await service.waitForSessions(parsed);
|
|
118
|
+
respond(true, result);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
safeHandle(respond, "session_wait_all_failed", error);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
109
124
|
"multiclaws.session.end": async ({ params, respond }) => {
|
|
110
125
|
try {
|
|
111
126
|
const parsed = sessionEndSchema.parse(params);
|
package/dist/index.js
CHANGED
|
@@ -155,6 +155,30 @@ function createTools(getService) {
|
|
|
155
155
|
return textResult(JSON.stringify({ sessions }, null, 2), { sessions });
|
|
156
156
|
},
|
|
157
157
|
};
|
|
158
|
+
const multiclawsSessionWaitAll = {
|
|
159
|
+
name: "multiclaws_session_wait_all",
|
|
160
|
+
description: "Wait for multiple sessions to complete, then return all results at once. Use this when you have started multiple sessions concurrently and need all results before synthesizing an answer. Returns early if any session needs input (input-required). Default timeout: 5 minutes.",
|
|
161
|
+
parameters: {
|
|
162
|
+
type: "object",
|
|
163
|
+
additionalProperties: false,
|
|
164
|
+
properties: {
|
|
165
|
+
sessionIds: { type: "array", items: { type: "string" } },
|
|
166
|
+
timeoutMs: { type: "number" },
|
|
167
|
+
},
|
|
168
|
+
required: ["sessionIds"],
|
|
169
|
+
},
|
|
170
|
+
execute: async (_toolCallId, args) => {
|
|
171
|
+
const service = requireService(getService());
|
|
172
|
+
const sessionIds = Array.isArray(args.sessionIds)
|
|
173
|
+
? args.sessionIds.map((s) => String(s).trim()).filter(Boolean)
|
|
174
|
+
: [];
|
|
175
|
+
if (!sessionIds.length)
|
|
176
|
+
throw new Error("sessionIds must be a non-empty array");
|
|
177
|
+
const timeoutMs = typeof args.timeoutMs === "number" ? args.timeoutMs : undefined;
|
|
178
|
+
const result = await service.waitForSessions({ sessionIds, timeoutMs });
|
|
179
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
180
|
+
},
|
|
181
|
+
};
|
|
158
182
|
const multiclawsSessionEnd = {
|
|
159
183
|
name: "multiclaws_session_end",
|
|
160
184
|
description: "Cancel and close a collaboration session.",
|
|
@@ -327,6 +351,7 @@ function createTools(getService) {
|
|
|
327
351
|
multiclawsSessionStart,
|
|
328
352
|
multiclawsSessionReply,
|
|
329
353
|
multiclawsSessionStatus,
|
|
354
|
+
multiclawsSessionWaitAll,
|
|
330
355
|
multiclawsSessionEnd,
|
|
331
356
|
multiclawsTeamCreate,
|
|
332
357
|
multiclawsTeamJoin,
|
|
@@ -63,6 +63,19 @@ export declare class MulticlawsService extends EventEmitter {
|
|
|
63
63
|
}): Promise<SessionReplyResult>;
|
|
64
64
|
getSession(sessionId: string): ConversationSession | null;
|
|
65
65
|
listSessions(): ConversationSession[];
|
|
66
|
+
waitForSessions(params: {
|
|
67
|
+
sessionIds: string[];
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
results: Array<{
|
|
71
|
+
sessionId: string;
|
|
72
|
+
status: string;
|
|
73
|
+
agentName: string;
|
|
74
|
+
lastMessage?: string;
|
|
75
|
+
error?: string;
|
|
76
|
+
}>;
|
|
77
|
+
timedOut: boolean;
|
|
78
|
+
}>;
|
|
66
79
|
endSession(sessionId: string): boolean;
|
|
67
80
|
private runSession;
|
|
68
81
|
private handleSessionResult;
|
|
@@ -262,6 +262,36 @@ class MulticlawsService extends node_events_1.EventEmitter {
|
|
|
262
262
|
listSessions() {
|
|
263
263
|
return this.sessionStore.list();
|
|
264
264
|
}
|
|
265
|
+
async waitForSessions(params) {
|
|
266
|
+
const timeout = params.timeoutMs ?? 5 * 60 * 1000;
|
|
267
|
+
const deadline = Date.now() + timeout;
|
|
268
|
+
const terminalStates = new Set(["completed", "failed", "canceled"]);
|
|
269
|
+
const getResults = () => params.sessionIds.map((id) => {
|
|
270
|
+
const session = this.sessionStore.get(id);
|
|
271
|
+
if (!session)
|
|
272
|
+
return { sessionId: id, agentName: "unknown", status: "not_found" };
|
|
273
|
+
const lastAgent = [...session.messages].reverse().find((m) => m.role === "agent");
|
|
274
|
+
return {
|
|
275
|
+
sessionId: id,
|
|
276
|
+
agentName: session.agentName,
|
|
277
|
+
status: session.status,
|
|
278
|
+
lastMessage: lastAgent?.content,
|
|
279
|
+
error: session.error,
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
while (Date.now() < deadline) {
|
|
283
|
+
const results = getResults();
|
|
284
|
+
const allSettled = results.every((r) => terminalStates.has(r.status) || r.status === "not_found");
|
|
285
|
+
if (allSettled)
|
|
286
|
+
return { results, timedOut: false };
|
|
287
|
+
// Return early if any session needs input — AI must handle it before continuing
|
|
288
|
+
const needsInput = results.some((r) => r.status === "input-required");
|
|
289
|
+
if (needsInput)
|
|
290
|
+
return { results, timedOut: false };
|
|
291
|
+
await new Promise((r) => setTimeout(r, 1_000));
|
|
292
|
+
}
|
|
293
|
+
return { results: getResults(), timedOut: true };
|
|
294
|
+
}
|
|
265
295
|
endSession(sessionId) {
|
|
266
296
|
const session = this.sessionStore.get(sessionId);
|
|
267
297
|
if (!session)
|
package/package.json
CHANGED
|
@@ -49,13 +49,19 @@ multiclaws_session_status(sessionId="...") → 查看单个会话及消息历史
|
|
|
49
49
|
multiclaws_session_end(sessionId="...") → 取消并关闭会话
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
###
|
|
53
|
-
|
|
52
|
+
### 并发协作(自动汇总)
|
|
53
|
+
同时开启多个 session,等所有结果后汇总:
|
|
54
54
|
```
|
|
55
|
-
multiclaws_session_start(agentUrl=B, message="
|
|
56
|
-
multiclaws_session_start(agentUrl=C, message="
|
|
55
|
+
id1 = multiclaws_session_start(agentUrl=B, message="子任务1")
|
|
56
|
+
id2 = multiclaws_session_start(agentUrl=C, message="子任务2")
|
|
57
|
+
results = multiclaws_session_wait_all(sessionIds=[id1, id2])
|
|
58
|
+
→ 阻塞直到全部完成,返回所有结果
|
|
59
|
+
→ AI 汇总后回复用户
|
|
57
60
|
```
|
|
58
61
|
|
|
62
|
+
**注意**:若任何 session 变为 `input-required`,`wait_all` 会提前返回,
|
|
63
|
+
AI 应先用 `session_reply` 处理,再继续等待剩余 session。
|
|
64
|
+
|
|
59
65
|
### 链式协作(A→B→C)
|
|
60
66
|
B 内部可以自己调用 `multiclaws_session_start` 委派给 C,结果自然冒泡回 A。
|
|
61
67
|
|
|
@@ -99,6 +105,7 @@ multiclaws_profile_show()
|
|
|
99
105
|
| `multiclaws_session_start` | 开始协作会话(替代旧 delegate) | `agentUrl`, `message` |
|
|
100
106
|
| `multiclaws_session_reply` | 在会话中发送后续消息 | `sessionId`, `message` |
|
|
101
107
|
| `multiclaws_session_status` | 查看会话状态和消息历史 | `sessionId`(可选,不传返回全部) |
|
|
108
|
+
| `multiclaws_session_wait_all` | 等待多个会话全部完成,返回所有结果 | `sessionIds[]`, `timeoutMs`(可选) |
|
|
102
109
|
| `multiclaws_session_end` | 取消/关闭会话 | `sessionId` |
|
|
103
110
|
|
|
104
111
|
### 档案
|