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