// ==UserScript== // @name AI Chat Turbo Engine // @namespace https://cyojkoy.github.io/Payment/ // @version 0.16.3 // @description 跨平台 AI 对话加速:常驻统计 + 完整消息提取 + YAML 交接 + 多平台适配 + 长代码折叠 + 自适应脱水 + 推理强度记忆 + 元宝原子工具记忆 // @author Yoko // @match https://chatgpt.com/* // @match https://chat.openai.com/* // @match https://gemini.google.com/* // @match https://grok.com/* // @match https://x.com/i/grok* // @match https://claude.ai/* // @match https://chat.deepseek.com/* // @match https://copilot.microsoft.com/* // @match https://perplexity.ai/* // @match https://www.perplexity.ai/* // @match https://poe.com/* // @match https://doubao.com/* // @match https://www.doubao.com/* // @match https://yuanbao.tencent.com/* // @match https://chat.qwen.ai/* // @match https://qianwen.com/* // @match https://www.qianwen.com/* // @match https://chatglm.cn/* // @match https://chat.z.ai/* // @run-at document-start // @grant none // @noframes // @icon data:image/svg+xml;utf8, // @license MIT // ==/UserScript== "use strict"; (() => { // shared/userscript/globals.ts function isRecord(value) { return typeof value === "object" && value !== null; } function readUserscriptInfo(scope) { if (!("GM_info" in scope)) return null; const candidate = scope.GM_info; if (!isRecord(candidate)) return null; const script = candidate["script"]; if (!isRecord(script)) return null; const name = typeof script["name"] === "string" ? script["name"] : void 0; const version = typeof script["version"] === "string" ? script["version"] : void 0; return { script: { name, version } }; } // scripts/ai-chat-turbo-engine/src/config.ts var HUD_ID = "ai-turbo-extreme-hud"; var STYLE_ID = "ai-turbo-engine-styles"; var CODE_COLLAPSE_HEIGHT = 300; var CODE_PREVIEW_HEIGHT = 200; var DEFAULT_MESSAGE_LIMIT = 60; var MESSAGE_LIMIT_MIN = 10; var MESSAGE_LIMIT_MAX = 999; var LOAD_WARNING_RATIO = 0.7; var LOAD_RING_RADIUS = 16.2; var LOAD_RING_CIRCUMFERENCE = 2 * Math.PI * LOAD_RING_RADIUS; var TURN_MARKER_ATTRIBUTES = /* @__PURE__ */ new Set([ "data-testid", "data-turn", "data-turn-key", "data-message-author-role", "data-message-role", "data-conversation-role", "data-role", "data-content-search-unit-key", "data-content-search-turn-key", "data-thread-find-target", "data-conversation-transcript", "data-user-message-bubble", "data-chatgpt-agent-turn-start", "data-app-shell-main-surface" ]); var TURN_SELECTOR_ATTRIBUTES = /* @__PURE__ */ new Set([ ...TURN_MARKER_ATTRIBUTES, "class", "id" ]); var CHATGPT_SHELL_ROOT_SELECTOR = '[data-app-shell-main-surface] [data-thread-find-target="conversation"]'; var CHATGPT_SHELL_TURN_SELECTOR = '[data-app-shell-main-surface] [data-thread-find-target="conversation"] [data-turn-key]'; var CHATGPT_TRANSCRIPT_ROOT_SELECTOR = "ol[data-conversation-transcript]"; var CHATGPT_TRANSCRIPT_MESSAGE_SELECTOR = "ol[data-conversation-transcript] > li[data-message-role]"; var CHATGPT_CODE_CARD_BOUNDARY_SELECTOR = [ "[data-turn-key]", '[data-testid^="conversation-turn-"]', "article[data-turn]", "section[data-turn]", 'li[data-message-role="assistant"]', '[data-message-author-role="assistant"]' ].join(", "); var CHATGPT_CODE_HEADER_MARKER_SELECTOR = [ ".code-block-decoration", '[data-testid*="code-block-header" i]', '[data-testid*="code-block-toolbar" i]', '[class*="code-block-header" i]', '[class*="code-header" i]', '[class*="code-toolbar" i]', 'button[aria-label*="copy code" i]', 'button[title*="copy code" i]', '[data-testid*="copy-code" i]', 'button[aria-label*="复制代码"]', 'button[title*="复制代码"]' ].join(", "); var CHATGPT_CODE_CARD_MAX_ANCESTORS = 10; var SEARCH_PREVIEW_LIMIT = 180; var SEARCH_LIMIT = 10; var STORAGE_KEY_POS = "ai_turbo_pill_pos"; var STORAGE_KEY_CONFIG = "ai_turbo_engine_config"; var VIRTUAL_FILE_THRESHOLD = 1500; var COMPOSER_VISUAL_GAP = 48; var COMPOSER_VISUAL_MAX_DEPTH = 5; var STREAMING_IDLE_DELAY = 1500; var THROTTLE_INTERVAL = 80; var CODE_FENCE = "```"; var VF_TOKEN_START = "[[TURBO_VFILE_START:"; var VF_TOKEN_END = ":TURBO_VFILE_END]]"; var VF_REGEX = /\[\[TURBO_VFILE_START:([^|\r\n]+)\|(\d+)\|(\d+):TURBO_VFILE_END\]\]/; var HANDOFF_STORAGE_KEY = "ai_turbo_handoff_restore"; var PLAIN_HANDOFF_START = "[META]"; var PLAIN_HANDOFF_END = "[END]"; var PLAIN_HANDOFF_SECTIONS = [ "[META]", "[TASK]", "[DECISIONS]", "[PROGRESS]", "[ROLE]", "[CONTEXT]", "[OPEN_ISSUES]", "[KEY_ENTITIES]", "[HANDOFF_NOTES]", "[END]" ]; var PLAIN_HANDOFF_TOLERANCE = 1; var REASONING_SELECTOR = [ "model-thoughts", ".thoughts-container", ".thoughts-content", "[data-test-id*='thought' i]", "[data-testid*='thought' i]", "[data-testid*='reasoning' i]", "[data-testid*='thinking' i]", "[class*='reasoning' i]", "[class*='thinking' i]", "[class*='thought-process' i]", "[aria-label*='reasoning' i]", "[aria-label*='thinking' i]", "[aria-label*='思考']", "[aria-label*='推理']", "[data-type='reasoning']" ].join(", "); var STORAGE_KEY_REASONING = "ai_turbo_reasoning_memory"; var STORAGE_KEY_TOOL_MEMORY = "ai_turbo_tool_memory"; var REASONING_CONTROL_PATTERN = /深度思考|深度推理|思考|推理|思维链|thinking|reasoning|think harder|effort|智商|extended thinking/i; var REASONING_CONTROL_SELECTOR = [ "button", "[role='button']", "[role='switch']", "[role='checkbox']", "[role='radio']", "[role='menuitemradio']", "[role='menuitem']", "[role='option']", "[aria-pressed]", "[aria-checked]", "[data-state]" ].join(", "); var REASONING_MENU_SELECTOR = "[role='menu'], [role='listbox'], [role='dialog'], [role='radiogroup'], [data-radix-popper-content-wrapper], [data-floating-ui-portal]"; var CHOICE_OPTION_SELECTOR = "[aria-checked], [aria-selected], [role='menuitemradio'], [role='radio'], [role='option'], [role='menuitem'], button, a"; var CHOICE_RADIO_SELECTOR = "[aria-checked], [aria-selected], [role='menuitemradio'], [role='radio']"; var TOOL_TRIGGER_SELECTOR = '[data-new-input-control="add-tools-trigger"]'; var TOOL_TRIGGER_CONTAINER_SELECTOR = '[data-new-input-control="add-tools"]'; var ATOMIC_ACTIONS_SELECTOR = '[data-new-input-control="atomic-actions"]'; var ATOMIC_TOOL_ITEM_SELECTOR = `${ATOMIC_ACTIONS_SELECTOR} [data-application-id]`; var ATOMIC_TOOL_CHIP_SELECTOR = '[data-new-input-control="selected-atomic-action"][data-application-id]'; var ATOMIC_TOOL_MENU_SELECTOR = `${ATOMIC_ACTIONS_SELECTOR} [role='menu']`; var TOOL_POPUP_SELECTOR = [ "[role='menu']", "[role='listbox']", "[role='dialog']", "[role='radiogroup']", "[data-radix-popper-content-wrapper]", "[data-floating-ui-portal]" ].join(", "); var TOOL_ROW_SELECTOR = [ "[role='menuitemcheckbox']", "[role='menuitemradio']", "[role='checkbox']", "[role='option']", "[aria-checked]", "[aria-pressed]", "[aria-selected]", "[data-state='checked']", "[data-state='unchecked']", "button" ].join(", "); var TOOL_TOGGLE_ROW_SELECTOR = [ "[role='menuitemcheckbox']", "[role='menuitemradio']", "[role='checkbox']", "[role='option']", "[aria-checked]", "[aria-pressed]", "[aria-selected]", "[data-state='checked']", "[data-state='unchecked']" ].join(", "); function isToolControlElement(node) { if (!(node instanceof Element)) return false; return Boolean( node.closest(TOOL_TRIGGER_SELECTOR) || node.closest(TOOL_TRIGGER_CONTAINER_SELECTOR) || node.closest(ATOMIC_ACTIONS_SELECTOR) || node.closest(ATOMIC_TOOL_CHIP_SELECTOR) ); } var BLOCK_TEXT_TAGS = /* @__PURE__ */ new Set([ "ADDRESS", "ARTICLE", "ASIDE", "BLOCKQUOTE", "DD", "DIV", "DL", "DT", "FIELDSET", "FIGCAPTION", "FIGURE", "FOOTER", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER", "HR", "LI", "MAIN", "NAV", "OL", "P", "SECTION", "TABLE", "TBODY", "TD", "TH", "THEAD", "TR", "UL" ]); var PLATFORMS = { chatgpt: { name: "ChatGPT", turnSelectorGroups: [ [CHATGPT_SHELL_TURN_SELECTOR], [CHATGPT_TRANSCRIPT_MESSAGE_SELECTOR], [ '[data-testid^="conversation-turn-"]', "article[data-turn]", "section[data-turn]" ], [ '[data-message-author-role="user"]', '[data-message-author-role="assistant"]', '[data-message-role="user"]', '[data-message-role="assistant"]', '[data-role="user"]', '[data-role="assistant"]' ], [ '[data-content-search-unit-key$=":user"]', '[data-content-search-unit-key$=":assistant"]' ], ["[data-turn-key]"] ], turnSelectors: [ CHATGPT_SHELL_TURN_SELECTOR, CHATGPT_TRANSCRIPT_MESSAGE_SELECTOR, '[data-testid^="conversation-turn-"]', "article[data-turn]", "section[data-turn]", '[data-message-author-role="user"]', '[data-message-author-role="assistant"]', '[data-message-role="user"]', '[data-message-role="assistant"]', '[data-role="user"]', '[data-role="assistant"]', '[data-content-search-unit-key$=":user"]', '[data-content-search-unit-key$=":assistant"]', "[data-turn-key]" ], userTurnSelectors: [ '[data-message-author-role="user"]', '[data-role="user"]', '[data-content-search-unit-key$=":user"]', '[data-user-message-bubble="true"]', '[data-testid="collapsible-user-message-root"]', '[data-testid*="user-message"]', '[class*="user-message"]' ], userContentSelectors: [ '[data-testid="collapsible-user-message-root"]', ".whitespace-pre-wrap", '[data-user-message-bubble="true"]', '[data-content-search-unit-key$=":user"]', '[data-message-author-role="user"]' ], codeSelectors: ["pre"], contentSelectors: [ ".markdown", ".prose", '[class*="markdown"]', ".whitespace-pre-wrap", '[data-content-search-unit-key$=":assistant"]', '[data-message-author-role="assistant"]', '[data-testid="message-content"]' ], inputSelectors: [ 'form[data-chatgpt-composer] [contenteditable="true"][role="textbox"]', 'form[data-chatgpt-composer] [contenteditable="true"]', '[data-chatgpt-composer] [contenteditable="true"]', 'div.ProseMirror[contenteditable="true"][role="textbox"]', "#prompt-textarea", 'textarea[name="prompt-textarea"]', 'div[contenteditable="true"][role="textbox"]', 'div[contenteditable="true"]', "textarea" ], sendButtonSelectors: [ 'form[data-chatgpt-composer] button[type="submit"]', 'form[data-chatgpt-composer] button[data-testid*="send" i]', 'form[data-chatgpt-composer] button[aria-label*="Send" i]', 'form[data-chatgpt-composer] button[aria-label*="发送"]', '[data-chatgpt-composer] button[data-testid*="send" i]', '[data-chatgpt-composer] button[aria-label*="Send" i]', 'button[data-testid="send-button"]', 'button[data-testid="fruitjuice-send-button"]', 'button[data-testid="composer-send-button"]', 'button[data-testid*="send-button" i]', 'button[data-testid*="send" i]', 'button[aria-label="Send prompt"]', 'button[aria-label*="Send prompt" i]', 'button[aria-label*="Send message" i]', 'button[aria-label*="Send" i]', 'button[aria-label*="发送"]', 'button[title*="Send" i]', 'button[type="submit"]' ] }, gemini: { name: "Gemini", turnSelectors: [ "user-query", "model-response", '[data-test-id="user-query"]', '[data-test-id="model-response"]', ".user-query", ".model-response", ".user-query-container", ".model-response-container" ], codeSelectors: ["code-block", "pre"], contentSelectors: [ ".query-text", ".user-query-text", "[class*='query-content']", ".model-response-text", "message-content", ".message-content", ".markdown", ".md-content", ".response-content" ], inputSelectors: [ "rich-textarea .ql-editor", "rich-textarea div[contenteditable='true']", ".rich-textarea div[contenteditable='true']", "div[contenteditable='true'][role='textbox']", "div[contenteditable='true']", "textarea" ], sendButtonSelectors: [ "button.send-button", 'button[aria-label*="Send message"]', 'button[aria-label*="发送消息"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', 'button[aria-label*="提交"]', ".send-button-container button", "rich-textarea + * button" ] }, grok: { name: "Grok", turnSelectors: [ 'div[data-testid*="message-container"]', 'div[data-testid*="conversation-turn"]', 'div[class*="message-bubble"]' ], codeSelectors: ["pre"], contentSelectors: ['div[class*="message-content"]', 'div[dir="auto"]'], inputSelectors: ["textarea", 'div[contenteditable="true"]'], sendButtonSelectors: [ 'button[aria-label*="Grok"]', 'button[type="submit"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]' ] }, claude: { name: "Claude", turnSelectors: [ "div.font-user-message", ".font-claude-response", ".font-claude-message", "div[data-test-render-count]" ], codeSelectors: ["pre"], contentSelectors: [ ".standard-markdown", ".progressive-markdown", ".markdown", '[class*="font-claude"]' ], inputSelectors: [ "div.ProseMirror[contenteditable='true']", 'div[contenteditable="true"]' ], sendButtonSelectors: [ 'button[aria-label*="Send Message"]', 'button[aria-label*="发送消息"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', "fieldset button:last-child" ] }, deepseek: { name: "DeepSeek", turnSelectors: [ ".ds-message", "div[data-um-id]", "div.dad65929", "div._4f9bf79", "div.d29f3d7d", '[data-message-author-role="user"]', '[data-message-author-role="assistant"]', '[data-role="user"]', '[data-role="assistant"]' ], userTurnSelectors: [ '[data-message-author-role="user"]', '[data-role="user"]', "div[data-um-id]", "div.d29f3d7d", '[data-testid*="user-message"]', '[class*="user-message"]' ], userContentSelectors: [ "._9663006 .fbb737a4", ".ds-markdown", "div[data-um-id]", '[data-testid*="user-message"]', '[class*="user-message"]' ], codeSelectors: ["pre", "code-block"], contentSelectors: [ ".ds-markdown", ".markdown", ".prose", '[class*="markdown"]', '[class*="answer"]' ], inputSelectors: [ "#chat-input", 'textarea[data-testid="chat-input"]', 'textarea[placeholder*="Send a message" i]', "textarea[placeholder]", 'div[contenteditable="true"][role="textbox"]', "textarea", '[contenteditable="true"]' ], sendButtonSelectors: [ 'button[data-testid="send-button"]', 'button[aria-label="Send message"]', 'button[data-testid*="send"]', 'button[type="submit"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]' ] }, copilot: { name: "Microsoft Copilot", turnSelectors: [ '[class*="user-message"]', '[class*="assistant-message"]', '[data-testid*="message"]' ], userTurnSelectors: [ '[class*="user-message"]', '[data-testid*="user-message"]', '[data-message-author-role="user"]' ], userContentSelectors: [ '[class*="user-message"]', '[data-testid*="user-message"]' ], codeSelectors: ["pre"], contentSelectors: [ ".ac-textBlock", ".markdown", ".prose", '[class*="message-content"]' ], inputSelectors: [ "textarea[placeholder]", 'div[contenteditable="true"][role="textbox"]', 'div[contenteditable="true"]', "textarea" ], sendButtonSelectors: [ 'button[data-testid*="send"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', 'button[type="submit"]' ] }, perplexity: { name: "Perplexity", turnSelectors: [ '[data-testid="chat-message"]', '[data-testid*="chat-message"]', '[data-message-author-role="user"]', '[data-message-author-role="assistant"]' ], userTurnSelectors: [ '[data-testid*="user-message"]', '[data-message-author-role="user"]', '[class*="user-message"]', '[class*="human"]' ], userContentSelectors: [ '[data-testid*="user-message"]', '[class*="user-message"]', ".whitespace-pre-wrap" ], codeSelectors: ["pre"], contentSelectors: [ ".prose", ".markdown", '[class*="prose"]', '[class*="message-content"]' ], inputSelectors: [ "textarea[placeholder]", 'div[contenteditable="true"][role="textbox"]', 'div[contenteditable="true"]', "textarea" ], sendButtonSelectors: [ 'button[data-testid*="send"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', 'button[type="submit"]' ] }, poe: { name: "Poe", turnSelectors: [ ".Message", ".ChatMessage", '[data-message-author-role="user"]', '[data-message-author-role="assistant"]' ], userTurnSelectors: [ '[data-message-author-role="user"]', '[data-testid*="user-message"]', '[class*="UserMessage"]', '[class*="humanMessage"]' ], userContentSelectors: [ '[data-testid*="user-message"]', '[class*="UserMessage"]', ".Message" ], codeSelectors: ["pre"], contentSelectors: [ ".markdown", ".MessageContent", '[class*="messageContent"]', '[class*="message-content"]' ], inputSelectors: [ "textarea[placeholder]", 'div[contenteditable="true"][role="textbox"]', 'div[contenteditable="true"]', "textarea" ], sendButtonSelectors: [ 'button[data-testid*="send"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', 'button[type="submit"]' ] }, doubao: { name: "Doubao", turnSelectors: [ '[data-testid="send_message"]', '[data-testid="receive_message"]', '[data-testid="message_text_content"]', '[data-testid="message_content"]', '[data-testid*="message_content"]', '[data-message-author-role="user"]', '[data-message-author-role="assistant"]' ], userTurnSelectors: [ '[data-testid="send_message"]', '[data-testid*="user-message"]', '[data-message-author-role="user"]', '[data-message-role="user"]', '[data-role="user"]', '[class*="user-message"]' ], userContentSelectors: [ '[data-testid="message_text_content"]', '[data-testid="message_content"]', '[data-testid*="user-message"]', '[class*="user-message"]' ], codeSelectors: ["pre"], contentSelectors: [ '[data-testid="message_text_content"]', '[data-testid="message_content"]', '[data-testid*="message_content"]', ".markdown", '[class*="message-content"]' ], inputSelectors: [ '[data-testid="chat_input_input"]', "#chat-input", "textarea[placeholder]", 'div[contenteditable="true"][role="textbox"]', 'div[contenteditable="true"]', "textarea" ], sendButtonSelectors: [ '[data-testid="chat_input_send_button"]', 'button[data-testid*="send"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', 'button[type="submit"]' ] }, yuanbao: { name: "Tencent Yuanbao / 腾讯元宝", turnSelectors: [ ".agent-chat__list__item--human", ".agent-chat__list__item--ai", '[data-message-author-role="user"]', '[data-message-author-role="assistant"]' ], userTurnSelectors: [ ".agent-chat__list__item--human", ".agent-chat__bubble--human", '[data-message-author-role="user"]', '[data-role="user"]' ], userContentSelectors: [ ".agent-chat__bubble--human .hyc-content-text", ".agent-chat__bubble--human .agent-chat__bubble__content", ".agent-chat__bubble__content", '[data-message-author-role="user"]' ], codeSelectors: ["pre"], contentSelectors: [ ".hyc-common-markdown-style", ".hyc-content-md-done", ".hyc-content-md", ".agent-chat__speech-text", ".agent-chat__bubble__content", ".hyc-content-text", '[data-message-author-role="assistant"]' ], inputSelectors: [ '.agent-dialogue__content--common__input .ql-editor[contenteditable="true"]', '#search-bar .ql-editor[contenteditable="true"]', '.ql-editor[contenteditable="true"]', 'div[contenteditable="true"][role="textbox"]', "textarea" ], sendButtonSelectors: [ "#yuanbao-send-btn", '.agent-dialogue__content--common__input button[type="submit"]', 'button[aria-label*="发送"]', 'button[aria-label*="Send"]', 'button[type="submit"]' ] }, qwen: { name: "Qwen Chat", turnSelectors: [ ".chat-user-message-container", ".chat-user-message", '[data-message-author-role="user"]', '[data-message-author-role="assistant"]', '[data-message-author="user"]', '[data-message-author="assistant"]', '[data-role="user"]', '[data-role="assistant"]', '[data-testid="chat-message"]', '[class*="questionItem"]', '[class*="answerItem"]' ], userTurnSelectors: [ ".chat-user-message-container", ".chat-user-message", '[data-message-author-role="user"]', '[data-message-author="user"]', '[data-role="user"]', '[data-testid="user-message"]', '[class*="questionItem"]', '[class*="user-message"]' ], userContentSelectors: [ ".chat-user-message", ".chat-user-message-container", '[class*="questionItem"]', '[data-message-author-role="user"]', '[data-message-author="user"]', '[data-role="user"]', ".whitespace-pre-wrap" ], codeSelectors: ["pre"], contentSelectors: [ ".markdown-root", ".markdown-body", ".tongyi-markdown", ".markdown", ".prose", '[class*="answerItem"]', '[data-message-author-role="assistant"]', '[data-message-author="assistant"]', '[data-role="assistant"]' ], inputSelectors: [ "textarea#chat-input", '#chat-input[contenteditable="true"]', "textarea.message-input-textarea", 'textarea[placeholder*="Ask Qwen" i]', 'textarea[placeholder*="message" i]', '[contenteditable="true"][role="textbox"]', "textarea", '[contenteditable="true"]' ], sendButtonSelectors: [ ".message-input-right-button-send", 'button[data-testid="send-button"]', 'button[aria-label*="Send"]', 'button[aria-label*="发送"]', 'button[type="submit"]' ] }, qianwen: { name: "Qianwen / 千问", turnSelectors: [ '[class*="questionItem"]', '[class*="answerItem"]', '[data-message-author-role="user"]', '[data-message-author-role="assistant"]', '[data-message-author="user"]', '[data-message-author="assistant"]', '[data-role="user"]', '[data-role="assistant"]' ], userTurnSelectors: [ '[class*="questionItem"]', '[data-message-author-role="user"]', '[data-message-author="user"]', '[data-role="user"]', '[class*="user-message"]' ], userContentSelectors: [ '[class*="questionItem"]', ".bubble-uo23is", '[data-message-author-role="user"]', '[data-message-author="user"]', '[data-role="user"]' ], codeSelectors: ["pre"], contentSelectors: [ ".tongyi-markdown", ".markdown-body", ".markdown", ".prose", '[class*="answerItem"]', '[data-message-author-role="assistant"]', '[data-message-author="assistant"]', '[data-role="assistant"]' ], inputSelectors: [ "textarea#chat-input", "textarea.message-input-textarea", '#chat-input[contenteditable="true"]', 'textarea[placeholder*="问" i]', 'textarea[placeholder*="消息" i]', '[contenteditable="true"][role="textbox"]', "textarea", '[contenteditable="true"]' ], sendButtonSelectors: [ ".message-input-right-button-send", 'button[data-testid="send-button"]', 'button[aria-label*="发送"]', 'button[aria-label*="Send"]', 'button[type="submit"]' ] }, glm: { name: "ChatGLM / 智谱清言", turnSelectors: [ ".question-txt.dots", '[data-message-author="user"]', '[data-message-author="assistant"]', '[data-message-author-role="user"]', '[data-message-author-role="assistant"]', '[data-role="user"]', '[data-role="assistant"]', ".role-user", ".role-assistant", ".message-user", ".message-assistant" ], userTurnSelectors: [ ".question-txt.dots", '[data-message-author="user"]', '[data-message-author-role="user"]', '[data-role="user"]', ".role-user", ".message-user", '[data-testid*="user-message"]' ], userContentSelectors: [ ".question-txt.dots", ".message-user .markdown-body", ".message-user .markdown", ".role-user", ".message-user", '[data-message-author="user"]', '[data-role="user"]' ], codeSelectors: ["pre"], contentSelectors: [ ".role-assistant .markdown-body", ".message-assistant .markdown-body", ".markdown-body", ".markdown", ".prose", '[class*="markdown"]', '[class*="answer"]', '[data-message-author="assistant"]', '[data-role="assistant"]' ], inputSelectors: [ "#chat-input", 'textarea[placeholder*="请输入"]', 'textarea[placeholder*="消息"]', 'div[contenteditable="true"][role="textbox"]', 'div[contenteditable="true"]', "textarea" ], sendButtonSelectors: [ 'button[data-testid="send-button"]', 'button[aria-label*="发送"]', 'button[aria-label*="Send"]', 'button[type="submit"]' ] }, zai: { name: "Z.ai (GLM)", turnSelectors: [ ".chat-user", ".chat-assistant", '[data-message-author="user"]', '[data-message-author="assistant"]', '[data-role="user"]', '[data-role="assistant"]', ".message-user", ".message-assistant", ".role-user", ".role-assistant" ], userTurnSelectors: [ ".chat-user", '[data-message-author="user"]', '[data-role="user"]', ".message-user", ".role-user", '[data-testid="user-message"]' ], userContentSelectors: [ ".chat-user .flex.justify-end.pb-1", '[data-message-author="user"]', '[data-role="user"]', ".chat-user", ".message-user", ".role-user" ], codeSelectors: ["pre"], contentSelectors: [ ".chat-assistant .markdown-body", ".chat-assistant .markdown-root", ".chat-assistant", ".markdown-body", ".markdown-root", ".markdown", ".prose", '[class*="markdown"]', '[data-message-author="assistant"]', '[data-role="assistant"]', ".message-assistant", ".role-assistant" ], inputSelectors: [ 'div[contenteditable="true"]#chat-input', 'div[contenteditable="true"][data-testid*="input"]', "textarea#chat-input", 'textarea[placeholder="Send a Message"]', 'textarea[placeholder*="message" i]', 'div[contenteditable="true"][role="textbox"]', "textarea", '[contenteditable="true"]' ], sendButtonSelectors: [ 'button[type="submit"]', 'button[aria-label="Send"]', 'button[data-testid="send-button"]', 'button[aria-label*="send" i]', 'button[aria-label*="发送"]' ] } }; // scripts/ai-chat-turbo-engine/src/core/diagnostics.ts var REPORT_LIMIT = 50; var reported = /* @__PURE__ */ new Set(); function reportRecoverableError(scope, error) { const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error); const key = `${scope}\0${detail}`; if (reported.has(key) || reported.size >= REPORT_LIMIT) return; reported.add(key); console.warn(`[AI Chat Turbo] ${scope} skipped: ${detail}`); } // scripts/ai-chat-turbo-engine/src/core/text.ts function normalizeText(sourceText) { return String(sourceText || "").replace(/\u00a0/g, " ").replace(/\r\n?/g, "\n").split("\n").map((line) => line.replace(/[ \t]+$/g, "")).join("\n").replace(/\n{3,}/g, "\n\n").trim(); } function escapeHtml(text) { return String(text || "").replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); } function fastCountLines(text) { if (!text) return 0; let count = 1; for (let i = 0; i < text.length; i++) { if (text.charCodeAt(i) === 10) count++; } return count; } function matchesReasoningElement(element) { if (!(element instanceof Element)) return false; try { return element.matches(REASONING_SELECTOR); } catch (error) { reportRecoverableError("match reasoning element", error); return false; } } function isReasoningElement(element) { if (!(element instanceof Element)) return false; try { return matchesReasoningElement(element) || Boolean(element.closest(REASONING_SELECTOR)); } catch (error) { reportRecoverableError("resolve reasoning ancestor", error); return false; } } function elementToPlainText(rootElement) { if (!(rootElement instanceof Element) || matchesReasoningElement(rootElement)) { return ""; } const ignoredSelectors = [ REASONING_SELECTOR, ".ai-turbo-chat-file-row", ".ai-turbo-chat-capsule", ".ai-turbo-code-bar", "#ai-turbo-vf-tray", "#ai-turbo-vf-preview-modal", "button", "[role='toolbar']", "script", "style", "svg", "[hidden]" ].join(", "); const preservedCodeBlocks = []; function walk(node) { if (node.nodeType === Node.TEXT_NODE) { return node.nodeValue || ""; } if (!(node instanceof Element)) { return Array.from(node.childNodes).map(walk).join(""); } try { if (node !== rootElement && node.matches(ignoredSelectors)) return ""; } catch (error) { reportRecoverableError("test ignored transcript selectors", error); } const tag = node.tagName.toUpperCase(); if (tag === "BR") return "\n"; if (tag === "PRE") { const codeText = node.textContent || ""; const codeClasses = [ node.className || "", node.querySelector("code")?.className || "", node.getAttribute("data-language") || "", node.querySelector("code")?.getAttribute("data-language") || "", node.querySelector("code")?.getAttribute("lang") || "" ].join(" "); const languageMatch = /language-([a-z0-9+#.-]+)/i.exec(codeClasses); const language = languageMatch ? (languageMatch[1] ?? "text").toLowerCase() : "text"; const token = `TURBO_CODE_${preservedCodeBlocks.length}`; preservedCodeBlocks.push({ token, codeText, language }); return ` ${CODE_FENCE}${language} ${token} ${CODE_FENCE} `; } const content = Array.from(node.childNodes).map(walk).join(""); return BLOCK_TEXT_TAGS.has(tag) ? "\n" + content + "\n" : content; } let text = normalizeText(walk(rootElement)); for (const block of preservedCodeBlocks) { const placeholder = `${CODE_FENCE}${block.language} ${block.token} ${CODE_FENCE}`; const preserved = `${CODE_FENCE}${block.language} ${block.codeText} ${CODE_FENCE}`; text = text.replace(placeholder, preserved); } return text; } // scripts/ai-chat-turbo-engine/src/core/turns.ts function createTurnUtils(platform) { let activeTurnSelectorGroup = null; const renderedCheckCache = /* @__PURE__ */ new Map(); function clearRenderedCache() { renderedCheckCache.clear(); } function isGeminiThoughtElement(element) { if (platform !== PLATFORMS.gemini || !(element instanceof Element)) return false; return Boolean( element.closest( "model-thoughts, .thoughts-container, .thoughts-content, [data-test-id*='thought']" ) ); } function isUserTurn(turnElement) { if (!(turnElement instanceof Element)) return false; const contentSearchKey = turnElement.getAttribute( "data-content-search-unit-key" ); if (contentSearchKey && /:(user|human)$/i.test(contentSearchKey)) { return true; } if (contentSearchKey && /:(assistant|model|system)$/i.test(contentSearchKey)) { return false; } const roleValues = [ turnElement.getAttribute("data-message-author-role"), turnElement.getAttribute("data-message-author"), turnElement.getAttribute("data-role"), turnElement.getAttribute("data-message-role"), turnElement.getAttribute("data-conversation-role"), turnElement.getAttribute("data-turn") ].filter((role) => typeof role === "string"); if (roleValues.some((role) => /^(user|human)$/i.test(role))) return true; if (roleValues.some((role) => /^(assistant|model|system)$/i.test(role))) { return false; } const platformUserSelectors = platform.userTurnSelectors || []; for (const selector of platformUserSelectors) { if (turnElement.matches(selector) || turnElement.querySelector(selector)) { return true; } } let ancestor = turnElement.parentElement; let ancestorDepth = 0; while (ancestor && ancestorDepth < 3) { const currentAncestor = ancestor; if (platformUserSelectors.some( (selector) => currentAncestor.matches(selector) )) { return true; } ancestor = ancestor.parentElement; ancestorDepth++; } if (turnElement.matches( "user-query, [data-test-id='user-query'], .user-query, .user-query-container" ) || turnElement.querySelector( ".user-query-text, .query-text, [class*='query-content']" )) { return true; } if (turnElement.matches("div.font-user-message") || turnElement.querySelector(".font-user-message")) { return true; } if (turnElement.matches('[data-testid*="user"], [class*="user"]') || turnElement.querySelector('[data-testid*="user"]')) { return true; } return false; } function getTurnRole(turnElement) { if (!(turnElement instanceof Element)) return "assistant"; const contentSearchKey = turnElement.getAttribute( "data-content-search-unit-key" ); if (contentSearchKey && /:(user|human)$/i.test(contentSearchKey)) { return "user"; } if (contentSearchKey && /:(assistant|model)$/i.test(contentSearchKey)) { return "assistant"; } const roleValues = [ turnElement.getAttribute("data-message-author-role"), turnElement.getAttribute("data-message-author"), turnElement.getAttribute("data-role"), turnElement.getAttribute("data-message-role"), turnElement.getAttribute("data-conversation-role"), turnElement.getAttribute("data-turn") ].filter((role) => typeof role === "string"); if (roleValues.some((role) => /^(user|human)$/i.test(role))) return "user"; if (roleValues.some((role) => /^(assistant|model)$/i.test(role))) { return "assistant"; } for (const selector of platform.userTurnSelectors || []) { try { if (turnElement.matches(selector)) return "user"; } catch (error) { reportRecoverableError("test user turn selector", error); } } return isUserTurn(turnElement) ? "user" : "assistant"; } function uniqueDomOrdered(elements) { const seen = /* @__PURE__ */ new Set(); const unique = []; for (const element of elements) { if (!(element instanceof Element) || seen.has(element)) continue; seen.add(element); unique.push(element); } unique.sort((first, second) => { if (first === second) return 0; const relation = first.compareDocumentPosition(second); if (relation & Node.DOCUMENT_POSITION_FOLLOWING) return -1; if (relation & Node.DOCUMENT_POSITION_PRECEDING) return 1; return 0; }); return unique; } function filterOutNested(elements) { const ordered = uniqueDomOrdered(elements); const candidateSet = new Set(ordered); return ordered.filter((element) => { let parent = element.parentElement; while (parent) { if (candidateSet.has(parent)) return false; parent = parent.parentElement; } return true; }); } function isRenderedChatGPTElement(element) { if (!(element instanceof HTMLElement) || !element.isConnected || element.closest('[hidden], [aria-hidden="true"], [inert]')) { return false; } const cachedResult = renderedCheckCache.get(element); if (cachedResult !== void 0) return cachedResult; const computedStyle = window.getComputedStyle(element); const isRendered = computedStyle.display !== "none" && computedStyle.visibility !== "hidden" && computedStyle.visibility !== "collapse" && element.getClientRects().length > 0; renderedCheckCache.set(element, isRendered); return isRendered; } function selectChatGPTRootWithMostTurns(roots, turnSelector) { let selectedRoot = null; let largestTurnCount = -1; for (const candidateRoot of roots) { const turnCount = Array.from( candidateRoot.querySelectorAll(turnSelector) ).filter( (turnElement) => turnElement.closest("[data-turn-key]") === turnElement && isRenderedChatGPTElement(turnElement) ).length; if (turnCount >= largestTurnCount) { selectedRoot = candidateRoot; largestTurnCount = turnCount; } } return selectedRoot; } function collectChatGPTShellMessages(conversationRoot) { const messageNodes = []; const seenTurnRoles = /* @__PURE__ */ new Set(); const turnContainers = Array.from( conversationRoot.querySelectorAll("[data-turn-key]") ).filter( (turnContainer) => turnContainer.closest("[data-turn-key]") === turnContainer && isRenderedChatGPTElement(turnContainer) ); const roleSelectors = [ { role: "user", selectors: [ '[data-content-search-unit-key$=":user"]', '[data-user-message-bubble="true"]', '[data-message-role="user"]', '[data-conversation-role="user"]' ] }, { role: "assistant", selectors: [ '[data-content-search-unit-key$=":assistant"]', '[data-message-role="assistant"]', '[data-conversation-role="assistant"]', "[data-chatgpt-agent-turn-start]" ] } ]; for (const turnContainer of turnContainers) { const turnKey = (turnContainer.getAttribute("data-turn-key") || turnContainer.getAttribute("data-turn-id") || turnContainer.id || "").trim(); if (!turnKey) continue; for (const roleConfig of roleSelectors) { const roleIdentity = `${turnKey}:${roleConfig.role}`; if (seenTurnRoles.has(roleIdentity)) continue; let roleElement = null; for (const selector of roleConfig.selectors) { roleElement = Array.from(turnContainer.querySelectorAll(selector)).find( (candidateElement) => candidateElement.closest("[data-turn-key]") === turnContainer && isRenderedChatGPTElement(candidateElement) ) ?? null; if (roleElement) break; } if (!roleElement) continue; seenTurnRoles.add(roleIdentity); messageNodes.push(roleElement); } } return filterOutNested(uniqueDomOrdered(messageNodes)).filter( (element) => !isGeminiThoughtElement(element) && !matchesReasoningElement(element) ); } function getCurrentChatGPTTurns() { if (platform.name !== "ChatGPT") return null; const shellRoots = Array.from( document.querySelectorAll(CHATGPT_SHELL_ROOT_SELECTOR) ).filter(isRenderedChatGPTElement); if (shellRoots.length) { const activeShellRoot = selectChatGPTRootWithMostTurns( shellRoots, "[data-turn-key]" ); return activeShellRoot ? collectChatGPTShellMessages(activeShellRoot) : []; } const transcriptRoots = Array.from( document.querySelectorAll(CHATGPT_TRANSCRIPT_ROOT_SELECTOR) ).filter(isRenderedChatGPTElement); if (transcriptRoots.length) { let activeTranscriptRoot = transcriptRoots[0]; let largestMessageCount = -1; for (const candidateRoot of transcriptRoots) { const messageCount = Array.from( candidateRoot.querySelectorAll(":scope > li[data-message-role]") ).filter(isRenderedChatGPTElement).length; if (messageCount >= largestMessageCount) { activeTranscriptRoot = candidateRoot; largestMessageCount = messageCount; } } return Array.from( activeTranscriptRoot.querySelectorAll(":scope > li[data-message-role]") ).filter(isRenderedChatGPTElement); } return null; } function getTurns() { const currentChatGPTTurns = getCurrentChatGPTTurns(); if (currentChatGPTTurns !== null) return currentChatGPTTurns; const collected = []; for (const selector of getActiveTurnSelectors()) { document.querySelectorAll(selector).forEach((elem) => collected.push(elem)); } const unnested = filterOutNested(collected); return unnested.filter( (element) => (platform.name !== "ChatGPT" || isRenderedChatGPTElement(element)) && !isGeminiThoughtElement(element) && !matchesReasoningElement(element) ); } function findContentElement(turnElement) { const selectorGroups = []; if (isUserTurn(turnElement) && Array.isArray(platform.userContentSelectors)) { selectorGroups.push(platform.userContentSelectors); } selectorGroups.push(platform.contentSelectors || []); for (const selectorGroup of selectorGroups) { for (const selector of selectorGroup) { const match = turnElement.matches(selector) ? turnElement : turnElement.querySelector(selector); if (match && !isGeminiThoughtElement(match)) return match; } } return turnElement; } function extractTurnText(turnElement) { let raw = elementToPlainText(turnElement); const vfIdx = raw.indexOf(VF_TOKEN_START); if (vfIdx !== -1) { let userPart = raw.slice(0, vfIdx).replace(/```[a-z]*\s*$/i, "").trim(); if (userPart === "请查阅并分析以下文本内容:" || userPart === "请查阅以下文本:") { userPart = ""; } const match = raw.match(VF_REGEX); const fileName = match ? ` [📎 ${match[1]}]` : " [📎 附件文件]"; raw = (userPart || "附件文本") + fileName; } return normalizeText(raw); } function getActiveTurnSelectors() { const selectorGroups = platform.turnSelectorGroups; if (!Array.isArray(selectorGroups)) { return platform.turnSelectors; } if (activeTurnSelectorGroup) { return activeTurnSelectorGroup; } for (const selectorGroup of selectorGroups) { if (selectorGroup.some( (selector) => document.querySelector(selector) )) { activeTurnSelectorGroup = selectorGroup; return selectorGroup; } } return platform.turnSelectors; } function invalidateActiveTurnSelectorGroup() { activeTurnSelectorGroup = null; } return { isGeminiThoughtElement, isUserTurn, getTurnRole, filterOutNested, getCurrentChatGPTTurns, getTurns, findContentElement, extractTurnText, getActiveTurnSelectors, invalidateActiveTurnSelectorGroup, clearRenderedCache }; } // shared/storage/keyValue.ts var DEFAULT_MESSAGES = { read: "[shared/storage] read failed", write: "[shared/storage] write failed", remove: "[shared/storage] remove failed", parse: "[shared/storage] invalid JSON" }; function reportFailure(options, operation, error) { if (options.onError !== void 0) { options.onError({ operation, error }); return; } console.error(DEFAULT_MESSAGES[operation], error); } function createStringStorage(storage, options = {}) { const memory = /* @__PURE__ */ new Map(); const useCache = options.cache !== false; const read = (key) => { if (useCache) { const cached = memory.get(key); if (cached !== void 0) return cached; } try { const value = storage.getItem(key); if (useCache && value !== null) memory.set(key, value); return value; } catch (error) { reportFailure(options, "read", error); return null; } }; const write = (key, value) => { if (useCache) memory.set(key, value); try { storage.setItem(key, value); return true; } catch (error) { reportFailure(options, "write", error); return false; } }; const remove = (key) => { if (useCache) memory.delete(key); try { storage.removeItem(key); return true; } catch (error) { reportFailure(options, "remove", error); return false; } }; return { read, write, readJson: (key, fallback) => { const raw = read(key); if (raw === null) return fallback; try { return JSON.parse(raw); } catch (error) { reportFailure(options, "parse", error); return fallback; } }, writeJson: (key, value) => { let serialized; try { serialized = JSON.stringify(value); } catch (error) { reportFailure(options, "write", error); return false; } return write(key, serialized); }, remove }; } function isStorageArea(value) { if (typeof value !== "object" || value === null) return false; return "getItem" in value && "setItem" in value && "removeItem" in value; } function resolveArea(kind) { const area = kind === "localStorage" ? window.localStorage : window.sessionStorage; if (!isStorageArea(area)) { throw new Error(kind + " is unavailable in this frame"); } return area; } function getBrowserStorage(kind, options = {}) { return createStringStorage( { getItem: (key) => resolveArea(kind).getItem(key), setItem: (key, value) => resolveArea(kind).setItem(key, value), removeItem: (key) => resolveArea(kind).removeItem(key) }, options ); } // scripts/ai-chat-turbo-engine/src/storage/reported.ts function createReportedStorage(kind, report) { return getBrowserStorage(kind, { cache: false, onError: report }); } // scripts/ai-chat-turbo-engine/src/state.ts var configStore = createReportedStorage("localStorage", (failure) => { const scope = failure.operation === "write" || failure.operation === "remove" ? "save engine config" : "load saved engine config"; reportRecoverableError(scope, failure.error); }); function createEngineState() { return { pruneEnabled: true, keepTurns: 8, messageLimit: DEFAULT_MESSAGE_LIMIT, collapseCode: true, virtualFileEnabled: true, rememberReasoning: true, rememberTools: true, hudOpen: false, totalTurns: 0, hiddenCount: 0, foldedCodeCount: 0, indexedTurns: [] }; } function normalizeMessageLimit(rawLimit) { const numericLimit = Number(rawLimit); if (!Number.isFinite(numericLimit)) return DEFAULT_MESSAGE_LIMIT; return Math.min( MESSAGE_LIMIT_MAX, Math.max(MESSAGE_LIMIT_MIN, Math.round(numericLimit)) ); } function isSavedConfig(value) { return typeof value === "object" && value !== null; } function loadSavedConfig(state) { try { const raw = configStore.read(STORAGE_KEY_CONFIG); if (raw === null || raw === "") return; const parsed = JSON.parse(raw); if (!isSavedConfig(parsed)) return; if (typeof parsed.keepTurns === "number" && !isNaN(parsed.keepTurns)) { state.keepTurns = Math.max(2, Math.min(50, parsed.keepTurns)); } if (typeof parsed.messageLimit === "number" && Number.isFinite(parsed.messageLimit)) { state.messageLimit = normalizeMessageLimit(parsed.messageLimit); } if (typeof parsed.pruneEnabled === "boolean") { state.pruneEnabled = parsed.pruneEnabled; } if (typeof parsed.collapseCode === "boolean") { state.collapseCode = parsed.collapseCode; } if (typeof parsed.virtualFileEnabled === "boolean") { state.virtualFileEnabled = parsed.virtualFileEnabled; } if (typeof parsed.rememberReasoning === "boolean") { state.rememberReasoning = parsed.rememberReasoning; } if (typeof parsed.rememberTools === "boolean") { state.rememberTools = parsed.rememberTools; } } catch (error) { reportRecoverableError("load saved engine config", error); } } function saveCurrentConfig(state) { try { const config = { keepTurns: state.keepTurns, messageLimit: state.messageLimit, pruneEnabled: state.pruneEnabled, collapseCode: state.collapseCode, virtualFileEnabled: state.virtualFileEnabled, rememberReasoning: state.rememberReasoning, rememberTools: state.rememberTools }; configStore.write(STORAGE_KEY_CONFIG, JSON.stringify(config)); } catch (error) { reportRecoverableError("save engine config", error); } } // scripts/ai-chat-turbo-engine/src/ui/code-blocks.ts function createCodeBlockUtils(deps) { const { currentPlatform, state, el, withSelfMutation, filterOutNested, isGeminiThoughtElement, requestUpdate } = deps; const codeState = /* @__PURE__ */ new Map(); const dirtyCodeBlocks = /* @__PURE__ */ new Set(); let codeScanRequested = true; let codeResizeObserver = null; function normalizeCodeElement(candidate) { if (!(candidate instanceof HTMLElement)) return null; const geminiBlock = candidate.closest("code-block"); if (geminiBlock instanceof HTMLElement) return geminiBlock; if (candidate.matches("code")) { return candidate.parentElement?.matches("pre") ? candidate.parentElement : candidate; } return candidate; } function getCodeBlocks(rootNode = document) { const collected = []; const selectors = currentPlatform.codeSelectors || ["pre"]; for (const selector of selectors) { rootNode.querySelectorAll(selector).forEach((candidate) => { const belongsToUserTurn = (currentPlatform.userTurnSelectors || []).some((selector2) => { try { return candidate.matches(selector2) || Boolean(candidate.closest(selector2)); } catch (error) { reportRecoverableError("test code card boundary", error); return false; } }); if (candidate.classList.contains("ai-turbo-chat-folded-target") || belongsToUserTurn || candidate.closest( ".ai-turbo-chat-folded-target, .ai-turbo-chat-capsule, user-query, [data-message-author-role='user'], [data-content-search-unit-key$=':user'], [data-user-message-bubble='true'], [data-testid='collapsible-user-message-root'], .font-user-message" )) { return; } const codeElement = normalizeCodeElement(candidate); if (!codeElement) return; if (isGeminiThoughtElement(codeElement)) return; collected.push(codeElement); }); } return filterOutNested(collected).filter( (element) => element instanceof HTMLElement ); } function getCodeText(codeElement) { const sourceElement = codeElement.querySelector("pre code") || codeElement.querySelector("pre") || codeElement.querySelector("code") || codeElement; return typeof sourceElement.textContent === "string" ? sourceElement.textContent : ""; } function getCodeLanguage(codeElement) { const langElem = codeElement.querySelector( 'code[class*="language-"], [class*="language-"]' ); if (langElem) { const match = String(langElem.className || "").match( /language-([a-z0-9+#.-]+)/i ); if (match) return (match[1] ?? "").toUpperCase(); } const decElem = codeElement.querySelector( ".code-block-decoration, [data-testid*='language']" ); const decText = decElem?.textContent?.trim(); if (decText && decText.length < 24) return decText.toUpperCase(); const attrLang = codeElement.getAttribute("data-language") || codeElement.getAttribute("lang"); if (attrLang) return attrLang.toUpperCase(); return "代码"; } function getCodeElementHeight(codeElement) { const pre = codeElement.querySelector("pre"); return Math.max( codeElement.scrollHeight || 0, codeElement.offsetHeight || 0, pre?.scrollHeight || 0, pre?.offsetHeight || 0 ); } function applyFoldStyles(entry, codeElement) { withSelfMutation(() => { if (entry.expanded) { codeElement.classList.remove("ai-turbo-folded"); codeElement.classList.add("ai-turbo-expanded"); codeElement.style.removeProperty("max-height"); codeElement.style.removeProperty("overflow"); } else { codeElement.classList.remove("ai-turbo-expanded"); codeElement.classList.add("ai-turbo-folded"); codeElement.style.setProperty("display", "block", "important"); codeElement.style.setProperty( "max-height", `${CODE_PREVIEW_HEIGHT}px`, "important" ); codeElement.style.setProperty("overflow", "hidden", "important"); } }); } function updateCodeMeta(entry, codeElement) { if (!entry || !codeElement?.isConnected) return; if (entry.renderedStaticOnce && !entry.isDisplayingStreaming && !dirtyCodeBlocks.has(codeElement)) { return; } const currentText = getCodeText(codeElement); const currentLen = currentText.length; const now = Date.now(); if (currentLen !== entry.lastLength) { entry.lastLength = currentLen; entry.lastMutationTime = now; entry.renderedStaticOnce = false; } const isActivelyStreaming = entry.lastMutationTime > 0 && now - entry.lastMutationTime < STREAMING_IDLE_DELAY; if (isActivelyStreaming) { if (!entry.isDisplayingStreaming) { entry.isDisplayingStreaming = true; entry.langLabel.textContent = getCodeLanguage(codeElement); entry.linesLabel.textContent = ""; entry.linesLabel.appendChild( el("span", { className: "ai-turbo-streaming-badge" }, [ "● 正在输出..." ]) ); entry.toggleButton.textContent = entry.expanded ? "收起代码" : "展开代码"; } if (entry.streamingTimer) clearTimeout(entry.streamingTimer); entry.streamingTimer = setTimeout(() => { updateCodeMeta(entry, codeElement); }, STREAMING_IDLE_DELAY + 50); return; } entry.isDisplayingStreaming = false; entry.renderedStaticOnce = true; const lineCount = fastCountLines(currentText); entry.langLabel.textContent = getCodeLanguage(codeElement); entry.linesLabel.textContent = lineCount ? `${lineCount.toLocaleString()} 行` : ""; entry.toggleButton.textContent = entry.expanded ? "收起代码" : `展开 ${lineCount ? `${lineCount.toLocaleString()} 行` : "代码"}`; entry.toggleButton.setAttribute("aria-expanded", String(entry.expanded)); } function unmountCodeControls(codeElement) { const entry = codeState.get(codeElement); if (!entry) return; if (entry.streamingTimer) clearTimeout(entry.streamingTimer); withSelfMutation(() => { entry.bar?.remove(); codeElement.classList.remove( "ai-turbo-code-target", "ai-turbo-folded", "ai-turbo-expanded" ); codeElement.style.removeProperty("max-height"); codeElement.style.removeProperty("overflow"); codeElement.style.removeProperty("display"); }); codeState.delete(codeElement); } function isNativeCodeHeaderNode(node) { if (!(node instanceof HTMLElement)) return false; try { if (node.matches(CHATGPT_CODE_HEADER_MARKER_SELECTOR) || node.querySelector(CHATGPT_CODE_HEADER_MARKER_SELECTOR)) { return true; } } catch (error) { reportRecoverableError("inspect native code header", error); return false; } const className = typeof node.className === "string" ? node.className : ""; const markerText = [ className, node.getAttribute("data-testid") || "", node.getAttribute("aria-label") || "", node.getAttribute("title") || "" ].join(" "); if (/(?:code|language).*(?:header|toolbar|decoration)|(?:header|toolbar).*(?:code|language)/i.test( markerText )) { return true; } if (node.querySelector("button") && !node.querySelector("pre, code")) { const headerText = (node.textContent || "").trim(); if (headerText.length > 0 && headerText.length <= 64 && (/^(?:[a-z0-9_+#.-]+)$/i.test(headerText) || /copy|复制|运行代码|code block/i.test(headerText))) { return true; } } return false; } function getChatGPTCodeCardAnchor(codeElement) { let branch = codeElement; let parent = codeElement.parentElement; let classBasedFallback = null; let depth = 0; while (parent instanceof HTMLElement && depth < CHATGPT_CODE_CARD_MAX_ANCESTORS) { if (parent.matches(CHATGPT_CODE_CARD_BOUNDARY_SELECTOR)) break; let precedingSibling = branch.previousElementSibling; while (precedingSibling) { if (isNativeCodeHeaderNode(precedingSibling)) { return parent.contains(codeElement) ? parent : null; } precedingSibling = precedingSibling.previousElementSibling; } const className = typeof parent.className === "string" ? parent.className : ""; const cardMarker = [ className, parent.getAttribute("data-testid") || "", parent.getAttribute("data-role") || "" ].join(" "); if (/(?:code[-_ ]?(?:block|card|container)|(?:block|card)[-_ ]?code|group\/code)/i.test( cardMarker )) { classBasedFallback = parent; } branch = parent; parent = parent.parentElement; depth++; } return classBasedFallback instanceof HTMLElement && classBasedFallback.isConnected && classBasedFallback.contains(codeElement) ? classBasedFallback : null; } function getCodeControlAnchor(codeElement) { if (currentPlatform !== PLATFORMS.chatgpt) return codeElement; return getChatGPTCodeCardAnchor(codeElement); } function positionCodeControl(entry, codeElement) { const anchor = getCodeControlAnchor(codeElement); if (!(anchor instanceof HTMLElement) || anchor === codeElement) { unmountCodeControls(codeElement); return false; } if (entry.anchor === anchor && entry.bar.isConnected && entry.bar.nextElementSibling === anchor) { return true; } withSelfMutation(() => { entry.bar.remove(); anchor.insertAdjacentElement("beforebegin", entry.bar); entry.anchor = anchor; }); return true; } function flashCopyState(button, label) { button.textContent = label; window.setTimeout(() => { if (button.isConnected) button.textContent = "复制"; }, 1200); } function copyCodeText(button, codeElement) { const text = getCodeText(codeElement); if (!navigator.clipboard?.writeText) { flashCopyState(button, "不可用"); return; } navigator.clipboard.writeText(text).then( () => flashCopyState(button, "已复制"), () => flashCopyState(button, "复制失败") ); } function mountCodeControls(codeElement) { if (!state.collapseCode || !codeElement.isConnected || codeState.has(codeElement)) return; if (codeElement.parentElement?.closest(".ai-turbo-code-target")) return; const measuredH = getCodeElementHeight(codeElement); if (measuredH <= CODE_COLLAPSE_HEIGHT) return; const anchor = getCodeControlAnchor(codeElement); if (currentPlatform === PLATFORMS.chatgpt && (!(anchor instanceof HTMLElement) || anchor === codeElement)) { return; } let sibling = codeElement.previousElementSibling; while (sibling && sibling.classList.contains("ai-turbo-code-bar")) { const toRemove = sibling; sibling = sibling.previousElementSibling; toRemove.remove(); } const initialText = getCodeText(codeElement); const langLabel = el("span", { className: "ai-turbo-code-lang" }); const linesLabel = el("span", { className: "ai-turbo-code-lines" }); const metaWrap = el("div", { className: "ai-turbo-code-bar-meta" }, [ langLabel, linesLabel ]); const toggleButton = el("button", { type: "button", className: "ai-turbo-code-toggle", "aria-expanded": "false" }); const copyButton = el("button", { type: "button", className: "ai-turbo-code-copy", "aria-label": "复制整段代码" }); copyButton.textContent = "复制"; copyButton.addEventListener("click", () => { copyCodeText(copyButton, codeElement); }); const actionsWrap = el("div", { className: "ai-turbo-code-bar-actions" }, [ copyButton, toggleButton ]); const bar = el( "div", { className: currentPlatform === PLATFORMS.chatgpt ? "ai-turbo-code-bar ai-turbo-code-bar-chatgpt" : "ai-turbo-code-bar" }, [metaWrap, actionsWrap] ); const entry = { bar, anchor, langLabel, linesLabel, toggleButton, expanded: false, lastLength: initialText.length, lastMutationTime: 0, streamingTimer: null, isDisplayingStreaming: false, renderedStaticOnce: false }; if (!(anchor instanceof HTMLElement)) return; codeState.set(codeElement, entry); withSelfMutation(() => { codeElement.classList.add("ai-turbo-code-target"); anchor.insertAdjacentElement("beforebegin", bar); }); toggleButton.addEventListener("click", (event) => { event.preventDefault(); event.stopPropagation(); entry.expanded = !entry.expanded; applyFoldStyles(entry, codeElement); entry.renderedStaticOnce = false; updateCodeMeta(entry, codeElement); if (!entry.expanded) { bar.scrollIntoView({ block: "nearest", behavior: "smooth" }); } }); applyFoldStyles(entry, codeElement); updateCodeMeta(entry, codeElement); } function sweepOrphanBars() { const activeBars = new Set( Array.from(codeState.values(), (entry) => entry.bar) ); document.querySelectorAll(".ai-turbo-code-bar").forEach((bar) => { if (!activeBars.has(bar)) { bar.remove(); return; } if (bar.classList.contains("ai-turbo-code-bar-chatgpt")) return; const next = bar.nextElementSibling; const nextEntry = next instanceof HTMLElement ? codeState.get(next) : void 0; if (!(next instanceof HTMLElement) || !nextEntry || nextEntry.bar !== bar) { bar.remove(); } }); } function syncCodeBlocks(forceScan, dirtyCandidates) { if (!state.collapseCode) { for (const [codeElement] of codeState) { unmountCodeControls(codeElement); } state.foldedCodeCount = 0; codeScanRequested = false; dirtyCodeBlocks.clear(); sweepOrphanBars(); return; } for (const [codeElement] of codeState) { if (!codeElement.isConnected) { unmountCodeControls(codeElement); } } const rawCandidates = forceScan ? getCodeBlocks() : Array.from(dirtyCandidates).map(normalizeCodeElement).filter( (elem) => elem instanceof HTMLElement && elem.isConnected ); const candidates = filterOutNested(rawCandidates).filter( (element) => element instanceof HTMLElement ); for (const codeElement of candidates) { const entry = codeState.get(codeElement); if (entry) { if (currentPlatform === PLATFORMS.chatgpt && !positionCodeControl(entry, codeElement)) { continue; } updateCodeMeta(entry, codeElement); } else { mountCodeControls(codeElement); } if (codeResizeObserver) { codeResizeObserver.observe(codeElement); } } sweepOrphanBars(); state.foldedCodeCount = Array.from(codeState.values()).filter( (entry) => !entry.expanded ).length; codeScanRequested = false; dirtyCodeBlocks.clear(); } function observeCodeLayout() { if (!("ResizeObserver" in window)) return; codeResizeObserver?.disconnect(); codeResizeObserver = new ResizeObserver((entries) => { for (const resizeEntry of entries) { const normalized = normalizeCodeElement(resizeEntry.target); if (normalized instanceof HTMLElement) { dirtyCodeBlocks.add(normalized); } } if (entries.length) requestUpdate(); }); getCodeBlocks().forEach((codeElement) => { codeResizeObserver?.observe(codeElement); }); } function flushCodeBlockScan() { syncCodeBlocks(codeScanRequested, dirtyCodeBlocks); } function unmountAllCodeControls() { for (const codeElement of Array.from(codeState.keys())) { unmountCodeControls(codeElement); } } function disconnectCodeLayoutObserver() { codeResizeObserver?.disconnect(); codeResizeObserver = null; } function requestCodeScan() { codeScanRequested = true; } function markCodeBlockDirty(codeElement) { dirtyCodeBlocks.add(codeElement); } return { normalizeCodeElement, flushCodeBlockScan, unmountAllCodeControls, observeCodeLayout, disconnectCodeLayoutObserver, requestCodeScan, markCodeBlockDirty }; } // scripts/ai-chat-turbo-engine/src/core/auth.ts function hostnameMatches(hostname, domains) { return domains.some( (domain) => hostname === domain || hostname.endsWith("." + domain) ); } var AUTH_ROUTE_SEGMENTS = /* @__PURE__ */ new Set([ "auth", "auth0", "authorize", "authorization", "oauth", "oauth2", "openid", "sso", "saml", "login", "log-in", "signin", "sign-in", "sign_in", "signup", "sign-up", "sign_up", "register", "registration", "callback", "magic-link", "magiclink", "verify", "verification", "mfa", "2fa", "otp", "account", "accounts", "account-chooser", "choose-account", "switch-account", "challenge", "captcha", "consent", "redirect", "recover", "recovery", "reset-password", "forgot-password", "password" ]); var AUTH_HOSTNAME_PREFIXES = [ "auth.", "auth0.", "login.", "signin.", "accounts.", "sso." ]; var engineActive = false; function setEngineActive(active) { engineActive = active; } function isEngineActive() { return engineActive; } function isAuthOrRedirectRoute(locationLike) { const source = locationLike || window.location; if (!source) return false; const hostname = String(source.hostname || "").toLowerCase(); if (AUTH_HOSTNAME_PREFIXES.some((prefix) => hostname.startsWith(prefix))) { return true; } const pathname = String(source.pathname || "").toLowerCase(); if (!pathname) return false; return pathname.split("/").filter(Boolean).some( (segment) => AUTH_ROUTE_SEGMENTS.has(segment.replace(/\.(?:html?|php|aspx?)$/, "")) ); } function isEngineDormant() { return !engineActive || isAuthOrRedirectRoute(); } function detectPlatform() { const hostname = window.location.hostname.toLowerCase(); const pathname = window.location.pathname; if (hostnameMatches(hostname, ["chatgpt.com", "chat.openai.com"])) { return PLATFORMS.chatgpt; } if (hostnameMatches(hostname, ["gemini.google.com"])) { return PLATFORMS.gemini; } if (hostnameMatches(hostname, ["grok.com"]) || hostname === "x.com" && pathname.startsWith("/i/grok")) { return PLATFORMS.grok; } if (hostnameMatches(hostname, ["claude.ai"])) { return PLATFORMS.claude; } if (hostnameMatches(hostname, ["deepseek.com"])) { return PLATFORMS.deepseek; } if (hostnameMatches(hostname, ["copilot.microsoft.com"])) { return PLATFORMS.copilot; } if (hostnameMatches(hostname, ["perplexity.ai"])) { return PLATFORMS.perplexity; } if (hostnameMatches(hostname, ["poe.com"])) { return PLATFORMS.poe; } if (hostnameMatches(hostname, ["doubao.com"])) { return PLATFORMS.doubao; } if (hostnameMatches(hostname, ["yuanbao.tencent.com"])) { return PLATFORMS.yuanbao; } if (hostnameMatches(hostname, ["chat.qwen.ai"])) { return PLATFORMS.qwen; } if (hostnameMatches(hostname, ["qianwen.com"])) { return PLATFORMS.qianwen; } if (hostnameMatches(hostname, ["chatglm.cn"])) { return PLATFORMS.glm; } if (hostnameMatches(hostname, ["chat.z.ai"])) { return PLATFORMS.zai; } return null; } // scripts/ai-chat-turbo-engine/src/storage/reasoning-memory.ts var memoryStore = createReportedStorage("localStorage", (failure) => { const scope = failure.operation === "write" || failure.operation === "remove" ? "save reasoning memory" : "load reasoning memory"; reportRecoverableError(scope, failure.error); }); function isObjectRecord(value) { return typeof value === "object" && value !== null; } function toReasoningRecord(value) { if (!isObjectRecord(value)) return null; const mode = value["mode"]; if (mode !== "choice" && mode !== "toggle") return null; const record = { mode }; const key = value["key"]; if (typeof key === "string") record.key = key; const controlLabel = value["controlLabel"]; if (typeof controlLabel === "string") record.controlLabel = controlLabel; const option = value["option"]; if (typeof option === "string") record.option = option; const hint = value["hint"]; if (typeof hint === "string") record.hint = hint; const resultLabel = value["resultLabel"]; if (typeof resultLabel === "string") record.resultLabel = resultLabel; const label = value["label"]; if (typeof label === "string") record.label = label; const on = value["on"]; if (typeof on === "boolean") record.on = on; const ts = value["ts"]; if (typeof ts === "number") record.ts = ts; const path = value["path"]; if (Array.isArray(path)) { record.path = path.filter((part) => typeof part === "string"); } return record; } function loadReasoningMemory() { try { const raw = memoryStore.read(STORAGE_KEY_REASONING); const parsed = raw === null || raw === "" ? {} : JSON.parse(raw); if (!isObjectRecord(parsed)) return {}; const memory = {}; for (const [scope, entry] of Object.entries(parsed)) { const record = toReasoningRecord(entry); if (record) memory[scope] = record; } return memory; } catch (error) { reportRecoverableError("load reasoning memory", error); return {}; } } function saveReasoningMemory(memory) { memoryStore.writeJson(STORAGE_KEY_REASONING, memory); } function reasoningScope() { const account = location.pathname.match(/^\/u\/(\d+)(?:\/|$)/); return account ? `${location.hostname}#u${account[1]}` : location.hostname; } function readReasoningRecord(memory) { const all = memory ?? loadReasoningMemory(); const scoped = all[reasoningScope()]; if (scoped) return scoped; return all[location.hostname] ?? null; } function writeReasoningRecord(record) { const memory = loadReasoningMemory(); const scope = reasoningScope(); memory[scope] = record; if (scope !== location.hostname) delete memory[location.hostname]; saveReasoningMemory(memory); return record; } function clearReasoningRecord() { const memory = loadReasoningMemory(); delete memory[reasoningScope()]; delete memory[location.hostname]; saveReasoningMemory(memory); } // scripts/ai-chat-turbo-engine/src/core/reasoning.ts function createReasoningUtils(deps) { const { el, state, toolScope, withSelfMutation, triggerSendButton, requestUpdate, markRestoredTurn, requestFullTurnSync } = deps; let reasoningStatusNode = null; let reasoningRestoreTimer = 0; let reasoningRestoreAttempts = 0; let reasoningRestoreDone = false; let applyingReasoning = false; let restoreToken = 0; const correctedToggleAttempts = /* @__PURE__ */ new Set(); const choiceRestoreAttempts = /* @__PURE__ */ new Map(); const popupCloseTimers = []; let conversationKey = `${location.origin}${location.pathname}`; let reasoningSettleTimer = 0; let reasoningMenuTrigger = null; let reasoningMenuTriggerAt = 0; let reasoningMenuTriggerLabel = ""; function isInsideTurboUI3(node) { if (!(node instanceof Element)) return false; return Boolean(node.closest("[id^='ai-turbo-'], .ai-turbo-code-bar")); } function controlLabel(control) { const visible = String(control.innerText || "").replace(/\s+/g, " ").trim(); const raw = visible || control.getAttribute("aria-label") || control.getAttribute("title") || control.textContent || ""; return raw.replace(/\s+/g, " ").trim().slice(0, 60); } function hasPopupSemantics(control) { if (control.hasAttribute("aria-expanded")) return true; const popup = control.getAttribute("aria-haspopup"); if (popup !== null && popup !== "false") return true; if (control.hasAttribute("gemmenutrigger")) return true; if (control.hasAttribute("cdkoverlayorigin")) return true; if (control.matches("[data-radix-menu-trigger], .mat-mdc-menu-trigger")) { return true; } return false; } function explicitToggleState(control) { if (control instanceof HTMLInputElement) { if (control.type !== "checkbox" && control.type !== "radio") return null; return control.checked === true; } const input = control.querySelector( 'input[type="checkbox"], input[type="radio"]' ); if (input instanceof HTMLInputElement) return input.checked === true; const pressed = control.getAttribute("aria-pressed"); if (pressed === "true" || pressed === "false") return pressed === "true"; const checked = control.getAttribute("aria-checked"); if (checked === "true" || checked === "false") return checked === "true"; const dataState = control.getAttribute("data-state"); if (dataState === "on" || dataState === "checked" || dataState === "active") { return true; } if (dataState === "off" || dataState === "unchecked" || dataState === "inactive") { return false; } return null; } function controlOnState(control) { const explicit = explicitToggleState(control); if (explicit !== null) return explicit; if (hasPopupSemantics(control)) return null; const dataState = control.getAttribute("data-state"); if (dataState !== null && dataState !== "") { return /^(selected|true)$/i.test(dataState) ? true : null; } const cls = control.className; if (/(^|[\s_-])(active|selected|checked|is-on)([\s_-]|$)/i.test(cls)) return true; return null; } function controlKey(control) { const raw = control.getAttribute("data-test-id") || control.getAttribute("data-testid") || control.id || control.getAttribute("aria-label") || ""; return String(raw).replace(/\s+/g, " ").trim().slice(0, 60); } function toggleAttemptKey(control, desired) { const identity = controlKey(control) || controlLabel(control) || "reasoning-toggle"; return `${conversationKey}|${identity}|${desired ? "on" : "off"}`; } function choiceAttemptKey(control, saved) { const path = Array.isArray(saved.path) ? saved.path.join(">") : ""; return `${conversationKey}|${controlKey(control)}|${saved.option || ""}|${path}`; } function syncConversationScope() { const nextKey = `${location.origin}${location.pathname}`; if (nextKey === conversationKey) return; conversationKey = nextKey; correctedToggleAttempts.clear(); choiceRestoreAttempts.clear(); } function clickControlOnce(control) { try { control.click(); return true; } catch (error) { reportRecoverableError("restore reasoning control", error); return false; } } function beginRestore() { restoreToken += 1; applyingReasoning = false; return restoreToken; } function restoreIsStale(token) { return token !== restoreToken; } function settleToggleCorrection(control, desired, token) { let attempts = 0; const check = () => { reasoningSettleTimer = 0; if (restoreIsStale(token)) return; attempts += 1; const current = controlOnState(control); if (current === desired || attempts >= 8 || !control.isConnected) { applyingReasoning = false; return; } reasoningSettleTimer = window.setTimeout(check, 100); }; check(); } function isDropdownTrigger(control) { if (control.hasAttribute("aria-expanded")) return true; const popup = control.getAttribute("aria-haspopup"); if (popup !== null && popup !== "false") return true; if (control.hasAttribute("gemmenutrigger") || control.hasAttribute("cdkoverlayorigin")) return true; if (control.matches("[data-state], [data-radix-menu-trigger], .mat-mdc-menu-trigger")) return true; const label = control.getAttribute("aria-label") || ""; return /^(open|选择|打开).{0,20}(picker|menu|mode|model)/i.test(label.trim()); } function dispatchEscape() { const esc = new KeyboardEvent("keydown", { key: "Escape", code: "Escape", keyCode: 27, bubbles: true, cancelable: true }); if (document.activeElement) document.activeElement.dispatchEvent(esc); document.dispatchEvent(esc); } function closeOpenPopup(control = null) { dispatchEscape(); const trigger = control ?? reasoningMenuTrigger; if (!trigger || !trigger.isConnected) return; const settle = (remaining) => { if (!trigger.isConnected) return; if (trigger.getAttribute("aria-expanded") !== "true") return; if (!clickControlOnce(trigger)) return; if (remaining <= 1) return; const timer2 = window.setTimeout(() => { const index = popupCloseTimers.indexOf(timer2); if (index >= 0) popupCloseTimers.splice(index, 1); settle(remaining - 1); }, 160); popupCloseTimers.push(timer2); }; const timer = window.setTimeout(() => { const index = popupCloseTimers.indexOf(timer); if (index >= 0) popupCloseTimers.splice(index, 1); settle(3); }, 120); popupCloseTimers.push(timer); } function popupRootFor(control) { const id = control.getAttribute("aria-controls"); const byId = id ? document.getElementById(id) : null; if (byId) return byId; const owner = control.closest(REASONING_MENU_SELECTOR); return owner instanceof HTMLElement ? owner : null; } function hasVisibleMenu() { return Array.from(document.querySelectorAll(REASONING_MENU_SELECTOR)).some( (node) => !isInsideTurboUI3(node) && nodeVisible3(node) ); } function rowScopedText(node, selector) { if (!(node instanceof Element)) return ""; const part = Array.from( node.querySelectorAll(selector) ).find((candidate) => { if (isInsideTurboUI3(candidate) || !nodeVisible3(candidate)) return false; const owner = candidate.closest( "gem-menu-item, [role='menuitem'], [role='menuitemradio'], [role='option'], [role='radio']" ); return owner === node; }); return part ? String(part.innerText || "").replace(/\s+/g, " ").trim() : ""; } function rowLabel(node) { const structured = rowScopedText(node, ".label"); if (structured) return structured; const line = (node.innerText || "").split("\n").find((part) => part.trim()); return line ? line.replace(/\s+/g, " ").trim() : ""; } function rowHint(node) { const structured = rowScopedText(node, ".sublabel"); if (structured) return structured; const lines = (node.innerText || "").split("\n").map((part) => part.replace(/\s+/g, " ").trim()).filter(Boolean); return lines[1] || ""; } function choiceRowSelected(node) { if (!(node instanceof Element)) return null; const checked = node.getAttribute("aria-checked"); if (checked !== null && checked !== "") return checked === "true"; const selected = node.getAttribute("aria-selected"); if (selected !== null && selected !== "") return selected === "true"; const dataState = node.getAttribute("data-state"); if (dataState === "checked" || dataState === "selected" || dataState === "on") return true; if (dataState === "unchecked" || dataState === "unselected" || dataState === "off") return false; if (node.matches(".selected, .checked")) return true; if (node.querySelector( ".selected, .checked, [aria-label='Selected'], [aria-label='selected'], [aria-label='已选中'], [data-state='checked'], [data-mat-icon-name='check']" )) { return true; } return null; } function menuHasSelectionState(menu) { if (!menu) return false; return Boolean( menu.querySelector( "[aria-checked], [aria-selected], [role='menuitemradio'], [role='radio'], .selected, .checked, [aria-label='Selected'], [aria-label='已选中'], [data-mat-icon-name='check']" ) ); } function nodeVisible3(node) { if (!(node instanceof HTMLElement)) return false; const rect = node.getBoundingClientRect(); return rect.width >= 1 && rect.height >= 1; } function choiceRowIsSelected(row) { const explicit = choiceRowSelected(row); if (explicit !== null) return explicit; const menu = row.closest(REASONING_MENU_SELECTOR); return menu && menuHasSelectionState(menu) ? false : null; } function choicePathForRow(row) { const path = []; let menu = row.closest(REASONING_MENU_SELECTOR); let depth = 0; while (menu && depth < 5) { const menuId = menu.id; if (!menuId) break; const parent = Array.from( document.querySelectorAll("[aria-controls]") ).find( (node) => { if (isInsideTurboUI3(node) || !nodeVisible3(node)) return false; if (node.getAttribute("aria-controls") !== menuId) return false; const popup = node.getAttribute("aria-haspopup"); if (popup === null || popup === "false") return false; const owner2 = node.closest(REASONING_MENU_SELECTOR); return Boolean(owner2 && owner2 !== menu); } ); if (!parent) break; const owner = parent.closest(REASONING_MENU_SELECTOR); if (!owner || owner === menu) break; const label = rowLabel(parent); if (label) path.unshift(label); menu = owner; depth += 1; } return path; } function choiceRowForTarget(target) { const row = target.closest( "gem-menu-item, [role='menuitem'], [role='menuitemradio'], [role='option'], [aria-checked], [aria-selected]" ); if (!(row instanceof HTMLElement) || !row.closest(REASONING_MENU_SELECTOR)) { return null; } const popup = row.getAttribute("aria-haspopup"); if (popup !== null && popup !== "false") return null; return rowLabel(row) ? row : null; } function findPathParent(menu, label) { if (!menu || !label) return null; const parents = Array.from( menu.querySelectorAll("[aria-haspopup]:not([aria-haspopup='false'])") ).filter((node) => { if (!(node instanceof HTMLElement)) return false; if (isInsideTurboUI3(node) || !nodeVisible3(node)) return false; const owner = node.closest("[role='menu']"); if (owner && owner !== menu && menu.contains(owner)) return false; return rowLabel(node) === label; }); return parents[0] || null; } function findExactChoiceRow(menu, option) { if (!menu || !option) return null; const rows = Array.from( menu.querySelectorAll(CHOICE_OPTION_SELECTOR) ).filter( (node) => { if (isInsideTurboUI3(node) || !nodeVisible3(node)) return false; if (node.closest(REASONING_MENU_SELECTOR) !== menu) return false; const popup = node.getAttribute("aria-haspopup"); if (popup !== null && popup !== "false") return false; return rowLabel(node) === option; } ); return rows.reduce((deepest, node) => { if (!deepest) return node; return deepest.contains(node) ? node : deepest; }, null); } function submenuForParent(parent) { const id = parent.getAttribute("aria-controls"); const menu = id ? document.getElementById(id) : null; return menu && nodeVisible3(menu) ? menu : null; } function choiceLooksApplied(saved, control) { const label = controlLabel(control).toLowerCase(); if (!label) return false; if (saved.resultLabel && label === String(saved.resultLabel).toLowerCase()) { return true; } const option = String(saved.option || "").trim(); if (!option) return false; if (/\bcurrently\s+/i.test(option)) { const tail = option.replace(/^.*\bcurrently\s+/i, "").trim().toLowerCase(); return Boolean(tail) && (label === tail || label.endsWith(` ${tail}`)); } const expected = option.toLowerCase(); return label === expected || label.endsWith(` ${expected}`); } function choiceTokens(saved) { const option = String(saved.option || "").trim(); if (Array.isArray(saved.path) && saved.path.length) { return [...saved.path, option].map((part) => String(part).trim()).filter(Boolean); } const currentValue = option.replace(/^.*\bcurrently\s+/i, "").trim(); return currentValue.split(/\s+/).filter(Boolean); } function upgradeChoiceRecord(saved, control, info) { const stableKey = controlKey(control); if (!stableKey || !info || !info.option) return; const samePath = JSON.stringify(Array.isArray(saved.path) ? saved.path : []) === JSON.stringify(info.path); if (saved.key === stableKey && saved.option === info.option && samePath) return; const labelNow = controlLabel(control); writeReasoningRecord({ mode: "choice", key: stableKey, controlLabel: saved.controlLabel || "", path: info.path, option: info.option, hint: info.hint || "", resultLabel: labelNow || saved.resultLabel || "", ts: Date.now() }); renderReasoningStatus(); } function findRowIn(root, token) { if (!root || !token) return null; const rows = Array.from( root.querySelectorAll(CHOICE_OPTION_SELECTOR) ).filter((node) => { if (isInsideTurboUI3(node)) return false; const rect = node.getBoundingClientRect(); return rect.width >= 1 && rect.height >= 1; }); const exact = rows.filter((node) => rowLabel(node) === token); if (exact.length) { return exact.reduce((best, node) => best.contains(node) ? node : best); } const tail = rows.filter((node) => rowLabel(node).endsWith(token)); if (tail.length === 1) return tail[0]; const head = rows.filter((node) => rowLabel(node).startsWith(`${token} `)); return head.length === 1 ? head[0] : null; } function interactiveTarget(node) { if (node.matches("button, a, [role='menuitemradio'], [role='radio']")) return node; const inner = node.querySelector("button, a"); return inner instanceof HTMLElement ? inner : node; } function findRowInOpenMenus(token) { const menus = Array.from( document.querySelectorAll(REASONING_MENU_SELECTOR) ).filter((node) => { if (isInsideTurboUI3(node) || toolScope.isInside(node)) return false; const rect = node.getBoundingClientRect(); return rect.width >= 1 && rect.height >= 1; }); for (let i = menus.length - 1; i >= 0; i -= 1) { const row = findRowIn(menus[i], token); if (row) return row; } return null; } function findSubmenuParent(root, token) { if (!root) return null; const parents = Array.from( root.querySelectorAll("[aria-haspopup]:not([aria-haspopup='false'])") ).filter((node) => { if (!(node instanceof HTMLElement)) return false; if (isInsideTurboUI3(node)) return false; const owner = node.closest("[role='menu']"); if (owner && owner !== root && root.contains(owner)) return false; const rect = node.getBoundingClientRect(); return rect.width >= 1 && rect.height >= 1; }); if (!parents.length) return null; const loaded = parents.find((parent) => { const sub = document.getElementById(parent.getAttribute("aria-controls") || ""); return sub ? Boolean(findRowIn(sub, token)) : false; }); return loaded || (parents.length === 1 ? parents[0] : null); } function choiceRowInfo(row) { if (!row || !row.isConnected) return null; const option = rowLabel(row); if (!option) return null; return { option, hint: rowHint(row), path: choicePathForRow(row) }; } function restorePathChoice(saved, control, onSettled, token) { const path = (Array.isArray(saved.path) ? saved.path : []).map((part) => String(part).trim()).filter(Boolean); const option = String(saved.option || "").trim(); if (!option) { onSettled(false, false); return; } let settled = false; let lastRow = null; const finish = (ok, conclusive) => { if (settled) return; settled = true; if (restoreIsStale(token)) return; const info = ok ? choiceRowInfo(lastRow) : null; window.setTimeout(() => closeOpenPopup(control), 100); if (info) { window.setTimeout(() => { if (control.isConnected) upgradeChoiceRecord(saved, control, info); }, 300); } applyingReasoning = false; onSettled(ok, conclusive === true); }; const waitForSubmenu = (parent, done, attempt) => { if (settled || restoreIsStale(token)) return; const sub = submenuForParent(parent); if (sub) { done(sub); return; } if (attempt >= 10) { done(null); return; } window.setTimeout(() => waitForSubmenu(parent, done, attempt + 1), 180); }; const walk = (menu, index, done, fail) => { if (settled || restoreIsStale(token)) return; if (!menu) { fail(false); return; } if (index >= path.length) { const row = findExactChoiceRow(menu, option); if (row) done(row); else fail(true); return; } const parent = findPathParent(menu, path[index]); if (!parent) { fail(true); return; } parent.dispatchEvent( new PointerEvent("pointerover", { bubbles: true, cancelable: true, view: window }) ); parent.dispatchEvent(new MouseEvent("mouseenter", { view: window })); triggerSendButton(interactiveTarget(parent)); waitForSubmenu(parent, (sub) => { if (!sub) { fail(false); return; } walk(sub, index + 1, done, fail); }, 0); }; const openRoot = (done, attempt) => { if (settled || restoreIsStale(token)) return; const root = popupRootFor(control); if (root && nodeVisible3(root)) { done(root); return; } const fallback = Array.from( document.querySelectorAll(REASONING_MENU_SELECTOR) ).find((node) => !isInsideTurboUI3(node) && nodeVisible3(node)); if (fallback) { done(fallback); return; } if (attempt >= 10) { finish(false, false); return; } if (attempt === 0) triggerSendButton(interactiveTarget(control)); window.setTimeout(() => openRoot(done, attempt + 1), 180); }; const verifySelection = () => { window.setTimeout(() => { if (settled) return; if (restoreIsStale(token)) return; closeOpenPopup(control); window.setTimeout(() => { if (settled) return; openRoot((menu) => { walk( menu, 0, (row) => { lastRow = row; const selected = choiceRowIsSelected(row); if (selected === true) finish(true); else if (selected === false) finish(false); else finish(choiceLooksApplied(saved, control)); }, (conclusive) => finish(false, conclusive === true) ); }, 0); }, 220); }, 260); }; applyingReasoning = true; openRoot((menu) => { walk( menu, 0, (row) => { lastRow = row; const selected = choiceRowIsSelected(row); if (selected === true) { finish(true); return; } if (selected === null && choiceLooksApplied(saved, control)) { finish(true); return; } triggerSendButton(interactiveTarget(row)); verifySelection(); }, (conclusive) => finish(false, conclusive === true) ); }, 0); } function restoreChoice(saved, control, onSettled, restoreId) { const tokens = choiceTokens(saved); if (!tokens.length) { onSettled(false, false); return; } let index = 0; let settled = false; let lastRow = null; const finish = (ok, conclusive) => { if (settled) return; settled = true; if (restoreIsStale(restoreId)) return; const info = ok ? choiceRowInfo(lastRow) : null; window.setTimeout(() => closeOpenPopup(control), 100); if (info) { window.setTimeout(() => { if (control.isConnected) upgradeChoiceRecord(saved, control, info); }, 300); } applyingReasoning = false; onSettled(ok, conclusive === true); }; const step = (attempt) => { if (settled || restoreIsStale(restoreId)) return; const token = tokens[index]; const root = popupRootFor(control); const hit = findRowIn(root, token) || findRowInOpenMenus(token); if (hit) { lastRow = hit; triggerSendButton(interactiveTarget(hit)); next(); return; } const parent = findSubmenuParent(root, token); if (parent) { parent.dispatchEvent( new PointerEvent("pointerover", { bubbles: true, cancelable: true, view: window }) ); parent.dispatchEvent(new MouseEvent("mouseenter", { view: window })); triggerSendButton(interactiveTarget(parent)); const lookInSub = (deep) => { if (settled || restoreIsStale(restoreId)) return; const sub = document.getElementById(parent.getAttribute("aria-controls") || ""); const row = findRowIn(sub, token) || findRowIn(popupRootFor(control), token) || findRowInOpenMenus(token); if (row) { lastRow = row; triggerSendButton(interactiveTarget(row)); next(); return; } if (deep >= 6) { closeOpenPopup(control); finish(false, true); return; } window.setTimeout(() => lookInSub(deep + 1), 200); }; window.setTimeout(() => lookInSub(0), 250); return; } if (attempt >= 8) { const menuWasOpen = hasVisibleMenu(); closeOpenPopup(control); finish(false, menuWasOpen); return; } window.setTimeout(() => step(attempt + 1), 250); }; const next = () => { index += 1; if (index >= tokens.length) { finish(true); return; } closeOpenPopup(control); window.setTimeout(() => { triggerSendButton(interactiveTarget(control)); window.setTimeout(() => step(0), 350); }, 200); }; applyingReasoning = true; triggerSendButton(interactiveTarget(control)); window.setTimeout(() => step(0), 350); } function observeControlChoice(control, labelBefore, startedAt) { [400, 900, 1600, 2600].forEach((delay) => { window.setTimeout(() => { if (applyingReasoning || !control.isConnected) return; const labelNow = controlLabel(control); if (!labelNow || labelNow === labelBefore) return; const memory = loadReasoningMemory(); const saved = readReasoningRecord(memory); if (saved && saved.mode === "choice") { if (startedAt && saved.ts && saved.ts >= startedAt) return; if (saved.option === labelNow) return; } const root = popupRootFor(control); if (!hasVisibleMenu() && !(root && nodeVisible3(root))) return; writeReasoningRecord({ mode: "choice", key: controlKey(control), controlLabel: labelBefore, option: labelNow, ts: Date.now() }); renderReasoningStatus(); }, delay); }); } function captureChoiceResult(trigger, record) { [300, 700, 1400, 2400].forEach((delay) => { window.setTimeout(() => { if (applyingReasoning || !trigger.isConnected) return; const labelNow = controlLabel(trigger); if (!labelNow || labelNow === record.controlLabel) return; const memory = loadReasoningMemory(); const saved = readReasoningRecord(memory); if (!saved || saved.mode !== "choice" || saved.ts !== record.ts) return; if (saved.resultLabel === labelNow) return; saved.resultLabel = labelNow; saveReasoningMemory(memory); renderReasoningStatus(); }, delay); }); } function pairOptionClick(target) { if (isToolControlElement(target) || toolScope.isInside(target)) return false; const row = choiceRowForTarget(target); if (!row) return false; const trigger = reasoningMenuTrigger; if (!trigger || !trigger.isConnected) return false; if (Date.now() - reasoningMenuTriggerAt > 2e4) return false; if (row === trigger || row.contains(trigger)) return false; const optionText = rowLabel(row); if (!optionText) return false; const menu = row.closest(REASONING_MENU_SELECTOR); const path = choicePathForRow(row); const explicitChoice = row.matches(CHOICE_RADIO_SELECTOR); if (!explicitChoice && !(path.length && menuHasSelectionState(menu))) { return false; } const triggerLabel = reasoningMenuTriggerLabel; const hint = rowHint(row); const ts = Date.now(); const record = { mode: "choice", key: controlKey(trigger), controlLabel: triggerLabel, path, option: optionText, hint, ts }; window.setTimeout(() => { if (applyingReasoning) return; writeReasoningRecord(record); renderReasoningStatus(); captureChoiceResult(trigger, record); }, 0); return true; } function handleReasoningClick(event) { if (isEngineDormant()) return; if (!state.rememberReasoning || applyingReasoning) return; const target = event.target; if (!(target instanceof Element) || isInsideTurboUI3(target)) return; if (isToolControlElement(target) || toolScope.isInside(target)) return; if (pairOptionClick(target)) return; if (target.closest(REASONING_MENU_SELECTOR)) return; const control = target.closest(REASONING_CONTROL_SELECTOR); if (!(control instanceof HTMLElement)) return; const startedAt = Date.now(); const labelBefore = controlLabel(control); if (!labelBefore) return; const keywordMatch = REASONING_CONTROL_PATTERN.test(labelBefore); if (!keywordMatch && !isDropdownTrigger(control)) return; reasoningMenuTrigger = control; reasoningMenuTriggerAt = Date.now(); reasoningMenuTriggerLabel = labelBefore; if (keywordMatch) { window.setTimeout(() => { if (applyingReasoning || !control.isConnected) return; const on = controlOnState(control); if (on === null) return; writeReasoningRecord({ mode: "toggle", label: labelBefore, on, ts: Date.now() }); renderReasoningStatus(); }, 0); } if (keywordMatch && explicitToggleState(control) !== null) return; observeControlChoice(control, labelBefore, startedAt); } function handleDehydratedClick(event) { if (isEngineDormant()) return; const target = event.target; if (!(target instanceof Element)) return; const turnElement = target.closest(".ai-turbo-dehydrated"); if (!(turnElement instanceof HTMLElement)) return; markRestoredTurn(turnElement); withSelfMutation(() => { turnElement.classList.remove("ai-turbo-dehydrated"); turnElement.style.removeProperty("--turbo-cached-h"); }); requestFullTurnSync(); requestUpdate(); } function renderReasoningStatus() { if (!reasoningStatusNode) return; reasoningStatusNode.textContent = ""; if (!state.rememberReasoning) { reasoningStatusNode.textContent = "推理记忆:已关闭"; return; } const saved = readReasoningRecord(); if (!saved || !saved.mode) { reasoningStatusNode.textContent = "推理记忆:未记录(在页面里点一次强度/模型选项即可)"; return; } const pathText = saved.mode === "choice" && Array.isArray(saved.path) && saved.path.length ? `${saved.path.join(" / ")} / ` : ""; const shown = saved.mode === "choice" ? `${saved.controlLabel || "控件"} → ${pathText}${saved.option}` : `${saved.label}(${saved.on ? "开" : "关"})`; reasoningStatusNode.textContent = `推理记忆:${shown} `; reasoningStatusNode.appendChild( el( "button", { type: "button", onclick: () => { clearReasoningRecord(); renderReasoningStatus(); } }, ["清除"] ) ); } function findRememberedControl(saved) { const visible = Array.from( document.querySelectorAll(REASONING_CONTROL_SELECTOR) ).filter( (node) => !isInsideTurboUI3(node) && !toolScope.isInside(node) && !isToolControlElement(node) && nodeVisible3(node) ); if (saved.key) { const byKey = visible.find((node) => controlKey(node) === saved.key); if (byKey) return byKey; } if (/,\s*currently\b/i.test(saved.key || "")) { const prefix = String(saved.key).split(/,\s*currently\b/i)[0].trim(); const byAccessibleName = visible.find((node) => { const ariaLabel = node.getAttribute("aria-label") || ""; return ariaLabel === saved.key || ariaLabel.startsWith(`${prefix},`); }); if (byAccessibleName) return byAccessibleName; } if (saved.controlLabel) { const byLabel = visible.find((node) => controlLabel(node) === saved.controlLabel); if (byLabel) return byLabel; const byLabelPrefix = visible.find( (node) => controlLabel(node).startsWith(`${saved.controlLabel} `) ); if (byLabelPrefix) return byLabelPrefix; } return visible.find((node) => REASONING_CONTROL_PATTERN.test(controlLabel(node))) || null; } function applyReasoningMemory() { syncConversationScope(); if (isEngineDormant()) { reasoningRestoreDone = true; return; } const saved = readReasoningRecord(); if (!saved || !saved.mode) { reasoningRestoreDone = true; return; } const control = findRememberedControl(saved); if (!control) return; if (applyingReasoning) return; const stableKey = controlKey(control); if (saved.mode === "choice" && stableKey && saved.key !== stableKey) { saved.key = stableKey; writeReasoningRecord(saved); } if (saved.mode === "choice" && /,\s*currently\b/i.test(saved.option || "")) { const normalized = String(saved.option).replace(/^.*\bcurrently\s+/i, "").trim(); if (normalized) { saved.option = normalized; writeReasoningRecord(saved); } } if (saved.mode === "choice" && saved.option) { if (choiceLooksApplied(saved, control)) { reasoningRestoreDone = true; return; } const attemptKey2 = choiceAttemptKey(control, saved); const attempts = choiceRestoreAttempts.get(attemptKey2) ?? 0; if (attempts >= 2) { reasoningRestoreDone = true; return; } choiceRestoreAttempts.set(attemptKey2, attempts + 1); const token2 = beginRestore(); const restore = Array.isArray(saved.path) ? restorePathChoice : restoreChoice; restore(saved, control, (ok, conclusive) => { reasoningRestoreDone = ok || conclusive === true; if (attempts + 1 >= 2) reasoningRestoreDone = true; }, token2); return; } reasoningRestoreDone = true; if (saved.mode !== "toggle") return; const now = controlOnState(control); if (now === null || now === (saved.on === true)) return; const desired = saved.on === true; const attemptKey = toggleAttemptKey(control, desired); if (correctedToggleAttempts.has(attemptKey)) return; correctedToggleAttempts.add(attemptKey); const token = beginRestore(); applyingReasoning = true; if (!clickControlOnce(control)) { applyingReasoning = false; return; } settleToggleCorrection(control, desired, token); } function clearReasoningRestoreTimer() { window.clearInterval(reasoningRestoreTimer); reasoningRestoreTimer = 0; window.clearTimeout(reasoningSettleTimer); reasoningSettleTimer = 0; for (const timer of popupCloseTimers.splice(0)) window.clearTimeout(timer); restoreToken += 1; applyingReasoning = false; } function scheduleReasoningRestore() { clearReasoningRestoreTimer(); syncConversationScope(); reasoningRestoreDone = false; reasoningRestoreAttempts = 0; if (isEngineDormant()) return; if (!state.rememberReasoning) return; if (!readReasoningRecord()) return; reasoningRestoreTimer = window.setInterval(() => { reasoningRestoreAttempts += 1; applyReasoningMemory(); if (reasoningRestoreDone || reasoningRestoreAttempts >= 120) { clearReasoningRestoreTimer(); } }, 500); } function attachStatusNode(node) { reasoningStatusNode = node; } return { handleReasoningClick, handleDehydratedClick, renderReasoningStatus, applyReasoningMemory, clearReasoningRestoreTimer, scheduleReasoningRestore, attachStatusNode }; } // scripts/ai-chat-turbo-engine/src/storage/tool-memory.ts var toolStore = createReportedStorage("localStorage", (failure) => { const scope = failure.operation === "write" || failure.operation === "remove" ? "save tool memory" : "load tool memory"; reportRecoverableError(scope, failure.error); }); var MAX_TOOLS = 40; var MAX_LABEL = 120; var MAX_APPLICATION_ID = 120; function cleanLabel(raw) { if (typeof raw !== "string") return ""; return raw.replace(/\s+/g, " ").trim().slice(0, MAX_LABEL); } function toToolRecord(value) { if (!isObjectRecord(value)) return null; const key = cleanLabel(value["key"]); const applicationId = cleanLabel(value["applicationId"]).slice(0, MAX_APPLICATION_ID); const label = cleanLabel(value["label"]); const selectedRaw = value["selected"]; const legacyLabels = []; if (Array.isArray(selectedRaw)) { for (const entry of selectedRaw) { const legacy = cleanLabel(entry); if (!legacy || legacyLabels.includes(legacy)) continue; legacyLabels.push(legacy); if (legacyLabels.length >= MAX_TOOLS) break; } } if (!key || !applicationId && !label && !legacyLabels.length) return null; const controlLabel = cleanLabel(value["controlLabel"]); const ts = value["ts"]; return { key, controlLabel, applicationId, label: label || legacyLabels[0] || "", legacyLabels, ts: typeof ts === "number" && Number.isFinite(ts) ? ts : 0 }; } function loadToolMemory() { try { const raw = toolStore.read(STORAGE_KEY_TOOL_MEMORY); const parsed = raw === null || raw === "" ? {} : JSON.parse(raw); if (!isObjectRecord(parsed)) return {}; const memory = {}; for (const [scope, entry] of Object.entries(parsed)) { const record = toToolRecord(entry); if (record) memory[scope] = record; } return memory; } catch (error) { reportRecoverableError("load tool memory", error); return {}; } } function saveToolMemory(memory) { toolStore.writeJson(STORAGE_KEY_TOOL_MEMORY, memory); } function readToolRecord(memory) { const all = memory ?? loadToolMemory(); const scoped = all[reasoningScope()]; if (scoped) return scoped; return all[location.hostname] ?? null; } function writeToolRecord(record) { const memory = loadToolMemory(); const scope = reasoningScope(); memory[scope] = record; if (scope !== location.hostname) delete memory[location.hostname]; saveToolMemory(memory); return record; } function clearToolRecord() { const memory = loadToolMemory(); delete memory[reasoningScope()]; delete memory[location.hostname]; saveToolMemory(memory); } // scripts/ai-chat-turbo-engine/src/core/tool-memory.ts var POLL_INTERVAL = 350; var MAX_POLLS = 80; var MENU_WAIT_INTERVAL = 120; var MENU_WAIT_ATTEMPTS = 12; var MAX_RESTORE_ATTEMPTS = 6; var RECORD_DELAYS = [120, 320, 700, 1200]; var VERIFY_DELAYS = [150, 400, 800, 1400]; function cleanText(raw) { return raw.replace(/\s+/g, " ").trim().slice(0, 120); } function nodeVisible(node) { const rect = node.getBoundingClientRect(); return rect.width >= 1 && rect.height >= 1; } function isInsideTurboUI(node) { return Boolean(node.closest("[id^='ai-turbo-'], .ai-turbo-code-bar")); } function applicationIdOf(node) { return cleanText(node.getAttribute("data-application-id") || ""); } function toolLabel(node) { const aria = cleanText(node.getAttribute("aria-label") || ""); if (aria) return aria; const visible = node.querySelector("[data-input-label='tools']"); if (visible instanceof HTMLElement) { const label = cleanText(visible.textContent || ""); if (label) return label; } return cleanText(node.textContent || ""); } function chipRecord(node) { if (!nodeVisible(node)) return null; const applicationId = applicationIdOf(node); if (!applicationId) return null; const labelNode = node.querySelector("span > span"); const label = labelNode instanceof HTMLElement ? cleanText(labelNode.textContent || "") : ""; return { applicationId, label, node }; } function currentChip() { const chips = Array.from( document.querySelectorAll(ATOMIC_TOOL_CHIP_SELECTOR) ).filter((node) => !isInsideTurboUI(node) && nodeVisible(node)); for (const chip of chips) { const record = chipRecord(chip); if (record) return record; } return null; } function matchesSaved(tool, saved) { if (saved.applicationId) return tool.applicationId === saved.applicationId; const expected = saved.label || saved.legacyLabels[0] || ""; return Boolean(expected) && tool.label === expected; } function collectTools(nodes) { const tools = []; for (const node of nodes) { if (isInsideTurboUI(node) || !nodeVisible(node)) continue; const applicationId = applicationIdOf(node); if (!applicationId) continue; tools.push({ applicationId, label: toolLabel(node), node }); } return tools; } function inlineTools() { const items = Array.from( document.querySelectorAll(ATOMIC_TOOL_ITEM_SELECTOR) ).filter((node) => !node.closest("[role='menu']")); return collectTools(items); } function menuTools() { return collectTools( document.querySelectorAll( `${ATOMIC_TOOL_MENU_SELECTOR} [role='menuitem'][data-application-id]` ) ); } function overflowTrigger() { const actions = document.querySelectorAll(ATOMIC_ACTIONS_SELECTOR); for (const action of actions) { if (isInsideTurboUI(action) || !nodeVisible(action)) continue; const candidates = Array.from( action.querySelectorAll("button[aria-expanded]") ).filter((node) => !node.hasAttribute("data-application-id")); const trigger = candidates.find((node) => nodeVisible(node)); if (trigger) return trigger; } return null; } function atomicToolbarPresent() { return Array.from( document.querySelectorAll(ATOMIC_ACTIONS_SELECTOR) ).some((node) => !isInsideTurboUI(node) && nodeVisible(node)); } function findTool(tools, saved) { if (saved.applicationId) { const byId = tools.find((tool) => tool.applicationId === saved.applicationId); if (byId) return byId; } const expected = saved.label || saved.legacyLabels[0] || ""; if (!expected) return null; return tools.find((tool) => tool.label === expected) ?? null; } function createToolMemoryUtils(deps) { const { el, state, triggerSendButton } = deps; let statusNode = null; let pollTimer = 0; let pollCount = 0; let stepTimer = 0; const recordTimers = []; const verifyTimers = []; let restoreToken = 0; let restoring = false; let restoreDone = false; let restoreAttempts = 0; let openedOverflow = null; let actionStatus = ""; function stopPolling() { window.clearInterval(pollTimer); pollTimer = 0; pollCount = 0; } function clearTimers(list) { for (const timer of list.splice(0)) window.clearTimeout(timer); } function click(control, scope) { try { return triggerSendButton(control); } catch (error) { reportRecoverableError(scope, error); return false; } } function closeOverflow() { const trigger = openedOverflow; openedOverflow = null; if (!trigger || !trigger.isConnected) return; if (trigger.getAttribute("aria-expanded") !== "true") return; click(trigger, "close tool overflow menu"); } function finishRestore(token, status) { if (token !== restoreToken) return; restoring = false; restoreDone = true; closeOverflow(); actionStatus = status; renderStatus(); } function persistChip(tool) { if (!tool) { clearToolRecord(); actionStatus = "当前没有选中任何工具"; renderStatus(); return; } const saved = readToolRecord(); if (saved && saved.applicationId === tool.applicationId && saved.label === tool.label) { return; } writeToolRecord({ key: "atomic-actions", controlLabel: "工具", applicationId: tool.applicationId, label: tool.label, legacyLabels: tool.label ? [tool.label] : [], ts: Date.now() }); actionStatus = tool.label ? `已记录 ${tool.label}` : `已记录 ${tool.applicationId}`; renderStatus(); } function scheduleRecordCapture(applicationId, label, removing) { clearTimers(recordTimers); let confirmed = false; for (const [index, delay] of RECORD_DELAYS.entries()) { const timer = window.setTimeout(() => { const position = recordTimers.indexOf(timer); if (position >= 0) recordTimers.splice(position, 1); if (isEngineDormant() || !state.rememberTools || confirmed) return; const chip = currentChip(); if (!removing && chip) { if (chip.applicationId === applicationId || index === RECORD_DELAYS.length - 1) { confirmed = true; persistChip(chip); } return; } if (removing && !chip) { confirmed = true; persistChip(null); return; } if (index === RECORD_DELAYS.length - 1) { actionStatus = label ? `未确认 ${label} 的选择,已保留原记录` : "未确认工具选择,已保留原记录"; renderStatus(); } }, delay); recordTimers.push(timer); } } function handleToolClick(event) { if (isEngineDormant()) return; const target = event.target; if (!(target instanceof Element) || isInsideTurboUI(target)) return; const chip = target.closest(ATOMIC_TOOL_CHIP_SELECTOR); if (chip instanceof HTMLElement) { if (restoring || !target.closest("button")) return; const info = chipRecord(chip); scheduleRecordCapture(info?.applicationId || "", info?.label || "", true); return; } if (restoring || !state.rememberTools) return; const item = target.closest(ATOMIC_TOOL_ITEM_SELECTOR); if (!(item instanceof HTMLElement)) return; const applicationId = applicationIdOf(item); if (!applicationId) return; scheduleRecordCapture(applicationId, toolLabel(item), false); } function verifyRestored(token, saved, attemptsLeft) { clearTimers(verifyTimers); for (const [index, delay] of VERIFY_DELAYS.entries()) { const timer = window.setTimeout(() => { const position = verifyTimers.indexOf(timer); if (position >= 0) verifyTimers.splice(position, 1); if (token !== restoreToken) return; const chip = currentChip(); if (chip && matchesSaved(chip, saved)) { clearTimers(verifyTimers); writeToolRecord({ key: "atomic-actions", controlLabel: "工具", applicationId: chip.applicationId, label: chip.label || saved.label, legacyLabels: chip.label ? [chip.label] : saved.legacyLabels, ts: Date.now() }); finishRestore( token, `已恢复 ${chip.label || saved.label || saved.applicationId}` ); return; } if (index !== VERIFY_DELAYS.length - 1) return; restoring = false; closeOverflow(); if (attemptsLeft > 1) return; finishRestore(token, "未能恢复已记录的工具"); }, delay); verifyTimers.push(timer); } } function tryRestore(saved, token) { restoreAttempts += 1; const chip = currentChip(); if (chip && matchesSaved(chip, saved)) { finishRestore(token, `已恢复 ${chip.label || saved.label || saved.applicationId}`); return; } const attemptsLeft = MAX_RESTORE_ATTEMPTS - restoreAttempts + 1; const inline = findTool(inlineTools(), saved); if (inline) { if (!click(inline.node, "select atomic tool")) { restoring = false; return; } verifyRestored(token, saved, attemptsLeft); return; } const openMenuTool = findTool(menuTools(), saved); if (openMenuTool) { if (!click(openMenuTool.node, "select atomic overflow tool")) { restoring = false; return; } verifyRestored(token, saved, attemptsLeft); return; } const trigger = overflowTrigger(); if (!trigger) { restoring = false; return; } if (trigger.getAttribute("aria-expanded") !== "true") { openedOverflow = trigger; if (!click(trigger, "open atomic tool overflow")) { openedOverflow = null; restoring = false; return; } } let attempt = 0; const wait = () => { stepTimer = 0; if (token !== restoreToken) return; const menuTool = findTool(menuTools(), saved); if (menuTool) { if (!click(menuTool.node, "select atomic overflow tool")) { restoring = false; closeOverflow(); return; } verifyRestored(token, saved, attemptsLeft); return; } attempt += 1; if (attempt >= MENU_WAIT_ATTEMPTS) { restoring = false; closeOverflow(); return; } stepTimer = window.setTimeout(wait, MENU_WAIT_INTERVAL); }; stepTimer = window.setTimeout(wait, MENU_WAIT_INTERVAL); } function maybeRestore() { if (restoreDone || restoring) return; if (isEngineDormant() || !state.rememberTools) { restoreDone = true; return; } const saved = readToolRecord(); if (!saved || !saved.applicationId && !saved.label && !saved.legacyLabels.length) { restoreDone = true; return; } const chip = currentChip(); if (chip && matchesSaved(chip, saved)) { finishRestore(restoreToken, `已恢复 ${chip.label || saved.label || saved.applicationId}`); return; } if (!chip && !atomicToolbarPresent()) return; if (restoreAttempts >= MAX_RESTORE_ATTEMPTS) { finishRestore(restoreToken, "找不到已记录的工具"); return; } restoring = true; restoreToken += 1; tryRestore(saved, restoreToken); } function clearTimer() { stopPolling(); window.clearTimeout(stepTimer); stepTimer = 0; clearTimers(recordTimers); clearTimers(verifyTimers); restoreToken += 1; restoring = false; restoreDone = false; restoreAttempts = 0; closeOverflow(); } function scheduleRestore() { clearTimer(); if (isEngineDormant() || !state.rememberTools) return; const saved = readToolRecord(); if (!saved) return; restoreDone = false; pollTimer = window.setInterval(() => { pollCount += 1; maybeRestore(); if (restoreDone || pollCount >= MAX_POLLS) stopPolling(); }, POLL_INTERVAL); } function renderStatus() { if (!statusNode) return; statusNode.textContent = ""; statusNode.title = actionStatus; if (!state.rememberTools) { statusNode.textContent = "工具记忆:已关闭"; return; } const saved = readToolRecord(); if (!saved) { statusNode.textContent = actionStatus || "工具记忆:未记录(在工具按钮里选择一个工具即可)"; return; } const shown = saved.label || saved.applicationId || "已记录工具"; statusNode.textContent = "工具记忆:" + shown + " "; if (actionStatus) { statusNode.appendChild(el("span", {}, ["· " + actionStatus + " "])); } statusNode.appendChild( el( "button", { type: "button", onclick: () => { clearToolRecord(); actionStatus = ""; clearTimer(); renderStatus(); } }, ["清除"] ) ); } function attachStatusNode(node) { statusNode = node; } function teardown() { clearTimer(); statusNode = null; } return { handleToolClick, maybeRestore, scheduleRestore, renderStatus, clearTimer, teardown, attachStatusNode }; } // scripts/ai-chat-turbo-engine/src/core/tool-scope.ts var TOOL_POPUP_TTL = 3e4; function isInsideTurboUI2(node) { if (!(node instanceof Element)) return false; return Boolean(node.closest("[id^='ai-turbo-'], .ai-turbo-code-bar")); } function nodeVisible2(node) { const rect = node.getBoundingClientRect(); return rect.width >= 1 && rect.height >= 1; } function visiblePopups() { return Array.from( document.querySelectorAll(TOOL_POPUP_SELECTOR) ).filter((node) => !isInsideTurboUI2(node) && nodeVisible2(node)); } function popupOwnedByToolTrigger(popup) { if (popup.closest(TOOL_TRIGGER_CONTAINER_SELECTOR)) return true; const popupId = popup.id; if (!popupId) return false; const containers = document.querySelectorAll(TOOL_TRIGGER_CONTAINER_SELECTOR); for (const container of containers) { const controls = container.querySelectorAll("[aria-controls]"); for (const control of controls) { if (control.getAttribute("aria-controls") === popupId) return true; } } return false; } function escapePopup() { const escape = new KeyboardEvent("keydown", { key: "Escape", code: "Escape", keyCode: 27, bubbles: true, cancelable: true }); document.activeElement?.dispatchEvent(escape); document.dispatchEvent(escape); } function createToolPopupScope() { const registered = []; function prune(now) { for (let index = registered.length - 1; index >= 0; index -= 1) { const entry = registered[index]; if (!entry.popup.isConnected || entry.until <= now) { registered.splice(index, 1); } } } function register(control, popup) { const now = Date.now(); prune(now); const existing = registered.find((entry) => entry.popup === popup); if (existing) { existing.control = control; existing.until = now + TOOL_POPUP_TTL; return; } registered.push({ control, popup, until: now + TOOL_POPUP_TTL }); } function snapshot() { return new Set(visiblePopups()); } function note(control, before) { const added = visiblePopups().filter( (popup2) => popup2 !== control && !before.has(popup2) ); const preferredId = control.getAttribute("aria-controls"); const preferred = preferredId ? added.find((popup2) => popup2.id === preferredId) : void 0; const popup = preferred ?? added[added.length - 1]; if (popup) { register(control, popup); return popup; } if (!preferredId) return null; const fallback = document.getElementById(preferredId); if (!(fallback instanceof HTMLElement) || !nodeVisible2(fallback)) { return null; } register(control, fallback); return fallback; } function active(control) { prune(Date.now()); for (let index = registered.length - 1; index >= 0; index -= 1) { const entry = registered[index]; if (entry.control === control && nodeVisible2(entry.popup)) { return entry.popup; } } return null; } function resolve(control) { const known = active(control); if (known) return known; const popupId = control.getAttribute("aria-controls"); if (!popupId) return null; const popup = document.getElementById(popupId); if (!(popup instanceof HTMLElement) || !nodeVisible2(popup)) return null; register(control, popup); return popup; } function popupFor(node) { if (!(node instanceof Element)) return null; prune(Date.now()); for (let index = registered.length - 1; index >= 0; index -= 1) { const entry = registered[index]; if (entry.popup === node || entry.popup.contains(node)) return entry.popup; } const closest = node.closest(TOOL_POPUP_SELECTOR); if (!(closest instanceof HTMLElement)) return null; return popupOwnedByToolTrigger(closest) ? closest : null; } function isInside(node) { return popupFor(node) !== null; } return { snapshot, note, active, resolve, popupFor, isInside, close: escapePopup }; } // scripts/ai-chat-turbo-engine/src/core/composer.ts function createComposerUtils(deps) { const { currentPlatform } = deps; function getChatInput() { const selectors = [ ...currentPlatform.inputSelectors || [], 'form[data-chatgpt-composer] [contenteditable="true"][role="textbox"]', 'div.ProseMirror[contenteditable="true"][role="textbox"]', "rich-textarea div[contenteditable='true']", 'div[contenteditable="true"][role="textbox"]', "textarea", '[contenteditable="true"]' ]; for (const selector of [...new Set(selectors)]) { const candidates = document.querySelectorAll(selector); for (const candidate of candidates) { if (!(candidate instanceof HTMLElement) || !candidate.isConnected || candidate.closest("#" + HUD_ID) || candidate.offsetParent === null && candidate.getClientRects().length === 0) { continue; } if (candidate.matches( 'input[type="hidden"], textarea[aria-hidden="true"]' ) || candidate.getAttribute("aria-hidden") === "true") { continue; } return candidate; } } return null; } function isSendControlForInput(sendControl, inputElement) { if (!(sendControl instanceof HTMLElement) || !(inputElement instanceof HTMLElement)) { return false; } const inputForm = inputElement.closest("form"); const sendForm = sendControl.closest("form"); if (inputForm && sendForm) { return inputForm === sendForm; } const composerSelectors = [ "[data-chatgpt-composer]", ".input-area", ".input-area-container", "rich-textarea", "[class*='composer-parent']", "[class*='input-area']", "[class*='composer']", "[class*='input-container']", "fieldset" ]; const sharesComposerContainer = composerSelectors.some((selector) => { const inputContainer = inputElement.closest(selector); return Boolean( inputContainer && inputContainer === sendControl.closest(selector) ); }); if (sharesComposerContainer) return true; let ancestor = inputElement.parentElement; let depth = 0; while (ancestor && depth < 5 && ancestor !== document.body) { if (ancestor.contains(sendControl)) return true; ancestor = ancestor.parentElement; depth++; } return false; } function isSendLikeButton(btn) { if (!(btn instanceof HTMLElement) || btn.tagName !== "BUTTON") return false; const label = [ btn.getAttribute("aria-label") || "", btn.getAttribute("title") || "", btn.getAttribute("data-testid") || "", btn.getAttribute("data-tooltip") || "" ].join(" ").toLowerCase(); if (/\bstop\b|停止|cancel|abort|中止|取消/.test(label)) return false; return /send|submit|发送|提交|prompt|ask/.test(label); } function isButtonUsable(btn) { if (!(btn instanceof HTMLElement) || !btn.isConnected) return false; if (btn.closest(`#${HUD_ID}, #ai-turbo-vf-tray, #ai-turbo-vf-preview-modal`)) return false; const style = window.getComputedStyle(btn); if (style.display === "none" || style.visibility === "hidden") return false; return btn.getClientRects().length > 0; } function isButtonDisabled(btn) { if (!(btn instanceof HTMLElement)) return true; if (btn.hasAttribute("disabled")) return true; if (btn instanceof HTMLButtonElement && btn.disabled === true) return true; if (btn instanceof HTMLInputElement && btn.disabled === true) return true; if (btn.getAttribute("aria-disabled") === "true") return true; return false; } function findSendControl(inputElement, { allowDisabled = false } = {}) { if (!inputElement) return null; const usable = (btn) => isButtonUsable(btn) && (allowDisabled || !isButtonDisabled(btn)); for (const sel of currentPlatform.sendButtonSelectors || []) { let matches; try { matches = document.querySelectorAll(sel); } catch (error) { reportRecoverableError("query platform send selector", error); continue; } for (const btn of matches) { if (usable(btn) && isSendControlForInput(btn, inputElement) && btn instanceof HTMLElement) { return btn; } } } const form = inputElement.closest("form"); if (form) { for (const btn of form.querySelectorAll( 'button[type="submit"], button:not([type="button"]):not([type="reset"])' )) { if (usable(btn) && isSendLikeButton(btn) && btn instanceof HTMLElement) return btn; } for (const btn of form.querySelectorAll("button")) { if (usable(btn) && isSendLikeButton(btn) && btn instanceof HTMLElement) return btn; } } const composerSelectors = [ "[data-chatgpt-composer]", ".input-area-container", "[class*='composer']", "[class*='input-area']", "[class*='input-container']", "[class*='query-bar']", "rich-textarea", "fieldset" ]; for (const sel of composerSelectors) { let container = null; try { container = inputElement.closest(sel); } catch (error) { reportRecoverableError("query composer container", error); } if (!container) continue; for (const btn of container.querySelectorAll("button")) { if (usable(btn) && isSendLikeButton(btn) && btn instanceof HTMLElement) return btn; } } let ancestor = inputElement.parentElement; let depth = 0; while (ancestor && depth < 8 && ancestor !== document.body && ancestor !== document.documentElement) { for (const btn of ancestor.querySelectorAll("button")) { if (usable(btn) && isSendLikeButton(btn) && btn instanceof HTMLElement) return btn; } ancestor = ancestor.parentElement; depth++; } return null; } function triggerSendButton(btn) { if (!(btn instanceof HTMLElement)) return false; try { btn.focus({ preventScroll: true }); } catch (error) { reportRecoverableError("focus send control", error); } const opts = { bubbles: true, cancelable: true, view: window, button: 0 }; try { btn.dispatchEvent( new PointerEvent("pointerdown", { ...opts, buttons: 1, pointerId: 1, pointerType: "mouse", isPrimary: true }) ); } catch (error) { reportRecoverableError("dispatch pointerdown", error); } try { btn.dispatchEvent(new MouseEvent("mousedown", { ...opts, buttons: 1 })); } catch (error) { reportRecoverableError("dispatch mousedown", error); } try { btn.dispatchEvent( new PointerEvent("pointerup", { ...opts, buttons: 0, pointerId: 1, pointerType: "mouse", isPrimary: true }) ); } catch (error) { reportRecoverableError("dispatch pointerup", error); } try { btn.dispatchEvent(new MouseEvent("mouseup", { ...opts, buttons: 0 })); } catch (error) { reportRecoverableError("dispatch mouseup", error); } try { btn.click(); } catch (error) { reportRecoverableError("click send control", error); return false; } return true; } function fallbackKeyboardSubmit(inputElement) { if (!inputElement) return false; try { inputElement.focus({ preventScroll: true }); } catch (error) { reportRecoverableError("focus composer", error); } const form = inputElement.closest("form"); if (form && typeof form.requestSubmit === "function") { try { form.requestSubmit(); return true; } catch (error) { reportRecoverableError("submit composer form", error); } } const enterOpts = { key: "Enter", code: "Enter", keyCode: 13, which: 13, bubbles: true, cancelable: true, composed: true }; const enterEvt = new KeyboardEvent("keydown", enterOpts); try { Object.defineProperty(enterEvt, "keyCode", { get: () => 13 }); Object.defineProperty(enterEvt, "which", { get: () => 13 }); } catch (error) { reportRecoverableError("emulate legacy Enter key", error); } inputElement.dispatchEvent(enterEvt); inputElement.dispatchEvent(new KeyboardEvent("keyup", enterOpts)); return true; } function getInputContainer(input) { if (!input) return null; const candidates = [ "form[data-chatgpt-composer]", "[data-chatgpt-composer]", ".input-area-container", "form", ".input-area", "[class*='composer-parent']", "[class*='composer']", "[class*='input-area']", "[class*='input-container']", "rich-textarea", "fieldset" ]; const inputRect = input.getBoundingClientRect(); if (!inputRect.width || !inputRect.height) { return input.parentElement; } let best = null; let bestArea = Infinity; for (const selector of candidates) { let matched = null; try { matched = input.closest(selector); } catch (error) { reportRecoverableError("query input container", error); continue; } if (!(matched instanceof HTMLElement) || matched === input) continue; const rect = matched.getBoundingClientRect(); if (rect.height < 20 || rect.width < 40) continue; if (rect.top > inputRect.top + 2) continue; if (rect.bottom < inputRect.bottom - 2) continue; if (rect.width < inputRect.width * 0.75) continue; const area = rect.width * rect.height; if (area < bestArea) { bestArea = area; best = matched; } } return best || input.parentElement; } function getComposerVisualBounds(input, anchor) { const baseRect = (anchor || input).getBoundingClientRect(); const bounds = { top: baseRect.top, left: baseRect.left, right: baseRect.right, width: baseRect.width }; let node = anchor || input; let depth = 0; while (node && depth < COMPOSER_VISUAL_MAX_DEPTH) { const nodeRect = node.getBoundingClientRect(); let cursorTop = Math.min(nodeRect.top, bounds.top); let sibling = node.previousElementSibling; let guard = 0; while (sibling && guard < 24) { guard++; if (sibling.id === "ai-turbo-vf-tray" || sibling.id === HUD_ID || sibling.id === "ai-turbo-vf-preview-modal") { sibling = sibling.previousElementSibling; continue; } const siblingRect = sibling.getBoundingClientRect(); const isVisible = siblingRect.width > 0 && siblingRect.height > 0; if (!isVisible) { sibling = sibling.previousElementSibling; continue; } const siblingStyle = window.getComputedStyle(sibling); if (siblingStyle.position === "fixed" || siblingStyle.position === "sticky") { sibling = sibling.previousElementSibling; continue; } if (sibling.matches('button, [role="button"]') && !sibling.querySelector( 'input, textarea, [contenteditable="true"], [role="textbox"]' )) { sibling = sibling.previousElementSibling; continue; } if (siblingRect.top < 8) { break; } const maxSiblingHeight = Math.max(baseRect.height * 3, 320); if (siblingRect.height > maxSiblingHeight) { break; } const overlap = Math.min(bounds.right, siblingRect.right) - Math.max(bounds.left, siblingRect.left); const minOverlap = Math.min(bounds.width, siblingRect.width) * 0.35; const gap = cursorTop - siblingRect.bottom; if (overlap > minOverlap && gap >= -1 && gap <= COMPOSER_VISUAL_GAP) { bounds.top = Math.min(bounds.top, siblingRect.top); bounds.left = Math.min(bounds.left, siblingRect.left); bounds.right = Math.max(bounds.right, siblingRect.right); bounds.width = bounds.right - bounds.left; cursorTop = siblingRect.top; sibling = sibling.previousElementSibling; continue; } break; } const parent = node.parentElement; if (!parent || parent === document.body || parent === document.documentElement) { break; } node = parent; depth++; } return bounds; } function insertTextAtomic(inputElement, text) { if (inputElement instanceof HTMLTextAreaElement || inputElement instanceof HTMLInputElement) { const proto = inputElement instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype; const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set; if (setter) setter.call(inputElement, text); else inputElement.value = text; inputElement.dispatchEvent(new Event("input", { bubbles: true })); inputElement.dispatchEvent(new Event("change", { bubbles: true })); return; } inputElement.focus(); try { const range = document.createRange(); range.selectNodeContents(inputElement); const sel = window.getSelection(); sel?.removeAllRanges(); sel?.addRange(range); } catch (error) { reportRecoverableError("select composer text", error); try { document.execCommand("selectAll"); } catch (fallbackError) { reportRecoverableError("select composer text fallback", fallbackError); } } const singleContainer = `