diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df5ac27..4bc8b685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ ## [Unreleased] +## [v0.51.347] — 2026-06-09 — Release LK (streaming & render reliability cluster) + +### Fixed + +- **Mid-stream content no longer flickers (disappears and reappears) during a live turn.** When `renderMessages()` rebuilt the transcript while a session was actively streaming (e.g. a clarify-response echo or a CLI-import refresh), the `inner.innerHTML=''` wipe detached the live assistant turn node that the streaming markdown parser keeps writing into, so the streamed text vanished until the next stream event. The live turn's DOM node is now preserved across the rebuild and re-attached so the parser target stays connected and the text never blanks. (#3877) +- **Recovered turns with empty visible content no longer render a blank transcript.** A run-journal-recovered assistant anchor (empty content + a `reasoning` payload + recovery marker) extracted no inline thinking text and rendered nothing, so a session made of such rows painted as only date separators. Two fixes: the backend now reuses one empty recovered anchor per stream instead of appending a fresh empty row on every lazy recovery retry (which previously bloated sessions with thousands of content-less rows), and the renderer surfaces the message's reasoning payload as a Thinking card for empty-content turns so the turn is never blank. (#3875) +- **`stream_end` no longer finalizes a turn prematurely when the server is still active.** When a `stream_end` event arrived while the session was still streaming server-side, the client could settle to a partial state. It now polls the persisted session and retries settlement (bounded) until the server reports the stream complete, and the SSE error path defers to an in-flight recovery instead of starting a competing reconnect. (#3885) +- **Markdown list markers and indentation are preserved around LaTeX blocks.** Continuation lines, nested indentation, and KaTeX-placeholder lines inside list items no longer break the list into fragments or lose their markers. (#3830) + +### Changed + +- **Worklog details settings now align with the live-to-final model.** The old "Activity expanded by default" setting is renamed to **Worklog details** (default folded), the legacy "Compact tool activity" preference is deprecated, and the Worklog renderer stays enabled for older installs that had saved `simplified_tool_calling=false`. (#3400, #3820) + ## [v0.51.346] — 2026-06-09 — Release LJ (PWA notification controls) ### Added diff --git a/api/config.py b/api/config.py index b7ebaa6d..d0746d0d 100644 --- a/api/config.py +++ b/api/config.py @@ -5488,7 +5488,7 @@ _SETTINGS_DEFAULTS = { "font_size": "default", # small | default | large | xlarge "session_jump_buttons": False, # show Start/End transcript jump pills "session_endless_scroll": False, # auto-load older transcript pages while scrolling upward - "activity_feed_expanded_default": False, # expand Activity disclosures by default for new turns + "worklog_details_expanded_default": False, # opt-in: expand Worklog details by default; default remains folded "pinned_sessions_limit": 3, # maximum active pinned sessions shown in the sidebar "inflight_state_max_sessions": 8, # max active-stream recovery snapshots kept in browser localStorage "inflight_state_max_messages": 24, # max recent messages kept per recovery snapshot @@ -5505,7 +5505,7 @@ _SETTINGS_DEFAULTS = { "rtl": False, # right-to-left chat layout (chat messages + composer only) "notifications_enabled": False, # browser notification when tab is in background "show_thinking": True, # show/hide thinking/reasoning blocks in chat view - "simplified_tool_calling": True, # render tools/thinking as compact inline timeline activity + "simplified_tool_calling": True, # legacy compatibility; Worklog renderer remains enabled "terminal_auto_expand_on_output": False, # auto-expand terminal panel when output arrives while collapsed "api_redact_enabled": True, # redact sensitive data (API keys, secrets) from API responses "dashboard_plugins": {}, # plugin_name -> bool, opt-in per plugin (default off per PF-10b) @@ -5514,7 +5514,13 @@ _SETTINGS_DEFAULTS = { "busy_input_mode": "queue", # behavior when sending while agent is running: queue | interrupt | steer "password_hash": None, # PBKDF2-HMAC-SHA256 hash; None = auth disabled } -_SETTINGS_LEGACY_DROP_KEYS = {"assistant_language", "bubble_layout", "default_model"} +_SETTINGS_LEGACY_DROP_KEYS = { + "assistant_language", + "bubble_layout", + "default_model", + "activity_feed_expanded_default", + "simplified_tool_calling", +} _SETTINGS_THEME_VALUES = {"light", "dark", "system"} _SETTINGS_SKIN_VALUES = { "default", @@ -5595,6 +5601,13 @@ def load_settings() -> dict: try: stored = json.loads(SETTINGS_FILE.read_text(encoding="utf-8")) if isinstance(stored, dict): + if ( + "worklog_details_expanded_default" not in stored + and "activity_feed_expanded_default" in stored + ): + settings["worklog_details_expanded_default"] = bool( + stored.get("activity_feed_expanded_default") + ) settings.update( { k: v @@ -5621,6 +5634,7 @@ def load_settings() -> dict: _SETTINGS_ALLOWED_KEYS = set(_SETTINGS_DEFAULTS.keys()) - { "password_hash", "default_model", + "simplified_tool_calling", } _SETTINGS_ENUM_VALUES = { "send_key": {"enter", "ctrl+enter"}, @@ -5655,12 +5669,11 @@ _SETTINGS_BOOL_KEYS = { "rtl", "notifications_enabled", "show_thinking", - "simplified_tool_calling", "terminal_auto_expand_on_output", "api_redact_enabled", "session_jump_buttons", "session_endless_scroll", - "activity_feed_expanded_default", + "worklog_details_expanded_default", } # Language codes are validated as short alphanumeric BCP-47-like tags (e.g. 'en', 'zh', 'fr') _SETTINGS_LANG_RE = __import__("re").compile(r"^[a-zA-Z]{2,10}(-[a-zA-Z0-9]{2,8})?$") @@ -5669,6 +5682,15 @@ _SETTINGS_LANG_RE = __import__("re").compile(r"^[a-zA-Z]{2,10}(-[a-zA-Z0-9]{2,8} def save_settings(settings: dict) -> dict: """Save settings to disk. Returns the merged settings. Ignores unknown keys.""" current = load_settings() + if ( + "worklog_details_expanded_default" not in settings + and "activity_feed_expanded_default" in settings + ): + settings["worklog_details_expanded_default"] = settings.get( + "activity_feed_expanded_default" + ) + settings.pop("activity_feed_expanded_default", None) + settings.pop("simplified_tool_calling", None) pending_theme = current.get("theme") pending_skin = current.get("skin") theme_was_explicit = False diff --git a/api/models.py b/api/models.py index 3abc89d7..a358e4c4 100644 --- a/api/models.py +++ b/api/models.py @@ -1421,6 +1421,30 @@ def _append_journaled_partial_output( # A stream can start with tools before any text. Keep those tools # visible after restart with an empty recovered assistant anchor instead # of inventing synthetic progress prose. + # + # Dedup guard (#3875): reuse an existing empty recovered anchor for THIS + # stream instead of appending a fresh one. The lazy read-side retry path + # (_retry_journal_recovery_in_place) re-runs this recovery on repeated + # get_session() calls, and a tool-first stream that never emitted text + # has no content to dedup on (flush_assistant() returns early on empty), + # so without this guard each retry — and each distinct interrupted stream + # over the session's life — appends another empty anchor. A session that + # was interrupted-and-recovered many times then accumulates thousands of + # empty content-less assistant rows, bloating the file and (combined with + # the render path) painting the transcript blank. One anchor per stream + # is all that's needed to host its recovered tool cards. + for _existing_idx in range(len(session.messages) - 1, -1, -1): + _m = session.messages[_existing_idx] + if not isinstance(_m, dict): + continue + if ( + _m.get('_recovered_from_run_journal') + and _m.get('_recovered_stream_id') == stream_id + and _m.get('role') == 'assistant' + and not str(_m.get('content') or '').strip() + ): + current_assistant_idx = _existing_idx + return _existing_idx session.messages.append({ 'role': 'assistant', 'content': '', diff --git a/static/boot.js b/static/boot.js index 34e8f8b8..bb2c4709 100644 --- a/static/boot.js +++ b/static/boot.js @@ -1794,9 +1794,13 @@ function applyBotName(){ if(s.default_workspace) S._profileDefaultWorkspace=s.default_workspace; window._whatsNewSummaryEnabled=!!s.whats_new_summary_enabled; window._showThinking=s.show_thinking!==false; - window._simplifiedToolCalling=s.simplified_tool_calling!==false; + window._simplifiedToolCalling=true; window._terminalAutoExpandOnOutput=!!s.terminal_auto_expand_on_output; - window._activityFeedExpandedDefault=!!s.activity_feed_expanded_default; + window._worklogDetailsExpandedByDefault=!!( + Object.prototype.hasOwnProperty.call(s,'worklog_details_expanded_default') + ? s.worklog_details_expanded_default + : s.activity_feed_expanded_default + ); window._sidebarDensity=(s.sidebar_density==='detailed'?'detailed':'compact'); window._pinnedSessionsLimit=parseInt(s.pinned_sessions_limit||3,10)||3; window._inflightStateLimits={ diff --git a/static/i18n.js b/static/i18n.js index bc17289d..f7d6eeb4 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -558,8 +558,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Load older messages while scrolling up', settings_desc_session_endless_scroll: 'When enabled, older messages load automatically as you scroll upward. When disabled, use the older-messages button.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Sidebar tabs', settings_desc_tab_visibility: 'Choose which tabs appear in the sidebar and rail. Drag chips to reorder them. Chat and Settings are always visible.', @@ -1962,8 +1962,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Carica messaggi precedenti scorrendo in alto', settings_desc_session_endless_scroll: 'Se abilitato, i messaggi precedenti si caricano automaticamente scorrendo in alto. Se disabilitato, usa il pulsante messaggi precedenti.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Schede della barra laterale', settings_desc_tab_visibility: 'Scegli quali schede mostrare nella barra laterale e nel rail. Chat e Impostazioni sono sempre visibili.', @@ -3358,8 +3358,8 @@ const LOCALES = { settings_label_session_endless_scroll: '上スクロールで古いメッセージを読み込む', settings_desc_session_endless_scroll: '有効にすると、上にスクロールしたとき古いメッセージを自動で読み込みます。無効の場合は古いメッセージボタンを使います。', - settings_label_activity_feed_expanded_default: 'アクティビティフィードをデフォルトで展開', - settings_desc_activity_feed_expanded_default: '新しいアクティビティの詳細を自動的に展開し、ツールやモデルの進捗をクリックなしで確認できます。ターンごとの手動折りたたみ/展開は優先されます。', + settings_label_worklog_details_expanded_default: 'Worklog の詳細を自動的に開く', + settings_desc_worklog_details_expanded_default: '有効にすると、新しい Worklog の詳細が展開された状態で始まり、ツール、Thinking、進捗カードをクリックなしで確認できます。無効の場合、Worklog の詳細はデフォルトで折りたたまれます。ターンごとの手動折りたたみ/展開は優先されます。', settings_label_tab_visibility: 'サイドバータブ', settings_desc_tab_visibility: 'サイドバーとレールに表示するタブを選択します。チャットと設定は常に表示されます。', @@ -5371,8 +5371,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Загружать старые сообщения при прокрутке вверх', settings_desc_session_endless_scroll: 'Если включено, старые сообщения загружаются автоматически при прокрутке вверх. Если выключено, используйте кнопку загрузки старых сообщений.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Вкладки боковой панели', settings_desc_tab_visibility: 'Выберите, какие вкладки отображаются на боковой панели и в рейле. Чат и настройки всегда видны.', @@ -6692,8 +6692,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Cargar mensajes antiguos al desplazarse hacia arriba', settings_desc_session_endless_scroll: 'Si está activado, los mensajes antiguos se cargan automáticamente al desplazarte hacia arriba. Si está desactivado, usa el botón de mensajes antiguos.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Pestañas de la barra lateral', settings_desc_tab_visibility: 'Elige qué pestañas aparecen en la barra lateral y el rail. Chat y Configuración siempre están visibles.', @@ -7713,8 +7713,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Ältere Nachrichten beim Hochscrollen laden', settings_desc_session_endless_scroll: 'Wenn aktiviert, werden ältere Nachrichten beim Hochscrollen automatisch geladen. Wenn deaktiviert, nutzt du den Button für ältere Nachrichten.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Seitenleiste-Tabs', settings_desc_tab_visibility: 'Wähle, welche Tabs in der Seitenleiste und im Rail angezeigt werden. Ziehe die Chips, um die Reihenfolge zu ändern. Chat und Einstellungen sind immer sichtbar.', @@ -9369,8 +9369,8 @@ const LOCALES = { settings_label_session_endless_scroll: '向上滚动时加载更早的消息', settings_desc_session_endless_scroll: '启用后,向上滚动时会自动加载更早的消息。禁用时请使用加载更早消息按钮。', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: '侧边栏标签', settings_desc_tab_visibility: '选择在侧边栏和导航栏中显示哪些标签。聊天和设置始终可见。', @@ -10087,8 +10087,8 @@ const LOCALES = { settings_label_session_endless_scroll: '向上捲動時載入較早訊息', settings_desc_session_endless_scroll: '啟用後,向上捲動時會自動載入較早訊息。停用時請使用載入較早訊息按鈕。', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: '側邊欄標籤', settings_desc_tab_visibility: '選擇在側邊欄和導覽列中顯示哪些標籤。聊天和設定始終可見。', @@ -11373,8 +11373,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Carregar mensagens antigas ao rolar para cima', settings_desc_session_endless_scroll: 'Quando ativado, mensagens antigas carregam automaticamente ao rolar para cima. Quando desativado, use o botão de mensagens antigas.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Abas da barra lateral', settings_desc_tab_visibility: 'Escolha quais abas aparecem na barra lateral e no rail. Chat e Configurações estão sempre visíveis.', @@ -12670,8 +12670,8 @@ const LOCALES = { settings_label_session_endless_scroll: '위로 스크롤할 때 이전 메시지 불러오기', settings_desc_session_endless_scroll: '활성화하면 위로 스크롤할 때 이전 메시지를 자동으로 불러옵니다. 비활성화하면 이전 메시지 버튼을 사용합니다.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: '사이드바 탭', settings_desc_tab_visibility: '사이드바와 레일에 표시할 탭을 선택하세요. 채팅과 설정은 항상 표시됩니다.', @@ -13984,8 +13984,8 @@ const LOCALES = { settings_desc_terminal_auto_expand: 'Développer automatiquement le panneau de terminal réduit lorsqu\'une commande en cours d\'exécution émet une nouvelle sortie.', settings_label_session_endless_scroll: 'Charger les anciens messages en faisant défiler vers le haut', settings_desc_session_endless_scroll: 'Lorsqu\'ils sont activés, les anciens messages se chargent automatiquement lorsque vous faites défiler vers le haut. Lorsqu\'il est désactivé, utilisez le bouton des messages plus anciens.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Onglets de la barre latérale', settings_desc_tab_visibility: 'Choisissez quels onglets apparaissent dans la barre latérale et le rail. Chat et Paramètres sont toujours visibles.', @@ -15399,8 +15399,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Yukarı kaydırırken eski mesajları yükle', settings_desc_session_endless_scroll: 'Etkinleştirildiğinde, yukarı doğru kaydırdığınızda eski mesajlar otomatik olarak yüklenir. Devre dışı bırakıldığında eski mesajlar düğmesini kullanın.', - settings_label_activity_feed_expanded_default: 'Expand activity feed by default', - settings_desc_activity_feed_expanded_default: 'Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.', + settings_label_worklog_details_expanded_default: 'Open Worklog details automatically', + settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.', settings_label_tab_visibility: 'Kenar çubuğu sekmeleri', settings_desc_tab_visibility: 'Kenar çubuğunda ve rayda hangi sekmelerin görüneceğini seçin. Sohbet ve Ayarlar her zaman görünür durumdadır.', @@ -16806,8 +16806,8 @@ const LOCALES = { settings_label_session_endless_scroll: 'Ładuj starsze wiadomości podczas przewijania w górę', settings_desc_session_endless_scroll: 'Gdy ta opcja jest włączona, starsze wiadomości ładują się automatycznie przy przewijaniu w górę. Gdy jest wyłączona, użyj przycisku wczytywania starszych wiadomości.', - settings_label_activity_feed_expanded_default: 'Rozwiń kanał aktywności domyślnie', - settings_desc_activity_feed_expanded_default: 'Rozwijaj nowe szczegóły Aktywności automatycznie, aby postęp narzędzi i modeli był widoczny bez dodatkowego kliknięcia. Ręczne decyzje o zwinięciu/rozwinięciu w danej turze mają pierwszeństwo.', + 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_tab_visibility: 'Karty paska bocznego', settings_desc_tab_visibility: 'Wybierz, które karty pojawiają się na pasku bocznym i szynie. Przeciągnij elementy, aby zmienić ich kolejność. Czat i Ustawienia są zawsze widoczne.', diff --git a/static/index.html b/static/index.html index 0a5a6812..686d4303 100644 --- a/static/index.html +++ b/static/index.html @@ -1006,10 +1006,10 @@
-
Open new Activity disclosures automatically so tool and model progress is visible without an extra click. Per-turn manual collapse/expand choices still win.
+
When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.
@@ -1160,13 +1160,6 @@
Fade newly streamed words in while the assistant is responding. Similar to OpenWebUI; off by default for maximum performance.
-
- -
Show thinking and tool calls as compact inline activity while preserving the agent timeline.
-