multiclaws 0.4.15 → 0.4.17

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/infra/frp.js CHANGED
@@ -362,8 +362,9 @@ class FrpTunnelManager {
362
362
  (0, node_child_process_1.execSync)(`tar -xzf "${archivePath}" -C "${downloadDir}"`, { stdio: "ignore" });
363
363
  }
364
364
  else {
365
- // Windows: tar does not support .zip; use PowerShell's Expand-Archive instead
366
- (0, node_child_process_1.execSync)(`powershell -NoProfile -Command "Expand-Archive -LiteralPath '${archivePath}' -DestinationPath '${downloadDir}' -Force"`, { stdio: "ignore" });
365
+ // Windows: suppress progress bar to prevent silent failure in headless environments;
366
+ // use stdio:"pipe" so execSync captures errors if PowerShell exits non-zero
367
+ (0, node_child_process_1.execSync)(`powershell -NoProfile -Command "$ProgressPreference = 'SilentlyContinue'; Expand-Archive -LiteralPath '${archivePath}' -DestinationPath '${downloadDir}' -Force"`, { stdio: "pipe" });
367
368
  }
368
369
  // Move binary to target
369
370
  const extractedBinary = node_path_1.default.join(downloadDir, archiveName, binaryName);
@@ -27,17 +27,20 @@ export declare class OpenClawAgentExecutor implements AgentExecutor {
27
27
  constructor(options: A2AAdapterOptions);
28
28
  execute(context: RequestContext, eventBus: ExecutionEventBus): Promise<void>;
29
29
  /**
30
- * Poll sessions_history until the subagent produces a final assistant message.
31
- * Uses backoff: 2s, 3s, 4s, then 5s intervals.
30
+ * Poll sessions_history until the subagent session completes.
31
+ * Collects ALL assistant text messages and returns them joined.
32
32
  */
33
33
  private waitForCompletion;
34
34
  /**
35
- * Extract the final assistant response from session history.
35
+ * Extract all assistant text from session history once the session is complete.
36
36
  * Returns null if the session is still running.
37
+ * Returns all assistant text messages joined (not just the last one).
37
38
  *
38
39
  * Gateway /tools/invoke returns: { content: [...], details: { messages: [...], isComplete?: boolean } }
39
40
  */
40
41
  private extractCompletedResult;
42
+ /** Extract text content from a single history message. */
43
+ private extractTextFromHistoryMessage;
41
44
  cancelTask(taskId: string, eventBus: ExecutionEventBus): Promise<void>;
42
45
  updateGatewayConfig(config: GatewayConfig): void;
43
46
  private publishMessage;
@@ -103,14 +103,13 @@ class OpenClawAgentExecutor {
103
103
  eventBus.finished();
104
104
  }
105
105
  /**
106
- * Poll sessions_history until the subagent produces a final assistant message.
107
- * Uses backoff: 2s, 3s, 4s, then 5s intervals.
106
+ * Poll sessions_history until the subagent session completes.
107
+ * Collects ALL assistant text messages and returns them joined.
108
108
  */
109
109
  async waitForCompletion(sessionKey, timeoutMs) {
110
110
  const gateway = this.gatewayConfig;
111
111
  const startTime = Date.now();
112
112
  let attempt = 0;
113
- // Start aggressive, max out at 500ms to minimize result latency
114
113
  const pollDelays = [100, 200, 300, 500];
115
114
  while (Date.now() - startTime < timeoutMs) {
116
115
  const delay = pollDelays[Math.min(attempt, pollDelays.length - 1)];
@@ -122,7 +121,7 @@ class OpenClawAgentExecutor {
122
121
  tool: "sessions_history",
123
122
  args: {
124
123
  sessionKey,
125
- limit: 20,
124
+ limit: 50,
126
125
  includeTools: false,
127
126
  },
128
127
  timeoutMs: 8_000,
@@ -140,8 +139,9 @@ class OpenClawAgentExecutor {
140
139
  throw new Error(`task timed out after ${Math.round(timeoutMs / 1000)}s waiting for subagent`);
141
140
  }
142
141
  /**
143
- * Extract the final assistant response from session history.
142
+ * Extract all assistant text from session history once the session is complete.
144
143
  * Returns null if the session is still running.
144
+ * Returns all assistant text messages joined (not just the last one).
145
145
  *
146
146
  * Gateway /tools/invoke returns: { content: [...], details: { messages: [...], isComplete?: boolean } }
147
147
  */
@@ -152,37 +152,69 @@ class OpenClawAgentExecutor {
152
152
  // Respect explicit completion flag from gateway
153
153
  if (details.isComplete === false)
154
154
  return null;
155
+ // Check for session-level error/status from gateway
156
+ const sessionError = details.error;
157
+ const sessionStatus = details.status;
155
158
  const messages = (details.messages ?? []);
156
- if (messages.length === 0)
159
+ if (messages.length === 0 && !details.isComplete)
157
160
  return null;
158
- // If no explicit flag, check the last message for signs of ongoing execution
161
+ // If no explicit isComplete flag, use heuristic: check if the session is still executing
159
162
  if (details.isComplete === undefined) {
163
+ if (messages.length === 0)
164
+ return null;
160
165
  const lastMsg = messages[messages.length - 1];
161
166
  if (lastMsg && Array.isArray(lastMsg.content)) {
162
167
  const content = lastMsg.content;
163
168
  const hasToolCalls = content.some((c) => c?.type === "toolCall" || c?.type === "tool_use");
169
+ // If the last message only has tool calls (no text), still running
164
170
  const hasText = content.some((c) => c?.type === "text" && typeof c.text === "string" && c.text.trim());
165
171
  if (hasToolCalls && !hasText)
166
172
  return null;
167
173
  }
174
+ // If the last message is a user message, the agent hasn't responded yet
175
+ if (lastMsg?.role === "user")
176
+ return null;
168
177
  }
169
- // Walk backwards to find the last assistant message with text content
170
- for (let i = messages.length - 1; i >= 0; i--) {
171
- const msg = messages[i];
178
+ // Session is complete collect ALL assistant text messages in order
179
+ const allTexts = [];
180
+ for (const msg of messages) {
172
181
  if (msg.role !== "assistant")
173
182
  continue;
174
- const content = msg.content;
175
- if (typeof content === "string" && content.trim()) {
176
- return content;
183
+ const text = this.extractTextFromHistoryMessage(msg);
184
+ if (text)
185
+ allTexts.push(text);
186
+ }
187
+ // If we have assistant text, return it (even if there's also an error)
188
+ if (allTexts.length > 0) {
189
+ // Append error info if present so the delegating agent sees both
190
+ if (sessionError) {
191
+ allTexts.push(`[session error: ${sessionError}]`);
177
192
  }
178
- if (Array.isArray(content)) {
179
- const parts = content;
180
- const textParts = parts
181
- .filter((c) => c?.type === "text" && typeof c.text === "string" && c.text.trim())
182
- .map((c) => c.text);
183
- if (textParts.length > 0) {
184
- return textParts.join("\n");
185
- }
193
+ return allTexts.join("\n\n");
194
+ }
195
+ // No assistant text — check if the session reported an error
196
+ if (sessionError) {
197
+ return `Error: ${sessionError}`;
198
+ }
199
+ if (sessionStatus === "failed" || sessionStatus === "error") {
200
+ return `Error: session ended with status "${sessionStatus}"`;
201
+ }
202
+ // Session truly completed with no output at all
203
+ return "(task completed with no text output)";
204
+ }
205
+ /** Extract text content from a single history message. */
206
+ extractTextFromHistoryMessage(msg) {
207
+ const content = msg.content;
208
+ if (typeof content === "string" && content.trim()) {
209
+ return content;
210
+ }
211
+ if (Array.isArray(content)) {
212
+ const parts = content;
213
+ const textParts = parts
214
+ .filter((c) => c?.type === "text" && typeof c.text === "string" && c.text.trim())
215
+ .map((c) => c.text);
216
+ if (textParts.length > 0) {
217
+ return textParts.join("\n");
186
218
  }
187
219
  }
188
220
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multiclaws",
3
- "version": "0.4.15",
3
+ "version": "0.4.17",
4
4
  "description": "MultiClaws plugin for OpenClaw collaboration via A2A protocol",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",