@steipete/oracle 0.18.0 → 0.19.0
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/README.md +1 -1
- package/dist/bin/oracle-cli.js +65 -63
- package/dist/bin/oracle-mcp.js +0 -0
- package/dist/src/browser/actions/archiveConversation.js +31 -7
- package/dist/src/browser/actions/assistantResponse.js +43 -1
- package/dist/src/browser/actions/attachmentContext.js +239 -0
- package/dist/src/browser/actions/attachmentDataTransfer.js +19 -1
- package/dist/src/browser/actions/attachmentEvidence.js +78 -0
- package/dist/src/browser/actions/attachmentProgress.js +41 -0
- package/dist/src/browser/actions/attachmentPrompt.js +130 -0
- package/dist/src/browser/actions/attachments.js +306 -355
- package/dist/src/browser/actions/deepResearch.js +2 -1
- package/dist/src/browser/actions/modelSelection.js +13 -3
- package/dist/src/browser/actions/navigation.js +1 -1
- package/dist/src/browser/actions/promptComposer.js +361 -186
- package/dist/src/browser/actions/remoteFileTransfer.js +4 -2
- package/dist/src/browser/actions/thinkingStatus.js +2 -5
- package/dist/src/browser/actions/thinkingTime.js +119 -16
- package/dist/src/browser/attachRunning.js +46 -2
- package/dist/src/browser/attachmentValidation.js +53 -0
- package/dist/src/browser/cancellation.js +105 -0
- package/dist/src/browser/chatgptImages.js +2 -0
- package/dist/src/browser/chatgptThrottle.js +104 -0
- package/dist/src/browser/chromeLifecycle.js +267 -43
- package/dist/src/browser/config.js +13 -0
- package/dist/src/browser/detect.js +1 -1
- package/dist/src/browser/index.js +444 -261
- package/dist/src/browser/modelDisplay.js +9 -0
- package/dist/src/browser/pageActions.js +2 -2
- package/dist/src/browser/profileState.js +114 -9
- package/dist/src/browser/projectSourcesRunner.js +83 -15
- package/dist/src/browser/prompt.js +272 -113
- package/dist/src/browser/providers/chatgptDomProvider.js +2 -0
- package/dist/src/browser/reattach.js +10 -3
- package/dist/src/browser/sessionRunner.js +71 -11
- package/dist/src/browser/tabLeaseRegistry.js +414 -38
- package/dist/src/browser/utils.js +20 -2
- package/dist/src/cli/browserConfig.js +3 -1
- package/dist/src/cli/browserDefaults.js +10 -0
- package/dist/src/cli/browserTabs.js +12 -29
- package/dist/src/cli/detachedSession.js +69 -0
- package/dist/src/cli/dryRun.js +58 -48
- package/dist/src/cli/harvestIntegrity.js +140 -0
- package/dist/src/cli/serveBrowserConfig.js +24 -0
- package/dist/src/cli/sessionDisplay.js +9 -2
- package/dist/src/cli/sessionRunner.js +91 -7
- package/dist/src/config.js +1 -0
- package/dist/src/gemini-web/client.js +67 -21
- package/dist/src/gemini-web/executor.js +4 -0
- package/dist/src/gemini-web/http.js +15 -0
- package/dist/src/gemini-web/models.js +15 -11
- package/dist/src/mcp/server.js +11 -14
- package/dist/src/mcp/tools/chatgptImage.js +4 -4
- package/dist/src/mcp/tools/consult.js +84 -22
- package/dist/src/mcp/tools/projectSources.js +4 -6
- package/dist/src/mcp/tools/sessionResources.js +1 -1
- package/dist/src/mcp/tools/sessions.js +2 -2
- package/dist/src/mcp/tools/wait.js +182 -0
- package/dist/src/mcp/types.js +7 -0
- package/dist/src/oracle/errors.js +11 -0
- package/dist/src/oracle/providerRoutePlan.js +3 -2
- package/dist/src/remote/client.js +70 -6
- package/dist/src/remote/health.js +6 -2
- package/dist/src/remote/runSlots.js +83 -0
- package/dist/src/remote/server.js +345 -71
- package/dist/src/sessionManager.js +36 -1
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/package.json +25 -23
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/bin/oracle.js +0 -683
- package/dist/docs-site/.nojekyll +0 -0
- package/dist/docs-site/CNAME +0 -1
- package/dist/docs-site/RELEASING.html +0 -410
- package/dist/docs-site/agents.html +0 -374
- package/dist/docs-site/anthropic.html +0 -368
- package/dist/docs-site/bridge.html +0 -400
- package/dist/docs-site/browser-mode.html +0 -588
- package/dist/docs-site/chromium-forks.html +0 -347
- package/dist/docs-site/cli-reference.html +0 -346
- package/dist/docs-site/configuration.html +0 -436
- package/dist/docs-site/favicon.svg +0 -14
- package/dist/docs-site/followup.html +0 -368
- package/dist/docs-site/gemini.html +0 -379
- package/dist/docs-site/grok.html +0 -325
- package/dist/docs-site/index.html +0 -360
- package/dist/docs-site/install.html +0 -335
- package/dist/docs-site/linux.html +0 -321
- package/dist/docs-site/llms.txt +0 -43
- package/dist/docs-site/manual-tests.html +0 -595
- package/dist/docs-site/mcp.html +0 -368
- package/dist/docs-site/multimodel.html +0 -364
- package/dist/docs-site/mythical-pro-agents.html +0 -360
- package/dist/docs-site/notifier.html +0 -338
- package/dist/docs-site/openai-endpoints.html +0 -387
- package/dist/docs-site/openrouter.html +0 -344
- package/dist/docs-site/quickstart.html +0 -369
- package/dist/docs-site/refactor/ux.html +0 -532
- package/dist/docs-site/sessions.html +0 -388
- package/dist/docs-site/social-card.png +0 -0
- package/dist/docs-site/social-card.svg +0 -79
- package/dist/docs-site/spec.html +0 -363
- package/dist/docs-site/testing.html +0 -320
- package/dist/docs-site/tui-debug.html +0 -326
- package/dist/docs-site/windows-work.html +0 -323
- package/dist/docs-site/windows.html +0 -320
- package/dist/markdansi/types/index.js +0 -4
- package/dist/oracle/bin/oracle-cli.js +0 -472
- package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
- package/dist/oracle/src/browser/actions/attachments.js +0 -82
- package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
- package/dist/oracle/src/browser/actions/navigation.js +0 -75
- package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
- package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
- package/dist/oracle/src/browser/config.js +0 -33
- package/dist/oracle/src/browser/constants.js +0 -40
- package/dist/oracle/src/browser/cookies.js +0 -210
- package/dist/oracle/src/browser/domDebug.js +0 -36
- package/dist/oracle/src/browser/index.js +0 -331
- package/dist/oracle/src/browser/pageActions.js +0 -5
- package/dist/oracle/src/browser/prompt.js +0 -88
- package/dist/oracle/src/browser/promptSummary.js +0 -20
- package/dist/oracle/src/browser/sessionRunner.js +0 -80
- package/dist/oracle/src/browser/types.js +0 -1
- package/dist/oracle/src/browser/utils.js +0 -62
- package/dist/oracle/src/browserMode.js +0 -1
- package/dist/oracle/src/cli/browserConfig.js +0 -44
- package/dist/oracle/src/cli/dryRun.js +0 -59
- package/dist/oracle/src/cli/engine.js +0 -17
- package/dist/oracle/src/cli/errorUtils.js +0 -9
- package/dist/oracle/src/cli/help.js +0 -70
- package/dist/oracle/src/cli/markdownRenderer.js +0 -15
- package/dist/oracle/src/cli/options.js +0 -103
- package/dist/oracle/src/cli/promptRequirement.js +0 -14
- package/dist/oracle/src/cli/rootAlias.js +0 -30
- package/dist/oracle/src/cli/sessionCommand.js +0 -77
- package/dist/oracle/src/cli/sessionDisplay.js +0 -270
- package/dist/oracle/src/cli/sessionRunner.js +0 -94
- package/dist/oracle/src/heartbeat.js +0 -43
- package/dist/oracle/src/oracle/client.js +0 -48
- package/dist/oracle/src/oracle/config.js +0 -29
- package/dist/oracle/src/oracle/errors.js +0 -101
- package/dist/oracle/src/oracle/files.js +0 -220
- package/dist/oracle/src/oracle/format.js +0 -33
- package/dist/oracle/src/oracle/fsAdapter.js +0 -7
- package/dist/oracle/src/oracle/oscProgress.js +0 -60
- package/dist/oracle/src/oracle/request.js +0 -48
- package/dist/oracle/src/oracle/run.js +0 -444
- package/dist/oracle/src/oracle/tokenStats.js +0 -39
- package/dist/oracle/src/oracle/types.js +0 -1
- package/dist/oracle/src/oracle.js +0 -9
- package/dist/oracle/src/sessionManager.js +0 -205
- package/dist/oracle/src/version.js +0 -39
- package/dist/scripts/chrome/browser-tools.js +0 -295
- package/dist/src/browser/chromeCookies.js +0 -312
- package/dist/src/browser/keytarShim.js +0 -56
- package/dist/src/browser/profileSync.js +0 -141
- package/dist/src/browser/windowsCookies.js +0 -219
|
@@ -6,6 +6,7 @@ import { isKnownModel } from "../oracle/modelResolver.js";
|
|
|
6
6
|
import { buildPromptMarkdown } from "../oracle/promptAssembly.js";
|
|
7
7
|
import { buildAttachmentPlan } from "./policies.js";
|
|
8
8
|
import { createStoredZip } from "./zipBundle.js";
|
|
9
|
+
import { buildAttachmentBasenameCollisionDetails, findAttachmentBasenameCollisions, formatAttachmentBasenameCollisionMessage, } from "./attachmentValidation.js";
|
|
9
10
|
const DEFAULT_BROWSER_INLINE_CHAR_BUDGET = 60_000;
|
|
10
11
|
const MAX_BROWSER_ATTACHMENTS = 10;
|
|
11
12
|
const MAX_BROWSER_ZIP_BUNDLE_BYTES = 128 * 1024 * 1024;
|
|
@@ -82,70 +83,197 @@ export function isRawUploadFile(filePath) {
|
|
|
82
83
|
const ext = path.extname(filePath).toLowerCase();
|
|
83
84
|
return MEDIA_EXTENSIONS.has(ext) || ARCHIVE_EXTENSIONS.has(ext);
|
|
84
85
|
}
|
|
86
|
+
const GENERATED_BUNDLE_DIR_PREFIX = "oracle-browser-bundle-";
|
|
87
|
+
const pendingFallbackBundles = new WeakMap();
|
|
85
88
|
function formatSectionsForBundle(sections, options = {}) {
|
|
86
89
|
return formatFileSections(sections, {
|
|
87
90
|
lineNumbers: options.lineNumbers ?? true,
|
|
88
91
|
trailingNewline: true,
|
|
89
92
|
});
|
|
90
93
|
}
|
|
91
|
-
function resolveBrowserBundleFormat(format,
|
|
94
|
+
function resolveBrowserBundleFormat(format, { hasRawUploadFiles }) {
|
|
92
95
|
if (format !== "auto") {
|
|
93
96
|
return format;
|
|
94
97
|
}
|
|
95
|
-
return
|
|
98
|
+
return hasRawUploadFiles ? "zip" : "text";
|
|
96
99
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
function resolveBrowserBundleScope(format, { bundleRequested, rawAttachmentCount, textAttachmentCount, }) {
|
|
101
|
+
const attachmentCount = textAttachmentCount + rawAttachmentCount;
|
|
102
|
+
if (attachmentCount === 0) {
|
|
103
|
+
return "none";
|
|
104
|
+
}
|
|
105
|
+
if (format === "text") {
|
|
106
|
+
if (textAttachmentCount === 0) {
|
|
107
|
+
return "none";
|
|
108
|
+
}
|
|
109
|
+
const shouldBundleText = bundleRequested || textAttachmentCount > 1 || attachmentCount > MAX_BROWSER_ATTACHMENTS;
|
|
110
|
+
return shouldBundleText ? "text-only" : "none";
|
|
111
|
+
}
|
|
112
|
+
if (bundleRequested) {
|
|
113
|
+
return "all";
|
|
102
114
|
}
|
|
103
|
-
|
|
115
|
+
// Preserve native uploads for images, PDFs, archives, and other raw inputs.
|
|
116
|
+
// Multiple text/source files benefit from a real filesystem tree, so bundle
|
|
117
|
+
// those into one ZIP while leaving any native attachments alongside it.
|
|
118
|
+
if (textAttachmentCount > 1) {
|
|
119
|
+
return rawAttachmentCount + 1 <= MAX_BROWSER_ATTACHMENTS ? "text-only" : "all";
|
|
120
|
+
}
|
|
121
|
+
return attachmentCount > MAX_BROWSER_ATTACHMENTS ? "all" : "none";
|
|
122
|
+
}
|
|
123
|
+
function appendZipBundleInstruction(composerText, originalCount, bundlePath) {
|
|
124
|
+
const fileLabel = originalCount === 1 ? "file" : "files";
|
|
125
|
+
const instruction = [
|
|
126
|
+
`The attached \`${path.basename(bundlePath)}\` contains ${originalCount} selected ${fileLabel} with relative paths preserved.`,
|
|
127
|
+
"Extract it into a temporary directory, then inspect the resulting file tree with filesystem and search tools before answering.",
|
|
128
|
+
].join(" ");
|
|
129
|
+
return [composerText, instruction].filter(Boolean).join("\n\n").trim();
|
|
130
|
+
}
|
|
131
|
+
function assertAttachmentCount(attachmentCount, format) {
|
|
132
|
+
if (attachmentCount <= MAX_BROWSER_ATTACHMENTS)
|
|
133
|
+
return;
|
|
134
|
+
throw new Error(`Browser upload has ${attachmentCount} attachments after applying bundle format "${format}". Use --browser-bundle-format auto or zip to stay within the ${MAX_BROWSER_ATTACHMENTS}-attachment limit.`);
|
|
104
135
|
}
|
|
105
|
-
function
|
|
106
|
-
|
|
136
|
+
function assertUniqueAttachmentBasenames(attachments, cwd) {
|
|
137
|
+
const collisions = findAttachmentBasenameCollisions(attachments);
|
|
138
|
+
if (collisions.length === 0)
|
|
107
139
|
return;
|
|
108
|
-
|
|
140
|
+
const details = buildAttachmentBasenameCollisionDetails(collisions, (attachment) => path.isAbsolute(attachment.path) ? attachment.path : path.resolve(cwd, attachment.path));
|
|
141
|
+
throw new FileValidationError(formatAttachmentBasenameCollisionMessage("Browser upload", details.collisions), { ...details });
|
|
142
|
+
}
|
|
143
|
+
async function applyWrittenBundle({ sections, sources, format, scope, rawUploadAttachments, composerText, bundleParentDir, }) {
|
|
144
|
+
const nativeAttachments = scope === "text-only" ? rawUploadAttachments : [];
|
|
145
|
+
assertAttachmentCount(1 + nativeAttachments.length, format);
|
|
146
|
+
assertUniqueAttachmentBasenames(nativeAttachments, process.cwd());
|
|
147
|
+
const reservedNames = new Set(nativeAttachments.map((a) => path.basename(a.path).toLowerCase()));
|
|
148
|
+
let bundleName = `attachments-bundle.${format === "zip" ? "zip" : "txt"}`;
|
|
149
|
+
for (let suffix = 2; reservedNames.has(bundleName.toLowerCase()); suffix += 1) {
|
|
150
|
+
bundleName = `attachments-bundle-${suffix}.${format === "zip" ? "zip" : "txt"}`;
|
|
151
|
+
}
|
|
152
|
+
const writtenBundle = await writeBrowserBundle(sections, sources, format, bundleName, bundleParentDir);
|
|
153
|
+
const attachments = [writtenBundle.attachment];
|
|
154
|
+
if (scope === "text-only") {
|
|
155
|
+
attachments.push(...rawUploadAttachments);
|
|
156
|
+
}
|
|
157
|
+
assertAttachmentCount(attachments.length, format);
|
|
158
|
+
return {
|
|
159
|
+
attachments,
|
|
160
|
+
bundled: writtenBundle.metadata,
|
|
161
|
+
composerText: format === "zip"
|
|
162
|
+
? appendZipBundleInstruction(composerText, writtenBundle.metadata.originalCount, writtenBundle.metadata.bundlePath)
|
|
163
|
+
: composerText,
|
|
164
|
+
tokenEstimateText: writtenBundle.tokenEstimateText,
|
|
165
|
+
};
|
|
109
166
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
167
|
+
function generatedBundleDirectory(attachment) {
|
|
168
|
+
if (!attachment.generatedBundle)
|
|
169
|
+
return null;
|
|
170
|
+
const dir = path.dirname(attachment.path);
|
|
171
|
+
return path.basename(dir).startsWith(GENERATED_BUNDLE_DIR_PREFIX) ? dir : null;
|
|
172
|
+
}
|
|
173
|
+
export function listGeneratedBrowserBundleDirs(artifacts) {
|
|
174
|
+
const dirs = new Set();
|
|
175
|
+
for (const attachment of [...artifacts.attachments, ...(artifacts.fallback?.attachments ?? [])]) {
|
|
176
|
+
const dir = generatedBundleDirectory(attachment);
|
|
177
|
+
if (dir)
|
|
178
|
+
dirs.add(dir);
|
|
179
|
+
}
|
|
180
|
+
return [...dirs];
|
|
181
|
+
}
|
|
182
|
+
export async function cleanupGeneratedBrowserBundles(artifacts) {
|
|
183
|
+
await Promise.all(listGeneratedBrowserBundleDirs(artifacts).map((dir) => fs.rm(dir, { recursive: true, force: true })));
|
|
184
|
+
}
|
|
185
|
+
export async function materializeBrowserFallback(artifacts) {
|
|
186
|
+
const pending = pendingFallbackBundles.get(artifacts);
|
|
187
|
+
if (!pending || !artifacts.fallback) {
|
|
188
|
+
return artifacts.fallback ?? null;
|
|
189
|
+
}
|
|
190
|
+
pendingFallbackBundles.delete(artifacts);
|
|
191
|
+
const applied = await applyWrittenBundle({
|
|
192
|
+
sections: pending.sections,
|
|
193
|
+
sources: pending.scope === "all" ? pending.allSources : pending.textSources,
|
|
194
|
+
format: pending.format,
|
|
195
|
+
scope: pending.scope,
|
|
196
|
+
rawUploadAttachments: pending.rawUploadAttachments,
|
|
197
|
+
composerText: artifacts.fallback.composerText,
|
|
114
198
|
});
|
|
199
|
+
artifacts.fallback.composerText = applied.composerText;
|
|
200
|
+
artifacts.fallback.attachments = applied.attachments;
|
|
201
|
+
artifacts.fallback.bundled = applied.bundled;
|
|
202
|
+
artifacts.fallback.pendingBundle = null;
|
|
203
|
+
return artifacts.fallback;
|
|
204
|
+
}
|
|
205
|
+
export async function materializeStagedFallbackBundle({ composerText, attachments, format, scope, bundleParentDir, }) {
|
|
206
|
+
const textAttachments = attachments.filter((attachment) => !isRawUploadFile(attachment.path));
|
|
207
|
+
const rawAttachments = attachments.filter((attachment) => isRawUploadFile(attachment.path));
|
|
208
|
+
const textSources = textAttachments.map((attachment) => ({
|
|
209
|
+
absolutePath: attachment.path,
|
|
210
|
+
displayPath: attachment.displayPath,
|
|
211
|
+
sizeBytes: attachment.sizeBytes ?? 0,
|
|
212
|
+
}));
|
|
213
|
+
const allSources = [
|
|
214
|
+
...textSources,
|
|
215
|
+
...rawAttachments.map((attachment) => ({
|
|
216
|
+
absolutePath: attachment.path,
|
|
217
|
+
displayPath: attachment.displayPath,
|
|
218
|
+
sizeBytes: attachment.sizeBytes ?? 0,
|
|
219
|
+
})),
|
|
220
|
+
];
|
|
221
|
+
const sections = await Promise.all(textAttachments.map(async (attachment, index) => {
|
|
222
|
+
const content = await fs.readFile(attachment.path, "utf8");
|
|
223
|
+
return {
|
|
224
|
+
index: index + 1,
|
|
225
|
+
absolutePath: attachment.path,
|
|
226
|
+
displayPath: attachment.displayPath,
|
|
227
|
+
content,
|
|
228
|
+
sectionText: "",
|
|
229
|
+
};
|
|
230
|
+
}));
|
|
231
|
+
return applyWrittenBundle({
|
|
232
|
+
sections,
|
|
233
|
+
sources: scope === "all" ? allSources : textSources,
|
|
234
|
+
format,
|
|
235
|
+
scope,
|
|
236
|
+
rawUploadAttachments: rawAttachments,
|
|
237
|
+
composerText,
|
|
238
|
+
bundleParentDir,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
async function writeBrowserBundle(sections, sources, format, bundleName, bundleParentDir = os.tmpdir()) {
|
|
242
|
+
const tokenEstimateText = formatSectionsForBundle(sections, { lineNumbers: format === "text" });
|
|
243
|
+
let content = tokenEstimateText;
|
|
115
244
|
if (format === "zip") {
|
|
116
245
|
const totalSourceBytes = sources.reduce((total, source) => total + source.sizeBytes, 0);
|
|
117
246
|
if (totalSourceBytes > MAX_BROWSER_ZIP_BUNDLE_BYTES) {
|
|
118
247
|
throw new Error(`Browser ZIP bundle inputs exceed the ${MAX_BROWSER_ZIP_BUNDLE_BYTES}-byte in-memory limit.`);
|
|
119
248
|
}
|
|
120
|
-
|
|
121
|
-
const buffer = createStoredZip(await Promise.all(sources.map(async (source) => ({
|
|
249
|
+
content = createStoredZip(await Promise.all(sources.map(async (source) => ({
|
|
122
250
|
path: source.displayPath,
|
|
123
251
|
content: await fs.readFile(source.absolutePath),
|
|
124
252
|
}))));
|
|
125
|
-
|
|
253
|
+
}
|
|
254
|
+
const bundleDir = await fs.mkdtemp(path.join(bundleParentDir, GENERATED_BUNDLE_DIR_PREFIX));
|
|
255
|
+
const bundlePath = path.join(bundleDir, bundleName);
|
|
256
|
+
try {
|
|
257
|
+
await fs.writeFile(bundlePath, content);
|
|
126
258
|
return {
|
|
127
259
|
attachment: {
|
|
128
260
|
path: bundlePath,
|
|
129
261
|
displayPath: bundlePath,
|
|
130
|
-
sizeBytes:
|
|
262
|
+
sizeBytes: Buffer.byteLength(content),
|
|
131
263
|
generatedBundle: true,
|
|
132
264
|
},
|
|
133
|
-
metadata: {
|
|
265
|
+
metadata: {
|
|
266
|
+
originalCount: format === "zip" ? sources.length : sections.length,
|
|
267
|
+
bundlePath,
|
|
268
|
+
format,
|
|
269
|
+
},
|
|
134
270
|
tokenEstimateText,
|
|
135
271
|
};
|
|
136
272
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
path: bundlePath,
|
|
142
|
-
displayPath: bundlePath,
|
|
143
|
-
sizeBytes: Buffer.byteLength(tokenEstimateText, "utf8"),
|
|
144
|
-
generatedBundle: true,
|
|
145
|
-
},
|
|
146
|
-
metadata: { originalCount: sections.length, bundlePath, format },
|
|
147
|
-
tokenEstimateText,
|
|
148
|
-
};
|
|
273
|
+
catch (error) {
|
|
274
|
+
await fs.rm(bundleDir, { recursive: true, force: true });
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
149
277
|
}
|
|
150
278
|
export async function assembleBrowserPrompt(runOptions, deps = {}) {
|
|
151
279
|
const cwd = deps.cwd ?? process.cwd();
|
|
@@ -206,10 +334,10 @@ export async function assembleBrowserPrompt(runOptions, deps = {}) {
|
|
|
206
334
|
.filter(Boolean)
|
|
207
335
|
.join("\n\n")
|
|
208
336
|
.trim();
|
|
209
|
-
const selectedPlan = attachmentsPolicy === "
|
|
210
|
-
?
|
|
211
|
-
: attachmentsPolicy === "
|
|
212
|
-
?
|
|
337
|
+
const selectedPlan = attachmentsPolicy === "never"
|
|
338
|
+
? inlinePlan
|
|
339
|
+
: attachmentsPolicy === "always" || bundleRequested
|
|
340
|
+
? uploadPlan
|
|
213
341
|
: inlineComposerText.length <= DEFAULT_BROWSER_INLINE_CHAR_BUDGET || sections.length === 0
|
|
214
342
|
? inlinePlan
|
|
215
343
|
: uploadPlan;
|
|
@@ -228,13 +356,13 @@ export async function assembleBrowserPrompt(runOptions, deps = {}) {
|
|
|
228
356
|
const resolvedBundleFormat = resolveBrowserBundleFormat(bundleFormat, {
|
|
229
357
|
hasRawUploadFiles: rawUploadAttachments.length > 0,
|
|
230
358
|
});
|
|
231
|
-
const
|
|
232
|
-
attachmentCount: attachments.length,
|
|
359
|
+
const bundleScope = resolveBrowserBundleScope(resolvedBundleFormat, {
|
|
233
360
|
bundleRequested,
|
|
234
|
-
|
|
235
|
-
|
|
361
|
+
rawAttachmentCount: rawUploadAttachments.length,
|
|
362
|
+
textAttachmentCount: selectedPlan.attachments.length,
|
|
236
363
|
});
|
|
237
|
-
const
|
|
364
|
+
const shouldBundle = bundleScope !== "none";
|
|
365
|
+
let composerText = (!shouldBundle && selectedPlan.inlineBlock
|
|
238
366
|
? [...baseComposerSections, selectedPlan.inlineBlock]
|
|
239
367
|
: baseComposerSections)
|
|
240
368
|
.filter(Boolean)
|
|
@@ -242,85 +370,116 @@ export async function assembleBrowserPrompt(runOptions, deps = {}) {
|
|
|
242
370
|
.trim();
|
|
243
371
|
let bundleText = null;
|
|
244
372
|
let bundled = null;
|
|
245
|
-
if (
|
|
246
|
-
const writtenBundle = await
|
|
373
|
+
if (bundleScope !== "none") {
|
|
374
|
+
const writtenBundle = await applyWrittenBundle({
|
|
375
|
+
sections,
|
|
376
|
+
sources: bundleScope === "all" ? allBundleSources : textBundleSources,
|
|
377
|
+
format: resolvedBundleFormat,
|
|
378
|
+
scope: bundleScope,
|
|
379
|
+
rawUploadAttachments,
|
|
380
|
+
composerText,
|
|
381
|
+
});
|
|
247
382
|
bundleText = writtenBundle.tokenEstimateText;
|
|
248
383
|
attachments.length = 0;
|
|
249
|
-
attachments.push(writtenBundle.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
bundled = writtenBundle.metadata;
|
|
384
|
+
attachments.push(...writtenBundle.attachments);
|
|
385
|
+
bundled = writtenBundle.bundled;
|
|
386
|
+
composerText = writtenBundle.composerText;
|
|
254
387
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
388
|
+
else {
|
|
389
|
+
assertAttachmentCount(attachments.length, resolvedBundleFormat);
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
assertUniqueAttachmentBasenames(attachments, cwd);
|
|
393
|
+
const inlineFileCount = shouldBundle ? 0 : selectedPlan.inlineFileCount;
|
|
394
|
+
const modelConfig = isKnownModel(runOptions.model)
|
|
395
|
+
? MODEL_CONFIGS[runOptions.model]
|
|
396
|
+
: MODEL_CONFIGS["gpt-5.1"];
|
|
397
|
+
const tokenizer = deps.tokenizeImpl ?? modelConfig.tokenizer;
|
|
398
|
+
const tokenizerUserSections = [userPrompt];
|
|
399
|
+
if (inlineFileCount > 0 && selectedPlan.inlineBlock) {
|
|
400
|
+
tokenizerUserSections.push(selectedPlan.inlineBlock);
|
|
401
|
+
}
|
|
402
|
+
if (shouldBundle && resolvedBundleFormat === "zip" && bundled) {
|
|
403
|
+
tokenizerUserSections.push(appendZipBundleInstruction("", bundled.originalCount, bundled.bundlePath));
|
|
404
|
+
}
|
|
405
|
+
const tokenizerUserContent = tokenizerUserSections
|
|
263
406
|
.filter((value) => Boolean(value?.trim()))
|
|
264
407
|
.join("\n\n")
|
|
265
|
-
.trim()
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
408
|
+
.trim();
|
|
409
|
+
const tokenizerMessages = [
|
|
410
|
+
systemPrompt ? { role: "system", content: systemPrompt } : null,
|
|
411
|
+
tokenizerUserContent ? { role: "user", content: tokenizerUserContent } : null,
|
|
412
|
+
].filter(Boolean);
|
|
413
|
+
let estimatedInputTokens = tokenizer(tokenizerMessages.length > 0 ? tokenizerMessages : [{ role: "user", content: "" }], TOKENIZER_OPTIONS);
|
|
414
|
+
const tokenEstimateIncludesInlineFiles = inlineFileCount > 0 && Boolean(selectedPlan.inlineBlock);
|
|
415
|
+
if (!tokenEstimateIncludesInlineFiles && sections.length > 0) {
|
|
416
|
+
const attachmentText = bundleText ?? formatFileSections(sections, { lineNumbers: false });
|
|
417
|
+
const attachmentTokens = tokenizer([{ role: "user", content: attachmentText }], TOKENIZER_OPTIONS);
|
|
418
|
+
estimatedInputTokens += attachmentTokens;
|
|
419
|
+
}
|
|
420
|
+
let fallback = null;
|
|
421
|
+
let pendingFallback;
|
|
422
|
+
if (attachmentsPolicy === "auto" && selectedPlan.mode === "inline" && sections.length > 0) {
|
|
423
|
+
const fallbackComposerText = baseComposerSections.join("\n\n").trim();
|
|
424
|
+
const fallbackAttachments = [...uploadPlan.attachments, ...rawUploadAttachments];
|
|
425
|
+
const fallbackBundleFormat = resolveBrowserBundleFormat(bundleFormat, {
|
|
426
|
+
hasRawUploadFiles: rawUploadAttachments.length > 0,
|
|
427
|
+
});
|
|
428
|
+
const fallbackBundleScope = resolveBrowserBundleScope(fallbackBundleFormat, {
|
|
429
|
+
bundleRequested,
|
|
430
|
+
rawAttachmentCount: rawUploadAttachments.length,
|
|
431
|
+
textAttachmentCount: uploadPlan.attachments.length,
|
|
432
|
+
});
|
|
433
|
+
fallback = {
|
|
434
|
+
composerText: fallbackComposerText,
|
|
435
|
+
attachments: fallbackAttachments,
|
|
436
|
+
bundled: null,
|
|
437
|
+
pendingBundle: fallbackBundleScope === "none"
|
|
438
|
+
? null
|
|
439
|
+
: { format: fallbackBundleFormat, scope: fallbackBundleScope },
|
|
440
|
+
};
|
|
441
|
+
if (fallbackBundleScope !== "none") {
|
|
442
|
+
pendingFallback = {
|
|
443
|
+
format: fallbackBundleFormat,
|
|
444
|
+
scope: fallbackBundleScope,
|
|
445
|
+
sections,
|
|
446
|
+
textSources: textBundleSources,
|
|
447
|
+
allSources: allBundleSources,
|
|
448
|
+
rawUploadAttachments,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
assertAttachmentCount(fallbackAttachments.length, fallbackBundleFormat);
|
|
298
453
|
}
|
|
299
|
-
fallbackBundled = writtenBundle.metadata;
|
|
300
454
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
composerText
|
|
304
|
-
|
|
305
|
-
|
|
455
|
+
const artifacts = {
|
|
456
|
+
markdown,
|
|
457
|
+
composerText,
|
|
458
|
+
estimatedInputTokens,
|
|
459
|
+
attachments,
|
|
460
|
+
inlineFileCount,
|
|
461
|
+
tokenEstimateIncludesInlineFiles,
|
|
462
|
+
attachmentsPolicy,
|
|
463
|
+
attachmentMode: shouldBundle
|
|
464
|
+
? "bundle"
|
|
465
|
+
: attachments.length > 0
|
|
466
|
+
? "upload"
|
|
467
|
+
: selectedPlan.mode === "bundle"
|
|
468
|
+
? "inline"
|
|
469
|
+
: selectedPlan.mode,
|
|
470
|
+
fallback,
|
|
471
|
+
bundled,
|
|
306
472
|
};
|
|
473
|
+
if (pendingFallback) {
|
|
474
|
+
pendingFallbackBundles.set(artifacts, pendingFallback);
|
|
475
|
+
}
|
|
476
|
+
return artifacts;
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
await Promise.all(attachments
|
|
480
|
+
.map(generatedBundleDirectory)
|
|
481
|
+
.filter((dir) => dir !== null)
|
|
482
|
+
.map((dir) => fs.rm(dir, { recursive: true, force: true })));
|
|
483
|
+
throw error;
|
|
307
484
|
}
|
|
308
|
-
return {
|
|
309
|
-
markdown,
|
|
310
|
-
composerText,
|
|
311
|
-
estimatedInputTokens,
|
|
312
|
-
attachments,
|
|
313
|
-
inlineFileCount,
|
|
314
|
-
tokenEstimateIncludesInlineFiles,
|
|
315
|
-
attachmentsPolicy,
|
|
316
|
-
attachmentMode: shouldBundle
|
|
317
|
-
? "bundle"
|
|
318
|
-
: attachments.length > 0
|
|
319
|
-
? "upload"
|
|
320
|
-
: selectedPlan.mode === "bundle"
|
|
321
|
-
? "inline"
|
|
322
|
-
: selectedPlan.mode,
|
|
323
|
-
fallback,
|
|
324
|
-
bundled,
|
|
325
|
-
};
|
|
326
485
|
}
|
|
@@ -20,7 +20,9 @@ async function submitPromptViaAdapter(ctx) {
|
|
|
20
20
|
const committedTurns = await submitPrompt({
|
|
21
21
|
runtime: state.runtime,
|
|
22
22
|
input: state.input,
|
|
23
|
+
page: state.page,
|
|
23
24
|
attachmentNames: state.attachmentNames ?? [],
|
|
25
|
+
attachmentNavigationUrl: state.attachmentNavigationUrl,
|
|
24
26
|
baselineTurns: state.baselineTurns ?? undefined,
|
|
25
27
|
inputTimeoutMs: state.inputTimeoutMs ?? undefined,
|
|
26
28
|
attachmentTimeoutMs: state.attachmentTimeoutMs ?? undefined,
|
|
@@ -3,8 +3,8 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { mkdtemp, mkdir, rm } from "node:fs/promises";
|
|
5
5
|
import { waitForAssistantResponse, captureAssistantMarkdown, navigateToChatGPT, ensureNotBlocked, ensureLoggedIn, ensurePromptReady, waitForResumedConversationHydration, } from "./pageActions.js";
|
|
6
|
-
import { launchChrome, connectToChrome, positionChromeWindowOffscreen, connectToRemoteChromeTarget, listRemoteChromeTargets, } from "./chromeLifecycle.js";
|
|
7
|
-
import { resolveBrowserConfig } from "./config.js";
|
|
6
|
+
import { launchChrome, connectToChrome, positionChromeWindowOffscreen, positionChromeWindowOnscreen, connectToRemoteChromeTarget, listRemoteChromeTargets, } from "./chromeLifecycle.js";
|
|
7
|
+
import { resolveBrowserApprovalWait, resolveBrowserConfig } from "./config.js";
|
|
8
8
|
import { clearStaleChatGptConversationCookies, syncCookies } from "./cookies.js";
|
|
9
9
|
import { CHATGPT_URL } from "./constants.js";
|
|
10
10
|
import { buildConversationTurnListExpression } from "./conversationTurns.js";
|
|
@@ -31,11 +31,14 @@ export async function resumeBrowserSession(runtime, config, logger, deps = {}) {
|
|
|
31
31
|
const host = liveRuntime.chromeHost ?? "127.0.0.1";
|
|
32
32
|
const port = liveRuntime.chromePort ?? inferPortFromBrowserWSEndpoint(liveRuntime.chromeBrowserWSEndpoint);
|
|
33
33
|
const browserWSEndpoint = liveRuntime.chromeBrowserWSEndpoint ?? undefined;
|
|
34
|
+
const approvalWaitMs = resolveBrowserApprovalWait(config?.approvalWaitMs);
|
|
34
35
|
const listTargets = deps.listTargets ??
|
|
35
36
|
(async () => (await listRemoteChromeTargets({
|
|
36
37
|
host,
|
|
37
38
|
port: port ?? 9222,
|
|
38
39
|
browserWSEndpoint,
|
|
40
|
+
approvalWaitMs,
|
|
41
|
+
logger,
|
|
39
42
|
})));
|
|
40
43
|
const targetList = (await listTargets());
|
|
41
44
|
const target = pickTarget(targetList, liveRuntime);
|
|
@@ -44,6 +47,7 @@ export async function resumeBrowserSession(runtime, config, logger, deps = {}) {
|
|
|
44
47
|
browserWSEndpoint,
|
|
45
48
|
targetId: target?.targetId ?? target?.id,
|
|
46
49
|
closeTargetOnDispose: false,
|
|
50
|
+
approvalWaitMs,
|
|
47
51
|
})
|
|
48
52
|
: await (async () => {
|
|
49
53
|
const client = (await (deps.connect ?? ((options) => CDP(options)))(browserWSEndpoint
|
|
@@ -216,7 +220,10 @@ async function resumeBrowserSessionViaNewChrome(runtime, config, logger, deps) {
|
|
|
216
220
|
await DOM.enable();
|
|
217
221
|
}
|
|
218
222
|
if (!resolved.headless && resolved.hideWindow) {
|
|
219
|
-
await positionChromeWindowOffscreen(client, logger);
|
|
223
|
+
await positionChromeWindowOffscreen(client, userDataDir, logger);
|
|
224
|
+
}
|
|
225
|
+
else if (!resolved.headless) {
|
|
226
|
+
await positionChromeWindowOnscreen(client, userDataDir, logger);
|
|
220
227
|
}
|
|
221
228
|
let appliedCookies = 0;
|
|
222
229
|
if (shouldSyncBrowserCookies(resolved, { manualLogin })) {
|
|
@@ -2,10 +2,11 @@ import chalk from "chalk";
|
|
|
2
2
|
import { formatTokenCount } from "../oracle/runUtils.js";
|
|
3
3
|
import { formatFinishLine } from "../oracle/finishLine.js";
|
|
4
4
|
import { runBrowserMode } from "../browserMode.js";
|
|
5
|
-
import {
|
|
5
|
+
import { DEFAULT_BROWSER_CONFIG } from "./config.js";
|
|
6
|
+
import { assembleBrowserPrompt, cleanupGeneratedBrowserBundles, materializeBrowserFallback, } from "./prompt.js";
|
|
6
7
|
import { BrowserAutomationError } from "../oracle/errors.js";
|
|
7
8
|
import { appendArtifacts, saveBrowserTranscriptArtifact, saveDeepResearchReportArtifact, } from "./artifacts.js";
|
|
8
|
-
import { formatBrowserModelSelectionEvidence, formatBrowserModelTarget, resolveBrowserModelDisplayName, } from "./modelDisplay.js";
|
|
9
|
+
import { formatBrowserModelSelectionEvidence, formatBrowserThinkingSelectionEvidence, formatBrowserModelTarget, resolveBrowserModelDisplayName, } from "./modelDisplay.js";
|
|
9
10
|
const LARGE_PRO_FAST_INPUT_TOKEN_THRESHOLD = 25_000;
|
|
10
11
|
const LARGE_PRO_FAST_ELAPSED_MS_THRESHOLD = 120_000;
|
|
11
12
|
function buildUnavailableModelSelectionEvidence(browserConfig) {
|
|
@@ -57,7 +58,50 @@ function buildBrowserRunWarnings(args) {
|
|
|
57
58
|
export async function runBrowserSessionExecution({ runOptions, browserConfig, cwd, log }, deps = {}) {
|
|
58
59
|
const assemblePrompt = deps.assemblePrompt ?? assembleBrowserPrompt;
|
|
59
60
|
const executeBrowser = deps.executeBrowser ?? runBrowserMode;
|
|
60
|
-
const
|
|
61
|
+
const persistRuntimeHint = deps.persistRuntimeHint ?? (() => { });
|
|
62
|
+
const inputTimeoutMs = browserConfig.inputTimeoutMs ?? DEFAULT_BROWSER_CONFIG.inputTimeoutMs;
|
|
63
|
+
let preparationTimedOut = false;
|
|
64
|
+
let preparationTimeout;
|
|
65
|
+
let promptArtifacts;
|
|
66
|
+
try {
|
|
67
|
+
promptArtifacts = await Promise.race([
|
|
68
|
+
assemblePrompt(runOptions, { cwd }).then(async (artifacts) => {
|
|
69
|
+
if (preparationTimedOut)
|
|
70
|
+
await cleanupGeneratedBrowserBundles(artifacts);
|
|
71
|
+
return artifacts;
|
|
72
|
+
}),
|
|
73
|
+
new Promise((_, reject) => {
|
|
74
|
+
preparationTimeout = setTimeout(() => {
|
|
75
|
+
preparationTimedOut = true;
|
|
76
|
+
reject(new BrowserAutomationError(`Browser prompt preparation timed out after ${inputTimeoutMs}ms; increase --browser-input-timeout if local files need more time.`, {
|
|
77
|
+
stage: "prepare-prompt",
|
|
78
|
+
code: "prompt-preparation-timeout",
|
|
79
|
+
timeoutMs: inputTimeoutMs,
|
|
80
|
+
}));
|
|
81
|
+
}, inputTimeoutMs);
|
|
82
|
+
}),
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
if (preparationTimeout) {
|
|
87
|
+
clearTimeout(preparationTimeout);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return await executeAssembledBrowserSession({
|
|
92
|
+
runOptions,
|
|
93
|
+
browserConfig,
|
|
94
|
+
log,
|
|
95
|
+
promptArtifacts,
|
|
96
|
+
executeBrowser,
|
|
97
|
+
persistRuntimeHint,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
await cleanupGeneratedBrowserBundles(promptArtifacts);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function executeAssembledBrowserSession({ runOptions, browserConfig, log, promptArtifacts, executeBrowser, persistRuntimeHint, }) {
|
|
61
105
|
if (runOptions.verbose) {
|
|
62
106
|
log(chalk.dim(`[verbose] Browser config: ${JSON.stringify({
|
|
63
107
|
...browserConfig,
|
|
@@ -91,7 +135,7 @@ export async function runBrowserSessionExecution({ runOptions, browserConfig, cw
|
|
|
91
135
|
if (typeof message !== "string")
|
|
92
136
|
return;
|
|
93
137
|
const shouldAlwaysPrint = message.startsWith("[browser] ") &&
|
|
94
|
-
/archive|fallback|follow-up|retry|thinking|waiting for chatgpt|browser slot|browser control|browser guidance|model selection|model picker/i.test(message);
|
|
138
|
+
/archive|fallback|follow-up|retry|thinking|waiting for chatgpt|remote debugging approval|browser slot|browser control|browser guidance|model selection|model picker/i.test(message);
|
|
95
139
|
if (!runOptions.verbose && !shouldAlwaysPrint)
|
|
96
140
|
return;
|
|
97
141
|
log(message);
|
|
@@ -103,7 +147,22 @@ export async function runBrowserSessionExecution({ runOptions, browserConfig, cw
|
|
|
103
147
|
if (runOptions.verbose) {
|
|
104
148
|
log(chalk.dim("Chrome automation does not stream output; this may take a minute..."));
|
|
105
149
|
}
|
|
106
|
-
|
|
150
|
+
let fallbackSubmission = undefined;
|
|
151
|
+
if (promptArtifacts.fallback) {
|
|
152
|
+
fallbackSubmission = {
|
|
153
|
+
prompt: promptArtifacts.fallback.composerText,
|
|
154
|
+
attachments: promptArtifacts.fallback.attachments,
|
|
155
|
+
pendingBundle: promptArtifacts.fallback.pendingBundle ?? undefined,
|
|
156
|
+
prepare: async () => {
|
|
157
|
+
const prepared = await materializeBrowserFallback(promptArtifacts);
|
|
158
|
+
if (!prepared || !fallbackSubmission)
|
|
159
|
+
return;
|
|
160
|
+
fallbackSubmission.prompt = prepared.composerText;
|
|
161
|
+
fallbackSubmission.attachments = prepared.attachments;
|
|
162
|
+
fallbackSubmission.pendingBundle = undefined;
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
107
166
|
const executionBrowserConfig = runOptions.browserResumeConversationUrl
|
|
108
167
|
? { ...browserConfig, resumeConversationUrl: runOptions.browserResumeConversationUrl }
|
|
109
168
|
: browserConfig;
|
|
@@ -112,12 +171,7 @@ export async function runBrowserSessionExecution({ runOptions, browserConfig, cw
|
|
|
112
171
|
browserResult = await executeBrowser({
|
|
113
172
|
prompt: promptArtifacts.composerText,
|
|
114
173
|
attachments: promptArtifacts.attachments,
|
|
115
|
-
fallbackSubmission
|
|
116
|
-
? {
|
|
117
|
-
prompt: promptArtifacts.fallback.composerText,
|
|
118
|
-
attachments: promptArtifacts.fallback.attachments,
|
|
119
|
-
}
|
|
120
|
-
: undefined,
|
|
174
|
+
fallbackSubmission,
|
|
121
175
|
config: executionBrowserConfig,
|
|
122
176
|
log: automationLogger,
|
|
123
177
|
heartbeatIntervalMs: runOptions.heartbeatIntervalMs,
|
|
@@ -151,6 +205,10 @@ export async function runBrowserSessionExecution({ runOptions, browserConfig, cw
|
|
|
151
205
|
if (modelSelection) {
|
|
152
206
|
log(`[browser] Model selection evidence: ${formatBrowserModelSelectionEvidence(modelSelection, runOptions.model)}`);
|
|
153
207
|
}
|
|
208
|
+
const thinkingSelection = browserResult.thinkingSelection;
|
|
209
|
+
if (thinkingSelection) {
|
|
210
|
+
log(`[browser] Thinking effort evidence: ${formatBrowserThinkingSelectionEvidence(thinkingSelection)}`);
|
|
211
|
+
}
|
|
154
212
|
const warnings = buildBrowserRunWarnings({
|
|
155
213
|
runOptions,
|
|
156
214
|
browserConfig,
|
|
@@ -227,9 +285,11 @@ export async function runBrowserSessionExecution({ runOptions, browserConfig, cw
|
|
|
227
285
|
},
|
|
228
286
|
archive: browserResult.archive,
|
|
229
287
|
modelSelection,
|
|
288
|
+
thinkingSelection,
|
|
230
289
|
warnings,
|
|
231
290
|
answerText,
|
|
232
291
|
artifacts: savedArtifacts,
|
|
292
|
+
savedFiles: browserResult.savedFiles,
|
|
233
293
|
};
|
|
234
294
|
}
|
|
235
295
|
export async function ensureSessionArtifacts(params) {
|