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,216 @@
1
+ import { isRecord } from "../../parsing.js";
2
+ import { detectConfirmationRequired } from "../confirmation.js";
3
+ import { formatRawSnapshotText, formatSnapshotSummary } from "../snapshot.js";
4
+ import { redactModelFacingText, stringifyModelFacing } from "./common.js";
5
+ import { formatDiagnosticSummary, formatDiagnosticText, formatProfilesText, getStreamSummary, getTabSummary } from "./diagnostics.js";
6
+ import { getScreenshotSummary } from "./artifacts.js";
7
+ import { formatSkillsText } from "./skills.js";
8
+ import { formatExtractionSummary, formatExtractionText, formatNavigationActionResult, formatNavigationSummary, getNavigationSummary, isNavigationObservableCommand, } from "./navigation.js";
9
+ import { formatSemanticActionPresentationSummary, formatSemanticActionPresentationText, resolvePresentationCommandInfo, } from "./semantic-action.js";
10
+ function getPageSummary(data) {
11
+ const title = typeof data.title === "string" ? data.title : undefined;
12
+ const url = typeof data.url === "string" ? data.url : undefined;
13
+ if (!title && !url)
14
+ return undefined;
15
+ if (title && url)
16
+ return `${title}\n${url}`;
17
+ return title ?? url;
18
+ }
19
+ function formatConfirmationRequiredSummary(confirmation) {
20
+ return `Confirmation required: ${confirmation.id}`;
21
+ }
22
+ const VITALS_METRICS = ["lcp", "fcp", "ttfb", "inp", "cls"];
23
+ function coerceVitalsMetricValue(value) {
24
+ if (typeof value === "number" && Number.isFinite(value))
25
+ return value;
26
+ if (isRecord(value)) {
27
+ for (const nestedKey of ["value", "duration", "startTime", "score"]) {
28
+ const nestedValue = value[nestedKey];
29
+ if (typeof nestedValue === "number" && Number.isFinite(nestedValue))
30
+ return nestedValue;
31
+ }
32
+ }
33
+ return undefined;
34
+ }
35
+ function getVitalsMetric(data, key) {
36
+ const metrics = isRecord(data.metrics) ? data.metrics : undefined;
37
+ return coerceVitalsMetricValue(data[key] ?? data[key.toUpperCase()] ?? metrics?.[key] ?? metrics?.[key.toUpperCase()]);
38
+ }
39
+ function formatVitalsMetric(key, value) {
40
+ return key === "cls" ? `${key.toUpperCase()}: ${value}` : `${key.toUpperCase()}: ${Math.round(value)}ms`;
41
+ }
42
+ function getVitalsMetrics(data) {
43
+ return VITALS_METRICS.flatMap((key) => {
44
+ const value = getVitalsMetric(data, key);
45
+ return value === undefined ? [] : [formatVitalsMetric(key, value)];
46
+ });
47
+ }
48
+ function getVitalsUnavailableReason(data) {
49
+ for (const key of ["reason", "message", "error", "status"]) {
50
+ const value = data[key];
51
+ if (typeof value === "string" && value.trim().length > 0)
52
+ return redactModelFacingText(value.trim());
53
+ }
54
+ return "No Core Web Vitals metric fields were present in the upstream result.";
55
+ }
56
+ function formatVitalsText(data) {
57
+ const url = typeof data.url === "string" && data.url.trim().length > 0 ? redactModelFacingText(data.url.trim()) : undefined;
58
+ const metrics = getVitalsMetrics(data);
59
+ const lines = [url ? `Vitals for ${url}` : "Vitals result"];
60
+ if (metrics.length > 0)
61
+ lines.push(...metrics.map((metric) => `- ${metric}`));
62
+ else
63
+ lines.push(`Metrics unavailable: ${getVitalsUnavailableReason(data)}`);
64
+ return lines.join("\n");
65
+ }
66
+ function formatVitalsSummary(data) {
67
+ const metrics = getVitalsMetrics(data);
68
+ if (metrics.length > 0)
69
+ return `Vitals: ${metrics.join(", ")}`;
70
+ return "Vitals: metrics unavailable";
71
+ }
72
+ function formatConfirmationRequiredText(confirmation) {
73
+ const lines = [
74
+ "Confirmation required.",
75
+ `Pending confirmation id: ${confirmation.id}`,
76
+ ];
77
+ if (confirmation.actionText)
78
+ lines.push(`Action: ${confirmation.actionText}`);
79
+ lines.push("", "Next steps:", `- Approve: { "args": ["confirm", "${confirmation.id}"] }`, `- Deny: { "args": ["deny", "${confirmation.id}"] }`);
80
+ return lines.join("\n");
81
+ }
82
+ const COMMAND_PRESENTERS = {
83
+ profiles: {
84
+ summary: (_commandInfo, data) => Array.isArray(data) ? `Chrome profiles: ${data.length}` : undefined,
85
+ text: (_commandInfo, data) => Array.isArray(data) ? formatProfilesText(data, "Chrome profiles") : undefined,
86
+ },
87
+ screenshot: {
88
+ summary: (_commandInfo, data) => isRecord(data) && typeof data.path === "string" ? `Screenshot saved: ${data.path}` : undefined,
89
+ text: (_commandInfo, data) => isRecord(data) ? getScreenshotSummary(data) : undefined,
90
+ },
91
+ skills: {
92
+ summary: (commandInfo, data) => {
93
+ if (Array.isArray(data) && commandInfo.subcommand === "list")
94
+ return `agent-browser skills: ${data.length}`;
95
+ if (commandInfo.subcommand === "get")
96
+ return "agent-browser skill loaded";
97
+ if (commandInfo.subcommand === "path")
98
+ return "agent-browser skill path";
99
+ return undefined;
100
+ },
101
+ text: formatSkillsText,
102
+ },
103
+ snapshot: {
104
+ summary: (_commandInfo, data) => isRecord(data) ? formatSnapshotSummary(data) : undefined,
105
+ text: (_commandInfo, data) => isRecord(data) ? formatRawSnapshotText(data) : undefined,
106
+ },
107
+ stream: {
108
+ summary: (commandInfo, data) => {
109
+ if (!isRecord(data) || commandInfo.subcommand !== "status")
110
+ return undefined;
111
+ const port = typeof data.port === "number" ? ` on port ${data.port}` : "";
112
+ return `Stream ${data.enabled === true ? "enabled" : "disabled"}${port}`;
113
+ },
114
+ text: (commandInfo, data) => isRecord(data) && commandInfo.subcommand === "status" ? getStreamSummary(data) : undefined,
115
+ },
116
+ tab: {
117
+ summary: (_commandInfo, data) => isRecord(data) && Array.isArray(data.tabs) ? `Tabs: ${data.tabs.length}` : undefined,
118
+ text: (_commandInfo, data) => isRecord(data) ? getTabSummary(data) : undefined,
119
+ },
120
+ vitals: {
121
+ summary: (_commandInfo, data) => isRecord(data) ? formatVitalsSummary(data) : undefined,
122
+ text: (_commandInfo, data) => isRecord(data) ? formatVitalsText(data) : undefined,
123
+ },
124
+ "web-vitals": {
125
+ summary: (_commandInfo, data) => isRecord(data) ? formatVitalsSummary(data) : undefined,
126
+ text: (_commandInfo, data) => isRecord(data) ? formatVitalsText(data) : undefined,
127
+ },
128
+ };
129
+ function formatBatchSummary(data) {
130
+ if (!Array.isArray(data))
131
+ return undefined;
132
+ const successCount = data.filter((item) => isRecord(item) && item.success !== false).length;
133
+ return successCount === data.length
134
+ ? `Batch: ${successCount}/${data.length} succeeded`
135
+ : `Batch failed: ${successCount}/${data.length} succeeded`;
136
+ }
137
+ export function formatPresentationSummary(commandInfo, data, compiledSemanticAction) {
138
+ const confirmationRequired = detectConfirmationRequired(data);
139
+ if (confirmationRequired)
140
+ return formatConfirmationRequiredSummary(confirmationRequired);
141
+ const presentationCommandInfo = resolvePresentationCommandInfo(commandInfo, compiledSemanticAction);
142
+ if (commandInfo.command === "batch") {
143
+ const batchSummary = formatBatchSummary(data);
144
+ if (batchSummary)
145
+ return batchSummary;
146
+ }
147
+ if (isRecord(data)) {
148
+ if (compiledSemanticAction) {
149
+ const semanticSummary = formatSemanticActionPresentationSummary(compiledSemanticAction, data);
150
+ if (semanticSummary)
151
+ return semanticSummary;
152
+ }
153
+ const navigationSummary = getNavigationSummary(data);
154
+ if (navigationSummary && isNavigationObservableCommand(presentationCommandInfo.command)) {
155
+ const navigationText = formatNavigationSummary(navigationSummary);
156
+ if (navigationText) {
157
+ return `${presentationCommandInfo.command ?? "navigation"} → ${navigationText.split("\n", 1)[0] ?? navigationText}`;
158
+ }
159
+ }
160
+ }
161
+ const presenterSummary = commandInfo.command ? COMMAND_PRESENTERS[commandInfo.command]?.summary?.(commandInfo, data) : undefined;
162
+ if (presenterSummary)
163
+ return presenterSummary;
164
+ if (isRecord(data)) {
165
+ const diagnosticSummary = formatDiagnosticSummary(commandInfo, data);
166
+ if (diagnosticSummary)
167
+ return diagnosticSummary;
168
+ const extractionSummary = formatExtractionSummary(commandInfo, data);
169
+ if (extractionSummary)
170
+ return extractionSummary;
171
+ const pageSummary = getPageSummary(data);
172
+ if (pageSummary)
173
+ return pageSummary.split("\n", 1)[0] ?? "agent-browser result";
174
+ }
175
+ if (typeof data === "string" && data.length > 0)
176
+ return data.split("\n", 1)[0] ?? data;
177
+ return `${presentationCommandInfo.command ?? commandInfo.command ?? "agent-browser"} completed`;
178
+ }
179
+ export function formatPresentationContentText(commandInfo, data, compiledSemanticAction) {
180
+ const confirmationRequired = detectConfirmationRequired(data);
181
+ if (confirmationRequired)
182
+ return formatConfirmationRequiredText(confirmationRequired);
183
+ const presenterText = commandInfo.command ? COMMAND_PRESENTERS[commandInfo.command]?.text?.(commandInfo, data) : undefined;
184
+ if (presenterText)
185
+ return presenterText;
186
+ if (typeof data === "string")
187
+ return redactModelFacingText(data);
188
+ if (typeof data === "number" || typeof data === "boolean")
189
+ return String(data);
190
+ if (!isRecord(data))
191
+ return stringifyModelFacing(data);
192
+ if (compiledSemanticAction) {
193
+ const semanticText = formatSemanticActionPresentationText(compiledSemanticAction, data);
194
+ if (semanticText)
195
+ return semanticText;
196
+ }
197
+ const presentationCommandInfo = resolvePresentationCommandInfo(commandInfo, compiledSemanticAction);
198
+ const navigationSummary = getNavigationSummary(data);
199
+ if (navigationSummary && isNavigationObservableCommand(presentationCommandInfo.command)) {
200
+ const navigationText = formatNavigationSummary(navigationSummary);
201
+ if (navigationText) {
202
+ const actionText = formatNavigationActionResult(data);
203
+ return actionText ? `${actionText}\n\nCurrent page:\n${navigationText}` : `Current page:\n${navigationText}`;
204
+ }
205
+ }
206
+ const extractionText = formatExtractionText(commandInfo, data);
207
+ if (extractionText)
208
+ return extractionText;
209
+ const diagnosticText = formatDiagnosticText(commandInfo, data);
210
+ if (diagnosticText)
211
+ return diagnosticText;
212
+ const pageSummary = getPageSummary(data);
213
+ if (pageSummary)
214
+ return redactModelFacingText(pageSummary);
215
+ return stringifyModelFacing(data);
216
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Purpose: Map successful semanticAction results to the same presentation signals as direct ref commands.
3
+ * Responsibilities: Resolve presentation command names, compact action prose, and navigation-summary probe gates.
4
+ * Scope: semanticAction success presentation only.
5
+ */
6
+ import { getCompiledSemanticActionCommandIndex, isCompiledSemanticActionFindCommand, } from "../../input-modes/semantic-action.js";
7
+ import { isRecord } from "../../parsing.js";
8
+ import { formatNavigationSummary, getNavigationSummary, isNavigationObservableCommand, } from "./navigation.js";
9
+ import { redactModelFacingText } from "./common.js";
10
+ const SEMANTIC_NAVIGATION_PROBE_ACTIONS = new Set(["check", "click"]);
11
+ const SEMANTIC_PRESENTATION_ACTIONS = new Set(["check", "click", "fill", "select"]);
12
+ function getPageSummary(data) {
13
+ const title = typeof data.title === "string" ? data.title : undefined;
14
+ const url = typeof data.url === "string" ? data.url : undefined;
15
+ if (!title && !url)
16
+ return undefined;
17
+ if (title && url)
18
+ return `${title}\n${url}`;
19
+ return title ?? url;
20
+ }
21
+ function formatSemanticActionTarget(compiled) {
22
+ if (compiled.action === "select") {
23
+ const selector = compiled.selector ?? "selector";
24
+ const values = compiled.values?.length ? compiled.values.join(", ") : "";
25
+ return values ? `${selector} → ${values}` : selector;
26
+ }
27
+ const commandIndex = getCompiledSemanticActionCommandIndex(compiled);
28
+ const locator = compiled.locator ?? compiled.args[commandIndex + 1] ?? "locator";
29
+ const locatorValue = compiled.args[commandIndex + 2];
30
+ const nameIndex = compiled.args.indexOf("--name");
31
+ const name = nameIndex >= 0 ? compiled.args[nameIndex + 1] : undefined;
32
+ const quotedValue = JSON.stringify(locatorValue ?? "");
33
+ const target = `${locator} ${quotedValue}`;
34
+ return name ? `${target} (name ${JSON.stringify(name)})` : target;
35
+ }
36
+ export function formatSemanticActionCompactLine(compiled) {
37
+ const target = formatSemanticActionTarget(compiled);
38
+ switch (compiled.action) {
39
+ case "click":
40
+ return `Clicked: ${target}`;
41
+ case "fill":
42
+ return `Filled: ${target}`;
43
+ case "check":
44
+ return `Checked: ${target}`;
45
+ case "select":
46
+ return `Selected: ${target}`;
47
+ default:
48
+ return `${compiled.action}: ${target}`;
49
+ }
50
+ }
51
+ export function resolveSemanticPresentationCommand(compiled) {
52
+ if (!compiled || !SEMANTIC_PRESENTATION_ACTIONS.has(compiled.action))
53
+ return undefined;
54
+ if (compiled.action === "select")
55
+ return "select";
56
+ if (isCompiledSemanticActionFindCommand(compiled))
57
+ return compiled.action;
58
+ return undefined;
59
+ }
60
+ export function resolvePresentationCommandInfo(commandInfo, compiledSemanticAction) {
61
+ const presentationCommand = resolveSemanticPresentationCommand(compiledSemanticAction);
62
+ if (!presentationCommand)
63
+ return commandInfo;
64
+ return { ...commandInfo, command: presentationCommand };
65
+ }
66
+ export function shouldCaptureSemanticActionNavigationSummary(compiled, data) {
67
+ if (!compiled || !SEMANTIC_NAVIGATION_PROBE_ACTIONS.has(compiled.action))
68
+ return false;
69
+ if (!isCompiledSemanticActionFindCommand(compiled))
70
+ return false;
71
+ return !isRecord(data) || (typeof data.title !== "string" && typeof data.url !== "string");
72
+ }
73
+ export function formatSemanticActionPresentationText(compiled, data) {
74
+ const presentationCommand = resolveSemanticPresentationCommand(compiled);
75
+ if (!presentationCommand)
76
+ return undefined;
77
+ const actionLine = formatSemanticActionCompactLine(compiled);
78
+ const navigationSummary = getNavigationSummary(data);
79
+ if (navigationSummary && isNavigationObservableCommand(presentationCommand)) {
80
+ const navigationText = formatNavigationSummary(navigationSummary);
81
+ if (navigationText)
82
+ return `${actionLine}\n\nCurrent page:\n${navigationText}`;
83
+ }
84
+ const pageSummary = getPageSummary(data);
85
+ if (pageSummary)
86
+ return `${actionLine}\n\nCurrent page:\n${redactModelFacingText(pageSummary)}`;
87
+ return actionLine;
88
+ }
89
+ export function formatSemanticActionPresentationSummary(compiled, data) {
90
+ const presentationCommand = resolveSemanticPresentationCommand(compiled);
91
+ if (!presentationCommand)
92
+ return undefined;
93
+ const navigationSummary = getNavigationSummary(data);
94
+ if (navigationSummary && isNavigationObservableCommand(presentationCommand)) {
95
+ const navigationText = formatNavigationSummary(navigationSummary);
96
+ if (navigationText) {
97
+ return `${presentationCommand} → ${navigationText.split("\n", 1)[0] ?? navigationText}`;
98
+ }
99
+ }
100
+ const pageSummary = getPageSummary(data);
101
+ if (pageSummary)
102
+ return `${presentationCommand} → ${pageSummary.split("\n", 1)[0] ?? pageSummary}`;
103
+ return `${presentationCommand} → ${formatSemanticActionTarget(compiled)}`;
104
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Purpose: Render upstream agent-browser skills output as native pi tool guidance.
3
+ * Responsibilities: Format skills list/path/get results and translate agent-browser shell snippets to agent_browser tool calls.
4
+ * Scope: Skills command presentation only.
5
+ */
6
+ import { isRecord } from "../../parsing.js";
7
+ import { getStringField, redactModelFacingText, stringifyModelFacing } from "./common.js";
8
+ function formatSkillsListText(skills) {
9
+ if (skills.length === 0)
10
+ return "No agent-browser skills found.";
11
+ return skills
12
+ .map((item, index) => {
13
+ if (!isRecord(item))
14
+ return `${index + 1}. ${stringifyModelFacing(item)}`;
15
+ const name = redactModelFacingText(getStringField(item, "name") ?? `(skill ${index + 1})`);
16
+ const description = getStringField(item, "description");
17
+ return description ? `${index + 1}. ${name} — ${redactModelFacingText(description)}` : `${index + 1}. ${name}`;
18
+ })
19
+ .join("\n");
20
+ }
21
+ function getSkillContent(data) {
22
+ if (typeof data === "string")
23
+ return data;
24
+ if (isRecord(data) && typeof data.content === "string")
25
+ return data.content;
26
+ if (!Array.isArray(data))
27
+ return undefined;
28
+ const content = data.flatMap((item) => (isRecord(item) && typeof item.content === "string" ? [item.content] : []));
29
+ return content.length > 0 ? content.join("\n\n") : undefined;
30
+ }
31
+ function splitShellWords(input) {
32
+ const words = [];
33
+ let current = "";
34
+ let quote;
35
+ for (let index = 0; index < input.length; index += 1) {
36
+ const char = input[index];
37
+ if (quote === "single") {
38
+ if (char === "'")
39
+ quote = undefined;
40
+ else
41
+ current += char;
42
+ continue;
43
+ }
44
+ if (quote === "double") {
45
+ if (char === '"')
46
+ quote = undefined;
47
+ else if (char === "\\" && index + 1 < input.length) {
48
+ index += 1;
49
+ current += input[index];
50
+ }
51
+ else
52
+ current += char;
53
+ continue;
54
+ }
55
+ if (char === "'") {
56
+ quote = "single";
57
+ continue;
58
+ }
59
+ if (char === '"') {
60
+ quote = "double";
61
+ continue;
62
+ }
63
+ if (char === "\\" && index + 1 < input.length) {
64
+ index += 1;
65
+ current += input[index];
66
+ continue;
67
+ }
68
+ if (char === "#" && current.length === 0) {
69
+ break;
70
+ }
71
+ if (/\s/.test(char)) {
72
+ if (current.length > 0) {
73
+ words.push(current);
74
+ current = "";
75
+ }
76
+ continue;
77
+ }
78
+ current += char;
79
+ }
80
+ if (quote)
81
+ return undefined;
82
+ if (current.length > 0)
83
+ words.push(current);
84
+ return words;
85
+ }
86
+ function formatNativeAgentBrowserCall(args, stdin) {
87
+ return stdin === undefined
88
+ ? `agent_browser { "args": ${JSON.stringify(args)} }`
89
+ : `agent_browser { "args": ${JSON.stringify(args)}, "stdin": ${JSON.stringify(stdin)} }`;
90
+ }
91
+ function formatNativeSkillContent(content) {
92
+ const lines = content.replace(/^allowed-tools:.*agent-browser.*\n?/gim, "").replace(/^```bash\s*$/gim, "```text").split("\n");
93
+ const output = [];
94
+ for (let index = 0; index < lines.length; index += 1) {
95
+ const line = lines[index];
96
+ const commandMatch = /^(\s*)agent-browser\s+(.+?)\s*$/.exec(line);
97
+ if (!commandMatch) {
98
+ output.push(line);
99
+ continue;
100
+ }
101
+ const indent = commandMatch[1];
102
+ const rawArgsText = commandMatch[2];
103
+ const heredocMatch = /^(.*?)\s+(<<-?)['"]?([A-Za-z_][A-Za-z0-9_]*)['"]?\s*$/.exec(rawArgsText);
104
+ const argsText = heredocMatch?.[1] ?? rawArgsText;
105
+ const args = splitShellWords(argsText);
106
+ if (!args || args.length === 0) {
107
+ output.push(line);
108
+ continue;
109
+ }
110
+ if (!heredocMatch) {
111
+ output.push(`${indent}${formatNativeAgentBrowserCall(args)}`);
112
+ continue;
113
+ }
114
+ const stripsLeadingTabs = heredocMatch[2] === "<<-";
115
+ const delimiter = heredocMatch[3];
116
+ const stdinLines = [];
117
+ let cursor = index + 1;
118
+ while (cursor < lines.length) {
119
+ const candidate = stripsLeadingTabs ? lines[cursor].replace(/^\t+/, "") : lines[cursor];
120
+ if (candidate === delimiter)
121
+ break;
122
+ stdinLines.push(candidate);
123
+ cursor += 1;
124
+ }
125
+ if (cursor >= lines.length) {
126
+ output.push(line);
127
+ continue;
128
+ }
129
+ output.push(`${indent}${formatNativeAgentBrowserCall(args, stdinLines.join("\n"))}`);
130
+ index = cursor;
131
+ }
132
+ return output.join("\n");
133
+ }
134
+ export function formatSkillsText(commandInfo, data) {
135
+ if (commandInfo.command !== "skills")
136
+ return undefined;
137
+ if (commandInfo.subcommand === "path")
138
+ return typeof data === "string" ? redactModelFacingText(data) : undefined;
139
+ if (commandInfo.subcommand === "list" && Array.isArray(data))
140
+ return formatSkillsListText(data);
141
+ const content = getSkillContent(data);
142
+ if (content) {
143
+ const note = [
144
+ "Pi native-tool note: upstream skill text was adapted for this native tool.",
145
+ "Use args for CLI tokens and stdin only for batch, eval --stdin, or auth save --password-stdin; do not pipe heredocs through bash unless the user explicitly asks for a bash workflow.",
146
+ ].join("\n");
147
+ return `${note}\n\n${redactModelFacingText(formatNativeSkillContent(content))}`;
148
+ }
149
+ if (typeof data === "string")
150
+ return redactModelFacingText(formatNativeSkillContent(data));
151
+ return undefined;
152
+ }
@@ -0,0 +1,177 @@
1
+ /*
2
+ * Purpose: Render parsed agent-browser results into concise pi-facing summaries, text content, and optional inline image attachments.
3
+ * Responsibilities: Orchestrate specialized presentation modules, attach inline images within size limits, and keep generic record formatting distinct from envelope parsing.
4
+ * Scope: Presentation shaping only; upstream stdout parsing and snapshot compaction internals live in separate modules.
5
+ */
6
+ import { isRecord } from "../parsing.js";
7
+ import { buildAgentBrowserNextActions } from "./action-recommendations.js";
8
+ import { buildAgentBrowserResultCategoryDetails } from "./categories.js";
9
+ import { detectConfirmationRequired } from "./confirmation.js";
10
+ import { buildSnapshotPresentation } from "./snapshot.js";
11
+ import { parseJsonPreviewString, redactModelFacingText, stringifyModelFacing } from "./presentation/common.js";
12
+ import { applyArtifactManifest, attachInlineImage, buildArtifactVerificationSummary, buildManifestEntriesForFileArtifacts, classifyPresentationSuccessCategory, extractFileArtifacts, extractImagePath, formatArtifactMetadataLines, formatArtifactSummary, formatMissingArtifactFailureText, getSavedFileDetails, hasMissingFileArtifact, isManifestFileArtifact, } from "./presentation/artifacts.js";
13
+ import { buildBatchPresentation, isAgentBrowserBatchResultArray } from "./presentation/batch.js";
14
+ import { getPresentationPaths } from "./presentation/content.js";
15
+ import { buildNetworkRequestsNextActions, buildStreamNextActions, enrichStreamStatusData, formatNetworkRouteDiagnosticsText, redactPresentationData, } from "./presentation/diagnostics.js";
16
+ import { buildErrorPresentation } from "./presentation/errors.js";
17
+ import { compactLargePresentationOutput } from "./presentation/large-output.js";
18
+ import { buildPageChangeSummary } from "./presentation/navigation.js";
19
+ import { formatPresentationContentText, formatPresentationSummary } from "./presentation/registry.js";
20
+ import { resolvePresentationCommandInfo } from "./presentation/semantic-action.js";
21
+ function sanitizeModelFacingPresentation(presentation) {
22
+ presentation.content = presentation.content.map((item) => {
23
+ if (item.type !== "text")
24
+ return item;
25
+ const parsed = parseJsonPreviewString(item.text);
26
+ return parsed === item.text ? item : { ...item, text: stringifyModelFacing(parsed) };
27
+ });
28
+ presentation.summary = redactModelFacingText(presentation.summary);
29
+ return presentation;
30
+ }
31
+ function mergeNextActions(...groups) {
32
+ const merged = groups.flatMap((group) => group ?? []);
33
+ return merged.length > 0 ? merged : undefined;
34
+ }
35
+ function shouldAddAnnotatedScreenshotGuidance(commandInfo, args) {
36
+ return commandInfo.command === "screenshot" && (args?.includes("--annotate") ?? false);
37
+ }
38
+ export async function buildToolPresentation(options) {
39
+ const { args, artifactManifest, artifactRequest, commandInfo, compiledSemanticAction, cwd, envelope, errorText, networkRouteDiagnostics, networkRoutes, persistentArtifactStore, sessionName, } = options;
40
+ const presentationCommandInfo = resolvePresentationCommandInfo(commandInfo, compiledSemanticAction);
41
+ if (errorText) {
42
+ return buildErrorPresentation({ args, commandInfo, errorText, sessionName });
43
+ }
44
+ const data = enrichStreamStatusData(commandInfo, envelope?.data);
45
+ const presentationData = redactPresentationData(commandInfo, data);
46
+ const artifacts = await extractFileArtifacts({ artifactManifest, artifactRequest, commandInfo: presentationCommandInfo, cwd, data, sessionName });
47
+ const artifactVerification = buildArtifactVerificationSummary(artifacts);
48
+ const artifactSummary = formatArtifactSummary(artifacts);
49
+ const summary = artifactSummary ?? formatPresentationSummary(commandInfo, data, compiledSemanticAction);
50
+ const artifactText = artifacts.length > 0 ? formatArtifactMetadataLines(artifacts).join("\n") : undefined;
51
+ let presentation;
52
+ if (commandInfo.command === "batch" && isAgentBrowserBatchResultArray(data)) {
53
+ presentation = await buildBatchPresentation({
54
+ artifactManifest,
55
+ artifactRequests: options.batchArtifactRequests,
56
+ buildNestedToolPresentation: buildToolPresentation,
57
+ cwd,
58
+ data,
59
+ networkRoutes,
60
+ persistentArtifactStore,
61
+ sessionName,
62
+ summary,
63
+ });
64
+ }
65
+ else if (commandInfo.command === "snapshot" && isRecord(data)) {
66
+ presentation = await buildSnapshotPresentation(data, persistentArtifactStore, artifactManifest);
67
+ }
68
+ else {
69
+ presentation = {
70
+ artifactVerification,
71
+ artifacts: artifacts.length > 0 ? artifacts : undefined,
72
+ content: [{ type: "text", text: artifactText ?? formatPresentationContentText(commandInfo, data, compiledSemanticAction) }],
73
+ data: presentationData,
74
+ summary,
75
+ };
76
+ }
77
+ if (networkRouteDiagnostics && networkRouteDiagnostics.length > 0 && presentation.content[0]?.type === "text") {
78
+ const diagnosticText = formatNetworkRouteDiagnosticsText(networkRouteDiagnostics);
79
+ if (diagnosticText)
80
+ presentation.content[0] = { ...presentation.content[0], text: `${diagnosticText}\n\n${presentation.content[0].text}` };
81
+ presentation.networkRouteDiagnostics = networkRouteDiagnostics;
82
+ }
83
+ if (artifacts.length > 0 && !presentation.artifacts) {
84
+ presentation.artifacts = artifacts;
85
+ }
86
+ presentation.artifactVerification = presentation.artifactVerification ?? artifactVerification;
87
+ if (isRecord(data)) {
88
+ const savedFile = getSavedFileDetails(commandInfo, data);
89
+ if (savedFile) {
90
+ presentation.savedFile = savedFile;
91
+ presentation.savedFilePath = savedFile.path;
92
+ }
93
+ }
94
+ if (shouldAddAnnotatedScreenshotGuidance(commandInfo, args) && presentation.content[0]?.type === "text") {
95
+ const guidance = "Annotated screenshot note: dense pages can produce overlapping labels. If the labels are noisy, capture a scoped element screenshot, take a non-annotated screenshot, or use snapshot -i high-value refs as the machine-readable map.";
96
+ presentation.content[0] = { ...presentation.content[0], text: `${presentation.content[0].text}\n\n${guidance}` };
97
+ }
98
+ const imagePath = artifactRequest?.absolutePath ?? extractImagePath(commandInfo, cwd, data);
99
+ const presentationWithImage = imagePath ? await attachInlineImage(presentation, imagePath) : presentation;
100
+ const compactedPresentation = await compactLargePresentationOutput({
101
+ artifactManifest,
102
+ commandInfo,
103
+ data: presentationData,
104
+ persistentArtifactStore,
105
+ presentation: presentationWithImage,
106
+ });
107
+ const presentationWithManifest = applyArtifactManifest(compactedPresentation, compactedPresentation.artifactManifest ?? artifactManifest, buildManifestEntriesForFileArtifacts(artifacts.filter(isManifestFileArtifact)));
108
+ const currentSpillPaths = new Set(getPresentationPaths({
109
+ primaryPath: presentationWithManifest.fullOutputPath,
110
+ secondaryPaths: presentationWithManifest.fullOutputPaths,
111
+ }));
112
+ presentationWithManifest.artifactVerification = buildArtifactVerificationSummary(artifacts, presentationWithManifest.artifactManifest, currentSpillPaths) ?? presentationWithManifest.artifactVerification;
113
+ const confirmationRequired = detectConfirmationRequired(data);
114
+ const missingArtifactFailureText = formatMissingArtifactFailureText(presentationWithManifest.artifacts);
115
+ if (missingArtifactFailureText && hasMissingFileArtifact(presentationWithManifest.artifacts)) {
116
+ presentationWithManifest.resultCategory = "failure";
117
+ presentationWithManifest.failureCategory = "artifact-missing";
118
+ presentationWithManifest.successCategory = undefined;
119
+ presentationWithManifest.summary = missingArtifactFailureText;
120
+ if (presentationWithManifest.content[0]?.type === "text") {
121
+ presentationWithManifest.content[0] = { ...presentationWithManifest.content[0], text: `${missingArtifactFailureText}\n\n${presentationWithManifest.content[0].text}` };
122
+ }
123
+ else {
124
+ presentationWithManifest.content.unshift({ type: "text", text: missingArtifactFailureText });
125
+ }
126
+ }
127
+ if (!presentationWithManifest.resultCategory) {
128
+ const categoryDetails = buildAgentBrowserResultCategoryDetails({
129
+ artifacts: presentationWithManifest.artifacts,
130
+ command: presentationCommandInfo.command,
131
+ confirmationRequired: confirmationRequired !== undefined,
132
+ errorText: envelope?.success === false ? presentationWithManifest.summary : undefined,
133
+ savedFile: presentationWithManifest.savedFile,
134
+ succeeded: envelope?.success !== false,
135
+ });
136
+ presentationWithManifest.resultCategory = categoryDetails.resultCategory;
137
+ presentationWithManifest.successCategory = categoryDetails.resultCategory === "success"
138
+ ? classifyPresentationSuccessCategory({
139
+ artifactVerification: presentationWithManifest.artifactVerification,
140
+ artifacts: presentationWithManifest.artifacts,
141
+ savedFile: presentationWithManifest.savedFile,
142
+ })
143
+ : categoryDetails.successCategory;
144
+ presentationWithManifest.failureCategory = categoryDetails.failureCategory;
145
+ }
146
+ if (presentationWithManifest.resultCategory === "success") {
147
+ presentationWithManifest.successCategory = classifyPresentationSuccessCategory({
148
+ artifactVerification: presentationWithManifest.artifactVerification,
149
+ artifacts: presentationWithManifest.artifacts,
150
+ savedFile: presentationWithManifest.savedFile,
151
+ });
152
+ }
153
+ const genericNextActions = presentationWithManifest.nextActions ? undefined : buildAgentBrowserNextActions({
154
+ artifacts: presentationWithManifest.artifacts,
155
+ args,
156
+ command: presentationCommandInfo.command,
157
+ confirmationId: confirmationRequired?.id,
158
+ failureCategory: presentationWithManifest.failureCategory,
159
+ resultCategory: presentationWithManifest.resultCategory ?? "success",
160
+ savedFilePath: presentationWithManifest.savedFilePath,
161
+ successCategory: presentationWithManifest.successCategory,
162
+ });
163
+ const networkNextActions = commandInfo.command === "network" && commandInfo.subcommand === "requests" && presentationWithManifest.resultCategory === "success"
164
+ ? buildNetworkRequestsNextActions(data, sessionName, presentationWithManifest.networkRouteDiagnostics)
165
+ : undefined;
166
+ const streamNextActions = presentationWithManifest.resultCategory === "success" ? buildStreamNextActions(commandInfo, data, sessionName) : undefined;
167
+ presentationWithManifest.nextActions = mergeNextActions(presentationWithManifest.nextActions, genericNextActions, networkNextActions, streamNextActions);
168
+ presentationWithManifest.pageChangeSummary = presentationWithManifest.pageChangeSummary ?? buildPageChangeSummary({
169
+ artifacts: presentationWithManifest.artifacts,
170
+ commandInfo: presentationCommandInfo,
171
+ data,
172
+ nextActions: presentationWithManifest.nextActions,
173
+ savedFilePath: presentationWithManifest.savedFilePath,
174
+ summary: presentationWithManifest.summary,
175
+ });
176
+ return sanitizeModelFacingPresentation(presentationWithManifest);
177
+ }