multiclaws 0.4.36 → 0.4.37

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 CHANGED
@@ -1,39 +1,39 @@
1
- # MultiClaws
2
-
3
- Multi-agent collaboration plugin for [OpenClaw](https://openclaw.ai). Connect multiple OpenClaw instances into a team and delegate tasks between them using the [A2A protocol](https://google.github.io/A2A/).
4
-
5
- [中文文档](README.zh-CN.md)
6
-
7
- ## Installation
8
-
9
- Just tell your AI:
10
-
11
- > Run `openclaw plugins install multiclaws` and tell me what it can do.
12
-
13
- Your AI handles the rest — installation, configuration, and profile setup — no manual steps required.
14
-
15
- ## Usage
16
-
17
- Everything works through natural language:
18
-
19
- - **"Create a team called my-team"** — creates a team and generates an invite code
20
- - **"Join team with invite code mc:xxxxx"** — join a teammate's team
21
- - **"Ask Bob to summarize the latest report"** — delegate a task to a teammate's AI
22
- - **"Show all agents"** — list team members and their capabilities
23
-
24
- ## How It Works
25
-
26
- MultiClaws enables multiple OpenClaw instances to collaborate as a team. Each instance acts as both a client (delegating tasks) and a server (receiving tasks from others). Tasks are executed by the remote AI and results are returned directly.
27
-
28
- Works out of the box on the same local network. Cross-network collaboration is also supported.
29
-
30
- ## Documentation
31
-
32
- See [SKILL.md](skills/multiclaws/SKILL.md) for full details.
33
-
34
- ## Development
35
-
36
- ```bash
37
- npm install
38
- npm run build
39
- ```
1
+ # MultiClaws
2
+
3
+ Multi-agent collaboration plugin for [OpenClaw](https://openclaw.ai). Connect multiple OpenClaw instances into a team and delegate tasks between them using the [A2A protocol](https://google.github.io/A2A/).
4
+
5
+ [中文文档](README.zh-CN.md)
6
+
7
+ ## Installation
8
+
9
+ Just tell your AI:
10
+
11
+ > Run `openclaw plugins install multiclaws` and tell me what it can do.
12
+
13
+ Your AI handles the rest — installation, configuration, and profile setup — no manual steps required.
14
+
15
+ ## Usage
16
+
17
+ Everything works through natural language:
18
+
19
+ - **"Create a team called my-team"** — creates a team and generates an invite code
20
+ - **"Join team with invite code mc:xxxxx"** — join a teammate's team
21
+ - **"Ask Bob to summarize the latest report"** — delegate a task to a teammate's AI
22
+ - **"Show all agents"** — list team members and their capabilities
23
+
24
+ ## How It Works
25
+
26
+ MultiClaws enables multiple OpenClaw instances to collaborate as a team. Each instance acts as both a client (delegating tasks) and a server (receiving tasks from others). Tasks are executed by the remote AI and results are returned directly.
27
+
28
+ Works out of the box on the same local network. Cross-network collaboration is also supported.
29
+
30
+ ## Documentation
31
+
32
+ See [SKILL.md](skills/multiclaws/SKILL.md) for full details.
33
+
34
+ ## Development
35
+
36
+ ```bash
37
+ npm install
38
+ npm run build
39
+ ```
package/README.zh-CN.md CHANGED
@@ -1,39 +1,39 @@
1
- # MultiClaws
2
-
3
- [OpenClaw](https://openclaw.ai) 多智能体协作插件。将多个 OpenClaw 实例组成团队,通过 [A2A 协议](https://google.github.io/A2A/) 互相委派任务。
4
-
5
- [English](README.md)
6
-
7
- ## 安装
8
-
9
- 对你的 AI 说:
10
-
11
- > 请运行 `openclaw plugins install multiclaws`,安装完成后告诉我这个插件能做什么
12
-
13
- AI 会自动完成安装、配置和档案生成,无需手动修改任何文件。
14
-
15
- ## 使用
16
-
17
- 一切通过自然语言完成:
18
-
19
- - **「创建一个叫 my-team 的团队」** — 创建团队并获取邀请码
20
- - **「用邀请码 mc:xxxxx 加入团队」** — 加入队友的团队
21
- - **「让 Bob 总结一下最新报告」** — 把任务委派给队友的 AI
22
- - **「显示所有智能体」** — 查看团队成员及其能力
23
-
24
- ## 工作原理
25
-
26
- MultiClaws 让多个 OpenClaw 实例作为一个团队协作。每个实例既可以作为客户端(委派任务),也可以作为服务端(接收他人任务)。任务由远端 AI 执行,结果直接返回。
27
-
28
- 同局域网开箱即用,也支持跨网络协作。
29
-
30
- ## 详细文档
31
-
32
- 见 [SKILL.md](skills/multiclaws/SKILL.md)。
33
-
34
- ## 开发
35
-
36
- ```bash
37
- npm install
38
- npm run build
39
- ```
1
+ # MultiClaws
2
+
3
+ [OpenClaw](https://openclaw.ai) 多智能体协作插件。将多个 OpenClaw 实例组成团队,通过 [A2A 协议](https://google.github.io/A2A/) 互相委派任务。
4
+
5
+ [English](README.md)
6
+
7
+ ## 安装
8
+
9
+ 对你的 AI 说:
10
+
11
+ > 请运行 `openclaw plugins install multiclaws`,安装完成后告诉我这个插件能做什么
12
+
13
+ AI 会自动完成安装、配置和档案生成,无需手动修改任何文件。
14
+
15
+ ## 使用
16
+
17
+ 一切通过自然语言完成:
18
+
19
+ - **「创建一个叫 my-team 的团队」** — 创建团队并获取邀请码
20
+ - **「用邀请码 mc:xxxxx 加入团队」** — 加入队友的团队
21
+ - **「让 Bob 总结一下最新报告」** — 把任务委派给队友的 AI
22
+ - **「显示所有智能体」** — 查看团队成员及其能力
23
+
24
+ ## 工作原理
25
+
26
+ MultiClaws 让多个 OpenClaw 实例作为一个团队协作。每个实例既可以作为客户端(委派任务),也可以作为服务端(接收他人任务)。任务由远端 AI 执行,结果直接返回。
27
+
28
+ 同局域网开箱即用,也支持跨网络协作。
29
+
30
+ ## 详细文档
31
+
32
+ 见 [SKILL.md](skills/multiclaws/SKILL.md)。
33
+
34
+ ## 开发
35
+
36
+ ```bash
37
+ npm install
38
+ npm run build
39
+ ```
@@ -13,6 +13,10 @@ const taskDelegateSchema = zod_1.z.object({
13
13
  task: nonEmptyString,
14
14
  });
15
15
  const taskStatusSchema = zod_1.z.object({ taskId: nonEmptyString });
16
+ const taskRespondSchema = zod_1.z.object({
17
+ taskId: nonEmptyString,
18
+ approved: zod_1.z.boolean(),
19
+ });
16
20
  const profileSetSchema = zod_1.z.object({
17
21
  ownerName: zod_1.z.string().trim().optional(),
18
22
  bio: zod_1.z.string().optional(),
@@ -86,6 +90,19 @@ function createGatewayHandlers(getService, logger) {
86
90
  safeHandle(respond, "task_delegate_failed", error);
87
91
  }
88
92
  },
93
+ "multiclaws.task.respond": async ({ params, respond }) => {
94
+ log("debug", `task.respond(taskId=${params?.taskId}, approved=${params?.approved})`);
95
+ try {
96
+ const parsed = taskRespondSchema.parse(params);
97
+ const service = getService();
98
+ const resolved = service.respondToTask(parsed.taskId, parsed.approved);
99
+ respond(true, { resolved, approved: parsed.approved });
100
+ }
101
+ catch (error) {
102
+ log("error", `task.respond failed: ${error instanceof Error ? error.message : String(error)}`);
103
+ safeHandle(respond, "task_respond_failed", error);
104
+ }
105
+ },
89
106
  "multiclaws.task.status": async ({ params, respond }) => {
90
107
  log("debug", `task.status(taskId=${params?.taskId})`);
91
108
  try {
package/dist/index.js CHANGED
@@ -140,9 +140,10 @@ function createTools(getService, logger) {
140
140
  };
141
141
  const multiclawsDelegate = {
142
142
  name: "multiclaws_delegate",
143
- description: "Delegate a task to a remote A2A agent. " +
144
- "Automatically spawns a sub-agent that sends the task, waits for the result, " +
145
- "and reports back via the message tool. Returns immediately.",
143
+ description: "Delegate a task to a remote A2A agent and wait for the result inline. " +
144
+ "Sends the task synchronously via A2A and returns the output directly in the current session. " +
145
+ "For long-running tasks this may take several minutes. " +
146
+ "Do NOT use multiclaws_delegate_send directly — use this tool instead.",
146
147
  parameters: {
147
148
  type: "object",
148
149
  additionalProperties: false,
@@ -160,8 +161,13 @@ function createTools(getService, logger) {
160
161
  const task = typeof args.task === "string" ? args.task.trim() : "";
161
162
  if (!agentUrl || !task)
162
163
  throw new Error("agentUrl and task are required");
163
- const result = await service.spawnDelegation({ agentUrl, task });
164
- return textResult(result.message, result);
164
+ const result = await service.delegateTaskSync({ agentUrl, task });
165
+ const summary = result.output
166
+ ? result.output
167
+ : result.error
168
+ ? `任务失败:${result.error}`
169
+ : `任务状态:${result.status}`;
170
+ return textResult(summary, result);
165
171
  }
166
172
  catch (err) {
167
173
  log("error", `tool:multiclaws_delegate failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -172,8 +178,8 @@ function createTools(getService, logger) {
172
178
  const multiclawsDelegateSend = {
173
179
  name: "multiclaws_delegate_send",
174
180
  description: "Send a task to a remote A2A agent and wait for the result synchronously. " +
175
- "Used internally by sub-agents spawned from multiclaws_delegate. " +
176
- "Do NOT call this directly use multiclaws_delegate instead.",
181
+ "Low-level primitive used by sub-agents or advanced orchestration flows. " +
182
+ "In most cases use multiclaws_delegate instead, which handles this automatically.",
177
183
  parameters: {
178
184
  type: "object",
179
185
  additionalProperties: false,
@@ -263,6 +269,42 @@ function createTools(getService, logger) {
263
269
  }
264
270
  },
265
271
  };
272
+ const multiclawsTaskRespond = {
273
+ name: "multiclaws_task_respond",
274
+ description: "Approve or reject a pending incoming delegated task that requires human authorization. " +
275
+ "Call with approved=true to allow execution, approved=false to reject. " +
276
+ "Use this when the user responds to an approval request for a risky incoming task.",
277
+ parameters: {
278
+ type: "object",
279
+ additionalProperties: false,
280
+ properties: {
281
+ taskId: { type: "string", description: "The taskId from the approval request." },
282
+ approved: { type: "boolean", description: "true to approve, false to reject." },
283
+ },
284
+ required: ["taskId", "approved"],
285
+ },
286
+ execute: async (_toolCallId, args) => {
287
+ const taskId = typeof args.taskId === "string" ? args.taskId.trim() : "";
288
+ const approved = typeof args.approved === "boolean" ? args.approved : false;
289
+ log("info", `tool:multiclaws_task_respond(taskId=${taskId}, approved=${approved})`);
290
+ try {
291
+ const service = requireService(getService());
292
+ if (!taskId)
293
+ throw new Error("taskId is required");
294
+ const resolved = service.respondToTask(taskId, approved);
295
+ if (!resolved) {
296
+ return textResult(`未找到任务 ${taskId} 的待审批记录,可能已超时或不存在。`);
297
+ }
298
+ return textResult(approved
299
+ ? `✅ 已授权任务 ${taskId},执行中…`
300
+ : `❌ 已拒绝任务 ${taskId}。`);
301
+ }
302
+ catch (err) {
303
+ log("error", `tool:multiclaws_task_respond failed: ${err instanceof Error ? err.message : String(err)}`);
304
+ throw err;
305
+ }
306
+ },
307
+ };
266
308
  const multiclawsTaskStatus = {
267
309
  name: "multiclaws_task_status",
268
310
  description: "Check the status of a delegated task.",
@@ -501,6 +543,7 @@ function createTools(getService, logger) {
501
543
  multiclawsDelegateSend,
502
544
  multiclawsA2ACallback,
503
545
  multiclawsNotify,
546
+ multiclawsTaskRespond,
504
547
  multiclawsTaskStatus,
505
548
  multiclawsTeamCreate,
506
549
  multiclawsTeamJoin,
@@ -625,16 +668,16 @@ const plugin = {
625
668
  api.on("gateway_stop", () => {
626
669
  structured.logger.info("[multiclaws] gateway_stop observed");
627
670
  });
628
- // Collect notification targets from incoming messages
671
+ // Collect notification targets from incoming messages.
672
+ // WebChat is intentionally excluded here: it's registered via
673
+ // before_prompt_build (type="web") using sessions_send, which correctly
674
+ // injects messages into the active session. Registering it here too would
675
+ // cause duplicate notifications.
629
676
  api.on("message_received", (_event, ctx) => {
630
677
  if (!service || !ctx.channelId)
631
678
  return;
632
- if (ctx.channelId === "webchat" && ctx.conversationId) {
633
- // WebChat: use conversationId with the message tool
634
- service.addNotificationTarget(`webchat:${ctx.conversationId}`, { type: "channel", conversationId: ctx.conversationId });
635
- }
636
- else if (ctx.channelId !== "webchat" && ctx.conversationId) {
637
- // External channels (Telegram, etc.)
679
+ if (ctx.channelId !== "webchat" && ctx.conversationId) {
680
+ // External channels only (Telegram, Discord, etc.)
638
681
  service.addNotificationTarget(`${ctx.channelId}:${ctx.conversationId}`, { type: "channel", conversationId: ctx.conversationId });
639
682
  }
640
683
  });
@@ -654,35 +697,35 @@ const plugin = {
654
697
  if (!review.pending)
655
698
  return;
656
699
  return {
657
- appendSystemContext: `## MultiClaws 首次安装 — 需要完成档案设置
658
-
659
- multiclaws 插件刚安装,需要在本次对话中完成以下初始化流程(优先处理,不管用户说了什么):
660
-
661
- 1. **确认用户名**(需要用户明确回答):
662
- - 询问用户希望使用什么名字
663
- - 这个名字会以「{名字} 的 OpenClaw」格式展示给团队其他成员
664
- - 例如用户叫「小明」,则其他成员看到的是「小明 的 OpenClaw」
665
-
666
- 2. **自动生成 bio**(无需用户确认,直接生成并保存):
667
- 扫描当前环境,生成详细的 bio(markdown 格式)。bio 是给其他 AI 智能体看的,用来判断这个智能体能做什么任务、能访问什么数据。必须准确反映实际能力,具体检查:
668
-
669
- - **已安装的工具(tools)**:列出所有可用的工具名称,说明能执行哪些类型的操作(如文件读写、代码执行、网络请求等)
670
- - **已安装的 skills**:列出 skill 名称和功能描述
671
- - **已连接的渠道(channels)**:检查是否连接了 Telegram、Discord、Gmail、Slack、微信等,列出具体渠道名称
672
- - **已安装的插件(plugins)**:列出所有已加载的插件及其主要功能
673
- - **工作区内容**:检查当前工作目录(pwd)下的项目结构,包括:
674
- - git 仓库信息(仓库名、分支)
675
- - 主要编程语言和框架
676
- - 项目名称和用途(从 README 或 package.json 推断)
677
- - **可访问的数据源**:检查是否有日历(Google Calendar 等)、邮件(Gmail 等)、Notion、数据库、API 等数据访问能力
678
- - **系统信息**:时区、操作系统、语言偏好
679
-
680
- 3. 用户确认名字后,立即调用 \`multiclaws_profile_set(ownerName="确认后的名字", bio="生成的bio")\` 保存。
681
-
682
- 4. 调用 \`multiclaws_profile_clear_pending_review()\` 完成初始化。
683
-
684
- 5. **网络情况告知**(无需用户回答):告知用户「所有实例通过 FRP 隧道通信,需在插件配置中设置 tunnel 字段(包含 frps 服务器地址、端口、token 和可用端口范围),frpc 会自动下载安装」
685
-
700
+ appendSystemContext: `## MultiClaws 首次安装 — 需要完成档案设置
701
+
702
+ multiclaws 插件刚安装,需要在本次对话中完成以下初始化流程(优先处理,不管用户说了什么):
703
+
704
+ 1. **确认用户名**(需要用户明确回答):
705
+ - 询问用户希望使用什么名字
706
+ - 这个名字会以「{名字} 的 OpenClaw」格式展示给团队其他成员
707
+ - 例如用户叫「小明」,则其他成员看到的是「小明 的 OpenClaw」
708
+
709
+ 2. **自动生成 bio**(无需用户确认,直接生成并保存):
710
+ 扫描当前环境,生成详细的 bio(markdown 格式)。bio 是给其他 AI 智能体看的,用来判断这个智能体能做什么任务、能访问什么数据。必须准确反映实际能力,具体检查:
711
+
712
+ - **已安装的工具(tools)**:列出所有可用的工具名称,说明能执行哪些类型的操作(如文件读写、代码执行、网络请求等)
713
+ - **已安装的 skills**:列出 skill 名称和功能描述
714
+ - **已连接的渠道(channels)**:检查是否连接了 Telegram、Discord、Gmail、Slack、微信等,列出具体渠道名称
715
+ - **已安装的插件(plugins)**:列出所有已加载的插件及其主要功能
716
+ - **工作区内容**:检查当前工作目录(pwd)下的项目结构,包括:
717
+ - git 仓库信息(仓库名、分支)
718
+ - 主要编程语言和框架
719
+ - 项目名称和用途(从 README 或 package.json 推断)
720
+ - **可访问的数据源**:检查是否有日历(Google Calendar 等)、邮件(Gmail 等)、Notion、数据库、API 等数据访问能力
721
+ - **系统信息**:时区、操作系统、语言偏好
722
+
723
+ 3. 用户确认名字后,立即调用 \`multiclaws_profile_set(ownerName="确认后的名字", bio="生成的bio")\` 保存。
724
+
725
+ 4. 调用 \`multiclaws_profile_clear_pending_review()\` 完成初始化。
726
+
727
+ 5. **网络情况告知**(无需用户回答):告知用户「所有实例通过 FRP 隧道通信,需在插件配置中设置 tunnel 字段(包含 frps 服务器地址、端口、token 和可用端口范围),frpc 会自动下载安装」
728
+
686
729
  **注意**:只有名字需要用户明确确认;bio 自动生成直接保存无需确认;网络情况仅告知无需回答。`,
687
730
  };
688
731
  }
@@ -18,10 +18,13 @@ export type A2AAdapterOptions = {
18
18
  *
19
19
  * When a remote agent sends a task via A2A `message/send`,
20
20
  * this executor:
21
- * 1. Records the task via TaskTracker
22
- * 2. Calls OpenClaw's `sessions_spawn` (run mode) to start execution
23
- * 3. Waits for the sub-agent to call back via `multiclaws_a2a_callback`
24
- * 4. Returns the final result as a Message
21
+ * 1. Classifies the task risk (safe vs risky)
22
+ * 2. Notifies the local human owner
23
+ * 3. For risky tasks: waits for explicit human approval
24
+ * For safe tasks: executes immediately
25
+ * 4. Calls OpenClaw's `sessions_spawn` (run mode) to start execution
26
+ * 5. Waits for the sub-agent to call back via `multiclaws_a2a_callback`
27
+ * 6. Returns the final result as a Message
25
28
  */
26
29
  export declare class OpenClawAgentExecutor implements AgentExecutor {
27
30
  private gatewayConfig;
@@ -30,6 +33,7 @@ export declare class OpenClawAgentExecutor implements AgentExecutor {
30
33
  private readonly logger;
31
34
  private readonly cwd;
32
35
  private readonly pendingCallbacks;
36
+ private readonly pendingApprovals;
33
37
  constructor(options: A2AAdapterOptions);
34
38
  execute(context: RequestContext, eventBus: ExecutionEventBus): Promise<void>;
35
39
  /**
@@ -37,6 +41,11 @@ export declare class OpenClawAgentExecutor implements AgentExecutor {
37
41
  * Returns true if a pending callback was found and resolved.
38
42
  */
39
43
  resolveCallback(taskId: string, result: string): boolean;
44
+ /**
45
+ * Called when the local human owner approves or rejects a pending risky task.
46
+ * Returns true if a pending approval was found.
47
+ */
48
+ resolveApproval(taskId: string, approved: boolean): boolean;
40
49
  cancelTask(taskId: string, eventBus: ExecutionEventBus): Promise<void>;
41
50
  updateGatewayConfig(config: GatewayConfig): void;
42
51
  /**
@@ -44,6 +53,11 @@ export declare class OpenClawAgentExecutor implements AgentExecutor {
44
53
  * or rejects on timeout.
45
54
  */
46
55
  private createCallback;
56
+ /**
57
+ * Create a pending approval that resolves when the human owner responds,
58
+ * or rejects on timeout or cancellation.
59
+ */
60
+ private createApprovalCallback;
47
61
  /** Send a notification to all known targets. Individual failures are silently ignored. */
48
62
  private notifyUser;
49
63
  private publishMessage;