multiclaws 0.4.33 → 0.4.34

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/index.js CHANGED
@@ -625,16 +625,25 @@ const plugin = {
625
625
  api.on("gateway_stop", () => {
626
626
  structured.logger.info("[multiclaws] gateway_stop observed");
627
627
  });
628
- // Collect notification targets from incoming messages (external channels)
628
+ // Collect notification targets from incoming messages
629
629
  api.on("message_received", (_event, ctx) => {
630
- if (service && ctx.channelId && ctx.channelId !== "webchat" && ctx.conversationId) {
630
+ if (!service || !ctx.channelId)
631
+ 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.)
631
638
  service.addNotificationTarget(`${ctx.channelId}:${ctx.conversationId}`, { type: "channel", conversationId: ctx.conversationId });
632
639
  }
633
640
  });
634
641
  // Inject onboarding prompt when profile is pending first-run setup
635
- // Also capture web session targets for notifications
642
+ // Also capture web session targets for notifications (skip internal sub-agent sessions)
643
+ const INTERNAL_SESSION_PREFIXES = ["delegate-", "a2a-"];
636
644
  api.on("before_prompt_build", async (_event, ctx) => {
637
- if (service && ctx.sessionKey) {
645
+ if (service && ctx.sessionKey &&
646
+ !INTERNAL_SESSION_PREFIXES.some((p) => ctx.sessionKey.startsWith(p))) {
638
647
  service.addNotificationTarget(`web:${ctx.sessionKey}`, { type: "web", sessionKey: ctx.sessionKey });
639
648
  }
640
649
  if (!service)
@@ -37,33 +37,43 @@ class OpenClawAgentExecutor {
37
37
  async execute(context, eventBus) {
38
38
  const taskText = extractTextFromMessage(context.userMessage);
39
39
  const taskId = context.taskId;
40
+ this.logger.info(`[a2a-adapter] ▶ execute() called — taskId=${taskId}, textLen=${taskText.length}`);
40
41
  if (!taskText.trim()) {
42
+ this.logger.warn(`[a2a-adapter] ✗ empty task text, rejecting — taskId=${taskId}`);
41
43
  this.publishMessage(eventBus, "Error: empty task received.");
42
44
  eventBus.finished();
43
45
  return;
44
46
  }
45
- const fromAgent = context.userMessage.metadata?.agentUrl ?? "unknown";
47
+ const meta = context.userMessage.metadata ?? {};
48
+ const fromAgentUrl = meta.agentUrl ?? "unknown";
49
+ const fromAgentName = meta.agentName || fromAgentUrl;
50
+ this.logger.info(`[a2a-adapter] task ${taskId} from ${fromAgentName} (${fromAgentUrl}): ${taskText.slice(0, 120)}`);
46
51
  this.taskTracker.create({
47
- fromPeerId: fromAgent,
52
+ fromPeerId: fromAgentUrl,
48
53
  toPeerId: "local",
49
54
  task: taskText,
50
55
  });
56
+ this.logger.info(`[a2a-adapter] task ${taskId} tracked`);
51
57
  if (!this.gatewayConfig) {
52
- this.logger.error("[a2a-adapter] gateway config not available, cannot execute task");
58
+ this.logger.error(`[a2a-adapter] gateway config not available taskId=${taskId}`);
53
59
  this.taskTracker.update(taskId, { status: "failed", error: "gateway config not available" });
54
60
  this.publishMessage(eventBus, "Error: gateway config not available, cannot execute task.");
55
61
  eventBus.finished();
56
62
  return;
57
63
  }
58
64
  // Notify local user about incoming task
59
- void this.notifyUser(`📨 收到来自 **${fromAgent}** 的委派任务:${taskText.slice(0, 200)}`);
65
+ const notifyTargets = this.getNotificationTargets();
66
+ this.logger.info(`[a2a-adapter] task ${taskId} notifying user (${notifyTargets.size} targets)`);
67
+ void this.notifyUser(`📨 收到来自 **${fromAgentName}** 的委派任务:${taskText.slice(0, 200)}`);
60
68
  try {
61
- this.logger.info(`[a2a-adapter] executing task ${taskId}: ${taskText.slice(0, 100)}`);
62
69
  // Create a promise that resolves when sub-agent calls multiclaws_a2a_callback
63
- const resultPromise = this.createCallback(taskId, 180_000);
70
+ const timeoutMs = 180_000;
71
+ const resultPromise = this.createCallback(taskId, timeoutMs);
72
+ this.logger.info(`[a2a-adapter] task ${taskId} callback registered (timeout=${timeoutMs / 1000}s)`);
64
73
  // Spawn the subagent with instructions to call back when done
65
74
  const prompt = buildA2ASubagentPrompt(taskId, taskText);
66
- await (0, gateway_client_1.invokeGatewayTool)({
75
+ this.logger.info(`[a2a-adapter] task ${taskId} spawning sub-agent via sessions_spawn (cwd=${this.cwd}, sessionKey=a2a-${taskId})`);
76
+ const spawnResult = await (0, gateway_client_1.invokeGatewayTool)({
67
77
  gateway: this.gatewayConfig,
68
78
  tool: "sessions_spawn",
69
79
  args: {
@@ -74,20 +84,22 @@ class OpenClawAgentExecutor {
74
84
  sessionKey: `a2a-${taskId}`,
75
85
  timeoutMs: 15_000,
76
86
  });
77
- this.logger.info(`[a2a-adapter] task ${taskId} spawned, waiting for callback...`);
87
+ this.logger.info(`[a2a-adapter] task ${taskId} sub-agent spawned result=${JSON.stringify(spawnResult).slice(0, 200)}`);
88
+ this.logger.info(`[a2a-adapter] task ${taskId} waiting for callback from sub-agent...`);
78
89
  // Wait for the sub-agent to call back
79
90
  const output = await resultPromise;
80
91
  // Return result
81
92
  this.taskTracker.update(taskId, { status: "completed", result: output });
82
- this.logger.info(`[a2a-adapter] task ${taskId} completed, resultLen=${output.length}`);
93
+ this.logger.info(`[a2a-adapter] task ${taskId} completed resultLen=${output.length}, preview=${output.slice(0, 120)}`);
83
94
  this.publishMessage(eventBus, output || "Task completed with no output.");
84
95
  }
85
96
  catch (err) {
86
97
  const errorMsg = err instanceof Error ? err.message : String(err);
87
- this.logger.error(`[a2a-adapter] task execution failed: ${errorMsg}`);
98
+ this.logger.error(`[a2a-adapter] task ${taskId} failed: ${errorMsg}`);
88
99
  this.taskTracker.update(taskId, { status: "failed", error: errorMsg });
89
100
  this.publishMessage(eventBus, `Error: ${errorMsg}`);
90
101
  }
102
+ this.logger.info(`[a2a-adapter] task ${taskId} eventBus.finished()`);
91
103
  eventBus.finished();
92
104
  }
93
105
  /**
@@ -96,10 +108,13 @@ class OpenClawAgentExecutor {
96
108
  */
97
109
  resolveCallback(taskId, result) {
98
110
  const pending = this.pendingCallbacks.get(taskId);
99
- if (!pending)
111
+ if (!pending) {
112
+ this.logger.warn(`[a2a-adapter] resolveCallback: no pending callback for taskId=${taskId} (may have timed out)`);
100
113
  return false;
114
+ }
101
115
  clearTimeout(pending.timer);
102
116
  this.pendingCallbacks.delete(taskId);
117
+ this.logger.info(`[a2a-adapter] resolveCallback: taskId=${taskId} resolved — resultLen=${result.length}`);
103
118
  pending.resolve(result);
104
119
  return true;
105
120
  }
@@ -111,6 +126,7 @@ class OpenClawAgentExecutor {
111
126
  clearTimeout(pending.timer);
112
127
  this.pendingCallbacks.delete(taskId);
113
128
  pending.reject(new Error("canceled"));
129
+ this.logger.info(`[a2a-adapter] cancelTask: pending callback rejected for taskId=${taskId}`);
114
130
  }
115
131
  this.taskTracker.update(taskId, { status: "failed", error: "canceled" });
116
132
  this.publishMessage(eventBus, "Task was canceled.");
@@ -127,6 +143,7 @@ class OpenClawAgentExecutor {
127
143
  return new Promise((resolve, reject) => {
128
144
  const timer = setTimeout(() => {
129
145
  this.pendingCallbacks.delete(taskId);
146
+ this.logger.error(`[a2a-adapter] ✗ task ${taskId} callback timed out after ${timeoutMs / 1000}s — pending callbacks remaining: ${this.pendingCallbacks.size}`);
130
147
  reject(new Error(`task timed out after ${timeoutMs / 1000}s waiting for sub-agent callback`));
131
148
  }, timeoutMs);
132
149
  this.pendingCallbacks.set(taskId, { resolve, reject, timer });
@@ -135,21 +152,36 @@ class OpenClawAgentExecutor {
135
152
  /** Send a notification to all known targets. Individual failures are silently ignored. */
136
153
  async notifyUser(message) {
137
154
  const targets = this.getNotificationTargets();
138
- if (!this.gatewayConfig || targets.size === 0)
155
+ if (!this.gatewayConfig || targets.size === 0) {
156
+ this.logger.info(`[a2a-adapter] notifyUser: skipped (gateway=${!!this.gatewayConfig}, targets=${targets.size})`);
139
157
  return;
140
- await Promise.allSettled([...targets.values()].map((target) => target.type === "channel"
141
- ? (0, gateway_client_1.invokeGatewayTool)({
142
- gateway: this.gatewayConfig,
143
- tool: "message",
144
- args: { action: "send", target: target.conversationId, message },
145
- timeoutMs: 5_000,
146
- })
147
- : (0, gateway_client_1.invokeGatewayTool)({
148
- gateway: this.gatewayConfig,
149
- tool: "chat.send",
150
- args: { sessionKey: target.sessionKey, message },
151
- timeoutMs: 5_000,
152
- })));
158
+ }
159
+ const results = await Promise.allSettled([...targets.entries()].map(async ([key, target]) => {
160
+ this.logger.info(`[a2a-adapter] notifyUser: sending to ${key} (type=${target.type})`);
161
+ try {
162
+ await (target.type === "channel"
163
+ ? (0, gateway_client_1.invokeGatewayTool)({
164
+ gateway: this.gatewayConfig,
165
+ tool: "message",
166
+ args: { action: "send", target: target.conversationId, message },
167
+ timeoutMs: 5_000,
168
+ })
169
+ : (0, gateway_client_1.invokeGatewayTool)({
170
+ gateway: this.gatewayConfig,
171
+ tool: "chat.send",
172
+ args: { sessionKey: target.sessionKey, message },
173
+ timeoutMs: 5_000,
174
+ }));
175
+ this.logger.info(`[a2a-adapter] notifyUser: sent to ${key} ✓`);
176
+ }
177
+ catch (err) {
178
+ this.logger.warn(`[a2a-adapter] notifyUser: failed to send to ${key}: ${err instanceof Error ? err.message : String(err)}`);
179
+ throw err;
180
+ }
181
+ }));
182
+ const ok = results.filter((r) => r.status === "fulfilled").length;
183
+ const fail = results.filter((r) => r.status === "rejected").length;
184
+ this.logger.info(`[a2a-adapter] notifyUser: done (${ok} ok, ${fail} failed)`);
153
185
  }
154
186
  publishMessage(eventBus, text) {
155
187
  const message = {
@@ -133,7 +133,7 @@ export declare class MulticlawsService extends EventEmitter {
133
133
  private extractArtifactText;
134
134
  /** Fetch with up to 2 retries and exponential backoff. */
135
135
  private fetchWithRetry;
136
- /** Register a channel ID for notifications. */
136
+ /** Resolve a pending A2A callback from sub-agent. */
137
137
  resolveA2ACallback(taskId: string, result: string): boolean;
138
138
  addNotificationTarget(key: string, target: NotificationTarget): void;
139
139
  /** Send a notification to all known targets. Individual failures are silently ignored. */
@@ -256,26 +256,32 @@ class MulticlawsService extends node_events_1.EventEmitter {
256
256
  /* Task delegation */
257
257
  /* ---------------------------------------------------------------- */
258
258
  async delegateTask(params) {
259
- this.log("info", `delegateTask(agentUrl=${params.agentUrl}, task=${params.task.slice(0, 80)})`);
259
+ this.log("info", `[delegate] ▶ delegateTask(agentUrl=${params.agentUrl}, taskLen=${params.task.length})`);
260
+ this.log("info", `[delegate] task preview: ${params.task.slice(0, 120)}`);
260
261
  await this.requireCompleteProfile();
261
262
  const agentRecord = await this.agentRegistry.get(params.agentUrl);
262
263
  if (!agentRecord) {
263
- this.log("warn", `delegateTask: unknown agent ${params.agentUrl}`);
264
+ this.log("warn", `[delegate] unknown agent: ${params.agentUrl}`);
264
265
  return { status: "failed", error: `unknown agent: ${params.agentUrl}` };
265
266
  }
267
+ this.log("info", `[delegate] agent found: ${agentRecord.name} (${agentRecord.url})`);
266
268
  const track = this.taskTracker.create({
267
269
  fromPeerId: "local",
268
270
  toPeerId: params.agentUrl,
269
271
  task: params.task,
270
272
  });
271
273
  this.taskTracker.update(track.taskId, { status: "running" });
274
+ this.log("info", `[delegate] task tracked: ${track.taskId}, status=running`);
272
275
  try {
276
+ this.log("info", `[delegate] ${track.taskId} creating A2A client for ${agentRecord.url}`);
273
277
  const client = await this.createA2AClient(agentRecord);
278
+ this.log("info", `[delegate] ${track.taskId} A2A client created, starting fire-and-forget send`);
274
279
  // Fire-and-forget execution: keep running in the background so that
275
280
  // the gateway call can return quickly and the task can outlive
276
281
  // the gateway's HTTP timeout.
277
282
  void (async () => {
278
283
  try {
284
+ this.log("info", `[delegate] ${track.taskId} sending A2A message (background)...`);
279
285
  const result = await client.sendMessage({
280
286
  message: {
281
287
  kind: "message",
@@ -284,22 +290,24 @@ class MulticlawsService extends node_events_1.EventEmitter {
284
290
  messageId: track.taskId,
285
291
  },
286
292
  });
293
+ this.log("info", `[delegate] ${track.taskId} A2A response received (background)`);
287
294
  this.processTaskResult(track.taskId, result);
288
295
  }
289
296
  catch (err) {
290
297
  const errorMsg = err instanceof Error ? err.message : String(err);
291
298
  this.taskTracker.update(track.taskId, { status: "failed", error: errorMsg });
292
- this.log("warn", `delegateTask background execution for ${track.taskId} failed: ${errorMsg}`);
299
+ this.log("error", `[delegate] ${track.taskId} background send failed: ${errorMsg}`);
293
300
  }
294
301
  })();
295
302
  // Return immediately so that gateway tool invocations are fast and
296
303
  // do not depend on the remote agent's total execution time.
304
+ this.log("info", `[delegate] ${track.taskId} returned immediately (fire-and-forget)`);
297
305
  return { taskId: track.taskId, status: "running" };
298
306
  }
299
307
  catch (err) {
300
308
  const errorMsg = err instanceof Error ? err.message : String(err);
301
309
  this.taskTracker.update(track.taskId, { status: "failed", error: errorMsg });
302
- this.log("error", `delegateTask failed for ${track.taskId}: ${errorMsg}`);
310
+ this.log("error", `[delegate] ${track.taskId} failed: ${errorMsg}`);
303
311
  return { taskId: track.taskId, status: "failed", error: errorMsg };
304
312
  }
305
313
  }
@@ -308,37 +316,47 @@ class MulticlawsService extends node_events_1.EventEmitter {
308
316
  * Used by sub-agents internally via the multiclaws_delegate_send tool.
309
317
  */
310
318
  async delegateTaskSync(params) {
311
- this.log("info", `delegateTaskSync(agentUrl=${params.agentUrl}, task=${params.task.slice(0, 80)})`);
319
+ this.log("info", `[delegate-sync] ▶ delegateTaskSync(agentUrl=${params.agentUrl}, taskLen=${params.task.length})`);
320
+ this.log("info", `[delegate-sync] task preview: ${params.task.slice(0, 120)}`);
312
321
  await this.requireCompleteProfile();
313
322
  const agentRecord = await this.agentRegistry.get(params.agentUrl);
314
323
  if (!agentRecord) {
315
- this.log("warn", `delegateTaskSync: unknown agent ${params.agentUrl}`);
324
+ this.log("warn", `[delegate-sync] unknown agent: ${params.agentUrl}`);
316
325
  return { status: "failed", error: `unknown agent: ${params.agentUrl}` };
317
326
  }
327
+ this.log("info", `[delegate-sync] agent found: ${agentRecord.name} (${agentRecord.url})`);
318
328
  const track = this.taskTracker.create({
319
329
  fromPeerId: "local",
320
330
  toPeerId: params.agentUrl,
321
331
  task: params.task,
322
332
  });
323
333
  this.taskTracker.update(track.taskId, { status: "running" });
334
+ this.log("info", `[delegate-sync] task tracked: ${track.taskId}, status=running`);
324
335
  try {
336
+ this.log("info", `[delegate-sync] ${track.taskId} creating A2A client for ${agentRecord.url}`);
325
337
  const client = await this.createA2AClient(agentRecord);
338
+ this.log("info", `[delegate-sync] ${track.taskId} sending A2A message (sync, with metadata: selfUrl=${this.selfUrl}, selfName=${this.agentCard?.name ?? "unknown"})...`);
326
339
  const result = await client.sendMessage({
327
340
  message: {
328
341
  kind: "message",
329
342
  role: "user",
330
343
  parts: [{ kind: "text", text: params.task }],
331
344
  messageId: track.taskId,
345
+ metadata: {
346
+ agentUrl: this.selfUrl,
347
+ agentName: this.agentCard?.name ?? "unknown",
348
+ },
332
349
  },
333
350
  });
351
+ this.log("info", `[delegate-sync] ${track.taskId} A2A response received`);
334
352
  const taskResult = this.processTaskResult(track.taskId, result);
335
- this.log("debug", `delegateTaskSync completed for ${track.taskId}`);
353
+ this.log("info", `[delegate-sync] ${track.taskId} completed — status=${taskResult.status}, outputLen=${taskResult.output?.length ?? 0}`);
336
354
  return taskResult;
337
355
  }
338
356
  catch (err) {
339
357
  const errorMsg = err instanceof Error ? err.message : String(err);
340
358
  this.taskTracker.update(track.taskId, { status: "failed", error: errorMsg });
341
- this.log("error", `delegateTaskSync failed for ${track.taskId}: ${errorMsg}`);
359
+ this.log("error", `[delegate-sync] ${track.taskId} failed: ${errorMsg}`);
342
360
  return { taskId: track.taskId, status: "failed", error: errorMsg };
343
361
  }
344
362
  }
@@ -348,26 +366,30 @@ class MulticlawsService extends node_events_1.EventEmitter {
348
366
  * reports results back to the user via the message tool.
349
367
  */
350
368
  async spawnDelegation(params) {
351
- this.log("info", `spawnDelegation(agentUrl=${params.agentUrl}, task=${params.task.slice(0, 80)})`);
369
+ this.log("info", `[spawn-delegate] ▶ spawnDelegation(agentUrl=${params.agentUrl}, taskLen=${params.task.length})`);
370
+ this.log("info", `[spawn-delegate] task preview: ${params.task.slice(0, 120)}`);
352
371
  await this.requireCompleteProfile();
353
372
  const agent = await this.agentRegistry.get(params.agentUrl);
354
373
  if (!agent) {
355
- this.log("warn", `spawnDelegation: unknown agent ${params.agentUrl}`);
374
+ this.log("warn", `[spawn-delegate] unknown agent: ${params.agentUrl}`);
356
375
  throw new Error(`unknown agent: ${params.agentUrl}`);
357
376
  }
377
+ this.log("info", `[spawn-delegate] agent found: ${agent.name} (${agent.url})`);
358
378
  if (!this.gatewayConfig) {
359
- this.log("error", "spawnDelegation: gateway config not available");
379
+ this.log("error", `[spawn-delegate] gateway config not available`);
360
380
  throw new Error("gateway config not available — cannot spawn sub-agent");
361
381
  }
362
382
  const prompt = buildDelegationPrompt(agent, params.task);
363
- await (0, gateway_client_1.invokeGatewayTool)({
383
+ const sessionKey = `delegate-${Date.now()}`;
384
+ this.log("info", `[spawn-delegate] spawning sub-agent via sessions_spawn (cwd=${this.resolvedCwd}, sessionKey=${sessionKey}, promptLen=${prompt.length})`);
385
+ const spawnResult = await (0, gateway_client_1.invokeGatewayTool)({
364
386
  gateway: this.gatewayConfig,
365
387
  tool: "sessions_spawn",
366
388
  args: { task: prompt, mode: "run", cwd: this.resolvedCwd },
367
- sessionKey: `delegate-${Date.now()}`,
389
+ sessionKey,
368
390
  timeoutMs: 15_000,
369
391
  });
370
- this.log("info", `spawnDelegation completed: sub-agent spawned for ${agent.name}`);
392
+ this.log("info", `[spawn-delegate] sub-agent spawned for ${agent.name} — result=${JSON.stringify(spawnResult).slice(0, 200)}`);
371
393
  return { message: `已启动子 agent 向 ${agent.name} 委派任务` };
372
394
  }
373
395
  getTaskStatus(taskId) {
@@ -858,24 +880,27 @@ class MulticlawsService extends node_events_1.EventEmitter {
858
880
  * return the final Task or Message as soon as B signals completion.
859
881
  */
860
882
  processTaskResult(trackId, result) {
861
- this.log("debug", `processTaskResult(trackId=${trackId})`);
883
+ this.log("info", `[process-result] processing result for ${trackId}, resultType=${("status" in result && result.status) ? "Task" : "Message"}`);
862
884
  try {
863
885
  if ("status" in result && result.status) {
864
886
  const task = result;
865
887
  const state = task.status?.state ?? "unknown";
866
888
  const output = this.extractArtifactText(task);
889
+ this.log("info", `[process-result] ${trackId} Task response — state=${state}, outputLen=${output.length}, preview=${output.slice(0, 120)}`);
867
890
  if (state === "completed") {
868
891
  this.taskTracker.update(trackId, { status: "completed", result: output });
892
+ this.log("info", `[process-result] ✓ ${trackId} marked completed`);
869
893
  }
870
894
  else if (state === "failed") {
871
895
  this.taskTracker.update(trackId, { status: "failed", error: output || "remote task failed" });
896
+ this.log("warn", `[process-result] ✗ ${trackId} marked failed — error=${output || "remote task failed"}`);
872
897
  }
873
898
  else {
874
899
  // For any other state (unknown, working, etc.), mark as failed to avoid
875
900
  // tasks stuck in "running" forever until TTL prune.
876
901
  this.taskTracker.update(trackId, { status: "failed", error: `unexpected remote state: ${state}` });
902
+ this.log("warn", `[process-result] ✗ ${trackId} unexpected state=${state}, marked failed`);
877
903
  }
878
- this.log("debug", `processTaskResult completed, status=${state}`);
879
904
  return { taskId: task.id, output, status: state };
880
905
  }
881
906
  const msg = result;
@@ -884,11 +909,11 @@ class MulticlawsService extends node_events_1.EventEmitter {
884
909
  .map((p) => p.text)
885
910
  .join("\n") ?? "";
886
911
  this.taskTracker.update(trackId, { status: "completed", result: text });
887
- this.log("debug", "processTaskResult completed, status=completed (message)");
912
+ this.log("info", `[process-result] ✓ ${trackId} Message response — completed, textLen=${text.length}, preview=${text.slice(0, 120)}`);
888
913
  return { taskId: trackId, output: text, status: "completed" };
889
914
  }
890
915
  catch (err) {
891
- this.log("error", `processTaskResult failed for ${trackId}: ${err instanceof Error ? err.message : String(err)}`);
916
+ this.log("error", `[process-result] ${trackId} processing failed: ${err instanceof Error ? err.message : String(err)}`);
892
917
  throw err;
893
918
  }
894
919
  }
@@ -920,11 +945,16 @@ class MulticlawsService extends node_events_1.EventEmitter {
920
945
  }
921
946
  throw lastError;
922
947
  }
923
- /** Register a channel ID for notifications. */
948
+ /** Resolve a pending A2A callback from sub-agent. */
924
949
  resolveA2ACallback(taskId, result) {
925
- if (!this.agentExecutor)
950
+ this.log("info", `[a2a-callback] resolveA2ACallback(taskId=${taskId}, resultLen=${result.length})`);
951
+ if (!this.agentExecutor) {
952
+ this.log("warn", `[a2a-callback] ✗ no agentExecutor available for taskId=${taskId}`);
926
953
  return false;
927
- return this.agentExecutor.resolveCallback(taskId, result);
954
+ }
955
+ const resolved = this.agentExecutor.resolveCallback(taskId, result);
956
+ this.log("info", `[a2a-callback] ${resolved ? "✓" : "✗"} taskId=${taskId} ${resolved ? "resolved" : "no pending callback found"}`);
957
+ return resolved;
928
958
  }
929
959
  addNotificationTarget(key, target) {
930
960
  if (!this.notificationTargets.has(key)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multiclaws",
3
- "version": "0.4.33",
3
+ "version": "0.4.34",
4
4
  "description": "MultiClaws plugin for OpenClaw collaboration via A2A protocol",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",