@steipete/oracle 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +107 -49
- package/dist/bin/oracle-cli.js +551 -410
- package/dist/bin/oracle-mcp.js +2 -2
- package/dist/bin/oracle.js +165 -279
- package/dist/scripts/agent-send.js +31 -31
- package/dist/scripts/check.js +6 -6
- package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
- package/dist/scripts/docs-list.js +30 -30
- package/dist/scripts/git-policy.js +25 -23
- package/dist/scripts/run-cli.js +8 -8
- package/dist/scripts/runner.js +203 -195
- package/dist/scripts/test-browser.js +21 -18
- package/dist/scripts/test-remote-chrome.js +20 -20
- package/dist/src/bridge/connection.js +18 -18
- package/dist/src/bridge/userConfigFile.js +7 -7
- package/dist/src/browser/actions/archiveConversation.js +224 -0
- package/dist/src/browser/actions/assistantResponse.js +175 -101
- package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
- package/dist/src/browser/actions/attachments.js +246 -150
- package/dist/src/browser/actions/deepResearch.js +662 -0
- package/dist/src/browser/actions/domEvents.js +2 -2
- package/dist/src/browser/actions/modelSelection.js +342 -119
- package/dist/src/browser/actions/navigation.js +183 -137
- package/dist/src/browser/actions/projectSources.js +491 -0
- package/dist/src/browser/actions/promptComposer.js +152 -91
- package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
- package/dist/src/browser/actions/thinkingStatus.js +391 -0
- package/dist/src/browser/actions/thinkingTime.js +207 -110
- package/dist/src/browser/artifacts.js +150 -0
- package/dist/src/browser/attachRunning.js +31 -0
- package/dist/src/browser/chatgptImages.js +315 -0
- package/dist/src/browser/chromeLifecycle.js +276 -63
- package/dist/src/browser/config.js +59 -16
- package/dist/src/browser/constants.js +25 -12
- package/dist/src/browser/controlPlan.js +81 -0
- package/dist/src/browser/cookies.js +19 -19
- package/dist/src/browser/detect.js +250 -77
- package/dist/src/browser/domDebug.js +50 -1
- package/dist/src/browser/index.js +1559 -692
- package/dist/src/browser/liveTabs.js +434 -0
- package/dist/src/browser/modelStrategy.js +1 -1
- package/dist/src/browser/pageActions.js +5 -5
- package/dist/src/browser/policies.js +16 -13
- package/dist/src/browser/profileState.js +127 -42
- package/dist/src/browser/projectSourcesRunner.js +366 -0
- package/dist/src/browser/prompt.js +72 -42
- package/dist/src/browser/promptSummary.js +5 -5
- package/dist/src/browser/providerDomFlow.js +1 -1
- package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
- package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
- package/dist/src/browser/providers/index.js +2 -2
- package/dist/src/browser/reattach.js +178 -73
- package/dist/src/browser/reattachHelpers.js +32 -27
- package/dist/src/browser/sessionRunner.js +89 -25
- package/dist/src/browser/tabLeaseRegistry.js +182 -0
- package/dist/src/browser/utils.js +9 -9
- package/dist/src/browserMode.js +1 -1
- package/dist/src/cli/bridge/claudeConfig.js +24 -20
- package/dist/src/cli/bridge/client.js +28 -20
- package/dist/src/cli/bridge/codexConfig.js +16 -16
- package/dist/src/cli/bridge/doctor.js +47 -39
- package/dist/src/cli/bridge/host.js +58 -56
- package/dist/src/cli/browserConfig.js +102 -48
- package/dist/src/cli/browserDefaults.js +51 -26
- package/dist/src/cli/browserTabs.js +228 -0
- package/dist/src/cli/bundleWarnings.js +1 -1
- package/dist/src/cli/clipboard.js +11 -2
- package/dist/src/cli/detach.js +2 -2
- package/dist/src/cli/dryRun.js +62 -26
- package/dist/src/cli/duplicatePromptGuard.js +12 -4
- package/dist/src/cli/engine.js +9 -9
- package/dist/src/cli/errorUtils.js +1 -1
- package/dist/src/cli/fileSize.js +3 -3
- package/dist/src/cli/format.js +2 -2
- package/dist/src/cli/help.js +28 -28
- package/dist/src/cli/hiddenAliases.js +3 -3
- package/dist/src/cli/markdownBundle.js +7 -7
- package/dist/src/cli/markdownRenderer.js +15 -15
- package/dist/src/cli/notifier.js +77 -67
- package/dist/src/cli/options.js +131 -106
- package/dist/src/cli/oscUtils.js +1 -1
- package/dist/src/cli/projectSources.js +116 -0
- package/dist/src/cli/promptRequirement.js +2 -2
- package/dist/src/cli/renderOutput.js +1 -1
- package/dist/src/cli/rootAlias.js +1 -1
- package/dist/src/cli/runOptions.js +32 -28
- package/dist/src/cli/sessionCommand.js +82 -21
- package/dist/src/cli/sessionDisplay.js +213 -87
- package/dist/src/cli/sessionLineage.js +6 -2
- package/dist/src/cli/sessionRunner.js +149 -95
- package/dist/src/cli/sessionTable.js +26 -23
- package/dist/src/cli/stdin.js +22 -0
- package/dist/src/cli/tagline.js +121 -124
- package/dist/src/cli/tui/index.js +139 -128
- package/dist/src/cli/writeOutputPath.js +5 -5
- package/dist/src/config.js +7 -7
- package/dist/src/gemini-web/browserSessionManager.js +19 -15
- package/dist/src/gemini-web/client.js +76 -70
- package/dist/src/gemini-web/executionMode.js +6 -8
- package/dist/src/gemini-web/executor.js +98 -93
- package/dist/src/gemini-web/index.js +1 -1
- package/dist/src/mcp/consultPresets.js +19 -0
- package/dist/src/mcp/server.js +18 -12
- package/dist/src/mcp/tools/consult.js +246 -67
- package/dist/src/mcp/tools/projectSources.js +123 -0
- package/dist/src/mcp/tools/sessionResources.js +12 -12
- package/dist/src/mcp/tools/sessions.js +26 -17
- package/dist/src/mcp/types.js +12 -5
- package/dist/src/mcp/utils.js +21 -8
- package/dist/src/oracle/background.js +15 -15
- package/dist/src/oracle/claude.js +53 -25
- package/dist/src/oracle/client.js +50 -41
- package/dist/src/oracle/config.js +96 -66
- package/dist/src/oracle/errors.js +38 -38
- package/dist/src/oracle/files.js +55 -46
- package/dist/src/oracle/finishLine.js +10 -8
- package/dist/src/oracle/format.js +3 -3
- package/dist/src/oracle/gemini.js +37 -33
- package/dist/src/oracle/logging.js +7 -7
- package/dist/src/oracle/markdown.js +28 -28
- package/dist/src/oracle/modelResolver.js +16 -16
- package/dist/src/oracle/multiModelRunner.js +12 -12
- package/dist/src/oracle/oscProgress.js +8 -8
- package/dist/src/oracle/promptAssembly.js +6 -3
- package/dist/src/oracle/request.js +16 -13
- package/dist/src/oracle/run.js +160 -135
- package/dist/src/oracle/runUtils.js +8 -5
- package/dist/src/oracle/tokenEstimate.js +6 -6
- package/dist/src/oracle/tokenStats.js +5 -5
- package/dist/src/oracle/tokenStringifier.js +5 -5
- package/dist/src/oracle.js +12 -12
- package/dist/src/oracleHome.js +3 -3
- package/dist/src/projectSources/plan.js +27 -0
- package/dist/src/projectSources/url.js +23 -0
- package/dist/src/remote/client.js +25 -25
- package/dist/src/remote/health.js +20 -20
- package/dist/src/remote/remoteServiceConfig.js +9 -9
- package/dist/src/remote/server.js +129 -118
- package/dist/src/sessionManager.js +78 -75
- package/dist/src/sessionStore.js +3 -3
- package/dist/src/version.js +10 -10
- package/dist/vendor/oracle-notifier/README.md +2 -0
- package/package.json +67 -62
- package/vendor/oracle-notifier/README.md +2 -0
- package/dist/markdansi/types/index.js +0 -4
- package/dist/oracle/bin/oracle-cli.js +0 -472
- package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
- package/dist/oracle/src/browser/actions/attachments.js +0 -82
- package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
- package/dist/oracle/src/browser/actions/navigation.js +0 -75
- package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
- package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
- package/dist/oracle/src/browser/config.js +0 -33
- package/dist/oracle/src/browser/constants.js +0 -40
- package/dist/oracle/src/browser/cookies.js +0 -210
- package/dist/oracle/src/browser/domDebug.js +0 -36
- package/dist/oracle/src/browser/index.js +0 -331
- package/dist/oracle/src/browser/pageActions.js +0 -5
- package/dist/oracle/src/browser/prompt.js +0 -88
- package/dist/oracle/src/browser/promptSummary.js +0 -20
- package/dist/oracle/src/browser/sessionRunner.js +0 -80
- package/dist/oracle/src/browser/utils.js +0 -62
- package/dist/oracle/src/browserMode.js +0 -1
- package/dist/oracle/src/cli/browserConfig.js +0 -44
- package/dist/oracle/src/cli/dryRun.js +0 -59
- package/dist/oracle/src/cli/engine.js +0 -17
- package/dist/oracle/src/cli/errorUtils.js +0 -9
- package/dist/oracle/src/cli/help.js +0 -70
- package/dist/oracle/src/cli/markdownRenderer.js +0 -15
- package/dist/oracle/src/cli/options.js +0 -103
- package/dist/oracle/src/cli/promptRequirement.js +0 -14
- package/dist/oracle/src/cli/rootAlias.js +0 -30
- package/dist/oracle/src/cli/sessionCommand.js +0 -77
- package/dist/oracle/src/cli/sessionDisplay.js +0 -270
- package/dist/oracle/src/cli/sessionRunner.js +0 -94
- package/dist/oracle/src/heartbeat.js +0 -43
- package/dist/oracle/src/oracle/client.js +0 -48
- package/dist/oracle/src/oracle/config.js +0 -29
- package/dist/oracle/src/oracle/errors.js +0 -101
- package/dist/oracle/src/oracle/files.js +0 -220
- package/dist/oracle/src/oracle/format.js +0 -33
- package/dist/oracle/src/oracle/fsAdapter.js +0 -7
- package/dist/oracle/src/oracle/oscProgress.js +0 -60
- package/dist/oracle/src/oracle/request.js +0 -48
- package/dist/oracle/src/oracle/run.js +0 -444
- package/dist/oracle/src/oracle/tokenStats.js +0 -39
- package/dist/oracle/src/oracle/types.js +0 -1
- package/dist/oracle/src/oracle.js +0 -9
- package/dist/oracle/src/sessionManager.js +0 -205
- package/dist/oracle/src/version.js +0 -39
- package/dist/scripts/chrome/browser-tools.js +0 -295
- package/dist/src/browser/profileSync.js +0 -141
- /package/dist/{oracle/src/browser → src/projectSources}/types.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { MENU_CONTAINER_SELECTOR, MENU_ITEM_SELECTOR, MODEL_BUTTON_SELECTOR, } from
|
|
2
|
-
import { logDomFailure } from
|
|
3
|
-
import { buildClickDispatcher } from
|
|
4
|
-
export async function ensureModelSelection(Runtime, desiredModel, logger, strategy =
|
|
1
|
+
import { COMPOSER_MODEL_SIGNAL_SELECTOR, MENU_CONTAINER_SELECTOR, MENU_ITEM_SELECTOR, MODEL_BUTTON_SELECTOR, } from "../constants.js";
|
|
2
|
+
import { logDomFailure } from "../domDebug.js";
|
|
3
|
+
import { buildClickDispatcher } from "./domEvents.js";
|
|
4
|
+
export async function ensureModelSelection(Runtime, desiredModel, logger, strategy = "select") {
|
|
5
5
|
const outcome = await Runtime.evaluate({
|
|
6
6
|
expression: buildModelSelectionExpression(desiredModel, strategy),
|
|
7
7
|
awaitPromise: true,
|
|
@@ -9,52 +9,88 @@ export async function ensureModelSelection(Runtime, desiredModel, logger, strate
|
|
|
9
9
|
});
|
|
10
10
|
const result = outcome.result?.value;
|
|
11
11
|
switch (result?.status) {
|
|
12
|
-
case
|
|
13
|
-
case
|
|
14
|
-
case
|
|
12
|
+
case "already-selected":
|
|
13
|
+
case "switched":
|
|
14
|
+
case "switched-best-effort": {
|
|
15
15
|
const label = result.label ?? desiredModel;
|
|
16
|
+
if (strategy !== "current") {
|
|
17
|
+
assertResolvedModelSelection(desiredModel, label);
|
|
18
|
+
}
|
|
16
19
|
logger(`Model picker: ${label}`);
|
|
17
20
|
return;
|
|
18
21
|
}
|
|
19
|
-
case
|
|
20
|
-
await logDomFailure(Runtime, logger,
|
|
22
|
+
case "option-not-found": {
|
|
23
|
+
await logDomFailure(Runtime, logger, "model-switcher-option");
|
|
21
24
|
const isTemporary = result.hint?.temporaryChat ?? false;
|
|
22
25
|
const available = (result.hint?.availableOptions ?? []).filter(Boolean);
|
|
23
|
-
const availableHint = available.length > 0 ? ` Available: ${available.join(
|
|
26
|
+
const availableHint = available.length > 0 ? ` Available: ${available.join(", ")}.` : "";
|
|
24
27
|
const tempHint = isTemporary && /\bpro\b/i.test(desiredModel)
|
|
25
28
|
? ' You are in Temporary Chat mode; Pro models are not available there. Remove "temporary-chat=true" from --chatgpt-url or use a non-Pro model (e.g. gpt-5.2).'
|
|
26
|
-
:
|
|
29
|
+
: "";
|
|
27
30
|
throw new Error(`Unable to find model option matching "${desiredModel}" in the model switcher.${availableHint}${tempHint}`);
|
|
28
31
|
}
|
|
29
32
|
default: {
|
|
30
|
-
await logDomFailure(Runtime, logger,
|
|
31
|
-
throw new Error(
|
|
33
|
+
await logDomFailure(Runtime, logger, "model-switcher-button");
|
|
34
|
+
throw new Error("Unable to locate the ChatGPT model selector button.");
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
}
|
|
38
|
+
function assertResolvedModelSelection(desiredModel, resolvedLabel) {
|
|
39
|
+
const desired = desiredModel.toLowerCase();
|
|
40
|
+
const resolved = resolvedLabel.toLowerCase();
|
|
41
|
+
const wantsGpt55Pro = desired === "gpt-5.5-pro" ||
|
|
42
|
+
desired.includes("5.5 pro") ||
|
|
43
|
+
desired.includes("5-5 pro") ||
|
|
44
|
+
(desired.includes("pro") && desired.includes("extended"));
|
|
45
|
+
if (!wantsGpt55Pro || !resolved) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const hasProSignal = resolved.includes(" pro") ||
|
|
49
|
+
resolved.endsWith("pro") ||
|
|
50
|
+
resolved.includes("pro ") ||
|
|
51
|
+
resolved.includes("extended") ||
|
|
52
|
+
resolved.includes("gpt-5.5-pro") ||
|
|
53
|
+
resolved.includes("gpt 5 5 pro");
|
|
54
|
+
if (!hasProSignal || (resolved.includes("thinking") && !resolved.includes("pro"))) {
|
|
55
|
+
throw new Error(`Model picker selected "${resolvedLabel}" while "${desiredModel}" requires GPT-5.5 Pro Extended. Use model "gpt-5.5" with browser thinking time "heavy" for Thinking Heavy.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function assertResolvedModelSelectionForTest(desiredModel, resolvedLabel) {
|
|
59
|
+
assertResolvedModelSelection(desiredModel, resolvedLabel);
|
|
60
|
+
}
|
|
35
61
|
/**
|
|
36
62
|
* Builds the DOM expression that runs inside the ChatGPT tab to select a model.
|
|
37
63
|
* The string is evaluated inside Chrome, so keep it self-contained and well-commented.
|
|
38
64
|
*/
|
|
39
65
|
function buildModelSelectionExpression(targetModel, strategy) {
|
|
40
66
|
const matchers = buildModelMatchersLiteral(targetModel);
|
|
67
|
+
const composerSignalMatchers = buildComposerSignalMatchers(targetModel);
|
|
41
68
|
const labelLiteral = JSON.stringify(matchers.labelTokens);
|
|
42
69
|
const idLiteral = JSON.stringify(matchers.testIdTokens);
|
|
43
70
|
const primaryLabelLiteral = JSON.stringify(targetModel);
|
|
44
71
|
const strategyLiteral = JSON.stringify(strategy);
|
|
72
|
+
const composerSignalSelectorLiteral = JSON.stringify(COMPOSER_MODEL_SIGNAL_SELECTOR);
|
|
73
|
+
const composerIncludesLiteral = JSON.stringify(composerSignalMatchers.includesAny);
|
|
74
|
+
const composerExcludesLiteral = JSON.stringify(composerSignalMatchers.excludesAny);
|
|
75
|
+
const composerAllowBlankLiteral = JSON.stringify(composerSignalMatchers.allowBlank);
|
|
45
76
|
const menuContainerLiteral = JSON.stringify(MENU_CONTAINER_SELECTOR);
|
|
46
77
|
const menuItemLiteral = JSON.stringify(MENU_ITEM_SELECTOR);
|
|
47
78
|
return `(() => {
|
|
48
79
|
${buildClickDispatcher()}
|
|
49
80
|
// Capture the selectors and matcher literals up front so the browser expression stays pure.
|
|
50
81
|
const BUTTON_SELECTOR = '${MODEL_BUTTON_SELECTOR}';
|
|
82
|
+
const COMPOSER_MODEL_SIGNAL_SELECTOR = ${composerSignalSelectorLiteral};
|
|
51
83
|
const LABEL_TOKENS = ${labelLiteral};
|
|
52
84
|
const TEST_IDS = ${idLiteral};
|
|
53
85
|
const PRIMARY_LABEL = ${primaryLabelLiteral};
|
|
54
86
|
const MODEL_STRATEGY = ${strategyLiteral};
|
|
87
|
+
const COMPOSER_SIGNAL_INCLUDES = ${composerIncludesLiteral};
|
|
88
|
+
const COMPOSER_SIGNAL_EXCLUDES = ${composerExcludesLiteral};
|
|
89
|
+
const COMPOSER_SIGNAL_ALLOW_BLANK = ${composerAllowBlankLiteral};
|
|
55
90
|
const INITIAL_WAIT_MS = 150;
|
|
56
91
|
const REOPEN_INTERVAL_MS = 400;
|
|
57
92
|
const MAX_WAIT_MS = 20000;
|
|
93
|
+
const SETTLE_WAIT_MS = 1500;
|
|
58
94
|
const normalizeText = (value) => {
|
|
59
95
|
if (!value) {
|
|
60
96
|
return '';
|
|
@@ -73,16 +109,32 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
73
109
|
const targetWords = normalizedTarget.split(' ').filter(Boolean);
|
|
74
110
|
const desiredVersion = normalizedTarget.includes('5 4')
|
|
75
111
|
? '5-4'
|
|
76
|
-
: normalizedTarget.includes('5
|
|
112
|
+
: normalizedTarget.includes('5 5')
|
|
113
|
+
? '5-5'
|
|
114
|
+
: normalizedTarget.includes('5 2')
|
|
77
115
|
? '5-2'
|
|
78
116
|
: normalizedTarget.includes('5 1')
|
|
79
117
|
? '5-1'
|
|
80
118
|
: normalizedTarget.includes('5 0')
|
|
81
119
|
? '5-0'
|
|
82
|
-
|
|
120
|
+
: null;
|
|
83
121
|
const wantsPro = normalizedTarget.includes(' pro') || normalizedTarget.endsWith(' pro') || normalizedTokens.includes('pro');
|
|
84
122
|
const wantsInstant = normalizedTarget.includes('instant');
|
|
85
123
|
const wantsThinking = normalizedTarget.includes('thinking');
|
|
124
|
+
const isTargetGpt55VisibleAlias = (value) => {
|
|
125
|
+
if (desiredVersion !== '5-5') return false;
|
|
126
|
+
const label = normalizeText(value);
|
|
127
|
+
if (wantsPro) {
|
|
128
|
+
return label.includes('pro') && label.includes('extended') && !label.includes('thinking');
|
|
129
|
+
}
|
|
130
|
+
if (wantsThinking) {
|
|
131
|
+
return label.includes('thinking') && label.includes('heavy') && !label.includes('pro');
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
};
|
|
135
|
+
const hasProComposerPill = () => Boolean(
|
|
136
|
+
document.querySelector('button.__composer-pill, button[aria-label="Pro, click to remove"]')
|
|
137
|
+
);
|
|
86
138
|
|
|
87
139
|
const button = document.querySelector(BUTTON_SELECTOR);
|
|
88
140
|
if (!button) {
|
|
@@ -110,13 +162,34 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
110
162
|
};
|
|
111
163
|
|
|
112
164
|
const getButtonLabel = () => (button.textContent ?? '').trim();
|
|
165
|
+
const getComposerModelLabel = () =>
|
|
166
|
+
(document.querySelector(COMPOSER_MODEL_SIGNAL_SELECTOR)?.textContent ?? '').trim();
|
|
167
|
+
const readComposerModelSignal = () => normalizeText(getComposerModelLabel());
|
|
168
|
+
const withProPillSignal = (label) => {
|
|
169
|
+
const resolved = label || '';
|
|
170
|
+
if (!wantsPro || !hasProComposerPill()) return resolved;
|
|
171
|
+
const normalized = normalizeText(resolved);
|
|
172
|
+
if (!normalized || normalized.includes('pro')) return resolved;
|
|
173
|
+
return resolved + ' + Pro';
|
|
174
|
+
};
|
|
175
|
+
const getResolvedLabel = (fallback) =>
|
|
176
|
+
withProPillSignal(getComposerModelLabel() || getButtonLabel() || fallback);
|
|
113
177
|
if (MODEL_STRATEGY === 'current') {
|
|
114
|
-
|
|
178
|
+
const currentLabel = getResolvedLabel(PRIMARY_LABEL);
|
|
179
|
+
return {
|
|
180
|
+
status: 'already-selected',
|
|
181
|
+
label: currentLabel,
|
|
182
|
+
};
|
|
115
183
|
}
|
|
116
184
|
const buttonMatchesTarget = () => {
|
|
117
185
|
const normalizedLabel = normalizeText(getButtonLabel());
|
|
118
186
|
if (!normalizedLabel) return false;
|
|
187
|
+
if (isTargetGpt55VisibleAlias(normalizedLabel)) return true;
|
|
188
|
+
if (wantsPro && normalizedLabel === 'chatgpt' && hasProComposerPill()) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
119
191
|
if (desiredVersion) {
|
|
192
|
+
if (desiredVersion === '5-5' && !normalizedLabel.includes('5 5')) return false;
|
|
120
193
|
if (desiredVersion === '5-4' && !normalizedLabel.includes('5 4')) return false;
|
|
121
194
|
if (desiredVersion === '5-2' && !normalizedLabel.includes('5 2')) return false;
|
|
122
195
|
if (desiredVersion === '5-1' && !normalizedLabel.includes('5 1')) return false;
|
|
@@ -131,9 +204,47 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
131
204
|
if (!wantsThinking && normalizedLabel.includes('thinking')) return false;
|
|
132
205
|
return true;
|
|
133
206
|
};
|
|
207
|
+
const buttonHasGenericLabel = () => {
|
|
208
|
+
const normalizedLabel = normalizeText(getButtonLabel());
|
|
209
|
+
return !normalizedLabel || normalizedLabel === 'chatgpt';
|
|
210
|
+
};
|
|
211
|
+
const composerSignalMatchesTarget = () => {
|
|
212
|
+
const signal = readComposerModelSignal();
|
|
213
|
+
if (!signal) {
|
|
214
|
+
return COMPOSER_SIGNAL_ALLOW_BLANK;
|
|
215
|
+
}
|
|
216
|
+
if (COMPOSER_SIGNAL_EXCLUDES.some((token) => token && signal.includes(token))) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
if (COMPOSER_SIGNAL_INCLUDES.length === 0) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
return COMPOSER_SIGNAL_INCLUDES.some((token) => token && signal.includes(token));
|
|
223
|
+
};
|
|
224
|
+
const activeSelectionMatchesTarget = () => {
|
|
225
|
+
if (buttonMatchesTarget()) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
if (!buttonHasGenericLabel()) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return composerSignalMatchesTarget();
|
|
232
|
+
};
|
|
233
|
+
const selectionStateChanged = (previousButtonLabel, previousComposerSignal) => {
|
|
234
|
+
const currentButtonLabel = normalizeText(getButtonLabel());
|
|
235
|
+
const currentComposerSignal = readComposerModelSignal();
|
|
236
|
+
if (
|
|
237
|
+
currentButtonLabel &&
|
|
238
|
+
currentButtonLabel !== previousButtonLabel &&
|
|
239
|
+
!buttonHasGenericLabel()
|
|
240
|
+
) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
return currentComposerSignal !== previousComposerSignal;
|
|
244
|
+
};
|
|
134
245
|
|
|
135
|
-
if (
|
|
136
|
-
return { status: 'already-selected', label:
|
|
246
|
+
if (activeSelectionMatchesTarget()) {
|
|
247
|
+
return { status: 'already-selected', label: getResolvedLabel(PRIMARY_LABEL) };
|
|
137
248
|
}
|
|
138
249
|
|
|
139
250
|
let lastPointerClick = 0;
|
|
@@ -144,6 +255,10 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
144
255
|
};
|
|
145
256
|
|
|
146
257
|
const getOptionLabel = (node) => node?.textContent?.trim() ?? '';
|
|
258
|
+
const isThinkingEffortControl = (node) =>
|
|
259
|
+
node instanceof HTMLElement &&
|
|
260
|
+
(node.getAttribute('data-model-picker-thinking-effort-action') === 'true' ||
|
|
261
|
+
Boolean(node.closest('[data-model-picker-thinking-effort-action="true"]')));
|
|
147
262
|
const optionIsSelected = (node) => {
|
|
148
263
|
if (!(node instanceof HTMLElement)) {
|
|
149
264
|
return false;
|
|
@@ -160,7 +275,7 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
160
275
|
if (dataSelected === 'true' || selectedStates.includes(dataState)) {
|
|
161
276
|
return true;
|
|
162
277
|
}
|
|
163
|
-
if (node.querySelector('[data-testid*="check"], [role="img"][data-icon="check"], svg[data-icon="check"]')) {
|
|
278
|
+
if (node.querySelector('[data-testid*="check"], [role="img"][data-icon="check"], svg[data-icon="check"], .trailing svg')) {
|
|
164
279
|
return true;
|
|
165
280
|
}
|
|
166
281
|
return false;
|
|
@@ -182,6 +297,12 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
182
297
|
normalizedTestId.includes('gpt-5-2') ||
|
|
183
298
|
normalizedTestId.includes('gpt-5.2') ||
|
|
184
299
|
normalizedTestId.includes('gpt52');
|
|
300
|
+
const has55 =
|
|
301
|
+
normalizedTestId.includes('5-5') ||
|
|
302
|
+
normalizedTestId.includes('5.5') ||
|
|
303
|
+
normalizedTestId.includes('gpt-5-5') ||
|
|
304
|
+
normalizedTestId.includes('gpt-5.5') ||
|
|
305
|
+
normalizedTestId.includes('gpt55');
|
|
185
306
|
const has54 =
|
|
186
307
|
normalizedTestId.includes('5-4') ||
|
|
187
308
|
normalizedTestId.includes('5.4') ||
|
|
@@ -200,7 +321,7 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
200
321
|
normalizedTestId.includes('gpt-5-0') ||
|
|
201
322
|
normalizedTestId.includes('gpt-5.0') ||
|
|
202
323
|
normalizedTestId.includes('gpt50');
|
|
203
|
-
const candidateVersion = has54 ? '5-4' : has52 ? '5-2' : has51 ? '5-1' : has50 ? '5-0' : null;
|
|
324
|
+
const candidateVersion = has55 ? '5-5' : has54 ? '5-4' : has52 ? '5-2' : has51 ? '5-1' : has50 ? '5-0' : null;
|
|
204
325
|
// If a candidate advertises a different version, ignore it entirely.
|
|
205
326
|
if (candidateVersion && candidateVersion !== desiredVersion) {
|
|
206
327
|
return 0;
|
|
@@ -227,6 +348,33 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
227
348
|
}
|
|
228
349
|
}
|
|
229
350
|
}
|
|
351
|
+
const candidateGpt55VisibleAlias = isTargetGpt55VisibleAlias(normalizedText);
|
|
352
|
+
const candidateHasThinking =
|
|
353
|
+
normalizedText.includes('thinking') || normalizedTestId.includes('thinking');
|
|
354
|
+
const candidateHasPro =
|
|
355
|
+
candidateGpt55VisibleAlias ||
|
|
356
|
+
normalizedText === 'pro' ||
|
|
357
|
+
normalizedText.startsWith('pro ') ||
|
|
358
|
+
normalizedText.includes(' pro ') ||
|
|
359
|
+
normalizedText.endsWith(' pro') ||
|
|
360
|
+
normalizedText.includes('proresearch') ||
|
|
361
|
+
normalizedTestId.includes('pro');
|
|
362
|
+
if (wantsPro && candidateHasThinking) return 0;
|
|
363
|
+
if (wantsPro && !candidateHasPro) return 0;
|
|
364
|
+
if (wantsThinking && candidateHasPro) return 0;
|
|
365
|
+
if (desiredVersion === '5-5' && normalizedText && !candidateGpt55VisibleAlias) {
|
|
366
|
+
const candidateHasVersion =
|
|
367
|
+
normalizedText.includes('5 5') ||
|
|
368
|
+
normalizedText.includes('gpt55') ||
|
|
369
|
+
normalizedText.includes('gpt 5 5');
|
|
370
|
+
const versionLikeLabel = /(?:^|\\s)5\\s+[0-9](?:\\s|$)/.test(normalizedText) || normalizedText.includes('gpt');
|
|
371
|
+
if (versionLikeLabel && !candidateHasVersion) {
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (candidateGpt55VisibleAlias) {
|
|
376
|
+
score += 900;
|
|
377
|
+
}
|
|
230
378
|
if (normalizedText && normalizedTarget) {
|
|
231
379
|
if (normalizedText === normalizedTarget) {
|
|
232
380
|
score += 500;
|
|
@@ -286,6 +434,9 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
286
434
|
for (const menu of menus) {
|
|
287
435
|
const buttons = Array.from(menu.querySelectorAll(${menuItemLiteral}));
|
|
288
436
|
for (const option of buttons) {
|
|
437
|
+
if (isThinkingEffortControl(option)) {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
289
440
|
const text = option.textContent ?? '';
|
|
290
441
|
const normalizedText = normalizeText(text);
|
|
291
442
|
const testid = option.getAttribute('data-testid') ?? '';
|
|
@@ -301,6 +452,25 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
301
452
|
}
|
|
302
453
|
return bestMatch;
|
|
303
454
|
};
|
|
455
|
+
const waitForTargetSelection = (previousButtonLabel, previousComposerSignal) => new Promise((resolve) => {
|
|
456
|
+
const waitStart = performance.now();
|
|
457
|
+
const check = () => {
|
|
458
|
+
if (activeSelectionMatchesTarget()) {
|
|
459
|
+
resolve('target');
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (selectionStateChanged(previousButtonLabel, previousComposerSignal)) {
|
|
463
|
+
resolve('changed');
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (performance.now() - waitStart > SETTLE_WAIT_MS) {
|
|
467
|
+
resolve('timeout');
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
setTimeout(check, 100);
|
|
471
|
+
};
|
|
472
|
+
check();
|
|
473
|
+
});
|
|
304
474
|
|
|
305
475
|
return new Promise((resolve) => {
|
|
306
476
|
const start = performance.now();
|
|
@@ -345,11 +515,13 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
345
515
|
ensureMenuOpen();
|
|
346
516
|
const match = findBestOption();
|
|
347
517
|
if (match) {
|
|
348
|
-
if (
|
|
518
|
+
if (activeSelectionMatchesTarget()) {
|
|
349
519
|
closeMenu();
|
|
350
|
-
resolve({ status: 'already-selected', label:
|
|
520
|
+
resolve({ status: 'already-selected', label: getResolvedLabel(match.label) });
|
|
351
521
|
return;
|
|
352
522
|
}
|
|
523
|
+
const previousButtonLabel = normalizeText(getButtonLabel());
|
|
524
|
+
const previousComposerSignal = readComposerModelSignal();
|
|
353
525
|
dispatchClickSequence(match.node);
|
|
354
526
|
// Submenus (e.g. "Legacy models") need a second pass to pick the actual model option.
|
|
355
527
|
// Keep scanning once the submenu opens instead of treating the submenu click as a final switch.
|
|
@@ -358,15 +530,15 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
358
530
|
setTimeout(attempt, REOPEN_INTERVAL_MS / 2);
|
|
359
531
|
return;
|
|
360
532
|
}
|
|
361
|
-
// Wait for the
|
|
362
|
-
|
|
363
|
-
if (
|
|
533
|
+
// Wait for the selected model signal to settle before reopening the picker.
|
|
534
|
+
waitForTargetSelection(previousButtonLabel, previousComposerSignal).then((selectionSettled) => {
|
|
535
|
+
if (selectionSettled === 'target') {
|
|
364
536
|
closeMenu();
|
|
365
|
-
resolve({ status: 'switched', label:
|
|
537
|
+
resolve({ status: 'switched', label: getResolvedLabel(match.label) });
|
|
366
538
|
return;
|
|
367
539
|
}
|
|
368
540
|
attempt();
|
|
369
|
-
}
|
|
541
|
+
});
|
|
370
542
|
return;
|
|
371
543
|
}
|
|
372
544
|
if (performance.now() - start > MAX_WAIT_MS) {
|
|
@@ -385,6 +557,27 @@ function buildModelSelectionExpression(targetModel, strategy) {
|
|
|
385
557
|
export function buildModelMatchersLiteralForTest(targetModel) {
|
|
386
558
|
return buildModelMatchersLiteral(targetModel);
|
|
387
559
|
}
|
|
560
|
+
function buildComposerSignalMatchers(targetModel) {
|
|
561
|
+
const normalized = targetModel
|
|
562
|
+
.trim()
|
|
563
|
+
.toLowerCase()
|
|
564
|
+
.replace(/[^a-z0-9]+/g, " ")
|
|
565
|
+
.replace(/\s+/g, " ")
|
|
566
|
+
.trim();
|
|
567
|
+
if (normalized.includes("pro")) {
|
|
568
|
+
return { includesAny: ["pro"], excludesAny: ["thinking"], allowBlank: false };
|
|
569
|
+
}
|
|
570
|
+
if (normalized.includes("thinking")) {
|
|
571
|
+
return { includesAny: ["thinking"], excludesAny: ["pro"], allowBlank: false };
|
|
572
|
+
}
|
|
573
|
+
if (normalized.includes("instant")) {
|
|
574
|
+
return { includesAny: [], excludesAny: ["thinking", "pro"], allowBlank: true };
|
|
575
|
+
}
|
|
576
|
+
return { includesAny: [], excludesAny: ["thinking", "pro"], allowBlank: true };
|
|
577
|
+
}
|
|
578
|
+
export function buildComposerSignalMatchersForTest(targetModel) {
|
|
579
|
+
return buildComposerSignalMatchers(targetModel);
|
|
580
|
+
}
|
|
388
581
|
function buildModelMatchersLiteral(targetModel) {
|
|
389
582
|
const base = targetModel.trim().toLowerCase();
|
|
390
583
|
const labelTokens = new Set();
|
|
@@ -396,115 +589,145 @@ function buildModelMatchersLiteral(targetModel) {
|
|
|
396
589
|
}
|
|
397
590
|
};
|
|
398
591
|
push(base, labelTokens);
|
|
399
|
-
push(base.replace(/\s+/g,
|
|
400
|
-
const collapsed = base.replace(/\s+/g,
|
|
592
|
+
push(base.replace(/\s+/g, " "), labelTokens);
|
|
593
|
+
const collapsed = base.replace(/\s+/g, "");
|
|
401
594
|
push(collapsed, labelTokens);
|
|
402
|
-
const dotless = base.replace(/[.]/g,
|
|
595
|
+
const dotless = base.replace(/[.]/g, "");
|
|
403
596
|
push(dotless, labelTokens);
|
|
404
597
|
push(`chatgpt ${base}`, labelTokens);
|
|
405
598
|
push(`chatgpt ${dotless}`, labelTokens);
|
|
406
599
|
push(`gpt ${base}`, labelTokens);
|
|
407
600
|
push(`gpt ${dotless}`, labelTokens);
|
|
601
|
+
// Numeric variations (5.5 <-> 55 <-> gpt-5-5)
|
|
602
|
+
if (base.includes("5.5") || base.includes("5-5") || base.includes("55")) {
|
|
603
|
+
push("5.5", labelTokens);
|
|
604
|
+
push("gpt-5.5", labelTokens);
|
|
605
|
+
push("gpt5.5", labelTokens);
|
|
606
|
+
push("gpt-5-5", labelTokens);
|
|
607
|
+
push("gpt5-5", labelTokens);
|
|
608
|
+
push("gpt55", labelTokens);
|
|
609
|
+
push("chatgpt 5.5", labelTokens);
|
|
610
|
+
if (base.includes("thinking")) {
|
|
611
|
+
push("thinking heavy", labelTokens);
|
|
612
|
+
push("heavy thinking", labelTokens);
|
|
613
|
+
testIdTokens.add("model-switcher-gpt-5-5-thinking");
|
|
614
|
+
testIdTokens.add("gpt-5-5-thinking");
|
|
615
|
+
testIdTokens.add("gpt-5.5-thinking");
|
|
616
|
+
}
|
|
617
|
+
if (!base.includes("pro") && !base.includes("thinking")) {
|
|
618
|
+
testIdTokens.add("model-switcher-gpt-5-5");
|
|
619
|
+
}
|
|
620
|
+
testIdTokens.add("gpt-5-5");
|
|
621
|
+
testIdTokens.add("gpt5-5");
|
|
622
|
+
testIdTokens.add("gpt55");
|
|
623
|
+
}
|
|
408
624
|
// Numeric variations (5.4 ↔ 54 ↔ gpt-5-4)
|
|
409
|
-
if (base.includes(
|
|
410
|
-
push(
|
|
411
|
-
push(
|
|
412
|
-
push(
|
|
413
|
-
push(
|
|
414
|
-
push(
|
|
415
|
-
push(
|
|
416
|
-
push(
|
|
417
|
-
if (!base.includes(
|
|
418
|
-
testIdTokens.add(
|
|
419
|
-
}
|
|
420
|
-
testIdTokens.add(
|
|
421
|
-
testIdTokens.add(
|
|
422
|
-
testIdTokens.add(
|
|
625
|
+
if (base.includes("5.4") || base.includes("5-4") || base.includes("54")) {
|
|
626
|
+
push("5.4", labelTokens);
|
|
627
|
+
push("gpt-5.4", labelTokens);
|
|
628
|
+
push("gpt5.4", labelTokens);
|
|
629
|
+
push("gpt-5-4", labelTokens);
|
|
630
|
+
push("gpt5-4", labelTokens);
|
|
631
|
+
push("gpt54", labelTokens);
|
|
632
|
+
push("chatgpt 5.4", labelTokens);
|
|
633
|
+
if (!base.includes("pro")) {
|
|
634
|
+
testIdTokens.add("model-switcher-gpt-5-4");
|
|
635
|
+
}
|
|
636
|
+
testIdTokens.add("gpt-5-4");
|
|
637
|
+
testIdTokens.add("gpt5-4");
|
|
638
|
+
testIdTokens.add("gpt54");
|
|
423
639
|
}
|
|
424
640
|
// Numeric variations (5.1 ↔ 51 ↔ gpt-5-1)
|
|
425
|
-
if (base.includes(
|
|
426
|
-
push(
|
|
427
|
-
push(
|
|
428
|
-
push(
|
|
429
|
-
push(
|
|
430
|
-
push(
|
|
431
|
-
push(
|
|
432
|
-
push(
|
|
433
|
-
testIdTokens.add(
|
|
434
|
-
testIdTokens.add(
|
|
435
|
-
testIdTokens.add(
|
|
641
|
+
if (base.includes("5.1") || base.includes("5-1") || base.includes("51")) {
|
|
642
|
+
push("5.1", labelTokens);
|
|
643
|
+
push("gpt-5.1", labelTokens);
|
|
644
|
+
push("gpt5.1", labelTokens);
|
|
645
|
+
push("gpt-5-1", labelTokens);
|
|
646
|
+
push("gpt5-1", labelTokens);
|
|
647
|
+
push("gpt51", labelTokens);
|
|
648
|
+
push("chatgpt 5.1", labelTokens);
|
|
649
|
+
testIdTokens.add("gpt-5-1");
|
|
650
|
+
testIdTokens.add("gpt5-1");
|
|
651
|
+
testIdTokens.add("gpt51");
|
|
436
652
|
}
|
|
437
653
|
// Numeric variations (5.0 ↔ 50 ↔ gpt-5-0)
|
|
438
|
-
if (base.includes(
|
|
439
|
-
push(
|
|
440
|
-
push(
|
|
441
|
-
push(
|
|
442
|
-
push(
|
|
443
|
-
push(
|
|
444
|
-
push(
|
|
445
|
-
push(
|
|
446
|
-
testIdTokens.add(
|
|
447
|
-
testIdTokens.add(
|
|
448
|
-
testIdTokens.add(
|
|
654
|
+
if (base.includes("5.0") || base.includes("5-0") || base.includes("50")) {
|
|
655
|
+
push("5.0", labelTokens);
|
|
656
|
+
push("gpt-5.0", labelTokens);
|
|
657
|
+
push("gpt5.0", labelTokens);
|
|
658
|
+
push("gpt-5-0", labelTokens);
|
|
659
|
+
push("gpt5-0", labelTokens);
|
|
660
|
+
push("gpt50", labelTokens);
|
|
661
|
+
push("chatgpt 5.0", labelTokens);
|
|
662
|
+
testIdTokens.add("gpt-5-0");
|
|
663
|
+
testIdTokens.add("gpt5-0");
|
|
664
|
+
testIdTokens.add("gpt50");
|
|
449
665
|
}
|
|
450
666
|
// Numeric variations (5.2 ↔ 52 ↔ gpt-5-2)
|
|
451
|
-
if (base.includes(
|
|
452
|
-
push(
|
|
453
|
-
push(
|
|
454
|
-
push(
|
|
455
|
-
push(
|
|
456
|
-
push(
|
|
457
|
-
push(
|
|
458
|
-
push(
|
|
667
|
+
if (base.includes("5.2") || base.includes("5-2") || base.includes("52")) {
|
|
668
|
+
push("5.2", labelTokens);
|
|
669
|
+
push("gpt-5.2", labelTokens);
|
|
670
|
+
push("gpt5.2", labelTokens);
|
|
671
|
+
push("gpt-5-2", labelTokens);
|
|
672
|
+
push("gpt5-2", labelTokens);
|
|
673
|
+
push("gpt52", labelTokens);
|
|
674
|
+
push("chatgpt 5.2", labelTokens);
|
|
459
675
|
// Thinking variant: explicit testid for "Thinking" picker option
|
|
460
|
-
if (base.includes(
|
|
461
|
-
push(
|
|
462
|
-
testIdTokens.add(
|
|
463
|
-
testIdTokens.add(
|
|
464
|
-
testIdTokens.add(
|
|
676
|
+
if (base.includes("thinking")) {
|
|
677
|
+
push("thinking", labelTokens);
|
|
678
|
+
testIdTokens.add("model-switcher-gpt-5-2-thinking");
|
|
679
|
+
testIdTokens.add("gpt-5-2-thinking");
|
|
680
|
+
testIdTokens.add("gpt-5.2-thinking");
|
|
465
681
|
}
|
|
466
682
|
// Instant variant: explicit testid for "Instant" picker option
|
|
467
|
-
if (base.includes(
|
|
468
|
-
push(
|
|
469
|
-
testIdTokens.add(
|
|
470
|
-
testIdTokens.add(
|
|
471
|
-
testIdTokens.add(
|
|
683
|
+
if (base.includes("instant")) {
|
|
684
|
+
push("instant", labelTokens);
|
|
685
|
+
testIdTokens.add("model-switcher-gpt-5-2-instant");
|
|
686
|
+
testIdTokens.add("gpt-5-2-instant");
|
|
687
|
+
testIdTokens.add("gpt-5.2-instant");
|
|
472
688
|
}
|
|
473
689
|
// Base 5.2 testids (for "Auto" mode when no suffix specified)
|
|
474
|
-
if (!base.includes(
|
|
475
|
-
testIdTokens.add(
|
|
690
|
+
if (!base.includes("thinking") && !base.includes("instant") && !base.includes("pro")) {
|
|
691
|
+
testIdTokens.add("model-switcher-gpt-5-2");
|
|
476
692
|
}
|
|
477
|
-
testIdTokens.add(
|
|
478
|
-
testIdTokens.add(
|
|
479
|
-
testIdTokens.add(
|
|
693
|
+
testIdTokens.add("gpt-5-2");
|
|
694
|
+
testIdTokens.add("gpt5-2");
|
|
695
|
+
testIdTokens.add("gpt52");
|
|
480
696
|
}
|
|
481
697
|
// Pro / research variants
|
|
482
|
-
if (base.includes(
|
|
483
|
-
push(
|
|
484
|
-
push(
|
|
485
|
-
push(
|
|
486
|
-
if (base.includes(
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
testIdTokens.add(
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
testIdTokens.add(
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
testIdTokens.add(
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
testIdTokens.add(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
698
|
+
if (base.includes("pro")) {
|
|
699
|
+
push("proresearch", labelTokens);
|
|
700
|
+
push("research grade", labelTokens);
|
|
701
|
+
push("advanced reasoning", labelTokens);
|
|
702
|
+
if (base.includes("5.5") || base.includes("5-5") || base.includes("55")) {
|
|
703
|
+
push("pro extended", labelTokens);
|
|
704
|
+
push("extended pro", labelTokens);
|
|
705
|
+
testIdTokens.add("gpt-5.5-pro");
|
|
706
|
+
testIdTokens.add("gpt-5-5-pro");
|
|
707
|
+
testIdTokens.add("gpt55pro");
|
|
708
|
+
}
|
|
709
|
+
if (base.includes("5.4") || base.includes("5-4") || base.includes("54")) {
|
|
710
|
+
testIdTokens.add("gpt-5.4-pro");
|
|
711
|
+
testIdTokens.add("gpt-5-4-pro");
|
|
712
|
+
testIdTokens.add("gpt54pro");
|
|
713
|
+
}
|
|
714
|
+
if (base.includes("5.1") || base.includes("5-1") || base.includes("51")) {
|
|
715
|
+
testIdTokens.add("gpt-5.1-pro");
|
|
716
|
+
testIdTokens.add("gpt-5-1-pro");
|
|
717
|
+
testIdTokens.add("gpt51pro");
|
|
718
|
+
}
|
|
719
|
+
if (base.includes("5.0") || base.includes("5-0") || base.includes("50")) {
|
|
720
|
+
testIdTokens.add("gpt-5.0-pro");
|
|
721
|
+
testIdTokens.add("gpt-5-0-pro");
|
|
722
|
+
testIdTokens.add("gpt50pro");
|
|
723
|
+
}
|
|
724
|
+
if (base.includes("5.2") || base.includes("5-2") || base.includes("52")) {
|
|
725
|
+
testIdTokens.add("gpt-5.2-pro");
|
|
726
|
+
testIdTokens.add("gpt-5-2-pro");
|
|
727
|
+
testIdTokens.add("gpt52pro");
|
|
728
|
+
}
|
|
729
|
+
testIdTokens.add("pro");
|
|
730
|
+
testIdTokens.add("proresearch");
|
|
508
731
|
}
|
|
509
732
|
base
|
|
510
733
|
.split(/\s+/)
|
|
@@ -513,7 +736,7 @@ function buildModelMatchersLiteral(targetModel) {
|
|
|
513
736
|
.forEach((token) => {
|
|
514
737
|
push(token, labelTokens);
|
|
515
738
|
});
|
|
516
|
-
const hyphenated = base.replace(/\s+/g,
|
|
739
|
+
const hyphenated = base.replace(/\s+/g, "-");
|
|
517
740
|
push(hyphenated, testIdTokens);
|
|
518
741
|
push(collapsed, testIdTokens);
|
|
519
742
|
push(dotless, testIdTokens);
|
|
@@ -525,13 +748,13 @@ function buildModelMatchersLiteral(targetModel) {
|
|
|
525
748
|
labelTokens.add(base);
|
|
526
749
|
}
|
|
527
750
|
if (!testIdTokens.size) {
|
|
528
|
-
testIdTokens.add(base.replace(/\s+/g,
|
|
751
|
+
testIdTokens.add(base.replace(/\s+/g, "-"));
|
|
529
752
|
}
|
|
530
753
|
return {
|
|
531
754
|
labelTokens: Array.from(labelTokens).filter(Boolean),
|
|
532
755
|
testIdTokens: Array.from(testIdTokens).filter(Boolean),
|
|
533
756
|
};
|
|
534
757
|
}
|
|
535
|
-
export function buildModelSelectionExpressionForTest(targetModel) {
|
|
536
|
-
return buildModelSelectionExpression(targetModel,
|
|
758
|
+
export function buildModelSelectionExpressionForTest(targetModel, strategy = "select") {
|
|
759
|
+
return buildModelSelectionExpression(targetModel, strategy);
|
|
537
760
|
}
|