pi-agent-browser-native 0.2.47 → 0.2.49
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 +63 -19
- package/README.md +52 -19
- package/dist/extensions/agent-browser/index.js +785 -0
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
- package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
- package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
- package/dist/extensions/agent-browser/lib/config-policy.js +686 -0
- package/dist/extensions/agent-browser/lib/config.js +122 -0
- package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
- package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
- package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
- package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
- package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
- package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
- package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
- package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
- package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
- package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
- package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
- package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
- package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
- package/dist/extensions/agent-browser/lib/playbook.js +121 -0
- package/dist/extensions/agent-browser/lib/process.js +448 -0
- package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
- package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
- package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
- package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
- package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
- package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
- package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
- package/dist/extensions/agent-browser/lib/results/network.js +73 -0
- package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +960 -0
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
- package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
- package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
- package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
- package/dist/extensions/agent-browser/lib/results/text.js +40 -0
- package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
- package/dist/extensions/agent-browser/lib/runtime.js +816 -0
- package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
- package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
- package/dist/extensions/agent-browser/lib/temp.js +498 -0
- package/dist/extensions/agent-browser/lib/web-search.js +562 -0
- package/docs/ARCHITECTURE.md +10 -10
- package/docs/COMMAND_REFERENCE.md +35 -21
- package/docs/ELECTRON.md +3 -3
- package/docs/RELEASE.md +46 -26
- package/docs/REQUIREMENTS.md +1 -1
- package/docs/SUPPORT_MATRIX.md +35 -106
- package/docs/TOOL_CONTRACT.md +23 -21
- package/package.json +12 -8
- package/scripts/agent-browser-capability-baseline.mjs +6 -3
- package/scripts/config.mjs +8 -2
- package/scripts/doctor.mjs +19 -17
- package/scripts/platform-smoke.mjs +1 -1
- package/extensions/agent-browser/index.ts +0 -952
- package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
- package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
- package/extensions/agent-browser/lib/bash-guard.ts +0 -205
- package/extensions/agent-browser/lib/command-policy.ts +0 -71
- package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
- package/extensions/agent-browser/lib/config-policy.js +0 -690
- package/extensions/agent-browser/lib/config.ts +0 -209
- package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
- package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
- package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
- package/extensions/agent-browser/lib/electron/launch.ts +0 -499
- package/extensions/agent-browser/lib/executable-path.ts +0 -19
- package/extensions/agent-browser/lib/fs-utils.ts +0 -18
- package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
- package/extensions/agent-browser/lib/input-modes/job.ts +0 -451
- package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
- package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
- package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
- package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
- package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
- package/extensions/agent-browser/lib/input-modes.ts +0 -45
- package/extensions/agent-browser/lib/json-schema.ts +0 -73
- package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
- package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
- package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
- package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -257
- package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -912
- package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -512
- package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -1481
- package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -564
- package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
- package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
- package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -564
- package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
- package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
- package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
- package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -252
- package/extensions/agent-browser/lib/playbook.ts +0 -142
- package/extensions/agent-browser/lib/process.ts +0 -516
- package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
- package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
- package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
- package/extensions/agent-browser/lib/results/categories.ts +0 -106
- package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
- package/extensions/agent-browser/lib/results/contracts.ts +0 -241
- package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
- package/extensions/agent-browser/lib/results/envelope.ts +0 -195
- package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
- package/extensions/agent-browser/lib/results/network.ts +0 -78
- package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
- package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
- package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
- package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
- package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
- package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
- package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
- package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
- package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
- package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
- package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
- package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
- package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
- package/extensions/agent-browser/lib/results/presentation.ts +0 -257
- package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
- package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
- package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
- package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
- package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
- package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
- package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
- package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
- package/extensions/agent-browser/lib/results/text.ts +0 -40
- package/extensions/agent-browser/lib/runtime.ts +0 -988
- package/extensions/agent-browser/lib/session-page-state.ts +0 -512
- package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
- package/extensions/agent-browser/lib/temp.ts +0 -577
- package/extensions/agent-browser/lib/web-search.ts +0 -721
- /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { cleanupElectronLaunchResources } from "../../electron/cleanup.js";
|
|
2
|
+
import { getCompiledSemanticActionCommandIndex, getCompiledSemanticActionSessionPrefix, isCompiledSemanticActionFindCommand, redactNetworkSourceLookupSurface, } from "../../input-modes.js";
|
|
3
|
+
import { buildAgentBrowserNextActions, buildAgentBrowserResultCategoryDetails, } from "../../results.js";
|
|
4
|
+
import { formatSessionArtifactRetentionSummary } from "../../results/artifact-manifest.js";
|
|
5
|
+
import { AgentBrowserNextActionCollector, alignPageChangeSummaryNextActionIds, isStandaloneSnapshotNextAction, withOptionalSessionArgs, } from "../../results/next-actions.js";
|
|
6
|
+
import { buildConnectedSessionNextActions, buildNoActivePageNextActions, buildSessionAwareStaleRefNextActions, buildSessionTabRecoveryNextActions, } from "../../results/recovery-next-actions.js";
|
|
7
|
+
import { buildRichInputRecoveryDiagnostic, buildRichInputRecoveryNextActions, buildVisibleRefFallbackNextActions, formatRichInputRecoveryText, formatVisibleRefFallbackText, sanitizeVisibleRefFallbackDiagnostic, } from "../../results/selector-recovery.js";
|
|
8
|
+
import { buildNoActivePageRefSnapshotInvalidation, isNoActivePageSnapshotFailure, } from "../../session-page-state.js";
|
|
9
|
+
import { extractExplicitSessionName, redactInvocationArgs, redactSensitiveText, redactSensitiveValue } from "../../runtime.js";
|
|
10
|
+
import { isRecord } from "../../parsing.js";
|
|
11
|
+
import { buildClickDispatchNextActions, formatClickDispatchDiagnosticText } from "./click-dispatch.js";
|
|
12
|
+
import { buildComboboxFocusNextActions, buildElectronBroadGetTextScopeNextActions, buildFillVerificationNextActions, buildOverlayBlockerNextActions, buildScrollNoopNextActions, buildSelectorTextVisibilityNextActions, buildSourceLookupElectronNextActions, collectVisibleRefFallbackDiagnostic, formatArtifactCleanupGuidanceText, formatComboboxFocusDiagnosticText, formatElectronBroadGetTextScopeText, formatEvalResultWarningText, formatEvalStdinHintText, formatFillVerificationText, formatOverlayBlockerText, formatRecordingDependencyWarningText, formatScrollNoopDiagnosticText, formatSelectorTextVisibilityText, formatTimeoutPartialProgressText, } from "./diagnostics.js";
|
|
13
|
+
import { buildElectronIdentifiers, buildElectronLifecycleNextActions, buildElectronMismatchNextActions, buildElectronRefFreshnessNextActions, buildManagedSessionFreshFailureNextActions, buildManagedSessionOutcome, buildSessionDetailFields, formatElectronRefFreshnessText, formatManagedSessionOutcomeText, } from "./session-state.js";
|
|
14
|
+
export function buildMissingBinaryMessage() {
|
|
15
|
+
return [
|
|
16
|
+
"agent-browser is required but was not found on PATH.",
|
|
17
|
+
"This project does not bundle agent-browser.",
|
|
18
|
+
"Run `pi-agent-browser-doctor` for package/PATH diagnostics, then install agent-browser using the upstream docs:",
|
|
19
|
+
"- https://agent-browser.dev/",
|
|
20
|
+
"- https://github.com/vercel-labs/agent-browser",
|
|
21
|
+
].join("\n");
|
|
22
|
+
}
|
|
23
|
+
const SEMANTIC_ACTION_CANDIDATE_ACTION_IDS = new Set(["try-button-name-candidate", "try-link-name-candidate"]);
|
|
24
|
+
export function formatSemanticActionCandidateText(actions) {
|
|
25
|
+
const candidateActions = actions.filter((action) => SEMANTIC_ACTION_CANDIDATE_ACTION_IDS.has(action.id) && action.params?.args);
|
|
26
|
+
if (candidateActions.length === 0)
|
|
27
|
+
return undefined;
|
|
28
|
+
return ["Agent-browser candidate fallbacks:", ...candidateActions.map((action) => `- ${action.id}: agent_browser ${JSON.stringify({ args: action.params?.args })} — ${action.reason}`)].join("\n");
|
|
29
|
+
}
|
|
30
|
+
export function buildSemanticActionCandidateActions(compiled) {
|
|
31
|
+
const commandIndex = getCompiledSemanticActionCommandIndex(compiled);
|
|
32
|
+
if (commandIndex < 0 || compiled.args[commandIndex] !== "find")
|
|
33
|
+
return [];
|
|
34
|
+
const locator = compiled.args[commandIndex + 1];
|
|
35
|
+
const value = compiled.args[commandIndex + 2];
|
|
36
|
+
if (!locator || !value)
|
|
37
|
+
return [];
|
|
38
|
+
const sessionPrefix = getCompiledSemanticActionSessionPrefix(compiled);
|
|
39
|
+
const buildRoleCandidate = (role, id, reason) => {
|
|
40
|
+
const args = [...sessionPrefix, "find", "role", role, compiled.action];
|
|
41
|
+
args.push("--name", value);
|
|
42
|
+
return { id, params: { args: redactInvocationArgs(args) }, reason, safety: "Candidate locator fallback only; inspect the page if multiple elements could match the same accessible name.", tool: "agent_browser" };
|
|
43
|
+
};
|
|
44
|
+
if (locator === "text" && compiled.action === "click") {
|
|
45
|
+
return [
|
|
46
|
+
buildRoleCandidate("button", "try-button-name-candidate", "Retry against a button with the same accessible name when text lookup misses."),
|
|
47
|
+
buildRoleCandidate("link", "try-link-name-candidate", "Retry against a link with the same accessible name when text lookup misses."),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
export function buildWrapperRecoveryHint(options) {
|
|
53
|
+
const wrapperManagedContexts = [options.sessionTabCorrection ? "session tab correction" : undefined, options.pinnedBatchUnwrapMode ? "pinned batch routing" : undefined].filter((item) => item !== undefined);
|
|
54
|
+
if (wrapperManagedContexts.length === 0)
|
|
55
|
+
return undefined;
|
|
56
|
+
return `Wrapper recovery hint: this call used ${wrapperManagedContexts.join(" and ")}. Inspect details.effectiveArgs and details.sessionTabCorrection; if the selected tab looks wrong, run tab list for the same session before retrying.`;
|
|
57
|
+
}
|
|
58
|
+
export function redactExactSensitiveText(text, sensitiveValues) {
|
|
59
|
+
let redacted = text;
|
|
60
|
+
for (const value of sensitiveValues)
|
|
61
|
+
redacted = redacted.split(value).join("[REDACTED]");
|
|
62
|
+
return redacted;
|
|
63
|
+
}
|
|
64
|
+
export function redactExactSensitiveValue(value, sensitiveValues) {
|
|
65
|
+
if (sensitiveValues.length === 0)
|
|
66
|
+
return value;
|
|
67
|
+
if (typeof value === "string")
|
|
68
|
+
return redactExactSensitiveText(value, sensitiveValues);
|
|
69
|
+
if (Array.isArray(value))
|
|
70
|
+
return value.map((item) => redactExactSensitiveValue(item, sensitiveValues));
|
|
71
|
+
if (!isRecord(value))
|
|
72
|
+
return value;
|
|
73
|
+
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, redactExactSensitiveValue(entryValue, sensitiveValues)]));
|
|
74
|
+
}
|
|
75
|
+
export function redactToolDetails(details, sensitiveValues) {
|
|
76
|
+
return redactSensitiveValue(redactExactSensitiveValue(details, sensitiveValues));
|
|
77
|
+
}
|
|
78
|
+
export function redactRecoveryHint(recoveryHint) {
|
|
79
|
+
if (!recoveryHint)
|
|
80
|
+
return undefined;
|
|
81
|
+
const exampleArgs = redactInvocationArgs(recoveryHint.exampleArgs);
|
|
82
|
+
return { ...recoveryHint, exampleArgs, exampleParams: { ...recoveryHint.exampleParams, args: exampleArgs } };
|
|
83
|
+
}
|
|
84
|
+
export function buildJsonVisibleContent(options) {
|
|
85
|
+
const { error, presentation, succeeded, warnings } = options;
|
|
86
|
+
const payload = redactSensitiveValue({ artifacts: presentation.artifacts, data: presentation.data, error, success: succeeded, warnings: warnings && warnings.length > 0 ? warnings : undefined });
|
|
87
|
+
if (isRecord(payload) && isRecord(payload.data) && isRecord(presentation.data) && typeof presentation.data.wsUrl === "string")
|
|
88
|
+
payload.data.wsUrl = presentation.data.wsUrl;
|
|
89
|
+
const images = presentation.content.filter((item) => item.type === "image");
|
|
90
|
+
return [{ type: "text", text: JSON.stringify(payload, null, 2) }, ...images];
|
|
91
|
+
}
|
|
92
|
+
export function getElectronLaunchFailureCategory(failure) {
|
|
93
|
+
if (failure.reason === "policy-blocked")
|
|
94
|
+
return "policy-blocked";
|
|
95
|
+
if (failure.reason === "timeout")
|
|
96
|
+
return "timeout";
|
|
97
|
+
if (failure.reason === "non-electron-target")
|
|
98
|
+
return "validation-error";
|
|
99
|
+
return "upstream-error";
|
|
100
|
+
}
|
|
101
|
+
function formatElectronLaunchFailureDiagnostics(failure) {
|
|
102
|
+
const diagnostics = failure?.diagnostics;
|
|
103
|
+
if (!diagnostics)
|
|
104
|
+
return undefined;
|
|
105
|
+
const lines = ["Electron launch diagnostics:"];
|
|
106
|
+
if (diagnostics.pid !== undefined)
|
|
107
|
+
lines.push(`- PID: ${diagnostics.pid} (${diagnostics.pidAlive === undefined ? "state unknown" : diagnostics.pidAlive ? "alive before cleanup" : "not alive before cleanup"}).`);
|
|
108
|
+
if (diagnostics.exitCode !== undefined || diagnostics.exitSignal !== undefined) {
|
|
109
|
+
const exitParts = [diagnostics.exitCode !== undefined ? `code ${diagnostics.exitCode}` : undefined, diagnostics.exitSignal ? `signal ${diagnostics.exitSignal}` : undefined].filter(Boolean).join(", ");
|
|
110
|
+
lines.push(`- Process exit: ${exitParts || "not observed before cleanup"}.`);
|
|
111
|
+
}
|
|
112
|
+
if (diagnostics.userDataDir)
|
|
113
|
+
lines.push(`- Wrapper profile: ${diagnostics.userDataDir}`);
|
|
114
|
+
if (diagnostics.devToolsActivePort) {
|
|
115
|
+
const activePort = diagnostics.devToolsActivePort;
|
|
116
|
+
const state = activePort.port ? `found port ${activePort.port}` : activePort.found ? `found but invalid${activePort.error ? ` (${activePort.error})` : ""}` : `missing${activePort.error ? ` (${activePort.error})` : ""}`;
|
|
117
|
+
lines.push(`- DevToolsActivePort: ${state} at ${activePort.path}.`);
|
|
118
|
+
}
|
|
119
|
+
if (diagnostics.cdpVersionReached === false)
|
|
120
|
+
lines.push("- CDP /json/version: did not return a valid payload before timeout.");
|
|
121
|
+
if (diagnostics.timeoutMs !== undefined || diagnostics.elapsedMs !== undefined)
|
|
122
|
+
lines.push(`- Timing: ${diagnostics.elapsedMs ?? "unknown"}ms elapsed${diagnostics.timeoutMs !== undefined ? ` of ${diagnostics.timeoutMs}ms timeout` : ""}.`);
|
|
123
|
+
if (diagnostics.outputCaptured === false)
|
|
124
|
+
lines.push("- App stdout/stderr: not captured by this wrapper launch path.");
|
|
125
|
+
lines.push("Retry guidance: increase electron.timeoutMs, try targetType:'any', pass an explicit appPath/executablePath, quit any already-running singleton instance, then retry launch.");
|
|
126
|
+
return lines.join("\n");
|
|
127
|
+
}
|
|
128
|
+
export function buildElectronHostFailureResult(options) {
|
|
129
|
+
const text = [options.errorText, formatElectronLaunchFailureDiagnostics(options.launchFailure), options.launchFailure?.cleanupError ? `Electron launch cleanup warning: ${options.launchFailure.cleanupError}` : undefined].filter((item) => item !== undefined && item.length > 0).join("\n");
|
|
130
|
+
const details = { args: [], compiledElectron: options.compiledElectron, electron: { action: options.compiledElectron.action, error: options.errorText, failure: options.launchFailure, status: options.status ?? "failed" }, managedSessionOutcome: options.managedSessionOutcome, ...buildAgentBrowserResultCategoryDetails({ args: [], errorText: options.errorText, failureCategory: options.failureCategory, succeeded: false, timedOut: options.failureCategory === "timeout" }), summary: options.errorText };
|
|
131
|
+
return { content: [{ type: "text", text: redactSensitiveText(text) }], details: redactToolDetails(details, []), isError: true };
|
|
132
|
+
}
|
|
133
|
+
export function formatElectronTargetLines(targets, limit = 8) {
|
|
134
|
+
const shownTargets = targets.slice(0, limit);
|
|
135
|
+
const lines = shownTargets.map((target) => {
|
|
136
|
+
const label = [target.type, target.title].filter(Boolean).join(" ") || target.id || "target";
|
|
137
|
+
return `- ${label}${target.url ? ` — ${target.url}` : ""}`;
|
|
138
|
+
});
|
|
139
|
+
if (targets.length > shownTargets.length)
|
|
140
|
+
lines.push(`- ... ${targets.length - shownTargets.length} more target(s) omitted`);
|
|
141
|
+
return lines;
|
|
142
|
+
}
|
|
143
|
+
const ELECTRON_PROFILE_ISOLATION_NOTE = "Profile note: electron.launch starts an isolated temporary profile; it does not reuse the app's normal signed-in profile or attach to an already-running authenticated app.";
|
|
144
|
+
const ELECTRON_EXISTING_AUTH_GUIDANCE = "For already-authenticated desktop app content, do not stop here: if host tools are allowed and the app is not running, launch the normal app with --remote-debugging-port=<port>, verify the port, then run agent_browser connect <port>; if it is already running without a debug port, ask before relaunching it.";
|
|
145
|
+
export function formatElectronLaunchText(options) {
|
|
146
|
+
const lines = [`Electron launch: ${options.record.appName} attached as ${options.record.sessionName ?? "managed session"} (launchId ${options.record.launchId}, port ${options.record.port}).`, `Identifiers: launchId ${options.record.launchId} for electron.status/electron.cleanup/electron.probe; sessionName ${options.record.sessionName ?? "not attached"} for browser snapshot/tab commands.`, ELECTRON_PROFILE_ISOLATION_NOTE, ELECTRON_EXISTING_AUTH_GUIDANCE, ...formatElectronTargetLines(options.targets)];
|
|
147
|
+
if (options.handoff?.handoff === "snapshot")
|
|
148
|
+
lines.push(options.handoff.refSnapshot && options.handoff.refSnapshot.refIds.length > 0 ? `Snapshot handoff: ${options.handoff.refSnapshot.refIds.length} interactive ref(s)${options.handoff.snapshotRetryCount ? ` after ${options.handoff.snapshotRetryCount} retry attempt(s)` : ""}.` : "Snapshot handoff: no interactive refs returned after a short readiness retry; run snapshot -i once more before assuming the Electron UI is unusable.");
|
|
149
|
+
else if (options.handoff?.handoff === "tabs")
|
|
150
|
+
lines.push("Tabs handoff completed: safer diagnostic starting point; no interactive refs were captured.");
|
|
151
|
+
else if (options.handoff?.handoff === "connect")
|
|
152
|
+
lines.push("Connect handoff completed: run snapshot -i before using interactive refs.");
|
|
153
|
+
lines.push(`Cleanup: use details.nextActions cleanup-electron-launch or call electron.cleanup with launchId ${options.record.launchId} when finished.`);
|
|
154
|
+
if (options.handoff?.error)
|
|
155
|
+
lines.push(`Handoff warning: ${options.handoff.error}`);
|
|
156
|
+
if (options.upstreamText.trim().length > 0)
|
|
157
|
+
lines.push("", options.upstreamText.trim());
|
|
158
|
+
return lines.join("\n");
|
|
159
|
+
}
|
|
160
|
+
export function buildRedactedPresentationContent(options) {
|
|
161
|
+
const { exactSensitiveValues, plainTextInspection, presentation, presentationEnvelope, succeeded, userRequestedJson, warningText } = options;
|
|
162
|
+
const contentWithSessionWarnings = userRequestedJson && !plainTextInspection ? buildJsonVisibleContent({ error: presentationEnvelope?.error, presentation, succeeded, warnings: warningText ? [warningText] : undefined }) : warningText ? [...presentation.content] : presentation.content;
|
|
163
|
+
if (warningText && !userRequestedJson) {
|
|
164
|
+
if (contentWithSessionWarnings[0]?.type === "text")
|
|
165
|
+
contentWithSessionWarnings[0] = { ...contentWithSessionWarnings[0], text: `${warningText}\n\n${contentWithSessionWarnings[0].text}` };
|
|
166
|
+
else
|
|
167
|
+
contentWithSessionWarnings.unshift({ type: "text", text: warningText });
|
|
168
|
+
}
|
|
169
|
+
return contentWithSessionWarnings.map((item) => {
|
|
170
|
+
if (item.type !== "text")
|
|
171
|
+
return item;
|
|
172
|
+
const exactRedactedText = redactExactSensitiveText(item.text, exactSensitiveValues);
|
|
173
|
+
return userRequestedJson && !plainTextInspection ? { ...item, text: exactRedactedText } : { ...item, text: redactSensitiveText(exactRedactedText) };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
export async function prepareFinalResultRecoveryState(options) {
|
|
177
|
+
let { currentRefSnapshot, currentRefSnapshotInvalidation } = options;
|
|
178
|
+
const categoryDetails = buildAgentBrowserResultCategoryDetails({ artifacts: options.presentation.artifacts, args: options.redactedProcessArgs, command: options.executionPlan.commandInfo.command, confirmationRequired: options.presentation.summary.startsWith("Confirmation required"), errorText: options.errorText ?? options.presentation.summary, failureCategory: options.presentation.failureCategory ?? options.presentation.batchFailure?.failedStep.failureCategory ?? (options.electronPostCommandHealth ? "tab-drift" : undefined), inspection: options.plainTextInspection, parseError: options.parseError, savedFile: options.presentation.savedFile, spawnError: options.processResult.spawnError?.message, succeeded: options.succeeded, tabDrift: !options.succeeded && (options.aboutBlankSessionMismatch !== undefined || options.electronPostCommandHealth !== undefined || options.sessionTabCorrection !== undefined), timedOut: options.processResult.timedOut, validationError: undefined });
|
|
179
|
+
let visibleRefFallbackDiagnostic;
|
|
180
|
+
const visibleRefFallbackSessionName = options.executionPlan.sessionName ?? extractExplicitSessionName(options.runtimeToolArgs);
|
|
181
|
+
if (categoryDetails.failureCategory === "selector-not-found") {
|
|
182
|
+
const selectorRecoveryCommandTokens = options.presentation.batchFailure?.failedStep.command ?? options.commandTokens;
|
|
183
|
+
visibleRefFallbackDiagnostic = await collectVisibleRefFallbackDiagnostic({ commandTokens: selectorRecoveryCommandTokens, compiledSemanticAction: options.compiledSemanticAction, cwd: options.cwd, sessionName: visibleRefFallbackSessionName, signal: options.signal });
|
|
184
|
+
if (visibleRefFallbackDiagnostic && visibleRefFallbackSessionName) {
|
|
185
|
+
const refUpdate = options.sessionPageState.applyRefSnapshot({ fallbackTarget: options.currentSessionTabTarget, sessionName: visibleRefFallbackSessionName, snapshot: visibleRefFallbackDiagnostic.snapshot, update: options.sessionPageStateUpdate });
|
|
186
|
+
currentRefSnapshot = refUpdate.refSnapshot;
|
|
187
|
+
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const richInputRecoveryDiagnostic = buildRichInputRecoveryDiagnostic(visibleRefFallbackDiagnostic);
|
|
191
|
+
const noActivePageSnapshotFailure = categoryDetails.resultCategory === "failure" && (isNoActivePageSnapshotFailure(options.executionPlan.commandInfo.command, options.errorText ?? options.presentation.summary) || options.batchRefSnapshotState?.invalidation !== undefined);
|
|
192
|
+
if (noActivePageSnapshotFailure && options.executionPlan.sessionName) {
|
|
193
|
+
const refUpdate = options.sessionPageState.applyRefSnapshotInvalidation({ invalidation: buildNoActivePageRefSnapshotInvalidation(), sessionName: options.executionPlan.sessionName, update: options.sessionPageStateUpdate });
|
|
194
|
+
currentRefSnapshot = refUpdate.refSnapshot;
|
|
195
|
+
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
196
|
+
}
|
|
197
|
+
return { categoryDetails, currentRefSnapshot, currentRefSnapshotInvalidation, noActivePageSnapshotFailure, richInputRecoveryDiagnostic, visibleRefFallbackDiagnostic, visibleRefFallbackSessionName };
|
|
198
|
+
}
|
|
199
|
+
function buildTimeoutPartialProgressNextActions(options) {
|
|
200
|
+
const retryArgs = options.timeoutPartialProgress?.retryStep?.retry?.args;
|
|
201
|
+
const stepIndex = options.timeoutPartialProgress?.retryStep?.index;
|
|
202
|
+
const freshSessionAbandoned = options.sessionMode === "fresh" && options.timeoutPartialProgress?.liveUrlRecovered !== true;
|
|
203
|
+
if (retryArgs) {
|
|
204
|
+
return [{
|
|
205
|
+
id: "retry-timeout-step",
|
|
206
|
+
params: freshSessionAbandoned
|
|
207
|
+
? { args: retryArgs, sessionMode: "fresh" }
|
|
208
|
+
: { args: withOptionalSessionArgs(options.executionPlan.sessionName, retryArgs) },
|
|
209
|
+
reason: freshSessionAbandoned
|
|
210
|
+
? `Retry the first incomplete timed-out step${stepIndex === undefined ? "" : ` ${stepIndex}`} in a fresh browser session because the timed-out fresh session was not proven live.`
|
|
211
|
+
: `Retry the first incomplete timed-out step${stepIndex === undefined ? "" : ` ${stepIndex}`} against the current browser session.`,
|
|
212
|
+
safety: "Only read-only or idempotent timeout steps get executable retry args; inspect current page/artifact state before using the action.",
|
|
213
|
+
tool: "agent_browser",
|
|
214
|
+
}];
|
|
215
|
+
}
|
|
216
|
+
if (!options.timeoutPartialProgress || freshSessionAbandoned || !options.executionPlan.sessionName)
|
|
217
|
+
return [];
|
|
218
|
+
return [{
|
|
219
|
+
id: "inspect-current-page-after-timeout",
|
|
220
|
+
params: { args: withOptionalSessionArgs(options.executionPlan.sessionName, ["snapshot", "-i"]) },
|
|
221
|
+
reason: `Inspect the current page after timeout before deciding how to resume${stepIndex === undefined ? "" : ` from incomplete step ${stepIndex}`}.`,
|
|
222
|
+
safety: "Read details.timeoutPartialProgress first. Do not blindly retry mutating steps such as clicks, fills, key presses, selects, or checks; split the remaining flow into shorter batches around the next navigation or DOM mutation boundary.",
|
|
223
|
+
tool: "agent_browser",
|
|
224
|
+
}];
|
|
225
|
+
}
|
|
226
|
+
function buildDialogTimeoutNextActions(options) {
|
|
227
|
+
if (options.command !== "dialog" && options.command !== "click" && options.command !== "tap" && options.command !== "find" && options.command !== "eval")
|
|
228
|
+
return [];
|
|
229
|
+
return [
|
|
230
|
+
{
|
|
231
|
+
id: "inspect-dialog-after-timeout",
|
|
232
|
+
params: { args: withOptionalSessionArgs(options.sessionName, ["dialog", "status"]) },
|
|
233
|
+
reason: "Check whether a blocking JavaScript dialog is pending after the timed-out interaction.",
|
|
234
|
+
safety: "Read-only dialog status; this wrapper bounds dialog commands so recovery attempts do not wait for the full default watchdog.",
|
|
235
|
+
tool: "agent_browser",
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: "dismiss-dialog-after-timeout",
|
|
239
|
+
params: { args: withOptionalSessionArgs(options.sessionName, ["dialog", "dismiss"]) },
|
|
240
|
+
reason: "Dismiss a pending alert/confirm/prompt when the workflow can safely abandon the dialog.",
|
|
241
|
+
safety: "Only run when dismissing/canceling the dialog is acceptable for the user flow.",
|
|
242
|
+
tool: "agent_browser",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
id: "recover-fresh-session-after-dialog-timeout",
|
|
246
|
+
params: { args: ["open", "about:blank"], sessionMode: "fresh" },
|
|
247
|
+
reason: "Start a clean browser session if the current session remains blocked behind a JavaScript dialog.",
|
|
248
|
+
safety: "Replace about:blank with the intended recovery URL; this abandons the blocked managed session.",
|
|
249
|
+
tool: "agent_browser",
|
|
250
|
+
},
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
function buildResultNextActions(options) {
|
|
254
|
+
const nextActionCollector = new AgentBrowserNextActionCollector(options.presentation.nextActions);
|
|
255
|
+
if (options.categoryDetails.resultCategory === "success" && options.executionPlan.commandInfo.command === "connect" && !options.electronLaunchRecord)
|
|
256
|
+
nextActionCollector.appendUnique(buildConnectedSessionNextActions(options.executionPlan.sessionName));
|
|
257
|
+
if (options.noActivePageSnapshotFailure)
|
|
258
|
+
nextActionCollector.appendUnique(buildNoActivePageNextActions(options.executionPlan.sessionName));
|
|
259
|
+
if (options.aboutBlankSessionMismatch) {
|
|
260
|
+
nextActionCollector.appendUnique(buildSessionTabRecoveryNextActions({ kind: "about-blank", recoveryApplied: options.aboutBlankSessionMismatch.recoveryApplied, sessionName: options.executionPlan.sessionName, tabCorrection: options.aboutBlankSessionMismatch.recoveryApplied ? options.sessionTabCorrection : undefined, target: { title: options.aboutBlankSessionMismatch.targetTitle, url: options.aboutBlankSessionMismatch.targetUrl } }));
|
|
261
|
+
if (!options.aboutBlankSessionMismatch.recoveryApplied)
|
|
262
|
+
nextActionCollector.removeWhere(isStandaloneSnapshotNextAction);
|
|
263
|
+
}
|
|
264
|
+
else if (options.categoryDetails.resultCategory === "success" && (options.sessionTabCorrection || options.openResultTabCorrection))
|
|
265
|
+
nextActionCollector.appendUnique(buildSessionTabRecoveryNextActions({ kind: "tab-drift", recoveryApplied: true, sessionName: options.executionPlan.sessionName, tabCorrection: options.sessionTabCorrection ?? options.openResultTabCorrection, target: options.currentSessionTabTarget ?? options.priorSessionTabTarget }));
|
|
266
|
+
if (options.categoryDetails.failureCategory === "stale-ref")
|
|
267
|
+
nextActionCollector.replace(buildSessionAwareStaleRefNextActions(options.executionPlan.sessionName));
|
|
268
|
+
if (options.visibleRefFallbackDiagnostic)
|
|
269
|
+
nextActionCollector.append(buildVisibleRefFallbackNextActions({ diagnostic: options.visibleRefFallbackDiagnostic, sessionName: options.visibleRefFallbackSessionName }));
|
|
270
|
+
if (options.richInputRecoveryDiagnostic)
|
|
271
|
+
nextActionCollector.append(buildRichInputRecoveryNextActions({ diagnostic: options.richInputRecoveryDiagnostic, sessionName: options.visibleRefFallbackSessionName }));
|
|
272
|
+
if (options.electronPostCommandHealth) {
|
|
273
|
+
const electronRecord = options.electronLaunchRecords.get(options.electronPostCommandHealth.launchId);
|
|
274
|
+
if (electronRecord)
|
|
275
|
+
nextActionCollector.appendUnique(buildElectronLifecycleNextActions(electronRecord));
|
|
276
|
+
}
|
|
277
|
+
if (options.electronSessionMismatch) {
|
|
278
|
+
const electronRecord = options.electronLaunchRecords.get(options.electronSessionMismatch.launchId);
|
|
279
|
+
if (electronRecord)
|
|
280
|
+
nextActionCollector.appendUnique(buildElectronMismatchNextActions(electronRecord, options.electronSessionMismatch.liveTarget));
|
|
281
|
+
}
|
|
282
|
+
if (options.categoryDetails.failureCategory === "selector-not-found" && options.redactedCompiledSemanticAction) {
|
|
283
|
+
const candidateActions = buildSemanticActionCandidateActions(options.redactedCompiledSemanticAction);
|
|
284
|
+
if (candidateActions.length > 0)
|
|
285
|
+
nextActionCollector.append(candidateActions);
|
|
286
|
+
}
|
|
287
|
+
if (options.overlayBlockerDiagnostic)
|
|
288
|
+
nextActionCollector.append(buildOverlayBlockerNextActions({ diagnostic: options.overlayBlockerDiagnostic, sessionName: options.executionPlan.sessionName }));
|
|
289
|
+
if (options.fillVerificationDiagnostic)
|
|
290
|
+
nextActionCollector.appendUnique(buildFillVerificationNextActions(options.fillVerificationDiagnostic, options.executionPlan.sessionName));
|
|
291
|
+
if (options.electronRefFreshnessDiagnostic)
|
|
292
|
+
nextActionCollector.appendUnique(buildElectronRefFreshnessNextActions(options.executionPlan.sessionName));
|
|
293
|
+
if (options.selectorTextVisibilityDiagnostics.length > 0)
|
|
294
|
+
nextActionCollector.append(buildSelectorTextVisibilityNextActions({ diagnostics: options.selectorTextVisibilityDiagnostics, sessionName: options.executionPlan.sessionName }));
|
|
295
|
+
if (options.electronBroadGetTextScopeDiagnostics.length > 0)
|
|
296
|
+
nextActionCollector.append(buildElectronBroadGetTextScopeNextActions({ diagnostics: options.electronBroadGetTextScopeDiagnostics, sessionName: options.executionPlan.sessionName }));
|
|
297
|
+
if (options.sourceLookup?.electronContext)
|
|
298
|
+
nextActionCollector.appendUnique(buildSourceLookupElectronNextActions(options.sourceLookup));
|
|
299
|
+
if (options.clickDispatchDiagnostic)
|
|
300
|
+
nextActionCollector.append(buildClickDispatchNextActions({ commandTokens: options.commandTokens, diagnostic: options.clickDispatchDiagnostic, sessionName: options.executionPlan.sessionName }));
|
|
301
|
+
if (options.scrollNoopDiagnostic)
|
|
302
|
+
nextActionCollector.append(buildScrollNoopNextActions(options.executionPlan.sessionName));
|
|
303
|
+
if (options.comboboxFocusDiagnostic)
|
|
304
|
+
nextActionCollector.append(buildComboboxFocusNextActions(options.executionPlan.sessionName));
|
|
305
|
+
if (options.managedSessionOutcome)
|
|
306
|
+
nextActionCollector.appendUnique(buildManagedSessionFreshFailureNextActions(options.managedSessionOutcome));
|
|
307
|
+
if (options.categoryDetails.failureCategory === "timeout" && options.processResult.timedOut) {
|
|
308
|
+
nextActionCollector.appendUnique(buildTimeoutPartialProgressNextActions(options));
|
|
309
|
+
nextActionCollector.appendUnique(buildDialogTimeoutNextActions({ command: options.executionPlan.commandInfo.command, sessionName: options.executionPlan.sessionName }));
|
|
310
|
+
}
|
|
311
|
+
if (options.categoryDetails.failureCategory === "stale-ref" && options.redactedCompiledSemanticAction && isCompiledSemanticActionFindCommand(options.compiledSemanticAction))
|
|
312
|
+
nextActionCollector.append([{ id: "retry-semantic-action-after-stale-ref", params: { args: options.redactedCompiledSemanticAction.args }, reason: "Retry the same semantic target via its compiled find command after the upstream stale-ref failure proves the prior action did not execute.", safety: "Use only for the same intended target; direct stale @refs still require a fresh snapshot or stable locator before retrying.", tool: "agent_browser" }]);
|
|
313
|
+
if (options.electronLaunchRecord)
|
|
314
|
+
nextActionCollector.append(buildAgentBrowserNextActions({ electron: { launchId: options.electronLaunchRecord.launchId, sessionName: options.electronLaunchRecord.sessionName, status: options.electronLaunchRecord.cleanupState }, failureCategory: options.categoryDetails.failureCategory, resultCategory: options.categoryDetails.resultCategory, successCategory: options.categoryDetails.successCategory }));
|
|
315
|
+
return nextActionCollector.toArray();
|
|
316
|
+
}
|
|
317
|
+
function buildAgentBrowserResultDetails(options, nextActions) {
|
|
318
|
+
const publicVisibleRefFallbackDiagnostic = options.visibleRefFallbackDiagnostic ? sanitizeVisibleRefFallbackDiagnostic(options.visibleRefFallbackDiagnostic) : undefined;
|
|
319
|
+
const rawPageChangeSummary = (options.scrollNoopDiagnostic || options.comboboxFocusDiagnostic) && options.presentation.pageChangeSummary ? { ...options.presentation.pageChangeSummary, nextActionIds: nextActions?.map((action) => action.id) } : options.presentation.pageChangeSummary;
|
|
320
|
+
const pageChangeSummary = alignPageChangeSummaryNextActionIds(rawPageChangeSummary, nextActions);
|
|
321
|
+
return {
|
|
322
|
+
args: options.redactedArgs,
|
|
323
|
+
compiledElectron: options.redactedCompiledElectron,
|
|
324
|
+
compiledJob: options.redactedCompiledJob,
|
|
325
|
+
compiledQaPreset: options.redactedCompiledQaPreset,
|
|
326
|
+
compiledSourceLookup: options.redactedCompiledSourceLookup,
|
|
327
|
+
compiledNetworkSourceLookup: options.redactedCompiledNetworkSourceLookup,
|
|
328
|
+
artifactManifest: options.resultArtifactManifest,
|
|
329
|
+
artifactRetentionSummary: options.presentation.artifactRetentionSummary ?? (options.resultArtifactManifest ? formatSessionArtifactRetentionSummary(options.resultArtifactManifest) : undefined),
|
|
330
|
+
artifactCleanup: options.artifactCleanup,
|
|
331
|
+
artifactVerification: options.presentation.artifactVerification,
|
|
332
|
+
artifacts: options.presentation.artifacts,
|
|
333
|
+
batchFailure: options.presentation.batchFailure,
|
|
334
|
+
batchSteps: options.presentation.batchSteps,
|
|
335
|
+
command: options.executionPlan.commandInfo.command,
|
|
336
|
+
compiledSemanticAction: options.redactedCompiledSemanticAction,
|
|
337
|
+
compatibilityWorkaround: options.compatibilityWorkaround,
|
|
338
|
+
subcommand: options.executionPlan.commandInfo.subcommand,
|
|
339
|
+
data: options.presentation.data,
|
|
340
|
+
error: options.plainTextInspection ? undefined : options.presentationEnvelope?.error,
|
|
341
|
+
inspection: options.plainTextInspection || undefined,
|
|
342
|
+
navigationSummary: options.navigationSummary,
|
|
343
|
+
electron: options.electronLaunchRecord ? { action: "launch", cleanup: options.electronFailedConnectCleanup, handoff: options.electronHandoff, identifiers: buildElectronIdentifiers(options.electronLaunchRecord), launch: options.electronLaunchRecord, profileIsolation: options.electronProfileIsolationDetails, status: options.succeeded ? "succeeded" : "failed", targets: options.electronLaunch?.targets, version: options.electronLaunch?.version } : undefined,
|
|
344
|
+
...options.categoryDetails,
|
|
345
|
+
aboutBlankSessionMismatch: options.aboutBlankSessionMismatch,
|
|
346
|
+
electronPostCommandHealth: options.electronPostCommandHealth,
|
|
347
|
+
electronRefFreshness: options.electronRefFreshnessDiagnostic,
|
|
348
|
+
electronSessionMismatch: options.electronSessionMismatch,
|
|
349
|
+
openResultTabCorrection: options.openResultTabCorrection,
|
|
350
|
+
effectiveArgs: options.redactedProcessArgs,
|
|
351
|
+
exitCode: options.processResult.exitCode,
|
|
352
|
+
fullOutputPath: options.parseFailureOutput.fullOutputPath ?? options.presentation.fullOutputPath,
|
|
353
|
+
fullOutputPaths: options.presentation.fullOutputPaths,
|
|
354
|
+
fullOutputUnavailable: options.parseFailureOutput.fullOutputUnavailable,
|
|
355
|
+
managedSessionOutcome: options.managedSessionOutcome,
|
|
356
|
+
imagePath: options.presentation.imagePath,
|
|
357
|
+
imagePaths: options.presentation.imagePaths,
|
|
358
|
+
nextActions,
|
|
359
|
+
pageChangeSummary,
|
|
360
|
+
clickDispatch: options.clickDispatchDiagnostic,
|
|
361
|
+
overlayBlockers: options.overlayBlockerDiagnostic,
|
|
362
|
+
fillVerification: options.fillVerificationDiagnostic,
|
|
363
|
+
visibleRefFallback: publicVisibleRefFallbackDiagnostic,
|
|
364
|
+
richInputRecovery: options.richInputRecoveryDiagnostic,
|
|
365
|
+
comboboxFocus: options.comboboxFocusDiagnostic,
|
|
366
|
+
recordingDependencyWarning: options.recordingDependencyWarning,
|
|
367
|
+
scrollNoop: options.scrollNoopDiagnostic,
|
|
368
|
+
qaPreset: options.qaPreset,
|
|
369
|
+
qaAttachedTarget: options.qaAttachedTarget,
|
|
370
|
+
electronGetTextScopeWarning: options.electronBroadGetTextScopeDiagnostics[0],
|
|
371
|
+
electronGetTextScopeWarnings: options.electronBroadGetTextScopeDiagnostics.length > 1 ? options.electronBroadGetTextScopeDiagnostics : undefined,
|
|
372
|
+
selectorTextVisibility: options.selectorTextVisibilityDiagnostics[0],
|
|
373
|
+
selectorTextVisibilityAll: options.selectorTextVisibilityDiagnostics.length > 1 ? options.selectorTextVisibilityDiagnostics : undefined,
|
|
374
|
+
evalStdinHint: options.evalStdinHint,
|
|
375
|
+
evalResultWarning: options.evalResultWarning,
|
|
376
|
+
timeoutPartialProgress: options.timeoutPartialProgress,
|
|
377
|
+
parseError: options.plainTextInspection ? undefined : options.parseError,
|
|
378
|
+
savedFile: options.presentation.savedFile,
|
|
379
|
+
savedFilePath: options.presentation.savedFilePath,
|
|
380
|
+
sourceLookup: options.sourceLookup,
|
|
381
|
+
networkSourceLookup: options.networkSourceLookup,
|
|
382
|
+
networkRouteDiagnostics: options.presentation.networkRouteDiagnostics,
|
|
383
|
+
sessionMode: options.sessionMode,
|
|
384
|
+
sessionTabCorrection: options.sessionTabCorrection,
|
|
385
|
+
sessionTabTarget: options.currentSessionTabTarget,
|
|
386
|
+
refSnapshot: options.currentRefSnapshot,
|
|
387
|
+
refSnapshotInvalidation: options.currentRefSnapshotInvalidation,
|
|
388
|
+
...buildSessionDetailFields(options.executionPlan.sessionName, options.executionPlan.usedImplicitSession),
|
|
389
|
+
sessionRecoveryHint: options.redactedRecoveryHint,
|
|
390
|
+
startupScopedFlags: options.executionPlan.startupScopedFlags,
|
|
391
|
+
stderr: options.processResult.stderr,
|
|
392
|
+
stdout: options.plainTextInspection ? options.inspectionText ?? "" : options.parseSucceeded ? undefined : options.processResult.stdout,
|
|
393
|
+
summary: options.presentation.summary,
|
|
394
|
+
timedOut: options.processResult.timedOut || undefined,
|
|
395
|
+
timeoutMs: options.processResult.timeoutMs,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
export function buildFinalAgentBrowserToolResult(options) {
|
|
399
|
+
const nextActions = buildResultNextActions(options);
|
|
400
|
+
const details = buildAgentBrowserResultDetails(options, nextActions);
|
|
401
|
+
const visibleRefFallbackText = formatVisibleRefFallbackText(options.visibleRefFallbackDiagnostic);
|
|
402
|
+
const richInputRecoveryText = formatRichInputRecoveryText(options.richInputRecoveryDiagnostic);
|
|
403
|
+
const semanticActionCandidateText = nextActions ? formatSemanticActionCandidateText(nextActions) : undefined;
|
|
404
|
+
const clickDispatchText = options.clickDispatchDiagnostic ? formatClickDispatchDiagnosticText(options.clickDispatchDiagnostic) : undefined;
|
|
405
|
+
const overlayBlockerText = options.overlayBlockerDiagnostic ? formatOverlayBlockerText(options.overlayBlockerDiagnostic) : undefined;
|
|
406
|
+
const fillVerificationText = formatFillVerificationText(options.fillVerificationDiagnostic);
|
|
407
|
+
const electronRefFreshnessText = formatElectronRefFreshnessText(options.electronRefFreshnessDiagnostic);
|
|
408
|
+
const selectorTextVisibilityText = formatSelectorTextVisibilityText(options.selectorTextVisibilityDiagnostics);
|
|
409
|
+
const electronBroadGetTextScopeText = formatElectronBroadGetTextScopeText(options.electronBroadGetTextScopeDiagnostics);
|
|
410
|
+
const scrollNoopDiagnosticText = formatScrollNoopDiagnosticText(options.scrollNoopDiagnostic);
|
|
411
|
+
const comboboxFocusDiagnosticText = formatComboboxFocusDiagnosticText(options.comboboxFocusDiagnostic);
|
|
412
|
+
const recordingDependencyWarningText = formatRecordingDependencyWarningText(options.recordingDependencyWarning);
|
|
413
|
+
const evalStdinHintText = formatEvalStdinHintText(options.evalStdinHint);
|
|
414
|
+
const evalResultWarningText = formatEvalResultWarningText(options.evalResultWarning);
|
|
415
|
+
const artifactCleanupText = formatArtifactCleanupGuidanceText(options.artifactCleanup);
|
|
416
|
+
const timeoutPartialProgressText = options.timeoutPartialProgress ? formatTimeoutPartialProgressText(options.timeoutPartialProgress) : undefined;
|
|
417
|
+
const managedSessionOutcomeText = formatManagedSessionOutcomeText(options.managedSessionOutcome);
|
|
418
|
+
const rawAppendedDiagnosticText = [visibleRefFallbackText, richInputRecoveryText, semanticActionCandidateText, clickDispatchText, overlayBlockerText, fillVerificationText, electronRefFreshnessText, selectorTextVisibilityText, electronBroadGetTextScopeText, scrollNoopDiagnosticText, comboboxFocusDiagnosticText, recordingDependencyWarningText, evalStdinHintText, evalResultWarningText, artifactCleanupText, timeoutPartialProgressText, managedSessionOutcomeText].filter((item) => item !== undefined).join("\n\n");
|
|
419
|
+
const appendedDiagnosticText = redactSensitiveText(redactExactSensitiveText(rawAppendedDiagnosticText, options.exactSensitiveValues));
|
|
420
|
+
const shouldAppendDiagnosticText = appendedDiagnosticText.length > 0 && (!options.userRequestedJson || options.plainTextInspection);
|
|
421
|
+
let content = shouldAppendDiagnosticText && options.redactedContent[0]?.type === "text" ? [{ ...options.redactedContent[0], text: `${options.redactedContent[0].text}\n\n${appendedDiagnosticText}` }, ...options.redactedContent.slice(1)] : options.redactedContent;
|
|
422
|
+
if (options.electronLaunchRecord && options.succeeded && content[0]?.type === "text") {
|
|
423
|
+
content = [{ ...content[0], text: redactSensitiveText(formatElectronLaunchText({ handoff: options.electronHandoff, record: options.electronLaunchRecord, targets: options.electronLaunch?.targets ?? [], upstreamText: content[0].text })) }, ...content.slice(1)];
|
|
424
|
+
}
|
|
425
|
+
const result = { content, details: redactToolDetails(details, options.exactSensitiveValues), isError: !options.succeeded };
|
|
426
|
+
return options.compiledNetworkSourceLookup ? redactNetworkSourceLookupSurface(result) : result;
|
|
427
|
+
}
|
|
428
|
+
export async function buildMissingBinaryFailureResult(options) {
|
|
429
|
+
if (!options.processResult.spawnError?.message.includes("ENOENT"))
|
|
430
|
+
return undefined;
|
|
431
|
+
const errorText = buildMissingBinaryMessage();
|
|
432
|
+
const managedSessionOutcome = buildManagedSessionOutcome({ activeAfter: options.managedSessionActive, activeBefore: options.managedSessionActive, attemptedSessionName: options.executionPlan.managedSessionName, command: options.executionPlan.commandInfo.command, currentSessionName: options.managedSessionName, previousSessionName: options.managedSessionName, sessionMode: options.sessionMode, succeeded: false });
|
|
433
|
+
const managedSessionOutcomeText = formatManagedSessionOutcomeText(managedSessionOutcome);
|
|
434
|
+
const managedSessionRecoveryNextActions = buildManagedSessionFreshFailureNextActions(managedSessionOutcome);
|
|
435
|
+
let missingBinaryElectronCleanup;
|
|
436
|
+
let missingBinaryElectronRecord;
|
|
437
|
+
if (options.electronLaunch) {
|
|
438
|
+
missingBinaryElectronCleanup = await cleanupElectronLaunchResources({ child: options.electronLaunch.child, record: options.electronLaunch.record, timeoutMs: options.implicitSessionCloseTimeoutMs });
|
|
439
|
+
missingBinaryElectronRecord = missingBinaryElectronCleanup.record;
|
|
440
|
+
}
|
|
441
|
+
const textParts = [errorText, managedSessionOutcomeText, missingBinaryElectronCleanup ? `Electron cleanup after failed attach: ${missingBinaryElectronCleanup.summary}` : undefined].filter((part) => part !== undefined && part.length > 0);
|
|
442
|
+
return { content: [{ type: "text", text: textParts.join("\n\n") }], details: { args: options.redactedArgs, compatibilityWorkaround: options.compatibilityWorkaround, effectiveArgs: options.redactedProcessArgs, electron: missingBinaryElectronRecord ? { action: "launch", cleanup: missingBinaryElectronCleanup, launch: missingBinaryElectronRecord, status: "failed", targets: options.electronLaunch?.targets, version: options.electronLaunch?.version } : undefined, managedSessionOutcome, nextActions: managedSessionRecoveryNextActions.length > 0 ? managedSessionRecoveryNextActions : undefined, sessionMode: options.sessionMode, sessionTabCorrection: options.sessionTabCorrection, ...buildAgentBrowserResultCategoryDetails({ args: options.redactedProcessArgs, command: options.executionPlan.commandInfo.command, errorText, failureCategory: "missing-binary", spawnError: options.processResult.spawnError.message, succeeded: false }), spawnError: options.processResult.spawnError.message }, isError: true };
|
|
443
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { runAgentBrowserProcess } from "../../process.js";
|
|
2
|
+
import { cleanupClickDispatchProbe } from "./click-dispatch.js";
|
|
3
|
+
import { applyBrowserRunStatePatch } from "./session-state.js";
|
|
4
|
+
import { buildMissingBinaryFailureResult } from "./final-result.js";
|
|
5
|
+
import { prepareBrowserRun } from "./prepare.js";
|
|
6
|
+
import { processBrowserOutput } from "./process-output.js";
|
|
7
|
+
export { closeManagedSession } from "./session-state.js";
|
|
8
|
+
export async function runAgentBrowserTool(options) {
|
|
9
|
+
const preparedResult = await prepareBrowserRun(options);
|
|
10
|
+
applyBrowserRunStatePatch(options.state, preparedResult.kind === "ready" ? preparedResult.prepared.statePatch : preparedResult.statePatch);
|
|
11
|
+
if (preparedResult.kind === "early-result") {
|
|
12
|
+
return preparedResult.result;
|
|
13
|
+
}
|
|
14
|
+
const { prepared } = preparedResult;
|
|
15
|
+
try {
|
|
16
|
+
const processResult = await runAgentBrowserProcess({
|
|
17
|
+
args: prepared.processArgs,
|
|
18
|
+
cwd: options.cwd,
|
|
19
|
+
env: prepared.executionPlan.managedSessionName ? { AGENT_BROWSER_IDLE_TIMEOUT_MS: options.implicitSessionIdleTimeoutMs } : undefined,
|
|
20
|
+
signal: options.signal,
|
|
21
|
+
stdin: prepared.processStdin,
|
|
22
|
+
timeoutMs: prepared.processTimeoutMs,
|
|
23
|
+
});
|
|
24
|
+
const missingBinaryResult = await buildMissingBinaryFailureResult({
|
|
25
|
+
compatibilityWorkaround: prepared.compatibilityWorkaround,
|
|
26
|
+
electronLaunch: prepared.electronLaunch,
|
|
27
|
+
executionPlan: prepared.executionPlan,
|
|
28
|
+
implicitSessionCloseTimeoutMs: options.implicitSessionCloseTimeoutMs,
|
|
29
|
+
managedSessionActive: options.state.managedSessionActive,
|
|
30
|
+
managedSessionName: options.state.managedSessionName,
|
|
31
|
+
processResult,
|
|
32
|
+
redactedArgs: prepared.redactedArgs,
|
|
33
|
+
redactedProcessArgs: prepared.redactedProcessArgs,
|
|
34
|
+
sessionMode: prepared.sessionMode,
|
|
35
|
+
sessionTabCorrection: prepared.sessionTabCorrection,
|
|
36
|
+
});
|
|
37
|
+
if (missingBinaryResult) {
|
|
38
|
+
return missingBinaryResult;
|
|
39
|
+
}
|
|
40
|
+
const output = await processBrowserOutput({ ...options, prepared, processResult });
|
|
41
|
+
applyBrowserRunStatePatch(options.state, output.statePatch);
|
|
42
|
+
return output.result;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await cleanupClickDispatchProbe({ cwd: options.cwd, probe: prepared.clickDispatchProbe, sessionName: prepared.executionPlan.sessionName });
|
|
46
|
+
}
|
|
47
|
+
}
|