codex-chatgpt-control 0.5.1-alpha.5 → 0.5.1-alpha.6
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/CHANGELOG.md +20 -0
- package/contracts/v1/fixtures/doctor-scenario-preflight.json +2 -2
- package/dist/codex-chatgpt-control-backend.mjs +207 -59
- package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +207 -59
- package/dist/codex-chatgpt-control-release-canary.bundle.mjs +207 -59
- package/dist/codex-chatgpt-control.bundle.mjs +207 -59
- package/dist/src/browser/attach.js +8 -0
- package/dist/src/commands/chat-popover.d.ts +3 -0
- package/dist/src/commands/chat-popover.js +115 -20
- package/dist/src/commands/configuration.js +6 -1
- package/dist/src/commands/experience.js +42 -8
- package/dist/src/commands/files.js +14 -6
- package/dist/src/commands/modes.js +6 -2
- package/dist/src/dom/generation-state.js +19 -4
- package/dist/src/dom/locale/en.d.ts +3 -3
- package/dist/src/dom/locale/en.js +3 -3
- package/dist/src/dom/message-format.js +17 -2
- package/dist/src/dom/messages.js +38 -11
- package/dist/src/dom/selectors.d.ts +3 -2
- package/dist/src/dom/selectors.js +3 -2
- package/dist/src/dom/wait-snapshot.js +24 -5
- package/package.json +1 -1
- package/references/backend-protocol.md +23 -0
- package/references/python-parity.md +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.1-alpha.6
|
|
4
|
+
|
|
5
|
+
- Recognizes the current owned Chat model picker when Pro is already selected,
|
|
6
|
+
including open-picker mode reads and strict configuration verification.
|
|
7
|
+
- Ignores a retained hidden home composer after starting a Work task, while
|
|
8
|
+
requiring a unique visible picker trigger and verifying its owned menu.
|
|
9
|
+
- Supports its active simple and advanced tracks, ignores model expiry
|
|
10
|
+
subtitles, and rejects hidden, disabled, ambiguous, or unowned controls.
|
|
11
|
+
- Adapts Chrome's accessibility keyboard for verified picker dismissal and
|
|
12
|
+
restoration without replacing an existing provider keyboard.
|
|
13
|
+
- Recognizes current pressed Chat/Work pane buttons and the marked composer
|
|
14
|
+
form, retaining bounded capture and rejecting quoted or ambiguous groups.
|
|
15
|
+
- Accepts observed current English Send and Stop labels while retaining previous
|
|
16
|
+
labels, composer ownership, disjointness and button-readiness checks.
|
|
17
|
+
- Captures current role-qualified conversation containers and file-only replies,
|
|
18
|
+
with completion actions bounded to the latest assistant's owner.
|
|
19
|
+
- Supports exact-filename current file previews while preserving native receipt
|
|
20
|
+
verification and non-resumable uncertainty when download completion is unknown.
|
|
21
|
+
- Updates the development-only `fast-uri` dependency to its security patch.
|
|
22
|
+
|
|
3
23
|
## 0.5.1-alpha.5
|
|
4
24
|
|
|
5
25
|
- Recognizes project-scoped composers whose accessible name begins with
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"fast"
|
|
92
92
|
],
|
|
93
93
|
"englishCanonicalPresent": true,
|
|
94
|
-
"labelCandidateCount":
|
|
94
|
+
"labelCandidateCount": 2625,
|
|
95
95
|
"missingConfigurationAxisIds": [],
|
|
96
96
|
"missingConfigurationOptionIds": [],
|
|
97
97
|
"missingModeOptionIds": [],
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"nonEnglishStopControlLocaleCount": 63,
|
|
134
134
|
"nonEnglishStoppedAssistantLocaleCount": 0,
|
|
135
135
|
"registeredLocaleCount": 65,
|
|
136
|
-
"stopControlCandidateCount":
|
|
136
|
+
"stopControlCandidateCount": 64,
|
|
137
137
|
"stopControlLocaleCount": 64,
|
|
138
138
|
"stoppedAssistantCandidateCount": 3,
|
|
139
139
|
"stoppedAssistantLocaleCount": 1,
|
|
@@ -1039,10 +1039,10 @@ function classifyVisibleText(text) {
|
|
|
1039
1039
|
var en = {
|
|
1040
1040
|
// --- Primary interaction path (accessible names) ---
|
|
1041
1041
|
composerTextbox: ["Chat with ChatGPT", "Ask ChatGPT"],
|
|
1042
|
-
workComposerTextbox: ["Work on anything", "Work on something"],
|
|
1042
|
+
workComposerTextbox: ["Work on anything", "Work on something", "Work with ChatGPT"],
|
|
1043
1043
|
projectComposerPrefixes: ["New chat in"],
|
|
1044
1044
|
newWork: ["Work on something else", "New work", "New task"],
|
|
1045
|
-
sendButton: ["Send prompt"],
|
|
1045
|
+
sendButton: ["Send prompt", "Send"],
|
|
1046
1046
|
searchChatsButton: ["Search chats"],
|
|
1047
1047
|
searchChatsPlaceholder: ["Search chats..."],
|
|
1048
1048
|
newChat: ["New chat"],
|
|
@@ -1115,7 +1115,7 @@ var en = {
|
|
|
1115
1115
|
/** Exact-match transient assistant placeholders filtered out of captured responses. */
|
|
1116
1116
|
transientAssistant: ["thinking", "reasoning", "searching", "searching the web"],
|
|
1117
1117
|
/** Streaming "stop" control text, matched while a response generates. */
|
|
1118
|
-
stopControl: ["stop generating", "stop streaming", "stop answering"],
|
|
1118
|
+
stopControl: ["stop generating", "stop streaming", "stop answering", "stop"],
|
|
1119
1119
|
/** Interrupted generation markers shown after the assistant stops before completion. */
|
|
1120
1120
|
stoppedAssistant: ["stopped thinking", "stopped answering", "generation stopped"],
|
|
1121
1121
|
/** Response-action affordance text (fallback to the structural copy-button locator). */
|
|
@@ -4834,8 +4834,9 @@ var generatedArtifactDownloadClauses = [
|
|
|
4834
4834
|
];
|
|
4835
4835
|
var cssSelectors = {
|
|
4836
4836
|
assistantMessages: "[data-message-author-role='assistant']",
|
|
4837
|
-
|
|
4838
|
-
|
|
4837
|
+
currentAssistantMessages: "main [data-chatgpt-search-unit-key$=':assistant'][data-chatgpt-search-message-ids]",
|
|
4838
|
+
userMessages: "[data-message-author-role='user'], main [data-chatgpt-search-unit-key$=':user'][data-chatgpt-search-message-ids]",
|
|
4839
|
+
roleMessages: "[data-message-author-role], main [data-chatgpt-search-unit-key$=':user'][data-chatgpt-search-message-ids], main [data-chatgpt-search-unit-key$=':assistant'][data-chatgpt-search-message-ids]",
|
|
4839
4840
|
conversationTurns: "[data-testid^='conversation-turn']",
|
|
4840
4841
|
hiddenFileInputs: "input[type='file']",
|
|
4841
4842
|
downloadControls: downloadControlClauses.join(", "),
|
|
@@ -4960,10 +4961,19 @@ function extractRoleMessageHtml(html) {
|
|
|
4960
4961
|
const root = parseHtmlFragment(html);
|
|
4961
4962
|
const messages = [];
|
|
4962
4963
|
walkElementsWithAncestors(root, [], (element, ancestors) => {
|
|
4963
|
-
const
|
|
4964
|
+
const current = element.attrs["data-message-author-role"] === void 0 && element.attrs["data-chatgpt-search-message-ids"] !== void 0;
|
|
4965
|
+
if (current && !ancestors.some((ancestor) => ancestor.tag === "main")) return;
|
|
4966
|
+
const role = element.attrs["data-message-author-role"] ?? (current ? element.attrs["data-chatgpt-search-unit-key"]?.split(":").at(-1) : void 0);
|
|
4964
4967
|
if (role === "user" || role === "assistant") {
|
|
4965
4968
|
const metadataElement = [...ancestors].reverse().find((ancestor) => ancestor.attrs["data-testid"]?.startsWith("conversation-turn")) ?? element;
|
|
4966
|
-
|
|
4969
|
+
let content = element;
|
|
4970
|
+
if (current) {
|
|
4971
|
+
walkElements(element, (child) => {
|
|
4972
|
+
if (role === "user" && child.attrs["data-user-message-bubble"] === "true" || role === "assistant" && child.attrs["data-markdown-text-style"] === "assistant-message" && child.children.length > 0) content = child;
|
|
4973
|
+
});
|
|
4974
|
+
}
|
|
4975
|
+
const messageHtml = serializeChildren(content).replace(/<h4\b[^>]*data-conversation-role=["']assistant["'][^>]*>[\s\S]*?<\/h4>/i, "");
|
|
4976
|
+
messages.push({ role, html: messageHtml, metadataHtml: serializeNode(metadataElement) });
|
|
4967
4977
|
}
|
|
4968
4978
|
});
|
|
4969
4979
|
return messages;
|
|
@@ -5498,15 +5508,19 @@ function extractMessagesFromHtml(html, args = {}) {
|
|
|
5498
5508
|
async function readMessages(page, args = {}) {
|
|
5499
5509
|
if (typeof page.evaluate === "function") {
|
|
5500
5510
|
const messages = await page.evaluate(() => {
|
|
5501
|
-
const
|
|
5511
|
+
const legacy = Array.from(document.querySelectorAll("[data-message-author-role]"));
|
|
5512
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
5513
|
+
"main [data-chatgpt-search-unit-key][data-chatgpt-search-message-ids]"
|
|
5514
|
+
));
|
|
5502
5515
|
return nodes.map((node) => {
|
|
5503
|
-
const role = node.getAttribute("data-message-author-role");
|
|
5516
|
+
const role = node.getAttribute("data-message-author-role") ?? node.getAttribute("data-chatgpt-search-unit-key")?.split(":").at(-1);
|
|
5504
5517
|
if (role !== "user" && role !== "assistant") {
|
|
5505
5518
|
return void 0;
|
|
5506
5519
|
}
|
|
5520
|
+
const content = role === "user" ? node.querySelector?.('[data-user-message-bubble="true"]') : node.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
5507
5521
|
return {
|
|
5508
5522
|
role,
|
|
5509
|
-
html: node.innerHTML,
|
|
5523
|
+
html: content?.innerHTML || node.innerHTML.replace(/<h4\b[^>]*data-conversation-role=["']assistant["'][^>]*>[\s\S]*?<\/h4>/i, ""),
|
|
5510
5524
|
metadataHtml: node.closest("[data-testid^='conversation-turn']")?.outerHTML ?? node.outerHTML
|
|
5511
5525
|
};
|
|
5512
5526
|
}).filter(Boolean);
|
|
@@ -5522,12 +5536,16 @@ async function readMessages(page, args = {}) {
|
|
|
5522
5536
|
async function readLatestMessage(page, role = "assistant", format = "markdown", maxChars) {
|
|
5523
5537
|
if (typeof page.evaluate === "function") {
|
|
5524
5538
|
const message = await page.evaluate((wantedRole) => {
|
|
5525
|
-
const
|
|
5539
|
+
const legacy = Array.from(document.querySelectorAll(`[data-message-author-role="${wantedRole}"]`));
|
|
5540
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
5541
|
+
`main [data-chatgpt-search-unit-key$=":${wantedRole}"][data-chatgpt-search-message-ids]`
|
|
5542
|
+
));
|
|
5526
5543
|
const node = nodes.at(-1);
|
|
5527
5544
|
if (node === void 0) return void 0;
|
|
5545
|
+
const content = wantedRole === "user" ? node.querySelector?.('[data-user-message-bubble="true"]') : node.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
5528
5546
|
return {
|
|
5529
5547
|
role: wantedRole,
|
|
5530
|
-
html: node.innerHTML,
|
|
5548
|
+
html: content?.innerHTML || node.innerHTML.replace(/<h4\b[^>]*data-conversation-role=["']assistant["'][^>]*>[\s\S]*?<\/h4>/i, ""),
|
|
5531
5549
|
metadataHtml: node.closest("[data-testid^='conversation-turn']")?.outerHTML ?? node.outerHTML
|
|
5532
5550
|
};
|
|
5533
5551
|
}, role).catch(() => void 0);
|
|
@@ -5546,9 +5564,15 @@ async function readLatestMessage(page, role = "assistant", format = "markdown",
|
|
|
5546
5564
|
async function readLatestMessageText(page, role = "assistant") {
|
|
5547
5565
|
if (typeof page.evaluate === "function") {
|
|
5548
5566
|
return page.evaluate((wantedRole) => {
|
|
5549
|
-
const
|
|
5567
|
+
const legacy = Array.from(document.querySelectorAll(`[data-message-author-role="${wantedRole}"]`));
|
|
5568
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
5569
|
+
`main [data-chatgpt-search-unit-key$=":${wantedRole}"][data-chatgpt-search-message-ids]`
|
|
5570
|
+
));
|
|
5550
5571
|
const node = nodes.at(-1);
|
|
5551
|
-
return node?.innerText ?? node?.textContent ?? void 0;
|
|
5572
|
+
if (node?.getAttribute("data-chatgpt-search-unit-key") === null) return node?.innerText ?? node?.textContent ?? void 0;
|
|
5573
|
+
if (node === void 0) return void 0;
|
|
5574
|
+
const content = wantedRole === "user" ? node.querySelector?.('[data-user-message-bubble="true"]') : node.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
5575
|
+
return content?.innerText || content?.textContent || (node.innerText ?? node.textContent ?? "").replace(node.querySelector?.('[data-conversation-role="assistant"]')?.textContent ?? "", "").trim();
|
|
5552
5576
|
}, role).catch(() => void 0);
|
|
5553
5577
|
}
|
|
5554
5578
|
return readLatestMessage(page, role, "normalized_text").then((message) => message?.text).catch(() => void 0);
|
|
@@ -5556,10 +5580,14 @@ async function readLatestMessageText(page, role = "assistant") {
|
|
|
5556
5580
|
async function readLatestMessageTextSnapshot(page, role) {
|
|
5557
5581
|
if (typeof page.evaluate === "function") {
|
|
5558
5582
|
return page.evaluate((wantedRole) => {
|
|
5559
|
-
const
|
|
5560
|
-
const
|
|
5583
|
+
const legacy = Array.from(document.querySelectorAll("[data-message-author-role]"));
|
|
5584
|
+
const allNodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
5585
|
+
"main [data-chatgpt-search-unit-key][data-chatgpt-search-message-ids]"
|
|
5586
|
+
)).filter((node) => /:(?:user|assistant)$/.test(node.getAttribute("data-chatgpt-search-unit-key") ?? ""));
|
|
5587
|
+
const roleNodes = allNodes.filter((node) => (node.getAttribute("data-message-author-role") ?? node.getAttribute("data-chatgpt-search-unit-key")?.split(":").at(-1)) === wantedRole);
|
|
5561
5588
|
const latest = roleNodes.at(-1);
|
|
5562
|
-
const
|
|
5589
|
+
const content = wantedRole === "user" ? latest?.querySelector?.('[data-user-message-bubble="true"]') : latest?.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
5590
|
+
const latestText2 = content?.innerText || content?.textContent || (latest === void 0 ? void 0 : (latest.innerText ?? latest.textContent ?? "").replace(latest.querySelector?.('[data-conversation-role="assistant"]')?.textContent ?? "", "").trim());
|
|
5563
5591
|
const snapshot3 = { turnCount: allNodes.length };
|
|
5564
5592
|
if (latestText2 !== void 0) snapshot3.latestText = latestText2;
|
|
5565
5593
|
return snapshot3;
|
|
@@ -5583,7 +5611,10 @@ async function countPageMessages(page, role) {
|
|
|
5583
5611
|
if (typeof page.evaluate === "function") {
|
|
5584
5612
|
return page.evaluate((wantedRole) => {
|
|
5585
5613
|
const selector = wantedRole === void 0 ? "[data-message-author-role]" : `[data-message-author-role="${wantedRole}"]`;
|
|
5586
|
-
|
|
5614
|
+
const legacyCount = document.querySelectorAll(selector).length;
|
|
5615
|
+
if (legacyCount > 0) return legacyCount;
|
|
5616
|
+
const currentSelector = wantedRole === void 0 ? 'main [data-chatgpt-search-unit-key$=":user"][data-chatgpt-search-message-ids], main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]' : `main [data-chatgpt-search-unit-key$=":${wantedRole}"][data-chatgpt-search-message-ids]`;
|
|
5617
|
+
return document.querySelectorAll(currentSelector).length;
|
|
5587
5618
|
}, role);
|
|
5588
5619
|
}
|
|
5589
5620
|
return countMessages(await readMessages(page), role);
|
|
@@ -7601,6 +7632,13 @@ function normalizePage(pageOrTab) {
|
|
|
7601
7632
|
const value = providerValue(primary, property) ?? providerValue(maybe, property);
|
|
7602
7633
|
if (isProviderRecord(value)) normalized[property] = value;
|
|
7603
7634
|
}
|
|
7635
|
+
const rawAx = providerValue(maybe, "ax");
|
|
7636
|
+
if (normalized.keyboard === void 0 && isProviderRecord(rawAx)) {
|
|
7637
|
+
const pressKey = providerCallable(rawAx, "pressKey");
|
|
7638
|
+
if (pressKey !== void 0) normalized.keyboard = { press: async (key) => {
|
|
7639
|
+
await pressKey(null, key);
|
|
7640
|
+
} };
|
|
7641
|
+
}
|
|
7604
7642
|
if (isProviderRecord(embedded)) normalized.playwright = embedded;
|
|
7605
7643
|
for (const method of [
|
|
7606
7644
|
"url",
|
|
@@ -9220,12 +9258,16 @@ async function tryGeneratedFilePreviewDownload(page, args) {
|
|
|
9220
9258
|
const selected = selectGeneratedFileAffordance(candidates, args);
|
|
9221
9259
|
if (selected === void 0) return void 0;
|
|
9222
9260
|
try {
|
|
9223
|
-
|
|
9224
|
-
|
|
9261
|
+
let assistantMessages = requiredLocator(page, cssSelectors.assistantMessages);
|
|
9262
|
+
let assistantCount = await locatorCountWithTimeout(
|
|
9225
9263
|
assistantMessages,
|
|
9226
9264
|
localGuardTimeout(timeoutMs, 5e3),
|
|
9227
9265
|
"generated_file_assistant_count_timeout"
|
|
9228
9266
|
);
|
|
9267
|
+
if (assistantCount === 0) {
|
|
9268
|
+
assistantMessages = requiredLocator(page, cssSelectors.currentAssistantMessages);
|
|
9269
|
+
assistantCount = await locatorCountWithTimeout(assistantMessages, localGuardTimeout(timeoutMs, 5e3), "generated_file_assistant_count_timeout");
|
|
9270
|
+
}
|
|
9229
9271
|
if (selected.assistantIndex < 0 || selected.assistantIndex >= assistantCount) {
|
|
9230
9272
|
throw new Error("The selected generated-file assistant turn is no longer present.");
|
|
9231
9273
|
}
|
|
@@ -9253,11 +9295,12 @@ async function tryGeneratedFilePreviewDownload(page, args) {
|
|
|
9253
9295
|
}
|
|
9254
9296
|
await affordance.click({ timeoutMs: localGuardTimeout(timeoutMs, 1e4) });
|
|
9255
9297
|
const labelledPreview = requiredLocator(page, `section[aria-label="${escapeCssAttribute(selected.filename)}"]`);
|
|
9298
|
+
const currentPreview = page.getByRole?.("tabpanel", { name: selected.filename, exact: true });
|
|
9256
9299
|
const workbookPreviews = requiredLocator(page, "section[data-testid^='popcorn-']");
|
|
9257
9300
|
const workbookPreview = typeof workbookPreviews.filter === "function" ? workbookPreviews.filter({ hasText: selected.filename }) : void 0;
|
|
9258
9301
|
const download = await waitForPreviewDownloadControl(
|
|
9259
9302
|
page,
|
|
9260
|
-
|
|
9303
|
+
[...currentPreview === void 0 ? [] : [currentPreview], labelledPreview, ...workbookPreview === void 0 ? [] : [workbookPreview]],
|
|
9261
9304
|
timeoutMs
|
|
9262
9305
|
);
|
|
9263
9306
|
if (download === void 0) {
|
|
@@ -9298,17 +9341,20 @@ async function inspectGeneratedFileAffordances(page, timeoutMs) {
|
|
|
9298
9341
|
const prefix = downloadLabels.map((label) => label.trim()).filter(Boolean).sort((left, right) => right.length - left.length).find((label) => lowered.startsWith(`${label.toLocaleLowerCase()} `));
|
|
9299
9342
|
return prefix === void 0 ? trimmed : trimmed.slice(prefix.length).trim();
|
|
9300
9343
|
};
|
|
9301
|
-
const
|
|
9344
|
+
const legacyAssistants = Array.from(document.querySelectorAll("[data-message-author-role='assistant']"));
|
|
9345
|
+
const assistants = legacyAssistants.length > 0 ? legacyAssistants : Array.from(document.querySelectorAll(
|
|
9346
|
+
'main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'
|
|
9347
|
+
));
|
|
9302
9348
|
return assistants.flatMap(
|
|
9303
9349
|
(assistant, assistantIndex) => Array.from(assistant.querySelectorAll("button[aria-label], a[download], a[href*='/backend-api/files/']")).filter(visible).map((element) => {
|
|
9304
9350
|
const controlLabel = (element.getAttribute("aria-label") ?? element.textContent ?? "").trim();
|
|
9305
9351
|
const text = (element.textContent ?? "").trim();
|
|
9306
9352
|
return {
|
|
9307
9353
|
assistantIndex,
|
|
9308
|
-
filename: normalizedFilename(controlLabel),
|
|
9354
|
+
filename: controlLabel.startsWith("Open preview of ") ? controlLabel.slice("Open preview of ".length) : normalizedFilename(controlLabel),
|
|
9309
9355
|
controlLabel,
|
|
9310
9356
|
tag: element.tagName.toLocaleLowerCase(),
|
|
9311
|
-
textFilename: normalizedFilename(text)
|
|
9357
|
+
textFilename: controlLabel.startsWith("Open preview of ") ? element.parentElement?.querySelector("[title]")?.getAttribute("title") ?? "" : normalizedFilename(text)
|
|
9312
9358
|
};
|
|
9313
9359
|
}).filter((item) => (item.tag === "button" || item.tag === "a") && fileLike(item.filename) && item.filename === item.textFilename).map(({ assistantIndex: index, filename, controlLabel, tag }) => ({
|
|
9314
9360
|
assistantIndex: index,
|
|
@@ -11182,8 +11228,11 @@ async function readAssistantGenerationState(page, options = {}) {
|
|
|
11182
11228
|
const visibleStopButtons = Array.from(document.querySelectorAll("button")).filter((button) => isVisible(button) && button.disabled !== true && button.getAttribute("aria-disabled") !== "true" && isScopedStopControl(button) && matchingLabels2(button, args.send).length === 0 && matchingLabels2(button, args.stop).length > 0);
|
|
11183
11229
|
const activeSignals = [...new Set(visibleStopButtons.flatMap((button) => matchingLabels2(button, args.stop)))];
|
|
11184
11230
|
const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
|
|
11185
|
-
const
|
|
11186
|
-
const
|
|
11231
|
+
const legacyAssistants = Array.from(document.querySelectorAll("[data-message-author-role='assistant']"));
|
|
11232
|
+
const latestAssistant = (legacyAssistants.length > 0 ? legacyAssistants : Array.from(document.querySelectorAll(
|
|
11233
|
+
'main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'
|
|
11234
|
+
))).at(-1);
|
|
11235
|
+
const latestTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? turns.at(-1) ?? (latestAssistant?.hasAttribute?.("data-chatgpt-search-unit-key") === true ? latestAssistant : void 0);
|
|
11187
11236
|
const stoppedSignals = latestTurn === void 0 ? [] : [...new Set(Array.from(latestTurn.querySelectorAll(
|
|
11188
11237
|
"button, [role='status'], [aria-label], [title], p, span, div"
|
|
11189
11238
|
)).filter((element) => isVisible(element)).flatMap((element) => matchingLabels2(element, args.stopped)))];
|
|
@@ -11221,7 +11270,17 @@ async function latestAssistantTurnHasResponseActions(page) {
|
|
|
11221
11270
|
if (typeof page.evaluate === "function") {
|
|
11222
11271
|
const scoped = await page.evaluate((phrases) => {
|
|
11223
11272
|
const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
|
|
11224
|
-
if (turns.length === 0)
|
|
11273
|
+
if (turns.length === 0) {
|
|
11274
|
+
const latest = Array.from(document.querySelectorAll('main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]')).at(-1);
|
|
11275
|
+
if (latest === void 0) return void 0;
|
|
11276
|
+
let owner = latest;
|
|
11277
|
+
for (let depth = 0; owner !== null && depth < 6 && owner.tagName !== "MAIN"; depth += 1, owner = owner.parentElement) {
|
|
11278
|
+
const assistants = Array.from(owner.querySelectorAll('[data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'));
|
|
11279
|
+
if (owner !== latest && (assistants.length !== 1 || assistants[0] !== latest)) break;
|
|
11280
|
+
if (Array.from(owner.querySelectorAll("button")).some((button) => phrases.some((phrase) => [button.innerText, button.textContent, button.getAttribute("aria-label"), button.getAttribute("title")].some((value) => (value ?? "").trim().toLowerCase() === phrase.trim().toLowerCase())))) return true;
|
|
11281
|
+
}
|
|
11282
|
+
return false;
|
|
11283
|
+
}
|
|
11225
11284
|
const latestTurn = turns.reverse().find(
|
|
11226
11285
|
(turn) => turn.querySelector("[data-message-author-role='assistant']") !== null
|
|
11227
11286
|
);
|
|
@@ -11391,11 +11450,15 @@ async function readWaitDomSnapshot(page) {
|
|
|
11391
11450
|
void __combinedWaitSnapshot;
|
|
11392
11451
|
const normalizeWs = (value) => value.replace(/\s+/g, " ").trim();
|
|
11393
11452
|
const normalizeLower = (value) => (value ?? "").trim().toLowerCase();
|
|
11394
|
-
const
|
|
11395
|
-
const
|
|
11453
|
+
const legacy = Array.from(document.querySelectorAll("[data-message-author-role]"));
|
|
11454
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
11455
|
+
"main [data-chatgpt-search-unit-key][data-chatgpt-search-message-ids]"
|
|
11456
|
+
)).filter((node) => /:(?:user|assistant)$/.test(node.getAttribute("data-chatgpt-search-unit-key") ?? ""));
|
|
11457
|
+
const assistantNodes = nodes.filter((node) => (node.getAttribute("data-message-author-role") ?? node.getAttribute("data-chatgpt-search-unit-key")?.split(":").at(-1)) === "assistant");
|
|
11396
11458
|
const latestAssistant = assistantNodes.at(-1);
|
|
11397
11459
|
const latestAssistantTurnIndex = latestAssistant === void 0 ? void 0 : nodes.indexOf(latestAssistant) + 1;
|
|
11398
|
-
const
|
|
11460
|
+
const content = latestAssistant?.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
11461
|
+
const normalizedText = normalizeWs(content?.innerText || content?.textContent || (latestAssistant?.innerText ?? latestAssistant?.textContent ?? "").replace(latestAssistant?.querySelector?.('[data-conversation-role="assistant"]')?.textContent ?? "", ""));
|
|
11399
11462
|
let hash = 2166136261;
|
|
11400
11463
|
for (let index = 0; index < normalizedText.length; index += 1) {
|
|
11401
11464
|
hash ^= normalizedText.charCodeAt(index);
|
|
@@ -11433,7 +11496,7 @@ async function readWaitDomSnapshot(page) {
|
|
|
11433
11496
|
};
|
|
11434
11497
|
const visibleStopButtons = Array.from(document.querySelectorAll("button")).filter((button) => isVisible(button) && button.disabled !== true && button.getAttribute("aria-disabled") !== "true" && isScopedStopControl(button) && matchingLabels2(button, args.send).length === 0 && matchingLabels2(button, args.stop).length > 0);
|
|
11435
11498
|
const activeSignals = [...new Set(visibleStopButtons.flatMap((button) => matchingLabels2(button, args.stop)))];
|
|
11436
|
-
const latestAssistantTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? Array.from(document.querySelectorAll("[data-testid^='conversation-turn']")).at(-1);
|
|
11499
|
+
const latestAssistantTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? Array.from(document.querySelectorAll("[data-testid^='conversation-turn']")).at(-1) ?? (latestAssistant?.hasAttribute?.("data-chatgpt-search-unit-key") === true ? latestAssistant : void 0);
|
|
11437
11500
|
const stoppedSignals = latestAssistantTurn === void 0 ? [] : [...new Set(Array.from(latestAssistantTurn.querySelectorAll(
|
|
11438
11501
|
"button, [role='status'], [aria-label], [title], p, span, div"
|
|
11439
11502
|
)).filter((element) => isVisible(element)).flatMap((element) => matchingLabels2(element, args.stopped)))];
|
|
@@ -11446,7 +11509,18 @@ async function readWaitDomSnapshot(page) {
|
|
|
11446
11509
|
const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
|
|
11447
11510
|
let hasResponseActions;
|
|
11448
11511
|
if (turns.length === 0) {
|
|
11449
|
-
|
|
11512
|
+
if (latestAssistant?.hasAttribute?.("data-chatgpt-search-unit-key") === true) {
|
|
11513
|
+
hasResponseActions = false;
|
|
11514
|
+
let owner = latestAssistant;
|
|
11515
|
+
for (let depth = 0; owner !== null && depth < 6 && owner.tagName !== "MAIN"; depth += 1, owner = owner.parentElement) {
|
|
11516
|
+
const assistants = Array.from(owner.querySelectorAll('[data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'));
|
|
11517
|
+
if (owner !== latestAssistant && (assistants.length !== 1 || assistants[0] !== latestAssistant)) break;
|
|
11518
|
+
if (Array.from(owner.querySelectorAll("button")).some((button) => args.actions.some((phrase) => [button.getAttribute("aria-label"), button.getAttribute("title"), button.textContent].some((value) => (value ?? "").trim().toLowerCase() === phrase.trim().toLowerCase())))) {
|
|
11519
|
+
hasResponseActions = true;
|
|
11520
|
+
break;
|
|
11521
|
+
}
|
|
11522
|
+
}
|
|
11523
|
+
}
|
|
11450
11524
|
} else {
|
|
11451
11525
|
const latestTurn = [...turns].reverse().find(
|
|
11452
11526
|
(turn) => turn.querySelector("[data-message-author-role='assistant']") !== null
|
|
@@ -13381,7 +13455,7 @@ async function readChatPopover(page) {
|
|
|
13381
13455
|
return current2 === null;
|
|
13382
13456
|
};
|
|
13383
13457
|
const normalize = (value) => value.replace(/\s+/g, " ").trim();
|
|
13384
|
-
const roots = document.querySelectorAll('[data-testid="composer-intelligence-picker-content"]');
|
|
13458
|
+
const roots = Array.from(document.querySelectorAll('[data-testid="composer-intelligence-picker-content"]')).concat(Array.from(document.querySelectorAll("[data-model-picker-view]")));
|
|
13385
13459
|
if (roots.length > 8) return { acted: false };
|
|
13386
13460
|
const activeRoots = Array.from(roots).filter((node) => visible(node));
|
|
13387
13461
|
if (activeRoots.length !== 1) return { acted: false };
|
|
@@ -13397,7 +13471,12 @@ async function readChatPopover(page) {
|
|
|
13397
13471
|
ancestor = ancestor.parentNode;
|
|
13398
13472
|
}
|
|
13399
13473
|
if (menu?.getAttribute("data-state") !== "open" || !visible(menu)) return { acted: false };
|
|
13400
|
-
const
|
|
13474
|
+
const currentProfile = root.hasAttribute("data-model-picker-view");
|
|
13475
|
+
if (currentProfile) {
|
|
13476
|
+
const triggers = Array.from(document.querySelectorAll('button[data-codex-intelligence-trigger="true"]')).filter((trigger) => trigger.getAttribute("id") === menu.getAttribute("aria-labelledby") && trigger.getAttribute("aria-haspopup") === "menu" && trigger.getAttribute("aria-expanded") === "true");
|
|
13477
|
+
if (triggers.length !== 1) return { acted: false };
|
|
13478
|
+
}
|
|
13479
|
+
const nodes = [root];
|
|
13401
13480
|
const text = /* @__PURE__ */ new Map();
|
|
13402
13481
|
let current = root.firstChild;
|
|
13403
13482
|
let count = 0;
|
|
@@ -13431,25 +13510,28 @@ async function readChatPopover(page) {
|
|
|
13431
13510
|
}
|
|
13432
13511
|
return false;
|
|
13433
13512
|
};
|
|
13434
|
-
const owners = nodes.filter((node) => node.getAttribute("data-has-slider") === "true" && node.getAttribute("data-has-advanced-view") === "true" && node.getAttribute("data-model-selection-view") === "true" && visible(node));
|
|
13513
|
+
const owners = currentProfile ? [root] : nodes.filter((node) => node.getAttribute("data-has-slider") === "true" && node.getAttribute("data-has-advanced-view") === "true" && node.getAttribute("data-model-selection-view") === "true" && visible(node));
|
|
13435
13514
|
if (owners.length !== 1) return { acted: false };
|
|
13436
13515
|
const owner = owners[0];
|
|
13437
|
-
const view = owner.getAttribute("data-view");
|
|
13516
|
+
const view = owner.getAttribute(currentProfile ? "data-model-picker-view" : "data-view");
|
|
13438
13517
|
if (view !== "simple" && view !== "advanced") return { acted: false };
|
|
13439
|
-
const panels = nodes.filter((node) => node.getAttribute("data-testid") === `composer-model-picker-slider-${view}-view` && within(node, owner) && node.getAttribute("data-active") === "true" && visible(node));
|
|
13518
|
+
const panels = nodes.filter((node) => (currentProfile ? node.parentNode === owner : node.getAttribute("data-testid") === `composer-model-picker-slider-${view}-view` && within(node, owner)) && node.getAttribute("data-active") === "true" && visible(node));
|
|
13440
13519
|
if (panels.length !== 1) return { acted: false };
|
|
13441
13520
|
const panel = panels[0];
|
|
13442
|
-
const toggles = nodes.filter((node) => node.getAttribute("role") === "menuitem" && node.getAttribute("data-interactive") === "true" && node.getAttribute("aria-expanded") === String(view === "advanced") && within(node, owner) && visible(node));
|
|
13521
|
+
const toggles = nodes.filter((node) => node.getAttribute("role") === "menuitem" && node.getAttribute("data-interactive") === "true" && (currentProfile ? node.getAttribute("data-model-picker-view-toggle") === "true" : node.getAttribute("aria-expanded") === String(view === "advanced")) && within(node, owner) && visible(node));
|
|
13443
13522
|
if (toggles.length > 1 || view === "simple" && toggles.length !== 1) return { acted: false };
|
|
13444
13523
|
const modelNodes = view === "advanced" ? nodes.filter((node) => within(node, panel) && node.getAttribute("role") === "menuitemradio" && visible(node)) : [];
|
|
13445
13524
|
if (modelNodes.length > 32) return { acted: false };
|
|
13446
13525
|
const modelLabel = (node) => {
|
|
13447
|
-
const primary = nodes.filter((child) =>
|
|
13526
|
+
const primary = nodes.filter((child) => {
|
|
13527
|
+
const classes = (child.getAttribute("class") ?? "").split(/\s+/);
|
|
13528
|
+
return within(child, node) && classes.includes("truncate") && !classes.includes("text-xs");
|
|
13529
|
+
});
|
|
13448
13530
|
return normalize(primary.length === 1 ? text.get(primary[0]) ?? "" : text.get(node) ?? "");
|
|
13449
13531
|
};
|
|
13450
13532
|
const snapshot2 = {
|
|
13451
13533
|
view,
|
|
13452
|
-
rootIndex: Array.from(
|
|
13534
|
+
rootIndex: currentProfile ? Array.from(document.querySelectorAll("[data-model-picker-view]")).indexOf(root) : Array.from(document.querySelectorAll('[data-testid="composer-intelligence-picker-content"]')).indexOf(root),
|
|
13453
13535
|
toggleIndex: nodes.filter((node) => node.getAttribute("role") === "menuitem" && node.getAttribute("data-interactive") === "true").indexOf(toggles[0]),
|
|
13454
13536
|
modelOptions: modelNodes.map((node) => ({
|
|
13455
13537
|
label: modelLabel(node),
|
|
@@ -13457,6 +13539,7 @@ async function readChatPopover(page) {
|
|
|
13457
13539
|
index: nodes.filter((row) => within(row, panel) && row.getAttribute("role") === "menuitemradio").indexOf(node)
|
|
13458
13540
|
})).filter((option) => option.label.length > 0)
|
|
13459
13541
|
};
|
|
13542
|
+
if (currentProfile) snapshot2.profile = "model_picker_v2";
|
|
13460
13543
|
const triggerId = menu.getAttribute("aria-labelledby");
|
|
13461
13544
|
if (triggerId !== null && triggerId.length > 0 && triggerId.length < 240 && !/\s/.test(triggerId)) snapshot2.triggerId = triggerId;
|
|
13462
13545
|
const checked = snapshot2.modelOptions.filter((option) => option.checked);
|
|
@@ -13475,7 +13558,7 @@ async function readChatPopover(page) {
|
|
|
13475
13558
|
if (sliders.length === 1) {
|
|
13476
13559
|
const slider = sliders[0];
|
|
13477
13560
|
const powers = nodes.filter((node) => within(slider, node) && within(node, panel) && node.getAttribute("role") === "menuitem" && visible(node) && config.powerLabels.some((label) => normalize(node.getAttribute("aria-label") ?? "").toLocaleLowerCase() === label.toLocaleLowerCase()));
|
|
13478
|
-
const sliderOwners = nodes.filter((node) => within(slider, node) && within(node, panel) && node.hasAttribute("data-model-reasoning-effort-slider"));
|
|
13561
|
+
const sliderOwners = nodes.filter((node) => within(slider, node) && within(node, panel) && node.hasAttribute(currentProfile ? "data-model-picker-power-slider" : "data-model-reasoning-effort-slider"));
|
|
13479
13562
|
const integer = (name) => {
|
|
13480
13563
|
const raw = slider.getAttribute(name);
|
|
13481
13564
|
return raw !== null && /^-?\d+$/.test(raw) && Number.isSafeInteger(Number(raw)) ? Number(raw) : void 0;
|
|
@@ -13504,11 +13587,46 @@ async function readChatPopover(page) {
|
|
|
13504
13587
|
return observation !== void 0 && observation !== null && typeof observation.acted === "boolean" ? observation : { acted: false };
|
|
13505
13588
|
}
|
|
13506
13589
|
function observedRoot(page, snapshot2) {
|
|
13507
|
-
const roots = page.locator?.('[data-testid="composer-intelligence-picker-content"]');
|
|
13590
|
+
const roots = page.locator?.(snapshot2.profile === "model_picker_v2" ? "[data-model-picker-view]" : '[data-testid="composer-intelligence-picker-content"]');
|
|
13508
13591
|
return roots?.nth?.(snapshot2.rootIndex) ?? (snapshot2.rootIndex === 0 ? roots : void 0);
|
|
13509
13592
|
}
|
|
13593
|
+
async function openChatPopover(page) {
|
|
13594
|
+
if ((await readChatPopover(page)).snapshot !== void 0) return true;
|
|
13595
|
+
let trigger = page.locator?.('button[data-codex-intelligence-trigger="true"][aria-haspopup="menu"]');
|
|
13596
|
+
let count = await trigger?.count?.().catch(() => 0) ?? 0;
|
|
13597
|
+
if (count === 0) return void 0;
|
|
13598
|
+
if (count > 1 && count <= 8 && typeof trigger?.filter === "function") {
|
|
13599
|
+
trigger = trigger.filter({ visible: true });
|
|
13600
|
+
count = await trigger.count?.().catch(() => 0) ?? 0;
|
|
13601
|
+
}
|
|
13602
|
+
if (count !== 1) return false;
|
|
13603
|
+
if (trigger?.click === void 0 || trigger.evaluate === void 0) return void 0;
|
|
13604
|
+
const actionable = await trigger.evaluate((element) => {
|
|
13605
|
+
if (element.tagName !== "BUTTON" || element.getAttribute("data-codex-intelligence-trigger") !== "true" || element.getAttribute("aria-haspopup") !== "menu") return void 0;
|
|
13606
|
+
let current = element;
|
|
13607
|
+
for (let depth = 0; current !== null && depth < 64; depth += 1) {
|
|
13608
|
+
if (current.nodeType !== 1) break;
|
|
13609
|
+
const node = current;
|
|
13610
|
+
if (node.hidden || node.hasAttribute("hidden") || node.hasAttribute("inert") || node.disabled || node.getAttribute("aria-hidden") === "true" || node.getAttribute("aria-disabled") === "true") return false;
|
|
13611
|
+
const style = window.getComputedStyle(node);
|
|
13612
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" || current === element && style.pointerEvents === "none") return false;
|
|
13613
|
+
current = current.parentNode;
|
|
13614
|
+
}
|
|
13615
|
+
if (current?.nodeType === 1) return false;
|
|
13616
|
+
const rect = element.getBoundingClientRect();
|
|
13617
|
+
return rect.width > 0 && rect.height > 0 && element.getAttribute("aria-expanded") === "false";
|
|
13618
|
+
}).catch(() => void 0);
|
|
13619
|
+
if (actionable === void 0) return void 0;
|
|
13620
|
+
if (!actionable) return false;
|
|
13621
|
+
await trigger.click();
|
|
13622
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
13623
|
+
await waitForPopoverTransition(page, 100);
|
|
13624
|
+
if ((await readChatPopover(page)).snapshot !== void 0) return true;
|
|
13625
|
+
}
|
|
13626
|
+
return false;
|
|
13627
|
+
}
|
|
13510
13628
|
async function clickObservedControl(page, snapshot2, modelIndex) {
|
|
13511
|
-
const selector = modelIndex === void 0 ? '[role="menuitem"][data-interactive="true"]' : '[data-testid="composer-model-picker-slider-advanced-view"][data-active="true"] [role="menuitemradio"]';
|
|
13629
|
+
const selector = modelIndex === void 0 ? '[role="menuitem"][data-interactive="true"]' : snapshot2.profile === "model_picker_v2" ? ':scope > [data-active="true"] [role="menuitemradio"]' : '[data-testid="composer-model-picker-slider-advanced-view"][data-active="true"] [role="menuitemradio"]';
|
|
13512
13630
|
const candidates = observedRoot(page, snapshot2)?.locator?.(selector);
|
|
13513
13631
|
const index = modelIndex ?? snapshot2.toggleIndex;
|
|
13514
13632
|
const target = candidates?.nth?.(index) ?? (index === 0 ? candidates : void 0);
|
|
@@ -13522,7 +13640,7 @@ async function clickObservedControl(page, snapshot2, modelIndex) {
|
|
|
13522
13640
|
if (node.hidden || node.hasAttribute("hidden") || node.hasAttribute("inert") || node.getAttribute("aria-hidden") === "true" || node.getAttribute("aria-disabled") === "true" || node.getAttribute("data-active") === "false") return void 0;
|
|
13523
13641
|
const style = window.getComputedStyle(node);
|
|
13524
13642
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" || style.pointerEvents === "none") return void 0;
|
|
13525
|
-
if (node.getAttribute("data-testid") === "composer-intelligence-picker-content") owned = true;
|
|
13643
|
+
if (node.getAttribute("data-testid") === "composer-intelligence-picker-content" || node.getAttribute("data-model-picker-view") === "simple" || node.getAttribute("data-model-picker-view") === "advanced") owned = true;
|
|
13526
13644
|
current = current.parentNode;
|
|
13527
13645
|
}
|
|
13528
13646
|
const rect = element.getBoundingClientRect();
|
|
@@ -13538,7 +13656,8 @@ async function clickObservedControl(page, snapshot2, modelIndex) {
|
|
|
13538
13656
|
if (label.length > 512) return void 0;
|
|
13539
13657
|
let parent = child.parentNode;
|
|
13540
13658
|
for (let depth = 0; parent !== null && parent !== element && depth < 64; depth += 1) {
|
|
13541
|
-
|
|
13659
|
+
const classes = parent.nodeType === 1 ? (parent.getAttribute("class") ?? "").split(/\s+/) : [];
|
|
13660
|
+
if (classes.includes("truncate") && !classes.includes("text-xs")) {
|
|
13542
13661
|
primary.set(parent, (primary.get(parent) ?? "") + (child.nodeValue ?? ""));
|
|
13543
13662
|
}
|
|
13544
13663
|
parent = parent.parentNode;
|
|
@@ -13552,9 +13671,9 @@ async function clickObservedControl(page, snapshot2, modelIndex) {
|
|
|
13552
13671
|
if (child === element || child === null) break;
|
|
13553
13672
|
child = child.nextSibling;
|
|
13554
13673
|
}
|
|
13555
|
-
return { role: element.getAttribute("role"), expanded: element.getAttribute("aria-expanded"), label: (primary.size === 1 ? [...primary.values()][0] : label).replace(/\s+/g, " ").trim() };
|
|
13674
|
+
return { role: element.getAttribute("role"), expanded: element.getAttribute("aria-expanded"), viewToggle: element.getAttribute("data-model-picker-view-toggle"), label: (primary.size === 1 ? [...primary.values()][0] : label).replace(/\s+/g, " ").trim() };
|
|
13556
13675
|
}).catch(() => void 0);
|
|
13557
|
-
if (state === void 0 || state.role !== (modelIndex === void 0 ? "menuitem" : "menuitemradio") || modelIndex === void 0 && state.expanded !== String(snapshot2.view === "advanced")) return false;
|
|
13676
|
+
if (state === void 0 || state.role !== (modelIndex === void 0 ? "menuitem" : "menuitemradio") || modelIndex === void 0 && (snapshot2.profile === "model_picker_v2" ? state.viewToggle !== "true" : state.expanded !== String(snapshot2.view === "advanced"))) return false;
|
|
13558
13677
|
const expectedModel = snapshot2.modelOptions.find((option) => option.index === modelIndex);
|
|
13559
13678
|
if (modelIndex !== void 0 && (expectedModel === void 0 || state.label !== expectedModel.label)) return false;
|
|
13560
13679
|
await target.click();
|
|
@@ -13565,9 +13684,9 @@ async function closeChatPopover(page, before) {
|
|
|
13565
13684
|
if (snapshot2 === void 0) return false;
|
|
13566
13685
|
const escapedId = snapshot2.triggerId?.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
13567
13686
|
const menu = escapedId === void 0 ? void 0 : page.locator?.(`[role="menu"][aria-labelledby="${escapedId}"]`);
|
|
13568
|
-
if (
|
|
13569
|
-
else if (page.keyboard?.press !== void 0) await page.keyboard.press("Escape");
|
|
13687
|
+
if (page.keyboard?.press !== void 0) await page.keyboard.press("Escape");
|
|
13570
13688
|
else if (page.cua?.keypress !== void 0) await page.cua.keypress({ keys: ["ESC"] });
|
|
13689
|
+
else if (menu?.press !== void 0 && await menu.count?.() === 1) await menu.press("Escape");
|
|
13571
13690
|
else return false;
|
|
13572
13691
|
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
13573
13692
|
await waitForPopoverTransition(page, 100);
|
|
@@ -13582,6 +13701,7 @@ async function waitForPopoverTransition(page, milliseconds) {
|
|
|
13582
13701
|
async function reopenChatPopover(page, before) {
|
|
13583
13702
|
if (before.triggerId === void 0) return void 0;
|
|
13584
13703
|
if (!await closeChatPopover(page, before)) return void 0;
|
|
13704
|
+
if (before.profile === "model_picker_v2") await waitForPopoverTransition(page, 250);
|
|
13585
13705
|
const trigger = page.locator?.(`[id="${before.triggerId.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"]`);
|
|
13586
13706
|
if (trigger?.click === void 0 || trigger.evaluate === void 0 || await trigger.count?.() !== 1) return void 0;
|
|
13587
13707
|
const isVisible = () => trigger.evaluate((element) => {
|
|
@@ -13678,7 +13798,7 @@ async function selectChatPopoverEffort(page, labels) {
|
|
|
13678
13798
|
return void 0;
|
|
13679
13799
|
}
|
|
13680
13800
|
if (before.slider.current === target) return before;
|
|
13681
|
-
const candidates = observedRoot(page, before)?.locator?.('[data-testid="composer-model-picker-slider-simple-view"][data-active="true"] [role="slider"]');
|
|
13801
|
+
const candidates = observedRoot(page, before)?.locator?.(before.profile === "model_picker_v2" ? ':scope > [data-active="true"] [role="slider"]' : '[data-testid="composer-model-picker-slider-simple-view"][data-active="true"] [role="slider"]');
|
|
13682
13802
|
const locator = candidates?.nth?.(before.slider.index) ?? (before.slider.index === 0 ? candidates : void 0);
|
|
13683
13803
|
if (locator?.press === void 0 || locator.evaluate === void 0 || await locator.count?.() !== 1) return void 0;
|
|
13684
13804
|
const locatorState = await locator.evaluate((element) => {
|
|
@@ -13692,6 +13812,12 @@ async function selectChatPopoverEffort(page, labels) {
|
|
|
13692
13812
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" || style.pointerEvents === "none") return void 0;
|
|
13693
13813
|
if (node.getAttribute("data-testid") === "composer-model-picker-slider-simple-view" && node.getAttribute("data-active") === "true") panel = true;
|
|
13694
13814
|
if (node.getAttribute("data-testid") === "composer-intelligence-picker-content") owned = true;
|
|
13815
|
+
if (node.getAttribute("data-model-picker-view") === "simple") {
|
|
13816
|
+
owned = true;
|
|
13817
|
+
let track = element;
|
|
13818
|
+
while (track !== null && track.parentNode !== node) track = track.parentNode;
|
|
13819
|
+
if (track?.nodeType === 1 && track.getAttribute("data-active") === "true") panel = true;
|
|
13820
|
+
}
|
|
13695
13821
|
current = current.parentNode;
|
|
13696
13822
|
}
|
|
13697
13823
|
const rect = element.getBoundingClientRect();
|
|
@@ -14032,7 +14158,8 @@ async function getMode(env, args = {}) {
|
|
|
14032
14158
|
}
|
|
14033
14159
|
const page = env.page;
|
|
14034
14160
|
try {
|
|
14035
|
-
const
|
|
14161
|
+
const popover = (await readChatPopover(page)).snapshot;
|
|
14162
|
+
const modes = popover?.effort === void 0 ? await visibleModeButtonLabelList(page) : [popover.effort];
|
|
14036
14163
|
const warnings = modes.length === 0 ? ["No mode-labelled composer control is currently visible, so the active ChatGPT mode could not be read."] : [];
|
|
14037
14164
|
return resultOk({ modes }, await contextFromPage(page), warnings);
|
|
14038
14165
|
} catch (error) {
|
|
@@ -14119,6 +14246,8 @@ async function clickFirstUniqueButton(page, labels) {
|
|
|
14119
14246
|
return false;
|
|
14120
14247
|
}
|
|
14121
14248
|
async function clickModeOpener(page, modeButtons) {
|
|
14249
|
+
const currentPicker = await openChatPopover(page);
|
|
14250
|
+
if (currentPicker !== void 0) return currentPicker;
|
|
14122
14251
|
if (await clickFirstUniqueButton(page, modeButtons)) {
|
|
14123
14252
|
return true;
|
|
14124
14253
|
}
|
|
@@ -14846,8 +14975,13 @@ async function readSurfaceSnapshot(page) {
|
|
|
14846
14975
|
};
|
|
14847
14976
|
const normalize = (value) => value.replace(/\s+/g, " ").trim();
|
|
14848
14977
|
const normalizeComparable = (value) => normalize(value).toLocaleLowerCase();
|
|
14849
|
-
const
|
|
14850
|
-
const
|
|
14978
|
+
const chatSurfaceLabels = new Set(surfaceOptionLabels.chat.map(normalizeComparable));
|
|
14979
|
+
const workSurfaceLabels = new Set(surfaceOptionLabels.work.map(normalizeComparable));
|
|
14980
|
+
const wantedSurfaceLabels = /* @__PURE__ */ new Set([...chatSurfaceLabels, ...workSurfaceLabels]);
|
|
14981
|
+
const currentComposerRoots = Array.from(document.querySelectorAll(
|
|
14982
|
+
'main form[data-thread-find-composer="true"]'
|
|
14983
|
+
)).filter(visible);
|
|
14984
|
+
const composerRoots = currentComposerRoots.length > 0 ? currentComposerRoots : Array.from(document.querySelectorAll(
|
|
14851
14985
|
"main form, main [data-testid*='composer' i], main [class*='composer' i]"
|
|
14852
14986
|
)).filter(visible);
|
|
14853
14987
|
const main = document.querySelector("main");
|
|
@@ -14894,9 +15028,19 @@ async function readSurfaceSnapshot(page) {
|
|
|
14894
15028
|
"h1, h2, h3, form, [data-testid*='composer' i], [class*='composer' i]"
|
|
14895
15029
|
)).filter(visible).slice(0, 32);
|
|
14896
15030
|
const mainText = normalize(surfaceTextNodes.map(labelFor).join(" ")).slice(0, 2e3);
|
|
14897
|
-
const
|
|
15031
|
+
const selectedRadioLabels = Array.from(document.querySelectorAll(
|
|
14898
15032
|
"[role='radio'][aria-checked='true'], [role='radio'][data-state='checked'], input[type='radio']:checked"
|
|
14899
|
-
)).filter(visible).map(labelFor).map(normalize).filter((label) => wantedSurfaceLabels.has(normalizeComparable(label)))
|
|
15033
|
+
)).filter(visible).map(labelFor).map(normalize).filter((label) => wantedSurfaceLabels.has(normalizeComparable(label)));
|
|
15034
|
+
const pressedGroups = Array.from(document.querySelectorAll("main [role='group']")).filter(visible).filter((group) => {
|
|
15035
|
+
let ancestor = group;
|
|
15036
|
+
for (let depth = 0; ancestor !== null && depth < 64; depth += 1) {
|
|
15037
|
+
if (ancestor.hasAttribute("data-message-author-role") || ancestor.tagName === "ARTICLE" || ["dialog", "menu", "listbox"].includes(ancestor.getAttribute("role") ?? "")) return false;
|
|
15038
|
+
ancestor = ancestor.parentElement;
|
|
15039
|
+
}
|
|
15040
|
+
return ancestor === null;
|
|
15041
|
+
}).map((group) => Array.from(group.querySelectorAll("button[aria-pressed]")).filter((button) => button.parentElement === group && visible(button) && button.getAttribute("disabled") === null && button.getAttribute("aria-disabled") !== "true")).filter((buttons) => buttons.length === 2 && new Set(buttons.map((button) => normalizeComparable(labelFor(button)))).size === 2 && buttons.every((button) => wantedSurfaceLabels.has(normalizeComparable(labelFor(button))) && ["true", "false"].includes(button.getAttribute("aria-pressed") ?? "")) && buttons.filter((button) => chatSurfaceLabels.has(normalizeComparable(labelFor(button)))).length === 1 && buttons.filter((button) => workSurfaceLabels.has(normalizeComparable(labelFor(button)))).length === 1 && buttons.filter((button) => button.getAttribute("aria-pressed") === "true").length === 1);
|
|
15042
|
+
const selectedButtonLabels = pressedGroups.length === 1 ? pressedGroups[0].filter((button) => button.getAttribute("aria-pressed") === "true").map(labelFor).map(normalize) : [];
|
|
15043
|
+
const selectedSurfaceLabels = Array.from(/* @__PURE__ */ new Set([...selectedRadioLabels, ...selectedButtonLabels])).slice(0, 4);
|
|
14900
15044
|
const workPopoverOpen = Array.from(document.querySelectorAll(
|
|
14901
15045
|
'[data-testid="composer-intelligence-picker-content"]'
|
|
14902
15046
|
)).filter(visible).some((root) => {
|
|
@@ -14907,10 +15051,10 @@ async function readSurfaceSnapshot(page) {
|
|
|
14907
15051
|
return speed.length === 1 && sliders.length === 1;
|
|
14908
15052
|
});
|
|
14909
15053
|
return { composerLabels, mainControls, composerControls, controlGroups, mainText, selectedSurfaceLabels, workPopoverOpen };
|
|
14910
|
-
},
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
15054
|
+
}, {
|
|
15055
|
+
chat: localeLabels.experienceOptions.chat,
|
|
15056
|
+
work: localeLabels.experienceOptions.work
|
|
15057
|
+
}).catch(() => ({ composerLabels: [], mainControls: [], mainText: "", selectedSurfaceLabels: [] }));
|
|
14914
15058
|
return { url, ...snapshot2 };
|
|
14915
15059
|
}
|
|
14916
15060
|
function profileFromSnapshot(snapshot2, experience) {
|
|
@@ -15561,6 +15705,10 @@ async function selectChatAxis(env, axis, requested, timeoutMs) {
|
|
|
15561
15705
|
}
|
|
15562
15706
|
async function openConfigurationRoot(page, experience) {
|
|
15563
15707
|
if (experience !== "unknown" && (await readChatPopover(page)).snapshot !== void 0) return true;
|
|
15708
|
+
if (experience !== "unknown") {
|
|
15709
|
+
const currentPicker = await openChatPopover(page);
|
|
15710
|
+
if (currentPicker !== void 0) return currentPicker;
|
|
15711
|
+
}
|
|
15564
15712
|
const existing = await readConfigurationPanel(page);
|
|
15565
15713
|
if (existing.axisRows.length > 0) {
|
|
15566
15714
|
return true;
|