@steipete/oracle 0.14.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 +2 -2
- package/dist/bin/oracle-cli.js +8 -8
- package/dist/src/browser/actions/assistantResponse.js +2 -1
- package/dist/src/browser/actions/modelSelection.js +344 -29
- package/dist/src/browser/actions/thinkingTime.js +239 -46
- package/dist/src/browser/chatgptImages.js +126 -24
- package/dist/src/browser/index.js +63 -8
- package/dist/src/browser/projectSourcesRunner.js +2 -1
- package/dist/src/browser/prompt.js +151 -22
- package/dist/src/cli/browserConfig.js +2 -1
- package/dist/src/cli/browserDefaults.js +2 -1
- package/dist/src/cli/options.js +8 -0
- package/dist/src/mcp/tools/chatgptImage.js +8 -3
- package/dist/src/mcp/tools/consult.js +9 -8
- package/dist/src/mcp/types.js +11 -2
- package/dist/src/oracle/thinkingTime.js +40 -0
- package/dist/vendor/oracle-notifier/build-notifier.sh +0 -0
- package/package.json +32 -34
- package/vendor/oracle-notifier/build-notifier.sh +0 -0
- package/dist/bin/oracle.js +0 -569
- 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 -593
- 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 -452
- package/dist/docs-site/favicon.svg +0 -14
- package/dist/docs-site/followup.html +0 -375
- package/dist/docs-site/gemini.html +0 -383
- 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 -596
- package/dist/docs-site/mcp.html +0 -391
- 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/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
package/README.md
CHANGED
|
@@ -302,8 +302,8 @@ Browser automation can open or control Chrome, so dry-runs and live runs print a
|
|
|
302
302
|
| `--browser-research deep` | Activate ChatGPT Deep Research for broad web research and cited reports (browser only). |
|
|
303
303
|
| `--browser-follow-up <prompt>` | Browser-only multi-turn consult: submit an additional prompt in the same ChatGPT conversation after the initial answer. Repeat for challenge/revision/final-decision passes. Not supported with Deep Research mode. |
|
|
304
304
|
| `--browser-archive <auto\|always\|never>` | Archive completed ChatGPT browser conversations after local artifacts are saved. `auto` archives successful one-shot chats only, and skips project, Deep Research, multi-turn, failed, and incomplete sessions. |
|
|
305
|
-
| `--browser-attachments <auto\|never\|always>` | Control browser file delivery: `auto` pastes small text files inline and uploads larger
|
|
306
|
-
| `--browser-bundle-files`, `--browser-bundle-format <text\|zip>`
|
|
305
|
+
| `--browser-attachments <auto\|never\|always>` | Control browser file delivery: `auto` pastes small text files inline and uploads larger or raw files, `never` requires inline-compatible text files, and `always` uploads files as ChatGPT attachments. |
|
|
306
|
+
| `--browser-bundle-files`, `--browser-bundle-format <auto\|text\|zip>` | Bundle browser uploads into one attachment. `auto` uses a text bundle for text-only inputs and a byte-preserving ZIP when bundled inputs include raw files; `text` writes a Markdown-style text bundle; `zip` archives the original file bytes. |
|
|
307
307
|
| `--browser-port <port>` | Pin the Chrome DevTools port (WSL/Windows firewall helper). |
|
|
308
308
|
| `--browser-inline-cookies[(-file)] <payload \| path>` | Supply cookies without Chrome/Keychain (browser). |
|
|
309
309
|
| `--browser-timeout`, `--browser-input-timeout`, `--browser-attachment-timeout` | Control overall/browser input/attachment readiness timeouts (supports h/m/s/ms). |
|
package/dist/bin/oracle-cli.js
CHANGED
|
@@ -18,7 +18,7 @@ import { DEFAULT_MODEL, MODEL_CONFIGS } from "../src/oracle/config.js";
|
|
|
18
18
|
import { isKnownModel } from "../src/oracle/modelResolver.js";
|
|
19
19
|
import { CHATGPT_URL } from "../src/browser/constants.js";
|
|
20
20
|
import { applyHelpStyling } from "../src/cli/help.js";
|
|
21
|
-
import { collectPaths, collectModelList, collectTextValues, parseFloatOption, parseIntOption, parseSearchOption, usesDefaultStatusFilters, resolvePreviewMode, normalizeModelOption, normalizeBaseUrl, resolveApiModel, inferModelFromLabel, parseHeartbeatOption, parseTimeoutOption, parseDurationOption, mergePathLikeOptions, dedupePathInputs, } from "../src/cli/options.js";
|
|
21
|
+
import { collectPaths, collectModelList, collectTextValues, parseFloatOption, parseIntOption, parseSearchOption, parseThinkingTimeOption, usesDefaultStatusFilters, resolvePreviewMode, normalizeModelOption, normalizeBaseUrl, resolveApiModel, inferModelFromLabel, parseHeartbeatOption, parseTimeoutOption, parseDurationOption, mergePathLikeOptions, dedupePathInputs, } from "../src/cli/options.js";
|
|
22
22
|
import { copyToClipboard } from "../src/cli/clipboard.js";
|
|
23
23
|
import { buildMarkdownBundle } from "../src/cli/markdownBundle.js";
|
|
24
24
|
import { shouldDetachSession } from "../src/cli/detach.js";
|
|
@@ -329,8 +329,8 @@ program
|
|
|
329
329
|
.addOption(new Option("--browser-hide-window", "Hide the Chrome window after launch (macOS headful only).").hideHelp())
|
|
330
330
|
.addOption(new Option("--browser-keep-browser", "Keep Chrome running after completion.").hideHelp())
|
|
331
331
|
.addOption(new Option("--browser-model-strategy <mode>", "ChatGPT model picker strategy: select (default) switches to the requested model, current keeps the active model, ignore skips the picker entirely.").choices(["select", "current", "ignore"]))
|
|
332
|
-
.addOption(new Option("--browser-thinking-time <level>", "Thinking time intensity for Thinking/Pro models: light, standard, extended, heavy.")
|
|
333
|
-
.
|
|
332
|
+
.addOption(new Option("--browser-thinking-time <level>", "Thinking time intensity for Thinking/Pro models: light, standard, extended, heavy, or ChatGPT UI aliases.")
|
|
333
|
+
.argParser(parseThinkingTimeOption)
|
|
334
334
|
.hideHelp())
|
|
335
335
|
.addOption(new Option("--browser-research <mode>", "Browser research mode: deep activates ChatGPT Deep Research.").choices(["off", "deep"]))
|
|
336
336
|
.addOption(new Option("--browser-archive <mode>", "Archive completed ChatGPT browser conversations after local artifacts are saved (auto archives successful non-project one-shots only).").choices(["auto", "always", "never"]))
|
|
@@ -338,7 +338,7 @@ program
|
|
|
338
338
|
.argParser(collectTextValues)
|
|
339
339
|
.default([]))
|
|
340
340
|
.addOption(new Option("--browser-allow-cookie-errors", "Continue even if Chrome cookies cannot be copied.").hideHelp())
|
|
341
|
-
.addOption(new Option("--browser-attachments <mode>", "How to deliver --file inputs in browser mode: auto (default) pastes inline up to ~60k chars then uploads; never
|
|
341
|
+
.addOption(new Option("--browser-attachments <mode>", "How to deliver --file inputs in browser mode: auto (default) pastes text inline up to ~60k chars then uploads; never requires inline-compatible text files; always uploads.")
|
|
342
342
|
.choices(["auto", "never", "always"])
|
|
343
343
|
.default("auto"))
|
|
344
344
|
.addOption(new Option("--remote-chrome <host:port>", "Connect to remote Chrome DevTools Protocol, or when combined with --browser-attach-running use this host:port as the local attach hint."))
|
|
@@ -347,9 +347,9 @@ program
|
|
|
347
347
|
.addOption(new Option("--remote-token <token>", "Access token for the remote `oracle serve` instance."))
|
|
348
348
|
.addOption(new Option("--browser-inline-files", "Alias for --browser-attachments never (force pasting file contents inline).").default(false))
|
|
349
349
|
.addOption(new Option("--browser-bundle-files", "Bundle all attachments into a single archive before uploading.").default(false))
|
|
350
|
-
.addOption(new Option("--browser-bundle-format <format>", "Bundle format for browser uploads when files are bundled:
|
|
351
|
-
.choices(["text", "zip"])
|
|
352
|
-
.default("
|
|
350
|
+
.addOption(new Option("--browser-bundle-format <format>", "Bundle format for browser uploads when files are bundled: auto (default), text, or zip.")
|
|
351
|
+
.choices(["auto", "text", "zip"])
|
|
352
|
+
.default("auto"))
|
|
353
353
|
.addOption(new Option("--youtube <url>", "YouTube video URL to analyze (Gemini web/cookie mode only; uses your signed-in Chrome cookies for gemini.google.com)."))
|
|
354
354
|
.addOption(new Option("--generate-image <file>", "Generate image and save to file (Gemini browser mode; ChatGPT browser mode saves downloadable image artifacts when present)."))
|
|
355
355
|
.addOption(new Option("--edit-image <file>", "Edit existing image (Gemini browser mode; for ChatGPT attach source images with --file and use --generate-image for output)."))
|
|
@@ -689,7 +689,7 @@ function buildRunOptions(options, overrides = {}) {
|
|
|
689
689
|
"auto",
|
|
690
690
|
browserInlineFiles: overrides.browserInlineFiles ?? options.browserInlineFiles ?? false,
|
|
691
691
|
browserBundleFiles: overrides.browserBundleFiles ?? options.browserBundleFiles ?? false,
|
|
692
|
-
browserBundleFormat: overrides.browserBundleFormat ?? options.browserBundleFormat ?? "
|
|
692
|
+
browserBundleFormat: overrides.browserBundleFormat ?? options.browserBundleFormat ?? "auto",
|
|
693
693
|
generateImage: overrides.generateImage ?? options.generateImage,
|
|
694
694
|
outputPath: overrides.outputPath ?? options.output,
|
|
695
695
|
browserFollowUps: overrides.browserFollowUps ?? options.browserFollowUp ?? [],
|
|
@@ -857,7 +857,8 @@ function buildAssistantExtractor(functionName) {
|
|
|
857
857
|
!normalizedText ||
|
|
858
858
|
normalizedText === 'edit' ||
|
|
859
859
|
normalizedText === 'stopped thinking' ||
|
|
860
|
-
normalizedText === 'stopped thinking edit'
|
|
860
|
+
normalizedText === 'stopped thinking edit' ||
|
|
861
|
+
/^thought for \\d+(?:\\.\\d+)?\\s*(?:s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours)\\s+edit$/.test(normalizedText);
|
|
861
862
|
if (generatedImages.length > 0 && imageOnlyChrome) {
|
|
862
863
|
const label = generatedImages.length === 1 ? 'Generated image.' : \`Generated \${generatedImages.length} images.\`;
|
|
863
864
|
return { text: label, html: messageRoot?.innerHTML ?? html, messageId, turnId, turnIndex: index };
|
|
@@ -12,8 +12,7 @@ export async function ensureModelSelection(Runtime, desiredModel, logger, strate
|
|
|
12
12
|
const result = outcome.result?.value;
|
|
13
13
|
switch (result?.status) {
|
|
14
14
|
case "already-selected":
|
|
15
|
-
case "switched":
|
|
16
|
-
case "switched-best-effort": {
|
|
15
|
+
case "switched": {
|
|
17
16
|
const label = result.label?.trim() || (strategy === "current" ? null : desiredModel);
|
|
18
17
|
if (strategy !== "current") {
|
|
19
18
|
assertResolvedModelSelection(desiredModel, label ?? desiredModel);
|
|
@@ -95,8 +94,8 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
95
94
|
const composerIncludesLiteral = JSON.stringify(composerSignalMatchers.includesAny);
|
|
96
95
|
const composerExcludesLiteral = JSON.stringify(composerSignalMatchers.excludesAny);
|
|
97
96
|
const composerAllowBlankLiteral = JSON.stringify(composerSignalMatchers.allowBlank);
|
|
98
|
-
const menuContainerLiteral = JSON.stringify(MENU_CONTAINER_SELECTOR);
|
|
99
|
-
const menuItemLiteral = JSON.stringify(MENU_ITEM_SELECTOR);
|
|
97
|
+
const menuContainerLiteral = JSON.stringify(`${MENU_CONTAINER_SELECTOR}, [role="listbox"], [role="dialog"]`);
|
|
98
|
+
const menuItemLiteral = JSON.stringify(`${MENU_ITEM_SELECTOR}, [role="option"], [role="radio"], [role="combobox"]`);
|
|
100
99
|
return `(() => {
|
|
101
100
|
${buildClickDispatcher()}
|
|
102
101
|
// Capture the selectors and matcher literals up front so the browser expression stays pure.
|
|
@@ -134,6 +133,8 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
134
133
|
? '5-4'
|
|
135
134
|
: normalizedTarget.includes('5 5')
|
|
136
135
|
? '5-5'
|
|
136
|
+
: normalizedTarget.includes('5 3')
|
|
137
|
+
? '5-3'
|
|
137
138
|
: normalizedTarget.includes('5 2')
|
|
138
139
|
? '5-2'
|
|
139
140
|
: normalizedTarget.includes('5 1')
|
|
@@ -196,7 +197,19 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
196
197
|
);
|
|
197
198
|
if (!label) return false;
|
|
198
199
|
if (label.includes('click to remove')) return false;
|
|
199
|
-
const modelTokens = [
|
|
200
|
+
const modelTokens = [
|
|
201
|
+
'chatgpt',
|
|
202
|
+
'gpt',
|
|
203
|
+
'instant',
|
|
204
|
+
'thinking',
|
|
205
|
+
'pro',
|
|
206
|
+
'extended',
|
|
207
|
+
'standard',
|
|
208
|
+
'medium',
|
|
209
|
+
'high',
|
|
210
|
+
'heavy',
|
|
211
|
+
'light',
|
|
212
|
+
];
|
|
200
213
|
return modelTokens.some((token) => hasToken(label, token));
|
|
201
214
|
};
|
|
202
215
|
const findModelButton = () => {
|
|
@@ -206,6 +219,14 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
206
219
|
};
|
|
207
220
|
|
|
208
221
|
const closeMenu = () => {
|
|
222
|
+
const dialogCloseButton = document.querySelector(
|
|
223
|
+
'[role="dialog"] [data-testid="close-button"]',
|
|
224
|
+
);
|
|
225
|
+
if (dialogCloseButton) {
|
|
226
|
+
try {
|
|
227
|
+
if (dispatchClickSequence(dialogCloseButton)) return;
|
|
228
|
+
} catch {}
|
|
229
|
+
}
|
|
209
230
|
const button = findModelButton();
|
|
210
231
|
if (!button) return;
|
|
211
232
|
try {
|
|
@@ -231,6 +252,25 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
231
252
|
const getComposerModelLabel = () =>
|
|
232
253
|
(document.querySelector(COMPOSER_MODEL_SIGNAL_SELECTOR)?.textContent ?? '').trim();
|
|
233
254
|
const readComposerModelSignal = () => normalizeText(getComposerModelLabel());
|
|
255
|
+
const isIntelligenceEffortLabel = (label) =>
|
|
256
|
+
label === 'instant' ||
|
|
257
|
+
label === 'medium' ||
|
|
258
|
+
label === 'high' ||
|
|
259
|
+
label === 'extra high' ||
|
|
260
|
+
label === 'extended' ||
|
|
261
|
+
label === 'standard' ||
|
|
262
|
+
label === 'heavy' ||
|
|
263
|
+
label === 'light';
|
|
264
|
+
const formatModelOptionLabel = (label) => {
|
|
265
|
+
const normalized = normalizeText(label ?? '');
|
|
266
|
+
if (normalized === '5 5' || normalized === 'gpt 5 5') return 'GPT-5.5';
|
|
267
|
+
if (normalized === '5 4' || normalized === 'gpt 5 4') return 'GPT-5.4';
|
|
268
|
+
if (normalized === '5 3' || normalized === 'gpt 5 3') return 'GPT-5.3';
|
|
269
|
+
if (normalized === '5 2' || normalized === 'gpt 5 2') return 'GPT-5.2';
|
|
270
|
+
if (normalized === '5 1' || normalized === 'gpt 5 1') return 'GPT-5.1';
|
|
271
|
+
if (normalized === '5 0' || normalized === 'gpt 5 0') return 'GPT-5.0';
|
|
272
|
+
return label || '';
|
|
273
|
+
};
|
|
234
274
|
const withProPillSignal = (label) => {
|
|
235
275
|
const resolved = label || '';
|
|
236
276
|
if (!wantsPro || !hasProComposerPill()) return resolved;
|
|
@@ -240,10 +280,84 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
240
280
|
if (normalized.includes('pro')) return resolved;
|
|
241
281
|
return resolved + ' + Pro';
|
|
242
282
|
};
|
|
243
|
-
const getResolvedLabel = (fallback) =>
|
|
244
|
-
withProPillSignal(getComposerModelLabel() || getButtonLabel() || fallback);
|
|
245
283
|
const isThinkingEffortLabel = (label) =>
|
|
246
|
-
label === 'extended' ||
|
|
284
|
+
label === 'extended' ||
|
|
285
|
+
label === 'standard' ||
|
|
286
|
+
label === 'heavy' ||
|
|
287
|
+
label === 'light' ||
|
|
288
|
+
label === 'medium' ||
|
|
289
|
+
label === 'high' ||
|
|
290
|
+
label === 'extra high';
|
|
291
|
+
const isNonProIntelligenceThinkingLabel = (label) =>
|
|
292
|
+
label === 'medium' || label === 'high' || label === 'extra high';
|
|
293
|
+
const scoreNonProGpt55ThinkingLabel = (label) => {
|
|
294
|
+
if (label === 'extra high') return 1400;
|
|
295
|
+
if (label === 'high') return 1200;
|
|
296
|
+
return 1000;
|
|
297
|
+
};
|
|
298
|
+
const versionFromLabel = (label) => {
|
|
299
|
+
if (label === '5 5' || label === 'gpt 5 5') return '5-5';
|
|
300
|
+
if (label === '5 4' || label === 'gpt 5 4') return '5-4';
|
|
301
|
+
if (label === '5 3' || label === 'gpt 5 3') return '5-3';
|
|
302
|
+
if (label === '5 2' || label === 'gpt 5 2') return '5-2';
|
|
303
|
+
if (label === '5 1' || label === 'gpt 5 1') return '5-1';
|
|
304
|
+
if (label === '5 0' || label === 'gpt 5 0') return '5-0';
|
|
305
|
+
if (label === '4 5' || label === 'gpt 4 5') return '4-5';
|
|
306
|
+
return null;
|
|
307
|
+
};
|
|
308
|
+
const versionFromTestId = (testid) => {
|
|
309
|
+
const normalized = normalizeText(testid);
|
|
310
|
+
if (normalized.includes('5 5') || normalized.includes('gpt55')) return '5-5';
|
|
311
|
+
if (normalized.includes('5 4') || normalized.includes('gpt54')) return '5-4';
|
|
312
|
+
if (normalized.includes('5 3') || normalized.includes('gpt53')) return '5-3';
|
|
313
|
+
if (normalized.includes('5 2') || normalized.includes('gpt52')) return '5-2';
|
|
314
|
+
if (normalized.includes('5 1') || normalized.includes('gpt51')) return '5-1';
|
|
315
|
+
if (normalized.includes('5 0') || normalized.includes('gpt50')) return '5-0';
|
|
316
|
+
return null;
|
|
317
|
+
};
|
|
318
|
+
const getConfigurationDialog = () => document.querySelector('[role="dialog"]');
|
|
319
|
+
const getConfiguredVersionLabel = () =>
|
|
320
|
+
(getConfigurationDialog()
|
|
321
|
+
?.querySelector?.('[role="combobox"][aria-labelledby="model-selection-label"]')
|
|
322
|
+
?.textContent ?? '').trim();
|
|
323
|
+
const getConfiguredVariantLabel = () => {
|
|
324
|
+
const label =
|
|
325
|
+
(getConfigurationDialog()
|
|
326
|
+
?.querySelector?.('[aria-label="Model options"] [role="radio"][aria-checked="true"]')
|
|
327
|
+
?.textContent ?? '').trim();
|
|
328
|
+
const normalized = normalizeText(label);
|
|
329
|
+
if (normalized.startsWith('instant')) return 'Instant';
|
|
330
|
+
if (normalized.startsWith('thinking')) return 'Thinking';
|
|
331
|
+
if (normalized.startsWith('pro')) return 'Pro';
|
|
332
|
+
return label;
|
|
333
|
+
};
|
|
334
|
+
const configuredSelectionMatchesTarget = () => {
|
|
335
|
+
const configuredVersion = versionFromLabel(normalizeText(getConfiguredVersionLabel()));
|
|
336
|
+
if (!configuredVersion || configuredVersion !== desiredVersion) return false;
|
|
337
|
+
const configuredVariant = normalizeText(getConfiguredVariantLabel());
|
|
338
|
+
if (wantsPro) return labelHasProWord(configuredVariant);
|
|
339
|
+
if (wantsInstant) return configuredVariant.includes('instant');
|
|
340
|
+
if (wantsThinking) {
|
|
341
|
+
return configuredVariant.includes('thinking') && !labelHasProWord(configuredVariant);
|
|
342
|
+
}
|
|
343
|
+
return true;
|
|
344
|
+
};
|
|
345
|
+
const getResolvedLabel = (fallback) => {
|
|
346
|
+
if (configuredSelectionMatchesTarget()) {
|
|
347
|
+
const variant = getConfiguredVariantLabel();
|
|
348
|
+
const version = formatModelOptionLabel(getConfiguredVersionLabel());
|
|
349
|
+
return [variant, version].filter(Boolean).join(' ');
|
|
350
|
+
}
|
|
351
|
+
const composerLabel = getComposerModelLabel();
|
|
352
|
+
if (composerLabel) return withProPillSignal(composerLabel);
|
|
353
|
+
const buttonLabel = getButtonLabel();
|
|
354
|
+
const normalizedButton = normalizeText(buttonLabel);
|
|
355
|
+
const fallbackLabel = formatModelOptionLabel(fallback);
|
|
356
|
+
if (fallbackLabel && !wantsPro && isIntelligenceEffortLabel(normalizedButton)) {
|
|
357
|
+
return fallbackLabel;
|
|
358
|
+
}
|
|
359
|
+
return withProPillSignal(buttonLabel || fallbackLabel || fallback);
|
|
360
|
+
};
|
|
247
361
|
if (MODEL_STRATEGY === 'current') {
|
|
248
362
|
const currentLabel = getResolvedLabel('') || null;
|
|
249
363
|
return {
|
|
@@ -257,15 +371,18 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
257
371
|
return { status: 'button-missing' };
|
|
258
372
|
}
|
|
259
373
|
const buttonMatchesTarget = () => {
|
|
374
|
+
if (configuredSelectionMatchesTarget()) return true;
|
|
260
375
|
const normalizedLabel = normalizeText(getButtonLabel());
|
|
261
376
|
if (!normalizedLabel) return false;
|
|
377
|
+
if (wantsThinking && !wantsPro && hasProComposerPill()) return false;
|
|
262
378
|
if (isTargetGpt55VisibleAlias(normalizedLabel)) return true;
|
|
263
379
|
if (
|
|
264
380
|
wantsThinking &&
|
|
265
381
|
desiredVersion === '5-5' &&
|
|
266
382
|
!hasProComposerPill() &&
|
|
267
383
|
isThinkingEffortLabel(normalizedLabel) &&
|
|
268
|
-
|
|
384
|
+
(isNonProIntelligenceThinkingLabel(normalizedLabel) ||
|
|
385
|
+
isTargetGpt55VisibleAlias(readComposerModelSignal()))
|
|
269
386
|
) {
|
|
270
387
|
return true;
|
|
271
388
|
}
|
|
@@ -283,6 +400,7 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
283
400
|
if (desiredVersion) {
|
|
284
401
|
if (desiredVersion === '5-5' && !normalizedLabel.includes('5 5')) return false;
|
|
285
402
|
if (desiredVersion === '5-4' && !normalizedLabel.includes('5 4')) return false;
|
|
403
|
+
if (desiredVersion === '5-3' && !normalizedLabel.includes('5 3')) return false;
|
|
286
404
|
if (desiredVersion === '5-2' && !normalizedLabel.includes('5 2')) return false;
|
|
287
405
|
if (desiredVersion === '5-1' && !normalizedLabel.includes('5 1')) return false;
|
|
288
406
|
if (desiredVersion === '5-0' && !normalizedLabel.includes('5 0')) return false;
|
|
@@ -292,9 +410,9 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
292
410
|
if (wantsInstant && !normalizedLabel.includes('instant')) return false;
|
|
293
411
|
if (
|
|
294
412
|
wantsThinking &&
|
|
295
|
-
desiredVersion
|
|
296
|
-
|
|
297
|
-
!normalizedLabel
|
|
413
|
+
desiredVersion &&
|
|
414
|
+
versionFromLabel(normalizedLabel) === desiredVersion &&
|
|
415
|
+
!labelHasProWord(normalizedLabel)
|
|
298
416
|
) {
|
|
299
417
|
return true;
|
|
300
418
|
}
|
|
@@ -359,10 +477,21 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
359
477
|
};
|
|
360
478
|
|
|
361
479
|
const getOptionLabel = (node) => node?.textContent?.trim() ?? '';
|
|
362
|
-
const
|
|
480
|
+
const isDetachedProEffortMenu = (menu) => {
|
|
481
|
+
const text = normalizeText(menu?.textContent ?? '');
|
|
482
|
+
return (
|
|
483
|
+
menu?.getAttribute?.('data-testid') !== 'composer-intelligence-picker-content' &&
|
|
484
|
+
text.includes('pro standard') &&
|
|
485
|
+
text.includes('pro extended')
|
|
486
|
+
);
|
|
487
|
+
};
|
|
488
|
+
const isNestedEffortControl = (node, menu) =>
|
|
363
489
|
node instanceof HTMLElement &&
|
|
364
490
|
(node.getAttribute('data-model-picker-thinking-effort-action') === 'true' ||
|
|
365
|
-
|
|
491
|
+
node.getAttribute('data-composer-intelligence-pro-effort-action') === 'true' ||
|
|
492
|
+
Boolean(node.closest('[data-model-picker-thinking-effort-action="true"]')) ||
|
|
493
|
+
Boolean(node.closest('[data-composer-intelligence-pro-effort-action="true"]')) ||
|
|
494
|
+
isDetachedProEffortMenu(menu));
|
|
366
495
|
const optionIsSelected = (node) => {
|
|
367
496
|
if (!(node instanceof HTMLElement)) {
|
|
368
497
|
return false;
|
|
@@ -382,13 +511,28 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
382
511
|
return false;
|
|
383
512
|
};
|
|
384
513
|
|
|
385
|
-
const scoreOption = (normalizedText, testid) => {
|
|
514
|
+
const scoreOption = (normalizedText, testid, node) => {
|
|
386
515
|
// Assign a score to every node so we can pick the most likely match without brittle equality checks.
|
|
387
516
|
if (!normalizedText && !testid) {
|
|
388
517
|
return 0;
|
|
389
518
|
}
|
|
390
519
|
let score = 0;
|
|
391
520
|
const normalizedTestId = (testid ?? '').toLowerCase();
|
|
521
|
+
const candidateTextVersion = versionFromLabel(normalizedText);
|
|
522
|
+
const candidateIsVersionCombobox =
|
|
523
|
+
node?.getAttribute?.('role') === 'combobox' &&
|
|
524
|
+
node?.getAttribute?.('aria-labelledby') === 'model-selection-label';
|
|
525
|
+
if (candidateIsVersionCombobox && candidateTextVersion === desiredVersion) {
|
|
526
|
+
return 0;
|
|
527
|
+
}
|
|
528
|
+
const candidateOpensConfiguration =
|
|
529
|
+
Boolean(desiredVersion) &&
|
|
530
|
+
desiredVersion !== '5-5' &&
|
|
531
|
+
(normalizedTestId === 'model-configure-modal' ||
|
|
532
|
+
(candidateIsVersionCombobox && node?.getAttribute?.('aria-expanded') !== 'true'));
|
|
533
|
+
if (candidateOpensConfiguration) {
|
|
534
|
+
return 2000;
|
|
535
|
+
}
|
|
392
536
|
let exactTestIdMatch = false;
|
|
393
537
|
if (normalizedTestId) {
|
|
394
538
|
if (desiredVersion) {
|
|
@@ -411,6 +555,12 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
411
555
|
normalizedTestId.includes('gpt-5-4') ||
|
|
412
556
|
normalizedTestId.includes('gpt-5.4') ||
|
|
413
557
|
normalizedTestId.includes('gpt54');
|
|
558
|
+
const has53 =
|
|
559
|
+
normalizedTestId.includes('5-3') ||
|
|
560
|
+
normalizedTestId.includes('5.3') ||
|
|
561
|
+
normalizedTestId.includes('gpt-5-3') ||
|
|
562
|
+
normalizedTestId.includes('gpt-5.3') ||
|
|
563
|
+
normalizedTestId.includes('gpt53');
|
|
414
564
|
const has51 =
|
|
415
565
|
normalizedTestId.includes('5-1') ||
|
|
416
566
|
normalizedTestId.includes('5.1') ||
|
|
@@ -423,7 +573,19 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
423
573
|
normalizedTestId.includes('gpt-5-0') ||
|
|
424
574
|
normalizedTestId.includes('gpt-5.0') ||
|
|
425
575
|
normalizedTestId.includes('gpt50');
|
|
426
|
-
const candidateVersion = has55
|
|
576
|
+
const candidateVersion = has55
|
|
577
|
+
? '5-5'
|
|
578
|
+
: has54
|
|
579
|
+
? '5-4'
|
|
580
|
+
: has53
|
|
581
|
+
? '5-3'
|
|
582
|
+
: has52
|
|
583
|
+
? '5-2'
|
|
584
|
+
: has51
|
|
585
|
+
? '5-1'
|
|
586
|
+
: has50
|
|
587
|
+
? '5-0'
|
|
588
|
+
: null;
|
|
427
589
|
// If a candidate advertises a different version, ignore it entirely.
|
|
428
590
|
if (candidateVersion && candidateVersion !== desiredVersion) {
|
|
429
591
|
return 0;
|
|
@@ -452,10 +614,44 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
452
614
|
}
|
|
453
615
|
}
|
|
454
616
|
const candidateGpt55VisibleAlias = isTargetGpt55VisibleAlias(normalizedText);
|
|
617
|
+
const candidateIsNonProThinkingEffort =
|
|
618
|
+
isNonProIntelligenceThinkingLabel(normalizedText) && !normalizedTestId.includes('pro');
|
|
619
|
+
const hasActiveProPill = hasProComposerPill();
|
|
620
|
+
const candidateIsNonProGpt55Thinking =
|
|
621
|
+
wantsThinking && desiredVersion === '5-5' && candidateIsNonProThinkingEffort;
|
|
622
|
+
const candidateClearsProForThinking =
|
|
623
|
+
wantsThinking && !wantsPro && hasActiveProPill && candidateIsNonProThinkingEffort;
|
|
624
|
+
const candidateOpensVersionSubmenu =
|
|
625
|
+
wantsThinking &&
|
|
626
|
+
desiredVersion !== '5-5' &&
|
|
627
|
+
normalizedText === 'gpt 5 5' &&
|
|
628
|
+
!normalizedTestId.includes('pro');
|
|
629
|
+
const candidateSelectsDesiredVersion =
|
|
630
|
+
Boolean(desiredVersion) && candidateTextVersion === desiredVersion;
|
|
631
|
+
if (
|
|
632
|
+
desiredVersion &&
|
|
633
|
+
candidateTextVersion &&
|
|
634
|
+
candidateTextVersion !== desiredVersion &&
|
|
635
|
+
!candidateOpensVersionSubmenu
|
|
636
|
+
) {
|
|
637
|
+
return 0;
|
|
638
|
+
}
|
|
639
|
+
const candidateIsGpt55ThinkingFamily =
|
|
640
|
+
wantsThinking &&
|
|
641
|
+
desiredVersion === '5-5' &&
|
|
642
|
+
(normalizedText === 'gpt 5 5' ||
|
|
643
|
+
normalizedText === '5 5' ||
|
|
644
|
+
normalizedTestId.includes('gpt-5-5') ||
|
|
645
|
+
normalizedTestId.includes('gpt-5.5') ||
|
|
646
|
+
normalizedTestId.includes('gpt55'));
|
|
455
647
|
const candidateHasThinking =
|
|
456
648
|
normalizedText.includes('thinking') ||
|
|
457
649
|
normalizedTestId.includes('thinking') ||
|
|
458
|
-
|
|
650
|
+
candidateIsNonProGpt55Thinking ||
|
|
651
|
+
candidateClearsProForThinking ||
|
|
652
|
+
candidateOpensVersionSubmenu ||
|
|
653
|
+
candidateIsGpt55ThinkingFamily ||
|
|
654
|
+
(wantsThinking && desiredVersion && (exactTestIdMatch || candidateSelectsDesiredVersion));
|
|
459
655
|
const candidateHasLegacyProVersion = labelHasLegacyProVersion(normalizedText);
|
|
460
656
|
const candidateHasPro =
|
|
461
657
|
labelHasProWord(normalizedText) ||
|
|
@@ -464,11 +660,11 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
464
660
|
const candidateHasInstant =
|
|
465
661
|
normalizedText.includes('instant') || normalizedTestId.includes('instant');
|
|
466
662
|
if (wantsPro && candidateHasThinking) return 0;
|
|
467
|
-
if (wantsPro && candidateHasLegacyProVersion) return 0;
|
|
468
|
-
if (wantsPro && !candidateHasPro) return 0;
|
|
469
|
-
if (wantsInstant && !candidateHasInstant) return 0;
|
|
663
|
+
if (wantsPro && candidateHasLegacyProVersion && !candidateSelectsDesiredVersion) return 0;
|
|
664
|
+
if (wantsPro && !candidateHasPro && !candidateSelectsDesiredVersion) return 0;
|
|
665
|
+
if (wantsInstant && !candidateHasInstant && !candidateSelectsDesiredVersion) return 0;
|
|
470
666
|
if (wantsThinking && candidateHasPro) return 0;
|
|
471
|
-
if (wantsThinking && !candidateHasThinking) return 0;
|
|
667
|
+
if (wantsThinking && !candidateHasThinking && !candidateSelectsDesiredVersion) return 0;
|
|
472
668
|
if (desiredVersion === '5-5' && normalizedText && !candidateGpt55VisibleAlias) {
|
|
473
669
|
const candidateHasVersion =
|
|
474
670
|
normalizedText.includes('5 5') ||
|
|
@@ -482,6 +678,39 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
482
678
|
if (candidateGpt55VisibleAlias) {
|
|
483
679
|
score += 900;
|
|
484
680
|
}
|
|
681
|
+
if (wantsPro && candidateHasPro && !candidateSelectsDesiredVersion) {
|
|
682
|
+
score += 900;
|
|
683
|
+
}
|
|
684
|
+
if (wantsInstant && candidateHasInstant && !candidateSelectsDesiredVersion) {
|
|
685
|
+
score += 900;
|
|
686
|
+
}
|
|
687
|
+
if (
|
|
688
|
+
wantsThinking &&
|
|
689
|
+
candidateHasThinking &&
|
|
690
|
+
!candidateSelectsDesiredVersion &&
|
|
691
|
+
!candidateOpensVersionSubmenu
|
|
692
|
+
) {
|
|
693
|
+
score += 900;
|
|
694
|
+
}
|
|
695
|
+
if (candidateIsNonProGpt55Thinking) {
|
|
696
|
+
score += scoreNonProGpt55ThinkingLabel(normalizedText);
|
|
697
|
+
}
|
|
698
|
+
if (candidateClearsProForThinking) {
|
|
699
|
+
score += scoreNonProGpt55ThinkingLabel(normalizedText) + 600;
|
|
700
|
+
}
|
|
701
|
+
if (
|
|
702
|
+
desiredVersion &&
|
|
703
|
+
candidateTextVersion === desiredVersion &&
|
|
704
|
+
!(wantsThinking && desiredVersion === '5-5' && normalizedText === 'gpt 5 5')
|
|
705
|
+
) {
|
|
706
|
+
score += 1200;
|
|
707
|
+
}
|
|
708
|
+
if (candidateOpensVersionSubmenu) {
|
|
709
|
+
score += 500;
|
|
710
|
+
}
|
|
711
|
+
if (candidateIsGpt55ThinkingFamily) {
|
|
712
|
+
score += 260;
|
|
713
|
+
}
|
|
485
714
|
if (normalizedText && normalizedTarget) {
|
|
486
715
|
if (normalizedText === normalizedTarget) {
|
|
487
716
|
score += 500;
|
|
@@ -517,7 +746,14 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
517
746
|
}
|
|
518
747
|
// Similarly for Thinking variant
|
|
519
748
|
if (wantsThinking) {
|
|
520
|
-
if (
|
|
749
|
+
if (
|
|
750
|
+
!candidateIsGpt55ThinkingFamily &&
|
|
751
|
+
!candidateIsNonProGpt55Thinking &&
|
|
752
|
+
!candidateClearsProForThinking &&
|
|
753
|
+
!candidateOpensVersionSubmenu &&
|
|
754
|
+
!normalizedText.includes('thinking') &&
|
|
755
|
+
!normalizedTestId.includes('thinking')
|
|
756
|
+
) {
|
|
521
757
|
score -= 80;
|
|
522
758
|
}
|
|
523
759
|
} else if (normalizedText.includes('thinking') || normalizedTestId.includes('thinking')) {
|
|
@@ -558,6 +794,21 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
558
794
|
);
|
|
559
795
|
return pickerMenus.concat(textFallbackMenus);
|
|
560
796
|
};
|
|
797
|
+
const isSubmenuOption = (node, testid) =>
|
|
798
|
+
(testid ?? '').toLowerCase().includes('submenu') ||
|
|
799
|
+
(testid ?? '').toLowerCase() === 'model-configure-modal' ||
|
|
800
|
+
(node?.getAttribute?.('role') === 'combobox' &&
|
|
801
|
+
node?.getAttribute?.('aria-labelledby') === 'model-selection-label') ||
|
|
802
|
+
node?.getAttribute?.('aria-haspopup') === 'menu' ||
|
|
803
|
+
node?.getAttribute?.('data-has-submenu') !== null;
|
|
804
|
+
const canTrustSelectedOption = (node, normalizedText, testid) => {
|
|
805
|
+
if (!optionIsSelected(node)) return false;
|
|
806
|
+
if (getConfigurationDialog() && !configuredSelectionMatchesTarget()) return false;
|
|
807
|
+
const optionVersion = versionFromLabel(normalizedText) ?? versionFromTestId(testid);
|
|
808
|
+
if (desiredVersion && optionVersion !== desiredVersion) return false;
|
|
809
|
+
const currentButtonLabel = normalizeText(getButtonLabel());
|
|
810
|
+
return !labelHasProWord(currentButtonLabel) && !hasProComposerPill();
|
|
811
|
+
};
|
|
561
812
|
|
|
562
813
|
const findBestOption = () => {
|
|
563
814
|
// Walk through every menu item and keep whichever earns the highest score.
|
|
@@ -566,16 +817,19 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
566
817
|
for (const menu of menus) {
|
|
567
818
|
const buttons = Array.from(menu.querySelectorAll(${menuItemLiteral}));
|
|
568
819
|
for (const option of buttons) {
|
|
569
|
-
if (
|
|
820
|
+
if (isNestedEffortControl(option, menu)) {
|
|
570
821
|
continue;
|
|
571
822
|
}
|
|
572
823
|
const text = option.textContent ?? '';
|
|
573
824
|
const normalizedText = normalizeText(text);
|
|
574
825
|
const testid = option.getAttribute('data-testid') ?? '';
|
|
575
|
-
|
|
826
|
+
let score = scoreOption(normalizedText, testid, option);
|
|
576
827
|
if (score <= 0) {
|
|
577
828
|
continue;
|
|
578
829
|
}
|
|
830
|
+
if (canTrustSelectedOption(option, normalizedText, testid)) {
|
|
831
|
+
score += 1000;
|
|
832
|
+
}
|
|
579
833
|
const label = getOptionLabel(option);
|
|
580
834
|
if (!bestMatch || score > bestMatch.score) {
|
|
581
835
|
bestMatch = { node: option, label, score, testid, normalizedText };
|
|
@@ -613,6 +867,28 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
613
867
|
};
|
|
614
868
|
check();
|
|
615
869
|
});
|
|
870
|
+
const dispatchHoverSequence = (target) => {
|
|
871
|
+
if (!target || !(target instanceof EventTarget)) return false;
|
|
872
|
+
const types = ['pointerover', 'pointerenter', 'mouseover', 'mouseenter', 'pointermove', 'mousemove'];
|
|
873
|
+
for (const type of types) {
|
|
874
|
+
try {
|
|
875
|
+
const common = { bubbles: true, cancelable: true, view: window };
|
|
876
|
+
const event =
|
|
877
|
+
type.startsWith('pointer') && 'PointerEvent' in window
|
|
878
|
+
? new PointerEvent(type, { ...common, pointerId: 1, pointerType: 'mouse' })
|
|
879
|
+
: new MouseEvent(type, common);
|
|
880
|
+
target.dispatchEvent(event);
|
|
881
|
+
} catch {}
|
|
882
|
+
}
|
|
883
|
+
try {
|
|
884
|
+
target.focus?.();
|
|
885
|
+
} catch {}
|
|
886
|
+
return true;
|
|
887
|
+
};
|
|
888
|
+
const openSubmenuOption = (node) => {
|
|
889
|
+
dispatchHoverSequence(node);
|
|
890
|
+
dispatchClickSequence(node);
|
|
891
|
+
};
|
|
616
892
|
|
|
617
893
|
return new Promise((resolve) => {
|
|
618
894
|
const start = performance.now();
|
|
@@ -655,26 +931,32 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
655
931
|
ensureMenuOpen();
|
|
656
932
|
const match = findBestOption();
|
|
657
933
|
if (match) {
|
|
658
|
-
if (
|
|
934
|
+
if (
|
|
935
|
+
activeSelectionMatchesTarget() ||
|
|
936
|
+
canTrustSelectedOption(match.node, match.normalizedText, match.testid)
|
|
937
|
+
) {
|
|
938
|
+
const resolvedLabel = getResolvedLabel(match.label);
|
|
659
939
|
closeMenu();
|
|
660
|
-
resolve({ status: 'already-selected', label:
|
|
940
|
+
resolve({ status: 'already-selected', label: resolvedLabel });
|
|
661
941
|
return;
|
|
662
942
|
}
|
|
663
943
|
const previousButtonLabel = normalizeText(getButtonLabel());
|
|
664
944
|
const previousComposerSignal = readComposerModelSignal();
|
|
665
|
-
dispatchClickSequence(match.node);
|
|
666
945
|
// Submenus (e.g. "Legacy models") need a second pass to pick the actual model option.
|
|
667
946
|
// Keep scanning once the submenu opens instead of treating the submenu click as a final switch.
|
|
668
|
-
const isSubmenu = (match.
|
|
947
|
+
const isSubmenu = isSubmenuOption(match.node, match.testid);
|
|
669
948
|
if (isSubmenu) {
|
|
949
|
+
openSubmenuOption(match.node);
|
|
670
950
|
setTimeout(attempt, REOPEN_INTERVAL_MS / 2);
|
|
671
951
|
return;
|
|
672
952
|
}
|
|
953
|
+
dispatchClickSequence(match.node);
|
|
673
954
|
// Wait for the selected model signal to settle before reopening the picker.
|
|
674
955
|
waitForTargetSelection(previousButtonLabel, previousComposerSignal).then((selectionSettled) => {
|
|
675
956
|
if (selectionSettled === 'target') {
|
|
957
|
+
const resolvedLabel = getResolvedLabel(match.label);
|
|
676
958
|
closeMenu();
|
|
677
|
-
resolve({ status: 'switched', label:
|
|
959
|
+
resolve({ status: 'switched', label: resolvedLabel });
|
|
678
960
|
return;
|
|
679
961
|
}
|
|
680
962
|
attempt();
|
|
@@ -783,6 +1065,34 @@ function buildModelMatchersLiteral(targetModel) {
|
|
|
783
1065
|
testIdTokens.add("gpt5-4");
|
|
784
1066
|
testIdTokens.add("gpt54");
|
|
785
1067
|
}
|
|
1068
|
+
// Numeric variations (5.3 ↔ 53 ↔ gpt-5-3)
|
|
1069
|
+
if (base.includes("5.3") || base.includes("5-3") || base.includes("53")) {
|
|
1070
|
+
push("5.3", labelTokens);
|
|
1071
|
+
push("gpt-5.3", labelTokens);
|
|
1072
|
+
push("gpt5.3", labelTokens);
|
|
1073
|
+
push("gpt-5-3", labelTokens);
|
|
1074
|
+
push("gpt5-3", labelTokens);
|
|
1075
|
+
push("gpt53", labelTokens);
|
|
1076
|
+
push("chatgpt 5.3", labelTokens);
|
|
1077
|
+
if (base.includes("thinking")) {
|
|
1078
|
+
push("thinking", labelTokens);
|
|
1079
|
+
testIdTokens.add("model-switcher-gpt-5-3-thinking");
|
|
1080
|
+
testIdTokens.add("gpt-5-3-thinking");
|
|
1081
|
+
testIdTokens.add("gpt-5.3-thinking");
|
|
1082
|
+
}
|
|
1083
|
+
if (base.includes("instant")) {
|
|
1084
|
+
push("instant", labelTokens);
|
|
1085
|
+
testIdTokens.add("model-switcher-gpt-5-3-instant");
|
|
1086
|
+
testIdTokens.add("gpt-5-3-instant");
|
|
1087
|
+
testIdTokens.add("gpt-5.3-instant");
|
|
1088
|
+
}
|
|
1089
|
+
if (!base.includes("pro") && !base.includes("thinking") && !base.includes("instant")) {
|
|
1090
|
+
testIdTokens.add("model-switcher-gpt-5-3");
|
|
1091
|
+
}
|
|
1092
|
+
testIdTokens.add("gpt-5-3");
|
|
1093
|
+
testIdTokens.add("gpt5-3");
|
|
1094
|
+
testIdTokens.add("gpt53");
|
|
1095
|
+
}
|
|
786
1096
|
// Numeric variations (5.1 ↔ 51 ↔ gpt-5-1)
|
|
787
1097
|
if (base.includes("5.1") || base.includes("5-1") || base.includes("51")) {
|
|
788
1098
|
push("5.1", labelTokens);
|
|
@@ -857,6 +1167,11 @@ function buildModelMatchersLiteral(targetModel) {
|
|
|
857
1167
|
testIdTokens.add("gpt-5-4-pro");
|
|
858
1168
|
testIdTokens.add("gpt54pro");
|
|
859
1169
|
}
|
|
1170
|
+
if (base.includes("5.3") || base.includes("5-3") || base.includes("53")) {
|
|
1171
|
+
testIdTokens.add("gpt-5.3-pro");
|
|
1172
|
+
testIdTokens.add("gpt-5-3-pro");
|
|
1173
|
+
testIdTokens.add("gpt53pro");
|
|
1174
|
+
}
|
|
860
1175
|
if (base.includes("5.1") || base.includes("5-1") || base.includes("51")) {
|
|
861
1176
|
testIdTokens.add("gpt-5.1-pro");
|
|
862
1177
|
testIdTokens.add("gpt-5-1-pro");
|