halo-agent 2.0.0 → 2.0.1
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/orchestrator.js +47 -25
- package/package.json +1 -1
package/orchestrator.js
CHANGED
|
@@ -369,15 +369,46 @@ async function runJob(queueItem, chromeConn, config, reportStatus) {
|
|
|
369
369
|
});
|
|
370
370
|
|
|
371
371
|
if (visionResult.submitted) {
|
|
372
|
-
// Vision
|
|
372
|
+
// Vision THINKS it submitted, but we shouldn't trust that without
|
|
373
|
+
// verifying — vision can confuse "review page rendered" with
|
|
374
|
+
// "application accepted." Route through the same verify-submit
|
|
375
|
+
// gate everything else uses. Worst case → REVIEWING, user clicks
|
|
376
|
+
// Submit. Better than a false-positive DONE.
|
|
373
377
|
const confirmShot = await page.screenshot({ type: 'jpeg', quality: 70 }).catch(() => null);
|
|
374
378
|
const confirmKey = confirmShot ? await uploadScreenshot(config, confirmShot, `confirm_${queueId}.jpg`) : null;
|
|
375
|
-
|
|
376
|
-
|
|
379
|
+
const verdictUrl = page.url();
|
|
380
|
+
let vVerdict = { submitted: null, error_message: null, source: 'unavailable' };
|
|
381
|
+
try {
|
|
382
|
+
const vRes = await fetch(`${config.apiUrl}/agent/verify-submit`, {
|
|
383
|
+
method: 'POST',
|
|
384
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.token}` },
|
|
385
|
+
body: JSON.stringify({ queue_id: queueId, page_url: verdictUrl }),
|
|
386
|
+
});
|
|
387
|
+
if (vRes.ok) vVerdict = await vRes.json();
|
|
388
|
+
} catch {}
|
|
389
|
+
if (vVerdict.submitted === true) {
|
|
390
|
+
await reportStatus('DONE', { confirmation_screenshot_r2_key: confirmKey || null, fields_filled: cumulativeFilled });
|
|
391
|
+
await clearCheckpoint(config, queueId);
|
|
392
|
+
console.log(`[orchestrator] Done via vision (verified): ${queueItem.company} - ${queueItem.title}`);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (vVerdict.submitted === false) {
|
|
396
|
+
await reportStatus('NEEDS_ATTENTION', {
|
|
397
|
+
review_screenshot_r2_key: confirmKey || null,
|
|
398
|
+
needs_attention_reason: `Vision submitted but ATS rejected: ${vVerdict.error_message || 'unknown'}`,
|
|
399
|
+
intervention_type: 'submit_failed',
|
|
400
|
+
step: 'VERIFY',
|
|
401
|
+
step_detail: (vVerdict.error_message || '').slice(0, 200),
|
|
402
|
+
fields_filled: cumulativeFilled,
|
|
403
|
+
});
|
|
404
|
+
throw new Error(`Vision-submit failed verification: ${vVerdict.error_message || 'unknown'}`);
|
|
405
|
+
}
|
|
406
|
+
await reportStatus('REVIEWING', {
|
|
407
|
+
review_screenshot_r2_key: confirmKey || null,
|
|
408
|
+
step: 'REVIEWING',
|
|
409
|
+
step_detail: 'Vision attempted submit — verifier unavailable, please eyeball',
|
|
377
410
|
fields_filled: cumulativeFilled,
|
|
378
411
|
});
|
|
379
|
-
await clearCheckpoint(config, queueId);
|
|
380
|
-
console.log(`[orchestrator] Done via vision: ${queueItem.company} - ${queueItem.title}`);
|
|
381
412
|
return;
|
|
382
413
|
}
|
|
383
414
|
|
|
@@ -474,31 +505,22 @@ async function runJob(queueItem, chromeConn, config, reportStatus) {
|
|
|
474
505
|
}
|
|
475
506
|
|
|
476
507
|
if (verdict.submitted === null) {
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
fields_filled: cumulativeFilled,
|
|
488
|
-
});
|
|
489
|
-
await clearCheckpoint(config, queueId);
|
|
490
|
-
console.log(`[orchestrator] Done (auto-submit, unverified): ${queueItem.company} - ${queueItem.title}`);
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
console.warn(`[orchestrator] Could not verify submission (source: ${verdict.source}). Sending to REVIEWING for your eyeball.`);
|
|
508
|
+
// EARLIER VERSION: when auto-submit was ON, we trusted the click and
|
|
509
|
+
// marked DONE. That was wrong — it produced false-positive submissions
|
|
510
|
+
// (applied=true in DB, no actual application sent). Auto-submit means
|
|
511
|
+
// "don't make me click Submit on the dashboard" — it does NOT mean
|
|
512
|
+
// "lie about delivery."
|
|
513
|
+
//
|
|
514
|
+
// Honest behavior: unverified == REVIEWING regardless of auto-submit.
|
|
515
|
+
// The screenshot is right there in the dashboard, one click confirms.
|
|
516
|
+
// Better to over-ask than to ghost-apply.
|
|
517
|
+
console.warn(`[orchestrator] Could not verify submission (source: ${verdict.source}). REVIEWING — please eyeball the screenshot + click Submit.`);
|
|
494
518
|
await reportStatus('REVIEWING', {
|
|
495
519
|
review_screenshot_r2_key: confirmKey || null,
|
|
496
520
|
step: 'REVIEWING',
|
|
497
|
-
step_detail:
|
|
521
|
+
step_detail: `Submit clicked at ${verdictUrl.slice(0, 100)} — verifier unavailable, please confirm`,
|
|
498
522
|
fields_filled: cumulativeFilled,
|
|
499
523
|
});
|
|
500
|
-
// Stop here; user clicks Submit on dashboard → /apply-queue/submit/:id
|
|
501
|
-
// will flip to DONE. Don't return — let the function return naturally.
|
|
502
524
|
return;
|
|
503
525
|
}
|
|
504
526
|
|