@enricai/barnacle 1.12.79 → 1.12.80
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/api/helpers/reply.d.ts.map +1 -1
- package/dist/api/helpers/reply.js +5 -2
- package/dist/api/helpers/reply.js.map +1 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/lib/llm/judge.d.ts.map +1 -1
- package/dist/lib/llm/judge.js +6 -1
- package/dist/lib/llm/judge.js.map +1 -1
- package/dist/lib/llm/judges/verify-step-advanced.d.ts +30 -0
- package/dist/lib/llm/judges/verify-step-advanced.d.ts.map +1 -0
- package/dist/lib/llm/judges/verify-step-advanced.js +62 -0
- package/dist/lib/llm/judges/verify-step-advanced.js.map +1 -0
- package/dist/lib/llm/judges/verify-submit.d.ts +7 -1
- package/dist/lib/llm/judges/verify-submit.d.ts.map +1 -1
- package/dist/lib/llm/judges/verify-submit.js +29 -8
- package/dist/lib/llm/judges/verify-submit.js.map +1 -1
- package/dist/lib/llm/schemas.d.ts +8 -0
- package/dist/lib/llm/schemas.d.ts.map +1 -1
- package/dist/lib/llm/schemas.js +21 -13
- package/dist/lib/llm/schemas.js.map +1 -1
- package/dist/lib/logging.d.ts +7 -0
- package/dist/lib/logging.d.ts.map +1 -1
- package/dist/lib/logging.js +19 -1
- package/dist/lib/logging.js.map +1 -1
- package/dist/lib/pii-redaction.d.ts +104 -0
- package/dist/lib/pii-redaction.d.ts.map +1 -0
- package/dist/lib/pii-redaction.js +397 -0
- package/dist/lib/pii-redaction.js.map +1 -0
- package/dist/lib/random.d.ts +3 -1
- package/dist/lib/random.d.ts.map +1 -1
- package/dist/lib/random.js +7 -2
- package/dist/lib/random.js.map +1 -1
- package/dist/lib/telemetry/beacon-capture.d.ts.map +1 -1
- package/dist/lib/telemetry/beacon-capture.js +2 -0
- package/dist/lib/telemetry/beacon-capture.js.map +1 -1
- package/dist/lib/telemetry/call-capture.d.ts.map +1 -1
- package/dist/lib/telemetry/call-capture.js +4 -1
- package/dist/lib/telemetry/call-capture.js.map +1 -1
- package/dist/lib/telemetry/submission-capture.d.ts +11 -1
- package/dist/lib/telemetry/submission-capture.d.ts.map +1 -1
- package/dist/lib/telemetry/submission-capture.js +32 -3
- package/dist/lib/telemetry/submission-capture.js.map +1 -1
- package/dist/plugins/config-plugin.d.ts +8 -0
- package/dist/plugins/config-plugin.d.ts.map +1 -1
- package/dist/plugins/config-plugin.js +4 -0
- package/dist/plugins/config-plugin.js.map +1 -1
- package/dist/plugins/discover.d.ts.map +1 -1
- package/dist/plugins/discover.js +2 -0
- package/dist/plugins/discover.js.map +1 -1
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +23 -6
- package/dist/plugins/loader.js.map +1 -1
- package/dist/scraper/active-page.d.ts +18 -0
- package/dist/scraper/active-page.d.ts.map +1 -0
- package/dist/scraper/active-page.js +53 -0
- package/dist/scraper/active-page.js.map +1 -0
- package/dist/scraper/click-settle.d.ts +19 -0
- package/dist/scraper/click-settle.d.ts.map +1 -0
- package/dist/scraper/click-settle.js +65 -0
- package/dist/scraper/click-settle.js.map +1 -0
- package/dist/scraper/deep-locator-candidates.d.ts +20 -1
- package/dist/scraper/deep-locator-candidates.d.ts.map +1 -1
- package/dist/scraper/deep-locator-candidates.js +75 -11
- package/dist/scraper/deep-locator-candidates.js.map +1 -1
- package/dist/scraper/flow-runner.d.ts +321 -6
- package/dist/scraper/flow-runner.d.ts.map +1 -1
- package/dist/scraper/flow-runner.js +2087 -341
- package/dist/scraper/flow-runner.js.map +1 -1
- package/dist/scraper/navigate.d.ts +3 -3
- package/dist/scraper/navigate.js +4 -4
- package/dist/scraper/navigate.js.map +1 -1
- package/dist/scraper/phantom-click.d.ts +34 -2
- package/dist/scraper/phantom-click.d.ts.map +1 -1
- package/dist/scraper/phantom-click.js +80 -6
- package/dist/scraper/phantom-click.js.map +1 -1
- package/dist/scraper/quoted-spans.d.ts +35 -0
- package/dist/scraper/quoted-spans.d.ts.map +1 -0
- package/dist/scraper/quoted-spans.js +83 -0
- package/dist/scraper/quoted-spans.js.map +1 -0
- package/dist/scraper/session-browserbase.d.ts +4 -2
- package/dist/scraper/session-browserbase.d.ts.map +1 -1
- package/dist/scraper/session-browserbase.js +36 -5
- package/dist/scraper/session-browserbase.js.map +1 -1
- package/dist/scraper/session-steel.d.ts.map +1 -1
- package/dist/scraper/session-steel.js +16 -2
- package/dist/scraper/session-steel.js.map +1 -1
- package/dist/scraper/session-teardown.d.ts +1 -0
- package/dist/scraper/session-teardown.d.ts.map +1 -1
- package/dist/scraper/session-teardown.js +19 -8
- package/dist/scraper/session-teardown.js.map +1 -1
- package/dist/scraper/spa-readiness.d.ts +13 -1
- package/dist/scraper/spa-readiness.d.ts.map +1 -1
- package/dist/scraper/spa-readiness.js +31 -1
- package/dist/scraper/spa-readiness.js.map +1 -1
- package/dist/scraper/stagehand-guard.d.ts +8 -3
- package/dist/scraper/stagehand-guard.d.ts.map +1 -1
- package/dist/scraper/stagehand-guard.js +181 -13
- package/dist/scraper/stagehand-guard.js.map +1 -1
- package/dist/scraper/transient-provider-error.d.ts +19 -0
- package/dist/scraper/transient-provider-error.d.ts.map +1 -0
- package/dist/scraper/transient-provider-error.js +59 -0
- package/dist/scraper/transient-provider-error.js.map +1 -0
- package/dist/scraper/trusted-click.d.ts +122 -0
- package/dist/scraper/trusted-click.d.ts.map +1 -0
- package/dist/scraper/trusted-click.js +201 -0
- package/dist/scraper/trusted-click.js.map +1 -0
- package/dist/scraper/upload-affordance-expr.d.ts +33 -0
- package/dist/scraper/upload-affordance-expr.d.ts.map +1 -0
- package/dist/scraper/upload-affordance-expr.js +91 -0
- package/dist/scraper/upload-affordance-expr.js.map +1 -0
- package/dist/scripts/recon-browser.d.ts +26 -1
- package/dist/scripts/recon-browser.d.ts.map +1 -1
- package/dist/scripts/recon-browser.js +108 -21
- package/dist/scripts/recon-browser.js.map +1 -1
- package/dist/scripts/recon-capture-rebind.d.ts +11 -0
- package/dist/scripts/recon-capture-rebind.d.ts.map +1 -0
- package/dist/scripts/recon-capture-rebind.js +26 -0
- package/dist/scripts/recon-capture-rebind.js.map +1 -0
- package/dist/scripts/recon-generate.d.ts +112 -9
- package/dist/scripts/recon-generate.d.ts.map +1 -1
- package/dist/scripts/recon-generate.js +889 -181
- package/dist/scripts/recon-generate.js.map +1 -1
- package/dist/scripts/recon-shared.d.ts +7 -0
- package/dist/scripts/recon-shared.d.ts.map +1 -1
- package/dist/scripts/recon-shared.js +19 -0
- package/dist/scripts/recon-shared.js.map +1 -1
- package/dist/site-plugin.d.ts +8 -0
- package/dist/site-plugin.d.ts.map +1 -1
- package/dist/types/pii-redaction.d.ts +39 -0
- package/dist/types/pii-redaction.d.ts.map +1 -0
- package/dist/types/pii-redaction.js +3 -0
- package/dist/types/pii-redaction.js.map +1 -0
- package/package.json +14 -1
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
* per act; healing and replans push the upper bound higher on flaky sites).
|
|
49
49
|
*/
|
|
50
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.writeFixtureToTempFile = exports.windowHasTransitionBody = exports.windowHasAdvanceTransition = exports.waitForTransitionBody = exports.verifyFillReadback = exports.shouldWarnMissingAdvancePattern = exports.shouldVetoFallbackAdvance = exports.shouldSkipTechnique = exports.selectRadioGroupOption = exports.selectBodyExcerpt = exports.resetBillingErrorFlagForTests = exports.rephraseWithLLM = exports.renderUnfocusedObserve = exports.renderLeafInvalidFields = exports.probeStepBeforeAttempts = exports.probeLeafInvalidContainers = exports.pollEnumerate = exports.parseSelectStep = exports.parseRadioStep = exports.parseCaptureIndex = exports.pairInvalidWithErrors = exports.normalizeDateValue = exports.narrowInvalidFormControl = exports.logBillingErrorIfPresent = exports.latestCaptureIndex = exports.isWizardExitAction = exports.isUploadAffordanceLabel = exports.isSubmitRevealedInvalid = exports.isDomOnlyAdvanceVerified = exports.isAdvanceStep = exports.isAdvanceStalled = exports.hasBillingErrorBeenLogged = exports.formatValidationRejectedReason = exports.findRecentPageTransition = exports.findRecentBackendError = exports.fillTextDatepickerInput = exports.fillHtml5DateTimeInput = exports.extractSubmitFailureEvidence = exports.extractGaEventEvidence = exports.describeAttemptEffectSignals = exports.chooseRequiredSelectOption = exports.capturesAfterIndex = exports.buildRadioIdXPath = exports.RECON_FLOW_FILE_SCHEMA = void 0;
|
|
51
|
+
exports.writeFixtureToTempFile = exports.windowHasTransitionBody = exports.windowHasAdvanceTransition = exports.waitForTransitionBody = exports.verifyFillReadback = exports.shouldWarnMissingAdvancePattern = exports.shouldVetoFallbackAdvance = exports.shouldSkipTechnique = exports.selectRadioGroupOption = exports.selectBodyExcerpt = exports.resetBillingErrorFlagForTests = exports.rephraseWithLLM = exports.renderUnfocusedObserve = exports.renderLeafInvalidFields = exports.probeStepBeforeAttempts = exports.probeLeafInvalidContainers = exports.pollEnumerate = exports.parseSelectStep = exports.parseRadioStep = exports.parseCaptureIndex = exports.pairInvalidWithErrors = exports.normalizeDateValue = exports.narrowInvalidFormControl = exports.logBillingErrorIfPresent = exports.latestCaptureIndex = exports.isWizardExitAction = exports.isUploadAffordanceLabel = exports.isSubmitRevealedInvalid = exports.isDomOnlyAdvanceVerified = exports.isAdvanceStep = exports.isAdvanceStalled = exports.hasBillingErrorBeenLogged = exports.formatValidationRejectedReason = exports.findRecentPageTransition = exports.findRecentBackendError = exports.fillTextDatepickerInput = exports.fillHtml5DateTimeInput = exports.extractSubmitFailureEvidence = exports.extractGaEventEvidence = exports.describeAttemptEffectSignals = exports.chooseRequiredSelectOption = exports.capturesAfterIndex = exports.buildRadioIdXPath = exports.MAX_TRANSIENT_STEP_RETRIES = exports.RECON_FLOW_FILE_SCHEMA = void 0;
|
|
52
52
|
exports.resolveGotoWaitUntil = resolveGotoWaitUntil;
|
|
53
53
|
exports.detectRejectionInResponseBody = detectRejectionInResponseBody;
|
|
54
54
|
exports.isFlowTruncated = isFlowTruncated;
|
|
@@ -63,7 +63,9 @@ exports.extractSubmitJudgeRequiredFields = extractSubmitJudgeRequiredFields;
|
|
|
63
63
|
exports.applyFailedStepFlagsToResumingBridgeStep = applyFailedStepFlagsToResumingBridgeStep;
|
|
64
64
|
exports.filterReplanDuplicatingNextAuthored = filterReplanDuplicatingNextAuthored;
|
|
65
65
|
exports.isReplanReproposingFailedStep = isReplanReproposingFailedStep;
|
|
66
|
+
exports.decideReplanNoProgress = decideReplanNoProgress;
|
|
66
67
|
exports.hasPageAlreadyAdvancedPastStep = hasPageAlreadyAdvancedPastStep;
|
|
68
|
+
exports.hasSubmitStepDomAdvanced = hasSubmitStepDomAdvanced;
|
|
67
69
|
exports.isReplanRegressingAcrossAuthBoundary = isReplanRegressingAcrossAuthBoundary;
|
|
68
70
|
exports.isSubmitShapedInstructionText = isSubmitShapedInstructionText;
|
|
69
71
|
exports.seedSubmitStepFromOwnInstructionText = seedSubmitStepFromOwnInstructionText;
|
|
@@ -108,8 +110,10 @@ const session_1 = require("../scraper/session");
|
|
|
108
110
|
const session_teardown_1 = require("../scraper/session-teardown");
|
|
109
111
|
const spa_readiness_1 = require("../scraper/spa-readiness");
|
|
110
112
|
const stagehand_guard_1 = require("../scraper/stagehand-guard");
|
|
113
|
+
const transient_provider_error_1 = require("../scraper/transient-provider-error");
|
|
111
114
|
const watchdog_1 = require("../scraper/watchdog");
|
|
112
115
|
const judge_llm_batch_1 = require("./judge-llm-batch");
|
|
116
|
+
const recon_capture_rebind_1 = require("./recon-capture-rebind");
|
|
113
117
|
const recon_shared_1 = require("./recon-shared");
|
|
114
118
|
const resume_fixture_1 = require("../testing/resume-fixture");
|
|
115
119
|
const client_1 = require("../testmail/client");
|
|
@@ -591,6 +595,11 @@ exports.RECON_FLOW_FILE_SCHEMA = v4_1.z.union([
|
|
|
591
595
|
* "<tenant>.<ats>.com"].
|
|
592
596
|
*/
|
|
593
597
|
ownBackendHostnames: v4_1.z.array(v4_1.z.string().min(1)).optional(),
|
|
598
|
+
/**
|
|
599
|
+
* Declares the ATS cannot be replayed as raw HTTP, so the generator emits
|
|
600
|
+
* a browser-flow-only plugin regardless of HTTP analysis.
|
|
601
|
+
*/
|
|
602
|
+
browserFlowOnly: v4_1.z.boolean().optional(),
|
|
594
603
|
/**
|
|
595
604
|
* Optional site-specific class-name prefixes that wrap form/error
|
|
596
605
|
* state. The Haiku invalid-fields judge uses these as additional
|
|
@@ -1171,6 +1180,28 @@ function isReplanReproposingFailedStep(newSteps, failedStep) {
|
|
|
1171
1180
|
const failedSig = stepSignature(failedStep);
|
|
1172
1181
|
return newSteps.every((s) => stepSignature(s.instruction) === failedSig && !hasCompoundBridgeClause(s.instruction));
|
|
1173
1182
|
}
|
|
1183
|
+
/** Max times one step may be re-run after a provider-only failure cascade. */
|
|
1184
|
+
exports.MAX_TRANSIENT_STEP_RETRIES = 2;
|
|
1185
|
+
/**
|
|
1186
|
+
* Cause-aware wrapper over {@link isReplanReproposingFailedStep}: a re-proposal
|
|
1187
|
+
* of only the failed step is a guaranteed re-fail for a real selector/page
|
|
1188
|
+
* problem, but a legitimate bounded re-run when every recorded attempt failed
|
|
1189
|
+
* on a transient provider error. Retries are counted per step signature in
|
|
1190
|
+
* `retryCounts` (mutated on "retry"); once exhausted, or when the dump is
|
|
1191
|
+
* missing/empty/mixed, the original abort stands.
|
|
1192
|
+
*/
|
|
1193
|
+
function decideReplanNoProgress(newSteps, failedStep, attempts, retryCounts) {
|
|
1194
|
+
if (!isReplanReproposingFailedStep(newSteps, failedStep))
|
|
1195
|
+
return "proceed";
|
|
1196
|
+
if (!attempts || !(0, transient_provider_error_1.summarizeAttemptTransience)(attempts).all)
|
|
1197
|
+
return "abort";
|
|
1198
|
+
const sig = stepSignature(failedStep);
|
|
1199
|
+
const used = retryCounts.get(sig) ?? 0;
|
|
1200
|
+
if (used >= exports.MAX_TRANSIENT_STEP_RETRIES)
|
|
1201
|
+
return "abort";
|
|
1202
|
+
retryCounts.set(sig, used + 1);
|
|
1203
|
+
return "retry";
|
|
1204
|
+
}
|
|
1174
1205
|
/**
|
|
1175
1206
|
* Normalize a URL to origin + pathname (query and hash stripped) for
|
|
1176
1207
|
* same-page-vs-navigated comparison. Returns null on unparseable input so
|
|
@@ -1212,6 +1243,18 @@ function hasPageAlreadyAdvancedPastStep(stepStartUrl, currentUrl, stepInstructio
|
|
|
1212
1243
|
return false;
|
|
1213
1244
|
return (0, phantom_click_1.isPlausibleStepDestination)(stepInstruction, currentUrl);
|
|
1214
1245
|
}
|
|
1246
|
+
/**
|
|
1247
|
+
* DOM-advance counterpart of {@link hasPageAlreadyAdvancedPastStep} for
|
|
1248
|
+
* non-final submit-shaped steps, whose SPA wizards swap content without a URL
|
|
1249
|
+
* change. Reuses the shared {@link hasPageAdvanced} judgement over the
|
|
1250
|
+
* step-start and live visible-text signatures; a final step is never credited
|
|
1251
|
+
* here because its completion is owned by the submit-destination judge.
|
|
1252
|
+
*/
|
|
1253
|
+
function hasSubmitStepDomAdvanced(isFinalStep, preVisibleTextSignature, liveVisibleTextSignature) {
|
|
1254
|
+
if (isFinalStep)
|
|
1255
|
+
return false;
|
|
1256
|
+
return (0, phantom_click_1.hasPageAdvanced)({ networkCount: 0, url: "", bodyHtmlLength: 0, visibleTextSignature: preVisibleTextSignature }, { networkCount: 0, url: "", bodyHtmlLength: 0, visibleTextSignature: liveVisibleTextSignature });
|
|
1257
|
+
}
|
|
1215
1258
|
/** Word-boundary phrase patterns identifying an account-creation/registration step. */
|
|
1216
1259
|
const ACCOUNT_CREATION_PATTERNS = [
|
|
1217
1260
|
/\bcreate\s+(an\s+)?account\b/,
|
|
@@ -1234,13 +1277,13 @@ const ACCOUNT_CREATION_PATTERNS = [
|
|
|
1234
1277
|
* in". Scopes the Sign-In match to the step's own action clause (via
|
|
1235
1278
|
* `splitIntoActionClauses`, shared with `isPlausibleStepDestination`) so a
|
|
1236
1279
|
* step that merely mentions sign-in in descriptive context isn't mistaken
|
|
1237
|
-
* for one that is itself about signing in.
|
|
1280
|
+
* for one that is itself about signing in. The completed-steps side is
|
|
1281
|
+
* clause-scoped the same way, so a step that only mentions account creation
|
|
1282
|
+
* in descriptive text (e.g. a wizard step title) isn't mistaken for a
|
|
1283
|
+
* completed account-creation step. Pure.
|
|
1238
1284
|
*/
|
|
1239
1285
|
function isReplanRegressingAcrossAuthBoundary(newSteps, completedSteps) {
|
|
1240
|
-
const hasAccountCreation = completedSteps.some((s) =>
|
|
1241
|
-
const norm = normalizeInstruction(s);
|
|
1242
|
-
return ACCOUNT_CREATION_PATTERNS.some((p) => p.test(norm));
|
|
1243
|
-
});
|
|
1286
|
+
const hasAccountCreation = completedSteps.some((s) => (0, phantom_click_1.splitIntoActionClauses)(s).some((clause) => ACCOUNT_CREATION_PATTERNS.some((p) => p.test(clause))));
|
|
1244
1287
|
if (!hasAccountCreation)
|
|
1245
1288
|
return false;
|
|
1246
1289
|
return newSteps.some((s) => (0, phantom_click_1.splitIntoActionClauses)(s.instruction).some((clause) => phantom_click_1.SIGN_IN_PATTERNS.some((p) => p.test(clause))));
|
|
@@ -1269,6 +1312,11 @@ const SUBMIT_SHAPED_INSTRUCTION_PATTERNS = [
|
|
|
1269
1312
|
* one. Pure.
|
|
1270
1313
|
*/
|
|
1271
1314
|
function isSubmitShapedInstructionText(instruction) {
|
|
1315
|
+
// The loose wording patterns below would seed an explicit `submitStep: true`,
|
|
1316
|
+
// which overrides a declared non-submit intent everywhere downstream; defer
|
|
1317
|
+
// to the same classifier the submit-judge gates read so the two cannot disagree.
|
|
1318
|
+
if ((0, flow_runner_1.classifyStepSubmitIntent)(instruction) === "non-submit")
|
|
1319
|
+
return false;
|
|
1272
1320
|
const norm = normalizeInstruction((0, flow_runner_1.stripNegatedSubmitClauses)(instruction));
|
|
1273
1321
|
return SUBMIT_SHAPED_INSTRUCTION_PATTERNS.some((p) => p.test(norm));
|
|
1274
1322
|
}
|
|
@@ -2227,24 +2275,27 @@ async function main() {
|
|
|
2227
2275
|
// rather than a previous attempt's partially-replanned plan.
|
|
2228
2276
|
const plan = [];
|
|
2229
2277
|
const replanEvents = [];
|
|
2278
|
+
const transientStepRetries = new Map();
|
|
2230
2279
|
try {
|
|
2231
2280
|
const stagehand = session.stagehand;
|
|
2232
|
-
|
|
2281
|
+
let page = await stagehand.context.awaitActivePage();
|
|
2233
2282
|
// Phase label is mutated between flow steps so the single CDP listener
|
|
2234
2283
|
// always tags captures with the currently active phase.
|
|
2235
2284
|
let currentPhase = "home";
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2285
|
+
// Live read so SPA history navigation between captures stays accurate.
|
|
2286
|
+
// Fallback to the initial url on parse failure (e.g. about:blank early
|
|
2287
|
+
// in the goto cycle) so we don't accidentally mark a capture as
|
|
2288
|
+
// cross-origin and miss the user-action signal.
|
|
2289
|
+
const currentPageOrigin = () => {
|
|
2241
2290
|
try {
|
|
2242
2291
|
return new URL(page.url()).origin;
|
|
2243
2292
|
}
|
|
2244
2293
|
catch {
|
|
2245
2294
|
return new URL(url).origin;
|
|
2246
2295
|
}
|
|
2247
|
-
}
|
|
2296
|
+
};
|
|
2297
|
+
const capture = (0, recon_capture_rebind_1.createCaptureRebinder)(page, (target) => wireNetworkCapture(target, counter, signalCounter, recentCaptures, recentCaptureMeta, () => currentPhase, currentPageOrigin));
|
|
2298
|
+
const stopCapture = capture.stopAll;
|
|
2248
2299
|
logger.info(`navigating to ${url} (waitUntil: ${GOTO_WAIT_UNTIL})`);
|
|
2249
2300
|
// A navigation wait that never resolves must not discard the run. Ad-heavy
|
|
2250
2301
|
// commercial sites (analytics/session-replay beacons on timers) never reach
|
|
@@ -2319,7 +2370,7 @@ async function main() {
|
|
|
2319
2370
|
const currentOrigin = originOf(readLiveUrl());
|
|
2320
2371
|
if (currentOrigin !== "" && currentOrigin !== lastOrigin) {
|
|
2321
2372
|
logger.info(`origin changed ${lastOrigin || "(none)"} → ${currentOrigin}; re-gating on SPA hydration`);
|
|
2322
|
-
await (0, spa_readiness_1.
|
|
2373
|
+
await (0, spa_readiness_1.regateSpaAfterOriginChange)(page, logger);
|
|
2323
2374
|
lastOrigin = currentOrigin;
|
|
2324
2375
|
}
|
|
2325
2376
|
// Debug: dump the full DOM right before this step's cascade runs. Lets
|
|
@@ -2363,6 +2414,10 @@ async function main() {
|
|
|
2363
2414
|
// in-frame navigation would otherwise be invisible to the top-level
|
|
2364
2415
|
// page.url() this used to read.
|
|
2365
2416
|
const urlAtStepStart = await (0, frame_target_1.readCurrentFrameUrl)(page, frameTarget);
|
|
2417
|
+
const textAtStepStart = step.submitStep
|
|
2418
|
+
? (await (0, flow_runner_1.snapshotPage)(frameTarget, signalCounter).catch(() => undefined))
|
|
2419
|
+
?.visibleTextSignature
|
|
2420
|
+
: undefined;
|
|
2366
2421
|
// A child frame CDP has just attached to may still be sitting on
|
|
2367
2422
|
// about:blank (the moment right after Target.setAutoAttach fires and
|
|
2368
2423
|
// before the OOPIF's own navigation lands). waitForSpaReady above only
|
|
@@ -2388,6 +2443,12 @@ async function main() {
|
|
|
2388
2443
|
: (0, flow_runner_1.executeStepWithHealing)({
|
|
2389
2444
|
stagehand,
|
|
2390
2445
|
page,
|
|
2446
|
+
onPageAdopted: (adopted) => {
|
|
2447
|
+
if (adopted === page)
|
|
2448
|
+
return;
|
|
2449
|
+
page = adopted;
|
|
2450
|
+
capture.adopt(adopted);
|
|
2451
|
+
},
|
|
2391
2452
|
abortSignal: session.deathAbortSignal,
|
|
2392
2453
|
frameTarget,
|
|
2393
2454
|
step: step.instruction,
|
|
@@ -2399,7 +2460,10 @@ async function main() {
|
|
|
2399
2460
|
emailStepConfig: step.emailStepConfig,
|
|
2400
2461
|
allocatedInbox,
|
|
2401
2462
|
flowHasSubmitSemantics: (0, flow_runner_1.flowHasSubmitSemantics)({
|
|
2402
|
-
steps: plan.map((s) => ({
|
|
2463
|
+
steps: plan.map((s) => ({
|
|
2464
|
+
submitStep: s.submitStep === true,
|
|
2465
|
+
instruction: s.instruction,
|
|
2466
|
+
})),
|
|
2403
2467
|
submitEndpointPattern,
|
|
2404
2468
|
requireSubmitEndpointMatch,
|
|
2405
2469
|
}),
|
|
@@ -2517,8 +2581,13 @@ async function main() {
|
|
|
2517
2581
|
// matches, so skip the replan dispatcher entirely and resume with
|
|
2518
2582
|
// the remaining tail.
|
|
2519
2583
|
const urlAfterFailure = await (0, frame_target_1.readCurrentFrameUrl)(page, frameTarget);
|
|
2520
|
-
|
|
2521
|
-
hasPageAlreadyAdvancedPastStep(urlAtStepStart, urlAfterFailure, step.instruction)
|
|
2584
|
+
const urlAdvanced = !step.submitStep &&
|
|
2585
|
+
hasPageAlreadyAdvancedPastStep(urlAtStepStart, urlAfterFailure, step.instruction);
|
|
2586
|
+
const domAdvanced = !urlAdvanced &&
|
|
2587
|
+
step.submitStep === true &&
|
|
2588
|
+
hasSubmitStepDomAdvanced(i === plan.length - 1, textAtStepStart, (await (0, flow_runner_1.snapshotPage)(frameTarget, signalCounter).catch(() => undefined))
|
|
2589
|
+
?.visibleTextSignature);
|
|
2590
|
+
if (urlAdvanced || domAdvanced) {
|
|
2522
2591
|
logger.info(`${(0, flow_runner_1.formatStepPrefix)(i, () => plan.length)} verification failed but the page already advanced past this step (${urlAtStepStart} → ${urlAfterFailure}); treating as completed and resuming remaining tail`);
|
|
2523
2592
|
consecutiveStaleSkips = 0;
|
|
2524
2593
|
lastSuccessNetworkCount = signalCounter.n;
|
|
@@ -2547,7 +2616,11 @@ async function main() {
|
|
|
2547
2616
|
// /tmp/recon/graphql/ during a sweep: some tenants hit this exact
|
|
2548
2617
|
// failure — only interruption_check + GA tracking POSTs fired, no
|
|
2549
2618
|
// integrated_apply, yet trailing-grace declared success.
|
|
2550
|
-
|
|
2619
|
+
const stepDeclaredNonSubmit = (0, flow_runner_1.isStepDeclaredNonSubmit)({
|
|
2620
|
+
step: step.instruction,
|
|
2621
|
+
submitStep: step.submitStep ?? false,
|
|
2622
|
+
});
|
|
2623
|
+
if (step.optional && !stepDeclaredNonSubmit && i >= plan.length - flow_runner_1.TRAILING_GRACE_WINDOW) {
|
|
2551
2624
|
// Trailing-grace check: did the submit actually land somewhere in
|
|
2552
2625
|
// the recent capture history? Ask the same Haiku judge — it has
|
|
2553
2626
|
// multi-signal reasoning to distinguish real submit POSTs from
|
|
@@ -2559,6 +2632,11 @@ async function main() {
|
|
|
2559
2632
|
const trailingGraceVerdict = await (0, verify_submit_1.verifySubmitWithLLM)({
|
|
2560
2633
|
client: anthropic,
|
|
2561
2634
|
input: {
|
|
2635
|
+
...(await (0, flow_runner_1.buildSubmitJudgeStepContext)({
|
|
2636
|
+
step: step.instruction,
|
|
2637
|
+
isFinalStep: i === plan.length - 1,
|
|
2638
|
+
target: (0, frame_target_1.mainFrameTarget)(page),
|
|
2639
|
+
})),
|
|
2562
2640
|
// A dead session throws synchronously here too — fall back to ""
|
|
2563
2641
|
// rather than let the trailing-grace check itself crash the run.
|
|
2564
2642
|
pageUrl: (() => {
|
|
@@ -2638,16 +2716,21 @@ async function main() {
|
|
|
2638
2716
|
// failed step's re-emission. originalRemaining is re-appended below.
|
|
2639
2717
|
// The untruncated failure-time DOM re-verifies completed fills so a
|
|
2640
2718
|
// silently-reset field isn't trusted as still-completed.
|
|
2641
|
-
const { bodyHtmlAtFailure, fieldValuesAtFailure } = (() => {
|
|
2719
|
+
const { bodyHtmlAtFailure, fieldValuesAtFailure, attemptsAtFailure } = (() => {
|
|
2642
2720
|
try {
|
|
2643
2721
|
const dump = JSON.parse((0, node_fs_1.readFileSync)(dumpPath, "utf8"));
|
|
2644
2722
|
return {
|
|
2723
|
+
attemptsAtFailure: dump.attempts ?? null,
|
|
2645
2724
|
bodyHtmlAtFailure: dump.bodyOuterHtml ?? null,
|
|
2646
2725
|
fieldValuesAtFailure: dump.fieldValuesAtFailure ?? null,
|
|
2647
2726
|
};
|
|
2648
2727
|
}
|
|
2649
2728
|
catch {
|
|
2650
|
-
return {
|
|
2729
|
+
return {
|
|
2730
|
+
bodyHtmlAtFailure: null,
|
|
2731
|
+
fieldValuesAtFailure: null,
|
|
2732
|
+
attemptsAtFailure: null,
|
|
2733
|
+
};
|
|
2651
2734
|
}
|
|
2652
2735
|
})();
|
|
2653
2736
|
const newSteps = filterCompletedFromReplan(rawNewSteps, completedSteps, step.instruction, bodyHtmlAtFailure, fieldValuesAtFailure);
|
|
@@ -2664,7 +2747,11 @@ async function main() {
|
|
|
2664
2747
|
// cascade on the identical click that just exhausted it. Abort now
|
|
2665
2748
|
// instead of waiting REPLAN_CYCLE_THRESHOLD repeats for the cycle
|
|
2666
2749
|
// detector — that many dead cascades cost minutes of wall-clock.
|
|
2667
|
-
|
|
2750
|
+
const noProgressDecision = decideReplanNoProgress(newSteps, step.instruction, attemptsAtFailure, transientStepRetries);
|
|
2751
|
+
if (noProgressDecision === "retry") {
|
|
2752
|
+
logger.warn(`replan #${replanIndex} re-proposed the failed step after provider-transient errors only; allowing bounded re-run`);
|
|
2753
|
+
}
|
|
2754
|
+
if (noProgressDecision === "abort") {
|
|
2668
2755
|
const noProgressMessage = `replan #${replanIndex} re-proposed only the just-failed step ("${step.instruction.slice(0, 60)}") with no new bridge; resuming would re-fail identically — aborting`;
|
|
2669
2756
|
logger.error(noProgressMessage);
|
|
2670
2757
|
throw new errors_2.StepVerificationError(noProgressMessage, "replan-cycle-detected");
|