pi-agent-browser-native 0.6.9 → 0.6.11
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 +48 -0
- package/README.md +62 -19
- package/dist/extensions/agent-browser/index.js +424 -451
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +6 -7
- package/dist/extensions/agent-browser/lib/argv-grammar.js +7 -1
- package/dist/extensions/agent-browser/lib/batch-lifecycle.js +4 -8
- package/dist/extensions/agent-browser/lib/command-policy.js +41 -2
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +15 -2
- package/dist/extensions/agent-browser/lib/input-modes/params.js +1 -1
- package/dist/extensions/agent-browser/lib/input-modes/script.js +3 -2
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +42 -12
- package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +3 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +6 -14
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +14 -25
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +12 -6
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +3 -2
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +38 -31
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +60 -20
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +161 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +5 -5
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +2 -4
- package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +68 -0
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +41 -6
- package/dist/extensions/agent-browser/lib/page-target-validation.js +9 -5
- package/dist/extensions/agent-browser/lib/playbook.js +13 -12
- package/dist/extensions/agent-browser/lib/process-environment.js +26 -8
- package/dist/extensions/agent-browser/lib/process.js +8 -5
- package/dist/extensions/agent-browser/lib/read-confirmation.js +59 -0
- package/dist/extensions/agent-browser/lib/recording-reservations.js +11 -1
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +8 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +6 -5
- package/dist/extensions/agent-browser/lib/results/categories.js +4 -2
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +76 -57
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +19 -8
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +5 -25
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +40 -38
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +1 -0
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +3 -3
- package/dist/extensions/agent-browser/lib/results/presentation.js +38 -9
- package/dist/extensions/agent-browser/lib/results/recording.js +50 -0
- package/dist/extensions/agent-browser/lib/runtime.js +72 -20
- package/dist/extensions/agent-browser/lib/session-page-state.js +24 -8
- package/dist/extensions/agent-browser/lib/temp.js +4 -0
- package/dist/scripts/agent-browser-target.mjs +1 -1
- package/docs/ARCHITECTURE.md +29 -12
- package/docs/COMMAND_REFERENCE.md +67 -31
- package/docs/RELEASE.md +6 -4
- package/docs/SUPPORT_MATRIX.md +24 -16
- package/docs/TOOL_CONTRACT.md +82 -28
- package/package.json +1 -1
- package/scripts/agent-browser-capability-baseline.mjs +10 -3
- package/scripts/agent-browser-target.mjs +1 -1
- package/scripts/prepare.mjs +2 -4
|
@@ -5,14 +5,15 @@ import { Text } from "@earendil-works/pi-tui";
|
|
|
5
5
|
import { batchHasSuccessfulCloseAll, getSuccessfulBatchCloseLifecycle } from "./lib/batch-lifecycle.js";
|
|
6
6
|
import { PROJECT_RULE_PROMPT, buildBrowserDefaultProfileGuideline, buildBrowserExecutablePathGuideline, buildToolPromptGuidelines, } from "./lib/playbook.js";
|
|
7
7
|
import { SessionPageState } from "./lib/session-page-state.js";
|
|
8
|
-
import { buildExecutionPlan, canUseHeadlessCompatibilityUserAgent, createEphemeralSessionSeed, createFreshSessionName, createImplicitSessionName, extractUpstreamCommandTokens, getImplicitSessionCloseTimeoutMs, getImplicitSessionIdleTimeoutMs, isRestorableManagedSessionName, restoreManagedSessionStateFromBranch, validateToolArgs, redactSensitiveText, isPlainTextInspectionArgs, } from "./lib/runtime.js";
|
|
9
|
-
import { extractExplicitNamespace, extractExplicitSessionName, getAgentBrowserSessionIdentityKey, isAgentBrowserSessionIdentityKeyInNamespace, isUpstreamEnvFlagEnabled, resolveAgentBrowserNamespace } from "./lib/argv-grammar.js";
|
|
8
|
+
import { buildExecutionPlan, canUseHeadlessCompatibilityUserAgent, createEphemeralSessionSeed, createFreshSessionName, createImplicitSessionName, extractUpstreamCommandTokens, getImplicitSessionCloseTimeoutMs, getImplicitSessionIdleTimeoutMs, isRestorableManagedSessionName, restoreManagedSessionStateFromBranch, validateToolArgs, redactSensitiveText, redactSensitiveValue, isPlainTextInspectionArgs, } from "./lib/runtime.js";
|
|
9
|
+
import { deleteIdentityKeysInNamespace, extractExplicitNamespace, extractExplicitSessionName, getAgentBrowserSessionIdentityKey, isAgentBrowserSessionIdentityKeyInNamespace, isUpstreamEnvFlagEnabled, resolveAgentBrowserNamespace } from "./lib/argv-grammar.js";
|
|
10
10
|
import { parseArgvDescriptor } from "./lib/argv-descriptor.js";
|
|
11
11
|
import { needsManagedSession } from "./lib/command-policy.js";
|
|
12
12
|
import { ManagedSessionRestoreState } from "./lib/managed-session-restore.js";
|
|
13
13
|
import { isRecord } from "./lib/parsing.js";
|
|
14
14
|
import { runAgentBrowserProcess } from "./lib/process.js";
|
|
15
15
|
import { getAgentBrowserProcessEnvironment, withIsolatedAgentBrowserEnvironment } from "./lib/process-environment.js";
|
|
16
|
+
import { withNativeSessionDefaults } from "./lib/orchestration/native-session-defaults.js";
|
|
16
17
|
import { MINIMUM_AGENT_BROWSER_VERSION, SUPPORTED_AGENT_BROWSER_VERSION_LABEL, TARGET_AGENT_BROWSER_VERSION, getAgentBrowserVersionValidationError, parseAgentBrowserVersionOutput, } from "./lib/upstream-version.js";
|
|
17
18
|
import { buildPromptPolicy, getLatestUserPrompt, shouldAppendBrowserSystemPrompt } from "./lib/prompt-policy.js";
|
|
18
19
|
import { isCloseAllCommand, isCloseCommand } from "./lib/command-taxonomy.js";
|
|
@@ -26,13 +27,14 @@ import { findElectronLaunchRecordForSession, getActiveElectronRecords } from "./
|
|
|
26
27
|
import { parseBatchCommandArgument, parseUserBatchStdin } from "./lib/orchestration/batch-stdin.js";
|
|
27
28
|
import { ELECTRON_POST_COMMAND_STATUS_SETTLE_MS, ELECTRON_PROFILE_ISOLATION_DETAILS, cleanupActiveElectronHostLaunches, handleElectronHostInput, restoreElectronLaunchRecordsFromBranch, } from "./lib/orchestration/electron-host/index.js";
|
|
28
29
|
import { buildValidationFailureResult, resolveAgentBrowserInput } from "./lib/orchestration/input-plan.js";
|
|
29
|
-
import { applyAgentBrowserOutputPath, normalizeRequestedOutputPath } from "./lib/orchestration/output-file.js";
|
|
30
|
+
import { applyAgentBrowserOutputPath, canWriteAgentBrowserOutput, normalizeRequestedOutputPath } from "./lib/orchestration/output-file.js";
|
|
30
31
|
import { appendScriptSessionLease, buildScriptBrowserEnvelope, buildScriptToolResult, getScriptSessionLeasesFromBranch } from "./lib/orchestration/script-mode.js";
|
|
31
32
|
import { formatSessionArtifactRetentionSummary, getSessionArtifactManifestEntryKey, isPendingRecordingCommand, isSessionArtifactManifest, mergeSessionArtifactManifest, retirePendingRecordingManifestEntries } from "./lib/results/artifact-manifest.js";
|
|
32
33
|
import { appendUniqueAgentBrowserNextActions, applyNamespaceToNextActions, applySessionToNextActions, buildNextToolAction } from "./lib/results/next-actions.js";
|
|
33
34
|
import { canRegisterWebSearchTool, loadAgentBrowserConfigSync } from "./lib/config.js";
|
|
34
35
|
import { appendRecordingReservationTransition, applyRecordingArtifactsToReservations, restoreRecordingReservationStateFromBranch, retireRecordingReservation, } from "./lib/recording-reservations.js";
|
|
35
36
|
import { createAgentBrowserWebSearchTool } from "./lib/web-search.js";
|
|
37
|
+
import { scopeReadConfirmationArgs } from "./lib/read-confirmation.js";
|
|
36
38
|
import { isDirectAgentBrowserBashAllowed, isHarmlessAgentBrowserInspectionCommand, looksLikeDirectAgentBrowserBash, } from "./lib/bash-guard.js";
|
|
37
39
|
import { AgentBrowserResultComponent, buildAgentBrowserToolResultPatch, formatAgentBrowserRenderCall, formatAgentBrowserRenderResult, } from "./lib/pi-tool-rendering.js";
|
|
38
40
|
function isBashToolCallEvent(event) {
|
|
@@ -67,7 +69,7 @@ function getArtifactPreflightValidationError(options) {
|
|
|
67
69
|
return error;
|
|
68
70
|
const activeRecordingDestinations = new Set();
|
|
69
71
|
const cleanupOnly = steps.length > 0 && steps.every((step) => {
|
|
70
|
-
const [command, subcommand] =
|
|
72
|
+
const [command, subcommand] = step;
|
|
71
73
|
return isCloseCommand(command) || (command === "record" && subcommand === "stop");
|
|
72
74
|
});
|
|
73
75
|
for (const reservation of options.activeRecordingReservations ?? []) {
|
|
@@ -93,10 +95,9 @@ function getArtifactPreflightValidationError(options) {
|
|
|
93
95
|
}
|
|
94
96
|
const artifactDestinations = new Map();
|
|
95
97
|
let sawBatchClose = false;
|
|
96
|
-
for (const [index,
|
|
97
|
-
const commandStep = extractUpstreamCommandTokens(step);
|
|
98
|
+
for (const [index, commandStep] of steps.entries()) {
|
|
98
99
|
if (batch) {
|
|
99
|
-
const stepValidationError = validateToolArgs(
|
|
100
|
+
const stepValidationError = validateToolArgs(commandStep, { batchStep: true });
|
|
100
101
|
if (stepValidationError)
|
|
101
102
|
return `Unsupported batch step ${index + 1}: ${stepValidationError}`;
|
|
102
103
|
if (sawBatchClose && commandStep[0] === "record" && (commandStep[1] === "start" || commandStep[1] === "restart")) {
|
|
@@ -127,7 +128,7 @@ function getArtifactPreflightValidationError(options) {
|
|
|
127
128
|
}
|
|
128
129
|
artifactDestinations.set(canonicalDestination, index);
|
|
129
130
|
}
|
|
130
|
-
if (batch && commandStep[0] === "screenshot" &&
|
|
131
|
+
if (batch && commandStep[0] === "screenshot" && commandStep.includes("--annotate")) {
|
|
131
132
|
return [
|
|
132
133
|
`Unsupported batch screenshot annotation in step ${index + 1}: put --annotate in top-level args, not inside the batch step.`,
|
|
133
134
|
`Use: { "args": ["--annotate", "batch"], "stdin": "[[\\"screenshot\\",\\"/path/to/image.png\\"]]" }`,
|
|
@@ -138,7 +139,7 @@ function getArtifactPreflightValidationError(options) {
|
|
|
138
139
|
}
|
|
139
140
|
function commandClosesAllSessions(args, stdin) {
|
|
140
141
|
const parsed = getArtifactCommandSteps(args, stdin);
|
|
141
|
-
return !parsed.error && parsed.steps.some(
|
|
142
|
+
return !parsed.error && parsed.steps.some(isCloseAllCommand);
|
|
142
143
|
}
|
|
143
144
|
function commandTouchesArtifactLifecycle(args, stdin, outputPath) {
|
|
144
145
|
if (outputPath)
|
|
@@ -146,10 +147,7 @@ function commandTouchesArtifactLifecycle(args, stdin, outputPath) {
|
|
|
146
147
|
const parsed = getArtifactCommandSteps(args, stdin);
|
|
147
148
|
if (parsed.error)
|
|
148
149
|
return true;
|
|
149
|
-
return parsed.steps.some((step) =>
|
|
150
|
-
const commandStep = extractUpstreamCommandTokens(step);
|
|
151
|
-
return getExplicitArtifactDestination(commandStep) !== undefined || commandStep[0] === "record" || commandStep[0] === "screenshot" || isCloseCommand(commandStep[0]);
|
|
152
|
-
});
|
|
150
|
+
return parsed.steps.some((step) => getExplicitArtifactDestination(step) !== undefined || step[0] === "record" || step[0] === "screenshot" || isCloseCommand(step[0]));
|
|
153
151
|
}
|
|
154
152
|
function isResultFileArtifact(artifact) {
|
|
155
153
|
return isRecord(artifact)
|
|
@@ -161,26 +159,6 @@ function getResultFileArtifacts(result) {
|
|
|
161
159
|
const details = isRecord(result.details) ? result.details : undefined;
|
|
162
160
|
return Array.isArray(details?.artifacts) ? details.artifacts.filter(isResultFileArtifact) : [];
|
|
163
161
|
}
|
|
164
|
-
function reportsNoRecordingInProgress(value) {
|
|
165
|
-
try {
|
|
166
|
-
return /no recording in progress/i.test(JSON.stringify(value));
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
function batchStepReportsNoRecordingInProgress(step) {
|
|
173
|
-
if (!isRecord(step) || step.success !== false)
|
|
174
|
-
return false;
|
|
175
|
-
const command = Array.isArray(step.command) && step.command.every((token) => typeof token === "string") ? extractUpstreamCommandTokens(step.command) : [];
|
|
176
|
-
return command[0] === "record" && command[1] === "stop" && reportsNoRecordingInProgress(step);
|
|
177
|
-
}
|
|
178
|
-
function resultReportsNoRecordingInProgress(result) {
|
|
179
|
-
if (result.isError !== true)
|
|
180
|
-
return false;
|
|
181
|
-
const details = isRecord(result.details) ? result.details : undefined;
|
|
182
|
-
return details?.command === "record" && details.subcommand === "stop" && reportsNoRecordingInProgress(result.content);
|
|
183
|
-
}
|
|
184
162
|
function restoreArtifactManifestFromBranch(branch) {
|
|
185
163
|
let restoredManifest;
|
|
186
164
|
for (const entry of branch) {
|
|
@@ -299,12 +277,6 @@ function detailsReportCloseAllApplied(details, succeeded) {
|
|
|
299
277
|
|| (succeeded && isCloseAllCommand(extractUpstreamCommandTokens(args)))
|
|
300
278
|
|| batchHasSuccessfulCloseAll(details.batchSteps);
|
|
301
279
|
}
|
|
302
|
-
function deleteIdentityKeysInNamespace(entries, namespace) {
|
|
303
|
-
for (const key of entries.keys()) {
|
|
304
|
-
if (isAgentBrowserSessionIdentityKeyInNamespace(key, namespace))
|
|
305
|
-
entries.delete(key);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
280
|
function isAttachedBrowserInvocation(args, env = getAgentBrowserProcessEnvironment()) {
|
|
309
281
|
const autoConnectEnv = env.AGENT_BROWSER_AUTO_CONNECT;
|
|
310
282
|
return extractUpstreamCommandTokens(args)[0] === "connect"
|
|
@@ -663,9 +635,6 @@ async function closeOwnedManagedSessionsExcept(sessions, restoreState, keepSessi
|
|
|
663
635
|
}
|
|
664
636
|
}
|
|
665
637
|
}
|
|
666
|
-
async function closeOwnedManagedSessions(sessions, restoreState, timeoutMs, attachedSessionKeys, onClosed) {
|
|
667
|
-
await closeOwnedManagedSessionsExcept(sessions, restoreState, undefined, timeoutMs, attachedSessionKeys, undefined, onClosed);
|
|
668
|
-
}
|
|
669
638
|
function getOffBranchOwnedElectronLaunchRecords(ownedRecords, branchRecords) {
|
|
670
639
|
const activeBranchLaunchIds = new Set(getActiveElectronRecords(branchRecords).map((record) => record.launchId));
|
|
671
640
|
const offBranchRecords = new Map();
|
|
@@ -814,7 +783,7 @@ function shouldIncludeProjectConfig(ctx, argv = process.argv) {
|
|
|
814
783
|
return false;
|
|
815
784
|
return ctx?.isProjectTrusted?.() ?? true;
|
|
816
785
|
}
|
|
817
|
-
export default function agentBrowserExtension(pi) {
|
|
786
|
+
export default function agentBrowserExtension(pi, { beforeExecute } = {}) {
|
|
818
787
|
const ephemeralSessionSeed = createEphemeralSessionSeed();
|
|
819
788
|
const agentBrowserConfig = loadAgentBrowserConfigSync({
|
|
820
789
|
cwd: process.cwd(),
|
|
@@ -926,6 +895,8 @@ export default function agentBrowserExtension(pi) {
|
|
|
926
895
|
if (result.isError !== true)
|
|
927
896
|
return result;
|
|
928
897
|
const details = isRecord(result.details) ? result.details : {};
|
|
898
|
+
if (details.recordingRecovery)
|
|
899
|
+
return result;
|
|
929
900
|
const cleanupOnly = details.managedSessionCleanupOnlyReason === "restore-disabled-daemon-without-provenance";
|
|
930
901
|
const nextActions = (Array.isArray(details.nextActions) ? details.nextActions : [])
|
|
931
902
|
.filter((action) => !cleanupOnly || action.id !== "stop-pending-recording");
|
|
@@ -986,12 +957,6 @@ export default function agentBrowserExtension(pi) {
|
|
|
986
957
|
const command = Array.isArray(step.command) && step.command.every((token) => typeof token === "string") ? step.command : undefined;
|
|
987
958
|
const commandTokens = command ? extractUpstreamCommandTokens(command) : [];
|
|
988
959
|
const commandName = commandTokens[0];
|
|
989
|
-
if (resultSessionName && batchStepReportsNoRecordingInProgress(step)) {
|
|
990
|
-
const sessionKey = getAgentBrowserSessionIdentityKey(resultSessionName, resultNamespace);
|
|
991
|
-
retireRecordingSession(resultSessionName, resultNamespace, false);
|
|
992
|
-
handledClosedSessionKeys.add(sessionKey);
|
|
993
|
-
continue;
|
|
994
|
-
}
|
|
995
960
|
if (step.success === true && commandName && isCloseCommand(commandName) && resultSessionName) {
|
|
996
961
|
const sessionKey = getAgentBrowserSessionIdentityKey(resultSessionName, resultNamespace);
|
|
997
962
|
retireRecordingSession(resultSessionName, resultNamespace, false);
|
|
@@ -1161,7 +1126,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
1161
1126
|
}
|
|
1162
1127
|
for (const [key, reservation] of activeRecordingReservations) {
|
|
1163
1128
|
const restored = restoredRecordingState.active.get(key);
|
|
1164
|
-
if (restored?.absolutePath !== reservation.absolutePath || restored.cwd !== reservation.cwd)
|
|
1129
|
+
if (restored?.absolutePath !== reservation.absolutePath || restored.cwd !== reservation.cwd || restored.recordingId !== reservation.recordingId || restored.startedAtMs !== reservation.startedAtMs)
|
|
1165
1130
|
recordingReservationsDirty = true;
|
|
1166
1131
|
restoredRecordingState.active.set(key, reservation);
|
|
1167
1132
|
}
|
|
@@ -1308,7 +1273,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
1308
1273
|
for (const identity of getCleanupResultsClosedManagedSessionIdentities(electronCleanupResults))
|
|
1309
1274
|
retireRecordingSession(identity.sessionName, identity.namespace);
|
|
1310
1275
|
if (quitting) {
|
|
1311
|
-
await
|
|
1276
|
+
await closeOwnedManagedSessionsExcept(ownedManagedSessions, managedSessionRestoreState, undefined, implicitSessionCloseTimeoutMs, attachedSessionKeys, undefined, (owner) => retireRecordingSession(owner.sessionName, owner.namespace));
|
|
1312
1277
|
}
|
|
1313
1278
|
else {
|
|
1314
1279
|
await closeOwnedManagedSessionsExcept(ownedManagedSessions, managedSessionRestoreState, managedSessionActive ? managedSessionName : undefined, implicitSessionCloseTimeoutMs, attachedSessionKeys, managedSessionActive ? managedSessionNamespace : undefined, (owner) => retireRecordingSession(owner.sessionName, owner.namespace));
|
|
@@ -1393,445 +1358,453 @@ export default function agentBrowserExtension(pi) {
|
|
|
1393
1358
|
component.setState(formatAgentBrowserRenderResult(result, options, theme, context.isError), options.expanded, theme);
|
|
1394
1359
|
return component;
|
|
1395
1360
|
},
|
|
1396
|
-
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
1361
|
+
async execute(toolCallId, params, signal, onUpdate, ctx, nativeToolCallId = toolCallId) {
|
|
1397
1362
|
const promptPolicy = buildPromptPolicy(getLatestUserPrompt(ctx.sessionManager.getBranch()));
|
|
1398
1363
|
const outputPath = isRecord(params) && typeof params.outputPath === "string" ? params.outputPath : undefined;
|
|
1399
1364
|
const resolvedInput = resolveAgentBrowserInput({
|
|
1400
1365
|
getBatchPreflightValidationError: (args, stdin) => getArtifactPreflightValidationError({ args, cwd: ctx.cwd, outputPath, stdin }),
|
|
1401
|
-
managedSessionActive,
|
|
1402
1366
|
params,
|
|
1403
1367
|
});
|
|
1404
1368
|
if (resolvedInput.status === "invalid") {
|
|
1405
1369
|
return buildValidationFailureResult(resolvedInput);
|
|
1406
1370
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
cwd: ctx.cwd,
|
|
1416
|
-
outputPath,
|
|
1417
|
-
});
|
|
1418
|
-
if (reservationError) {
|
|
1419
|
-
return warnRecordingPersistence(buildValidationFailureResult({ attemptedKind: resolvedInput.kind, kind: "invalid", redactedArgs: resolvedInput.redactedArgs, status: "invalid", toolArgs: resolvedInput.toolArgs, toolStdin: resolvedInput.toolStdin, validationError: reservationError }));
|
|
1420
|
-
}
|
|
1421
|
-
return applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, preserveTextContent, result: warnRecordingPersistence(result) });
|
|
1422
|
-
});
|
|
1423
|
-
};
|
|
1424
|
-
const versionCheckCommand = extractUpstreamCommandTokens(resolvedInput.toolArgs)[0];
|
|
1425
|
-
const electronHostOnlyAction = resolvedInput.kind === "electron" && ["cleanup", "list", "status"].includes(resolvedInput.compiledElectron.action);
|
|
1426
|
-
const browserBackedVersionCheck = needsManagedSession(parseArgvDescriptor(resolvedInput.toolArgs));
|
|
1427
|
-
if (resolvedInput.kind !== "script" && !electronHostOnlyAction && browserBackedVersionCheck && !isPlainTextInspectionArgs(resolvedInput.toolArgs) && !isCloseCommand(versionCheckCommand) && signal?.aborted !== true) {
|
|
1428
|
-
const versionFailure = await validateUpstreamVersion(ctx.cwd, signal);
|
|
1429
|
-
if (versionFailure)
|
|
1430
|
-
return applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, result: versionFailure });
|
|
1431
|
-
}
|
|
1432
|
-
if (resolvedInput.kind === "script") {
|
|
1433
|
-
if (!ctx.sessionManager.getSessionFile()) {
|
|
1434
|
-
return buildValidationFailureResult({
|
|
1435
|
-
attemptedKind: "script",
|
|
1436
|
-
kind: "invalid",
|
|
1437
|
-
redactedArgs: [],
|
|
1438
|
-
status: "invalid",
|
|
1439
|
-
toolArgs: [],
|
|
1440
|
-
validationError: "script requires a persisted Pi session so its isolated browser-session cleanup lease survives restart; relaunch Pi without --no-session.",
|
|
1441
|
-
});
|
|
1371
|
+
if (resolvedInput.kind !== "script")
|
|
1372
|
+
await beforeExecute?.(nativeToolCallId, { ...ctx, signal });
|
|
1373
|
+
return withNativeSessionDefaults(resolvedInput, ctx.cwd, signal, async (resolvedInput) => {
|
|
1374
|
+
const readConfirmation = sessionPageState.findReadConfirmation(resolvedInput.toolArgs, resolveAgentBrowserNamespace(resolvedInput.toolArgs, getAgentBrowserProcessEnvironment().AGENT_BROWSER_NAMESPACE));
|
|
1375
|
+
if (readConfirmation)
|
|
1376
|
+
resolvedInput = { ...resolvedInput, toolArgs: scopeReadConfirmationArgs(resolvedInput.toolArgs, readConfirmation) };
|
|
1377
|
+
if (resolvedInput.kind === "qa" && resolvedInput.compiledQaPreset.checks.attached && !managedSessionActive && !extractExplicitSessionName(resolvedInput.toolArgs)) {
|
|
1378
|
+
return buildValidationFailureResult({ ...resolvedInput, attemptedKind: "qa", kind: "invalid", status: "invalid", validationError: "qa.attached requires an active attached session. Run electron.launch or connect to an Electron debug port first, or configure a native shared session." });
|
|
1442
1379
|
}
|
|
1443
|
-
const
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1380
|
+
const applyUnserializedOutputPath = async (result, preserveTextContent = false) => {
|
|
1381
|
+
if (!outputPath || !canWriteAgentBrowserOutput(result))
|
|
1382
|
+
return warnRecordingPersistence(result);
|
|
1383
|
+
return artifactExecutionQueue.run(async () => {
|
|
1384
|
+
flushRecordingReservations();
|
|
1385
|
+
const reservationError = getArtifactPreflightValidationError({
|
|
1386
|
+
activeRecordingReservations: activeRecordingReservations.values(),
|
|
1387
|
+
args: [],
|
|
1388
|
+
cwd: ctx.cwd,
|
|
1389
|
+
outputPath,
|
|
1390
|
+
});
|
|
1391
|
+
if (reservationError) {
|
|
1392
|
+
return warnRecordingPersistence(buildValidationFailureResult({ attemptedKind: resolvedInput.kind, kind: "invalid", redactedArgs: resolvedInput.redactedArgs, status: "invalid", toolArgs: resolvedInput.toolArgs, toolStdin: resolvedInput.toolStdin, validationError: reservationError }));
|
|
1393
|
+
}
|
|
1394
|
+
return applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, preserveTextContent, result: warnRecordingPersistence(result) });
|
|
1395
|
+
});
|
|
1457
1396
|
};
|
|
1458
|
-
const
|
|
1459
|
-
const
|
|
1460
|
-
|
|
1461
|
-
if (signal?.aborted)
|
|
1462
|
-
|
|
1463
|
-
activeScriptControllers.add(scriptController);
|
|
1464
|
-
let finishScriptExecution;
|
|
1465
|
-
const scriptExecution = new Promise((resolve) => {
|
|
1466
|
-
finishScriptExecution = resolve;
|
|
1467
|
-
});
|
|
1468
|
-
activeScriptExecutions.add(scriptExecution);
|
|
1469
|
-
try {
|
|
1470
|
-
// Keep preflight inside shutdown tracking so quit cannot race into starting the sandbox afterward.
|
|
1471
|
-
const versionFailure = await withIsolatedAgentBrowserEnvironment(() => validateUpstreamVersion(ctx.cwd, scriptController.signal));
|
|
1397
|
+
const versionCheckCommand = extractUpstreamCommandTokens(resolvedInput.toolArgs)[0];
|
|
1398
|
+
const electronHostOnlyAction = resolvedInput.kind === "electron" && ["cleanup", "list", "status"].includes(resolvedInput.compiledElectron.action);
|
|
1399
|
+
const browserBackedVersionCheck = readConfirmation?.capabilities?.readRequiresConfirmation !== true && needsManagedSession(parseArgvDescriptor(resolvedInput.toolArgs), resolvedInput.toolStdin);
|
|
1400
|
+
if (resolvedInput.kind !== "script" && !electronHostOnlyAction && browserBackedVersionCheck && !isPlainTextInspectionArgs(resolvedInput.toolArgs) && !isCloseCommand(versionCheckCommand) && signal?.aborted !== true) {
|
|
1401
|
+
const versionFailure = await validateUpstreamVersion(ctx.cwd, signal);
|
|
1472
1402
|
if (versionFailure)
|
|
1473
1403
|
return applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, result: versionFailure });
|
|
1474
|
-
const pendingRun = runAgentBrowserScript({
|
|
1475
|
-
beforeFirstCall() {
|
|
1476
|
-
appendScriptSessionLease(pi, sessionName, "active");
|
|
1477
|
-
trackOwnedManagedSession(ownedManagedSessions, sessionName, ctx.cwd, { namespace: AGENT_BROWSER_SCRIPT_NAMESPACE });
|
|
1478
|
-
managedSessionRestoreState.disable(sessionName, AGENT_BROWSER_SCRIPT_NAMESPACE);
|
|
1479
|
-
leased = true;
|
|
1480
|
-
},
|
|
1481
|
-
code: resolvedInput.compiledScript.code,
|
|
1482
|
-
dispatch: async (innerParams, innerSignal) => {
|
|
1483
|
-
const remainingMs = Math.max(1, deadline - Date.now());
|
|
1484
|
-
const innerTimeoutMs = Math.min(innerParams.timeoutMs ?? remainingMs, remainingMs);
|
|
1485
|
-
const innerResult = await withIsolatedAgentBrowserEnvironment(() => agentBrowserTool.execute(`${toolCallId}:script:${innerResults.length + 1}`, {
|
|
1486
|
-
args: ["--namespace", AGENT_BROWSER_SCRIPT_NAMESPACE, "--session", sessionName, ...innerParams.args],
|
|
1487
|
-
stdin: innerParams.stdin,
|
|
1488
|
-
timeoutMs: innerTimeoutMs,
|
|
1489
|
-
}, innerSignal, undefined, ctx));
|
|
1490
|
-
innerResults.push(innerResult);
|
|
1491
|
-
return await buildScriptBrowserEnvelope(innerResult, innerParams.args, sessionName);
|
|
1492
|
-
},
|
|
1493
|
-
signal: scriptController.signal,
|
|
1494
|
-
timeoutMs: scriptTimeoutMs,
|
|
1495
|
-
});
|
|
1496
|
-
run = await pendingRun;
|
|
1497
1404
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
}
|
|
1509
|
-
catch {
|
|
1510
|
-
cleanupError = "The isolated script session cleanup operation failed.";
|
|
1511
|
-
try {
|
|
1512
|
-
appendScriptSessionLease(pi, sessionName, "failed");
|
|
1513
|
-
}
|
|
1514
|
-
catch { }
|
|
1515
|
-
}
|
|
1405
|
+
if (resolvedInput.kind === "script") {
|
|
1406
|
+
if (!ctx.sessionManager.getSessionFile()) {
|
|
1407
|
+
return buildValidationFailureResult({
|
|
1408
|
+
attemptedKind: "script",
|
|
1409
|
+
kind: "invalid",
|
|
1410
|
+
redactedArgs: [],
|
|
1411
|
+
status: "invalid",
|
|
1412
|
+
toolArgs: [],
|
|
1413
|
+
validationError: "script requires a persisted Pi session so its isolated browser-session cleanup lease survives restart; relaunch Pi without --no-session.",
|
|
1414
|
+
});
|
|
1516
1415
|
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1416
|
+
const sessionName = createAgentBrowserScriptSessionName();
|
|
1417
|
+
const innerResults = [];
|
|
1418
|
+
const scriptTimeoutMs = params.timeoutMs ?? AGENT_BROWSER_SCRIPT_DEFAULT_TIMEOUT_MS;
|
|
1419
|
+
const deadline = Date.now() + scriptTimeoutMs;
|
|
1420
|
+
let leased = false;
|
|
1421
|
+
let cleanupError;
|
|
1422
|
+
let run = {
|
|
1423
|
+
callCount: 0,
|
|
1424
|
+
emitCount: 0,
|
|
1425
|
+
error: "Script sandbox execution failed.",
|
|
1426
|
+
failureCategory: "upstream-error",
|
|
1427
|
+
ok: false,
|
|
1428
|
+
rejectedCallCount: 0,
|
|
1429
|
+
steps: [],
|
|
1529
1430
|
};
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1431
|
+
const scriptController = new AbortController();
|
|
1432
|
+
const abortScript = () => scriptController.abort();
|
|
1433
|
+
signal?.addEventListener("abort", abortScript, { once: true });
|
|
1434
|
+
if (signal?.aborted)
|
|
1435
|
+
scriptController.abort();
|
|
1436
|
+
activeScriptControllers.add(scriptController);
|
|
1437
|
+
let finishScriptExecution;
|
|
1438
|
+
const scriptExecution = new Promise((resolve) => {
|
|
1439
|
+
finishScriptExecution = resolve;
|
|
1440
|
+
});
|
|
1441
|
+
activeScriptExecutions.add(scriptExecution);
|
|
1442
|
+
try {
|
|
1443
|
+
// Keep preflight inside shutdown tracking so quit cannot race into starting the sandbox afterward.
|
|
1444
|
+
const versionFailure = await withIsolatedAgentBrowserEnvironment(() => validateUpstreamVersion(ctx.cwd, scriptController.signal));
|
|
1445
|
+
if (versionFailure)
|
|
1446
|
+
return applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, result: versionFailure });
|
|
1447
|
+
const pendingRun = runAgentBrowserScript({
|
|
1448
|
+
beforeFirstCall() {
|
|
1449
|
+
appendScriptSessionLease(pi, sessionName, "active");
|
|
1450
|
+
trackOwnedManagedSession(ownedManagedSessions, sessionName, ctx.cwd, { namespace: AGENT_BROWSER_SCRIPT_NAMESPACE });
|
|
1451
|
+
managedSessionRestoreState.disable(sessionName, AGENT_BROWSER_SCRIPT_NAMESPACE);
|
|
1452
|
+
// This fresh, unselectable lease owns any daemon its first read starts.
|
|
1453
|
+
managedSessionRestoreState.recordDaemonRestoreKey(sessionName, AGENT_BROWSER_SCRIPT_NAMESPACE, null);
|
|
1454
|
+
leased = true;
|
|
1455
|
+
},
|
|
1456
|
+
code: resolvedInput.compiledScript.code,
|
|
1457
|
+
dispatch: async (innerParams, innerSignal) => {
|
|
1458
|
+
const remainingMs = Math.max(1, deadline - Date.now());
|
|
1459
|
+
const innerTimeoutMs = Math.min(innerParams.timeoutMs ?? remainingMs, remainingMs);
|
|
1460
|
+
const innerResult = await withIsolatedAgentBrowserEnvironment(() => agentBrowserTool.execute(`${toolCallId}:script:${innerResults.length + 1}`, {
|
|
1461
|
+
args: ["--namespace", AGENT_BROWSER_SCRIPT_NAMESPACE, "--session", sessionName, ...innerParams.args],
|
|
1462
|
+
stdin: innerParams.stdin,
|
|
1463
|
+
timeoutMs: innerTimeoutMs,
|
|
1464
|
+
}, innerSignal, undefined, ctx, nativeToolCallId));
|
|
1465
|
+
innerResults.push(innerResult);
|
|
1466
|
+
return await buildScriptBrowserEnvelope(innerResult, innerParams.args, sessionName);
|
|
1467
|
+
},
|
|
1468
|
+
signal: scriptController.signal,
|
|
1469
|
+
timeoutMs: scriptTimeoutMs,
|
|
1470
|
+
});
|
|
1471
|
+
run = await pendingRun;
|
|
1571
1472
|
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
managedSessionName = createFreshSessionName(managedSessionBaseName, ephemeralSessionSeed, freshSessionOrdinal);
|
|
1473
|
+
catch { }
|
|
1474
|
+
finally {
|
|
1475
|
+
activeScriptControllers.delete(scriptController);
|
|
1476
|
+
signal?.removeEventListener("abort", abortScript);
|
|
1477
|
+
if (leased) {
|
|
1478
|
+
try {
|
|
1479
|
+
cleanupError = await artifactExecutionQueue.run(() => managedSessionExecutionQueue.run(() => {
|
|
1480
|
+
flushRecordingReservations();
|
|
1481
|
+
return closeScriptSessionLeaseWithinQueue(sessionName, ctx.cwd);
|
|
1482
|
+
}));
|
|
1483
|
+
}
|
|
1484
|
+
catch {
|
|
1485
|
+
cleanupError = "The isolated script session cleanup operation failed.";
|
|
1486
|
+
try {
|
|
1487
|
+
appendScriptSessionLease(pi, sessionName, "failed");
|
|
1488
|
+
}
|
|
1489
|
+
catch { }
|
|
1490
|
+
}
|
|
1591
1491
|
}
|
|
1492
|
+
activeScriptExecutions.delete(scriptExecution);
|
|
1493
|
+
finishScriptExecution();
|
|
1592
1494
|
}
|
|
1495
|
+
let scriptResult = buildScriptToolResult({ cleanupError, innerResults, run, sessionName: leased ? sessionName : undefined });
|
|
1593
1496
|
if (artifactManifest) {
|
|
1594
|
-
|
|
1595
|
-
...
|
|
1497
|
+
scriptResult = {
|
|
1498
|
+
...scriptResult,
|
|
1596
1499
|
details: {
|
|
1597
|
-
...(isRecord(
|
|
1598
|
-
artifactManifest,
|
|
1500
|
+
...(isRecord(scriptResult.details) ? scriptResult.details : {}),
|
|
1501
|
+
artifactManifest: redactSensitiveValue(artifactManifest),
|
|
1599
1502
|
artifactRetentionSummary: formatSessionArtifactRetentionSummary(artifactManifest),
|
|
1600
1503
|
},
|
|
1601
1504
|
};
|
|
1602
1505
|
}
|
|
1506
|
+
return applyUnserializedOutputPath(scriptResult);
|
|
1603
1507
|
}
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1508
|
+
const { toolArgs } = resolvedInput;
|
|
1509
|
+
const compiledElectron = resolvedInput.kind === "electron" ? resolvedInput.compiledElectron : undefined;
|
|
1510
|
+
const redactedCompiledElectron = resolvedInput.kind === "electron" ? resolvedInput.redactedCompiledElectron : undefined;
|
|
1511
|
+
const runElectronHostInput = async () => {
|
|
1512
|
+
const electronHostLaunchRecords = getElectronHostLaunchRecordsForInput({
|
|
1513
|
+
branchRecords: electronLaunchRecords,
|
|
1514
|
+
compiledElectron,
|
|
1515
|
+
ownedRecords: ownedElectronLaunchRecords,
|
|
1516
|
+
});
|
|
1517
|
+
let electronHostResult = await handleElectronHostInput({
|
|
1518
|
+
attachedSessionKeys,
|
|
1519
|
+
compiledElectron,
|
|
1615
1520
|
cwd: ctx.cwd,
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1521
|
+
electronChildProcesses,
|
|
1522
|
+
electronLaunchRecords: electronHostLaunchRecords,
|
|
1523
|
+
implicitSessionCloseTimeoutMs,
|
|
1524
|
+
managedSessionActive,
|
|
1525
|
+
managedSessionName,
|
|
1526
|
+
managedSessionNamespace,
|
|
1527
|
+
managedSessionRestoreState,
|
|
1528
|
+
ownedManagedSessions,
|
|
1529
|
+
redactedCompiledElectron,
|
|
1530
|
+
sessionPageState,
|
|
1531
|
+
signal,
|
|
1532
|
+
});
|
|
1533
|
+
if (electronHostResult && compiledElectron?.action === "cleanup") {
|
|
1534
|
+
branchStateGeneration += 1;
|
|
1535
|
+
const cleanupRecords = isRecord(electronHostResult.details)
|
|
1536
|
+
&& isRecord(electronHostResult.details.electron)
|
|
1537
|
+
&& isRecord(electronHostResult.details.electron.cleanup)
|
|
1538
|
+
&& Array.isArray(electronHostResult.details.electron.cleanup.results)
|
|
1539
|
+
? electronHostResult.details.electron.cleanup.results
|
|
1540
|
+
: [];
|
|
1541
|
+
const cleanedLaunchIds = new Set();
|
|
1542
|
+
for (const cleanupResult of cleanupRecords) {
|
|
1543
|
+
if (isRecord(cleanupResult) && isElectronLaunchRecord(cleanupResult.record)) {
|
|
1544
|
+
cleanedLaunchIds.add(cleanupResult.record.launchId);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
replaceWithActiveElectronLaunchRecords(ownedElectronLaunchRecords, electronHostLaunchRecords, branchOwnedElectronLaunchIds, cleanedLaunchIds);
|
|
1548
|
+
mergeElectronCleanupRecords(electronLaunchRecords, cleanupRecords);
|
|
1549
|
+
const cleanupNamespace = isRecord(electronHostResult.details) && typeof electronHostResult.details.namespace === "string"
|
|
1550
|
+
? electronHostResult.details.namespace
|
|
1551
|
+
: undefined;
|
|
1552
|
+
const closedSessionIdentities = getCleanupResultsClosedManagedSessionIdentities(cleanupRecords, cleanupNamespace);
|
|
1553
|
+
syncElectronCleanupManagedSessions(ownedManagedSessions, cleanupRecords, cleanupNamespace);
|
|
1554
|
+
for (const identity of closedSessionIdentities) {
|
|
1555
|
+
retireRecordingSession(identity.sessionName, identity.namespace);
|
|
1556
|
+
const closedSessionKey = getSessionContextKey(identity.sessionName, identity.namespace) ?? identity.sessionName;
|
|
1557
|
+
clearSessionScopedBrowserState(closedSessionKey);
|
|
1558
|
+
if (closedSessionKey === (getSessionContextKey(managedSessionName, managedSessionNamespace) ?? managedSessionName)) {
|
|
1559
|
+
managedSessionActive = false;
|
|
1560
|
+
managedSessionCompatibilityWorkaround = undefined;
|
|
1561
|
+
managedSessionHeadedAutosaveDisabled = false;
|
|
1562
|
+
managedSessionHeadedAutosaveInterval = undefined;
|
|
1563
|
+
managedSessionNamespace = undefined;
|
|
1564
|
+
freshSessionOrdinal += 1;
|
|
1565
|
+
managedSessionName = createFreshSessionName(managedSessionBaseName, ephemeralSessionSeed, freshSessionOrdinal);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
if (artifactManifest) {
|
|
1569
|
+
electronHostResult = {
|
|
1570
|
+
...electronHostResult,
|
|
1571
|
+
details: {
|
|
1572
|
+
...(isRecord(electronHostResult.details) ? electronHostResult.details : {}),
|
|
1573
|
+
artifactManifest: redactSensitiveValue(artifactManifest),
|
|
1574
|
+
artifactRetentionSummary: formatSessionArtifactRetentionSummary(artifactManifest),
|
|
1575
|
+
},
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1620
1578
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
const
|
|
1646
|
-
const
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
electronLaunchRecords,
|
|
1653
|
-
ephemeralSessionSeed,
|
|
1654
|
-
freshSessionOrdinal,
|
|
1655
|
-
managedSessionActive,
|
|
1656
|
-
managedSessionBaseName,
|
|
1657
|
-
managedSessionCompatibilityWorkaround,
|
|
1658
|
-
managedSessionHeadedAutosaveDisabled,
|
|
1659
|
-
managedSessionHeadedAutosaveInterval,
|
|
1660
|
-
managedSessionCwd,
|
|
1579
|
+
return electronHostResult;
|
|
1580
|
+
};
|
|
1581
|
+
const runSerializedElectronHostInput = () => shouldSerializeElectronHostInput(compiledElectron)
|
|
1582
|
+
? managedSessionExecutionQueue.run(runElectronHostInput)
|
|
1583
|
+
: runElectronHostInput();
|
|
1584
|
+
const electronHostResult = compiledElectron?.action === "cleanup"
|
|
1585
|
+
? await artifactExecutionQueue.run(async () => {
|
|
1586
|
+
flushRecordingReservations();
|
|
1587
|
+
const reservationError = outputPath ? getArtifactPreflightValidationError({
|
|
1588
|
+
activeRecordingReservations: activeRecordingReservations.values(),
|
|
1589
|
+
args: [],
|
|
1590
|
+
cwd: ctx.cwd,
|
|
1591
|
+
outputPath,
|
|
1592
|
+
}) : undefined;
|
|
1593
|
+
if (reservationError) {
|
|
1594
|
+
return warnRecordingPersistence(buildValidationFailureResult({ attemptedKind: resolvedInput.kind, kind: "invalid", redactedArgs: resolvedInput.redactedArgs, status: "invalid", toolArgs: resolvedInput.toolArgs, toolStdin: resolvedInput.toolStdin, validationError: reservationError }));
|
|
1595
|
+
}
|
|
1596
|
+
const result = await runSerializedElectronHostInput();
|
|
1597
|
+
return result ? applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, result: warnRecordingPersistence(result) }) : result;
|
|
1598
|
+
})
|
|
1599
|
+
: await runSerializedElectronHostInput();
|
|
1600
|
+
if (electronHostResult) {
|
|
1601
|
+
return compiledElectron?.action === "cleanup" ? electronHostResult : applyUnserializedOutputPath(electronHostResult);
|
|
1602
|
+
}
|
|
1603
|
+
const explicitSessionName = extractExplicitSessionName(toolArgs);
|
|
1604
|
+
const callerOwnedSessionNamespace = explicitSessionName
|
|
1605
|
+
? resolveAgentBrowserNamespace(toolArgs, getAgentBrowserProcessEnvironment().AGENT_BROWSER_NAMESPACE)
|
|
1606
|
+
: undefined;
|
|
1607
|
+
const serializeBrowserCommand = shouldSerializeBrowserCommand({
|
|
1608
|
+
namespace: callerOwnedSessionNamespace,
|
|
1609
|
+
explicitSessionName,
|
|
1661
1610
|
managedSessionName,
|
|
1662
|
-
|
|
1663
|
-
managedSessionRestoreState,
|
|
1664
|
-
networkRoutesBySession,
|
|
1611
|
+
ownedElectronLaunchRecords,
|
|
1665
1612
|
ownedManagedSessions,
|
|
1666
|
-
sessionPageState,
|
|
1667
|
-
traceOwners,
|
|
1668
|
-
};
|
|
1669
|
-
const selectedPlan = buildExecutionPlan(toolArgs, {
|
|
1670
|
-
freshSessionName: createFreshSessionName(browserRunState.managedSessionBaseName, browserRunState.ephemeralSessionSeed, browserRunState.freshSessionOrdinal + 1),
|
|
1671
|
-
managedSessionActive: browserRunState.managedSessionActive,
|
|
1672
|
-
managedSessionCompatibilityWorkaround: browserRunState.managedSessionCompatibilityWorkaround,
|
|
1673
|
-
managedSessionName: browserRunState.managedSessionName,
|
|
1674
|
-
managedSessionNamespace: browserRunState.managedSessionNamespace,
|
|
1675
|
-
sessionMode: compiledElectron?.action === "launch" ? "fresh" : params.sessionMode ?? "auto",
|
|
1676
1613
|
});
|
|
1677
|
-
const
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1720
|
-
const
|
|
1721
|
-
||
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1614
|
+
const callerOwnedSessionQueueKey = !serializeBrowserCommand && explicitSessionName
|
|
1615
|
+
? getSessionContextKey(explicitSessionName, callerOwnedSessionNamespace) ?? explicitSessionName
|
|
1616
|
+
: undefined;
|
|
1617
|
+
const runBrowserCommand = async () => {
|
|
1618
|
+
flushRecordingReservations();
|
|
1619
|
+
const branchRestoreGenerationAtStart = branchRestoreGeneration;
|
|
1620
|
+
const generationAtStart = branchStateGeneration;
|
|
1621
|
+
const sessionPageStateUpdate = sessionPageState.beginUpdate();
|
|
1622
|
+
const browserRunState = {
|
|
1623
|
+
activeRecordingReservations,
|
|
1624
|
+
artifactManifest,
|
|
1625
|
+
attachedSessionKeys,
|
|
1626
|
+
closedManagedSessionNames: new Set(),
|
|
1627
|
+
electronChildProcesses,
|
|
1628
|
+
electronLaunchRecords,
|
|
1629
|
+
ephemeralSessionSeed,
|
|
1630
|
+
freshSessionOrdinal,
|
|
1631
|
+
managedSessionActive,
|
|
1632
|
+
managedSessionBaseName,
|
|
1633
|
+
managedSessionCompatibilityWorkaround,
|
|
1634
|
+
managedSessionHeadedAutosaveDisabled,
|
|
1635
|
+
managedSessionHeadedAutosaveInterval,
|
|
1636
|
+
managedSessionCwd,
|
|
1637
|
+
managedSessionName,
|
|
1638
|
+
managedSessionNamespace,
|
|
1639
|
+
managedSessionRestoreState,
|
|
1640
|
+
networkRoutesBySession,
|
|
1641
|
+
ownedManagedSessions,
|
|
1642
|
+
sessionPageState,
|
|
1643
|
+
traceOwners,
|
|
1644
|
+
};
|
|
1645
|
+
const selectedPlan = buildExecutionPlan(toolArgs, {
|
|
1646
|
+
freshSessionName: createFreshSessionName(browserRunState.managedSessionBaseName, browserRunState.ephemeralSessionSeed, browserRunState.freshSessionOrdinal + 1),
|
|
1647
|
+
managedSessionActive: browserRunState.managedSessionActive,
|
|
1648
|
+
managedSessionCompatibilityWorkaround: browserRunState.managedSessionCompatibilityWorkaround,
|
|
1649
|
+
managedSessionName: browserRunState.managedSessionName,
|
|
1650
|
+
managedSessionNamespace: browserRunState.managedSessionNamespace,
|
|
1651
|
+
sessionMode: compiledElectron?.action === "launch" ? "fresh" : params.sessionMode ?? "auto",
|
|
1652
|
+
stdin: resolvedInput.toolStdin,
|
|
1653
|
+
browserIndependentReadConfirmation: readConfirmation?.capabilities?.readRequiresConfirmation === true,
|
|
1654
|
+
});
|
|
1655
|
+
const initialArtifactManifest = browserRunState.artifactManifest;
|
|
1656
|
+
const initialNetworkRoutesBySession = browserRunState.networkRoutesBySession;
|
|
1657
|
+
const attachedSessionRequested = isAttachedBrowserInvocation(toolArgs)
|
|
1658
|
+
|| (resolvedInput.kind === "electron" && resolvedInput.compiledElectron.action === "launch");
|
|
1659
|
+
const allocatesFreshManagedSession = explicitSessionName === undefined
|
|
1660
|
+
&& (params.sessionMode === "fresh" || (resolvedInput.kind === "electron" && resolvedInput.compiledElectron.action === "launch"));
|
|
1661
|
+
const reusableSessionKey = allocatesFreshManagedSession
|
|
1662
|
+
? undefined
|
|
1663
|
+
: getSessionContextKey(selectedPlan.sessionName, selectedPlan.namespace)
|
|
1664
|
+
?? getSessionContextKey(browserRunState.managedSessionName, browserRunState.managedSessionNamespace);
|
|
1665
|
+
const attachedSessionKnown = reusableSessionKey !== undefined && attachedSessionKeys.has(reusableSessionKey);
|
|
1666
|
+
let result = await runAgentBrowserTool({
|
|
1667
|
+
ctx,
|
|
1668
|
+
cwd: ctx.cwd,
|
|
1669
|
+
electronPostCommandStatusSettleMs: ELECTRON_POST_COMMAND_STATUS_SETTLE_MS,
|
|
1670
|
+
electronProfileIsolationDetails: ELECTRON_PROFILE_ISOLATION_DETAILS,
|
|
1671
|
+
implicitSessionCloseTimeoutMs,
|
|
1672
|
+
implicitSessionIdleTimeoutMs,
|
|
1673
|
+
input: resolvedInput,
|
|
1674
|
+
onUpdate,
|
|
1675
|
+
params,
|
|
1676
|
+
establishAttachedBrowserSession: attachedSessionRequested && !attachedSessionKnown,
|
|
1677
|
+
preserveAttachedBrowserSession: attachedSessionRequested || attachedSessionKnown,
|
|
1678
|
+
promptPolicy,
|
|
1679
|
+
sessionPageStateUpdate,
|
|
1680
|
+
signal,
|
|
1681
|
+
state: browserRunState,
|
|
1682
|
+
});
|
|
1683
|
+
const branchRestoreStillCurrent = branchRestoreGenerationAtStart === branchRestoreGeneration;
|
|
1684
|
+
const resultDetails = isRecord(result.details) ? result.details : undefined;
|
|
1685
|
+
const resultSessionName = typeof resultDetails?.sessionName === "string"
|
|
1686
|
+
? resultDetails.sessionName
|
|
1687
|
+
: extractExplicitSessionName(toolArgs);
|
|
1688
|
+
const resultNamespace = typeof resultDetails?.namespace === "string"
|
|
1689
|
+
? resultDetails.namespace
|
|
1690
|
+
: selectedPlan.namespace;
|
|
1691
|
+
if (branchRestoreStillCurrent) {
|
|
1692
|
+
const resultBatchCloseLifecycle = getSuccessfulBatchCloseLifecycle(resultDetails?.batchSteps);
|
|
1693
|
+
const resultSessionKey = getSessionContextKey(resultSessionName, resultNamespace) ?? resultSessionName;
|
|
1694
|
+
const managedSessionOutcome = isRecord(resultDetails?.managedSessionOutcome) ? resultDetails.managedSessionOutcome : undefined;
|
|
1695
|
+
const closeAllApplied = resultDetails?.closeAllApplied === true;
|
|
1696
|
+
const attachedSessionRemainsActive = result.isError !== true
|
|
1697
|
+
|| ((attachedSessionRequested || attachedSessionKnown) && managedSessionOutcome?.activeAfter === true);
|
|
1698
|
+
const closesAttachedSession = (result.isError !== true && isCloseCommand(extractUpstreamCommandTokens(toolArgs)[0]))
|
|
1699
|
+
|| resultBatchCloseLifecycle?.endsClosed === true;
|
|
1700
|
+
if (closeAllApplied) {
|
|
1701
|
+
deleteIdentityKeysInNamespace(attachedSessionKeys, resultNamespace);
|
|
1702
|
+
if (resultSessionKey && attachedSessionRemainsActive && (attachedSessionRequested || attachedSessionKnown) && resultBatchCloseLifecycle?.endsClosed === false) {
|
|
1703
|
+
attachedSessionKeys.add(resultSessionKey);
|
|
1704
|
+
result = { ...result, details: { ...(resultDetails ?? {}), attachedBrowserSession: true } };
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
else if (resultSessionKey && closesAttachedSession)
|
|
1708
|
+
attachedSessionKeys.delete(resultSessionKey);
|
|
1709
|
+
else if (resultSessionKey && attachedSessionRemainsActive && (attachedSessionRequested || attachedSessionKnown)) {
|
|
1725
1710
|
attachedSessionKeys.add(resultSessionKey);
|
|
1726
1711
|
result = { ...result, details: { ...(resultDetails ?? {}), attachedBrowserSession: true } };
|
|
1727
1712
|
}
|
|
1728
1713
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
artifactManifest = mergeBrowserRunArtifactManifest(artifactManifest, initialArtifactManifest, browserRunState.artifactManifest);
|
|
1739
|
-
const handledBatchCloseKeys = syncRecordingReservationsFromResult(result);
|
|
1740
|
-
if (resultDetails?.closeAllApplied === true) {
|
|
1741
|
-
for (const [sessionKey, reservation] of [...activeRecordingReservations]) {
|
|
1742
|
-
if (isAgentBrowserSessionIdentityKeyInNamespace(sessionKey, resultNamespace)) {
|
|
1743
|
-
retireRecordingSession(reservation.sessionName, reservation.namespace);
|
|
1714
|
+
if (branchRestoreStillCurrent) {
|
|
1715
|
+
networkRoutesBySession = mergeBrowserRunMap(networkRoutesBySession, initialNetworkRoutesBySession, browserRunState.networkRoutesBySession);
|
|
1716
|
+
artifactManifest = mergeBrowserRunArtifactManifest(artifactManifest, initialArtifactManifest, browserRunState.artifactManifest);
|
|
1717
|
+
const handledBatchCloseKeys = syncRecordingReservationsFromResult(result);
|
|
1718
|
+
if (resultDetails?.closeAllApplied === true) {
|
|
1719
|
+
for (const [sessionKey, reservation] of [...activeRecordingReservations]) {
|
|
1720
|
+
if (isAgentBrowserSessionIdentityKeyInNamespace(sessionKey, resultNamespace)) {
|
|
1721
|
+
retireRecordingSession(reservation.sessionName, reservation.namespace);
|
|
1722
|
+
}
|
|
1744
1723
|
}
|
|
1745
1724
|
}
|
|
1725
|
+
for (const closedSessionKey of browserRunState.closedManagedSessionNames) {
|
|
1726
|
+
if (handledBatchCloseKeys.has(closedSessionKey))
|
|
1727
|
+
continue;
|
|
1728
|
+
const reservation = activeRecordingReservations.get(closedSessionKey);
|
|
1729
|
+
if (reservation)
|
|
1730
|
+
retireRecordingSession(reservation.sessionName, reservation.namespace);
|
|
1731
|
+
}
|
|
1732
|
+
if (resultSessionName) {
|
|
1733
|
+
const reservation = activeRecordingReservations.get(getAgentBrowserSessionIdentityKey(resultSessionName, resultNamespace));
|
|
1734
|
+
if (reservation)
|
|
1735
|
+
result = appendActiveRecordingCleanupAction(result, reservation);
|
|
1736
|
+
}
|
|
1737
|
+
if (artifactManifest) {
|
|
1738
|
+
result = {
|
|
1739
|
+
...result,
|
|
1740
|
+
details: {
|
|
1741
|
+
...(isRecord(result.details) ? result.details : {}),
|
|
1742
|
+
artifactManifest: redactSensitiveValue(artifactManifest),
|
|
1743
|
+
artifactRetentionSummary: formatSessionArtifactRetentionSummary(artifactManifest),
|
|
1744
|
+
},
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1746
1747
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
},
|
|
1770
|
-
};
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
const branchStateStillCurrent = generationAtStart === branchStateGeneration;
|
|
1774
|
-
if (serializeBrowserCommand || branchStateStillCurrent) {
|
|
1775
|
-
freshSessionOrdinal = Math.max(freshSessionOrdinal, browserRunState.freshSessionOrdinal);
|
|
1776
|
-
managedSessionActive = browserRunState.managedSessionActive;
|
|
1777
|
-
managedSessionCompatibilityWorkaround = browserRunState.managedSessionCompatibilityWorkaround;
|
|
1778
|
-
managedSessionHeadedAutosaveDisabled = browserRunState.managedSessionHeadedAutosaveDisabled === true;
|
|
1779
|
-
managedSessionHeadedAutosaveInterval = browserRunState.managedSessionHeadedAutosaveInterval;
|
|
1780
|
-
managedSessionCwd = browserRunState.managedSessionCwd;
|
|
1781
|
-
managedSessionName = browserRunState.managedSessionName;
|
|
1782
|
-
managedSessionNamespace = browserRunState.managedSessionNamespace;
|
|
1783
|
-
for (const closedSessionName of browserRunState.closedManagedSessionNames) {
|
|
1784
|
-
untrackOwnedManagedSession(ownedManagedSessions, closedSessionName);
|
|
1748
|
+
const branchStateStillCurrent = generationAtStart === branchStateGeneration;
|
|
1749
|
+
if (serializeBrowserCommand || branchStateStillCurrent) {
|
|
1750
|
+
freshSessionOrdinal = Math.max(freshSessionOrdinal, browserRunState.freshSessionOrdinal);
|
|
1751
|
+
managedSessionActive = browserRunState.managedSessionActive;
|
|
1752
|
+
managedSessionCompatibilityWorkaround = browserRunState.managedSessionCompatibilityWorkaround;
|
|
1753
|
+
managedSessionHeadedAutosaveDisabled = browserRunState.managedSessionHeadedAutosaveDisabled === true;
|
|
1754
|
+
managedSessionHeadedAutosaveInterval = browserRunState.managedSessionHeadedAutosaveInterval;
|
|
1755
|
+
managedSessionCwd = browserRunState.managedSessionCwd;
|
|
1756
|
+
managedSessionName = browserRunState.managedSessionName;
|
|
1757
|
+
managedSessionNamespace = browserRunState.managedSessionNamespace;
|
|
1758
|
+
for (const closedSessionName of browserRunState.closedManagedSessionNames) {
|
|
1759
|
+
untrackOwnedManagedSession(ownedManagedSessions, closedSessionName);
|
|
1760
|
+
}
|
|
1761
|
+
syncOwnedManagedSessionsFromResult(ownedManagedSessions, result, browserRunState.managedSessionCwd);
|
|
1762
|
+
mergeActiveElectronLaunchRecords(ownedElectronLaunchRecords, electronLaunchRecords, {
|
|
1763
|
+
branchOwnedLaunchIds: branchOwnedElectronLaunchIds,
|
|
1764
|
+
touchedLaunchIds: !result.isError
|
|
1765
|
+
? getTouchedElectronLaunchIds(explicitSessionName ?? browserRunState.managedSessionName, electronLaunchRecords, resultNamespace)
|
|
1766
|
+
: undefined,
|
|
1767
|
+
});
|
|
1768
|
+
if (serializeBrowserCommand)
|
|
1769
|
+
branchStateGeneration += 1;
|
|
1785
1770
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
const plan = buildExecutionPlan(toolArgs, {
|
|
1803
|
-
freshSessionName: createFreshSessionName(managedSessionBaseName, ephemeralSessionSeed, freshSessionOrdinal + 1),
|
|
1804
|
-
managedSessionActive,
|
|
1805
|
-
managedSessionCompatibilityWorkaround,
|
|
1806
|
-
managedSessionName,
|
|
1807
|
-
managedSessionNamespace,
|
|
1808
|
-
sessionMode: params.sessionMode ?? "auto",
|
|
1771
|
+
return applyAgentBrowserOutputPath({ cwd: ctx.cwd, outputPath, preserveTextContent: Array.isArray(params.args) && params.args.includes("--json"), result: warnRecordingPersistence(result) });
|
|
1772
|
+
};
|
|
1773
|
+
const closesAllSessions = commandClosesAllSessions(toolArgs, resolvedInput.toolStdin);
|
|
1774
|
+
const runWithinSessionQueue = () => {
|
|
1775
|
+
if (closesAllSessions)
|
|
1776
|
+
return managedSessionExecutionQueue.run(() => {
|
|
1777
|
+
const plan = buildExecutionPlan(toolArgs, {
|
|
1778
|
+
freshSessionName: createFreshSessionName(managedSessionBaseName, ephemeralSessionSeed, freshSessionOrdinal + 1),
|
|
1779
|
+
managedSessionActive,
|
|
1780
|
+
managedSessionCompatibilityWorkaround,
|
|
1781
|
+
managedSessionName,
|
|
1782
|
+
managedSessionNamespace,
|
|
1783
|
+
sessionMode: params.sessionMode ?? "auto",
|
|
1784
|
+
stdin: resolvedInput.toolStdin,
|
|
1785
|
+
});
|
|
1786
|
+
return callerOwnedSessionExecutionQueues.runExclusive(plan.namespace, runBrowserCommand);
|
|
1809
1787
|
});
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
};
|
|
1818
|
-
if (!commandTouchesArtifactLifecycle(toolArgs, resolvedInput.toolStdin, outputPath))
|
|
1819
|
-
return runWithinSessionQueue();
|
|
1820
|
-
return artifactExecutionQueue.run(async () => {
|
|
1821
|
-
const artifactValidationError = getArtifactPreflightValidationError({
|
|
1822
|
-
activeRecordingReservations: activeRecordingReservations.values(),
|
|
1823
|
-
args: toolArgs,
|
|
1824
|
-
cwd: ctx.cwd,
|
|
1825
|
-
outputPath,
|
|
1826
|
-
stdin: resolvedInput.toolStdin,
|
|
1827
|
-
});
|
|
1828
|
-
if (!artifactValidationError)
|
|
1788
|
+
if (serializeBrowserCommand)
|
|
1789
|
+
return managedSessionExecutionQueue.run(runBrowserCommand);
|
|
1790
|
+
return callerOwnedSessionQueueKey
|
|
1791
|
+
? callerOwnedSessionExecutionQueues.run(callerOwnedSessionQueueKey, callerOwnedSessionNamespace, runBrowserCommand)
|
|
1792
|
+
: runBrowserCommand();
|
|
1793
|
+
};
|
|
1794
|
+
if (!commandTouchesArtifactLifecycle(toolArgs, resolvedInput.toolStdin, outputPath))
|
|
1829
1795
|
return runWithinSessionQueue();
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1796
|
+
return artifactExecutionQueue.run(async () => {
|
|
1797
|
+
const artifactValidationError = getArtifactPreflightValidationError({
|
|
1798
|
+
activeRecordingReservations: activeRecordingReservations.values(),
|
|
1799
|
+
args: toolArgs,
|
|
1800
|
+
cwd: ctx.cwd,
|
|
1801
|
+
outputPath,
|
|
1802
|
+
stdin: resolvedInput.toolStdin,
|
|
1803
|
+
});
|
|
1804
|
+
if (!artifactValidationError)
|
|
1805
|
+
return runWithinSessionQueue();
|
|
1806
|
+
flushRecordingReservations();
|
|
1807
|
+
return warnRecordingPersistence(buildValidationFailureResult({
|
|
1835
1808
|
attemptedKind: resolvedInput.kind,
|
|
1836
1809
|
kind: "invalid",
|
|
1837
1810
|
redactedArgs: resolvedInput.redactedArgs,
|
|
@@ -1839,11 +1812,11 @@ export default function agentBrowserExtension(pi) {
|
|
|
1839
1812
|
toolArgs: resolvedInput.toolArgs,
|
|
1840
1813
|
toolStdin: resolvedInput.toolStdin,
|
|
1841
1814
|
validationError: artifactValidationError,
|
|
1842
|
-
}))
|
|
1815
|
+
}));
|
|
1843
1816
|
});
|
|
1844
1817
|
});
|
|
1845
1818
|
},
|
|
1846
1819
|
};
|
|
1847
|
-
pi.registerTool(agentBrowserTool);
|
|
1820
|
+
pi.registerTool(beforeExecute ? { ...agentBrowserTool, executionMode: "sequential" } : agentBrowserTool);
|
|
1848
1821
|
registerWebSearchToolIfAvailable(agentBrowserConfig);
|
|
1849
1822
|
}
|