clawmoney 0.17.23 → 0.17.25
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/hub/executor.d.ts +10 -2
- package/dist/hub/executor.js +30 -2
- package/dist/hub/types.d.ts +14 -1
- package/dist/hub/ws-client.js +15 -1
- package/package.json +1 -1
package/dist/hub/executor.d.ts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import type { ProviderConfig, ServiceCallEvent, TestCallEvent, EscrowTaskEvent, DeliverEvent, TestResponseEvent } from "./types.js";
|
|
2
|
-
type SendFn = (event: DeliverEvent | TestResponseEvent) => boolean;
|
|
1
|
+
import type { ProviderConfig, ServiceCallEvent, TestCallEvent, EscrowTaskEvent, DeliverEvent, TestResponseEvent, ProgressEvent } from "./types.js";
|
|
2
|
+
type SendFn = (event: DeliverEvent | TestResponseEvent | ProgressEvent) => boolean;
|
|
3
3
|
export declare class Executor {
|
|
4
4
|
private config;
|
|
5
5
|
private send;
|
|
6
6
|
private activeTasks;
|
|
7
7
|
constructor(config: ProviderConfig, send: SendFn);
|
|
8
8
|
get activeCount(): number;
|
|
9
|
+
/**
|
|
10
|
+
* Fire a progress update for an in-flight order. The buyer-facing UI
|
|
11
|
+
* (clawmoney-web playground) polls /market/orders/{id} and reads the
|
|
12
|
+
* `progress` field that backend Redis-caches from these events.
|
|
13
|
+
* Best-effort: failed sends are non-fatal (the UI just sees a slightly
|
|
14
|
+
* stale stage label until the next progress fires).
|
|
15
|
+
*/
|
|
16
|
+
private sendProgress;
|
|
9
17
|
handleServiceCall(call: ServiceCallEvent): void;
|
|
10
18
|
handleEscrowTask(task: EscrowTaskEvent): void;
|
|
11
19
|
private executeEscrowTask;
|
package/dist/hub/executor.js
CHANGED
|
@@ -201,7 +201,7 @@ async function waitForStableSize(filePath) {
|
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
// ── CLI execution (openclaw agent / claude -p) ──
|
|
204
|
-
function runCli(command, prompt, timeoutMs, orderId, watchForImage) {
|
|
204
|
+
function runCli(command, prompt, timeoutMs, orderId, watchForImage, onProgress) {
|
|
205
205
|
return new Promise((resolve) => {
|
|
206
206
|
// Build args based on command
|
|
207
207
|
let args;
|
|
@@ -290,6 +290,10 @@ function runCli(command, prompt, timeoutMs, orderId, watchForImage) {
|
|
|
290
290
|
resolve({ stdout, stderr, exitCode: 0 });
|
|
291
291
|
};
|
|
292
292
|
if (dirBaseline) {
|
|
293
|
+
// Report once when codex actually starts working — the spawn ack
|
|
294
|
+
// is fast but the first reasoning step can take ~10s and we want
|
|
295
|
+
// the UI to know "we're actually running, not just queued".
|
|
296
|
+
onProgress?.("Generating image…");
|
|
293
297
|
pollHandle = setInterval(() => {
|
|
294
298
|
if (earlyResolved)
|
|
295
299
|
return;
|
|
@@ -299,6 +303,7 @@ function runCli(command, prompt, timeoutMs, orderId, watchForImage) {
|
|
|
299
303
|
clearInterval(pollHandle);
|
|
300
304
|
pollHandle = null;
|
|
301
305
|
}
|
|
306
|
+
onProgress?.("Image generated, finalizing…");
|
|
302
307
|
void finishWithEarlyImage(newImage);
|
|
303
308
|
}
|
|
304
309
|
}, POLL_INTERVAL_MS);
|
|
@@ -456,6 +461,22 @@ export class Executor {
|
|
|
456
461
|
get activeCount() {
|
|
457
462
|
return this.activeTasks.size;
|
|
458
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Fire a progress update for an in-flight order. The buyer-facing UI
|
|
466
|
+
* (clawmoney-web playground) polls /market/orders/{id} and reads the
|
|
467
|
+
* `progress` field that backend Redis-caches from these events.
|
|
468
|
+
* Best-effort: failed sends are non-fatal (the UI just sees a slightly
|
|
469
|
+
* stale stage label until the next progress fires).
|
|
470
|
+
*/
|
|
471
|
+
sendProgress(orderId, text) {
|
|
472
|
+
try {
|
|
473
|
+
this.send({ event: "progress", order_id: orderId, progress: text });
|
|
474
|
+
}
|
|
475
|
+
catch {
|
|
476
|
+
// Ignore — WS may be reconnecting; the next progress event will
|
|
477
|
+
// pick up where we left off.
|
|
478
|
+
}
|
|
479
|
+
}
|
|
459
480
|
handleServiceCall(call) {
|
|
460
481
|
if (isProcessed(call.order_id)) {
|
|
461
482
|
logger.info(`Skipping duplicate order: ${call.order_id}`);
|
|
@@ -650,11 +671,15 @@ export class Executor {
|
|
|
650
671
|
const timeoutS = Math.max(call.timeout - TIMEOUT_BUFFER_S, 30);
|
|
651
672
|
const command = this.config.provider.cli_command;
|
|
652
673
|
logger.info(`Executing: ${command} for skill="${call.skill}" order=${call.order_id} (timeout=${timeoutS}s)`);
|
|
674
|
+
this.sendProgress(call.order_id, `Spawning ${command}…`);
|
|
653
675
|
const { stdout, stderr, exitCode } = await runCli(command, prompt, timeoutS * 1000, call.order_id,
|
|
654
676
|
// Watch the codex image dir for generation/image so we can
|
|
655
677
|
// ship the moment the file lands, skipping codex's final
|
|
656
678
|
// reasoning tail (~60–90s of pure overhead).
|
|
657
|
-
call.category?.startsWith("generation/image")
|
|
679
|
+
call.category?.startsWith("generation/image"),
|
|
680
|
+
// Progress callback fired inside runCli when we cross
|
|
681
|
+
// observable milestones (image landing on disk, etc).
|
|
682
|
+
(text) => this.sendProgress(call.order_id, text));
|
|
658
683
|
if (exitCode !== 0) {
|
|
659
684
|
const errMsg = stderr.trim() || `CLI exited with code ${exitCode}`;
|
|
660
685
|
logger.error(`CLI failed (code=${exitCode}):`, errMsg);
|
|
@@ -701,6 +726,9 @@ export class Executor {
|
|
|
701
726
|
}
|
|
702
727
|
}
|
|
703
728
|
// Upload local files to R2
|
|
729
|
+
if (allFiles.length > 0) {
|
|
730
|
+
this.sendProgress(call.order_id, "Uploading to CDN…");
|
|
731
|
+
}
|
|
704
732
|
for (const filePath of allFiles) {
|
|
705
733
|
const cdnUrl = await uploadFile(filePath, this.config);
|
|
706
734
|
if (cdnUrl) {
|
package/dist/hub/types.d.ts
CHANGED
|
@@ -56,7 +56,20 @@ export interface TestResponseEvent {
|
|
|
56
56
|
order_id: string;
|
|
57
57
|
output: Record<string, unknown>;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Live in-flight progress reported back to backend during a service_call.
|
|
61
|
+
* Backend stashes the text at hub:progress:<order_id> in Redis with a
|
|
62
|
+
* 10-minute TTL; clawmoney-web's playground poll picks it up via the
|
|
63
|
+
* HubOrderPublic.progress field. Fire-and-forget — backend doesn't
|
|
64
|
+
* ack, so dropped progress messages just mean the UI sees a slightly
|
|
65
|
+
* stale stage label.
|
|
66
|
+
*/
|
|
67
|
+
export interface ProgressEvent {
|
|
68
|
+
event: "progress";
|
|
69
|
+
order_id: string;
|
|
70
|
+
progress: string;
|
|
71
|
+
}
|
|
72
|
+
export type OutgoingEvent = DeliverEvent | TestResponseEvent | ProgressEvent;
|
|
60
73
|
export interface ProviderSettings {
|
|
61
74
|
cli_command: string;
|
|
62
75
|
max_concurrent: number;
|
package/dist/hub/ws-client.js
CHANGED
|
@@ -102,7 +102,21 @@ export class WsClient {
|
|
|
102
102
|
this.stopHeartbeat();
|
|
103
103
|
this.heartbeatTimer = setInterval(() => {
|
|
104
104
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
105
|
-
|
|
105
|
+
// Application-level heartbeat. Backend's `event == "heartbeat"`
|
|
106
|
+
// handler is what updates ClawAgent.last_heartbeat_at, which in
|
|
107
|
+
// turn drives the `agent_is_online` field on /market/skills/search
|
|
108
|
+
// results. A WS protocol-level ping/pong (this.ws.ping()) keeps
|
|
109
|
+
// the TCP connection alive but the backend never sees it as a
|
|
110
|
+
// JSON message — so DB heartbeat would only ever get bumped at
|
|
111
|
+
// initial connect, then go stale after 600s and the agent would
|
|
112
|
+
// disappear from search results despite the daemon being fine.
|
|
113
|
+
try {
|
|
114
|
+
this.ws.send(JSON.stringify({ event: "heartbeat" }));
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Send failure is non-fatal; the reconnect loop will pick up
|
|
118
|
+
// a real socket close if the connection is actually dead.
|
|
119
|
+
}
|
|
106
120
|
}
|
|
107
121
|
}, HEARTBEAT_INTERVAL_MS);
|
|
108
122
|
this.heartbeatTimer.unref();
|