@mercuryo-ai/agentbrowse 0.2.60 → 0.2.63
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/CHANGELOG.md +33 -1
- package/README.md +132 -14
- package/dist/browser-session-state.d.ts +40 -10
- package/dist/browser-session-state.d.ts.map +1 -1
- package/dist/browser-session-state.js +63 -5
- package/dist/commands/act.d.ts.map +1 -1
- package/dist/commands/act.js +548 -535
- package/dist/commands/attach.d.ts +1 -3
- package/dist/commands/attach.d.ts.map +1 -1
- package/dist/commands/attach.js +5 -12
- package/dist/commands/browser-connection-failure.d.ts +9 -0
- package/dist/commands/browser-connection-failure.d.ts.map +1 -0
- package/dist/commands/browser-connection-failure.js +15 -0
- package/dist/commands/browser-status.d.ts +0 -2
- package/dist/commands/browser-status.d.ts.map +1 -1
- package/dist/commands/browser-status.js +27 -37
- package/dist/commands/close.d.ts.map +1 -1
- package/dist/commands/close.js +5 -0
- package/dist/commands/extract.d.ts.map +1 -1
- package/dist/commands/extract.js +147 -144
- package/dist/commands/interaction-kernel.d.ts +1 -1
- package/dist/commands/interaction-kernel.d.ts.map +1 -1
- package/dist/commands/interaction-kernel.js +1 -1
- package/dist/commands/launch.d.ts +0 -1
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +11 -12
- package/dist/commands/navigate.d.ts.map +1 -1
- package/dist/commands/navigate.js +79 -73
- package/dist/commands/observe-accessibility.d.ts.map +1 -1
- package/dist/commands/observe-accessibility.js +36 -2
- package/dist/commands/observe-inventory.d.ts +50 -7
- package/dist/commands/observe-inventory.d.ts.map +1 -1
- package/dist/commands/observe-inventory.js +822 -99
- package/dist/commands/observe-persistence.d.ts.map +1 -1
- package/dist/commands/observe-persistence.js +49 -6
- package/dist/commands/observe-projection.d.ts +6 -2
- package/dist/commands/observe-projection.d.ts.map +1 -1
- package/dist/commands/observe-projection.js +251 -27
- package/dist/commands/observe-semantics.d.ts +1 -0
- package/dist/commands/observe-semantics.d.ts.map +1 -1
- package/dist/commands/observe-semantics.js +541 -135
- package/dist/commands/observe-signals.d.ts +4 -4
- package/dist/commands/observe-signals.d.ts.map +1 -1
- package/dist/commands/observe-signals.js +2 -2
- package/dist/commands/observe-surfaces.d.ts +2 -1
- package/dist/commands/observe-surfaces.d.ts.map +1 -1
- package/dist/commands/observe-surfaces.js +143 -45
- package/dist/commands/observe.d.ts +5 -1
- package/dist/commands/observe.d.ts.map +1 -1
- package/dist/commands/observe.js +266 -274
- package/dist/commands/screenshot.d.ts.map +1 -1
- package/dist/commands/screenshot.js +50 -64
- package/dist/commands/semantic-observe.d.ts.map +1 -1
- package/dist/commands/semantic-observe.js +43 -0
- package/dist/library.d.ts +3 -1
- package/dist/library.d.ts.map +1 -1
- package/dist/library.js +3 -1
- package/dist/match-resolve-fill.d.ts +196 -0
- package/dist/match-resolve-fill.d.ts.map +1 -0
- package/dist/match-resolve-fill.js +700 -0
- package/dist/match-resolve-fill.test-support.d.ts +34 -0
- package/dist/match-resolve-fill.test-support.d.ts.map +1 -0
- package/dist/match-resolve-fill.test-support.js +81 -0
- package/dist/protected-fill.d.ts.map +1 -1
- package/dist/protected-fill.js +46 -7
- package/dist/runtime-protected-state.d.ts.map +1 -1
- package/dist/runtime-protected-state.js +12 -0
- package/dist/runtime-state.d.ts +6 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +6 -0
- package/dist/secrets/form-matcher.d.ts.map +1 -1
- package/dist/secrets/form-matcher.js +76 -27
- package/dist/secrets/protected-exact-value-redaction.d.ts.map +1 -1
- package/dist/secrets/protected-exact-value-redaction.js +6 -0
- package/dist/secrets/protected-fill.js +3 -3
- package/dist/session.d.ts +3 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -2
- package/dist/solver/browser-launcher.d.ts.map +1 -1
- package/dist/solver/browser-launcher.js +2 -1
- package/dist/sticky-owner-host-entry.d.ts +2 -0
- package/dist/sticky-owner-host-entry.d.ts.map +1 -0
- package/dist/sticky-owner-host-entry.js +97 -0
- package/dist/sticky-owner.d.ts +15 -0
- package/dist/sticky-owner.d.ts.map +1 -0
- package/dist/sticky-owner.js +431 -0
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -0
- package/docs/README.md +28 -11
- package/docs/api-reference.md +311 -19
- package/docs/assistive-runtime.md +41 -16
- package/docs/configuration.md +36 -4
- package/docs/getting-started.md +73 -5
- package/docs/integration-checklist.md +32 -3
- package/docs/match-resolve-fill.md +699 -0
- package/docs/protected-fill.md +373 -91
- package/docs/testing.md +147 -15
- package/docs/troubleshooting.md +47 -6
- package/examples/README.md +7 -0
- package/examples/match-resolve-fill.ts +107 -0
- package/package.json +4 -2
- package/dist/protected-fill-browser.d.ts +0 -22
- package/dist/protected-fill-browser.d.ts.map +0 -1
- package/dist/protected-fill-browser.js +0 -52
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* attach <cdp-url> — Attach AgentBrowse to an existing browser session.
|
|
3
3
|
*/
|
|
4
|
-
import { type BrowserSessionState
|
|
4
|
+
import { type BrowserSessionState } from '../browser-session-state.js';
|
|
5
5
|
import type { BrowseSessionTransport } from '../browser-session-state.js';
|
|
6
6
|
/** Stable top-level error codes returned by `attach(...)`. */
|
|
7
7
|
export declare const ATTACH_ERROR_CODES: readonly ["browser_attach_failed"];
|
|
@@ -13,7 +13,6 @@ export type AttachOutcomeType = (typeof ATTACH_OUTCOME_TYPES)[number];
|
|
|
13
13
|
export type AttachOptions = {
|
|
14
14
|
launchedAt?: string;
|
|
15
15
|
provider?: string;
|
|
16
|
-
capabilities?: BrowserSessionCapabilities;
|
|
17
16
|
transport?: BrowseSessionTransport;
|
|
18
17
|
};
|
|
19
18
|
/** Successful attach result for an existing CDP browser session. */
|
|
@@ -25,7 +24,6 @@ export type AttachSuccessResult = {
|
|
|
25
24
|
url: string;
|
|
26
25
|
title: string;
|
|
27
26
|
provider?: string;
|
|
28
|
-
captchaSolveCapable: boolean;
|
|
29
27
|
};
|
|
30
28
|
/** Failed attach result with a stable top-level error code. */
|
|
31
29
|
export type AttachFailureResult = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../../src/commands/attach.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../../src/commands/attach.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAG1E,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,oCAAqC,CAAC;AAErE,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,sBAAuB,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,kEAAkE;AAClE,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,eAAe,CAAC;IACvB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,OAAO,EAAE,wBAAwB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAErE,wFAAwF;AACxF,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoC/F"}
|
package/dist/commands/attach.js
CHANGED
|
@@ -2,28 +2,27 @@
|
|
|
2
2
|
* attach <cdp-url> — Attach AgentBrowse to an existing browser session.
|
|
3
3
|
*/
|
|
4
4
|
import { buildAttachedSession, buildCdpHttpEndpointUrl, } from '../browser-session-state.js';
|
|
5
|
-
import {
|
|
5
|
+
import { syncLaunchPage } from '../playwright-runtime.js';
|
|
6
|
+
import { initializeBrowserSessionOwner, withStickyOwnerBrowser } from '../sticky-owner.js';
|
|
6
7
|
/** Stable top-level error codes returned by `attach(...)`. */
|
|
7
8
|
export const ATTACH_ERROR_CODES = ['browser_attach_failed'];
|
|
8
9
|
/** Stable outcome categories emitted by `attach(...)`. */
|
|
9
10
|
export const ATTACH_OUTCOME_TYPES = ['blocked'];
|
|
10
11
|
/** Attaches AgentBrowse to an existing browser via a CDP websocket or HTTP endpoint. */
|
|
11
12
|
export async function attach(cdpUrl, options = {}) {
|
|
12
|
-
let browser = null;
|
|
13
13
|
try {
|
|
14
14
|
const normalizedCdpUrl = await resolveAttachEndpoint(cdpUrl);
|
|
15
15
|
const session = buildAttachedSession({
|
|
16
16
|
cdpUrl: normalizedCdpUrl,
|
|
17
17
|
launchedAt: options.launchedAt ?? new Date().toISOString(),
|
|
18
18
|
...(options.provider ? { provider: options.provider } : {}),
|
|
19
|
-
...(options.capabilities ? { capabilities: options.capabilities } : {}),
|
|
20
19
|
...(options.transport ? { transport: options.transport } : {}),
|
|
21
20
|
});
|
|
22
|
-
|
|
23
|
-
const syncedPage = await syncLaunchPage(session, browser, {
|
|
21
|
+
await initializeBrowserSessionOwner(session);
|
|
22
|
+
const syncedPage = await withStickyOwnerBrowser(session, (browser) => syncLaunchPage(session, browser, {
|
|
24
23
|
fallbackUrl: '',
|
|
25
24
|
fallbackTitle: '',
|
|
26
|
-
});
|
|
25
|
+
}));
|
|
27
26
|
return {
|
|
28
27
|
success: true,
|
|
29
28
|
runtime: 'attached',
|
|
@@ -32,7 +31,6 @@ export async function attach(cdpUrl, options = {}) {
|
|
|
32
31
|
url: syncedPage.url,
|
|
33
32
|
title: syncedPage.title,
|
|
34
33
|
...(options.provider ? { provider: options.provider } : {}),
|
|
35
|
-
captchaSolveCapable: options.capabilities?.captchaSolve === true,
|
|
36
34
|
};
|
|
37
35
|
}
|
|
38
36
|
catch (error) {
|
|
@@ -44,11 +42,6 @@ export async function attach(cdpUrl, options = {}) {
|
|
|
44
42
|
reason: formatUnknownError(error),
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
|
-
finally {
|
|
48
|
-
if (browser) {
|
|
49
|
-
await disconnectPlaywright(browser);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
45
|
}
|
|
53
46
|
async function resolveAttachEndpoint(input) {
|
|
54
47
|
const normalized = input.trim();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const STICKY_OWNER_UNRECOVERABLE_REASON = "sticky_owner_unrecoverable";
|
|
2
|
+
export declare function describeBrowserConnectionFailure(error: unknown, options: {
|
|
3
|
+
defaultMessage: string;
|
|
4
|
+
unrecoverableSessionMessage: string;
|
|
5
|
+
}): {
|
|
6
|
+
message: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=browser-connection-failure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-connection-failure.d.ts","sourceRoot":"","sources":["../../src/commands/browser-connection-failure.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iCAAiC,+BAA+B,CAAC;AAK9E,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IACP,cAAc,EAAE,MAAM,CAAC;IACvB,2BAA2B,EAAE,MAAM,CAAC;CACrC,GACA;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAcrC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const STICKY_OWNER_UNRECOVERABLE_REASON = 'sticky_owner_unrecoverable';
|
|
2
|
+
const STICKY_OWNER_UNRECOVERABLE_PUBLIC_REASON = 'The previous browser session is no longer reachable, so AgentBrowse could not restore control of the browser. Launch or attach a new browser session and try again.';
|
|
3
|
+
export function describeBrowserConnectionFailure(error, options) {
|
|
4
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
5
|
+
if (reason === STICKY_OWNER_UNRECOVERABLE_REASON) {
|
|
6
|
+
return {
|
|
7
|
+
message: options.unrecoverableSessionMessage,
|
|
8
|
+
reason: STICKY_OWNER_UNRECOVERABLE_PUBLIC_REASON,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
message: options.defaultMessage,
|
|
13
|
+
reason,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -29,13 +29,11 @@ export type BrowserStatusProtectedExposureResult = {
|
|
|
29
29
|
exposureReason: string;
|
|
30
30
|
message: string;
|
|
31
31
|
reason: string;
|
|
32
|
-
captchaSolveCapable?: boolean;
|
|
33
32
|
};
|
|
34
33
|
/** Success result when the browser is alive and a current page could be resolved or approximated. */
|
|
35
34
|
export type BrowserStatusAliveResult = {
|
|
36
35
|
success: true;
|
|
37
36
|
alive: true;
|
|
38
|
-
captchaSolveCapable?: boolean;
|
|
39
37
|
pageRef?: string;
|
|
40
38
|
url?: string;
|
|
41
39
|
title?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-status.d.ts","sourceRoot":"","sources":["../../src/commands/browser-status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"browser-status.d.ts","sourceRoot":"","sources":["../../src/commands/browser-status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AAiBrC,KAAK,mBAAmB,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,QAAQ,GAAG,gBAAgB,CAAC;CAC5C,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,4BAA4B,gFAI/B,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AACrF,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAClE,MAAM,MAAM,gCAAgC,GAAG,mBAAmB,CAAC;AAEnE,uGAAuG;AACvG,MAAM,MAAM,oCAAoC,GAAG;IACjD,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,IAAI,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,CAAC;IAC5E,OAAO,CAAC,EAAE,2BAA2B,CAAC;IACtC,mBAAmB,CAAC,EAAE,gCAAgC,CAAC;IACvD,uBAAuB,EAAE,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qGAAqG;AACrG,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,IAAI,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,2BAA2B,CAAC;IACtC,mBAAmB,CAAC,EAAE,gCAAgC,CAAC;IACvD,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,CAAC,EAAE,2BAA2B,CAAC;IACtC,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B,oCAAoC,GACpC,wBAAwB,GACxB,6BAA6B,CAAC;AA+KlC,qFAAqF;AACrF,wBAAsB,aAAa,CACjC,OAAO,EAAE,mBAAmB,GAAG,IAAI,GAClC,OAAO,CAAC,mBAAmB,CAAC,CA6F9B"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* browse browser-status — Check live browser/page/runtime state.
|
|
3
3
|
*/
|
|
4
|
-
import { buildCdpHttpEndpointUrl, getSessionPort,
|
|
5
|
-
import {
|
|
4
|
+
import { buildCdpHttpEndpointUrl, getSessionPort, } from '../browser-session-state.js';
|
|
5
|
+
import { resolveCurrentPageContext } from '../playwright-runtime.js';
|
|
6
6
|
import { captureDiagnosticSnapshotBestEffort, finishDiagnosticStepBestEffort, recordCommandLifecycleEventBestEffort, startDiagnosticStep, } from '../diagnostics.js';
|
|
7
7
|
import { scrubProtectedExactValues } from '../secrets/protected-exact-value-redaction.js';
|
|
8
|
+
import { withStickyOwnerBrowser } from '../sticky-owner.js';
|
|
8
9
|
/** Stable outcome categories exposed by `status(...)`. */
|
|
9
10
|
export const BROWSER_STATUS_OUTCOME_TYPES = [
|
|
10
11
|
'browser_alive',
|
|
@@ -38,9 +39,6 @@ function buildProtectedStatusPayload(params) {
|
|
|
38
39
|
success: true,
|
|
39
40
|
alive: true,
|
|
40
41
|
outcomeType: 'protected_exposure_active',
|
|
41
|
-
...(params.captchaSolveCapable !== undefined
|
|
42
|
-
? { captchaSolveCapable: params.captchaSolveCapable }
|
|
43
|
-
: {}),
|
|
44
42
|
runtime: params.runtimeSummary,
|
|
45
43
|
...(params.currentPageMismatch ? { currentPageMismatch: params.currentPageMismatch } : {}),
|
|
46
44
|
protectedExposureActive: true,
|
|
@@ -56,40 +54,35 @@ function buildProtectedStatusPayload(params) {
|
|
|
56
54
|
};
|
|
57
55
|
}
|
|
58
56
|
async function readCanonicalStatus(session) {
|
|
59
|
-
let browser = null;
|
|
60
57
|
try {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
58
|
+
return await withStickyOwnerBrowser(session, async (browser) => {
|
|
59
|
+
const resolved = await resolveCurrentPageContext(browser, session);
|
|
60
|
+
const persisted = session.runtime?.currentPageRef;
|
|
61
|
+
const title = (await resolved.page
|
|
62
|
+
.title()
|
|
63
|
+
.catch(() => session.runtime?.pages[resolved.pageRef]?.title ?? '')) ||
|
|
64
|
+
session.runtime?.pages[resolved.pageRef]?.title ||
|
|
65
|
+
'unknown';
|
|
66
|
+
const url = resolved.page.url() || session.runtime?.pages[resolved.pageRef]?.url || 'unknown';
|
|
67
|
+
return {
|
|
68
|
+
pageRef: resolved.pageRef,
|
|
69
|
+
url,
|
|
70
|
+
title,
|
|
71
|
+
...(persisted && (persisted !== resolved.pageRef || resolved.recoveredVia)
|
|
72
|
+
? {
|
|
73
|
+
currentPageMismatch: {
|
|
74
|
+
persistedPageRef: persisted,
|
|
75
|
+
...(persisted !== resolved.pageRef ? { livePageRef: resolved.pageRef } : {}),
|
|
76
|
+
...(resolved.recoveredVia ? { recoveredVia: resolved.recoveredVia } : {}),
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
: {}),
|
|
80
|
+
};
|
|
81
|
+
});
|
|
84
82
|
}
|
|
85
83
|
catch {
|
|
86
84
|
return null;
|
|
87
85
|
}
|
|
88
|
-
finally {
|
|
89
|
-
if (browser) {
|
|
90
|
-
await disconnectPlaywright(browser);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
86
|
}
|
|
94
87
|
function buildStatusEndpointUrl(session, port, resourcePath) {
|
|
95
88
|
if (session) {
|
|
@@ -179,7 +172,6 @@ export async function browserStatus(session) {
|
|
|
179
172
|
pageRef: canonical.pageRef,
|
|
180
173
|
pageUrl: canonical.url,
|
|
181
174
|
pageTitle: canonical.title,
|
|
182
|
-
captchaSolveCapable: supportsCaptchaSolve(session),
|
|
183
175
|
currentPageMismatch: canonical.currentPageMismatch,
|
|
184
176
|
protectedExposure,
|
|
185
177
|
});
|
|
@@ -190,7 +182,6 @@ export async function browserStatus(session) {
|
|
|
190
182
|
const result = {
|
|
191
183
|
success: true,
|
|
192
184
|
alive: true,
|
|
193
|
-
captchaSolveCapable: supportsCaptchaSolve(session),
|
|
194
185
|
pageRef: canonical.pageRef,
|
|
195
186
|
url: canonical.url,
|
|
196
187
|
title: canonical.title,
|
|
@@ -219,7 +210,6 @@ export async function browserStatus(session) {
|
|
|
219
210
|
const result = {
|
|
220
211
|
success: true,
|
|
221
212
|
alive: true,
|
|
222
|
-
...(session ? { captchaSolveCapable: supportsCaptchaSolve(session) } : {}),
|
|
223
213
|
url: page.url ?? 'unknown',
|
|
224
214
|
title: page.title ?? 'unknown',
|
|
225
215
|
...(session?.runtime ? { currentPageUnresolved: true } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"close.d.ts","sourceRoot":"","sources":["../../src/commands/close.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"close.d.ts","sourceRoot":"","sources":["../../src/commands/close.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAYvF,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB,mCAAoC,CAAC;AAEnE,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,gEAAiE,CAAC;AAElG,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAChE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,uCAAuC;AACvC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAEF,mCAAmC;AACnC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IAClD,OAAO,EAAE,uBAAuB,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAsClE,sFAAsF;AACtF,wBAAsB,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAyErF"}
|
package/dist/commands/close.js
CHANGED
|
@@ -6,6 +6,7 @@ import { captureDiagnosticSnapshotBestEffort, finishDiagnosticStepBestEffort, re
|
|
|
6
6
|
import { info } from '../output.js';
|
|
7
7
|
import { closeOwnedBrowser } from '../owned-browser.js';
|
|
8
8
|
import { isManagedBrowserPid } from '../owned-process.js';
|
|
9
|
+
import { terminateBrowserSessionOwner } from '../sticky-owner.js';
|
|
9
10
|
/** Stable top-level error codes returned by `close(...)`. */
|
|
10
11
|
export const CLOSE_ERROR_CODES = ['browser_close_failed'];
|
|
11
12
|
/** Stable outcome categories emitted by `close(...)`. */
|
|
@@ -64,6 +65,7 @@ export async function close(session) {
|
|
|
64
65
|
},
|
|
65
66
|
});
|
|
66
67
|
if (isCloseableManagedSession(session)) {
|
|
68
|
+
await terminateBrowserSessionOwner(session);
|
|
67
69
|
const closeResult = await closeOwnedBrowser(session);
|
|
68
70
|
if (!closeResult.success) {
|
|
69
71
|
recordCommandLifecycleEventBestEffort({
|
|
@@ -90,6 +92,9 @@ export async function close(session) {
|
|
|
90
92
|
};
|
|
91
93
|
}
|
|
92
94
|
}
|
|
95
|
+
else if (session?.stickyOwner) {
|
|
96
|
+
await terminateBrowserSessionOwner(session);
|
|
97
|
+
}
|
|
93
98
|
recordCommandLifecycleEventBestEffort({
|
|
94
99
|
step: closeStep,
|
|
95
100
|
phase: 'completed',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAUzE,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAsBtB,KAAK,sBAAsB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE9D,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAC1B,sBAAsB,GACtB,uBAAuB,GACvB,kBAAkB,EAAE,CAAC;AAEzB,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAAC;CACnC;AAED,4DAA4D;AAC5D,MAAM,MAAM,kBAAkB,GAAG,uBAAuB,GAAG,CAAC,CAAC,UAAU,CAAC;AAExE,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,8MAStB,CAAC;AAEX,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,8EAKxB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,+CAA+C;AAC/C,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG;IAChD,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC,kBAAkB,EAAE,eAAe,GAAG,SAAS,GAAG,aAAa,CAAC,CAAC;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG,qBAAqB,CAAC;AAE9E,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAibxE;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,EAC9B,WAAW,EAAE,kBAAkB,EAC/B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAUzE,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAsBtB,KAAK,sBAAsB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE9D,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAC1B,sBAAsB,GACtB,uBAAuB,GACvB,kBAAkB,EAAE,CAAC;AAEzB,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAAC;CACnC;AAED,4DAA4D;AAC5D,MAAM,MAAM,kBAAkB,GAAG,uBAAuB,GAAG,CAAC,CAAC,UAAU,CAAC;AAExE,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,8MAStB,CAAC;AAEX,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,8EAKxB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,+CAA+C;AAC/C,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG;IAChD,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC,kBAAkB,EAAE,eAAe,GAAG,SAAS,GAAG,aAAa,CAAC,CAAC;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG,qBAAqB,CAAC;AAE9E,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAibxE;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,EAC9B,WAAW,EAAE,kBAAkB,EAC/B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CAgSxB;AAED,sFAAsF;AACtF,wBAAsB,OAAO,CAC3B,OAAO,EAAE,qBAAqB,EAC9B,WAAW,EAAE,MAAM,GAAG,kBAAkB,EACxC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAgCf"}
|
package/dist/commands/extract.js
CHANGED
|
@@ -8,12 +8,14 @@ import { getSurface, getTarget, markSurfaceLifecycle, markTargetLifecycle, } fro
|
|
|
8
8
|
import { getPageScopeEpoch, setCurrentPage } from '../runtime-page-state.js';
|
|
9
9
|
import { outputContractFailure, outputJSON, } from '../output.js';
|
|
10
10
|
import { captureDiagnosticSnapshotBestEffort, finishDiagnosticStepBestEffort, recordCommandLifecycleEventBestEffort, startDiagnosticStep, } from '../diagnostics.js';
|
|
11
|
-
import {
|
|
11
|
+
import { resolveCurrentPageContext, resolvePageByRef as resolvePlaywrightPageByRef, syncSessionPage, } from '../playwright-runtime.js';
|
|
12
12
|
import { withApiTraceContext } from '../command-api-tracing.js';
|
|
13
13
|
import { normalizePageSignature } from './descriptor-validation.js';
|
|
14
14
|
import { readScopedDialogText } from './extract-scoped-dialog-text.js';
|
|
15
15
|
import { resolveScopedExtractContext } from './extract-scope-resolution.js';
|
|
16
16
|
import { executeStagehandExtract } from './extract-stagehand-executor.js';
|
|
17
|
+
import { describeBrowserConnectionFailure } from './browser-connection-failure.js';
|
|
18
|
+
import { withStickyOwnerBrowser } from '../sticky-owner.js';
|
|
17
19
|
/** Stable top-level error codes returned by `extract(...)`. */
|
|
18
20
|
export const EXTRACT_ERROR_CODES = [
|
|
19
21
|
'browser_connection_failed',
|
|
@@ -459,180 +461,181 @@ export async function extractBrowser(session, schemaInput, scopeRef) {
|
|
|
459
461
|
scopeRef,
|
|
460
462
|
});
|
|
461
463
|
}
|
|
462
|
-
let browser = null;
|
|
463
464
|
let failureMessage = null;
|
|
464
465
|
let cleanupScopedExtract = null;
|
|
465
466
|
let staleScope = false;
|
|
466
467
|
let staleReason = null;
|
|
467
468
|
try {
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
catch (err) {
|
|
471
|
-
return buildExtractContractFailureResult(session, {
|
|
472
|
-
step: extractStep,
|
|
473
|
-
error: 'browser_connection_failed',
|
|
474
|
-
outcomeType: 'blocked',
|
|
475
|
-
message: 'Extraction could not start because AgentBrowse failed to connect to the browser.',
|
|
476
|
-
reason: err instanceof Error ? err.message : String(err),
|
|
477
|
-
scopeRef,
|
|
478
|
-
pageRef,
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
try {
|
|
482
|
-
let sourcePage;
|
|
483
|
-
if (scopeTarget) {
|
|
484
|
-
sourcePage = await resolvePlaywrightPageByRef(browser, session, pageRef);
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
const resolvedPage = await resolveCurrentPageContext(browser, session);
|
|
488
|
-
pageRef = resolvedPage.pageRef;
|
|
489
|
-
sourcePage = resolvedPage.page;
|
|
490
|
-
}
|
|
491
|
-
let page = sourcePage;
|
|
492
|
-
let scopedResolution = null;
|
|
493
|
-
const { url, title } = await syncSessionPage(session, pageRef, sourcePage);
|
|
494
|
-
if (scopeTarget?.pageSignature &&
|
|
495
|
-
normalizePageSignature(url) !== scopeTarget.pageSignature) {
|
|
496
|
-
staleScope = true;
|
|
497
|
-
staleReason = 'page-signature-mismatch';
|
|
498
|
-
throw new Error('stale_scope_target_page_signature_changed');
|
|
499
|
-
}
|
|
500
|
-
let effectiveSelector;
|
|
501
|
-
if (scopeTarget) {
|
|
469
|
+
return await withStickyOwnerBrowser(session, async (browser) => {
|
|
502
470
|
try {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
471
|
+
let sourcePage;
|
|
472
|
+
if (scopeTarget) {
|
|
473
|
+
sourcePage = await resolvePlaywrightPageByRef(browser, session, pageRef);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
const resolvedPage = await resolveCurrentPageContext(browser, session);
|
|
477
|
+
pageRef = resolvedPage.pageRef;
|
|
478
|
+
sourcePage = resolvedPage.page;
|
|
479
|
+
}
|
|
480
|
+
let page = sourcePage;
|
|
481
|
+
let scopedResolution = null;
|
|
482
|
+
const { url, title } = await syncSessionPage(session, pageRef, sourcePage);
|
|
483
|
+
if (scopeTarget?.pageSignature &&
|
|
484
|
+
normalizePageSignature(url) !== scopeTarget.pageSignature) {
|
|
485
|
+
staleScope = true;
|
|
486
|
+
staleReason = 'page-signature-mismatch';
|
|
487
|
+
throw new Error('stale_scope_target_page_signature_changed');
|
|
488
|
+
}
|
|
489
|
+
let effectiveSelector;
|
|
490
|
+
if (scopeTarget) {
|
|
491
|
+
try {
|
|
492
|
+
scopedResolution = await resolveScopedExtractContext({
|
|
493
|
+
page: sourcePage,
|
|
494
|
+
scopeTarget,
|
|
495
|
+
validateDomSignature: Boolean(targetScope),
|
|
496
|
+
});
|
|
497
|
+
cleanupScopedExtract = scopedResolution.cleanup;
|
|
498
|
+
page = scopedResolution.page;
|
|
499
|
+
effectiveSelector = scopedResolution.selector;
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
if (error instanceof Error &&
|
|
503
|
+
error.message === 'stale_scope_target_dom_signature_changed') {
|
|
504
|
+
staleScope = true;
|
|
505
|
+
staleReason = 'dom-signature-mismatch';
|
|
506
|
+
}
|
|
507
|
+
else if (surfaceScope &&
|
|
508
|
+
surfaceExtractScopeLifetime(surfaceScope) === 'snapshot' &&
|
|
509
|
+
error instanceof Error &&
|
|
510
|
+
error.message === 'scope_target_unresolvable') {
|
|
511
|
+
return buildExtractContractFailureResult(session, {
|
|
512
|
+
step: extractStep,
|
|
513
|
+
error: 'expired_extract_scope',
|
|
514
|
+
outcomeType: 'binding_stale',
|
|
515
|
+
message: 'Extraction failed because the requested snapshot scope expired before it could be rebound.',
|
|
516
|
+
reason: `Snapshot scope ${scopeRef} is no longer present in the current visible page state.`,
|
|
517
|
+
scopeRef,
|
|
518
|
+
pageRef,
|
|
519
|
+
staleScope: true,
|
|
520
|
+
staleReason: 'snapshot-scope-expired',
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
setCurrentPage(session, pageRef);
|
|
527
|
+
const execution = await executeStagehandExtract({
|
|
528
|
+
session,
|
|
529
|
+
instruction,
|
|
530
|
+
schema: normalizedSchema.schema,
|
|
531
|
+
page,
|
|
532
|
+
selector: effectiveSelector,
|
|
533
|
+
degradationReason: scopedResolution?.degraded
|
|
534
|
+
? scopedResolution.degradationReason
|
|
535
|
+
: undefined,
|
|
536
|
+
});
|
|
537
|
+
let data = execution.data;
|
|
538
|
+
if (scopeTarget &&
|
|
539
|
+
effectiveSelector &&
|
|
540
|
+
normalizedSchema.requestsScopedDialogText &&
|
|
541
|
+
data &&
|
|
542
|
+
typeof data === 'object' &&
|
|
543
|
+
!Array.isArray(data)) {
|
|
544
|
+
const dialogText = await readScopedDialogText(page, effectiveSelector);
|
|
545
|
+
if (typeof dialogText === 'string' && dialogText.trim().length > 0) {
|
|
546
|
+
data = {
|
|
547
|
+
...data,
|
|
548
|
+
dialog_text: dialogText,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return buildExtractSuccessResult(session, extractStep, {
|
|
553
|
+
success: true,
|
|
554
|
+
...execution,
|
|
555
|
+
data,
|
|
556
|
+
pageRef,
|
|
557
|
+
scopeRef,
|
|
558
|
+
metrics: session.runtime?.metrics,
|
|
559
|
+
url,
|
|
560
|
+
title,
|
|
507
561
|
});
|
|
508
|
-
cleanupScopedExtract = scopedResolution.cleanup;
|
|
509
|
-
page = scopedResolution.page;
|
|
510
|
-
effectiveSelector = scopedResolution.selector;
|
|
511
562
|
}
|
|
512
|
-
catch (
|
|
513
|
-
if (
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
563
|
+
catch (err) {
|
|
564
|
+
if (staleScope && scopeRef) {
|
|
565
|
+
if (targetScope) {
|
|
566
|
+
markTargetLifecycle(session, scopeRef, 'stale', staleReason ?? 'unknown');
|
|
567
|
+
}
|
|
568
|
+
else if (surfaceScope) {
|
|
569
|
+
markSurfaceLifecycle(session, scopeRef, 'stale', staleReason ?? 'unknown');
|
|
570
|
+
}
|
|
517
571
|
}
|
|
518
|
-
|
|
519
|
-
surfaceExtractScopeLifetime(surfaceScope) === 'snapshot' &&
|
|
520
|
-
error instanceof Error &&
|
|
521
|
-
error.message === 'scope_target_unresolvable') {
|
|
572
|
+
if (!staleScope && err instanceof AssistiveStructuredOutputTruncatedError) {
|
|
522
573
|
return buildExtractContractFailureResult(session, {
|
|
523
574
|
step: extractStep,
|
|
524
|
-
error: '
|
|
525
|
-
outcomeType: '
|
|
526
|
-
message: 'Extraction failed because the
|
|
527
|
-
reason:
|
|
575
|
+
error: 'extract_output_truncated',
|
|
576
|
+
outcomeType: 'blocked',
|
|
577
|
+
message: 'Extraction failed because the provider truncated structured output.',
|
|
578
|
+
reason: buildTruncationReason(err),
|
|
528
579
|
scopeRef,
|
|
529
580
|
pageRef,
|
|
530
|
-
staleScope:
|
|
531
|
-
|
|
581
|
+
staleScope: false,
|
|
582
|
+
provider: err.provider,
|
|
583
|
+
model: err.model,
|
|
584
|
+
finishReason: err.finishReason,
|
|
585
|
+
maxOutputTokens: err.maxOutputTokens,
|
|
586
|
+
completionTokens: err.completionTokens,
|
|
532
587
|
});
|
|
533
588
|
}
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
setCurrentPage(session, pageRef);
|
|
538
|
-
const execution = await executeStagehandExtract({
|
|
539
|
-
session,
|
|
540
|
-
instruction,
|
|
541
|
-
schema: normalizedSchema.schema,
|
|
542
|
-
page,
|
|
543
|
-
selector: effectiveSelector,
|
|
544
|
-
degradationReason: scopedResolution?.degraded
|
|
545
|
-
? scopedResolution.degradationReason
|
|
546
|
-
: undefined,
|
|
547
|
-
});
|
|
548
|
-
let data = execution.data;
|
|
549
|
-
if (scopeTarget &&
|
|
550
|
-
effectiveSelector &&
|
|
551
|
-
normalizedSchema.requestsScopedDialogText &&
|
|
552
|
-
data &&
|
|
553
|
-
typeof data === 'object' &&
|
|
554
|
-
!Array.isArray(data)) {
|
|
555
|
-
const dialogText = await readScopedDialogText(page, effectiveSelector);
|
|
556
|
-
if (typeof dialogText === 'string' && dialogText.trim().length > 0) {
|
|
557
|
-
data = {
|
|
558
|
-
...data,
|
|
559
|
-
dialog_text: dialogText,
|
|
560
|
-
};
|
|
589
|
+
failureMessage = `Extract failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
561
590
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
data,
|
|
567
|
-
pageRef,
|
|
568
|
-
scopeRef,
|
|
569
|
-
metrics: session.runtime?.metrics,
|
|
570
|
-
url,
|
|
571
|
-
title,
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
catch (err) {
|
|
575
|
-
if (staleScope && scopeRef) {
|
|
576
|
-
if (targetScope) {
|
|
577
|
-
markTargetLifecycle(session, scopeRef, 'stale', staleReason ?? 'unknown');
|
|
591
|
+
finally {
|
|
592
|
+
if (cleanupScopedExtract) {
|
|
593
|
+
await cleanupScopedExtract().catch(() => undefined);
|
|
594
|
+
}
|
|
578
595
|
}
|
|
579
|
-
|
|
580
|
-
|
|
596
|
+
if (failureMessage) {
|
|
597
|
+
return buildExtractContractFailureResult(session, {
|
|
598
|
+
step: extractStep,
|
|
599
|
+
error: staleScope ? 'stale_extract_scope' : 'extract_failed',
|
|
600
|
+
outcomeType: staleScope ? 'binding_stale' : 'blocked',
|
|
601
|
+
message: staleScope
|
|
602
|
+
? 'Extraction failed because the requested scope became stale.'
|
|
603
|
+
: 'Extraction failed.',
|
|
604
|
+
reason: staleScope && scopeRef
|
|
605
|
+
? `${failureMessage} (${scopeRef} marked stale: ${staleReason ?? 'stale'})`
|
|
606
|
+
: failureMessage.replace(/^Extract failed:\s*/, ''),
|
|
607
|
+
scopeRef,
|
|
608
|
+
pageRef,
|
|
609
|
+
staleScope,
|
|
610
|
+
staleReason: staleReason ?? undefined,
|
|
611
|
+
});
|
|
581
612
|
}
|
|
582
|
-
}
|
|
583
|
-
if (!staleScope && err instanceof AssistiveStructuredOutputTruncatedError) {
|
|
584
613
|
return buildExtractContractFailureResult(session, {
|
|
585
614
|
step: extractStep,
|
|
586
|
-
error: '
|
|
615
|
+
error: 'extract_failed',
|
|
587
616
|
outcomeType: 'blocked',
|
|
588
|
-
message: 'Extraction failed
|
|
589
|
-
reason:
|
|
617
|
+
message: 'Extraction failed.',
|
|
618
|
+
reason: 'Extraction did not produce a success or failure result.',
|
|
590
619
|
scopeRef,
|
|
591
620
|
pageRef,
|
|
592
|
-
staleScope: false,
|
|
593
|
-
provider: err.provider,
|
|
594
|
-
model: err.model,
|
|
595
|
-
finishReason: err.finishReason,
|
|
596
|
-
maxOutputTokens: err.maxOutputTokens,
|
|
597
|
-
completionTokens: err.completionTokens,
|
|
598
621
|
});
|
|
599
|
-
}
|
|
600
|
-
failureMessage = `Extract failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
601
|
-
}
|
|
602
|
-
finally {
|
|
603
|
-
if (cleanupScopedExtract) {
|
|
604
|
-
await cleanupScopedExtract().catch(() => undefined);
|
|
605
|
-
}
|
|
606
|
-
if (browser) {
|
|
607
|
-
await disconnectPlaywright(browser);
|
|
608
|
-
}
|
|
622
|
+
});
|
|
609
623
|
}
|
|
610
|
-
|
|
624
|
+
catch (err) {
|
|
625
|
+
const browserConnectionFailure = describeBrowserConnectionFailure(err, {
|
|
626
|
+
defaultMessage: 'Extraction could not start because AgentBrowse failed to connect to the browser.',
|
|
627
|
+
unrecoverableSessionMessage: 'Extraction could not start because the previous browser session is no longer reachable.',
|
|
628
|
+
});
|
|
611
629
|
return buildExtractContractFailureResult(session, {
|
|
612
630
|
step: extractStep,
|
|
613
|
-
error:
|
|
614
|
-
outcomeType:
|
|
615
|
-
message:
|
|
616
|
-
|
|
617
|
-
: 'Extraction failed.',
|
|
618
|
-
reason: staleScope && scopeRef
|
|
619
|
-
? `${failureMessage} (${scopeRef} marked stale: ${staleReason ?? 'stale'})`
|
|
620
|
-
: failureMessage.replace(/^Extract failed:\s*/, ''),
|
|
631
|
+
error: 'browser_connection_failed',
|
|
632
|
+
outcomeType: 'blocked',
|
|
633
|
+
message: browserConnectionFailure.message,
|
|
634
|
+
reason: browserConnectionFailure.reason,
|
|
621
635
|
scopeRef,
|
|
622
636
|
pageRef,
|
|
623
|
-
staleScope,
|
|
624
|
-
staleReason: staleReason ?? undefined,
|
|
625
637
|
});
|
|
626
638
|
}
|
|
627
|
-
return buildExtractContractFailureResult(session, {
|
|
628
|
-
step: extractStep,
|
|
629
|
-
error: 'extract_failed',
|
|
630
|
-
outcomeType: 'blocked',
|
|
631
|
-
message: 'Extraction failed.',
|
|
632
|
-
reason: 'Extraction did not produce a success or failure result.',
|
|
633
|
-
scopeRef,
|
|
634
|
-
pageRef,
|
|
635
|
-
});
|
|
636
639
|
});
|
|
637
640
|
}
|
|
638
641
|
/** CLI wrapper for `extractBrowser(...)` that accepts JSON text or schema objects. */
|