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
|
@@ -215,10 +215,10 @@ function classifyVisibleText(text) {
|
|
|
215
215
|
var en = {
|
|
216
216
|
// --- Primary interaction path (accessible names) ---
|
|
217
217
|
composerTextbox: ["Chat with ChatGPT", "Ask ChatGPT"],
|
|
218
|
-
workComposerTextbox: ["Work on anything", "Work on something"],
|
|
218
|
+
workComposerTextbox: ["Work on anything", "Work on something", "Work with ChatGPT"],
|
|
219
219
|
projectComposerPrefixes: ["New chat in"],
|
|
220
220
|
newWork: ["Work on something else", "New work", "New task"],
|
|
221
|
-
sendButton: ["Send prompt"],
|
|
221
|
+
sendButton: ["Send prompt", "Send"],
|
|
222
222
|
searchChatsButton: ["Search chats"],
|
|
223
223
|
searchChatsPlaceholder: ["Search chats..."],
|
|
224
224
|
newChat: ["New chat"],
|
|
@@ -291,7 +291,7 @@ var en = {
|
|
|
291
291
|
/** Exact-match transient assistant placeholders filtered out of captured responses. */
|
|
292
292
|
transientAssistant: ["thinking", "reasoning", "searching", "searching the web"],
|
|
293
293
|
/** Streaming "stop" control text, matched while a response generates. */
|
|
294
|
-
stopControl: ["stop generating", "stop streaming", "stop answering"],
|
|
294
|
+
stopControl: ["stop generating", "stop streaming", "stop answering", "stop"],
|
|
295
295
|
/** Interrupted generation markers shown after the assistant stops before completion. */
|
|
296
296
|
stoppedAssistant: ["stopped thinking", "stopped answering", "generation stopped"],
|
|
297
297
|
/** Response-action affordance text (fallback to the structural copy-button locator). */
|
|
@@ -6433,6 +6433,13 @@ function normalizePage(pageOrTab) {
|
|
|
6433
6433
|
const value = providerValue(primary, property) ?? providerValue(maybe, property);
|
|
6434
6434
|
if (isProviderRecord(value)) normalized[property] = value;
|
|
6435
6435
|
}
|
|
6436
|
+
const rawAx = providerValue(maybe, "ax");
|
|
6437
|
+
if (normalized.keyboard === void 0 && isProviderRecord(rawAx)) {
|
|
6438
|
+
const pressKey = providerCallable(rawAx, "pressKey");
|
|
6439
|
+
if (pressKey !== void 0) normalized.keyboard = { press: async (key) => {
|
|
6440
|
+
await pressKey(null, key);
|
|
6441
|
+
} };
|
|
6442
|
+
}
|
|
6436
6443
|
if (isProviderRecord(embedded)) normalized.playwright = embedded;
|
|
6437
6444
|
for (const method of [
|
|
6438
6445
|
"url",
|
|
@@ -6889,10 +6896,19 @@ function extractRoleMessageHtml(html) {
|
|
|
6889
6896
|
const root = parseHtmlFragment(html);
|
|
6890
6897
|
const messages = [];
|
|
6891
6898
|
walkElementsWithAncestors(root, [], (element, ancestors) => {
|
|
6892
|
-
const
|
|
6899
|
+
const current = element.attrs["data-message-author-role"] === void 0 && element.attrs["data-chatgpt-search-message-ids"] !== void 0;
|
|
6900
|
+
if (current && !ancestors.some((ancestor) => ancestor.tag === "main")) return;
|
|
6901
|
+
const role = element.attrs["data-message-author-role"] ?? (current ? element.attrs["data-chatgpt-search-unit-key"]?.split(":").at(-1) : void 0);
|
|
6893
6902
|
if (role === "user" || role === "assistant") {
|
|
6894
6903
|
const metadataElement = [...ancestors].reverse().find((ancestor) => ancestor.attrs["data-testid"]?.startsWith("conversation-turn")) ?? element;
|
|
6895
|
-
|
|
6904
|
+
let content = element;
|
|
6905
|
+
if (current) {
|
|
6906
|
+
walkElements(element, (child) => {
|
|
6907
|
+
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;
|
|
6908
|
+
});
|
|
6909
|
+
}
|
|
6910
|
+
const messageHtml = serializeChildren(content).replace(/<h4\b[^>]*data-conversation-role=["']assistant["'][^>]*>[\s\S]*?<\/h4>/i, "");
|
|
6911
|
+
messages.push({ role, html: messageHtml, metadataHtml: serializeNode(metadataElement) });
|
|
6896
6912
|
}
|
|
6897
6913
|
});
|
|
6898
6914
|
return messages;
|
|
@@ -7427,15 +7443,19 @@ function extractMessagesFromHtml(html, args = {}) {
|
|
|
7427
7443
|
async function readMessages(page, args = {}) {
|
|
7428
7444
|
if (typeof page.evaluate === "function") {
|
|
7429
7445
|
const messages = await page.evaluate(() => {
|
|
7430
|
-
const
|
|
7446
|
+
const legacy = Array.from(document.querySelectorAll("[data-message-author-role]"));
|
|
7447
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
7448
|
+
"main [data-chatgpt-search-unit-key][data-chatgpt-search-message-ids]"
|
|
7449
|
+
));
|
|
7431
7450
|
return nodes.map((node) => {
|
|
7432
|
-
const role = node.getAttribute("data-message-author-role");
|
|
7451
|
+
const role = node.getAttribute("data-message-author-role") ?? node.getAttribute("data-chatgpt-search-unit-key")?.split(":").at(-1);
|
|
7433
7452
|
if (role !== "user" && role !== "assistant") {
|
|
7434
7453
|
return void 0;
|
|
7435
7454
|
}
|
|
7455
|
+
const content = role === "user" ? node.querySelector?.('[data-user-message-bubble="true"]') : node.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
7436
7456
|
return {
|
|
7437
7457
|
role,
|
|
7438
|
-
html: node.innerHTML,
|
|
7458
|
+
html: content?.innerHTML || node.innerHTML.replace(/<h4\b[^>]*data-conversation-role=["']assistant["'][^>]*>[\s\S]*?<\/h4>/i, ""),
|
|
7439
7459
|
metadataHtml: node.closest("[data-testid^='conversation-turn']")?.outerHTML ?? node.outerHTML
|
|
7440
7460
|
};
|
|
7441
7461
|
}).filter(Boolean);
|
|
@@ -7451,12 +7471,16 @@ async function readMessages(page, args = {}) {
|
|
|
7451
7471
|
async function readLatestMessage(page, role = "assistant", format = "markdown", maxChars) {
|
|
7452
7472
|
if (typeof page.evaluate === "function") {
|
|
7453
7473
|
const message = await page.evaluate((wantedRole) => {
|
|
7454
|
-
const
|
|
7474
|
+
const legacy = Array.from(document.querySelectorAll(`[data-message-author-role="${wantedRole}"]`));
|
|
7475
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
7476
|
+
`main [data-chatgpt-search-unit-key$=":${wantedRole}"][data-chatgpt-search-message-ids]`
|
|
7477
|
+
));
|
|
7455
7478
|
const node = nodes.at(-1);
|
|
7456
7479
|
if (node === void 0) return void 0;
|
|
7480
|
+
const content = wantedRole === "user" ? node.querySelector?.('[data-user-message-bubble="true"]') : node.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
7457
7481
|
return {
|
|
7458
7482
|
role: wantedRole,
|
|
7459
|
-
html: node.innerHTML,
|
|
7483
|
+
html: content?.innerHTML || node.innerHTML.replace(/<h4\b[^>]*data-conversation-role=["']assistant["'][^>]*>[\s\S]*?<\/h4>/i, ""),
|
|
7460
7484
|
metadataHtml: node.closest("[data-testid^='conversation-turn']")?.outerHTML ?? node.outerHTML
|
|
7461
7485
|
};
|
|
7462
7486
|
}, role).catch(() => void 0);
|
|
@@ -7475,9 +7499,15 @@ async function readLatestMessage(page, role = "assistant", format = "markdown",
|
|
|
7475
7499
|
async function readLatestMessageText(page, role = "assistant") {
|
|
7476
7500
|
if (typeof page.evaluate === "function") {
|
|
7477
7501
|
return page.evaluate((wantedRole) => {
|
|
7478
|
-
const
|
|
7502
|
+
const legacy = Array.from(document.querySelectorAll(`[data-message-author-role="${wantedRole}"]`));
|
|
7503
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
7504
|
+
`main [data-chatgpt-search-unit-key$=":${wantedRole}"][data-chatgpt-search-message-ids]`
|
|
7505
|
+
));
|
|
7479
7506
|
const node = nodes.at(-1);
|
|
7480
|
-
return node?.innerText ?? node?.textContent ?? void 0;
|
|
7507
|
+
if (node?.getAttribute("data-chatgpt-search-unit-key") === null) return node?.innerText ?? node?.textContent ?? void 0;
|
|
7508
|
+
if (node === void 0) return void 0;
|
|
7509
|
+
const content = wantedRole === "user" ? node.querySelector?.('[data-user-message-bubble="true"]') : node.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
7510
|
+
return content?.innerText || content?.textContent || (node.innerText ?? node.textContent ?? "").replace(node.querySelector?.('[data-conversation-role="assistant"]')?.textContent ?? "", "").trim();
|
|
7481
7511
|
}, role).catch(() => void 0);
|
|
7482
7512
|
}
|
|
7483
7513
|
return readLatestMessage(page, role, "normalized_text").then((message) => message?.text).catch(() => void 0);
|
|
@@ -7485,10 +7515,14 @@ async function readLatestMessageText(page, role = "assistant") {
|
|
|
7485
7515
|
async function readLatestMessageTextSnapshot(page, role) {
|
|
7486
7516
|
if (typeof page.evaluate === "function") {
|
|
7487
7517
|
return page.evaluate((wantedRole) => {
|
|
7488
|
-
const
|
|
7489
|
-
const
|
|
7518
|
+
const legacy = Array.from(document.querySelectorAll("[data-message-author-role]"));
|
|
7519
|
+
const allNodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
7520
|
+
"main [data-chatgpt-search-unit-key][data-chatgpt-search-message-ids]"
|
|
7521
|
+
)).filter((node) => /:(?:user|assistant)$/.test(node.getAttribute("data-chatgpt-search-unit-key") ?? ""));
|
|
7522
|
+
const roleNodes = allNodes.filter((node) => (node.getAttribute("data-message-author-role") ?? node.getAttribute("data-chatgpt-search-unit-key")?.split(":").at(-1)) === wantedRole);
|
|
7490
7523
|
const latest = roleNodes.at(-1);
|
|
7491
|
-
const
|
|
7524
|
+
const content = wantedRole === "user" ? latest?.querySelector?.('[data-user-message-bubble="true"]') : latest?.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
7525
|
+
const latestText2 = content?.innerText || content?.textContent || (latest === void 0 ? void 0 : (latest.innerText ?? latest.textContent ?? "").replace(latest.querySelector?.('[data-conversation-role="assistant"]')?.textContent ?? "", "").trim());
|
|
7492
7526
|
const snapshot2 = { turnCount: allNodes.length };
|
|
7493
7527
|
if (latestText2 !== void 0) snapshot2.latestText = latestText2;
|
|
7494
7528
|
return snapshot2;
|
|
@@ -7512,7 +7546,10 @@ async function countPageMessages(page, role) {
|
|
|
7512
7546
|
if (typeof page.evaluate === "function") {
|
|
7513
7547
|
return page.evaluate((wantedRole) => {
|
|
7514
7548
|
const selector = wantedRole === void 0 ? "[data-message-author-role]" : `[data-message-author-role="${wantedRole}"]`;
|
|
7515
|
-
|
|
7549
|
+
const legacyCount = document.querySelectorAll(selector).length;
|
|
7550
|
+
if (legacyCount > 0) return legacyCount;
|
|
7551
|
+
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]`;
|
|
7552
|
+
return document.querySelectorAll(currentSelector).length;
|
|
7516
7553
|
}, role);
|
|
7517
7554
|
}
|
|
7518
7555
|
return countMessages(await readMessages(page), role);
|
|
@@ -7720,8 +7757,9 @@ var generatedArtifactDownloadClauses = [
|
|
|
7720
7757
|
];
|
|
7721
7758
|
var cssSelectors = {
|
|
7722
7759
|
assistantMessages: "[data-message-author-role='assistant']",
|
|
7723
|
-
|
|
7724
|
-
|
|
7760
|
+
currentAssistantMessages: "main [data-chatgpt-search-unit-key$=':assistant'][data-chatgpt-search-message-ids]",
|
|
7761
|
+
userMessages: "[data-message-author-role='user'], main [data-chatgpt-search-unit-key$=':user'][data-chatgpt-search-message-ids]",
|
|
7762
|
+
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]",
|
|
7725
7763
|
conversationTurns: "[data-testid^='conversation-turn']",
|
|
7726
7764
|
hiddenFileInputs: "input[type='file']",
|
|
7727
7765
|
downloadControls: downloadControlClauses.join(", "),
|
|
@@ -8758,8 +8796,11 @@ async function readAssistantGenerationState(page, options = {}) {
|
|
|
8758
8796
|
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);
|
|
8759
8797
|
const activeSignals = [...new Set(visibleStopButtons.flatMap((button) => matchingLabels2(button, args.stop)))];
|
|
8760
8798
|
const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
|
|
8761
|
-
const
|
|
8762
|
-
const
|
|
8799
|
+
const legacyAssistants = Array.from(document.querySelectorAll("[data-message-author-role='assistant']"));
|
|
8800
|
+
const latestAssistant = (legacyAssistants.length > 0 ? legacyAssistants : Array.from(document.querySelectorAll(
|
|
8801
|
+
'main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'
|
|
8802
|
+
))).at(-1);
|
|
8803
|
+
const latestTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? turns.at(-1) ?? (latestAssistant?.hasAttribute?.("data-chatgpt-search-unit-key") === true ? latestAssistant : void 0);
|
|
8763
8804
|
const stoppedSignals = latestTurn === void 0 ? [] : [...new Set(Array.from(latestTurn.querySelectorAll(
|
|
8764
8805
|
"button, [role='status'], [aria-label], [title], p, span, div"
|
|
8765
8806
|
)).filter((element) => isVisible(element)).flatMap((element) => matchingLabels2(element, args.stopped)))];
|
|
@@ -8797,7 +8838,17 @@ async function latestAssistantTurnHasResponseActions(page) {
|
|
|
8797
8838
|
if (typeof page.evaluate === "function") {
|
|
8798
8839
|
const scoped = await page.evaluate((phrases) => {
|
|
8799
8840
|
const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
|
|
8800
|
-
if (turns.length === 0)
|
|
8841
|
+
if (turns.length === 0) {
|
|
8842
|
+
const latest = Array.from(document.querySelectorAll('main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]')).at(-1);
|
|
8843
|
+
if (latest === void 0) return void 0;
|
|
8844
|
+
let owner = latest;
|
|
8845
|
+
for (let depth = 0; owner !== null && depth < 6 && owner.tagName !== "MAIN"; depth += 1, owner = owner.parentElement) {
|
|
8846
|
+
const assistants = Array.from(owner.querySelectorAll('[data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'));
|
|
8847
|
+
if (owner !== latest && (assistants.length !== 1 || assistants[0] !== latest)) break;
|
|
8848
|
+
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;
|
|
8849
|
+
}
|
|
8850
|
+
return false;
|
|
8851
|
+
}
|
|
8801
8852
|
const latestTurn = turns.reverse().find(
|
|
8802
8853
|
(turn) => turn.querySelector("[data-message-author-role='assistant']") !== null
|
|
8803
8854
|
);
|
|
@@ -8967,11 +9018,15 @@ async function readWaitDomSnapshot(page) {
|
|
|
8967
9018
|
void __combinedWaitSnapshot;
|
|
8968
9019
|
const normalizeWs = (value) => value.replace(/\s+/g, " ").trim();
|
|
8969
9020
|
const normalizeLower = (value) => (value ?? "").trim().toLowerCase();
|
|
8970
|
-
const
|
|
8971
|
-
const
|
|
9021
|
+
const legacy = Array.from(document.querySelectorAll("[data-message-author-role]"));
|
|
9022
|
+
const nodes = legacy.length > 0 ? legacy : Array.from(document.querySelectorAll(
|
|
9023
|
+
"main [data-chatgpt-search-unit-key][data-chatgpt-search-message-ids]"
|
|
9024
|
+
)).filter((node) => /:(?:user|assistant)$/.test(node.getAttribute("data-chatgpt-search-unit-key") ?? ""));
|
|
9025
|
+
const assistantNodes = nodes.filter((node) => (node.getAttribute("data-message-author-role") ?? node.getAttribute("data-chatgpt-search-unit-key")?.split(":").at(-1)) === "assistant");
|
|
8972
9026
|
const latestAssistant = assistantNodes.at(-1);
|
|
8973
9027
|
const latestAssistantTurnIndex = latestAssistant === void 0 ? void 0 : nodes.indexOf(latestAssistant) + 1;
|
|
8974
|
-
const
|
|
9028
|
+
const content = latestAssistant?.querySelector?.('[data-markdown-text-style="assistant-message"]');
|
|
9029
|
+
const normalizedText = normalizeWs(content?.innerText || content?.textContent || (latestAssistant?.innerText ?? latestAssistant?.textContent ?? "").replace(latestAssistant?.querySelector?.('[data-conversation-role="assistant"]')?.textContent ?? "", ""));
|
|
8975
9030
|
let hash = 2166136261;
|
|
8976
9031
|
for (let index = 0; index < normalizedText.length; index += 1) {
|
|
8977
9032
|
hash ^= normalizedText.charCodeAt(index);
|
|
@@ -9009,7 +9064,7 @@ async function readWaitDomSnapshot(page) {
|
|
|
9009
9064
|
};
|
|
9010
9065
|
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);
|
|
9011
9066
|
const activeSignals = [...new Set(visibleStopButtons.flatMap((button) => matchingLabels2(button, args.stop)))];
|
|
9012
|
-
const latestAssistantTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? Array.from(document.querySelectorAll("[data-testid^='conversation-turn']")).at(-1);
|
|
9067
|
+
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);
|
|
9013
9068
|
const stoppedSignals = latestAssistantTurn === void 0 ? [] : [...new Set(Array.from(latestAssistantTurn.querySelectorAll(
|
|
9014
9069
|
"button, [role='status'], [aria-label], [title], p, span, div"
|
|
9015
9070
|
)).filter((element) => isVisible(element)).flatMap((element) => matchingLabels2(element, args.stopped)))];
|
|
@@ -9022,7 +9077,18 @@ async function readWaitDomSnapshot(page) {
|
|
|
9022
9077
|
const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
|
|
9023
9078
|
let hasResponseActions;
|
|
9024
9079
|
if (turns.length === 0) {
|
|
9025
|
-
|
|
9080
|
+
if (latestAssistant?.hasAttribute?.("data-chatgpt-search-unit-key") === true) {
|
|
9081
|
+
hasResponseActions = false;
|
|
9082
|
+
let owner = latestAssistant;
|
|
9083
|
+
for (let depth = 0; owner !== null && depth < 6 && owner.tagName !== "MAIN"; depth += 1, owner = owner.parentElement) {
|
|
9084
|
+
const assistants = Array.from(owner.querySelectorAll('[data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'));
|
|
9085
|
+
if (owner !== latestAssistant && (assistants.length !== 1 || assistants[0] !== latestAssistant)) break;
|
|
9086
|
+
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())))) {
|
|
9087
|
+
hasResponseActions = true;
|
|
9088
|
+
break;
|
|
9089
|
+
}
|
|
9090
|
+
}
|
|
9091
|
+
}
|
|
9026
9092
|
} else {
|
|
9027
9093
|
const latestTurn = [...turns].reverse().find(
|
|
9028
9094
|
(turn) => turn.querySelector("[data-message-author-role='assistant']") !== null
|
|
@@ -11552,8 +11618,13 @@ async function readSurfaceSnapshot(page) {
|
|
|
11552
11618
|
};
|
|
11553
11619
|
const normalize2 = (value) => value.replace(/\s+/g, " ").trim();
|
|
11554
11620
|
const normalizeComparable = (value) => normalize2(value).toLocaleLowerCase();
|
|
11555
|
-
const
|
|
11556
|
-
const
|
|
11621
|
+
const chatSurfaceLabels = new Set(surfaceOptionLabels.chat.map(normalizeComparable));
|
|
11622
|
+
const workSurfaceLabels = new Set(surfaceOptionLabels.work.map(normalizeComparable));
|
|
11623
|
+
const wantedSurfaceLabels = /* @__PURE__ */ new Set([...chatSurfaceLabels, ...workSurfaceLabels]);
|
|
11624
|
+
const currentComposerRoots = Array.from(document.querySelectorAll(
|
|
11625
|
+
'main form[data-thread-find-composer="true"]'
|
|
11626
|
+
)).filter(visible);
|
|
11627
|
+
const composerRoots = currentComposerRoots.length > 0 ? currentComposerRoots : Array.from(document.querySelectorAll(
|
|
11557
11628
|
"main form, main [data-testid*='composer' i], main [class*='composer' i]"
|
|
11558
11629
|
)).filter(visible);
|
|
11559
11630
|
const main = document.querySelector("main");
|
|
@@ -11600,9 +11671,19 @@ async function readSurfaceSnapshot(page) {
|
|
|
11600
11671
|
"h1, h2, h3, form, [data-testid*='composer' i], [class*='composer' i]"
|
|
11601
11672
|
)).filter(visible).slice(0, 32);
|
|
11602
11673
|
const mainText = normalize2(surfaceTextNodes.map(labelFor).join(" ")).slice(0, 2e3);
|
|
11603
|
-
const
|
|
11674
|
+
const selectedRadioLabels = Array.from(document.querySelectorAll(
|
|
11604
11675
|
"[role='radio'][aria-checked='true'], [role='radio'][data-state='checked'], input[type='radio']:checked"
|
|
11605
|
-
)).filter(visible).map(labelFor).map(normalize2).filter((label) => wantedSurfaceLabels.has(normalizeComparable(label)))
|
|
11676
|
+
)).filter(visible).map(labelFor).map(normalize2).filter((label) => wantedSurfaceLabels.has(normalizeComparable(label)));
|
|
11677
|
+
const pressedGroups = Array.from(document.querySelectorAll("main [role='group']")).filter(visible).filter((group) => {
|
|
11678
|
+
let ancestor = group;
|
|
11679
|
+
for (let depth = 0; ancestor !== null && depth < 64; depth += 1) {
|
|
11680
|
+
if (ancestor.hasAttribute("data-message-author-role") || ancestor.tagName === "ARTICLE" || ["dialog", "menu", "listbox"].includes(ancestor.getAttribute("role") ?? "")) return false;
|
|
11681
|
+
ancestor = ancestor.parentElement;
|
|
11682
|
+
}
|
|
11683
|
+
return ancestor === null;
|
|
11684
|
+
}).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);
|
|
11685
|
+
const selectedButtonLabels = pressedGroups.length === 1 ? pressedGroups[0].filter((button) => button.getAttribute("aria-pressed") === "true").map(labelFor).map(normalize2) : [];
|
|
11686
|
+
const selectedSurfaceLabels = Array.from(/* @__PURE__ */ new Set([...selectedRadioLabels, ...selectedButtonLabels])).slice(0, 4);
|
|
11606
11687
|
const workPopoverOpen = Array.from(document.querySelectorAll(
|
|
11607
11688
|
'[data-testid="composer-intelligence-picker-content"]'
|
|
11608
11689
|
)).filter(visible).some((root) => {
|
|
@@ -11613,10 +11694,10 @@ async function readSurfaceSnapshot(page) {
|
|
|
11613
11694
|
return speed.length === 1 && sliders.length === 1;
|
|
11614
11695
|
});
|
|
11615
11696
|
return { composerLabels, mainControls, composerControls, controlGroups, mainText, selectedSurfaceLabels, workPopoverOpen };
|
|
11616
|
-
},
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11697
|
+
}, {
|
|
11698
|
+
chat: localeLabels.experienceOptions.chat,
|
|
11699
|
+
work: localeLabels.experienceOptions.work
|
|
11700
|
+
}).catch(() => ({ composerLabels: [], mainControls: [], mainText: "", selectedSurfaceLabels: [] }));
|
|
11620
11701
|
return { url, ...snapshot };
|
|
11621
11702
|
}
|
|
11622
11703
|
function profileFromSnapshot(snapshot, experience) {
|
|
@@ -12258,7 +12339,7 @@ async function readChatPopover(page) {
|
|
|
12258
12339
|
return current2 === null;
|
|
12259
12340
|
};
|
|
12260
12341
|
const normalize2 = (value) => value.replace(/\s+/g, " ").trim();
|
|
12261
|
-
const roots = document.querySelectorAll('[data-testid="composer-intelligence-picker-content"]');
|
|
12342
|
+
const roots = Array.from(document.querySelectorAll('[data-testid="composer-intelligence-picker-content"]')).concat(Array.from(document.querySelectorAll("[data-model-picker-view]")));
|
|
12262
12343
|
if (roots.length > 8) return { acted: false };
|
|
12263
12344
|
const activeRoots = Array.from(roots).filter((node) => visible(node));
|
|
12264
12345
|
if (activeRoots.length !== 1) return { acted: false };
|
|
@@ -12274,7 +12355,12 @@ async function readChatPopover(page) {
|
|
|
12274
12355
|
ancestor = ancestor.parentNode;
|
|
12275
12356
|
}
|
|
12276
12357
|
if (menu?.getAttribute("data-state") !== "open" || !visible(menu)) return { acted: false };
|
|
12277
|
-
const
|
|
12358
|
+
const currentProfile = root.hasAttribute("data-model-picker-view");
|
|
12359
|
+
if (currentProfile) {
|
|
12360
|
+
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");
|
|
12361
|
+
if (triggers.length !== 1) return { acted: false };
|
|
12362
|
+
}
|
|
12363
|
+
const nodes = [root];
|
|
12278
12364
|
const text = /* @__PURE__ */ new Map();
|
|
12279
12365
|
let current = root.firstChild;
|
|
12280
12366
|
let count = 0;
|
|
@@ -12308,25 +12394,28 @@ async function readChatPopover(page) {
|
|
|
12308
12394
|
}
|
|
12309
12395
|
return false;
|
|
12310
12396
|
};
|
|
12311
|
-
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));
|
|
12397
|
+
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));
|
|
12312
12398
|
if (owners.length !== 1) return { acted: false };
|
|
12313
12399
|
const owner = owners[0];
|
|
12314
|
-
const view = owner.getAttribute("data-view");
|
|
12400
|
+
const view = owner.getAttribute(currentProfile ? "data-model-picker-view" : "data-view");
|
|
12315
12401
|
if (view !== "simple" && view !== "advanced") return { acted: false };
|
|
12316
|
-
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));
|
|
12402
|
+
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));
|
|
12317
12403
|
if (panels.length !== 1) return { acted: false };
|
|
12318
12404
|
const panel = panels[0];
|
|
12319
|
-
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));
|
|
12405
|
+
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));
|
|
12320
12406
|
if (toggles.length > 1 || view === "simple" && toggles.length !== 1) return { acted: false };
|
|
12321
12407
|
const modelNodes = view === "advanced" ? nodes.filter((node) => within(node, panel) && node.getAttribute("role") === "menuitemradio" && visible(node)) : [];
|
|
12322
12408
|
if (modelNodes.length > 32) return { acted: false };
|
|
12323
12409
|
const modelLabel = (node) => {
|
|
12324
|
-
const primary = nodes.filter((child) =>
|
|
12410
|
+
const primary = nodes.filter((child) => {
|
|
12411
|
+
const classes = (child.getAttribute("class") ?? "").split(/\s+/);
|
|
12412
|
+
return within(child, node) && classes.includes("truncate") && !classes.includes("text-xs");
|
|
12413
|
+
});
|
|
12325
12414
|
return normalize2(primary.length === 1 ? text.get(primary[0]) ?? "" : text.get(node) ?? "");
|
|
12326
12415
|
};
|
|
12327
12416
|
const snapshot = {
|
|
12328
12417
|
view,
|
|
12329
|
-
rootIndex: Array.from(
|
|
12418
|
+
rootIndex: currentProfile ? Array.from(document.querySelectorAll("[data-model-picker-view]")).indexOf(root) : Array.from(document.querySelectorAll('[data-testid="composer-intelligence-picker-content"]')).indexOf(root),
|
|
12330
12419
|
toggleIndex: nodes.filter((node) => node.getAttribute("role") === "menuitem" && node.getAttribute("data-interactive") === "true").indexOf(toggles[0]),
|
|
12331
12420
|
modelOptions: modelNodes.map((node) => ({
|
|
12332
12421
|
label: modelLabel(node),
|
|
@@ -12334,6 +12423,7 @@ async function readChatPopover(page) {
|
|
|
12334
12423
|
index: nodes.filter((row) => within(row, panel) && row.getAttribute("role") === "menuitemradio").indexOf(node)
|
|
12335
12424
|
})).filter((option) => option.label.length > 0)
|
|
12336
12425
|
};
|
|
12426
|
+
if (currentProfile) snapshot.profile = "model_picker_v2";
|
|
12337
12427
|
const triggerId = menu.getAttribute("aria-labelledby");
|
|
12338
12428
|
if (triggerId !== null && triggerId.length > 0 && triggerId.length < 240 && !/\s/.test(triggerId)) snapshot.triggerId = triggerId;
|
|
12339
12429
|
const checked = snapshot.modelOptions.filter((option) => option.checked);
|
|
@@ -12352,7 +12442,7 @@ async function readChatPopover(page) {
|
|
|
12352
12442
|
if (sliders.length === 1) {
|
|
12353
12443
|
const slider = sliders[0];
|
|
12354
12444
|
const powers = nodes.filter((node) => within(slider, node) && within(node, panel) && node.getAttribute("role") === "menuitem" && visible(node) && config.powerLabels.some((label) => normalize2(node.getAttribute("aria-label") ?? "").toLocaleLowerCase() === label.toLocaleLowerCase()));
|
|
12355
|
-
const sliderOwners = nodes.filter((node) => within(slider, node) && within(node, panel) && node.hasAttribute("data-model-reasoning-effort-slider"));
|
|
12445
|
+
const sliderOwners = nodes.filter((node) => within(slider, node) && within(node, panel) && node.hasAttribute(currentProfile ? "data-model-picker-power-slider" : "data-model-reasoning-effort-slider"));
|
|
12356
12446
|
const integer = (name) => {
|
|
12357
12447
|
const raw = slider.getAttribute(name);
|
|
12358
12448
|
return raw !== null && /^-?\d+$/.test(raw) && Number.isSafeInteger(Number(raw)) ? Number(raw) : void 0;
|
|
@@ -12381,11 +12471,46 @@ async function readChatPopover(page) {
|
|
|
12381
12471
|
return observation !== void 0 && observation !== null && typeof observation.acted === "boolean" ? observation : { acted: false };
|
|
12382
12472
|
}
|
|
12383
12473
|
function observedRoot(page, snapshot) {
|
|
12384
|
-
const roots = page.locator?.('[data-testid="composer-intelligence-picker-content"]');
|
|
12474
|
+
const roots = page.locator?.(snapshot.profile === "model_picker_v2" ? "[data-model-picker-view]" : '[data-testid="composer-intelligence-picker-content"]');
|
|
12385
12475
|
return roots?.nth?.(snapshot.rootIndex) ?? (snapshot.rootIndex === 0 ? roots : void 0);
|
|
12386
12476
|
}
|
|
12477
|
+
async function openChatPopover(page) {
|
|
12478
|
+
if ((await readChatPopover(page)).snapshot !== void 0) return true;
|
|
12479
|
+
let trigger = page.locator?.('button[data-codex-intelligence-trigger="true"][aria-haspopup="menu"]');
|
|
12480
|
+
let count = await trigger?.count?.().catch(() => 0) ?? 0;
|
|
12481
|
+
if (count === 0) return void 0;
|
|
12482
|
+
if (count > 1 && count <= 8 && typeof trigger?.filter === "function") {
|
|
12483
|
+
trigger = trigger.filter({ visible: true });
|
|
12484
|
+
count = await trigger.count?.().catch(() => 0) ?? 0;
|
|
12485
|
+
}
|
|
12486
|
+
if (count !== 1) return false;
|
|
12487
|
+
if (trigger?.click === void 0 || trigger.evaluate === void 0) return void 0;
|
|
12488
|
+
const actionable = await trigger.evaluate((element) => {
|
|
12489
|
+
if (element.tagName !== "BUTTON" || element.getAttribute("data-codex-intelligence-trigger") !== "true" || element.getAttribute("aria-haspopup") !== "menu") return void 0;
|
|
12490
|
+
let current = element;
|
|
12491
|
+
for (let depth = 0; current !== null && depth < 64; depth += 1) {
|
|
12492
|
+
if (current.nodeType !== 1) break;
|
|
12493
|
+
const node = current;
|
|
12494
|
+
if (node.hidden || node.hasAttribute("hidden") || node.hasAttribute("inert") || node.disabled || node.getAttribute("aria-hidden") === "true" || node.getAttribute("aria-disabled") === "true") return false;
|
|
12495
|
+
const style = window.getComputedStyle(node);
|
|
12496
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" || current === element && style.pointerEvents === "none") return false;
|
|
12497
|
+
current = current.parentNode;
|
|
12498
|
+
}
|
|
12499
|
+
if (current?.nodeType === 1) return false;
|
|
12500
|
+
const rect = element.getBoundingClientRect();
|
|
12501
|
+
return rect.width > 0 && rect.height > 0 && element.getAttribute("aria-expanded") === "false";
|
|
12502
|
+
}).catch(() => void 0);
|
|
12503
|
+
if (actionable === void 0) return void 0;
|
|
12504
|
+
if (!actionable) return false;
|
|
12505
|
+
await trigger.click();
|
|
12506
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
12507
|
+
await waitForPopoverTransition(page, 100);
|
|
12508
|
+
if ((await readChatPopover(page)).snapshot !== void 0) return true;
|
|
12509
|
+
}
|
|
12510
|
+
return false;
|
|
12511
|
+
}
|
|
12387
12512
|
async function clickObservedControl(page, snapshot, modelIndex) {
|
|
12388
|
-
const selector = modelIndex === void 0 ? '[role="menuitem"][data-interactive="true"]' : '[data-testid="composer-model-picker-slider-advanced-view"][data-active="true"] [role="menuitemradio"]';
|
|
12513
|
+
const selector = modelIndex === void 0 ? '[role="menuitem"][data-interactive="true"]' : snapshot.profile === "model_picker_v2" ? ':scope > [data-active="true"] [role="menuitemradio"]' : '[data-testid="composer-model-picker-slider-advanced-view"][data-active="true"] [role="menuitemradio"]';
|
|
12389
12514
|
const candidates = observedRoot(page, snapshot)?.locator?.(selector);
|
|
12390
12515
|
const index = modelIndex ?? snapshot.toggleIndex;
|
|
12391
12516
|
const target = candidates?.nth?.(index) ?? (index === 0 ? candidates : void 0);
|
|
@@ -12399,7 +12524,7 @@ async function clickObservedControl(page, snapshot, modelIndex) {
|
|
|
12399
12524
|
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;
|
|
12400
12525
|
const style = window.getComputedStyle(node);
|
|
12401
12526
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" || style.pointerEvents === "none") return void 0;
|
|
12402
|
-
if (node.getAttribute("data-testid") === "composer-intelligence-picker-content") owned = true;
|
|
12527
|
+
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;
|
|
12403
12528
|
current = current.parentNode;
|
|
12404
12529
|
}
|
|
12405
12530
|
const rect = element.getBoundingClientRect();
|
|
@@ -12415,7 +12540,8 @@ async function clickObservedControl(page, snapshot, modelIndex) {
|
|
|
12415
12540
|
if (label.length > 512) return void 0;
|
|
12416
12541
|
let parent = child.parentNode;
|
|
12417
12542
|
for (let depth = 0; parent !== null && parent !== element && depth < 64; depth += 1) {
|
|
12418
|
-
|
|
12543
|
+
const classes = parent.nodeType === 1 ? (parent.getAttribute("class") ?? "").split(/\s+/) : [];
|
|
12544
|
+
if (classes.includes("truncate") && !classes.includes("text-xs")) {
|
|
12419
12545
|
primary.set(parent, (primary.get(parent) ?? "") + (child.nodeValue ?? ""));
|
|
12420
12546
|
}
|
|
12421
12547
|
parent = parent.parentNode;
|
|
@@ -12429,9 +12555,9 @@ async function clickObservedControl(page, snapshot, modelIndex) {
|
|
|
12429
12555
|
if (child === element || child === null) break;
|
|
12430
12556
|
child = child.nextSibling;
|
|
12431
12557
|
}
|
|
12432
|
-
return { role: element.getAttribute("role"), expanded: element.getAttribute("aria-expanded"), label: (primary.size === 1 ? [...primary.values()][0] : label).replace(/\s+/g, " ").trim() };
|
|
12558
|
+
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() };
|
|
12433
12559
|
}).catch(() => void 0);
|
|
12434
|
-
if (state === void 0 || state.role !== (modelIndex === void 0 ? "menuitem" : "menuitemradio") || modelIndex === void 0 && state.expanded !== String(snapshot.view === "advanced")) return false;
|
|
12560
|
+
if (state === void 0 || state.role !== (modelIndex === void 0 ? "menuitem" : "menuitemradio") || modelIndex === void 0 && (snapshot.profile === "model_picker_v2" ? state.viewToggle !== "true" : state.expanded !== String(snapshot.view === "advanced"))) return false;
|
|
12435
12561
|
const expectedModel = snapshot.modelOptions.find((option) => option.index === modelIndex);
|
|
12436
12562
|
if (modelIndex !== void 0 && (expectedModel === void 0 || state.label !== expectedModel.label)) return false;
|
|
12437
12563
|
await target.click();
|
|
@@ -12442,9 +12568,9 @@ async function closeChatPopover(page, before) {
|
|
|
12442
12568
|
if (snapshot === void 0) return false;
|
|
12443
12569
|
const escapedId = snapshot.triggerId?.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
12444
12570
|
const menu = escapedId === void 0 ? void 0 : page.locator?.(`[role="menu"][aria-labelledby="${escapedId}"]`);
|
|
12445
|
-
if (
|
|
12446
|
-
else if (page.keyboard?.press !== void 0) await page.keyboard.press("Escape");
|
|
12571
|
+
if (page.keyboard?.press !== void 0) await page.keyboard.press("Escape");
|
|
12447
12572
|
else if (page.cua?.keypress !== void 0) await page.cua.keypress({ keys: ["ESC"] });
|
|
12573
|
+
else if (menu?.press !== void 0 && await menu.count?.() === 1) await menu.press("Escape");
|
|
12448
12574
|
else return false;
|
|
12449
12575
|
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
12450
12576
|
await waitForPopoverTransition(page, 100);
|
|
@@ -12459,6 +12585,7 @@ async function waitForPopoverTransition(page, milliseconds) {
|
|
|
12459
12585
|
async function reopenChatPopover(page, before) {
|
|
12460
12586
|
if (before.triggerId === void 0) return void 0;
|
|
12461
12587
|
if (!await closeChatPopover(page, before)) return void 0;
|
|
12588
|
+
if (before.profile === "model_picker_v2") await waitForPopoverTransition(page, 250);
|
|
12462
12589
|
const trigger = page.locator?.(`[id="${before.triggerId.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"]`);
|
|
12463
12590
|
if (trigger?.click === void 0 || trigger.evaluate === void 0 || await trigger.count?.() !== 1) return void 0;
|
|
12464
12591
|
const isVisible = () => trigger.evaluate((element) => {
|
|
@@ -12555,7 +12682,7 @@ async function selectChatPopoverEffort(page, labels) {
|
|
|
12555
12682
|
return void 0;
|
|
12556
12683
|
}
|
|
12557
12684
|
if (before.slider.current === target) return before;
|
|
12558
|
-
const candidates = observedRoot(page, before)?.locator?.('[data-testid="composer-model-picker-slider-simple-view"][data-active="true"] [role="slider"]');
|
|
12685
|
+
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"]');
|
|
12559
12686
|
const locator = candidates?.nth?.(before.slider.index) ?? (before.slider.index === 0 ? candidates : void 0);
|
|
12560
12687
|
if (locator?.press === void 0 || locator.evaluate === void 0 || await locator.count?.() !== 1) return void 0;
|
|
12561
12688
|
const locatorState = await locator.evaluate((element) => {
|
|
@@ -12569,6 +12696,12 @@ async function selectChatPopoverEffort(page, labels) {
|
|
|
12569
12696
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" || style.pointerEvents === "none") return void 0;
|
|
12570
12697
|
if (node.getAttribute("data-testid") === "composer-model-picker-slider-simple-view" && node.getAttribute("data-active") === "true") panel = true;
|
|
12571
12698
|
if (node.getAttribute("data-testid") === "composer-intelligence-picker-content") owned = true;
|
|
12699
|
+
if (node.getAttribute("data-model-picker-view") === "simple") {
|
|
12700
|
+
owned = true;
|
|
12701
|
+
let track = element;
|
|
12702
|
+
while (track !== null && track.parentNode !== node) track = track.parentNode;
|
|
12703
|
+
if (track?.nodeType === 1 && track.getAttribute("data-active") === "true") panel = true;
|
|
12704
|
+
}
|
|
12572
12705
|
current = current.parentNode;
|
|
12573
12706
|
}
|
|
12574
12707
|
const rect = element.getBoundingClientRect();
|
|
@@ -12909,7 +13042,8 @@ async function getMode(env, args = {}) {
|
|
|
12909
13042
|
}
|
|
12910
13043
|
const page = env.page;
|
|
12911
13044
|
try {
|
|
12912
|
-
const
|
|
13045
|
+
const popover = (await readChatPopover(page)).snapshot;
|
|
13046
|
+
const modes = popover?.effort === void 0 ? await visibleModeButtonLabelList(page) : [popover.effort];
|
|
12913
13047
|
const warnings = modes.length === 0 ? ["No mode-labelled composer control is currently visible, so the active ChatGPT mode could not be read."] : [];
|
|
12914
13048
|
return resultOk({ modes }, await contextFromPage(page), warnings);
|
|
12915
13049
|
} catch (error) {
|
|
@@ -12996,6 +13130,8 @@ async function clickFirstUniqueButton(page, labels) {
|
|
|
12996
13130
|
return false;
|
|
12997
13131
|
}
|
|
12998
13132
|
async function clickModeOpener(page, modeButtons) {
|
|
13133
|
+
const currentPicker = await openChatPopover(page);
|
|
13134
|
+
if (currentPicker !== void 0) return currentPicker;
|
|
12999
13135
|
if (await clickFirstUniqueButton(page, modeButtons)) {
|
|
13000
13136
|
return true;
|
|
13001
13137
|
}
|
|
@@ -13971,6 +14107,10 @@ async function selectChatAxis(env, axis, requested, timeoutMs) {
|
|
|
13971
14107
|
}
|
|
13972
14108
|
async function openConfigurationRoot(page, experience) {
|
|
13973
14109
|
if (experience !== "unknown" && (await readChatPopover(page)).snapshot !== void 0) return true;
|
|
14110
|
+
if (experience !== "unknown") {
|
|
14111
|
+
const currentPicker = await openChatPopover(page);
|
|
14112
|
+
if (currentPicker !== void 0) return currentPicker;
|
|
14113
|
+
}
|
|
13974
14114
|
const existing = await readConfigurationPanel(page);
|
|
13975
14115
|
if (existing.axisRows.length > 0) {
|
|
13976
14116
|
return true;
|
|
@@ -15480,12 +15620,16 @@ async function tryGeneratedFilePreviewDownload(page, args) {
|
|
|
15480
15620
|
const selected = selectGeneratedFileAffordance(candidates, args);
|
|
15481
15621
|
if (selected === void 0) return void 0;
|
|
15482
15622
|
try {
|
|
15483
|
-
|
|
15484
|
-
|
|
15623
|
+
let assistantMessages = requiredLocator(page, cssSelectors.assistantMessages);
|
|
15624
|
+
let assistantCount = await locatorCountWithTimeout(
|
|
15485
15625
|
assistantMessages,
|
|
15486
15626
|
localGuardTimeout(timeoutMs, 5e3),
|
|
15487
15627
|
"generated_file_assistant_count_timeout"
|
|
15488
15628
|
);
|
|
15629
|
+
if (assistantCount === 0) {
|
|
15630
|
+
assistantMessages = requiredLocator(page, cssSelectors.currentAssistantMessages);
|
|
15631
|
+
assistantCount = await locatorCountWithTimeout(assistantMessages, localGuardTimeout(timeoutMs, 5e3), "generated_file_assistant_count_timeout");
|
|
15632
|
+
}
|
|
15489
15633
|
if (selected.assistantIndex < 0 || selected.assistantIndex >= assistantCount) {
|
|
15490
15634
|
throw new Error("The selected generated-file assistant turn is no longer present.");
|
|
15491
15635
|
}
|
|
@@ -15513,11 +15657,12 @@ async function tryGeneratedFilePreviewDownload(page, args) {
|
|
|
15513
15657
|
}
|
|
15514
15658
|
await affordance.click({ timeoutMs: localGuardTimeout(timeoutMs, 1e4) });
|
|
15515
15659
|
const labelledPreview = requiredLocator(page, `section[aria-label="${escapeCssAttribute(selected.filename)}"]`);
|
|
15660
|
+
const currentPreview = page.getByRole?.("tabpanel", { name: selected.filename, exact: true });
|
|
15516
15661
|
const workbookPreviews = requiredLocator(page, "section[data-testid^='popcorn-']");
|
|
15517
15662
|
const workbookPreview = typeof workbookPreviews.filter === "function" ? workbookPreviews.filter({ hasText: selected.filename }) : void 0;
|
|
15518
15663
|
const download = await waitForPreviewDownloadControl(
|
|
15519
15664
|
page,
|
|
15520
|
-
|
|
15665
|
+
[...currentPreview === void 0 ? [] : [currentPreview], labelledPreview, ...workbookPreview === void 0 ? [] : [workbookPreview]],
|
|
15521
15666
|
timeoutMs
|
|
15522
15667
|
);
|
|
15523
15668
|
if (download === void 0) {
|
|
@@ -15558,17 +15703,20 @@ async function inspectGeneratedFileAffordances(page, timeoutMs) {
|
|
|
15558
15703
|
const prefix = downloadLabels.map((label) => label.trim()).filter(Boolean).sort((left, right) => right.length - left.length).find((label) => lowered.startsWith(`${label.toLocaleLowerCase()} `));
|
|
15559
15704
|
return prefix === void 0 ? trimmed : trimmed.slice(prefix.length).trim();
|
|
15560
15705
|
};
|
|
15561
|
-
const
|
|
15706
|
+
const legacyAssistants = Array.from(document.querySelectorAll("[data-message-author-role='assistant']"));
|
|
15707
|
+
const assistants = legacyAssistants.length > 0 ? legacyAssistants : Array.from(document.querySelectorAll(
|
|
15708
|
+
'main [data-chatgpt-search-unit-key$=":assistant"][data-chatgpt-search-message-ids]'
|
|
15709
|
+
));
|
|
15562
15710
|
return assistants.flatMap(
|
|
15563
15711
|
(assistant, assistantIndex) => Array.from(assistant.querySelectorAll("button[aria-label], a[download], a[href*='/backend-api/files/']")).filter(visible).map((element) => {
|
|
15564
15712
|
const controlLabel = (element.getAttribute("aria-label") ?? element.textContent ?? "").trim();
|
|
15565
15713
|
const text = (element.textContent ?? "").trim();
|
|
15566
15714
|
return {
|
|
15567
15715
|
assistantIndex,
|
|
15568
|
-
filename: normalizedFilename(controlLabel),
|
|
15716
|
+
filename: controlLabel.startsWith("Open preview of ") ? controlLabel.slice("Open preview of ".length) : normalizedFilename(controlLabel),
|
|
15569
15717
|
controlLabel,
|
|
15570
15718
|
tag: element.tagName.toLocaleLowerCase(),
|
|
15571
|
-
textFilename: normalizedFilename(text)
|
|
15719
|
+
textFilename: controlLabel.startsWith("Open preview of ") ? element.parentElement?.querySelector("[title]")?.getAttribute("title") ?? "" : normalizedFilename(text)
|
|
15572
15720
|
};
|
|
15573
15721
|
}).filter((item) => (item.tag === "button" || item.tag === "a") && fileLike(item.filename) && item.filename === item.textFilename).map(({ assistantIndex: index, filename, controlLabel, tag }) => ({
|
|
15574
15722
|
assistantIndex: index,
|