@steipete/oracle 0.13.0 → 0.14.1
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 +22 -11
- package/dist/bin/oracle-cli.js +71 -71
- package/dist/src/browser/actions/assistantResponse.js +93 -10
- package/dist/src/browser/actions/deepResearch.js +180 -52
- package/dist/src/browser/actions/modelSelection.js +357 -40
- package/dist/src/browser/actions/navigation.js +294 -65
- package/dist/src/browser/actions/promptComposer.js +50 -4
- package/dist/src/browser/actions/thinkingTime.js +517 -105
- package/dist/src/browser/artifacts.js +19 -0
- package/dist/src/browser/chatgptFiles.js +797 -0
- package/dist/src/browser/chatgptImages.js +256 -27
- package/dist/src/browser/chromeLifecycle.js +4 -0
- package/dist/src/browser/config.js +2 -0
- package/dist/src/browser/index.js +404 -41
- package/dist/src/browser/pageActions.js +1 -1
- package/dist/src/browser/policies.js +2 -6
- package/dist/src/browser/projectSourcesRunner.js +16 -3
- package/dist/src/browser/prompt.js +161 -36
- package/dist/src/browser/reattach.js +6 -2
- package/dist/src/browser/reattachability.js +22 -10
- package/dist/src/browser/recoverConversation.js +73 -0
- package/dist/src/browser/sessionRunner.js +4 -1
- package/dist/src/cli/browserConfig.js +6 -2
- package/dist/src/cli/browserDefaults.js +2 -1
- package/dist/src/cli/browserTabs.js +129 -54
- package/dist/src/cli/followup.js +72 -0
- package/dist/src/cli/help.js +1 -1
- package/dist/src/cli/options.js +24 -0
- package/dist/src/cli/reattachGuidance.js +8 -0
- package/dist/src/cli/runOptions.js +2 -12
- package/dist/src/cli/sessionCommand.js +4 -0
- package/dist/src/cli/sessionDisplay.js +17 -3
- package/dist/src/cli/sessionLineage.js +7 -4
- package/dist/src/cli/sessionRunner.js +16 -1
- package/dist/src/gemini-web/client.js +5 -10
- package/dist/src/gemini-web/executor.js +1 -24
- package/dist/src/gemini-web/models.js +83 -0
- package/dist/src/mcp/server.js +2 -0
- package/dist/src/mcp/tools/chatgptImage.js +132 -0
- package/dist/src/mcp/tools/consult.js +270 -175
- package/dist/src/mcp/types.js +13 -2
- package/dist/src/mcp/utils.js +87 -1
- package/dist/src/oracle/config.js +27 -1
- package/dist/src/oracle/files.js +4 -6
- package/dist/src/oracle/geminiModels.js +2 -0
- package/dist/src/oracle/markdown.js +36 -3
- package/dist/src/oracle/modelResolver.js +21 -13
- package/dist/src/oracle/promptAssembly.js +2 -4
- package/dist/src/oracle/request.js +3 -5
- package/dist/src/oracle/thinkingTime.js +40 -0
- package/dist/src/oracle/tokenStats.js +5 -1
- package/dist/src/oracle.js +1 -1
- package/dist/src/sessionManager.js +1 -0
- package/dist/vendor/oracle-notifier/build-notifier.sh +0 -0
- package/package.json +47 -58
- package/vendor/oracle-notifier/build-notifier.sh +0 -0
- package/dist/bin/oracle.js +0 -569
- package/dist/src/browser/chromeCookies.js +0 -312
- package/dist/src/browser/keytarShim.js +0 -56
- package/dist/src/browser/windowsCookies.js +0 -219
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/Info.plist +0 -20
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +0 -128
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/Info.plist +0 -20
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/Resources/OracleIcon.icns +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/_CodeSignature/CodeResources +0 -128
- package/vendor/oracle-notifier/README.md +0 -26
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getCliVersion } from "../../version.js";
|
|
3
|
-
import { LoggingMessageNotificationParamsSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { LoggingMessageNotificationParamsSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
import { ensureBrowserAvailable, mapConsultToRunOptions } from "../utils.js";
|
|
5
5
|
import { sessionStore } from "../../sessionStore.js";
|
|
6
6
|
import { resolveRemoteServiceConfig } from "../../remote/remoteServiceConfig.js";
|
|
@@ -20,11 +20,12 @@ async function readSessionLogTail(sessionId, maxBytes) {
|
|
|
20
20
|
import { performSessionRun } from "../../cli/sessionRunner.js";
|
|
21
21
|
import { runDryRunSummary } from "../../cli/dryRun.js";
|
|
22
22
|
import { CHATGPT_URL } from "../../browser/constants.js";
|
|
23
|
-
import { CONSULT_PRESETS, consultInputSchema } from "../types.js";
|
|
23
|
+
import { CONSULT_PRESETS, browserThinkingTimeRawSchema, consultInputSchema } from "../types.js";
|
|
24
24
|
import { applyConsultPreset } from "../consultPresets.js";
|
|
25
25
|
import { loadUserConfig } from "../../config.js";
|
|
26
26
|
import { resolveNotificationSettings } from "../../cli/notifier.js";
|
|
27
27
|
import { mapModelToBrowserLabel, resolveBrowserModelLabel } from "../../cli/browserConfig.js";
|
|
28
|
+
import { normalizeThinkingTimeLevel } from "../../oracle/thinkingTime.js";
|
|
28
29
|
// Use raw shapes so the MCP SDK (with its bundled Zod) wraps them and emits valid JSON Schema.
|
|
29
30
|
const consultInputShape = {
|
|
30
31
|
preset: z
|
|
@@ -61,11 +62,10 @@ const consultInputShape = {
|
|
|
61
62
|
.optional()
|
|
62
63
|
.describe("Browser-only: bundle many files into a single upload (helps with upload limits)."),
|
|
63
64
|
browserBundleFormat: z
|
|
64
|
-
.enum(["text", "zip"])
|
|
65
|
+
.enum(["auto", "text", "zip"])
|
|
65
66
|
.optional()
|
|
66
|
-
.describe('Browser-only: bundle upload format when browserBundleFiles is true or auto-bundling is needed. Defaults to "
|
|
67
|
-
browserThinkingTime:
|
|
68
|
-
.enum(["light", "standard", "extended", "heavy"])
|
|
67
|
+
.describe('Browser-only: bundle upload format when browserBundleFiles is true or auto-bundling is needed. Defaults to "auto"; "auto" uses ZIP when bundled inputs include raw/binary files.'),
|
|
68
|
+
browserThinkingTime: browserThinkingTimeRawSchema
|
|
69
69
|
.optional()
|
|
70
70
|
.describe("Browser-only: set ChatGPT thinking time when supported by the chosen model."),
|
|
71
71
|
browserModelStrategy: z
|
|
@@ -88,6 +88,14 @@ const consultInputShape = {
|
|
|
88
88
|
.boolean()
|
|
89
89
|
.optional()
|
|
90
90
|
.describe("Browser-only: keep Chrome running after completion (useful for debugging)."),
|
|
91
|
+
generateImage: z
|
|
92
|
+
.string()
|
|
93
|
+
.optional()
|
|
94
|
+
.describe("Browser-only: save generated image(s) to this file path. For ChatGPT browser mode this enables the image-aware wait/download path used by CLI --generate-image."),
|
|
95
|
+
outputPath: z
|
|
96
|
+
.string()
|
|
97
|
+
.optional()
|
|
98
|
+
.describe("Browser-only image output fallback path, mirroring the CLI --output option for image operations."),
|
|
91
99
|
dryRun: z
|
|
92
100
|
.boolean()
|
|
93
101
|
.optional()
|
|
@@ -130,6 +138,20 @@ const consultModelSummaryShape = z.object({
|
|
|
130
138
|
.optional(),
|
|
131
139
|
logPath: z.string().optional(),
|
|
132
140
|
});
|
|
141
|
+
const consultArtifactSummaryShape = z.object({
|
|
142
|
+
kind: z.enum(["transcript", "deep-research-report", "image", "file"]),
|
|
143
|
+
path: z.string(),
|
|
144
|
+
label: z.string().optional(),
|
|
145
|
+
mimeType: z.string().optional(),
|
|
146
|
+
sizeBytes: z.number().optional(),
|
|
147
|
+
});
|
|
148
|
+
const consultImageSummaryShape = consultArtifactSummaryShape.extend({
|
|
149
|
+
kind: z.literal("image"),
|
|
150
|
+
alt: z.string().optional(),
|
|
151
|
+
width: z.number().optional(),
|
|
152
|
+
height: z.number().optional(),
|
|
153
|
+
fileId: z.string().optional(),
|
|
154
|
+
});
|
|
133
155
|
const consultDryRunResolvedShape = z.object({
|
|
134
156
|
resolvedEngine: z.enum(["api", "browser"]),
|
|
135
157
|
model: z.string(),
|
|
@@ -144,22 +166,25 @@ const consultDryRunResolvedShape = z.object({
|
|
|
144
166
|
researchMode: z.string().nullable().optional(),
|
|
145
167
|
attachments: z.string().optional(),
|
|
146
168
|
bundleFiles: z.boolean().optional(),
|
|
147
|
-
bundleFormat: z.enum(["text", "zip"]).optional(),
|
|
169
|
+
bundleFormat: z.enum(["auto", "text", "zip"]).optional(),
|
|
148
170
|
keepBrowser: z.boolean().optional(),
|
|
149
171
|
manualLogin: z.boolean().optional(),
|
|
150
172
|
profileDir: z.string().nullable().optional(),
|
|
151
173
|
chatgptUrl: z.string().nullable().optional(),
|
|
174
|
+
imageOutputPath: z.string().nullable().optional(),
|
|
152
175
|
})
|
|
153
176
|
.optional(),
|
|
154
177
|
guidance: z.array(z.string()),
|
|
155
178
|
});
|
|
156
|
-
const consultOutputShape = {
|
|
179
|
+
export const consultOutputShape = {
|
|
157
180
|
sessionId: z.string().optional(),
|
|
158
181
|
status: z.string(),
|
|
159
182
|
output: z.string(),
|
|
160
183
|
dryRun: z.boolean().optional(),
|
|
161
184
|
resolved: consultDryRunResolvedShape.optional(),
|
|
162
185
|
models: z.array(consultModelSummaryShape).optional(),
|
|
186
|
+
artifacts: z.array(consultArtifactSummaryShape).optional(),
|
|
187
|
+
images: z.array(consultImageSummaryShape).optional(),
|
|
163
188
|
};
|
|
164
189
|
export function summarizeModelRunsForConsult(runs) {
|
|
165
190
|
if (!runs || runs.length === 0) {
|
|
@@ -191,6 +216,43 @@ export function summarizeModelRunsForConsult(runs) {
|
|
|
191
216
|
};
|
|
192
217
|
});
|
|
193
218
|
}
|
|
219
|
+
function optionalString(value) {
|
|
220
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
221
|
+
}
|
|
222
|
+
function optionalNumber(value) {
|
|
223
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
224
|
+
}
|
|
225
|
+
export function summarizeArtifactsForConsult(artifacts) {
|
|
226
|
+
if (!artifacts || artifacts.length === 0) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
return artifacts.map((artifact) => ({
|
|
230
|
+
kind: artifact.kind,
|
|
231
|
+
path: artifact.path,
|
|
232
|
+
label: artifact.label,
|
|
233
|
+
mimeType: artifact.mimeType,
|
|
234
|
+
sizeBytes: artifact.sizeBytes,
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
export function summarizeImageArtifactsForConsult(artifacts) {
|
|
238
|
+
const images = (artifacts ?? [])
|
|
239
|
+
.filter((artifact) => artifact.kind === "image")
|
|
240
|
+
.map((artifact) => {
|
|
241
|
+
const image = artifact;
|
|
242
|
+
return {
|
|
243
|
+
kind: "image",
|
|
244
|
+
path: artifact.path,
|
|
245
|
+
label: artifact.label,
|
|
246
|
+
mimeType: artifact.mimeType,
|
|
247
|
+
sizeBytes: artifact.sizeBytes,
|
|
248
|
+
alt: optionalString(image.alt),
|
|
249
|
+
width: optionalNumber(image.width),
|
|
250
|
+
height: optionalNumber(image.height),
|
|
251
|
+
fileId: optionalString(image.fileId),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
return images.length > 0 ? images : undefined;
|
|
255
|
+
}
|
|
194
256
|
export function buildConsultBrowserConfig({ userConfig, env, runModel, inputModel, browserModelLabel, browserThinkingTime, browserModelStrategy, browserResearchMode, browserArchive, browserKeepBrowser, }) {
|
|
195
257
|
const configuredBrowser = userConfig.browser ?? {};
|
|
196
258
|
const envProfileDir = (env.ORACLE_BROWSER_PROFILE_DIR ?? "").trim();
|
|
@@ -204,6 +266,7 @@ export function buildConsultBrowserConfig({ userConfig, env, runModel, inputMode
|
|
|
204
266
|
const manualLogin = hasProfileDir
|
|
205
267
|
? true
|
|
206
268
|
: (configuredBrowser.manualLogin ?? process.platform === "win32");
|
|
269
|
+
const configuredThinkingTime = normalizeThinkingTimeLevel(configuredBrowser.thinkingTime);
|
|
207
270
|
return {
|
|
208
271
|
...configuredBrowser,
|
|
209
272
|
url: configuredUrl,
|
|
@@ -216,7 +279,7 @@ export function buildConsultBrowserConfig({ userConfig, env, runModel, inputMode
|
|
|
216
279
|
manualLoginProfileDir: manualLogin
|
|
217
280
|
? ((envProfileDir || configuredBrowser.manualLoginProfileDir) ?? null)
|
|
218
281
|
: null,
|
|
219
|
-
thinkingTime: browserThinkingTime ??
|
|
282
|
+
thinkingTime: browserThinkingTime ?? configuredThinkingTime ?? undefined,
|
|
220
283
|
modelStrategy: browserModelStrategy ?? configuredBrowser.modelStrategy,
|
|
221
284
|
researchMode: browserResearchMode ?? configuredBrowser.researchMode,
|
|
222
285
|
archiveConversations: browserArchive ?? configuredBrowser.archiveConversations,
|
|
@@ -250,6 +313,10 @@ export function buildConsultDryRunResolved({ resolvedEngine, runOptions, browser
|
|
|
250
313
|
if (followUpCount > 0) {
|
|
251
314
|
guidance.push("This is a multi-turn browser consult; all follow-ups stay in one ChatGPT conversation.");
|
|
252
315
|
}
|
|
316
|
+
const imageOutputPath = runOptions.generateImage ?? runOptions.outputPath ?? null;
|
|
317
|
+
if (resolvedEngine === "browser" && imageOutputPath) {
|
|
318
|
+
guidance.push("ChatGPT generated images will use the image-aware wait/download path and return saved files in structuredContent.images.");
|
|
319
|
+
}
|
|
253
320
|
return {
|
|
254
321
|
resolvedEngine,
|
|
255
322
|
model: runOptions.model,
|
|
@@ -269,6 +336,7 @@ export function buildConsultDryRunResolved({ resolvedEngine, runOptions, browser
|
|
|
269
336
|
manualLogin: browserConfig?.manualLogin,
|
|
270
337
|
profileDir: browserConfig?.manualLoginProfileDir ?? null,
|
|
271
338
|
chatgptUrl,
|
|
339
|
+
imageOutputPath,
|
|
272
340
|
}
|
|
273
341
|
: undefined,
|
|
274
342
|
guidance,
|
|
@@ -291,7 +359,7 @@ export function formatConsultDryRunResolved(details) {
|
|
|
291
359
|
lines.push(` browser research mode: ${details.browser.researchMode ?? "off"}`);
|
|
292
360
|
lines.push(` browser attachments: ${details.browser.attachments ?? "auto"}`);
|
|
293
361
|
lines.push(` browser bundle files: ${details.browser.bundleFiles ? "yes" : "no"}`);
|
|
294
|
-
lines.push(` browser bundle format: ${details.browser.bundleFormat ?? "
|
|
362
|
+
lines.push(` browser bundle format: ${details.browser.bundleFormat ?? "auto"}`);
|
|
295
363
|
lines.push(` browser keep browser: ${details.browser.keepBrowser ? "yes" : "no"}`);
|
|
296
364
|
lines.push(` browser manual login: ${details.browser.manualLogin ? "yes" : "no"}`);
|
|
297
365
|
if (details.browser.profileDir) {
|
|
@@ -300,6 +368,9 @@ export function formatConsultDryRunResolved(details) {
|
|
|
300
368
|
if (details.browser.chatgptUrl) {
|
|
301
369
|
lines.push(` ChatGPT URL: ${details.browser.chatgptUrl}`);
|
|
302
370
|
}
|
|
371
|
+
if (details.browser.imageOutputPath) {
|
|
372
|
+
lines.push(` image output: ${details.browser.imageOutputPath}`);
|
|
373
|
+
}
|
|
303
374
|
}
|
|
304
375
|
lines.push(` follow-ups: ${details.followUpCount}`);
|
|
305
376
|
for (const guidance of details.guidance) {
|
|
@@ -307,28 +378,24 @@ export function formatConsultDryRunResolved(details) {
|
|
|
307
378
|
}
|
|
308
379
|
return lines;
|
|
309
380
|
}
|
|
310
|
-
export function
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
const { prompt, files, model, models, engine, search, browserModelLabel, browserAttachments, browserBundleFiles, browserBundleFormat, browserThinkingTime, browserModelStrategy, browserResearchMode, browserArchive, browserFollowUps, browserKeepBrowser, dryRun, slug, } = parsedInput;
|
|
330
|
-
const { config: userConfig } = await loadUserConfig();
|
|
331
|
-
const { runOptions, resolvedEngine } = mapConsultToRunOptions({
|
|
381
|
+
export async function runConsultTool(input, { server }) {
|
|
382
|
+
const textContent = (text) => [{ type: "text", text }];
|
|
383
|
+
let parsedInput;
|
|
384
|
+
try {
|
|
385
|
+
parsedInput = applyConsultPreset(consultInputSchema.parse(input));
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
return {
|
|
389
|
+
isError: true,
|
|
390
|
+
content: textContent(error instanceof Error ? error.message : String(error)),
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
const { prompt, files, model, models, engine, search, browserModelLabel, browserAttachments, browserBundleFiles, browserBundleFormat, browserThinkingTime, browserModelStrategy, browserResearchMode, browserArchive, browserFollowUps, browserKeepBrowser, generateImage, outputPath, dryRun, slug, } = parsedInput;
|
|
394
|
+
const { config: userConfig } = await loadUserConfig();
|
|
395
|
+
let runOptions;
|
|
396
|
+
let resolvedEngine;
|
|
397
|
+
try {
|
|
398
|
+
({ runOptions, resolvedEngine } = mapConsultToRunOptions({
|
|
332
399
|
prompt,
|
|
333
400
|
files: files ?? [],
|
|
334
401
|
model,
|
|
@@ -339,160 +406,188 @@ export function registerConsultTool(server) {
|
|
|
339
406
|
browserBundleFiles,
|
|
340
407
|
browserBundleFormat,
|
|
341
408
|
browserFollowUps,
|
|
409
|
+
generateImage,
|
|
410
|
+
outputPath,
|
|
342
411
|
userConfig,
|
|
343
412
|
env: process.env,
|
|
413
|
+
}));
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
return {
|
|
417
|
+
isError: true,
|
|
418
|
+
content: textContent(error instanceof Error ? error.message : String(error)),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const cwd = process.cwd();
|
|
422
|
+
const sendLog = (text, level = "info") => server
|
|
423
|
+
.sendLoggingMessage(LoggingMessageNotificationParamsSchema.parse({
|
|
424
|
+
level,
|
|
425
|
+
data: { text, bytes: Buffer.byteLength(text, "utf8") },
|
|
426
|
+
}))
|
|
427
|
+
.catch(() => { });
|
|
428
|
+
const resolvedRemote = resolveRemoteServiceConfig({ userConfig, env: process.env });
|
|
429
|
+
const imageOutputPath = runOptions.generateImage ?? runOptions.outputPath;
|
|
430
|
+
if (resolvedEngine === "browser" && resolvedRemote.host && imageOutputPath) {
|
|
431
|
+
return {
|
|
432
|
+
isError: true,
|
|
433
|
+
content: textContent("ChatGPT image output is not supported with a remote browser service: generated files are not transferred back to the MCP caller. Unset ORACLE_REMOTE_HOST to generate images locally, or omit generateImage/outputPath."),
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
let browserConfig;
|
|
437
|
+
if (resolvedEngine === "browser") {
|
|
438
|
+
browserConfig = buildConsultBrowserConfig({
|
|
439
|
+
userConfig,
|
|
440
|
+
env: process.env,
|
|
441
|
+
runModel: runOptions.model,
|
|
442
|
+
inputModel: model,
|
|
443
|
+
browserModelLabel,
|
|
444
|
+
browserThinkingTime,
|
|
445
|
+
browserModelStrategy,
|
|
446
|
+
browserResearchMode,
|
|
447
|
+
browserArchive,
|
|
448
|
+
browserKeepBrowser,
|
|
344
449
|
});
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
browserConfig
|
|
356
|
-
userConfig,
|
|
357
|
-
env: process.env,
|
|
358
|
-
runModel: runOptions.model,
|
|
359
|
-
inputModel: model,
|
|
360
|
-
browserModelLabel,
|
|
361
|
-
browserThinkingTime,
|
|
362
|
-
browserModelStrategy,
|
|
363
|
-
browserResearchMode,
|
|
364
|
-
browserArchive,
|
|
365
|
-
browserKeepBrowser,
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
if (dryRun) {
|
|
369
|
-
const lines = [];
|
|
370
|
-
const log = (line) => {
|
|
371
|
-
lines.push(line);
|
|
372
|
-
sendLog(line);
|
|
373
|
-
};
|
|
374
|
-
const resolved = buildConsultDryRunResolved({
|
|
375
|
-
resolvedEngine,
|
|
376
|
-
runOptions,
|
|
377
|
-
browserConfig,
|
|
378
|
-
});
|
|
379
|
-
await runDryRunSummary({
|
|
380
|
-
engine: resolvedEngine,
|
|
381
|
-
runOptions,
|
|
382
|
-
cwd,
|
|
383
|
-
version: getCliVersion(),
|
|
384
|
-
log,
|
|
385
|
-
browserConfig,
|
|
386
|
-
});
|
|
387
|
-
for (const line of formatConsultDryRunResolved(resolved)) {
|
|
388
|
-
log(line);
|
|
389
|
-
}
|
|
390
|
-
const output = lines.join("\n").trim();
|
|
391
|
-
return {
|
|
392
|
-
content: textContent(output),
|
|
393
|
-
structuredContent: {
|
|
394
|
-
status: "dry-run",
|
|
395
|
-
output,
|
|
396
|
-
dryRun: true,
|
|
397
|
-
resolved,
|
|
398
|
-
},
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
const browserGuard = ensureBrowserAvailable(resolvedEngine, {
|
|
402
|
-
remoteHost: resolvedRemote.host,
|
|
450
|
+
}
|
|
451
|
+
if (dryRun) {
|
|
452
|
+
const lines = [];
|
|
453
|
+
const log = (line) => {
|
|
454
|
+
lines.push(line);
|
|
455
|
+
sendLog(line);
|
|
456
|
+
};
|
|
457
|
+
const resolved = buildConsultDryRunResolved({
|
|
458
|
+
resolvedEngine,
|
|
459
|
+
runOptions,
|
|
460
|
+
browserConfig,
|
|
403
461
|
});
|
|
404
|
-
|
|
462
|
+
await runDryRunSummary({
|
|
463
|
+
engine: resolvedEngine,
|
|
464
|
+
runOptions,
|
|
465
|
+
cwd,
|
|
466
|
+
version: getCliVersion(),
|
|
467
|
+
log,
|
|
468
|
+
browserConfig,
|
|
469
|
+
});
|
|
470
|
+
for (const line of formatConsultDryRunResolved(resolved)) {
|
|
471
|
+
log(line);
|
|
472
|
+
}
|
|
473
|
+
const output = lines.join("\n").trim();
|
|
474
|
+
return {
|
|
475
|
+
content: textContent(output),
|
|
476
|
+
structuredContent: {
|
|
477
|
+
status: "dry-run",
|
|
478
|
+
output,
|
|
479
|
+
dryRun: true,
|
|
480
|
+
resolved,
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
const browserGuard = ensureBrowserAvailable(resolvedEngine, {
|
|
485
|
+
remoteHost: resolvedRemote.host,
|
|
486
|
+
});
|
|
487
|
+
if (resolvedEngine === "browser" && browserGuard) {
|
|
488
|
+
return {
|
|
489
|
+
isError: true,
|
|
490
|
+
content: textContent(browserGuard),
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
let browserDeps;
|
|
494
|
+
if (resolvedEngine === "browser" && resolvedRemote.host) {
|
|
495
|
+
if (!resolvedRemote.token) {
|
|
405
496
|
return {
|
|
406
497
|
isError: true,
|
|
407
|
-
content: textContent(
|
|
498
|
+
content: textContent(`Remote host configured (${resolvedRemote.host}) but remote token is missing. Run \`oracle bridge client --connect <...>\` or set ORACLE_REMOTE_TOKEN.`),
|
|
408
499
|
};
|
|
409
500
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
501
|
+
browserDeps = {
|
|
502
|
+
executeBrowser: createRemoteBrowserExecutor({
|
|
503
|
+
host: resolvedRemote.host,
|
|
504
|
+
token: resolvedRemote.token,
|
|
505
|
+
}),
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
const notifications = resolveNotificationSettings({
|
|
509
|
+
cliNotify: undefined,
|
|
510
|
+
cliNotifySound: undefined,
|
|
511
|
+
env: process.env,
|
|
512
|
+
config: userConfig.notify,
|
|
513
|
+
});
|
|
514
|
+
const sessionMeta = await sessionStore.createSession({
|
|
515
|
+
...runOptions,
|
|
516
|
+
mode: resolvedEngine,
|
|
517
|
+
slug,
|
|
518
|
+
browserConfig,
|
|
519
|
+
waitPreference: true,
|
|
520
|
+
}, cwd, notifications);
|
|
521
|
+
const logWriter = sessionStore.createLogWriter(sessionMeta.id);
|
|
522
|
+
// Stream logs to both the session log and MCP logging notifications, but avoid buffering in memory
|
|
523
|
+
const log = (line) => {
|
|
524
|
+
logWriter.logLine(line);
|
|
525
|
+
if (line !== undefined) {
|
|
526
|
+
sendLog(line);
|
|
424
527
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
528
|
+
};
|
|
529
|
+
const write = (chunk) => {
|
|
530
|
+
logWriter.writeChunk(chunk);
|
|
531
|
+
sendLog(chunk, "debug");
|
|
532
|
+
return true;
|
|
533
|
+
};
|
|
534
|
+
try {
|
|
535
|
+
await performSessionRun({
|
|
536
|
+
sessionMeta,
|
|
537
|
+
runOptions,
|
|
433
538
|
mode: resolvedEngine,
|
|
434
|
-
slug,
|
|
435
539
|
browserConfig,
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
540
|
+
cwd,
|
|
541
|
+
log,
|
|
542
|
+
write,
|
|
543
|
+
version: getCliVersion(),
|
|
544
|
+
notifications,
|
|
545
|
+
muteStdout: true,
|
|
546
|
+
browserDeps,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
catch (error) {
|
|
550
|
+
log(`Run failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
551
|
+
return {
|
|
552
|
+
isError: true,
|
|
553
|
+
content: textContent(`Session ${sessionMeta.id} failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
finally {
|
|
557
|
+
logWriter.stream.end();
|
|
558
|
+
}
|
|
559
|
+
try {
|
|
560
|
+
const finalMeta = (await sessionStore.readSession(sessionMeta.id)) ?? sessionMeta;
|
|
561
|
+
const summary = `Session ${sessionMeta.id} (${finalMeta.status})`;
|
|
562
|
+
const logTail = await readSessionLogTail(sessionMeta.id, 4000);
|
|
563
|
+
const modelsSummary = summarizeModelRunsForConsult(finalMeta.models);
|
|
564
|
+
const artifacts = summarizeArtifactsForConsult(finalMeta.artifacts);
|
|
565
|
+
const images = summarizeImageArtifactsForConsult(finalMeta.artifacts);
|
|
566
|
+
return {
|
|
567
|
+
content: textContent([summary, logTail || "(log empty)"].join("\n").trim()),
|
|
568
|
+
structuredContent: {
|
|
569
|
+
sessionId: sessionMeta.id,
|
|
570
|
+
status: finalMeta.status,
|
|
571
|
+
output: logTail ?? "",
|
|
572
|
+
models: modelsSummary,
|
|
573
|
+
artifacts,
|
|
574
|
+
images,
|
|
575
|
+
},
|
|
445
576
|
};
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
return {
|
|
580
|
+
isError: true,
|
|
581
|
+
content: textContent(`Session completed but metadata fetch failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
450
582
|
};
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
notifications,
|
|
462
|
-
muteStdout: true,
|
|
463
|
-
browserDeps,
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
catch (error) {
|
|
467
|
-
log(`Run failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
468
|
-
return {
|
|
469
|
-
isError: true,
|
|
470
|
-
content: textContent(`Session ${sessionMeta.id} failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
finally {
|
|
474
|
-
logWriter.stream.end();
|
|
475
|
-
}
|
|
476
|
-
try {
|
|
477
|
-
const finalMeta = (await sessionStore.readSession(sessionMeta.id)) ?? sessionMeta;
|
|
478
|
-
const summary = `Session ${sessionMeta.id} (${finalMeta.status})`;
|
|
479
|
-
const logTail = await readSessionLogTail(sessionMeta.id, 4000);
|
|
480
|
-
const modelsSummary = summarizeModelRunsForConsult(finalMeta.models);
|
|
481
|
-
return {
|
|
482
|
-
content: textContent([summary, logTail || "(log empty)"].join("\n").trim()),
|
|
483
|
-
structuredContent: {
|
|
484
|
-
sessionId: sessionMeta.id,
|
|
485
|
-
status: finalMeta.status,
|
|
486
|
-
output: logTail ?? "",
|
|
487
|
-
models: modelsSummary,
|
|
488
|
-
},
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
catch (error) {
|
|
492
|
-
return {
|
|
493
|
-
isError: true,
|
|
494
|
-
content: textContent(`Session completed but metadata fetch failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
export function registerConsultTool(server) {
|
|
586
|
+
server.registerTool("consult", {
|
|
587
|
+
title: "Run an oracle session",
|
|
588
|
+
description: 'Run an Oracle session (API or ChatGPT browser automation). Use `files` to attach project context. If `engine` is omitted, Oracle follows CLI defaults: config/ORACLE_ENGINE first, then API when OPENAI_API_KEY is set, otherwise browser. Browser GPT-5.5 Pro consults can take many minutes; use `dryRun:true` first when configuring an agent and inspect `sessions`/`oracle status` before retrying. Browser manual-login uses a private Oracle Chrome profile separate from the user\'s normal Chrome; dry-run output includes first-time setup guidance when that path is active. For browser-based image/file uploads, set `browserAttachments:"always"`. For ChatGPT image generation, set `generateImage` to enable the same image wait/download path as CLI --generate-image and read returned paths from `images`. Browser consults can include `browserFollowUps` for a multi-turn ChatGPT review in one conversation. Sessions are stored under `ORACLE_HOME_DIR` (shared with the CLI).',
|
|
589
|
+
// Cast to any to satisfy SDK typings across differing Zod versions.
|
|
590
|
+
inputSchema: consultInputShape,
|
|
591
|
+
outputSchema: consultOutputShape,
|
|
592
|
+
}, async (input) => runConsultTool(input, { server: server.server }));
|
|
498
593
|
}
|
package/dist/src/mcp/types.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { THINKING_TIME_INPUT_VALUES, normalizeThinkingTimeLevel } from "../oracle/thinkingTime.js";
|
|
2
3
|
export const CONSULT_PRESETS = ["chatgpt-pro-heavy"];
|
|
4
|
+
export const browserThinkingTimeRawSchema = z.enum(THINKING_TIME_INPUT_VALUES);
|
|
5
|
+
export const browserThinkingTimeInputSchema = browserThinkingTimeRawSchema.transform((value) => {
|
|
6
|
+
const normalized = normalizeThinkingTimeLevel(value);
|
|
7
|
+
if (!normalized) {
|
|
8
|
+
throw new Error(`Unknown browserThinkingTime value: ${value}`);
|
|
9
|
+
}
|
|
10
|
+
return normalized;
|
|
11
|
+
});
|
|
3
12
|
export const consultInputSchema = z
|
|
4
13
|
.object({
|
|
5
14
|
preset: z.enum(CONSULT_PRESETS).optional(),
|
|
@@ -11,13 +20,15 @@ export const consultInputSchema = z
|
|
|
11
20
|
browserModelLabel: z.string().optional(),
|
|
12
21
|
browserAttachments: z.enum(["auto", "never", "always"]).optional(),
|
|
13
22
|
browserBundleFiles: z.boolean().optional(),
|
|
14
|
-
browserBundleFormat: z.enum(["text", "zip"]).optional(),
|
|
15
|
-
browserThinkingTime:
|
|
23
|
+
browserBundleFormat: z.enum(["auto", "text", "zip"]).optional(),
|
|
24
|
+
browserThinkingTime: browserThinkingTimeInputSchema.optional(),
|
|
16
25
|
browserModelStrategy: z.enum(["select", "current", "ignore"]).optional(),
|
|
17
26
|
browserResearchMode: z.enum(["deep"]).optional(),
|
|
18
27
|
browserArchive: z.enum(["auto", "always", "never"]).optional(),
|
|
19
28
|
browserFollowUps: z.array(z.string()).optional(),
|
|
20
29
|
browserKeepBrowser: z.boolean().optional(),
|
|
30
|
+
generateImage: z.string().optional(),
|
|
31
|
+
outputPath: z.string().optional(),
|
|
21
32
|
dryRun: z.boolean().optional(),
|
|
22
33
|
search: z.boolean().optional(),
|
|
23
34
|
slug: z.string().optional(),
|