pi-agent-browser-native 0.2.48 → 0.2.50

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 (189) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/README.md +21 -11
  3. package/dist/extensions/agent-browser/index.js +808 -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 +669 -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 +363 -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 +956 -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 +855 -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 +5 -5
  95. package/docs/COMMAND_REFERENCE.md +4 -4
  96. package/docs/RELEASE.md +22 -11
  97. package/docs/REQUIREMENTS.md +1 -1
  98. package/docs/SUPPORT_MATRIX.md +5 -4
  99. package/docs/TOOL_CONTRACT.md +1 -1
  100. package/package.json +9 -5
  101. package/scripts/config.mjs +14 -20
  102. package/scripts/doctor.mjs +8 -7
  103. package/extensions/agent-browser/index.ts +0 -961
  104. package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
  105. package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
  106. package/extensions/agent-browser/lib/bash-guard.ts +0 -205
  107. package/extensions/agent-browser/lib/command-policy.ts +0 -71
  108. package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
  109. package/extensions/agent-browser/lib/config-policy.js +0 -690
  110. package/extensions/agent-browser/lib/config.ts +0 -211
  111. package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
  112. package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
  113. package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
  114. package/extensions/agent-browser/lib/electron/launch.ts +0 -499
  115. package/extensions/agent-browser/lib/executable-path.ts +0 -19
  116. package/extensions/agent-browser/lib/fs-utils.ts +0 -18
  117. package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
  118. package/extensions/agent-browser/lib/input-modes/job.ts +0 -527
  119. package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
  120. package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
  121. package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
  122. package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
  123. package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
  124. package/extensions/agent-browser/lib/input-modes.ts +0 -45
  125. package/extensions/agent-browser/lib/json-schema.ts +0 -73
  126. package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
  127. package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
  128. package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
  129. package/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.ts +0 -44
  130. package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -280
  131. package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -914
  132. package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -521
  133. package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
  134. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.ts +0 -158
  135. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.ts +0 -116
  136. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.ts +0 -147
  137. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.ts +0 -183
  138. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.ts +0 -58
  139. package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -847
  140. package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -559
  141. package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
  142. package/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.ts +0 -8
  143. package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
  144. package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -565
  145. package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
  146. package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
  147. package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
  148. package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -267
  149. package/extensions/agent-browser/lib/playbook.ts +0 -142
  150. package/extensions/agent-browser/lib/process.ts +0 -516
  151. package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
  152. package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
  153. package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
  154. package/extensions/agent-browser/lib/results/categories.ts +0 -106
  155. package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
  156. package/extensions/agent-browser/lib/results/contracts.ts +0 -241
  157. package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
  158. package/extensions/agent-browser/lib/results/envelope.ts +0 -195
  159. package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
  160. package/extensions/agent-browser/lib/results/network.ts +0 -78
  161. package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
  162. package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
  163. package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
  164. package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
  165. package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
  166. package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
  167. package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
  168. package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
  169. package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
  170. package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
  171. package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
  172. package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
  173. package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
  174. package/extensions/agent-browser/lib/results/presentation.ts +0 -257
  175. package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
  176. package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
  177. package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
  178. package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
  179. package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
  180. package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
  181. package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
  182. package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
  183. package/extensions/agent-browser/lib/results/text.ts +0 -40
  184. package/extensions/agent-browser/lib/runtime.ts +0 -988
  185. package/extensions/agent-browser/lib/session-page-state.ts +0 -512
  186. package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
  187. package/extensions/agent-browser/lib/temp.ts +0 -577
  188. package/extensions/agent-browser/lib/web-search.ts +0 -728
  189. /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
@@ -0,0 +1,205 @@
1
+ import { isOpenNavigationCommand } from "../../command-taxonomy.js";
2
+ import { redactSensitiveText } from "../../runtime.js";
3
+ import { buildBrowserProfileConfigRecovery } from "./browser-profile-recovery.js";
4
+ import { redactModelFacingText } from "./common.js";
5
+ import { buildAgentBrowserNextActions } from "../action-recommendations.js";
6
+ import { buildAgentBrowserResultCategoryDetails } from "../categories.js";
7
+ import { withOptionalSessionArgs } from "../next-actions.js";
8
+ const STALE_REF_ERROR_HINT = [
9
+ "Agent-browser hint: This ref may be stale after navigation, scrolling, or re-rendering.",
10
+ "Run `snapshot -i` again and retry with a current `@e…` ref; for less ref churn, use `find role|text|label|placeholder|alt|title|testid ...` or `scrollintoview` before interacting with off-screen elements.",
11
+ ].join(" ");
12
+ const SELECTOR_DIALECT_ERROR_HINT = [
13
+ "Agent-browser hint: This selector may use an unsupported selector dialect.",
14
+ "Prefer refs from `snapshot -i`, or use supported `find role|text|label|placeholder|alt|title|testid ...` locators; use `scrollintoview` before interacting with off-screen elements.",
15
+ ].join(" ");
16
+ const CLIPBOARD_PERMISSION_ERROR_HINT = [
17
+ "Agent-browser clipboard hint: Clipboard read/write access is environment-dependent and often fails in headless, managed, remote-profile, or file:// sessions.",
18
+ "If you see `NotAllowedError` or `permission denied`, treat it as a browser/OS permission limitation rather than proof that page state changed.",
19
+ "When possible, prefer page-native reads (`snapshot -i`, `get text`, `eval --stdin`) or direct input (`keyboard inserttext` / `keyboard type`) instead of relying on OS clipboard access.",
20
+ "If true clipboard access is required, retry in a browser/profile/session with explicit clipboard permission on a normal http(s) page.",
21
+ ].join(" ");
22
+ const KEYBOARD_PRESS_ERROR_HINT = [
23
+ "Agent-browser keyboard hint: upstream keyboard commands are `keyboard type <text>` and `keyboard inserttext <text>`; `keyboard press` is not a supported subcommand in the targeted upstream version.",
24
+ 'For Enter in text fields, use `keyboard type "\\n"` after focusing the intended control, then verify with a fresh snapshot, URL, or page-state check.',
25
+ ].join(" ");
26
+ function isRecord(value) {
27
+ return typeof value === "object" && value !== null;
28
+ }
29
+ function getSelectorRecoveryHint(errorText) {
30
+ const normalized = errorText.trim();
31
+ if (normalized.length === 0)
32
+ return undefined;
33
+ if (/\bUnknown ref\b|\bstale ref\b|\bref\b.*\b(?:not found|missing|expired)\b/i.test(normalized)) {
34
+ return STALE_REF_ERROR_HINT;
35
+ }
36
+ const mentionsPlaywrightSelectorDialect = /(?:\btext=|:has-text\(|\bgetByRole\b|\bgetByText\b)/i.test(normalized);
37
+ const reportsSelectorMatchFailure = /\b(?:no elements? found|failed to find|could not find|unable to find)\b.*\b(?:selector|locator)\b/i.test(normalized) ||
38
+ /\b(?:selector|locator)\b.*\b(?:no elements? found|not found|missing|failed to find|could not find|unable to find)\b/i.test(normalized);
39
+ if (/\b(?:unsupported|unknown|invalid)\s+(?:selector|locator)\b/i.test(normalized) ||
40
+ /\bfailed to parse selector\b/i.test(normalized) ||
41
+ /\bselector\b.*\b(?:parse|syntax|unsupported|invalid)\b/i.test(normalized) ||
42
+ (mentionsPlaywrightSelectorDialect && reportsSelectorMatchFailure)) {
43
+ return SELECTOR_DIALECT_ERROR_HINT;
44
+ }
45
+ return undefined;
46
+ }
47
+ function getClipboardPermissionHint(commandInfo, errorText) {
48
+ if (commandInfo.command !== "clipboard")
49
+ return undefined;
50
+ if (!/\bNotAllowedError\b|\bclipboard\b.*\bpermission denied\b|\bpermission denied\b.*\bclipboard\b/i.test(errorText)) {
51
+ return undefined;
52
+ }
53
+ return CLIPBOARD_PERMISSION_ERROR_HINT;
54
+ }
55
+ function getKeyboardPressHint(commandInfo, errorText) {
56
+ if (commandInfo.command !== "keyboard" || commandInfo.subcommand !== "press")
57
+ return undefined;
58
+ if (!/\bunknown\s+subcommand\b|\bvalid options?\b/i.test(errorText))
59
+ return undefined;
60
+ return KEYBOARD_PRESS_ERROR_HINT;
61
+ }
62
+ export function redactClipboardPermissionEcho(commandInfo, errorText) {
63
+ if (commandInfo.command !== "clipboard")
64
+ return errorText;
65
+ return errorText
66
+ .replace(/(\b(?:read|write)\s+permission denied\b(?:\s+for)?\s+)([\s\S]+)$/gi, "$1[REDACTED]")
67
+ .replace(/(\bFailed to execute '[^']+' on 'Clipboard':\s*)([\s\S]+)$/gi, (match, prefix, suffix) => {
68
+ if (!/\bpermission denied\b/i.test(suffix))
69
+ return match;
70
+ return `${prefix}${suffix.replace(/(\bpermission denied\b(?:\s+for)?\s+)([\s\S]+)$/i, "$1[REDACTED]")}`;
71
+ });
72
+ }
73
+ export function getClipboardWritePayloadCandidates(commandTokens) {
74
+ if (commandTokens[0] !== "clipboard" || commandTokens[1] !== "write")
75
+ return [];
76
+ const payloadTokens = commandTokens.slice(2).filter((value) => value.length > 0);
77
+ return [...new Set([...payloadTokens, payloadTokens.join(" ")].filter((value) => value.length > 0))];
78
+ }
79
+ function shouldRedactClipboardPayloadField(key, value, payloadCandidates) {
80
+ return payloadCandidates.some((candidate) => {
81
+ if (value === candidate)
82
+ return true;
83
+ if (candidate.length < 8 || !/payload|clipboard|argument/i.test(key))
84
+ return false;
85
+ return value.includes(candidate);
86
+ });
87
+ }
88
+ export function redactClipboardPermissionErrorValue(commandInfo, value, payloadCandidates = []) {
89
+ if (commandInfo.command !== "clipboard")
90
+ return value;
91
+ if (typeof value === "string")
92
+ return payloadCandidates.includes(value) ? "[REDACTED]" : redactClipboardPermissionEcho(commandInfo, value);
93
+ if (Array.isArray(value))
94
+ return value.map((item) => redactClipboardPermissionErrorValue(commandInfo, item, payloadCandidates));
95
+ if (!isRecord(value))
96
+ return value;
97
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
98
+ key,
99
+ typeof entryValue === "string" && shouldRedactClipboardPayloadField(key, entryValue, payloadCandidates)
100
+ ? "[REDACTED]"
101
+ : redactClipboardPermissionErrorValue(commandInfo, entryValue, payloadCandidates),
102
+ ]));
103
+ }
104
+ const UNKNOWN_COMMAND_SUGGESTIONS = {
105
+ attr: [{ description: "Use `get attr <selector> <name>` to read an attribute from a selector or current `@ref`." }],
106
+ count: [{ description: "Use `get count <selector>` to count matching elements." }],
107
+ html: [{ description: "Use `get html <selector>` to read element HTML, or `get html` for the page when upstream supports it." }],
108
+ text: [{ description: "Use `get text <selector>` to read text from a selector or current `@ref`; run `snapshot -i` first when you need a safe `@ref`." }],
109
+ title: [{ args: ["get", "title"], description: "Use `get title` to read the current page title.", id: "use-get-title" }],
110
+ url: [{ args: ["get", "url"], description: "Use `get url` to read the current page URL.", id: "use-get-url" }],
111
+ value: [{ description: "Use `get value <selector>` to read form control value from a selector or current `@ref`." }],
112
+ };
113
+ function getUnknownCommandSuggestions(command, errorText) {
114
+ if (!command)
115
+ return [];
116
+ const normalizedCommand = command.trim().toLowerCase();
117
+ if (!/\bunknown\s+command\b|\bunknown\s+subcommand\b|\bunrecognized\s+command\b/i.test(errorText))
118
+ return [];
119
+ return UNKNOWN_COMMAND_SUGGESTIONS[normalizedCommand] ?? [];
120
+ }
121
+ function formatUnknownCommandSuggestionText(suggestions) {
122
+ if (suggestions.length === 0)
123
+ return undefined;
124
+ return ["Agent-browser hint: This looks like a getter shortcut, but upstream getter commands are grouped under `get`.", ...suggestions.map((suggestion) => suggestion.description)].join(" ");
125
+ }
126
+ function buildUnknownCommandSuggestionActions(suggestions, sessionName) {
127
+ const actions = suggestions
128
+ .filter((suggestion) => suggestion.args !== undefined && suggestion.id !== undefined)
129
+ .map((suggestion) => ({
130
+ id: suggestion.id,
131
+ params: { args: withOptionalSessionArgs(sessionName, suggestion.args) },
132
+ reason: suggestion.description,
133
+ safety: "Read-only getter command; safe to retry when you intended to inspect page state.",
134
+ tool: "agent_browser",
135
+ }));
136
+ return actions.length > 0 ? actions : undefined;
137
+ }
138
+ function getLocalhostNavigationHint(commandInfo, errorText) {
139
+ if (!commandInfo.command || !isOpenNavigationCommand(commandInfo.command) || !commandInfo.subcommand)
140
+ return undefined;
141
+ if (!/\bnet::ERR_(?:EMPTY_RESPONSE|CONNECTION_REFUSED|ADDRESS_UNREACHABLE|TIMED_OUT|CONNECTION_RESET)\b/i.test(errorText))
142
+ return undefined;
143
+ let targetUrl;
144
+ try {
145
+ targetUrl = new URL(commandInfo.subcommand);
146
+ }
147
+ catch {
148
+ return undefined;
149
+ }
150
+ if (!["localhost", "127.0.0.1", "::1", "[::1]"].includes(targetUrl.hostname.toLowerCase()))
151
+ return undefined;
152
+ return [
153
+ "Agent-browser local fixture hint: the browser process could not read a loopback URL from its own network namespace or browser host.",
154
+ "Verify the server is still running and bound to an address the browser host can reach; if curl works from the shell but browser navigation fails, try the other loopback alias, add a proxy bypass for localhost/127.0.0.1 if a proxy is configured, or use a browser-host-reachable URL.",
155
+ "Use file:// only for static fallback fixtures and clean up any temporary server process outside agent_browser when the check is done.",
156
+ ].join(" ");
157
+ }
158
+ export function appendSelectorRecoveryHint(errorText) {
159
+ const hint = getSelectorRecoveryHint(errorText);
160
+ if (!hint || errorText.includes("Agent-browser hint:"))
161
+ return errorText;
162
+ return `${errorText}\n\n${hint}`;
163
+ }
164
+ export function buildErrorPresentation(options) {
165
+ const { args, commandInfo, errorText, sessionName } = options;
166
+ const safeErrorText = redactModelFacingText(redactSensitiveText(redactClipboardPermissionEcho(commandInfo, errorText)));
167
+ const selectorHintedErrorText = appendSelectorRecoveryHint(safeErrorText);
168
+ const unknownCommandSuggestions = getUnknownCommandSuggestions(commandInfo.command, safeErrorText);
169
+ const unknownCommandSuggestionText = formatUnknownCommandSuggestionText(unknownCommandSuggestions);
170
+ const browserProfileConfigRecovery = buildBrowserProfileConfigRecovery({ args, commandInfo, errorText: safeErrorText });
171
+ const localhostNavigationHint = getLocalhostNavigationHint(commandInfo, safeErrorText);
172
+ const clipboardPermissionHint = getClipboardPermissionHint(commandInfo, safeErrorText);
173
+ const keyboardPressHint = getKeyboardPressHint(commandInfo, safeErrorText);
174
+ const hintedErrorParts = [
175
+ selectorHintedErrorText,
176
+ unknownCommandSuggestionText && !selectorHintedErrorText.includes("Agent-browser hint:") ? unknownCommandSuggestionText : undefined,
177
+ browserProfileConfigRecovery?.hint,
178
+ localhostNavigationHint,
179
+ clipboardPermissionHint,
180
+ keyboardPressHint,
181
+ ].filter((part) => Boolean(part));
182
+ const hintedErrorText = hintedErrorParts.join("\n\n");
183
+ const categoryDetails = buildAgentBrowserResultCategoryDetails({
184
+ args: [commandInfo.command, commandInfo.subcommand].filter((item) => item !== undefined),
185
+ command: commandInfo.command,
186
+ errorText: hintedErrorText,
187
+ succeeded: false,
188
+ });
189
+ const nextActions = [
190
+ ...(buildUnknownCommandSuggestionActions(unknownCommandSuggestions, sessionName) ?? []),
191
+ ...(browserProfileConfigRecovery?.actions ?? []),
192
+ ...(buildAgentBrowserNextActions({
193
+ args,
194
+ command: commandInfo.command,
195
+ failureCategory: categoryDetails.failureCategory,
196
+ resultCategory: "failure",
197
+ }) ?? []),
198
+ ];
199
+ return {
200
+ ...categoryDetails,
201
+ content: [{ type: "text", text: hintedErrorText }],
202
+ nextActions: nextActions.length > 0 ? nextActions : undefined,
203
+ summary: hintedErrorText,
204
+ };
205
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Purpose: Compact oversized model-facing tool output into bounded previews and spill artifacts.
3
+ * Responsibilities: Write full output to persistent/session temp storage, update artifact manifests, and preserve safe previews.
4
+ * Scope: Large-output compaction only.
5
+ */
6
+ import { writePersistentSessionArtifactFile, writeSecureTempFile, } from "../../temp.js";
7
+ import { buildEvictedSessionArtifactEntries } from "../artifact-manifest.js";
8
+ import { countLines, truncateText } from "../text.js";
9
+ import { applyArtifactManifest } from "./artifacts.js";
10
+ import { getPresentationText } from "./content.js";
11
+ import { redactModelFacingText, stringifyModelFacing } from "./common.js";
12
+ const LARGE_OUTPUT_INLINE_MAX_CHARS = 8_000;
13
+ const LARGE_OUTPUT_INLINE_MAX_LINES = 120;
14
+ const LARGE_OUTPUT_PREVIEW_MAX_CHARS = 2_500;
15
+ const LARGE_OUTPUT_PREVIEW_MAX_LINES = 40;
16
+ const LARGE_OUTPUT_FILE_PREFIX = "pi-agent-browser-output";
17
+ function shouldCompactLargeOutput(text) {
18
+ return text.length > LARGE_OUTPUT_INLINE_MAX_CHARS || countLines(text) > LARGE_OUTPUT_INLINE_MAX_LINES;
19
+ }
20
+ function buildLargeOutputPreview(text) {
21
+ const lines = text.split("\n");
22
+ const previewLines = [];
23
+ let previewChars = 0;
24
+ for (const line of lines) {
25
+ if (previewLines.length >= LARGE_OUTPUT_PREVIEW_MAX_LINES || previewChars >= LARGE_OUTPUT_PREVIEW_MAX_CHARS) {
26
+ break;
27
+ }
28
+ const remainingChars = LARGE_OUTPUT_PREVIEW_MAX_CHARS - previewChars;
29
+ const previewLine = truncateText(line, Math.max(40, remainingChars));
30
+ previewLines.push(previewLine);
31
+ previewChars += previewLine.length + 1;
32
+ }
33
+ return {
34
+ omittedLineCount: Math.max(0, lines.length - previewLines.length),
35
+ previewText: previewLines.join("\n"),
36
+ };
37
+ }
38
+ async function writeLargeOutputSpillFile(options) {
39
+ const payload = typeof options.data === "string"
40
+ ? redactModelFacingText(options.data)
41
+ : typeof options.data === "number" || typeof options.data === "boolean"
42
+ ? String(options.data)
43
+ : options.data === undefined
44
+ ? redactModelFacingText(options.text)
45
+ : stringifyModelFacing(options.data);
46
+ const isStructuredPayload = typeof options.data !== "string" && typeof options.data !== "number" && typeof options.data !== "boolean";
47
+ const fileOptions = {
48
+ content: payload,
49
+ prefix: LARGE_OUTPUT_FILE_PREFIX,
50
+ suffix: isStructuredPayload ? ".json" : ".txt",
51
+ };
52
+ if (options.persistentArtifactStore) {
53
+ const result = await writePersistentSessionArtifactFile({ ...fileOptions, store: options.persistentArtifactStore });
54
+ return { ...result, storageScope: "persistent-session" };
55
+ }
56
+ return { evictedArtifacts: [], path: await writeSecureTempFile(fileOptions), storageScope: "process-temp" };
57
+ }
58
+ function buildSpillArtifactEntries(options) {
59
+ const nowMs = Date.now();
60
+ return [
61
+ {
62
+ command: options.commandInfo.command,
63
+ createdAtMs: nowMs,
64
+ kind: "spill",
65
+ path: options.path,
66
+ retentionState: options.storageScope === "persistent-session" ? "live" : "ephemeral",
67
+ storageScope: options.storageScope,
68
+ subcommand: options.commandInfo.subcommand,
69
+ },
70
+ ...buildEvictedSessionArtifactEntries(options.evictedArtifacts, nowMs),
71
+ ];
72
+ }
73
+ export async function compactLargePresentationOutput(options) {
74
+ const text = getPresentationText(options.presentation);
75
+ if (text.length === 0 || !shouldCompactLargeOutput(text)) {
76
+ return options.presentation;
77
+ }
78
+ let fullOutputPath;
79
+ let spill;
80
+ let spillErrorText;
81
+ try {
82
+ spill = await writeLargeOutputSpillFile({
83
+ data: options.data,
84
+ persistentArtifactStore: options.persistentArtifactStore,
85
+ text,
86
+ });
87
+ fullOutputPath = spill.path;
88
+ }
89
+ catch (error) {
90
+ spillErrorText = error instanceof Error ? error.message : String(error);
91
+ }
92
+ const { omittedLineCount, previewText } = buildLargeOutputPreview(text);
93
+ const commandLabel = options.commandInfo.command ?? "agent-browser";
94
+ const lines = [
95
+ `Large ${commandLabel} output compacted.`,
96
+ "",
97
+ "Preview:",
98
+ previewText,
99
+ ];
100
+ if (omittedLineCount > 0) {
101
+ lines.push(`- ... (${omittedLineCount} additional lines omitted)`);
102
+ }
103
+ lines.push("", fullOutputPath
104
+ ? `Full output path: ${fullOutputPath}`
105
+ : `Full output unavailable: ${spillErrorText ?? "spill file could not be created."}`);
106
+ const firstTextIndex = options.presentation.content.findIndex((part) => part.type === "text");
107
+ const compactedText = lines.join("\n");
108
+ if (firstTextIndex >= 0) {
109
+ options.presentation.content[firstTextIndex] = { type: "text", text: compactedText };
110
+ }
111
+ else {
112
+ options.presentation.content.unshift({ type: "text", text: compactedText });
113
+ }
114
+ options.presentation.data = {
115
+ compacted: true,
116
+ fullOutputPath,
117
+ outputCharCount: text.length,
118
+ outputLineCount: countLines(text),
119
+ previewCharCount: previewText.length,
120
+ previewLineCount: countLines(previewText),
121
+ spillError: spillErrorText,
122
+ };
123
+ options.presentation.fullOutputPath = fullOutputPath;
124
+ options.presentation.summary = `${options.presentation.summary} (compact)`;
125
+ if (fullOutputPath && spill) {
126
+ return applyArtifactManifest(options.presentation, options.presentation.artifactManifest ?? options.artifactManifest, buildSpillArtifactEntries({
127
+ commandInfo: options.commandInfo,
128
+ evictedArtifacts: spill.evictedArtifacts,
129
+ path: fullOutputPath,
130
+ storageScope: spill.storageScope,
131
+ }));
132
+ }
133
+ return options.presentation;
134
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Purpose: Format scalar extraction results, navigation summaries, and page-change summaries.
3
+ * Responsibilities: Keep navigation/extraction presentation separate from core tool result orchestration.
4
+ * Scope: Navigation and get/eval extraction formatting only.
5
+ */
6
+ import { isNavigationObservableCommandName, isPageChangeSummaryCommand } from "../../command-taxonomy.js";
7
+ import { isRecord } from "../../parsing.js";
8
+ import { detectConfirmationRequired } from "../confirmation.js";
9
+ import { redactModelFacingText, stringifyModelFacing } from "./common.js";
10
+ const NAVIGATION_SUMMARY_FIELD = "navigationSummary";
11
+ function getScalarExtractionResult(data) {
12
+ const { result } = data;
13
+ if (typeof result === "string") {
14
+ return result.trim().length > 0 ? result : undefined;
15
+ }
16
+ if (typeof result === "number" || typeof result === "boolean") {
17
+ return String(result);
18
+ }
19
+ return undefined;
20
+ }
21
+ function getExtractionOrigin(data) {
22
+ if (typeof data.origin === "string" && data.origin.trim().length > 0) {
23
+ return data.origin.trim();
24
+ }
25
+ if (typeof data.url === "string" && data.url.trim().length > 0) {
26
+ return data.url.trim();
27
+ }
28
+ return undefined;
29
+ }
30
+ function formatGetSummaryLabel(subcommand) {
31
+ if (!subcommand) {
32
+ return "Get result";
33
+ }
34
+ if (subcommand.toLowerCase() === "url") {
35
+ return "URL";
36
+ }
37
+ return `${subcommand.slice(0, 1).toUpperCase()}${subcommand.slice(1)}`;
38
+ }
39
+ export function formatExtractionSummary(commandInfo, data) {
40
+ const scalarResult = getScalarExtractionResult(data);
41
+ if (!scalarResult) {
42
+ return undefined;
43
+ }
44
+ const safeScalarResult = redactModelFacingText(scalarResult);
45
+ const firstResultLine = safeScalarResult.split("\n", 1)[0] ?? safeScalarResult;
46
+ if (commandInfo.command === "get") {
47
+ return `${formatGetSummaryLabel(commandInfo.subcommand)}: ${firstResultLine}`;
48
+ }
49
+ if (commandInfo.command === "eval") {
50
+ return `Eval result: ${firstResultLine}`;
51
+ }
52
+ return undefined;
53
+ }
54
+ export function formatExtractionText(commandInfo, data) {
55
+ if (commandInfo.command !== "get" && commandInfo.command !== "eval") {
56
+ return undefined;
57
+ }
58
+ const scalarResult = getScalarExtractionResult(data);
59
+ if (!scalarResult) {
60
+ return undefined;
61
+ }
62
+ const origin = getExtractionOrigin(data);
63
+ const safeScalarResult = redactModelFacingText(scalarResult);
64
+ const safeOrigin = origin ? redactModelFacingText(origin) : undefined;
65
+ return safeOrigin && safeOrigin !== safeScalarResult ? `${safeScalarResult}\n\nOrigin: ${safeOrigin}` : safeScalarResult;
66
+ }
67
+ export function isNavigationObservableCommand(command) {
68
+ return isNavigationObservableCommandName(command);
69
+ }
70
+ function isNavigationSummary(value) {
71
+ return isRecord(value) && (typeof value.title === "string" || typeof value.url === "string");
72
+ }
73
+ export function getNavigationSummary(data) {
74
+ const candidate = data[NAVIGATION_SUMMARY_FIELD];
75
+ return isNavigationSummary(candidate) ? candidate : undefined;
76
+ }
77
+ function getTopLevelNavigationSummary(data) {
78
+ return isNavigationSummary(data)
79
+ ? {
80
+ title: typeof data.title === "string" ? data.title : undefined,
81
+ url: typeof data.url === "string" ? data.url : undefined,
82
+ }
83
+ : undefined;
84
+ }
85
+ function getNormalizedNavigationSummary(summary) {
86
+ const title = typeof summary?.title === "string" && summary.title.trim().length > 0 ? summary.title.trim() : undefined;
87
+ const url = typeof summary?.url === "string" && summary.url.trim().length > 0 ? summary.url.trim() : undefined;
88
+ return title || url ? { title, url } : undefined;
89
+ }
90
+ export function formatNavigationSummary(summary) {
91
+ const normalized = getNormalizedNavigationSummary(summary);
92
+ if (!normalized)
93
+ return undefined;
94
+ if (normalized.title && normalized.url)
95
+ return `${normalized.title}\n${normalized.url}`;
96
+ return normalized.title ?? normalized.url;
97
+ }
98
+ export function buildPageChangeSummary(options) {
99
+ const { artifacts, commandInfo, data, nextActions, savedFilePath } = options;
100
+ const artifactCount = artifacts?.length ?? 0;
101
+ const navigation = isRecord(data)
102
+ ? getNormalizedNavigationSummary(getNavigationSummary(data) ?? (isPageChangeSummaryCommand(commandInfo.command) ? getTopLevelNavigationSummary(data) : undefined))
103
+ : undefined;
104
+ const confirmationRequired = detectConfirmationRequired(data) !== undefined;
105
+ if (!navigation && !confirmationRequired && artifactCount === 0 && !savedFilePath && !isPageChangeSummaryCommand(commandInfo.command)) {
106
+ return undefined;
107
+ }
108
+ const changeType = savedFilePath || artifactCount > 0
109
+ ? "artifact"
110
+ : navigation
111
+ ? "navigation"
112
+ : confirmationRequired
113
+ ? "confirmation"
114
+ : "mutation";
115
+ const parts = [commandInfo.command ?? "agent-browser", changeType];
116
+ if (navigation?.title)
117
+ parts.push(navigation.title);
118
+ if (navigation?.url)
119
+ parts.push(navigation.url);
120
+ if (savedFilePath)
121
+ parts.push(savedFilePath);
122
+ else if (artifactCount > 0)
123
+ parts.push(`${artifactCount} artifact${artifactCount === 1 ? "" : "s"}`);
124
+ return {
125
+ ...(artifactCount > 0 ? { artifactCount } : {}),
126
+ changeType,
127
+ ...(commandInfo.command ? { command: commandInfo.command } : {}),
128
+ ...(nextActions ? { nextActionIds: nextActions.map((action) => action.id) } : {}),
129
+ ...(savedFilePath ? { savedFilePath } : {}),
130
+ summary: parts.join(" → "),
131
+ ...(navigation?.title ? { title: navigation.title } : {}),
132
+ ...(navigation?.url ? { url: navigation.url } : {}),
133
+ };
134
+ }
135
+ function stripNavigationSummary(data) {
136
+ const { [NAVIGATION_SUMMARY_FIELD]: _navigationSummary, ...rest } = data;
137
+ return rest;
138
+ }
139
+ export function formatNavigationActionResult(data) {
140
+ const actionData = stripNavigationSummary(data);
141
+ const lines = [];
142
+ if (typeof actionData.clicked === "string" || typeof actionData.clicked === "boolean") {
143
+ lines.push(`Clicked: ${String(actionData.clicked)}`);
144
+ }
145
+ if (typeof actionData.href === "string") {
146
+ lines.push(`Href: ${redactModelFacingText(actionData.href)}`);
147
+ }
148
+ if (typeof actionData.navigated === "boolean") {
149
+ lines.push(`Navigated: ${actionData.navigated}`);
150
+ }
151
+ if (lines.length > 0) {
152
+ return lines.join("\n");
153
+ }
154
+ const actionText = stringifyModelFacing(actionData).trim();
155
+ if (actionText.length === 0 || actionText === "{}") {
156
+ return undefined;
157
+ }
158
+ return actionText;
159
+ }