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 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": 2624,
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": 63,
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
- userMessages: "[data-message-author-role='user']",
4838
- roleMessages: "[data-message-author-role]",
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 role = element.attrs["data-message-author-role"];
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
- messages.push({ role, html: serializeChildren(element), metadataHtml: serializeNode(metadataElement) });
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 nodes = Array.from(document.querySelectorAll("[data-message-author-role]"));
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 nodes = Array.from(document.querySelectorAll(`[data-message-author-role="${wantedRole}"]`));
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 nodes = Array.from(document.querySelectorAll(`[data-message-author-role="${wantedRole}"]`));
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 allNodes = Array.from(document.querySelectorAll("[data-message-author-role]"));
5560
- const roleNodes = allNodes.filter((node) => node.getAttribute("data-message-author-role") === wantedRole);
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 latestText2 = latest?.innerText ?? latest?.textContent ?? void 0;
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
- return document.querySelectorAll(selector).length;
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
- const assistantMessages = requiredLocator(page, cssSelectors.assistantMessages);
9224
- const assistantCount = await locatorCountWithTimeout(
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
- workbookPreview === void 0 ? [labelledPreview] : [labelledPreview, workbookPreview],
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 assistants = Array.from(document.querySelectorAll("[data-message-author-role='assistant']"));
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 latestAssistant = Array.from(document.querySelectorAll("[data-message-author-role='assistant']")).at(-1);
11186
- const latestTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? turns.at(-1);
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) return void 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 nodes = Array.from(document.querySelectorAll("[data-message-author-role]"));
11395
- const assistantNodes = nodes.filter((node) => node.getAttribute("data-message-author-role") === "assistant");
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 normalizedText = normalizeWs(latestAssistant?.innerText ?? latestAssistant?.textContent ?? "");
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
- hasResponseActions = void 0;
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 nodes = [];
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) => within(child, node) && (child.getAttribute("class") ?? "").split(/\s+/).includes("truncate"));
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(roots).indexOf(root),
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
- if (parent.nodeType === 1 && (parent.getAttribute("class") ?? "").split(/\s+/).includes("truncate")) {
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 (menu?.press !== void 0 && await menu.count?.() === 1) await menu.press("Escape");
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 modes = await visibleModeButtonLabelList(page);
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 wantedSurfaceLabels = new Set(surfaceOptionLabels.map(normalizeComparable));
14850
- const composerRoots = Array.from(document.querySelectorAll(
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 selectedSurfaceLabels = Array.from(new Set(Array.from(document.querySelectorAll(
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))))).slice(0, 4);
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
- ...localeLabels.experienceOptions.chat,
14912
- ...localeLabels.experienceOptions.work
14913
- ]).catch(() => ({ composerLabels: [], mainControls: [], mainText: "", selectedSurfaceLabels: [] }));
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;