From 6b0d8eaadfe83dd2b3b9b8b93bf5875f29493bae Mon Sep 17 00:00:00 2001 From: Stacey2911 Date: Tue, 30 Jun 2026 13:52:57 +1000 Subject: [PATCH] fix(webui): make large text paste-as-attachment toggleable via settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a user setting 'large_text_paste_as_attachment' (default: on) that lets users paste large text inline instead of having it auto-converted to .md file attachments. The toggle lives in Control Center → Chat tab and persists via settings.json, following the established upstream pattern for boolean settings. --- api/config.py | 2 ++ static/boot.js | 2 ++ static/i18n.js | 28 +++++++++++++++++++++++ static/index.html | 7 ++++++ static/panels.js | 13 +++++++++++ tests/test_large_text_paste_attachment.py | 26 +++++++++++++++++++++ 6 files changed, 78 insertions(+) diff --git a/api/config.py b/api/config.py index 2c60945e..7509da79 100644 --- a/api/config.py +++ b/api/config.py @@ -7776,6 +7776,7 @@ _SETTINGS_DEFAULTS = { "font_size": "default", # small | default | large | xlarge "session_jump_buttons": False, # show Start/End transcript jump pills "render_user_markdown": False, # opt-in: render full markdown in user messages (#3870) + "large_text_paste_as_attachment": True, # convert very large composer text pastes into .md attachments by default "structured_code_default_view": "auto", # JSON/YAML fenced-block default render: auto | on | off (#484 follow-up). auto => Tree when line count >= structured_code_auto_tree_lines, else Raw. "structured_code_auto_tree_lines": 10, # in 'auto' mode, minimum line count to default a JSON/YAML block to Tree view (preserves the original hardcoded >=10 behavior) "session_endless_scroll": False, # auto-load older transcript pages while scrolling upward @@ -8023,6 +8024,7 @@ _SETTINGS_BOOL_KEYS = { "api_redact_enabled", "session_jump_buttons", "render_user_markdown", + "large_text_paste_as_attachment", "session_endless_scroll", "auto_scroll_follow", "worklog_details_expanded_default", diff --git a/static/boot.js b/static/boot.js index 4a374143..9f84b5c4 100644 --- a/static/boot.js +++ b/static/boot.js @@ -1815,6 +1815,7 @@ function _largeTextPasteLineCount(text){ return value.endsWith('\n')?lines.length-1:lines.length; } function _shouldAttachLargePastedText(text){ + if(window._largeTextPasteAsAttachment===false)return false; const value=String(text||''); if(!value.trim())return false; return value.length>=LARGE_TEXT_PASTE_CHAR_THRESHOLD || _largeTextPasteLineCount(value)>=LARGE_TEXT_PASTE_LINE_THRESHOLD; @@ -2423,6 +2424,7 @@ window._applyTitlebarProfileVisibility=_applyTitlebarProfileVisibility; window._busyInputMode=(s.busy_input_mode||'queue'); window._sessionEndlessScrollEnabled=!!s.session_endless_scroll; window._autoScrollFollow=s.auto_scroll_follow!==false; + window._largeTextPasteAsAttachment=s.large_text_paste_as_attachment!==false; window._composerControlVisibility=_composerControlVisibilityFromSettings(s); window._showTitlebarProfile=!!s.show_titlebar_profile; _applyTitlebarProfileVisibility(); diff --git a/static/i18n.js b/static/i18n.js index 53b15afd..433ec157 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -614,6 +614,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -2253,6 +2255,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -3883,6 +3887,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -6225,6 +6231,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -7780,6 +7788,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -9016,6 +9026,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -10925,6 +10937,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -11782,6 +11796,8 @@ const LOCALES = { settings_label_show_titlebar_profile: '在標題列顯示設定檔切換器', settings_desc_show_titlebar_profile: '啟用後,左上角的應用程式標題列會出現設定檔切換按鈕,讓你在任何分頁都能切換設定檔。預設關閉;無論此設定為何,輸入列底部一律保留設定檔切換器。', settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -13309,6 +13325,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -14838,6 +14856,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -16480,6 +16500,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Afficher le sélecteur de profil dans la barre de titre', settings_desc_show_titlebar_profile: 'Lorsqu\'il est activé, un bouton de sélection de profil apparaît dans la barre de titre en haut à gauche de l\'application, vous permettant de changer de profil depuis n\'importe quel onglet. Désactivé par défaut ; le pied de page du compositeur dispose toujours d\'un sélecteur de profil, indépendamment de ce paramètre.', settings_desc_render_user_markdown: 'Lorsqu\'il est activé, le gras, l\'italique, les liens et autres éléments markdown dans vos propres messages sont rendus. Désactivé par défaut ; les blocs de code et les formules mathématiques sont toujours rendus, indépendamment de ce paramètre.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'Blocs de code JSON/YAML', settings_option_structured_code_auto: 'Auto : Arborescence pour les blocs longs', settings_option_structured_code_on: 'Arborescence par défaut', @@ -18078,6 +18100,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Show profile switcher in titlebar', // TODO: translate settings_desc_show_titlebar_profile: 'When enabled, a profile switcher button appears in the top-left app titlebar so you can change profiles from any tab. Off by default; the composer footer always has a profile switcher regardless of this setting.', // TODO: translate settings_desc_render_user_markdown: 'When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'JSON/YAML code blocks', settings_option_structured_code_auto: 'Auto: Tree for long blocks', settings_option_structured_code_on: 'Tree by default', @@ -19728,6 +19752,8 @@ const LOCALES = { settings_option_structured_code_off: 'Domyślnie widok źródła', settings_label_structured_code_auto_lines: 'Próg wierszy dla trybu automatycznego', settings_desc_structured_code: 'Gdy wybrano tryb automatyczny, bloki JSON/YAML o długości przynajmniej podanej liczby wierszy zostaną otwarte w widoku drzewa. Widok drzewa zawsze otwiera strukturyzowaną przeglądarkę; widok źródła zachowuje podświetlony składniowo tekst. Nadal możesz przełączać tryby dla każdego bloku osobno.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_worklog_details_expanded_default: 'Otwieraj szczegóły Worklog automatycznie', settings_desc_worklog_details_expanded_default: 'Gdy ta opcja jest włączona, nowe szczegóły Worklog zaczynają rozwinięte, dzięki czemu karty narzędzi, Thinking i postępu są widoczne bez dodatkowego kliknięcia. Gdy jest wyłączona, szczegóły Worklog pozostają domyślnie zwinięte. Ręczne decyzje o zwinięciu/rozwinięciu w danej turze mają pierwszeństwo.', settings_label_chat_activity_display_mode: 'Wyświetlanie aktywności', @@ -21254,6 +21280,8 @@ const LOCALES = { settings_label_show_titlebar_profile: 'Hiển thị bộ chuyển profile trên thanh tiêu đề', settings_desc_show_titlebar_profile: 'Khi bật, nút chuyển profile sẽ xuất hiện ở góc trên bên trái thanh tiêu đề ứng dụng để bạn đổi profile từ bất kỳ tab nào. Mặc định tắt; chân khung soạn thảo luôn có bộ chuyển profile dù cài đặt này thế nào.', settings_desc_render_user_markdown: 'Khi bật, chữ đậm, chữ nghiêng, liên kết và các Markdown khác trong tin nhắn của bạn sẽ được render. Mặc định tắt; khối code fenced và công thức toán luôn được render bất kể cài đặt này.', + settings_label_large_text_paste_as_attachment: 'Attach large pasted text as file', + settings_desc_large_text_paste_as_attachment: 'When enabled, long pasted text becomes a .md attachment instead of filling the composer.', settings_label_structured_code: 'Khối code JSON/YAML', settings_option_structured_code_auto: 'Tự động: dạng cây cho khối dài', settings_option_structured_code_on: 'Mặc định dạng cây', diff --git a/static/index.html b/static/index.html index 6eb732d4..0309cdcf 100644 --- a/static/index.html +++ b/static/index.html @@ -1050,6 +1050,13 @@
When enabled, bold, italic, links, and other markdown in your own messages are rendered. Off by default; fenced code blocks and math always render regardless of this setting.
+
+ +
When enabled, long pasted text becomes a .md attachment instead of filling the composer.
+