diff --git a/CHANGELOG.md b/CHANGELOG.md index aae3bf19652..b97a99b86b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,24 +37,10 @@ - **WebUI-created git worktrees can now be cleaned up (no more orphan accumulation).** The agent locks every worktree it creates, and git refuses to remove a locked worktree with a single `--force`, so WebUI-created worktrees were piling up unremovable. Session-worktree removal now runs a fail-soft `git worktree unlock` right before the remove (mirroring the agent's own cleanup ordering); the existing dirty/uncommitted-changes guard still runs first, so user data stays protected. Thanks @ayxuerui. (#6028, #6023) -- **"Max" reasoning-effort level (opt-in, availability-gated).** The reasoning selector now offers `Max` for models that actually support it (Claude adaptive-thinking 4.6+, DeepSeek), matching the level Hermes core already accepts. `Max` is shown *only* when the active model genuinely supports it — it's hidden for GPT-5 / o-series / Gemini / legacy Claude and stripped anywhere it would be rejected, and a stored/CLI `max` on a model that can't take it degrades to the next supported level (`xhigh`) instead of erroring. (One known edge: an aggregator provider like OpenRouter/Copilot that returns no per-model capability data can't confirm support, so `max` stays selectable there and would fall back at the provider if the specific model doesn't support it — same behavior as the CLI.) Thanks @perejaslav. (#5910, #4627) - -- **Opt-in: start a new chat when switching workspace.** A new default-off setting (Settings → Preferences → "Start a new chat when switching workspace"). When enabled, selecting a *different* workspace starts a fresh conversation bound to that workspace and leaves your current chat on its original workspace — avoiding stale cross-workspace context carrying into the conversation. Selecting the same workspace stays an in-place refresh, and when the setting is off (the default) switching workspace changes the current conversation's workspace in place exactly as before, so nothing changes for anyone who doesn't opt in. Thanks @ruizanthony. (#5473) - -- **Public read-only conversation sharing.** You can now opt in to share a single conversation via a public link (session action menu → Share). The link serves a redacted, read-only snapshot at `/share/` that anyone can view without logging in — nothing is public unless you explicitly share it, and you can revoke the link at any time (Stop sharing). The public page renders the transcript through the same sanitized markdown path as the app, is theme- and skin-aware (light/dark + all skins), and looks clean on desktop and mobile. The share payload is hardened at a dedicated always-on boundary: credentials, local workspace/worktree/home paths, system/tool messages, and any non-text structured content are stripped regardless of your API-redaction setting; only the conversation title and user/assistant text reach the public snapshot. Share tokens are 144-bit CSPRNG; create/revoke stay authenticated + CSRF-protected. Thanks @MicoRobot. (#5337) - -- **Per-event timestamps in the Transparent Stream worklog.** In Transparent Stream activity mode, each worklog event row (thinking / tool call) now shows a small right-aligned time label, so you can see when each step of a long agent run happened — useful for telling whether a run is progressing or stuck. The timestamp resolves from whatever timing the event carries (falling back to the observed live time only for a genuinely live event, never fabricating a time for a recovered/replayed old session), persists correctly when the turn settles, and carries a full date+time tooltip on hover so a session reviewed days later isn't date-ambiguous. The label is hidden on narrow (<420px) viewports so it never squeezes the command preview, and Compact Worklog / Final answer only modes are unaffected. Thanks @rodboev. (#5739, #5700) - -- **New "Final answer only" chat activity display mode.** Settings → Appearance → Activity display now offers a third option beside Compact Worklog and Transparent Stream: "Final answer only" hides all activity rows (thinking, tool calls, worklog) and shows just the assistant's final answer — the clean, minimal output style of ChatGPT/Claude. It's a pure display lens (opt-in; the default stays Compact Worklog), so no activity data is lost — switching modes re-renders the same conversation with more or less detail. Thanks @rodboev. (#5746, #5706) - -- **Czech (Čeština) is now a fully-supported UI language.** Added a complete Czech (`cs`) locale to Settings → Language with full key parity to English (all ~1,640 UI strings), real Czech translations for every string and function-valued key (including Slavic plural forms for message/queue counts and tool-activity summaries), a Czech login screen, and a dedicated locale-parity + placeholder + diacritics test guard mirroring the other per-language suites. Thanks @ostravajih. (#5546) - - **Fork a scheduled-job (cron) conversation into your own editable chat.** Cron-run sessions are read-only (the scheduler owns them), so you couldn't continue one. You can now branch/fork a cron session into a new WebUI-owned conversation — the original read-only session is never modified, and the fork picks up its history so you can carry on. Only genuine cron sessions qualify (verified by the server-side source, not a guessable id), and every other read-only session stays unbranchable. Thanks @rodboev. (#5555, #5477) - **Pick the exact time and day for scheduled jobs — no cron syntax needed.** The Tasks "New job" form now builds the schedule as a plain sentence: choose a frequency (Hourly / Daily / Weekdays / Weekly / Monthly / Custom) and it shows just the controls that matter — a time picker, a day-of-week dropdown, or a day-of-month dropdown — e.g. "Weekly on Monday at 09:00." The generated cron expression is previewed inline, and the raw cron field now appears only under "Custom." Thanks @rodboev. (#5554, #5552) -- **Transparent Stream fades newly streamed words in.** In Transparent Stream mode, newly arriving assistant words now fade in at the prose level as they stream — without animating (or re-flickering) the thinking rows, tool rows, or the transparent event rows. It respects your OS "reduce motion" setting (no fade when reduced motion is on) and is part of the Transparent Stream experience regardless of the "Fade text effect" toggle. Thanks @rodboev. (#5506, #5367) - - **The Preferences default-model setting now uses the rich model picker.** The "Default Model" control in Settings → Preferences was a plain dropdown; it now uses the same searchable, provider-grouped picker as the composer (with a "Custom Model ID" field), so choosing a default model is consistent everywhere. On touch devices the picker no longer pops the keyboard the instant you open it (it still focuses search on desktop and while you're typing), and its label now activates the picker directly. Thanks @rodboev. (#5502, #5497) - **Scheduled jobs get a preset schedule builder.** The cron job form now has a "Preset" dropdown (Hourly / Daily / Weekdays / Weekly / Monthly, plus Custom) above the Schedule field — pick one and it fills the schedule for you (e.g. Daily → `0 9 * * *`, Hourly → `every 1h`) instead of hand-writing a cron expression. "Custom" keeps the free-text field, and editing an existing job maps its schedule back to the matching preset. Thanks @rodboev. (#5438, #5427) @@ -121,26 +107,6 @@ - **Russian localization refreshed and onboarding notes localized.** The `ru` bundle was refreshed and brought to full key parity with English (identical key sets across all locales), new update/workspace UI strings were propagated to every locale, and onboarding provider notes now resolve through a localized key (with the English text preserved as fallback). Thanks @DrMaks22. (#5778) -- **A pending prompt no longer renders twice across a context-compaction boundary.** On reload / reattach to an active turn, a synthetic `[CONTEXT COMPACTION]` marker (a user-role row that isn't a real submitted turn) placed after your prompt was treated as the latest user message, so the tail scan missed the actual prompt right before it and rendered the same pending prompt twice. The session-load and refresh/reconnect tail scans now skip compaction markers when locating the current user message, while completed assistant rows stay hard boundaries so genuinely-repeated prompts still render. Thanks @starship-s. (#5920) - -- **Sessions from Zed and other ACP (Agent Client Protocol) clients now show up in the sidebar.** An ACP-adapter session persists to the agent database with source `acp`, which was classified as `other` and fell through both sidebar buckets — so those conversations were completely invisible and unclickable. ACP sessions are now grouped with the CLI/TUI family (labelled "ACP"), with the same zero-message / ended-connection hiding rules as other interactive agent sessions. Thanks @ai-ag2026. (#5939) - -- **Date-stamped legacy Claude 3.0 model ids no longer show reasoning-effort controls they don't support.** The capability check read an 8-digit date suffix (e.g. `claude-3-opus-20240229`) as the model's minor version, so a bare date-stamped Claude 3.0 id wrongly qualified as reasoning-capable. The minor-version match is now bounded (mirroring the existing date-stamp defense), so date-stamped Claude 3.0 ids correctly hide reasoning-effort options while Claude 3.7 / 4.x / adaptive keep them. Thanks @nankingjing. (#5934) - -- **Transparent Stream no longer flickers or flips its tool-activity view during a turn.** On an experimental build, a live transparent-stream turn with tool calls would repeatedly rebuild its rows each stream tick (flicker) and flip the tool-activity area between the grouped "Processed Ns" summary and the individual per-event row list (alternating). Root cause: a recent change let a hardcoded caller hint force the compact grouped-worklog frame onto a transparent turn instead of honoring your selected activity-display mode. The active display mode is now authoritative — the caller hint is only a fallback — so a transparent turn renders stable individual rows, a compact turn keeps its grouped worklog, and hide-all stays hidden. Verified by a deterministic stream-regression gate across all three activity modes and the full submit / reload / switch-away lifecycle. (#5946, #5942, #5943, #5367) - -- **Context chips restart at "Context 1" after you clear them.** The selection counter used to only ever increment, so clearing all context chips (or switching sessions) and selecting new text started at "Context N+1" instead of "Context 1". The counter now resets whenever the last chip is removed and on clear-all / session switch, so chip numbering starts fresh each time. Thanks @akay64. (#5929) - -- **The agent no longer tells you a stored credential is "wrong" when it's just masked.** Secrets are redacted (`***`, `sk-abc…xyz1`) before the model sees them, but nothing told the model that masking was intentional — so it sometimes read a masked API key or password and reported it as a typo or a placeholder. The WebUI progress-guidance prompt now explains that redacted credential fields are deliberate masking, so the agent stops flagging correctly-stored secrets as errors. Thanks @mvanhorn. (#5927, #5871) - -- **Stale "unread" dot no longer lingers on a session after you open it.** Visiting a session now clears its sidebar unread indicator across the paths that previously left it stuck — the same-session reselect, the metadata-arrival ack, and the post-message-load re-sync — while a completion that lands in a genuinely hidden/background tab correctly stays unread. It also stops a phantom unread/streaming indicator from appearing when you switch from a busy session to an idle one (the idle session's streaming flags are now reset from its own metadata before the sidebar repaint, instead of inheriting the previous session's busy state). Thanks @neaucode-bot. (#5917, #4946) - -- **Plugin-provided model providers route correctly when set as the default.** A model from a plugin-only provider (e.g. a `@plugin:model` route) was surfaced in the catalog but, when that plugin provider was also the configured default, the request dropped the `@plugin:` routing hint and went to the wrong backend. Provider-hint resolution now applies plugin routing before the configured-provider bare-passthrough. Thanks @alexfoxtm. (#5909, #5461) - -- **Composer no longer double-sends or re-uploads on a fast second send.** The message text + its attachments are now captured and the textarea cleared immediately on send, before the async upload round-trip, so a re-entrant / interrupt-mode send can't re-read stale composer text and submit the same message twice or inherit the previous send's attachment. A clipboard-copy failure after a successful send no longer shows a false "failed", and a draft typed during the upload window is no longer clobbered. Thanks @harryazj. (#5912, #4750) - -- **Mobile dictation stays alive through natural pauses.** On touch devices the composer mic now keeps a dictation session going across the brief silences that used to end it (desktop stays one-shot), with a serialized screen wake-lock so rapid start/stop/visibility changes can't leak or drop it, and cleaner fallback to recording when the browser's speech recognition is unavailable. Thanks @brianmmaina. (#5915, #4732) - - **Concurrent remote-gateway health checks no longer stampede the gateway.** When many requests needed a remote-gateway health probe at once, each fired its own probe (a thundering herd). Probes are now single-flighted: one "leader" thread probes while latecomers wait (bounded) and share the result, guarded by a single condition/lock with a `finally` that always releases waiters even if the probe errors. Thanks @ai-ag2026. (#5798, #5455) - **Appending run-journal events no longer gets slower as a session's journal grows.** The next sequence number was recomputed by scanning existing entries on every append (O(n²) over a session's lifetime); it's now cached per journal path (guarded by a dedicated lock, evicted on journal delete), making each append O(1). Thanks @ai-ag2026. (#5799) @@ -293,8 +259,6 @@ - **Windows: after an upgrade, browsers no longer keep serving stale JS/CSS when git isn't on the server's PATH.** When the WebUI server was launched on Windows from an environment without git on `PATH` (a venv, a service wrapper, a non-interactive launcher), version detection silently degraded to `unknown`, which froze the `?v=` static-asset cache key — so browsers kept serving cached `ui.js` / `messages.js` / CSS even after the server restarted with fixed code, and the only workaround was a manual hard-refresh on every device. Version detection now resolves `git.exe` from the Git-for-Windows registry key (and common install paths) when it isn't on `PATH`, so the cache stamp updates and clients pick up frontend fixes automatically. Non-Windows behavior is unchanged. Thanks @allenliang2022. (#5522) -- **Transparent Stream is smoother during streaming — less row churn and no thinking-block scrollbar flicker.** Building on the identity-preserving live-row reconcile, the renderer now skips redundant work while a response streams: a preserved row's markup isn't rewritten when the incoming HTML is unchanged, a row isn't reinserted when it's already in the correct position, and long thinking blocks no longer flicker an internal scrollbar as their scroll container appears. Purely a reduction of no-op DOM work — what renders is unchanged, and matching rows still preserve their DOM node, copy button, tool-call data, and expanded/collapsed state. Thanks @Stacey2911. (#5456, #5367) - - **Models from a user-defined provider in `config.yaml` now route correctly.** If you defined a custom provider under the `providers:` block with an explicit `models:` allowlist, a bare model id from that list wasn't matched by request-time routing — it silently fell back to the default provider and often 404'd. Resolution now scans your `providers:` allowlists (exact match, same as `custom_providers:`), so those models reach the right endpoint. Copilot is deliberately excluded from this scan because `providers.copilot.models` is a per-model settings map (reasoning effort, limits), not a routing allowlist. Thanks @akay64. (#5511) - **The transcript no longer scrolls up when the composer grows.** When you were pinned to the bottom of a conversation and the composer got taller — multi-line typing, `Shift+Enter`, or a multi-line / dictation paste — the transcript viewport shrank by the same amount and left you stranded a row or two above the bottom (it read as the chat "randomly scrolling up" during normal use). The transcript now re-pins to the bottom whenever the composer grows, but only when you were genuinely still pinned there — if you'd scrolled up to read history, nothing yanks you back down. (#5516, #5514, #5515) @@ -343,8 +307,6 @@ - **The sidebar's session action menu no longer closes the moment you scroll the chat.** Opening a session's "…" action menu and then scrolling the conversation used to dismiss the menu immediately, because any scroll event closed it. Scrolls inside the chat transcript are now ignored (the menu stays put), scrolls of the sidebar list itself reposition the menu to keep it anchored to its row, and if a session-list refresh detaches that row the menu closes cleanly instead of floating orphaned. Thanks @nankingjing. (#5402, #5347) -- **Transparent Stream no longer flickers or drops rows while the assistant is responding.** With Activity Display set to Transparent Stream, the live response area (text, thinking, and tool rows) used to visibly blink on every streamed update because the renderer tore down and rebuilt every live row each tick, replaying the entrance animation. Live rows are now reconciled by identity across rerenders — matching rows are refreshed in place (preserving the DOM node, its copy button, tool-call data, and expanded/collapsed state), stale rows are removed, and only genuinely new rows animate in. Thanks @rodboev. (#5400, #5367) - - **The profile dropdown opens instantly instead of stalling on a cold fetch.** On installs with many profiles (or slow profile metadata), clicking the profile chip used to block on a fresh `/api/profiles` request before the menu appeared, so it felt unresponsive for up to a few seconds. The dropdown now opens immediately from a short-lived cache (rendering a lightweight loading shell when there's no cache yet) and refreshes fresh data in the background; a malformed cache row is validated and purged rather than shown, and a single-profile install keeps its shared cache intact. Thanks @ruizanthony. (#5412) - **Hardened the built-in text-to-speech proxy against a DNS-rebinding attack (SSRF).** When you route text-to-speech through an OpenAI-compatible endpoint, the proxy used to validate the target host's address and then resolve it again to connect — a gap an attacker-controlled DNS server could exploit to answer "public" during the check and "internal" at connect time, redirecting the request (with your API key attached) at a machine on your private network. The proxy now resolves the host once, validates every returned address up front (rejecting any private/loopback/link-local/reserved target), and connects only to those already-vetted addresses — while keeping the original hostname for TLS/SNI so certificate validation is unaffected. Multi-address hosts still fail over correctly across their vetted addresses, environment proxies can't bypass the direct dial, and redirects can't carry your token elsewhere. Thanks @rodboev. (#5407, #5291) @@ -373,8 +335,6 @@ ### Documentation -- **Full accuracy refresh of `ROADMAP.md`.** The roadmap had drifted well behind what the project actually ships and was missing entire surfaces. This pass rewrites every section to reflect current reality — the extension system (loader, gallery, manifest contract, theme/TTS/nav/sidecar capabilities, per-extension settings + owned storage, trust model, vetted library repo), concurrent per-profile isolation, native Android app, release channels, and the StewardOS generalization — and switches version/test-count/release-history to be derived live rather than stamped, so the doc no longer goes stale every release. (#5709) - - **Documented the reverse-proxy basic-auth caveat for installed PWAs.** README, onboarding, and troubleshooting now explain that proxy basic auth can block the same-origin service-worker/shell update fetches an installed PWA needs (leaving it on a blank screen after an update), and give recovery steps — prefer WebUI's built-in password, or scope proxy auth so `sw.js`/manifest/shell requests complete. Thanks @rodboev. (#5673, #2781) - **Documented the `HERMES_WEBUI_*` environment variables and refreshed stale version/test/locale references.** README, ARCHITECTURE, TESTING, ROADMAP, SPRINTS, and the `.env` example files now describe the supported runtime env vars (host/port/state-dir/agent-dir/home) and no longer carry stale hardcoded version/test-count/locale figures. Thanks @mo7al876any. (#5536) @@ -401,6 +361,54 @@ - **The busy-time send behavior is now called "Default message mode," and new installs default to Steer.** The Settings → Preferences control formerly labeled "Busy input mode" is renamed to "Default message mode," and a fresh install now defaults to **Steer** (inject a mid-turn correction without interrupting) instead of Queue. Your existing choice is preserved — if you ever saved settings, your current mode (Queue/Interrupt/Steer) is migrated as-is and unchanged; only never-configured installs pick up the new Steer default. The saved preference still survives a reload or a brief server outage (the localStorage mirror from the previous release is intact). Thanks @rodboev. (#5162, #5145) +## [v0.52.41] — 2026-07-14 + +### Performance + +- **"Max" reasoning-effort level (opt-in, availability-gated).** The reasoning selector now offers `Max` for models that actually support it (Claude adaptive-thinking 4.6+, DeepSeek), matching the level Hermes core already accepts. `Max` is shown *only* when the active model genuinely supports it — it's hidden for GPT-5 / o-series / Gemini / legacy Claude and stripped anywhere it would be rejected, and a stored/CLI `max` on a model that can't take it degrades to the next supported level (`xhigh`) instead of erroring. (One known edge: an aggregator provider like OpenRouter/Copilot that returns no per-model capability data can't confirm support, so `max` stays selectable there and would fall back at the provider if the specific model doesn't support it — same behavior as the CLI.) Thanks @perejaslav. (#5910, #4627) + +- **Opt-in: start a new chat when switching workspace.** A new default-off setting (Settings → Preferences → "Start a new chat when switching workspace"). When enabled, selecting a *different* workspace starts a fresh conversation bound to that workspace and leaves your current chat on its original workspace — avoiding stale cross-workspace context carrying into the conversation. Selecting the same workspace stays an in-place refresh, and when the setting is off (the default) switching workspace changes the current conversation's workspace in place exactly as before, so nothing changes for anyone who doesn't opt in. Thanks @ruizanthony. (#5473) + +- **Public read-only conversation sharing.** You can now opt in to share a single conversation via a public link (session action menu → Share). The link serves a redacted, read-only snapshot at `/share/` that anyone can view without logging in — nothing is public unless you explicitly share it, and you can revoke the link at any time (Stop sharing). The public page renders the transcript through the same sanitized markdown path as the app, is theme- and skin-aware (light/dark + all skins), and looks clean on desktop and mobile. The share payload is hardened at a dedicated always-on boundary: credentials, local workspace/worktree/home paths, system/tool messages, and any non-text structured content are stripped regardless of your API-redaction setting; only the conversation title and user/assistant text reach the public snapshot. Share tokens are 144-bit CSPRNG; create/revoke stay authenticated + CSRF-protected. Thanks @MicoRobot. (#5337) + +- **Per-event timestamps in the Transparent Stream worklog.** In Transparent Stream activity mode, each worklog event row (thinking / tool call) now shows a small right-aligned time label, so you can see when each step of a long agent run happened — useful for telling whether a run is progressing or stuck. The timestamp resolves from whatever timing the event carries (falling back to the observed live time only for a genuinely live event, never fabricating a time for a recovered/replayed old session), persists correctly when the turn settles, and carries a full date+time tooltip on hover so a session reviewed days later isn't date-ambiguous. The label is hidden on narrow (<420px) viewports so it never squeezes the command preview, and Compact Worklog / Final answer only modes are unaffected. Thanks @rodboev. (#5739, #5700) + +- **New "Final answer only" chat activity display mode.** Settings → Appearance → Activity display now offers a third option beside Compact Worklog and Transparent Stream: "Final answer only" hides all activity rows (thinking, tool calls, worklog) and shows just the assistant's final answer — the clean, minimal output style of ChatGPT/Claude. It's a pure display lens (opt-in; the default stays Compact Worklog), so no activity data is lost — switching modes re-renders the same conversation with more or less detail. Thanks @rodboev. (#5746, #5706) + +- **Czech (Čeština) is now a fully-supported UI language.** Added a complete Czech (`cs`) locale to Settings → Language with full key parity to English (all ~1,640 UI strings), real Czech translations for every string and function-valued key (including Slavic plural forms for message/queue counts and tool-activity summaries), a Czech login screen, and a dedicated locale-parity + placeholder + diacritics test guard mirroring the other per-language suites. Thanks @ostravajih. (#5546) + +- **Transparent Stream fades newly streamed words in.** In Transparent Stream mode, newly arriving assistant words now fade in at the prose level as they stream — without animating (or re-flickering) the thinking rows, tool rows, or the transparent event rows. It respects your OS "reduce motion" setting (no fade when reduced motion is on) and is part of the Transparent Stream experience regardless of the "Fade text effect" toggle. Thanks @rodboev. (#5506, #5367) + +### Fixed + +- **A pending prompt no longer renders twice across a context-compaction boundary.** On reload / reattach to an active turn, a synthetic `[CONTEXT COMPACTION]` marker (a user-role row that isn't a real submitted turn) placed after your prompt was treated as the latest user message, so the tail scan missed the actual prompt right before it and rendered the same pending prompt twice. The session-load and refresh/reconnect tail scans now skip compaction markers when locating the current user message, while completed assistant rows stay hard boundaries so genuinely-repeated prompts still render. Thanks @starship-s. (#5920) + +- **Sessions from Zed and other ACP (Agent Client Protocol) clients now show up in the sidebar.** An ACP-adapter session persists to the agent database with source `acp`, which was classified as `other` and fell through both sidebar buckets — so those conversations were completely invisible and unclickable. ACP sessions are now grouped with the CLI/TUI family (labelled "ACP"), with the same zero-message / ended-connection hiding rules as other interactive agent sessions. Thanks @ai-ag2026. (#5939) + +- **Date-stamped legacy Claude 3.0 model ids no longer show reasoning-effort controls they don't support.** The capability check read an 8-digit date suffix (e.g. `claude-3-opus-20240229`) as the model's minor version, so a bare date-stamped Claude 3.0 id wrongly qualified as reasoning-capable. The minor-version match is now bounded (mirroring the existing date-stamp defense), so date-stamped Claude 3.0 ids correctly hide reasoning-effort options while Claude 3.7 / 4.x / adaptive keep them. Thanks @nankingjing. (#5934) + +- **Transparent Stream no longer flickers or flips its tool-activity view during a turn.** On an experimental build, a live transparent-stream turn with tool calls would repeatedly rebuild its rows each stream tick (flicker) and flip the tool-activity area between the grouped "Processed Ns" summary and the individual per-event row list (alternating). Root cause: a recent change let a hardcoded caller hint force the compact grouped-worklog frame onto a transparent turn instead of honoring your selected activity-display mode. The active display mode is now authoritative — the caller hint is only a fallback — so a transparent turn renders stable individual rows, a compact turn keeps its grouped worklog, and hide-all stays hidden. Verified by a deterministic stream-regression gate across all three activity modes and the full submit / reload / switch-away lifecycle. (#5946, #5942, #5943, #5367) + +- **Context chips restart at "Context 1" after you clear them.** The selection counter used to only ever increment, so clearing all context chips (or switching sessions) and selecting new text started at "Context N+1" instead of "Context 1". The counter now resets whenever the last chip is removed and on clear-all / session switch, so chip numbering starts fresh each time. Thanks @akay64. (#5929) + +- **The agent no longer tells you a stored credential is "wrong" when it's just masked.** Secrets are redacted (`***`, `sk-abc…xyz1`) before the model sees them, but nothing told the model that masking was intentional — so it sometimes read a masked API key or password and reported it as a typo or a placeholder. The WebUI progress-guidance prompt now explains that redacted credential fields are deliberate masking, so the agent stops flagging correctly-stored secrets as errors. Thanks @mvanhorn. (#5927, #5871) + +- **Stale "unread" dot no longer lingers on a session after you open it.** Visiting a session now clears its sidebar unread indicator across the paths that previously left it stuck — the same-session reselect, the metadata-arrival ack, and the post-message-load re-sync — while a completion that lands in a genuinely hidden/background tab correctly stays unread. It also stops a phantom unread/streaming indicator from appearing when you switch from a busy session to an idle one (the idle session's streaming flags are now reset from its own metadata before the sidebar repaint, instead of inheriting the previous session's busy state). Thanks @neaucode-bot. (#5917, #4946) + +- **Plugin-provided model providers route correctly when set as the default.** A model from a plugin-only provider (e.g. a `@plugin:model` route) was surfaced in the catalog but, when that plugin provider was also the configured default, the request dropped the `@plugin:` routing hint and went to the wrong backend. Provider-hint resolution now applies plugin routing before the configured-provider bare-passthrough. Thanks @alexfoxtm. (#5909, #5461) + +- **Composer no longer double-sends or re-uploads on a fast second send.** The message text + its attachments are now captured and the textarea cleared immediately on send, before the async upload round-trip, so a re-entrant / interrupt-mode send can't re-read stale composer text and submit the same message twice or inherit the previous send's attachment. A clipboard-copy failure after a successful send no longer shows a false "failed", and a draft typed during the upload window is no longer clobbered. Thanks @harryazj. (#5912, #4750) + +- **Mobile dictation stays alive through natural pauses.** On touch devices the composer mic now keeps a dictation session going across the brief silences that used to end it (desktop stays one-shot), with a serialized screen wake-lock so rapid start/stop/visibility changes can't leak or drop it, and cleaner fallback to recording when the browser's speech recognition is unavailable. Thanks @brianmmaina. (#5915, #4732) + +- **Transparent Stream is smoother during streaming — less row churn and no thinking-block scrollbar flicker.** Building on the identity-preserving live-row reconcile, the renderer now skips redundant work while a response streams: a preserved row's markup isn't rewritten when the incoming HTML is unchanged, a row isn't reinserted when it's already in the correct position, and long thinking blocks no longer flicker an internal scrollbar as their scroll container appears. Purely a reduction of no-op DOM work — what renders is unchanged, and matching rows still preserve their DOM node, copy button, tool-call data, and expanded/collapsed state. Thanks @Stacey2911. (#5456, #5367) + +- **Transparent Stream no longer flickers or drops rows while the assistant is responding.** With Activity Display set to Transparent Stream, the live response area (text, thinking, and tool rows) used to visibly blink on every streamed update because the renderer tore down and rebuilt every live row each tick, replaying the entrance animation. Live rows are now reconciled by identity across rerenders — matching rows are refreshed in place (preserving the DOM node, its copy button, tool-call data, and expanded/collapsed state), stale rows are removed, and only genuinely new rows animate in. Thanks @rodboev. (#5400, #5367) + +### Documentation + +- **Full accuracy refresh of `ROADMAP.md`.** The roadmap had drifted well behind what the project actually ships and was missing entire surfaces. This pass rewrites every section to reflect current reality — the extension system (loader, gallery, manifest contract, theme/TTS/nav/sidecar capabilities, per-extension settings + owned storage, trust model, vetted library repo), concurrent per-profile isolation, native Android app, release channels, and the StewardOS generalization — and switches version/test-count/release-history to be derived live rather than stamped, so the doc no longer goes stale every release. (#5709) + ## [v0.52.28] — 2026-07-13 ### Added