multiclaws 0.4.29 → 0.4.30
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
|
@@ -542,10 +542,10 @@ const plugin = {
|
|
|
542
542
|
api.on("gateway_stop", () => {
|
|
543
543
|
structured.logger.info("[multiclaws] gateway_stop observed");
|
|
544
544
|
});
|
|
545
|
-
//
|
|
545
|
+
// Collect all channel IDs for broadcasting notifications
|
|
546
546
|
api.on("message_received", (_event, ctx) => {
|
|
547
547
|
if (service && ctx.channelId) {
|
|
548
|
-
service.
|
|
548
|
+
service.addChannelId(ctx.channelId);
|
|
549
549
|
}
|
|
550
550
|
});
|
|
551
551
|
// Inject onboarding prompt when profile is pending first-run setup
|
|
@@ -5,7 +5,7 @@ export type A2AAdapterOptions = {
|
|
|
5
5
|
gatewayConfig: GatewayConfig | null;
|
|
6
6
|
taskTracker: TaskTracker;
|
|
7
7
|
cwd?: string;
|
|
8
|
-
|
|
8
|
+
getChannelIds?: () => ReadonlySet<string>;
|
|
9
9
|
logger: {
|
|
10
10
|
info: (msg: string) => void;
|
|
11
11
|
warn: (msg: string) => void;
|
|
@@ -25,7 +25,7 @@ export type A2AAdapterOptions = {
|
|
|
25
25
|
export declare class OpenClawAgentExecutor implements AgentExecutor {
|
|
26
26
|
private gatewayConfig;
|
|
27
27
|
private readonly taskTracker;
|
|
28
|
-
private readonly
|
|
28
|
+
private readonly getChannelIds;
|
|
29
29
|
private readonly logger;
|
|
30
30
|
private readonly cwd;
|
|
31
31
|
constructor(options: A2AAdapterOptions);
|
|
@@ -47,7 +47,7 @@ export declare class OpenClawAgentExecutor implements AgentExecutor {
|
|
|
47
47
|
private extractTextFromHistoryMessage;
|
|
48
48
|
cancelTask(taskId: string, eventBus: ExecutionEventBus): Promise<void>;
|
|
49
49
|
updateGatewayConfig(config: GatewayConfig): void;
|
|
50
|
-
/** Send a notification to
|
|
50
|
+
/** Send a notification to all known channels. Individual failures are silently ignored. */
|
|
51
51
|
private notifyUser;
|
|
52
52
|
private publishMessage;
|
|
53
53
|
}
|
|
@@ -41,13 +41,13 @@ function extractDetails(result) {
|
|
|
41
41
|
class OpenClawAgentExecutor {
|
|
42
42
|
gatewayConfig;
|
|
43
43
|
taskTracker;
|
|
44
|
-
|
|
44
|
+
getChannelIds;
|
|
45
45
|
logger;
|
|
46
46
|
cwd;
|
|
47
47
|
constructor(options) {
|
|
48
48
|
this.gatewayConfig = options.gatewayConfig;
|
|
49
49
|
this.taskTracker = options.taskTracker;
|
|
50
|
-
this.
|
|
50
|
+
this.getChannelIds = options.getChannelIds ?? (() => new Set());
|
|
51
51
|
this.logger = options.logger;
|
|
52
52
|
this.cwd = options.cwd || process.cwd();
|
|
53
53
|
}
|
|
@@ -142,10 +142,11 @@ class OpenClawAgentExecutor {
|
|
|
142
142
|
});
|
|
143
143
|
const result = this.extractCompletedResult(histResult);
|
|
144
144
|
if (result !== null) {
|
|
145
|
+
this.logger.info(`[a2a-adapter] poll attempt ${attempt}: session ${sessionKey} completed, resultLen=${result.length}`);
|
|
145
146
|
return result;
|
|
146
147
|
}
|
|
147
|
-
// Log details
|
|
148
|
-
if (attempt %
|
|
148
|
+
// Log details on first attempt, then every 10 attempts for diagnosis
|
|
149
|
+
if (attempt === 1 || attempt % 10 === 0) {
|
|
149
150
|
const details = extractDetails(histResult);
|
|
150
151
|
const messages = (details?.messages ?? []);
|
|
151
152
|
const lastMsg = messages[messages.length - 1];
|
|
@@ -164,7 +165,9 @@ class OpenClawAgentExecutor {
|
|
|
164
165
|
this.logger.warn(`[a2a-adapter] poll attempt ${attempt} error: ${err instanceof Error ? err.message : err}`);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
|
-
|
|
168
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
169
|
+
this.logger.error(`[a2a-adapter] waitForCompletion timed out: session=${sessionKey}, elapsed=${elapsed}s, attempts=${attempt}`);
|
|
170
|
+
throw new Error(`task timed out after ${elapsed}s (${attempt} attempts) waiting for subagent`);
|
|
168
171
|
}
|
|
169
172
|
/**
|
|
170
173
|
* Extract all assistant text from session history once the session is complete.
|
|
@@ -180,6 +183,12 @@ class OpenClawAgentExecutor {
|
|
|
180
183
|
// Check for session-level error/status from gateway
|
|
181
184
|
const sessionError = details.error;
|
|
182
185
|
const sessionStatus = details.status;
|
|
186
|
+
// Immediately fail on terminal session statuses — do NOT keep polling
|
|
187
|
+
const terminalStatuses = ["forbidden", "failed", "error", "not_found", "unauthorized"];
|
|
188
|
+
if (sessionStatus && terminalStatuses.includes(sessionStatus)) {
|
|
189
|
+
this.logger.warn(`[a2a-adapter] extractCompletedResult: terminal status="${sessionStatus}", error="${sessionError ?? "none"}"`);
|
|
190
|
+
return `Error: session status "${sessionStatus}"${sessionError ? `: ${sessionError}` : ""}`;
|
|
191
|
+
}
|
|
183
192
|
const messages = (details.messages ?? []);
|
|
184
193
|
if (messages.length === 0 && !details.isComplete)
|
|
185
194
|
return null;
|
|
@@ -253,22 +262,17 @@ class OpenClawAgentExecutor {
|
|
|
253
262
|
updateGatewayConfig(config) {
|
|
254
263
|
this.gatewayConfig = config;
|
|
255
264
|
}
|
|
256
|
-
/** Send a notification to
|
|
265
|
+
/** Send a notification to all known channels. Individual failures are silently ignored. */
|
|
257
266
|
async notifyUser(message) {
|
|
258
|
-
const
|
|
259
|
-
if (!this.gatewayConfig ||
|
|
267
|
+
const channels = this.getChannelIds();
|
|
268
|
+
if (!this.gatewayConfig || channels.size === 0)
|
|
260
269
|
return;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
catch {
|
|
270
|
-
this.logger.warn(`[a2a-adapter] notifyUser failed: ${message.slice(0, 80)}`);
|
|
271
|
-
}
|
|
270
|
+
await Promise.allSettled([...channels].map((target) => (0, gateway_client_1.invokeGatewayTool)({
|
|
271
|
+
gateway: this.gatewayConfig,
|
|
272
|
+
tool: "message",
|
|
273
|
+
args: { action: "send", target, message },
|
|
274
|
+
timeoutMs: 5_000,
|
|
275
|
+
})));
|
|
272
276
|
}
|
|
273
277
|
publishMessage(eventBus, text) {
|
|
274
278
|
const message = {
|
|
@@ -45,7 +45,7 @@ export declare class MulticlawsService extends EventEmitter {
|
|
|
45
45
|
private profileDescription;
|
|
46
46
|
private readonly gatewayConfig;
|
|
47
47
|
private readonly resolvedCwd;
|
|
48
|
-
private
|
|
48
|
+
private readonly knownChannelIds;
|
|
49
49
|
constructor(options: MulticlawsServiceOptions);
|
|
50
50
|
start(): Promise<void>;
|
|
51
51
|
stop(): Promise<void>;
|
|
@@ -126,9 +126,9 @@ export declare class MulticlawsService extends EventEmitter {
|
|
|
126
126
|
private extractArtifactText;
|
|
127
127
|
/** Fetch with up to 2 retries and exponential backoff. */
|
|
128
128
|
private fetchWithRetry;
|
|
129
|
-
/**
|
|
130
|
-
|
|
131
|
-
/** Send a notification to
|
|
129
|
+
/** Register a channel ID for notifications. */
|
|
130
|
+
addChannelId(channelId: string): void;
|
|
131
|
+
/** Send a notification to all known channels. Individual failures are silently ignored. */
|
|
132
132
|
private notifyUser;
|
|
133
133
|
private log;
|
|
134
134
|
}
|
|
@@ -68,7 +68,7 @@ class MulticlawsService extends node_events_1.EventEmitter {
|
|
|
68
68
|
profileDescription = "OpenClaw agent";
|
|
69
69
|
gatewayConfig;
|
|
70
70
|
resolvedCwd;
|
|
71
|
-
|
|
71
|
+
knownChannelIds = new Set();
|
|
72
72
|
constructor(options) {
|
|
73
73
|
super();
|
|
74
74
|
this.options = options;
|
|
@@ -123,7 +123,7 @@ class MulticlawsService extends node_events_1.EventEmitter {
|
|
|
123
123
|
gatewayConfig: this.options.gatewayConfig ?? null,
|
|
124
124
|
taskTracker: this.taskTracker,
|
|
125
125
|
cwd: this.resolvedCwd,
|
|
126
|
-
|
|
126
|
+
getChannelIds: () => this.knownChannelIds,
|
|
127
127
|
logger,
|
|
128
128
|
});
|
|
129
129
|
this.agentCard = {
|
|
@@ -919,26 +919,23 @@ class MulticlawsService extends node_events_1.EventEmitter {
|
|
|
919
919
|
}
|
|
920
920
|
throw lastError;
|
|
921
921
|
}
|
|
922
|
-
/**
|
|
923
|
-
|
|
924
|
-
this.
|
|
925
|
-
|
|
922
|
+
/** Register a channel ID for notifications. */
|
|
923
|
+
addChannelId(channelId) {
|
|
924
|
+
if (!this.knownChannelIds.has(channelId)) {
|
|
925
|
+
this.knownChannelIds.add(channelId);
|
|
926
|
+
this.log("debug", `channel registered: ${channelId} (total: ${this.knownChannelIds.size})`);
|
|
927
|
+
}
|
|
926
928
|
}
|
|
927
|
-
/** Send a notification to
|
|
929
|
+
/** Send a notification to all known channels. Individual failures are silently ignored. */
|
|
928
930
|
async notifyUser(message) {
|
|
929
|
-
if (!this.gatewayConfig ||
|
|
931
|
+
if (!this.gatewayConfig || this.knownChannelIds.size === 0)
|
|
930
932
|
return;
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
|
-
catch (err) {
|
|
940
|
-
this.log("warn", `notifyUser failed: ${err instanceof Error ? err.message : String(err)} | msg=${message.slice(0, 80)}`);
|
|
941
|
-
}
|
|
933
|
+
await Promise.allSettled([...this.knownChannelIds].map((target) => (0, gateway_client_1.invokeGatewayTool)({
|
|
934
|
+
gateway: this.gatewayConfig,
|
|
935
|
+
tool: "message",
|
|
936
|
+
args: { action: "send", target, message },
|
|
937
|
+
timeoutMs: 5_000,
|
|
938
|
+
})));
|
|
942
939
|
}
|
|
943
940
|
log(level, message) {
|
|
944
941
|
this.options.logger?.[level]?.(`[multiclaws] ${message}`);
|