@youdie006/prodex 0.39.4 → 0.39.5
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/dist/chatgpt-browser.js +35 -9
- package/dist/cli-args.js +5 -1
- package/dist/cli-help.js +5 -4
- package/dist/cli-pro.js +58 -2
- package/dist/mcp.js +5 -1
- package/package.json +1 -1
package/dist/chatgpt-browser.js
CHANGED
|
@@ -613,14 +613,32 @@ export function hasChatGptPromptAcceptance(previous, state) {
|
|
|
613
613
|
* they were getting Pro reasoning when they were not.
|
|
614
614
|
*/
|
|
615
615
|
export function modelSelectionWarning(requestedModel, modelSlug) {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
616
|
+
return selectionMismatchWarning({
|
|
617
|
+
...(requestedModel !== undefined ? { model: requestedModel } : {}),
|
|
618
|
+
...(modelSlug !== undefined ? { modelSlug } : {})
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
/** Whether a requested label names ChatGPT's Pro step, in either locale. */
|
|
622
|
+
export function namesPro(label) {
|
|
623
|
+
if (!label)
|
|
624
|
+
return false;
|
|
625
|
+
return /\bpro\b/i.test(label) || label.includes("프로");
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Compare what was asked for against the model that actually answered.
|
|
629
|
+
*
|
|
630
|
+
* Pro can be asked for on either axis - `--model Pro` or `--effort Pro` - and
|
|
631
|
+
* this only ever looked at the model, so an effort-shaped Pro request answered
|
|
632
|
+
* by a lesser model passed without a word. Measured: a consult asking for Pro
|
|
633
|
+
* came back from gpt-5-6-thinking and was recorded as a clean success.
|
|
634
|
+
*/
|
|
635
|
+
export function selectionMismatchWarning(input) {
|
|
636
|
+
const asked = namesPro(input.model) ? input.model : namesPro(input.effort) ? input.effort : undefined;
|
|
637
|
+
if (!asked || !input.modelSlug)
|
|
620
638
|
return undefined;
|
|
621
|
-
if (/pro/i.test(modelSlug))
|
|
639
|
+
if (/pro/i.test(input.modelSlug))
|
|
622
640
|
return undefined;
|
|
623
|
-
return `model_mismatch: you asked for ${
|
|
641
|
+
return `model_mismatch: you asked for ${asked}, but the answer came from "${input.modelSlug}". Check the model picker in the browser; the selection did not take.`;
|
|
624
642
|
}
|
|
625
643
|
/**
|
|
626
644
|
* The panel ChatGPT raises to ask which of two answers you prefer.
|
|
@@ -2248,6 +2266,14 @@ async function selectModelReasoning(cdp, options, selectionWarnings = []) {
|
|
|
2248
2266
|
const noSuchStep = /has no "[^"]*" step/.test(message);
|
|
2249
2267
|
if (!noSuchStep)
|
|
2250
2268
|
throw error;
|
|
2269
|
+
// Asking for a step is a contract. Sending at whatever the slider
|
|
2270
|
+
// happened to be on is not a lesser version of that contract, it is
|
|
2271
|
+
// a different answer that the caller cannot use: measured, a Pro
|
|
2272
|
+
// request came back from gpt-5-6-thinking after minutes of waiting
|
|
2273
|
+
// and was thrown away. A caller that would rather have any answer
|
|
2274
|
+
// says so with --allow-model-fallback.
|
|
2275
|
+
if (!options.allowSelectionFallback)
|
|
2276
|
+
throw error;
|
|
2251
2277
|
const offered = /It showed: (.*)$/.exec(message)?.[1]?.split(" / ").map((part) => part.trim()) ?? [];
|
|
2252
2278
|
selectionWarnings.push(stepSelectionUnavailableWarning(plan.sliderLabel, offered));
|
|
2253
2279
|
}
|
|
@@ -3108,7 +3134,7 @@ export async function sendChatGptPrompt(options) {
|
|
|
3108
3134
|
answer: transcript.answer,
|
|
3109
3135
|
modelHints: finalState?.modelHints ?? [],
|
|
3110
3136
|
...(transcript.modelSlug ? { modelSlug: transcript.modelSlug } : finalState?.modelSlug ? { modelSlug: finalState.modelSlug } : {}),
|
|
3111
|
-
warnings: withDialogNote([...sendWarnings,
|
|
3137
|
+
warnings: withDialogNote([...sendWarnings, selectionMismatchWarning({ ...(options.model !== undefined ? { model: options.model } : {}), ...(options.effort !== undefined ? { effort: options.effort } : {}), ...((transcript.modelSlug || finalState?.modelSlug) ? { modelSlug: (transcript.modelSlug || finalState?.modelSlug) } : {}) })]).filter((warning) => Boolean(warning))
|
|
3112
3138
|
};
|
|
3113
3139
|
};
|
|
3114
3140
|
// Deep research never reaches the DOM answer wait below: the report is
|
|
@@ -3256,7 +3282,7 @@ export async function sendChatGptPrompt(options) {
|
|
|
3256
3282
|
answer: completed.answer.trim(),
|
|
3257
3283
|
modelHints: completed.modelHints,
|
|
3258
3284
|
...(completed.modelSlug ? { modelSlug: completed.modelSlug } : {}),
|
|
3259
|
-
warnings: withDialogNote([...sendWarnings,
|
|
3285
|
+
warnings: withDialogNote([...sendWarnings, selectionMismatchWarning({ ...(options.model !== undefined ? { model: options.model } : {}), ...(options.effort !== undefined ? { effort: options.effort } : {}), ...(completed.modelSlug !== undefined ? { modelSlug: completed.modelSlug } : {}) })]).filter((warning) => Boolean(warning))
|
|
3260
3286
|
};
|
|
3261
3287
|
}
|
|
3262
3288
|
// Timed out while the answer was still streaming: salvage the partial text
|
|
@@ -3272,7 +3298,7 @@ export async function sendChatGptPrompt(options) {
|
|
|
3272
3298
|
...(completed.modelSlug ? { modelSlug: completed.modelSlug } : {}),
|
|
3273
3299
|
warnings: withDialogNote([
|
|
3274
3300
|
...sendWarnings,
|
|
3275
|
-
...(
|
|
3301
|
+
...(selectionMismatchWarning({ ...(options.model !== undefined ? { model: options.model } : {}), ...(options.effort !== undefined ? { effort: options.effort } : {}), ...(completed.modelSlug !== undefined ? { modelSlug: completed.modelSlug } : {}) }) ? [selectionMismatchWarning({ ...(options.model !== undefined ? { model: options.model } : {}), ...(options.effort !== undefined ? { effort: options.effort } : {}), ...(completed.modelSlug !== undefined ? { modelSlug: completed.modelSlug } : {}) })] : []),
|
|
3276
3302
|
`answer_incomplete: ChatGPT was still generating after ${formatDurationMs(timeoutMs)} (${timeoutMs}ms), so the answer below may be truncated. Raise --timeout-ms and retry for the full response.`
|
|
3277
3303
|
])
|
|
3278
3304
|
};
|
package/dist/cli-args.js
CHANGED
|
@@ -259,7 +259,11 @@ export const ASK_PRO_BOOLEAN_FLAGS = new Set([
|
|
|
259
259
|
"--auto-login",
|
|
260
260
|
"--no-auto-login",
|
|
261
261
|
// Send outside any project for once, overriding a pinned default.
|
|
262
|
-
"--no-project"
|
|
262
|
+
"--no-project",
|
|
263
|
+
// Send even when the requested model/effort could not be applied, rather
|
|
264
|
+
// than stopping. Off by default: an answer from a step nobody asked for is
|
|
265
|
+
// usually thrown away.
|
|
266
|
+
"--allow-model-fallback"
|
|
263
267
|
]);
|
|
264
268
|
export const ASK_PRO_SELECTION_VALUE_FLAGS = ["--project", "--project-new", "--model", "--pro-mode", "--effort"];
|
|
265
269
|
export const ASK_PRO_VALUE_FLAGS = new Set([
|
package/dist/cli-help.js
CHANGED
|
@@ -26,7 +26,7 @@ Ask / consult commands:
|
|
|
26
26
|
prodex pro browser models [--source-cli /absolute/path/to/dist/cli.js] [--port 9333] [--timeout-ms 15000] # read-only list of model menu options
|
|
27
27
|
prodex pro browser projects [--source-cli /absolute/path/to/dist/cli.js] [--port 9333] [--timeout-ms 15000] # read-only list of sidebar project names (for --project)
|
|
28
28
|
prodex pro browser recover [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] --target-url <thread-url> [--timeout-ms 60000] # recover a finished answer from a thread whose send timed out
|
|
29
|
-
prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--temporary] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"|Max|Ultra|Pro] [--project "name" | --project-new "name"] "prompt" # explicit visible-browser send
|
|
29
|
+
prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--temporary] [--allow-model-fallback] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"|Max|Ultra|Pro] [--project "name" | --project-new "name"] "prompt" # explicit visible-browser send
|
|
30
30
|
prodex pro latest [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--json]
|
|
31
31
|
prodex pro list [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--json]
|
|
32
32
|
prodex pro show <task-id|latest> [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--json]
|
|
@@ -88,6 +88,7 @@ Optional visible-browser send defaults (applied by \`pro browser ask\` when the
|
|
|
88
88
|
--model Composer model by its exact menu label. Only Pro applies on the current picker: it is a slider step, and the model rows cannot be clicked
|
|
89
89
|
--pro-mode Pro sub-mode: 기본 (standard) or 확장 (extended)
|
|
90
90
|
--effort Reasoning effort: 즉시 / 중간 / 높음 / 매우 높음 / Max / Ultra / Pro. Max and Ultra are rungs of ChatGPT's Work surface and only apply when the browser is already on Work (prodex does not switch to Work for them); every other value is sent on Chat, whose top step is Pro
|
|
91
|
+
--allow-model-fallback Send even when the requested model/effort could not be applied. Off by default: a send that could not reach what was asked for stops instead, because an answer from a step nobody asked for is usually unusable
|
|
91
92
|
--project Sidebar project to enter before sending
|
|
92
93
|
Clear a saved default with --clear-model / --clear-pro-mode / --clear-effort / --clear-project.
|
|
93
94
|
--pro-mode and --effort are different model axes and cannot be combined. View saved defaults with \`prodex status\`.`);
|
|
@@ -168,7 +169,7 @@ Commands:
|
|
|
168
169
|
prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
|
|
169
170
|
prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
|
|
170
171
|
prodex pro browser models [--source-cli /absolute/path/to/dist/cli.js]
|
|
171
|
-
prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--target-url url --confirm-target] [--new-chat] [--temporary] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"|Max|Ultra|Pro] [--project "name" | --project-new "name"] "prompt"
|
|
172
|
+
prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--target-url url --confirm-target] [--new-chat] [--temporary] [--allow-model-fallback] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"|Max|Ultra|Pro] [--project "name" | --project-new "name"] "prompt"
|
|
172
173
|
prodex pro latest [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--json]
|
|
173
174
|
prodex pro list [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--json]
|
|
174
175
|
prodex pro show <task-id|latest> [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--json]
|
|
@@ -255,8 +256,8 @@ export function printProBrowserHelp(stdout, sourceCli) {
|
|
|
255
256
|
: "prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000]";
|
|
256
257
|
const selectionUsage = '[--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"|Max|Ultra|Pro] [--project "name" | --project-new "name"]';
|
|
257
258
|
const askUsage = sourceCli
|
|
258
|
-
? `${cli} pro browser ask${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--temporary] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] ${selectionUsage} "prompt"`
|
|
259
|
-
: `prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--temporary] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] ${selectionUsage} "prompt"`;
|
|
259
|
+
? `${cli} pro browser ask${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--temporary] [--allow-model-fallback] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] ${selectionUsage} "prompt"`
|
|
260
|
+
: `prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--temporary] [--allow-model-fallback] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] ${selectionUsage} "prompt"`;
|
|
260
261
|
const modelsUsage = sourceCli
|
|
261
262
|
? `${cli} pro browser models${sourceCliOption} [--port 9333] [--timeout-ms 15000]`
|
|
262
263
|
: "prodex pro browser models [--source-cli /absolute/path/to/dist/cli.js] [--port 9333] [--timeout-ms 15000]";
|
package/dist/cli-pro.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, statSync } from "node:fs";
|
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { buildDryRunBundle } from "./bundle.js";
|
|
5
|
-
import { DEFAULT_CDP_PORT, resolveCdpPort, resolveConversationToDelete, resolveProjectToDelete, chatGptVisibilityBlocker, defaultChatGptProfileDir, formatDurationMs, getChatGptBrowserStatus, formatModelMenuOption, listChatGptModelOptions, deleteChatGptConversation, endWedgedBrowser, browserRecoveryPlan, findWedgedBrowser, wedgedBrowserBlocker, deleteChatGptProject, listChatGptProjectsWithIds, listRecentChatGptConversations, listChatGptSidebarProjects, normalizeChatGptTargetUrl, openChatGptBrowser, openChatGptTab, parseProMode, parseReasoningEffort, defaultTimeoutForTools, ensureVirtualDisplay, minimizeChatGptWindow, readLastBrowserLoginLaunch, resolveVirtualDisplayPreference, resolveBrowserWindowMode, resolveHeadlessPreference, recordBrowserLoginLaunch, recoverChatGptAnswerFromThread, sendChatGptPrompt, statusMeansBrowserDead } from "./chatgpt-browser.js";
|
|
5
|
+
import { DEFAULT_CDP_PORT, resolveCdpPort, resolveConversationToDelete, resolveProjectToDelete, chatGptVisibilityBlocker, defaultChatGptProfileDir, formatDurationMs, getChatGptBrowserStatus, formatModelMenuOption, listChatGptModelOptions, deleteChatGptConversation, endWedgedBrowser, browserRecoveryPlan, findWedgedBrowser, wedgedBrowserBlocker, deleteChatGptProject, listChatGptProjectsWithIds, listRecentChatGptConversations, listChatGptSidebarProjects, normalizeChatGptTargetUrl, openChatGptBrowser, openChatGptTab, parseProMode, parseReasoningEffort, defaultTimeoutForTools, ensureVirtualDisplay, minimizeChatGptWindow, readLastBrowserLoginLaunch, resolveVirtualDisplayPreference, resolveBrowserWindowMode, resolveHeadlessPreference, recordBrowserLoginLaunch, recoverChatGptAnswerFromThread, sendChatGptPrompt, statusMeansBrowserDead, namesPro } from "./chatgpt-browser.js";
|
|
6
6
|
import { ASK_PRO_BOOLEAN_FLAGS, ASK_PRO_PREVIEW_VALUE_FLAGS, ASK_PRO_VALUE_FLAGS, assertHelpRequestArgs, assertNoExtraArgs, assertOnlyOptions, findHelpFlagIndexBeforePromptDelimiter, formatCliCommand, hasAskProDryRunMode, hasAskProMode, hasAskProSendMode, isHelpSubcommand, parseAskProArgs, printHelpIfRequested, readFlag, readPortFlag, readPositionalsWithOptions, readNonNegativeIntegerFlag, readPositiveIntegerFlag, readRepeatedFlag, resolveCwdFlag, resolveOptionalFileFlag, unknownSubcommandError } from "./cli-args.js";
|
|
7
7
|
import { printProBrowserHelp, printProHelp } from "./cli-help.js";
|
|
8
8
|
import { listRawResultsForInspection, listTasksForInspection } from "./cli-ledger.js";
|
|
@@ -1110,13 +1110,22 @@ export async function runAskProCommand(rest, io) {
|
|
|
1110
1110
|
};
|
|
1111
1111
|
const browserPort = hasSendMode ? resolveCdpPort(readPortFlag(parsedAskPro.optionArgs, "--port")) : undefined;
|
|
1112
1112
|
const busyWaitMs = readNonNegativeIntegerFlag(parsedAskPro.optionArgs, "--busy-wait-ms");
|
|
1113
|
+
const allowSelectionFallback = parsedAskPro.optionArgs.includes("--allow-model-fallback");
|
|
1113
1114
|
// Pro extended can legitimately think for minutes, so its default timeout is
|
|
1114
1115
|
// higher; an explicit --timeout-ms always wins.
|
|
1115
1116
|
// Pro reasoning routinely runs for many minutes (a real consult measured
|
|
1116
1117
|
// ~13 minutes). The elevated default used to be keyed to the removed
|
|
1117
1118
|
// --pro-mode, so --model Pro sends fell back to 90s and chronically timed
|
|
1118
1119
|
// out. Any effective Pro selection now defaults to 15 minutes.
|
|
1119
|
-
|
|
1120
|
+
// Pro can be asked for on either axis. Keying the raised budget to the
|
|
1121
|
+
// model alone gave `--effort Pro` five minutes for reasoning this file's
|
|
1122
|
+
// own comment calls 6-20 minutes, which manufactured send_timeout
|
|
1123
|
+
// blockers - 55 of the 267 blockers measured on one machine.
|
|
1124
|
+
const effectiveProSelection = isProSelection({
|
|
1125
|
+
...(selectionModel !== undefined ? { model: selectionModel } : {}),
|
|
1126
|
+
...(selectionProMode !== undefined ? { proMode: selectionProMode } : {}),
|
|
1127
|
+
...(selectionEffort !== undefined ? { effort: selectionEffort } : {})
|
|
1128
|
+
});
|
|
1120
1129
|
// Pro reasoning routinely runs 6-20 minutes; 15 min was still cutting long
|
|
1121
1130
|
// answers off (field report), so a Pro selection defaults to 20 minutes.
|
|
1122
1131
|
// With NO model selection at all (no flag, no saved default) the UI's
|
|
@@ -1202,6 +1211,7 @@ export async function runAskProCommand(rest, io) {
|
|
|
1202
1211
|
model: selectionModel,
|
|
1203
1212
|
proMode: selectionProMode,
|
|
1204
1213
|
effort: selectionEffort,
|
|
1214
|
+
...(allowSelectionFallback ? { allowSelectionFallback: true } : {}),
|
|
1205
1215
|
onProgress: createBrowserSendProgressPrinter(io.stderr)
|
|
1206
1216
|
}));
|
|
1207
1217
|
// One-command recovery: interactive terminals (or explicit --auto-login)
|
|
@@ -1303,6 +1313,16 @@ export async function runAskProCommand(rest, io) {
|
|
|
1303
1313
|
io.stderr(warning);
|
|
1304
1314
|
if (consult.modelSlug)
|
|
1305
1315
|
io.stderr(`model_used: ${consult.modelSlug}`);
|
|
1316
|
+
// "Can I count this as a Pro review?" - answered here rather than left
|
|
1317
|
+
// for whoever reads the receipt to work out from two other fields.
|
|
1318
|
+
const proVerified = proSelectionVerified({
|
|
1319
|
+
...(selectionModel !== undefined ? { model: selectionModel } : {}),
|
|
1320
|
+
...(selectionProMode !== undefined ? { proMode: selectionProMode } : {}),
|
|
1321
|
+
...(selectionEffort !== undefined ? { effort: selectionEffort } : {}),
|
|
1322
|
+
...(consult.modelSlug !== undefined ? { modelSlug: consult.modelSlug } : {})
|
|
1323
|
+
});
|
|
1324
|
+
if (proVerified !== undefined)
|
|
1325
|
+
io.stderr(`pro_verified: ${proVerified ? "yes" : "no"}`);
|
|
1306
1326
|
let answerArtifactPath;
|
|
1307
1327
|
const answerArtifactBytes = Buffer.byteLength(answerArtifactText, "utf8");
|
|
1308
1328
|
if (answerArtifactBytes > MAX_FETCHABLE_RESULT_ARTIFACT_BYTES) {
|
|
@@ -1333,6 +1353,7 @@ export async function runAskProCommand(rest, io) {
|
|
|
1333
1353
|
// What actually answered, straight from ChatGPT's own tag - the
|
|
1334
1354
|
// receipt used to record only what prodex asked for.
|
|
1335
1355
|
...(consult.modelSlug ? { model_used: consult.modelSlug } : {}),
|
|
1356
|
+
...(proVerified !== undefined ? { pro_verified: proVerified } : {}),
|
|
1336
1357
|
warnings: persistenceWarnings
|
|
1337
1358
|
}
|
|
1338
1359
|
});
|
|
@@ -1498,6 +1519,7 @@ export async function performBrowserConsultForMcp(cwd, input, onProgress) {
|
|
|
1498
1519
|
...(input.attach ?? []).flatMap((file) => ["--attach", file]),
|
|
1499
1520
|
...(input.tools ?? []).flatMap((tool) => ["--tool", tool]),
|
|
1500
1521
|
...(input.new_chat ? ["--new-chat"] : []),
|
|
1522
|
+
...(input.allow_model_fallback ? ["--allow-model-fallback"] : []),
|
|
1501
1523
|
"--",
|
|
1502
1524
|
input.prompt
|
|
1503
1525
|
];
|
|
@@ -1705,6 +1727,29 @@ export async function assertBrowserLaunchStayedAlive(opened, timeoutMs) {
|
|
|
1705
1727
|
}
|
|
1706
1728
|
throw new Error(`Chrome/Chromium did not expose a reachable DevTools endpoint after launch. Check the visible browser environment, profile lock, display access, or PRODEX_CHROME, then retry.`);
|
|
1707
1729
|
}
|
|
1730
|
+
/** Whether a send asked for ChatGPT's Pro step, on either axis that can name it. */
|
|
1731
|
+
export function isProSelection(selection) {
|
|
1732
|
+
if (selection.proMode !== undefined)
|
|
1733
|
+
return true;
|
|
1734
|
+
return namesPro(selection.model) || namesPro(selection.effort);
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Whether a Pro request was actually answered by Pro, per ChatGPT's own tag on
|
|
1738
|
+
* the message. Undefined when Pro was not asked for, or when no tag came back
|
|
1739
|
+
* to check against - there is nothing to certify in either case.
|
|
1740
|
+
*
|
|
1741
|
+
* The receipt already carried the request and the answering model separately,
|
|
1742
|
+
* leaving the comparison to whoever read it later. The question a caller has
|
|
1743
|
+
* is "can I count this as a Pro review?", and a consult that asked for Pro and
|
|
1744
|
+
* was answered by gpt-5-6-thinking was recorded as a clean success.
|
|
1745
|
+
*/
|
|
1746
|
+
export function proSelectionVerified(selection) {
|
|
1747
|
+
if (!isProSelection(selection))
|
|
1748
|
+
return undefined;
|
|
1749
|
+
if (!selection.modelSlug)
|
|
1750
|
+
return undefined;
|
|
1751
|
+
return /pro/i.test(selection.modelSlug);
|
|
1752
|
+
}
|
|
1708
1753
|
export function browserSendBlockerFromError(error) {
|
|
1709
1754
|
const blocker = typeof error === "object" && error !== null && "blocker" in error ? error.blocker : undefined;
|
|
1710
1755
|
if (typeof blocker === "object" &&
|
|
@@ -1770,6 +1815,17 @@ export function browserSendBlockerFromError(error) {
|
|
|
1770
1815
|
next_step: "Another prodex send holds the browser. Wait for it to finish and retry, or pass a longer --timeout-ms, which is also the queue budget."
|
|
1771
1816
|
};
|
|
1772
1817
|
}
|
|
1818
|
+
// The picker could not provide the step that was asked for. Retrying asks
|
|
1819
|
+
// the same picker the same question, so this is not retryable; the caller
|
|
1820
|
+
// either picks a step it offers or opts into whatever the slider is on.
|
|
1821
|
+
if (/has no "[^"]*" step/.test(message)) {
|
|
1822
|
+
return {
|
|
1823
|
+
code: "selection_not_applied",
|
|
1824
|
+
message,
|
|
1825
|
+
retryable: false,
|
|
1826
|
+
next_step: "ChatGPT's picker could not provide the model or effort that was asked for, so nothing was sent. Run `prodex pro browser models` to see the steps this account offers and ask for one of those, or pass --allow-model-fallback to send at whatever the picker is currently set to."
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1773
1829
|
// The picker's slider took focus before its key handler was attached and
|
|
1774
1830
|
// ignored every press. Retrying is the cure; nothing in the browser is
|
|
1775
1831
|
// broken, so the generic "resolve it manually" pointed at nothing.
|
package/dist/mcp.js
CHANGED
|
@@ -187,7 +187,11 @@ export function createServer(cwd = process.cwd(), options = {}) {
|
|
|
187
187
|
new_chat: z
|
|
188
188
|
.boolean()
|
|
189
189
|
.optional()
|
|
190
|
-
.describe("Start a fresh thread. Omit to continue the current thread (preferred for follow-ups).")
|
|
190
|
+
.describe("Start a fresh thread. Omit to continue the current thread (preferred for follow-ups)."),
|
|
191
|
+
allow_model_fallback: z
|
|
192
|
+
.boolean()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe("Send even when the requested model or effort could not be applied. Off by default, because an answer from a step nobody asked for is usually unusable: a consult asking for Pro that comes back from a lesser model cannot be cited as a Pro review. Pass true only when any answer beats no answer.")
|
|
191
195
|
}
|
|
192
196
|
}, async (input, extra) => {
|
|
193
197
|
// Bridge send progress to MCP progress notifications, but only when
|