pi-agent-browser-native 0.2.47 → 0.2.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -19
- package/README.md +52 -19
- package/dist/extensions/agent-browser/index.js +785 -0
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
- package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
- package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
- package/dist/extensions/agent-browser/lib/config-policy.js +686 -0
- package/dist/extensions/agent-browser/lib/config.js +122 -0
- package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
- package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
- package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
- package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
- package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
- package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
- package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
- package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
- package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
- package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
- package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
- package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
- package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
- package/dist/extensions/agent-browser/lib/playbook.js +121 -0
- package/dist/extensions/agent-browser/lib/process.js +448 -0
- package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
- package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
- package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
- package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
- package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
- package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
- package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
- package/dist/extensions/agent-browser/lib/results/network.js +73 -0
- package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +960 -0
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
- package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
- package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
- package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
- package/dist/extensions/agent-browser/lib/results/text.js +40 -0
- package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
- package/dist/extensions/agent-browser/lib/runtime.js +816 -0
- package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
- package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
- package/dist/extensions/agent-browser/lib/temp.js +498 -0
- package/dist/extensions/agent-browser/lib/web-search.js +562 -0
- package/docs/ARCHITECTURE.md +10 -10
- package/docs/COMMAND_REFERENCE.md +35 -21
- package/docs/ELECTRON.md +3 -3
- package/docs/RELEASE.md +46 -26
- package/docs/REQUIREMENTS.md +1 -1
- package/docs/SUPPORT_MATRIX.md +35 -106
- package/docs/TOOL_CONTRACT.md +23 -21
- package/package.json +12 -8
- package/scripts/agent-browser-capability-baseline.mjs +6 -3
- package/scripts/config.mjs +8 -2
- package/scripts/doctor.mjs +19 -17
- package/scripts/platform-smoke.mjs +1 -1
- package/extensions/agent-browser/index.ts +0 -952
- package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
- package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
- package/extensions/agent-browser/lib/bash-guard.ts +0 -205
- package/extensions/agent-browser/lib/command-policy.ts +0 -71
- package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
- package/extensions/agent-browser/lib/config-policy.js +0 -690
- package/extensions/agent-browser/lib/config.ts +0 -209
- package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
- package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
- package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
- package/extensions/agent-browser/lib/electron/launch.ts +0 -499
- package/extensions/agent-browser/lib/executable-path.ts +0 -19
- package/extensions/agent-browser/lib/fs-utils.ts +0 -18
- package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
- package/extensions/agent-browser/lib/input-modes/job.ts +0 -451
- package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
- package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
- package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
- package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
- package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
- package/extensions/agent-browser/lib/input-modes.ts +0 -45
- package/extensions/agent-browser/lib/json-schema.ts +0 -73
- package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
- package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
- package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
- package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -257
- package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -912
- package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -512
- package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -1481
- package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -564
- package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
- package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
- package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -564
- package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
- package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
- package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
- package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -252
- package/extensions/agent-browser/lib/playbook.ts +0 -142
- package/extensions/agent-browser/lib/process.ts +0 -516
- package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
- package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
- package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
- package/extensions/agent-browser/lib/results/categories.ts +0 -106
- package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
- package/extensions/agent-browser/lib/results/contracts.ts +0 -241
- package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
- package/extensions/agent-browser/lib/results/envelope.ts +0 -195
- package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
- package/extensions/agent-browser/lib/results/network.ts +0 -78
- package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
- package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
- package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
- package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
- package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
- package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
- package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
- package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
- package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
- package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
- package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
- package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
- package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
- package/extensions/agent-browser/lib/results/presentation.ts +0 -257
- package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
- package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
- package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
- package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
- package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
- package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
- package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
- package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
- package/extensions/agent-browser/lib/results/text.ts +0 -40
- package/extensions/agent-browser/lib/runtime.ts +0 -988
- package/extensions/agent-browser/lib/session-page-state.ts +0 -512
- package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
- package/extensions/agent-browser/lib/temp.ts +0 -577
- package/extensions/agent-browser/lib/web-search.ts +0 -721
- /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
|
@@ -0,0 +1,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
|
+
}
|