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,247 @@
|
|
|
1
|
+
import { parseArgvDescriptor } from "../argv-descriptor.js";
|
|
2
|
+
import { validateToolArgs, redactInvocationArgs, redactSensitiveText } from "../runtime.js";
|
|
3
|
+
import { buildAgentBrowserResultCategoryDetails } from "../results/categories.js";
|
|
4
|
+
import { compileAgentBrowserElectron, compileAgentBrowserJob, compileAgentBrowserNetworkSourceLookup, compileAgentBrowserQaPreset, compileAgentBrowserSemanticAction, compileAgentBrowserSourceLookup, redactNetworkSourceLookupArgs, redactNetworkSourceLookupUrl, } from "../input-modes.js";
|
|
5
|
+
function redactCompiledElectron(compiled) {
|
|
6
|
+
if (!compiled)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (compiled.action === "list") {
|
|
9
|
+
return { ...compiled, query: compiled.query ? redactSensitiveText(compiled.query) : undefined };
|
|
10
|
+
}
|
|
11
|
+
if (compiled.action === "launch") {
|
|
12
|
+
return { ...compiled, appArgs: compiled.appArgs ? redactInvocationArgs(compiled.appArgs) : undefined };
|
|
13
|
+
}
|
|
14
|
+
return { ...compiled };
|
|
15
|
+
}
|
|
16
|
+
function redactCompiledJob(compiled) {
|
|
17
|
+
const redactedSteps = compiled?.steps.map((step) => ({ ...step, args: redactInvocationArgs(step.args) }));
|
|
18
|
+
return compiled && redactedSteps
|
|
19
|
+
? { ...compiled, stdin: JSON.stringify(redactedSteps.map((step) => step.args)), steps: redactedSteps }
|
|
20
|
+
: undefined;
|
|
21
|
+
}
|
|
22
|
+
function redactCompiledSourceLookup(compiled) {
|
|
23
|
+
const redactedSteps = compiled?.steps.map((step) => ({ ...step, args: redactInvocationArgs(step.args) }));
|
|
24
|
+
return compiled && redactedSteps
|
|
25
|
+
? { ...compiled, stdin: JSON.stringify(redactedSteps.map((step) => step.args)), steps: redactedSteps }
|
|
26
|
+
: undefined;
|
|
27
|
+
}
|
|
28
|
+
function redactCompiledNetworkSourceLookup(compiled) {
|
|
29
|
+
const redactedSteps = compiled?.steps.map((step) => ({ ...step, args: redactNetworkSourceLookupArgs(step.args) }));
|
|
30
|
+
return compiled && redactedSteps
|
|
31
|
+
? {
|
|
32
|
+
...compiled,
|
|
33
|
+
args: redactNetworkSourceLookupArgs(compiled.args),
|
|
34
|
+
query: {
|
|
35
|
+
...compiled.query,
|
|
36
|
+
filter: redactNetworkSourceLookupUrl(compiled.query.filter),
|
|
37
|
+
url: redactNetworkSourceLookupUrl(compiled.query.url),
|
|
38
|
+
},
|
|
39
|
+
stdin: JSON.stringify(redactedSteps.map((step) => step.args)),
|
|
40
|
+
steps: redactedSteps,
|
|
41
|
+
}
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
44
|
+
function normalizeExplicitEvalStdinArgs(args, stdin) {
|
|
45
|
+
if (stdin !== undefined) {
|
|
46
|
+
return { args, stdin };
|
|
47
|
+
}
|
|
48
|
+
const descriptor = parseArgvDescriptor(args);
|
|
49
|
+
if (descriptor.commandInfo.command !== "eval") {
|
|
50
|
+
return { args, stdin };
|
|
51
|
+
}
|
|
52
|
+
const stdinIndex = descriptor.commandTokens.indexOf("--stdin");
|
|
53
|
+
if (stdinIndex < 0 || stdinIndex >= descriptor.commandTokens.length - 1) {
|
|
54
|
+
return { args, stdin };
|
|
55
|
+
}
|
|
56
|
+
const commandStartIndex = args.length - descriptor.commandTokens.length;
|
|
57
|
+
const stdinValue = descriptor.commandTokens.slice(stdinIndex + 1).join(" ");
|
|
58
|
+
return {
|
|
59
|
+
args: [...args.slice(0, commandStartIndex), ...descriptor.commandTokens.slice(0, stdinIndex + 1)],
|
|
60
|
+
stdin: stdinValue,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function resolveAgentBrowserInput(options) {
|
|
64
|
+
const { getBatchPreflightValidationError, managedSessionActive, params } = options;
|
|
65
|
+
const semanticActionResult = params.semanticAction === undefined ? {} : compileAgentBrowserSemanticAction(params.semanticAction);
|
|
66
|
+
const jobResult = params.job === undefined ? {} : compileAgentBrowserJob(params.job);
|
|
67
|
+
const qaResult = params.qa === undefined ? {} : compileAgentBrowserQaPreset(params.qa);
|
|
68
|
+
const sourceLookupResult = params.sourceLookup === undefined ? {} : compileAgentBrowserSourceLookup(params.sourceLookup);
|
|
69
|
+
const networkSourceLookupResult = params.networkSourceLookup === undefined ? {} : compileAgentBrowserNetworkSourceLookup(params.networkSourceLookup);
|
|
70
|
+
const electronResult = params.electron === undefined ? {} : compileAgentBrowserElectron(params.electron);
|
|
71
|
+
const hasExplicitArgs = Array.isArray(params.args);
|
|
72
|
+
const explicitInputModes = [
|
|
73
|
+
hasExplicitArgs,
|
|
74
|
+
Boolean(semanticActionResult.compiled),
|
|
75
|
+
Boolean(jobResult.compiled),
|
|
76
|
+
Boolean(qaResult.compiled),
|
|
77
|
+
Boolean(sourceLookupResult.compiled),
|
|
78
|
+
Boolean(networkSourceLookupResult.compiled),
|
|
79
|
+
Boolean(electronResult.compiled),
|
|
80
|
+
].filter(Boolean).length;
|
|
81
|
+
const inputModeError = explicitInputModes !== 1
|
|
82
|
+
? "Provide exactly one of args, semanticAction, job, qa, sourceLookup, networkSourceLookup, or electron."
|
|
83
|
+
: undefined;
|
|
84
|
+
const compiledSemanticAction = semanticActionResult.compiled;
|
|
85
|
+
const compiledQaPreset = qaResult.compiled;
|
|
86
|
+
const compiledSourceLookup = sourceLookupResult.compiled;
|
|
87
|
+
const compiledNetworkSourceLookup = networkSourceLookupResult.compiled;
|
|
88
|
+
const compiledElectron = electronResult.compiled;
|
|
89
|
+
const compiledJob = jobResult.compiled ?? compiledQaPreset;
|
|
90
|
+
const compiledGeneratedBatch = compiledNetworkSourceLookup ?? compiledSourceLookup ?? compiledJob;
|
|
91
|
+
const normalizedExplicitArgs = normalizeExplicitEvalStdinArgs(params.args ?? [], params.stdin);
|
|
92
|
+
const toolArgs = compiledElectron ? [] : compiledSemanticAction?.args ?? compiledGeneratedBatch?.args ?? normalizedExplicitArgs.args;
|
|
93
|
+
const toolStdin = compiledGeneratedBatch?.stdin ?? normalizedExplicitArgs.stdin;
|
|
94
|
+
const redactedArgs = redactInvocationArgs(toolArgs);
|
|
95
|
+
const generatedStdinError = params.stdin !== undefined
|
|
96
|
+
? compiledGeneratedBatch
|
|
97
|
+
? "Do not provide stdin with job, qa, sourceLookup, or networkSourceLookup; those modes generate their own batch stdin."
|
|
98
|
+
: compiledElectron
|
|
99
|
+
? "Do not provide stdin with electron; electron mode is host-only or manages its own input."
|
|
100
|
+
: undefined
|
|
101
|
+
: undefined;
|
|
102
|
+
const outputPathError = params.outputPath !== undefined && (typeof params.outputPath !== "string" || params.outputPath.trim().length === 0)
|
|
103
|
+
? "outputPath must be a non-empty string when provided."
|
|
104
|
+
: undefined;
|
|
105
|
+
const timeoutMsError = params.timeoutMs !== undefined && (typeof params.timeoutMs !== "number" || !Number.isSafeInteger(params.timeoutMs) || params.timeoutMs <= 0)
|
|
106
|
+
? "timeoutMs must be a positive integer when provided."
|
|
107
|
+
: compiledElectron && params.timeoutMs !== undefined
|
|
108
|
+
? "Use electron.timeoutMs for electron actions; top-level timeoutMs applies only to browser CLI subprocess calls."
|
|
109
|
+
: undefined;
|
|
110
|
+
const attachedQaSessionError = compiledQaPreset?.checks.attached
|
|
111
|
+
? params.sessionMode === "fresh"
|
|
112
|
+
? "qa.attached cannot be used with sessionMode=fresh; attach or launch a session first, then run qa.attached with the current session."
|
|
113
|
+
: !managedSessionActive
|
|
114
|
+
? "qa.attached requires an active attached session. Run electron.launch or connect to an Electron debug port first."
|
|
115
|
+
: undefined
|
|
116
|
+
: undefined;
|
|
117
|
+
const validationError = semanticActionResult.error
|
|
118
|
+
?? jobResult.error
|
|
119
|
+
?? qaResult.error
|
|
120
|
+
?? sourceLookupResult.error
|
|
121
|
+
?? networkSourceLookupResult.error
|
|
122
|
+
?? electronResult.error
|
|
123
|
+
?? inputModeError
|
|
124
|
+
?? generatedStdinError
|
|
125
|
+
?? outputPathError
|
|
126
|
+
?? timeoutMsError
|
|
127
|
+
?? attachedQaSessionError
|
|
128
|
+
?? (compiledElectron ? undefined : validateToolArgs(toolArgs) ?? getBatchPreflightValidationError(toolArgs, toolStdin));
|
|
129
|
+
const redactedCompiledJob = redactCompiledJob(compiledJob);
|
|
130
|
+
const redactedCompiledSemanticAction = compiledSemanticAction
|
|
131
|
+
? { ...compiledSemanticAction, args: redactInvocationArgs(compiledSemanticAction.args) }
|
|
132
|
+
: undefined;
|
|
133
|
+
const attemptedKind = compiledElectron
|
|
134
|
+
? "electron"
|
|
135
|
+
: compiledNetworkSourceLookup
|
|
136
|
+
? "networkSourceLookup"
|
|
137
|
+
: compiledSourceLookup
|
|
138
|
+
? "sourceLookup"
|
|
139
|
+
: compiledQaPreset
|
|
140
|
+
? "qa"
|
|
141
|
+
: jobResult.compiled
|
|
142
|
+
? "job"
|
|
143
|
+
: compiledSemanticAction
|
|
144
|
+
? "semanticAction"
|
|
145
|
+
: hasExplicitArgs
|
|
146
|
+
? "args"
|
|
147
|
+
: undefined;
|
|
148
|
+
const redactedCompiledElectron = redactCompiledElectron(compiledElectron);
|
|
149
|
+
const redactedCompiledNetworkSourceLookup = redactCompiledNetworkSourceLookup(compiledNetworkSourceLookup);
|
|
150
|
+
const redactedCompiledQaPreset = compiledQaPreset && redactedCompiledJob ? { ...redactedCompiledJob, checks: compiledQaPreset.checks } : undefined;
|
|
151
|
+
const redactedCompiledSourceLookup = redactCompiledSourceLookup(compiledSourceLookup);
|
|
152
|
+
const resolvedBase = { redactedArgs, toolArgs, toolStdin };
|
|
153
|
+
if (validationError) {
|
|
154
|
+
return {
|
|
155
|
+
...resolvedBase,
|
|
156
|
+
attemptedKind,
|
|
157
|
+
compiledElectron,
|
|
158
|
+
compiledGeneratedBatch,
|
|
159
|
+
compiledJob,
|
|
160
|
+
compiledNetworkSourceLookup,
|
|
161
|
+
compiledQaPreset,
|
|
162
|
+
compiledSemanticAction,
|
|
163
|
+
compiledSourceLookup,
|
|
164
|
+
kind: "invalid",
|
|
165
|
+
redactedCompiledElectron,
|
|
166
|
+
redactedCompiledJob,
|
|
167
|
+
redactedCompiledNetworkSourceLookup,
|
|
168
|
+
redactedCompiledQaPreset,
|
|
169
|
+
redactedCompiledSemanticAction,
|
|
170
|
+
redactedCompiledSourceLookup,
|
|
171
|
+
status: "invalid",
|
|
172
|
+
validationError,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (compiledElectron && redactedCompiledElectron) {
|
|
176
|
+
return { ...resolvedBase, compiledElectron, kind: "electron", redactedCompiledElectron, status: "valid" };
|
|
177
|
+
}
|
|
178
|
+
if (compiledNetworkSourceLookup && redactedCompiledNetworkSourceLookup) {
|
|
179
|
+
return {
|
|
180
|
+
...resolvedBase,
|
|
181
|
+
compiledGeneratedBatch: compiledNetworkSourceLookup,
|
|
182
|
+
compiledNetworkSourceLookup,
|
|
183
|
+
kind: "networkSourceLookup",
|
|
184
|
+
redactedCompiledNetworkSourceLookup,
|
|
185
|
+
status: "valid",
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (compiledSourceLookup && redactedCompiledSourceLookup) {
|
|
189
|
+
return {
|
|
190
|
+
...resolvedBase,
|
|
191
|
+
compiledGeneratedBatch: compiledSourceLookup,
|
|
192
|
+
compiledSourceLookup,
|
|
193
|
+
kind: "sourceLookup",
|
|
194
|
+
redactedCompiledSourceLookup,
|
|
195
|
+
status: "valid",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (compiledQaPreset && redactedCompiledJob && redactedCompiledQaPreset) {
|
|
199
|
+
return {
|
|
200
|
+
...resolvedBase,
|
|
201
|
+
compiledGeneratedBatch: compiledQaPreset,
|
|
202
|
+
compiledJob: compiledQaPreset,
|
|
203
|
+
compiledQaPreset,
|
|
204
|
+
kind: "qa",
|
|
205
|
+
redactedCompiledJob,
|
|
206
|
+
redactedCompiledQaPreset,
|
|
207
|
+
status: "valid",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (jobResult.compiled && redactedCompiledJob) {
|
|
211
|
+
return {
|
|
212
|
+
...resolvedBase,
|
|
213
|
+
compiledGeneratedBatch: jobResult.compiled,
|
|
214
|
+
compiledJob: jobResult.compiled,
|
|
215
|
+
kind: "job",
|
|
216
|
+
redactedCompiledJob,
|
|
217
|
+
status: "valid",
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (compiledSemanticAction && redactedCompiledSemanticAction) {
|
|
221
|
+
return { ...resolvedBase, compiledSemanticAction, kind: "semanticAction", redactedCompiledSemanticAction, status: "valid" };
|
|
222
|
+
}
|
|
223
|
+
return { ...resolvedBase, kind: "args", status: "valid" };
|
|
224
|
+
}
|
|
225
|
+
export function buildValidationFailureResult(input) {
|
|
226
|
+
const validationError = input.validationError ?? "Invalid agent_browser input.";
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: "text", text: validationError }],
|
|
229
|
+
details: {
|
|
230
|
+
args: input.redactedArgs,
|
|
231
|
+
compiledElectron: input.redactedCompiledElectron,
|
|
232
|
+
compiledJob: input.redactedCompiledJob,
|
|
233
|
+
compiledQaPreset: input.redactedCompiledQaPreset,
|
|
234
|
+
compiledSourceLookup: input.redactedCompiledSourceLookup,
|
|
235
|
+
compiledNetworkSourceLookup: input.redactedCompiledNetworkSourceLookup,
|
|
236
|
+
compiledSemanticAction: input.redactedCompiledSemanticAction,
|
|
237
|
+
...buildAgentBrowserResultCategoryDetails({
|
|
238
|
+
args: input.redactedArgs,
|
|
239
|
+
errorText: validationError,
|
|
240
|
+
succeeded: false,
|
|
241
|
+
validationError,
|
|
242
|
+
}),
|
|
243
|
+
validationError,
|
|
244
|
+
},
|
|
245
|
+
isError: true,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { isRecord } from "../parsing.js";
|
|
4
|
+
function normalizeRequestedOutputPath(path) {
|
|
5
|
+
return path.startsWith("@") ? path.slice(1) : path;
|
|
6
|
+
}
|
|
7
|
+
function getTextContent(result) {
|
|
8
|
+
return result.content
|
|
9
|
+
?.filter((item) => item.type === "text")
|
|
10
|
+
.map((item) => item.text)
|
|
11
|
+
.join("\n\n") ?? "";
|
|
12
|
+
}
|
|
13
|
+
function getOutputPayload(result) {
|
|
14
|
+
const details = isRecord(result.details) ? result.details : undefined;
|
|
15
|
+
if (details && details.data !== undefined)
|
|
16
|
+
return { source: "details.data", value: details.data };
|
|
17
|
+
return { source: "content.text", value: getTextContent(result) };
|
|
18
|
+
}
|
|
19
|
+
function serializeOutputPayload(value) {
|
|
20
|
+
return typeof value === "string" ? value : `${JSON.stringify(value, null, 2)}\n`;
|
|
21
|
+
}
|
|
22
|
+
function appendOutputFileNotice(result, message) {
|
|
23
|
+
const content = [...(result.content ?? [])];
|
|
24
|
+
if (content[0]?.type === "text") {
|
|
25
|
+
content[0] = { ...content[0], text: `${content[0].text}\n\n${message}` };
|
|
26
|
+
return content;
|
|
27
|
+
}
|
|
28
|
+
return [{ type: "text", text: message }, ...content];
|
|
29
|
+
}
|
|
30
|
+
export async function applyAgentBrowserOutputPath(options) {
|
|
31
|
+
if (!options.outputPath)
|
|
32
|
+
return options.result;
|
|
33
|
+
if (options.result.isError || (isRecord(options.result.details) && options.result.details.resultCategory === "failure"))
|
|
34
|
+
return options.result;
|
|
35
|
+
const requestedPath = normalizeRequestedOutputPath(options.outputPath);
|
|
36
|
+
const absolutePath = isAbsolute(requestedPath) ? requestedPath : resolve(options.cwd, requestedPath);
|
|
37
|
+
const payload = getOutputPayload(options.result);
|
|
38
|
+
try {
|
|
39
|
+
const serialized = serializeOutputPayload(payload.value);
|
|
40
|
+
await mkdir(dirname(absolutePath), { recursive: true });
|
|
41
|
+
await writeFile(absolutePath, serialized, "utf8");
|
|
42
|
+
const bytes = Buffer.byteLength(serialized, "utf8");
|
|
43
|
+
const outputFile = { absolutePath, bytes, path: requestedPath, source: payload.source, status: "saved" };
|
|
44
|
+
const details = isRecord(options.result.details) ? { ...options.result.details, outputFile } : { outputFile };
|
|
45
|
+
return {
|
|
46
|
+
...options.result,
|
|
47
|
+
content: options.preserveTextContent ? options.result.content : appendOutputFileNotice(options.result, `Output file: ${requestedPath} (${bytes} bytes from ${payload.source}).`),
|
|
48
|
+
details,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
53
|
+
const outputFile = { absolutePath, error: message, path: requestedPath, source: payload.source, status: "failed" };
|
|
54
|
+
const details = isRecord(options.result.details)
|
|
55
|
+
? (() => {
|
|
56
|
+
const rest = { ...options.result.details };
|
|
57
|
+
delete rest.successCategory;
|
|
58
|
+
return { ...rest, failureCategory: rest.failureCategory ?? "upstream-error", outputFile, resultCategory: "failure" };
|
|
59
|
+
})()
|
|
60
|
+
: { failureCategory: "upstream-error", outputFile, resultCategory: "failure" };
|
|
61
|
+
return {
|
|
62
|
+
...options.result,
|
|
63
|
+
content: options.preserveTextContent ? options.result.content : appendOutputFileNotice(options.result, `Output file failed: ${requestedPath} (${message}).`),
|
|
64
|
+
details,
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js}
RENAMED
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|
* Usage: Imported by agent-browser wrapper modules that parse untyped JSON, persisted state, or environment variables.
|
|
6
6
|
* Invariants/Assumptions: Arrays intentionally count as records to preserve existing object-boundary semantics, and positive integers must be safe base-10 integer strings greater than zero.
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return typeof value === "object" && value !== null;
|
|
8
|
+
export function isRecord(value) {
|
|
9
|
+
return typeof value === "object" && value !== null;
|
|
11
10
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
export function parsePositiveInteger(rawValue) {
|
|
12
|
+
if (typeof rawValue !== "string")
|
|
13
|
+
return undefined;
|
|
14
|
+
const normalizedValue = rawValue.trim();
|
|
15
|
+
if (!/^\d+$/.test(normalizedValue))
|
|
16
|
+
return undefined;
|
|
17
|
+
const parsedValue = Number(normalizedValue);
|
|
18
|
+
if (!Number.isSafeInteger(parsedValue) || parsedValue <= 0)
|
|
19
|
+
return undefined;
|
|
20
|
+
return parsedValue;
|
|
20
21
|
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { getKeybindings, Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
import { compileAgentBrowserElectron, compileAgentBrowserJob, compileAgentBrowserNetworkSourceLookup, compileAgentBrowserQaPreset, compileAgentBrowserSemanticAction, compileAgentBrowserSourceLookup, } from "./input-modes.js";
|
|
3
|
+
import { isRecord } from "./parsing.js";
|
|
4
|
+
import { redactInvocationArgs } from "./runtime.js";
|
|
5
|
+
const TUI_INVOCATION_PREVIEW_MAX_CHARS = 160;
|
|
6
|
+
const TUI_COLLAPSED_OUTPUT_MAX_LINES = 12;
|
|
7
|
+
const ANSI_CONTROL_SEQUENCE_PATTERN = /\x1B(?:\][^\x07\x1B]*(?:\x07|\x1B\\)|\[[0-?]*[ -/]*[@-~]|P[^\x1B]*(?:\x1B\\)|_[^\x1B]*(?:\x1B\\)|\^[^\x1B]*(?:\x1B\\)|[@-Z\\-_])/g;
|
|
8
|
+
const JSON_TOKEN_PATTERN = /"(?:\\.|[^"\\])*"(?=\s*:)|"(?:\\.|[^"\\])*"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null|[{}\[\],:]/g;
|
|
9
|
+
const UNSAFE_DISPLAY_CONTROL_PATTERN = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x80-\x9F]/g;
|
|
10
|
+
function sanitizeDisplayText(value) {
|
|
11
|
+
return value
|
|
12
|
+
.replace(ANSI_CONTROL_SEQUENCE_PATTERN, "")
|
|
13
|
+
.replace(/\r/g, "")
|
|
14
|
+
.replace(UNSAFE_DISPLAY_CONTROL_PATTERN, "�");
|
|
15
|
+
}
|
|
16
|
+
function replaceTabsForDisplay(value) {
|
|
17
|
+
return value.replaceAll("\t", " ");
|
|
18
|
+
}
|
|
19
|
+
function trimTrailingBlankLines(lines) {
|
|
20
|
+
let end = lines.length;
|
|
21
|
+
while (end > 0 && lines[end - 1].trim().length === 0) {
|
|
22
|
+
end -= 1;
|
|
23
|
+
}
|
|
24
|
+
return lines.slice(0, end);
|
|
25
|
+
}
|
|
26
|
+
function isJsonDocumentText(value) {
|
|
27
|
+
const trimmed = value.trim();
|
|
28
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("["))
|
|
29
|
+
return false;
|
|
30
|
+
try {
|
|
31
|
+
JSON.parse(trimmed);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function colorizeJsonLine(line, theme) {
|
|
39
|
+
let output = "";
|
|
40
|
+
let cursor = 0;
|
|
41
|
+
for (const match of line.matchAll(JSON_TOKEN_PATTERN)) {
|
|
42
|
+
const token = match[0];
|
|
43
|
+
const index = match.index ?? 0;
|
|
44
|
+
output += line.slice(cursor, index);
|
|
45
|
+
const color = token.startsWith('"')
|
|
46
|
+
? /"\s*$/.test(token) && line.slice(index + token.length).trimStart().startsWith(":")
|
|
47
|
+
? "syntaxVariable"
|
|
48
|
+
: "syntaxString"
|
|
49
|
+
: /^[{}\[\],:]$/.test(token)
|
|
50
|
+
? "syntaxPunctuation"
|
|
51
|
+
: "syntaxType";
|
|
52
|
+
output += theme.fg(color, token);
|
|
53
|
+
cursor = index + token.length;
|
|
54
|
+
}
|
|
55
|
+
return output + line.slice(cursor);
|
|
56
|
+
}
|
|
57
|
+
function getPrimaryTextContent(result) {
|
|
58
|
+
const textContent = result.content.find((item) => item.type === "text");
|
|
59
|
+
return textContent?.type === "text" ? textContent.text : "";
|
|
60
|
+
}
|
|
61
|
+
function colorizeToolOutputLines(outputText, theme, isError) {
|
|
62
|
+
const normalizedLines = trimTrailingBlankLines(replaceTabsForDisplay(sanitizeDisplayText(outputText)).split("\n"));
|
|
63
|
+
const normalizedText = normalizedLines.join("\n");
|
|
64
|
+
if (normalizedText.length === 0)
|
|
65
|
+
return [];
|
|
66
|
+
const isJsonDocument = !isError && isJsonDocumentText(normalizedText);
|
|
67
|
+
return normalizedLines.map((line) => {
|
|
68
|
+
if (line.length === 0) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
if (isJsonDocument)
|
|
72
|
+
return colorizeJsonLine(line, theme);
|
|
73
|
+
return isError ? theme.fg("error", line) : theme.fg("toolOutput", line);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function formatExpandHint(theme) {
|
|
77
|
+
try {
|
|
78
|
+
const [key] = getKeybindings().getKeys("app.tools.expand");
|
|
79
|
+
if (key)
|
|
80
|
+
return `${theme.fg("dim", key)} ${theme.fg("muted", "to expand")}`;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Fall through to the built-in default key when coding-agent keybindings are unavailable.
|
|
84
|
+
}
|
|
85
|
+
return `${theme.fg("dim", "ctrl+o")} ${theme.fg("muted", "to expand")}`;
|
|
86
|
+
}
|
|
87
|
+
function formatVisualTruncationNotice(remainingLines, totalLines, theme, width) {
|
|
88
|
+
const notice = `${theme.fg("muted", `... (${remainingLines} more lines, ${totalLines} total, `)}${formatExpandHint(theme)}${theme.fg("muted", ")")}`;
|
|
89
|
+
return truncateToWidth(notice, Math.max(0, width));
|
|
90
|
+
}
|
|
91
|
+
function getStructuredModeInvocation(input) {
|
|
92
|
+
if (Array.isArray(input.args))
|
|
93
|
+
return { rawArgs: input.args.filter((value) => typeof value === "string") };
|
|
94
|
+
if (input.semanticAction !== undefined)
|
|
95
|
+
return { mode: "semanticAction", rawArgs: compileAgentBrowserSemanticAction(input.semanticAction).compiled?.args ?? [] };
|
|
96
|
+
if (input.job !== undefined)
|
|
97
|
+
return { mode: "job", rawArgs: compileAgentBrowserJob(input.job).compiled?.args ?? [] };
|
|
98
|
+
if (input.qa !== undefined)
|
|
99
|
+
return { mode: "qa", rawArgs: compileAgentBrowserQaPreset(input.qa).compiled?.args ?? [] };
|
|
100
|
+
if (input.sourceLookup !== undefined)
|
|
101
|
+
return { mode: "sourceLookup", rawArgs: compileAgentBrowserSourceLookup(input.sourceLookup).compiled?.args ?? [] };
|
|
102
|
+
if (input.networkSourceLookup !== undefined)
|
|
103
|
+
return { mode: "networkSourceLookup", rawArgs: compileAgentBrowserNetworkSourceLookup(input.networkSourceLookup).compiled?.args ?? [] };
|
|
104
|
+
if (input.electron !== undefined) {
|
|
105
|
+
const electron = compileAgentBrowserElectron(input.electron);
|
|
106
|
+
return { mode: "electron", rawArgs: electron.compiled ? ["electron", electron.compiled.action] : [] };
|
|
107
|
+
}
|
|
108
|
+
return { rawArgs: [] };
|
|
109
|
+
}
|
|
110
|
+
function formatInvocationPreview(rawArgs) {
|
|
111
|
+
const redactedArgs = redactInvocationArgs(rawArgs);
|
|
112
|
+
const invocation = sanitizeDisplayText(redactedArgs.join(" ")).replace(/\s+/g, " ").trim();
|
|
113
|
+
return invocation.length > TUI_INVOCATION_PREVIEW_MAX_CHARS
|
|
114
|
+
? `${invocation.slice(0, TUI_INVOCATION_PREVIEW_MAX_CHARS - 3)}...`
|
|
115
|
+
: invocation;
|
|
116
|
+
}
|
|
117
|
+
export function formatAgentBrowserRenderCall(args, theme) {
|
|
118
|
+
const input = isRecord(args) ? args : {};
|
|
119
|
+
const { mode, rawArgs } = getStructuredModeInvocation(input);
|
|
120
|
+
const invocationPreview = formatInvocationPreview(rawArgs);
|
|
121
|
+
let text = theme.fg("toolTitle", theme.bold("agent_browser"));
|
|
122
|
+
if (mode) {
|
|
123
|
+
text += ` ${theme.fg("accent", mode)}`;
|
|
124
|
+
if (invocationPreview.length > 0) {
|
|
125
|
+
text += ` ${theme.fg("dim", "→")} ${theme.fg("accent", invocationPreview)}`;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (invocationPreview.length > 0) {
|
|
129
|
+
text += ` ${theme.fg("accent", invocationPreview)}`;
|
|
130
|
+
}
|
|
131
|
+
if (input.sessionMode === "fresh") {
|
|
132
|
+
text += theme.fg("dim", " sessionMode=fresh");
|
|
133
|
+
}
|
|
134
|
+
if (typeof input.stdin === "string") {
|
|
135
|
+
text += theme.fg("dim", " + stdin");
|
|
136
|
+
}
|
|
137
|
+
return text;
|
|
138
|
+
}
|
|
139
|
+
export function formatAgentBrowserRenderResult(result, options, theme, isError) {
|
|
140
|
+
if (options.isPartial) {
|
|
141
|
+
return theme.fg("warning", "Running agent-browser...");
|
|
142
|
+
}
|
|
143
|
+
const outputText = getPrimaryTextContent(result);
|
|
144
|
+
const failureCategoryNotice = formatModelVisibleFailureCategoryNotice(result.details);
|
|
145
|
+
const outputLines = colorizeToolOutputLines(outputText, theme, isError);
|
|
146
|
+
if (failureCategoryNotice && outputLines.length > 0) {
|
|
147
|
+
outputLines.unshift(theme.fg("error", failureCategoryNotice), "");
|
|
148
|
+
}
|
|
149
|
+
if (outputLines.length === 0) {
|
|
150
|
+
const details = isRecord(result.details) ? result.details : undefined;
|
|
151
|
+
const rawSummary = typeof details?.summary === "string" ? details.summary : isError ? "agent-browser failed" : "Done";
|
|
152
|
+
const sanitizedSummary = sanitizeDisplayText(rawSummary).trim();
|
|
153
|
+
const summary = sanitizedSummary.length > 0 ? sanitizedSummary : isError ? "agent-browser failed" : "Done";
|
|
154
|
+
return isError ? theme.fg("error", summary) : theme.fg("success", summary);
|
|
155
|
+
}
|
|
156
|
+
return `\n${outputLines.join("\n")}`;
|
|
157
|
+
}
|
|
158
|
+
function formatModelVisibleFailureCategoryNotice(details) {
|
|
159
|
+
if (!isRecord(details) || details.resultCategory !== "failure")
|
|
160
|
+
return undefined;
|
|
161
|
+
const failureCategory = typeof details.failureCategory === "string" && details.failureCategory.length > 0
|
|
162
|
+
? details.failureCategory
|
|
163
|
+
: undefined;
|
|
164
|
+
return `Result category: failure${failureCategory ? `; failureCategory: ${failureCategory}` : ""}; Pi tool isError: true.`;
|
|
165
|
+
}
|
|
166
|
+
function agentBrowserToolResultRequestedJson(event) {
|
|
167
|
+
const details = isRecord(event.details) ? event.details : undefined;
|
|
168
|
+
const detailArgs = Array.isArray(details?.args) ? details.args : undefined;
|
|
169
|
+
const inputArgs = isRecord(event.input) && Array.isArray(event.input.args) ? event.input.args : undefined;
|
|
170
|
+
return detailArgs?.includes("--json") === true || inputArgs?.includes("--json") === true;
|
|
171
|
+
}
|
|
172
|
+
function agentBrowserToolResultHasParseableJsonContent(content) {
|
|
173
|
+
return content.some((item) => {
|
|
174
|
+
if (item.type !== "text" || typeof item.text !== "string")
|
|
175
|
+
return false;
|
|
176
|
+
const text = item.text.trim();
|
|
177
|
+
if (text.length === 0)
|
|
178
|
+
return false;
|
|
179
|
+
try {
|
|
180
|
+
JSON.parse(text);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function appendModelVisibleFailureCategoryNotice(content, notice) {
|
|
189
|
+
const noticeContent = { type: "text", text: notice };
|
|
190
|
+
const textIndex = content.findIndex((item) => item.type === "text" && typeof item.text === "string");
|
|
191
|
+
if (textIndex === -1)
|
|
192
|
+
return [noticeContent, ...content];
|
|
193
|
+
const textItem = content[textIndex];
|
|
194
|
+
if (textItem.type !== "text" || typeof textItem.text !== "string" || textItem.text.includes(notice))
|
|
195
|
+
return undefined;
|
|
196
|
+
return content.map((item, index) => index === textIndex
|
|
197
|
+
? { ...item, text: `${textItem.text}\n\n${notice}` }
|
|
198
|
+
: item);
|
|
199
|
+
}
|
|
200
|
+
export function buildAgentBrowserToolResultPatch(event) {
|
|
201
|
+
if (event.toolName !== "agent_browser")
|
|
202
|
+
return undefined;
|
|
203
|
+
const preservesParseableJson = agentBrowserToolResultRequestedJson(event) && agentBrowserToolResultHasParseableJsonContent(event.content);
|
|
204
|
+
const notice = preservesParseableJson ? undefined : formatModelVisibleFailureCategoryNotice(event.details);
|
|
205
|
+
const content = notice ? appendModelVisibleFailureCategoryNotice(event.content, notice) : undefined;
|
|
206
|
+
const shouldMarkError = isRecord(event.details) && event.details.resultCategory === "failure" && event.isError !== true;
|
|
207
|
+
if (!shouldMarkError && !content)
|
|
208
|
+
return undefined;
|
|
209
|
+
return {
|
|
210
|
+
...(content ? { content } : {}),
|
|
211
|
+
...(shouldMarkError ? { isError: true } : {}),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
export class AgentBrowserResultComponent {
|
|
215
|
+
expanded = false;
|
|
216
|
+
theme;
|
|
217
|
+
text = new Text("", 0, 0);
|
|
218
|
+
setState(value, expanded, theme) {
|
|
219
|
+
this.text.setText(value);
|
|
220
|
+
this.expanded = expanded;
|
|
221
|
+
this.theme = theme;
|
|
222
|
+
}
|
|
223
|
+
render(width) {
|
|
224
|
+
const lines = this.text.render(width);
|
|
225
|
+
if (this.expanded || lines.length <= TUI_COLLAPSED_OUTPUT_MAX_LINES) {
|
|
226
|
+
return lines;
|
|
227
|
+
}
|
|
228
|
+
const theme = this.theme;
|
|
229
|
+
if (!theme) {
|
|
230
|
+
return lines.slice(0, TUI_COLLAPSED_OUTPUT_MAX_LINES);
|
|
231
|
+
}
|
|
232
|
+
const hiddenLineCount = lines.length - TUI_COLLAPSED_OUTPUT_MAX_LINES;
|
|
233
|
+
return [
|
|
234
|
+
...lines.slice(0, TUI_COLLAPSED_OUTPUT_MAX_LINES),
|
|
235
|
+
formatVisualTruncationNotice(hiddenLineCount, lines.length, theme, width),
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
invalidate() {
|
|
239
|
+
this.text.invalidate();
|
|
240
|
+
}
|
|
241
|
+
}
|