clawmoney 0.17.19 → 0.17.20
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.js +79 -0
- package/package.json +1 -1
package/dist/hub/executor.js
CHANGED
|
@@ -173,21 +173,100 @@ function runCli(command, prompt, timeoutMs, orderId) {
|
|
|
173
173
|
});
|
|
174
174
|
let stdout = "";
|
|
175
175
|
let stderr = "";
|
|
176
|
+
let earlyResolved = false;
|
|
177
|
+
const tryEarlyExit = () => {
|
|
178
|
+
if (earlyResolved)
|
|
179
|
+
return;
|
|
180
|
+
// Only attempt early exit for codex — others either don't stream
|
|
181
|
+
// events with this shape, or already finish promptly after their
|
|
182
|
+
// last output. Codex on xhigh/high reasoning_effort wastes 60–90s
|
|
183
|
+
// doing "final reflection" reasoning even after the agent_message
|
|
184
|
+
// is already emitted with the image_path. Once we see that
|
|
185
|
+
// message in the JSONL stream the deliverable is fully on disk
|
|
186
|
+
// and we can ship the order — kill the child to avoid burning
|
|
187
|
+
// buyer wall-time on reasoning we won't read.
|
|
188
|
+
if (command !== "codex")
|
|
189
|
+
return;
|
|
190
|
+
if (!hasCodexDeliverable(stdout))
|
|
191
|
+
return;
|
|
192
|
+
earlyResolved = true;
|
|
193
|
+
// SIGTERM is enough; codex closes its writer and we'll get a
|
|
194
|
+
// 'close' event shortly. Don't await — let the resolve below
|
|
195
|
+
// return the snapshot we already have.
|
|
196
|
+
try {
|
|
197
|
+
child.kill("SIGTERM");
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// pid may already be gone
|
|
201
|
+
}
|
|
202
|
+
resolve({ stdout, stderr, exitCode: 0 });
|
|
203
|
+
};
|
|
176
204
|
child.stdout.on("data", (chunk) => {
|
|
177
205
|
stdout += chunk.toString();
|
|
206
|
+
tryEarlyExit();
|
|
178
207
|
});
|
|
179
208
|
child.stderr.on("data", (chunk) => {
|
|
180
209
|
stderr += chunk.toString();
|
|
181
210
|
});
|
|
182
211
|
child.on("close", (code) => {
|
|
212
|
+
if (earlyResolved)
|
|
213
|
+
return;
|
|
183
214
|
resolve({ stdout, stderr, exitCode: code });
|
|
184
215
|
});
|
|
185
216
|
child.on("error", (err) => {
|
|
217
|
+
if (earlyResolved)
|
|
218
|
+
return;
|
|
186
219
|
stderr += err.message;
|
|
187
220
|
resolve({ stdout, stderr, exitCode: null });
|
|
188
221
|
});
|
|
189
222
|
});
|
|
190
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Detect whether codex's JSONL stream already contains a final
|
|
226
|
+
* agent_message event whose text parses to JSON with an `image_path`.
|
|
227
|
+
* That's the signal that the image is on disk and the agent has
|
|
228
|
+
* acknowledged it — everything codex does after this point is its
|
|
229
|
+
* own final reasoning loop, which the buyer never sees.
|
|
230
|
+
*
|
|
231
|
+
* Scans newest-to-oldest so we exit as soon as we find the marker.
|
|
232
|
+
*/
|
|
233
|
+
function hasCodexDeliverable(streamSoFar) {
|
|
234
|
+
const lines = streamSoFar.split("\n");
|
|
235
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
236
|
+
const line = lines[i].trim();
|
|
237
|
+
if (!line.startsWith("{"))
|
|
238
|
+
continue;
|
|
239
|
+
let event;
|
|
240
|
+
try {
|
|
241
|
+
event = JSON.parse(line);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (event.type !== "item.completed")
|
|
247
|
+
continue;
|
|
248
|
+
const item = event.item;
|
|
249
|
+
if (item?.type !== "agent_message")
|
|
250
|
+
continue;
|
|
251
|
+
const text = item.text;
|
|
252
|
+
if (typeof text !== "string")
|
|
253
|
+
continue;
|
|
254
|
+
// Cheap pre-check before JSON.parse: must mention image_path.
|
|
255
|
+
if (!text.includes("image_path"))
|
|
256
|
+
continue;
|
|
257
|
+
try {
|
|
258
|
+
const parsed = JSON.parse(text);
|
|
259
|
+
const path = parsed.image_path;
|
|
260
|
+
if (typeof path === "string" && path.length > 0)
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// text wasn't JSON; agent might be talking about image_path
|
|
265
|
+
// in prose. Keep looking — don't early-exit on prose.
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
191
270
|
// ── JSON parser ──
|
|
192
271
|
function parseJsonOutput(raw) {
|
|
193
272
|
try {
|