- **Agent Chat groups by project.** History search now sections "Recent Conversations" per project (
name · count), and the Agents list grows project headers as soon as it spans more than one. - **⌥⌘L to focus the composer is a real setting.** The overflow row said "click to change" while the key monitor compared a hardcoded chord — remap one and the two disagreed. Both now read the same live binding.
- **Retry no longer asks your question twice, and closing a tab no longer deletes a transcript silently.**
- **Retry on a failed turn appended a second copy of your question.**
retryFailedAssistantset the draft and calledsendDraft(), which without a resend source appends a *new* user turn — one failure left "user · assistant(failed) · user · assistant", duplicating the turn in the transcript and in the next prompt. It now goes throughtruncateAndResendFromUserTurn: drop the failed bubble, clear the provider session, re-send with the original attachments. A stale bubble falls back to Continue instead of guessing at the last user message. - **English users saw Chinese, and Chinese users saw English.** A full-source scan for the three hard defects (EN row containing CJK / CJK default with no catalog row / missing EN row) is now clean.
agentChat.action.keyboardShortcutsdefaulted to "快捷键"; the Agent Customizations "Plugins" section defaulted to "知识与连接器";agentChat.sessions.importBody/importEmptyhad "终端 Resume" inside their **EN** rows and their zh-Hans / zh-Hant rows were still English placeholders. Five gear keys that existed only as code defaults (Models / Rules / MCP / All settings / gear help) gained real catalog rows. - **Closing a conversation tab permanently deleted its transcript with no warning.** Both the tab ✕ and the right-click Close now confirm first; an empty conversation still closes in one click.
- **Every product chat returned HTTP 502.**
qwen3.8:27bon ttqq 400s on every ping while still being listed by/v1/models, and a 400 never triggers fallback. The repo-side contract now matches the live admin config: default product models rideqwen3.6:35b-a3bwith aqwen3.6:27bfallback, and dead 3.8 aliases normalize to 3.6 instead of being rewritten back onto 3.8. - **Bonsplit left a blank pane after moving or closing a tab.** Vendor bumped to
f988e36: a stale selection falls back to the first tab, and the tab context menu is localized (en/ja plus new zh-Hans/zh-Hant). - **Agent Chat disabled controls still looked enabled.**
.plainand.borderlessButtonkeep an explicit tint, so gated icons never dimmed on their own.
- **Every Ask / Plan / Agent segment states its own scope** as help, so the three can be compared before you commit instead of discovered by trying. Context depth had no surface in the composer at all; its current value now rides the policy-overflow help.
- **Header overflow drops its duplicate entries.** Show/Hide Agents list (the header already has that toggle), Permissions (the policy overflow Approval section opens the same sheet), and MCP / Skills (the composer gear already jumps to both) are gone. One entry remains — Agent Customizations — and it stays enabled while a turn runs, so the header path is never a dead end. The composer gear gained a Skills jump so it is the single section shortcut.
- **Disabled states are honest.** Every secondary composer control carries a disabled-reason tooltip, the primary button has four explicit states instead of a click that does nothing, and gated icon controls no longer keep their live tint. Header and composer icon controls now share one metric (
agentIconControlSize = 22, previously 22/24 by call site). - **Tool status chrome is unified** behind
AgentChatToolStatusChrome(icon, label, color, rollup and research icons in one place), and tool cards plus rollups now show per-step elapsed — running chips tick, finished chips freeze from their timestamps, and a terminal event withoutcompletedAtshows no fake duration. - **Message-level Branch and Delete.** The bubble context menu's "Branch from here" forks with
upToMessageIDand rewrites session memory (newmemoryTruncated), so summaries, plans, scout digests, delivery obligations and injection journals derived from post-cut turns cannot leak into the branch. "Delete messages from here" confirms, then truncates in memory **and** on disk, clearing the provider resume id. **Working-tree files are not reverted, by design.** - **Fork/delete hardened across legacy paths.** Transcript entries now use
message.idasentry.id(existing files still match viaparentID), truncation is disk-first and aborts on failure,provider_sessionentries before the cut are dropped so reconcile can never resurrect a deleted backend session, and compaction memory is preserved for tracked compaction while untracked memory resets.
- **Streaming publishes at flush cadence.** Deltas no longer publish
streamingContentone by one; newline, >200 chars, and the 0.2 s tick are the only publish points. A newchatStreamingPublishcounter makes the rate observable. - **Conversation rows are Equatable snapshot projections.** Rows no longer subscribe to the store, so streaming ticks stop rebuilding every row; diff stats gained a fingerprint cache (
messageCount+lastMessageID+updatedAt) that skips the transcript scan on a hit. - **Hot chrome short-circuits through
Equatable** (run status chip, queued list, context usage chip, composer primary button, changes bar). - **Semantic index cache is bounded.** A 128 MB budget over the decoded-index cache with LRU eviction; oversized indexes resolve per call and are never cached.
- **Stale-index GC stays off.** Auto-deletion remains
staleSweepEnabled=false: liveness is only provable for one tab list while other windows and instances can read an index without rewriting it, so mtime proves nothing about use. The sweep logs a dry-run count only, until a durable cross-window workspace registry exists.
- Bumped version to **5.1.24** (build **359**).




