We recently changed this given some new models (e.g., Fable) don't allow
turning thinking off. In those cases, we are not rendering the split
button anymore, but we should still display the thinking icon, so they
look a bit more consistent.
Release Notes:
- N/A
Sometimes, landing in the archive view at first, particularly after
importing ACP threads, can be confusing as there's not an immediately
available "create new thread" button users can click on.
Release Notes:
- N/A
## Summary
Add keyboard shortcut for macOS, in the ACP Permission dialog, for
"Always Allow", following what is available in both Linux and Windows.
### Self-Review Checklist
- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable
Release Notes:
- Added missing `AllowAlways` keybinding on macOS (`cmd-alt-y`).
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Allows contents to update without dropping the permission (caused by
claude subagents)
Closes
https://github.com/agentclientprotocol/claude-agent-acp/issues/708
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- acp: Fix failed permissions requests for external agents
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#58653
Release Notes:
- Fix "Loading Commit History..." message in History tab stuck on
projects with empty or no repositories
On transparent or blurred window backgrounds, several agent panel
surfaces and
the multibuffer header rendered drop shadows and fade gradients that
have no
opaque surface to blend into, so they showed up as dark halos or colored
patches:
- agent message boxes and the activity bar (drop shadows)
- diff-hunk Reject/Keep controls (drop shadow)
- the diff review pane (double-painted `editor_background`)
- agent thread-list rows, the conversation title edit affordance, and
sidebar
project headers (fade gradient)
- the multibuffer buffer header (`editor_subheader_background` + sticky
shadow)
These are skipped when `window_background_appearance` isn't `Opaque`.
Opaque
windows are unchanged; on transparent windows the elements stay
delineated by
their borders and truncate text with an ellipsis instead of fading.
## Screenshots
Before:
<img width="1920" height="1200" alt="Screenshot 2026-06-09 at 3 26 26
PM"
src="https://github.com/user-attachments/assets/7dc9c76c-7de9-4c50-8719-05957d091706"
/>
After:
<img width="1728" height="1117" alt="Screenshot 2026-06-09 at 3 26 29
PM"
src="https://github.com/user-attachments/assets/889a53ad-9f11-41b9-9f51-ffcbd5c37821"
/>
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed dark shadow and gradient artifacts in the agent panel and
multibuffer headers when using a transparent or blurred window
background
This PR fixes some cases where scrolling is choppy due to a user
inputting a scroll event while a list state is going through a
remeasure. Currently, the list state would ignore the user's scroll and
fall back to the pending scroll position, this PR fixes this by rebasing
the pending scroll onto the user's new scroll position.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- agent_panel: Improve scroll smoothness while a response is streaming
## Summary
- add an editor action for selecting the contents of the innermost
enclosing bracket pair
- register the action without assigning a default key binding
- cover cursor, selection, nested bracket, no-op, and multi-cursor cases
## Tests
- cargo fmt --check
- cargo test -p editor test_select_inside_enclosing_bracket --lib
- cargo test -p editor test_move_to_enclosing_bracket --lib
Release Notes:
- Added action to select the contents enclosed by brackets
## Summary
Exposes the existing recursive pane-size reset as a command-palette
action, so it can be invoked outside of vim mode.
The center pane grid's sizes can already be evened out by
double-clicking a divider, or via `vim::ResetPaneSizes` (`ctrl-w =`)
when vim mode is on, but there is no general action for it — so users
not in vim mode have no discoverable way to undo a drifted split layout
in one step.
## How it works
`workspace::ResetPaneSizes` (palette: "workspace: reset pane sizes")
calls the existing `Workspace::reset_pane_sizes`, which resets every
`PaneAxis` in the center pane group to equal flexes, recursing into
nested splits. The split structure is preserved — no panes are added,
removed, or rearranged, only their sizes are equalized. This is the same
path the vim `ctrl-w =` binding and the divider double-click already
use.
## Out of scope
- Docks (left/right/bottom panels) — they keep their existing `Reset
Active Dock Size` / `Reset Open Docks Size` actions.
- The terminal panel's internal splits — it is a separate panel, not
part of the center pane group.
- No default keybinding (palette-only); vim users keep `ctrl-w =`.
## Testing
Added `test_reset_pane_sizes`: builds a nested split (a horizontal axis
of three panes whose last child is a vertical split), skews every axis's
flexes, dispatches the action, and asserts every axis returns to uniform
sizes.
Release Notes:
- Added a `workspace: reset pane sizes` command that equalizes the sizes
of all panes in the center group
## Context
This follow-up was inspired by Christopher’s suggestion in the review
comment on #58483: long filenames should truncate in the middle so both
the beginning and the suffix/extension remain visible.
Previously, very long filenames in picker rows could still be clipped or
end-truncated, making files with shared prefixes hard to distinguish.
This adds middle-truncation support to GPUI text overflow and applies it
to filename-focused picker surfaces: the tab switcher and the Ctrl-P
file finder. Normal editor tab bar behavior remains unchanged and
continues to use the existing title length cap.
## How to Review
- **`crates/gpui/src/style.rs`, `crates/gpui/src/styled.rs`,
`crates/gpui/src/elements/text.rs`,
`crates/gpui/src/text_system/line_wrapper.rs`**: Adds
`TextOverflow::TruncateMiddle`, wires it through text layout, and
implements middle truncation while preserving valid text runs. Very
narrow widths now show the truncation affix instead of falling back to
the abruptly clipped original text.
- **`crates/ui/src/components/label/label_like.rs`,
`crates/ui/src/components/label/label.rs`,
`crates/ui/src/components/label/highlighted_label.rs`**: Exposes middle
truncation through the shared label components.
- **`crates/workspace/src/item.rs`, `crates/editor/src/items.rs`,
`crates/workspace/src/pane.rs`,
`crates/tab_switcher/src/tab_switcher.rs`**: Adds an explicit
tab-content opt-in for middle truncation. The tab switcher enables it,
while the normal tab bar and dragged tabs keep their existing behavior.
- **`crates/file_finder/src/file_finder.rs`**: Applies middle truncation
to Ctrl-P file finder filenames and lets the path shrink from the start
so long paths do not hide important filename suffixes.
Manual test before change :
[Screencast from 2026-06-10
22-59-28.webm](https://github.com/user-attachments/assets/5e032646-a48c-45f2-8fe2-0424507fd576)
Manual test after change :
[Screencast from 2026-06-10
22-54-48.webm](https://github.com/user-attachments/assets/4b9253da-f169-4ed1-bdd5-ee71dcf49a83)
## Self-Review Checklist
- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Improved long filename truncation in the tab switcher and file finder
so extensions remain visible.
Pasting text that merely starts with a scheme-like prefix (for example a
commit message like `editor: Fix crash in project panel`) over a
selection in a Markdown buffer would wrap the selection in a Markdown
link, because `url::Url::parse` accepts `editor:` as a valid URL scheme.
Paste now only treats clipboard text as a URL when the whole text is a
single standalone URL, using `linkify` (already a workspace dependency)
instead of `url::Url::parse`. Added a regression test covering the
scheme-like prefix case.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#59070
Release Notes:
- Fixed pasting text starting with a scheme-like prefix (such as
`editor: ...`) over a selection in a Markdown buffer incorrectly
creating a Markdown link.
This slightly reworks the extension CLI bump workflow - instead of
triggering on label push, it now triggers on workflow dispatch with a
message enforced to be added there.
This primarily allows us to add a message to these bumps to better
communicate what changes with that version of the CLI. Furthermore, we
can soon restrict the label to be only created by that workflow, which
has the advantage that it can only be based off of main. Also, it has
the nice side-effect that we actually only ever update the label if
everything worked properly.
Release Notes:
- N/A
After prompting an agent, no response was received and only a spinner
was shown. After updating and reopening Zed, the thread still appeared
in the sidebar but failed to restore with `Failed to Launch` / `no
thread found with ID: SessionId(...)`, and the original prompt was lost.
## Root cause
A native agent thread is tracked by two independent persistence layers:
- **Sidebar metadata** (`ThreadMetadataStore`) and the **serialized
agent panel** record the thread's `session_id` through fast, separate
write paths.
- **Thread content** (`ThreadsDatabase`) is written by a per-session
async task (`NativeAgent::save_thread`) that can still be in flight when
the process exits.
When a graceful quit or update restart raced that async content save,
the metadata/serialized session id was persisted but the content row was
not. On restore, the metadata gate passes, then `load_thread` finds no
content row and hard-fails with `no thread found with ID`.
## Fix
Register an `on_app_quit` handler on `NativeAgent` that synchronously
commits every newly created non-empty thread's content to
`ThreadsDatabase` during shutdown, keeping the two stores consistent
across a graceful quit/restart (the auto-updater's path).
Closes AI-374
Release Notes:
- Fixed agent threads failing to restore after quitting or updating Zed
while a response was still in progress
Fixes the agent panel silently reverting all pending subagent file
changes when an earlier message is edited and regenerated.
`ThreadView::regenerate` decides whether to auto-keep pending edits from
earlier prompts (behavior introduced in #43347) by scanning the parent
thread's entries for diffs. Subagent edits never appear there — they are
only forwarded to the parent's action log via the linked-log mechanism —
so the auto-keep step was skipped and `rewind`'s unscoped
`reject_all_edits` reverted all of them on disk, without confirmation.
The fix treats any earlier subagent tool call as potentially having
edits, so they get auto-kept just like direct edits from earlier
prompts. Keeping all edits is a no-op when the subagent made none. Edits
produced by the prompt being regenerated are still auto-rejected,
consistent with existing behavior.
Also adds a regression test
(`test_regenerate_keeps_pending_subagent_edits`) that reproduces the
full flow — subagent edit forwarded through a linked action log,
follow-up prompt, regenerate — and fails with the exact reported data
loss without the fix.
Closes AI-386
Closes https://github.com/zed-industries/zed/issues/58932
Release Notes:
- Fixed pending subagent file changes being discarded when editing an
earlier message in the agent panel.
When running `zed` [directly from a foreground
terminal](https://github.com/zed-industries/zed/issues/51351#issuecomment-4507962670)
(stable `zed-editor`, or zed dev builds via `cargo run` as in #51351),
Zed only enables the stdout log sink and never creates `Zed.log` on
disk. This causes `zed: open log` and `zed: reveal log in file manager`
to always failed with `Unable to access/open log file ...: Failed to
read file... No such file or directory (os error 2)`.
Per maintainer feedback, rather than always creating the log file, this
change only registers the `OpenLog` and `RevealLogInFileManager` action
handlers when stdout isn't a PTY. In the PTY case the two actions no
longer appear in the command palette at all, so they can't be invoked
only to error.
Repro (before this change):
1. `rm -rf ~/.local/share/zed/logs/`
2. `~/.local/zed.app/libexec/zed-editor` (the GUI binary directly,
bypassing the CLI wrapper which detaches and sets `ZED_FORCE_CLI_MODE`)
3. In Zed, run `zed: open log` → error toast
Release Notes:
- Fixed `zed: open log` and `zed: reveal log in file manager` appearing
and erroring when Zed was launched directly from a terminal. These
actions are now hidden in that scenario, since logs go to stdout rather
than Zed's log file.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Self-Review Checklist:
- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: Martin Ye <martin@zed.dev>
Claude Fable 5 always thinks and cannot honor a request with thinking
disabled, but the cloud models listing gives clients no way to tell it
apart from models where thinking is optional (e.g. Claude Opus 4.6):
both report `supports_thinking: true` plus the same adaptive effort
levels. As a result, the agent panel shows a thinking toggle for Fable
even though turning it off isn't actually supported.
zed-industries/cloud#2789 adds a `supports_disabling_thinking` field to
the models listing. This PR mirrors it through
`cloud_llm_client::LanguageModel` (serde-defaulted to `false`, so a
server without the field is treated as "don't claim thinking can be
turned off") and exposes it as
`LanguageModel::supports_disabling_thinking()`, forwarded from the
listing by `CloudLanguageModel`. The agent panel now hides the thinking
toggle for models that report `false`, showing only the effort selector.
The trait default is `true`: every non-cloud provider in the tree treats
thinking as toggleable today, and only the cloud listing knows about
always-thinking models.
Draft until zed-industries/cloud#2789 lands and deploys.
Release Notes:
- Fixed the agent panel offering a thinking toggle for models that
cannot run with thinking disabled.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed a bug that prevented scrolling the sidebar when the mouse was
positioned over a project header.
## Summary
Routine housekeeping to remove seven inactive GitHub Actions workflows,
surfaced by a workflow-activity review (run history via the Actions
API).
The removals fall into two groups:
- **Four hand-written workflows** that are manually disabled, never run,
or long dormant.
- **Three xtask-generated workflows** (manual eval/perf tools) dormant
for >90 days — removed at the source in `tooling/xtask` and regenerated,
with now-unused helper code dropped.
Reusable workflows `extension_tests` and `extension_bump` were
intentionally **kept** — their low standalone run counts are an artifact
of `workflow_call` (they run constantly via `run_tests` and
`extension_auto_bump`), so they are not dormant.
## What is being removed
| Workflow | Roughly what it does | Author | Last run | Reason |
|---|---|---|---|---|
| `assign-reviewers.yml` | Auto-assigns reviewers to PRs (via a GitHub
App token) | John D. Swanson | 2026-04-17 | Manually disabled in Actions
settings |
| `assign_contributor_issue.yml` | Assigns/labels contributor issues and
notifies Slack | Lena | 2026-05-12 | Manually disabled in Actions
settings |
| `background_agent_mvp.yml` | Experimental background-agent MVP (manual
dispatch; schedule commented out) | morgankrey | 2026-02-24 | Dormant
>90 days; experimental, never promoted |
| `randomized_tests.yml` | Runs randomized tests via
`script/randomized-test-ci` | Max Brunsfeld | never | Never run; only
triggers on pushes to a branch that is never pushed |
| `compare_perf.yml` \* | Manual perf comparison between two commits for
a crate | Conrad Irwin | 2025-11-06 | Dormant >90 days; on-demand tool |
| `run_unit_evals.yml` \* | Manual agent unit evals for a given
model/commit | Ben Kunkle | 2025-11-14 | Dormant >90 days; on-demand
tool |
| `run_cron_unit_evals.yml` \* | Agent unit evals across a model matrix
(manual dispatch) | Richard Feldman | 2026-01-27 | Dormant >90 days;
on-demand tool |
\* xtask-generated — removed via `tooling/xtask` and regenerated (commit
2).
## Notes
- **Commit 1** removes the four hand-written workflows.
- **Commit 2** removes the three xtask-generated workflows: it deletes
their generator modules and registry entries, regenerates with `cargo
xtask workflows`, and drops the helper code left unused by the removal
(`vars` secrets and `steps::git_checkout`). Regeneration is a no-op for
all other workflows, and `./script/clippy` (deny-warnings) is clean.
Release Notes:
- N/A
On sign-in only, so it's a tiny change. I wonder if we could make the
error read nicer too, but at least now we're not throwing away the error
source anymore.
Release Notes:
- N/A
This is a bit too opinionated to be turning on for everyone by default.
We could consider bringing back a default-enabled setting with a less
intrusive UI.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Warnings about the lengths of commit message titles are now disabled
by default.
The git worktree picker shows worktrees open in the current window, but
had no way to remove them. This adds a "Remove Worktree from Window"
button (same `X` icon as the recent projects picker's "Remove Project
from Window") that closes the corresponding workspace in the
multi-workspace, without deleting the git worktree itself.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Added a button to the git worktree picker to remove an open worktree
from the current window.
Stop the Zed cloud LLM provider from funneling completion failures
through anyhow::Error and collapsing them into
LanguageModelCompletionError::Other (which surfaced as a generic
"Request failed.").
- perform_llm_completion now returns a typed
LanguageModelCompletionError, mapping each failure to its real variant
(SerializeRequest, HttpSend, ApiReadResponseError, and ApiError-derived
status variants).
- response_lines yields a typed ResponseStreamError so mid-stream read/
deserialize failures become ApiReadResponseError/DeserializeResponse
without a runtime downcast.
- Add a first-class PaymentRequired variant for HTTP 402 and remove the
now-dead PaymentRequiredError struct and its anyhow downcast checks.
Self-Review Checklist:
- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable
Closes #ISSUE
Release Notes:
- N/A
---------
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
Debugging an ignored Rust test whose code lives in a nested module (e.g.
`variant_get::test::get_complex_variant`) sometimes exited immediately
with "0 tests matched", When the test name itself came from tree-sitter
runnable capture, which sees only the bare function identifier. So
`--exact get_complex_variant` filtered out the actual test.
The fix is to only append `--exact` when the name contains `::`.
rust-analyzer's `experimental/runnables` produces qualified paths and
keeps the disambiguation introduced in #43110, and the runnables from
tree-sitter no longer break for nested modules.
Closes#51810.
Release Notes:
- Fixed debugging Rust tests in nested modules sometimes immediately
exiting with "0 tests matched".
Adds `default_open_behavior` which let's users control which action
should be the default (add to existing window/open a new window)
TODO:
- [x] Use sensible icon (not `IconName::Screen`) when
`default_open_behavior` is set to `new_window`
- [x] Tweak wording for actions in recent projects menu
<img width="420" height="59" alt="image"
src="https://github.com/user-attachments/assets/69ef112e-bf20-4dd1-9994-e4442266ef87"
/>
Release Notes:
- Added `default_open_behavior` which controls which action (add to
sidebar/open in new window) should be the default when selecting a
project from the recent projects menu
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Running `/compact` rendered a `/compact` user-message bubble during the
live session, but that text is never sent to the model as an ordinary
user turn — it triggers a built-in compaction that produces its own
"Context compacted" entry. Showing the bubble was misleading (it implied
the model received `/compact`), and it was also inconsistent: after a
reload the bubble vanished, since the persisted thread only carries an
empty marker. This changes the direction so native slash commands are
never echoed as user messages at all, live or after reload.
`AcpThread` gains a `send_command` path that runs the turn (so the agent
still receives and handles `/compact`) without pushing a user-message
entry or capturing a git checkpoint. In the UI, `leading_native_command`
now matches a native command whether or not it has trailing text, so
both `/compact` and `/compact do X` route through the command path; the
queued-message path detects native commands too, so a `/compact` typed
while a turn is generating behaves the same. MCP/ACP commands are
unaffected and still render as normal user messages, since their text is
a real argument the agent consumes.
Release Notes:
- N/A
---------
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Removes the `handoff` feature flag entirely and un-gates context
compaction so auto-compaction and the `/compact` command are available
to everyone. The `HandoffFeatureFlag` definition is deleted, and every
flag check is removed: auto-compaction always runs in the agent turn
loop (still governed by the `agent.auto_compact` setting and the model's
context window size), the `/compact` slash command is always registered
and routed to manual compaction, the token-limit callout always defers
to auto-compaction when the window is large enough, and the Auto Compact
settings always appear in the settings UI.
Merging this is the switch that ships the feature; until then it stays
stacked behind the telemetry and retry-fix PRs.
Release Notes:
- Added auto-compaction and /compact to Zed Agent
---------
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Fixes an issue where compaction would get marked as cancelled if the
previous turn took a while to cancel. E.g. you could reproduce this when
sending a normal message, and then interrupting generation by sending
`/compact`. If the task for the prior turn took a while to complete, it
would mark the compaction triggered by `/compact` as cancelled, even
though it was not.
Release Notes:
- N/A
Escaping control characters so they correctly render in the syntax tree.
Note: the original issue debates whether "\n" should be printed at all.
It should if it's part of the grammar syntax. In the example posted
below, "\n" is printed because it's part of the c-preprocessor grammar,
but "\t" which is not, is not printed.
Note2: I've added an inline test since I saw that only bigger,
integration tests get their own file. Feel free to give guidance on the
topic.
Screenshots of before and after:
<img width="920" height="579" alt="Screenshot 2026-06-10 at 10 42 14"
src="https://github.com/user-attachments/assets/697b65d2-4ca3-4d9b-9cb9-5bc05fe50bf1"
/>
<img width="918" height="580" alt="Screenshot 2026-06-10 at 10 46 20"
src="https://github.com/user-attachments/assets/cb83a105-81a1-4090-8d35-9def2bc1b552"
/>
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#54725
Release Notes:
- Fixed rendering of control-characters in syntax tree view
This PR builds out GPUI's benchmark harness so render benchmarks measure
realistic frame costs using GPUI-owned, runtime-gated instrumentation.
It adds measurements for frame draw time, dirty-to-draw latency,
invalidation coalescing, and frame-budget overruns, and runs benchmark
workloads with production-like concurrency.
## How it works
**Frame timings flow through the GPUI profiler.** `Window::draw` emits a
`FrameTiming { window_id, dirty_at, invalidations, draw_start, draw_end
}` event into a global ring buffer in `gpui::profiler`, mirroring the
existing task-timing channel. Collection is runtime-gated by
`profiler::set_frame_trace_enabled` (one relaxed atomic load when
disabled — no `Instant::now` calls in production). `BenchReport` is a
pure listener: it drains events through a cursor-based
`FrameTimingCollector` and builds histograms in the bench layer.
`Window` carries no bench-only cfg fields, and the same event channel
can later feed the miniprofiler UI or an in-app frame-time HUD.
**`BenchDispatcher`** is a multithreaded `PlatformDispatcher` for
benchmarks: background tasks run on a worker pool (same priority queue
as `LinuxDispatcher`, with task-profiler hooks), timers fire in real
time on a dedicated thread, and foreground tasks queue until the bench
thread drains them with a blocking `run_until_idle()`. Unlike
`TestDispatcher`, work executes in parallel in real time, so wall-clock
measurements reflect production concurrency. In-flight accounting is
panic-safe via drop guards.
**`gpui::bench_platform()`** returns a per-process `TestPlatform` backed
by the `BenchDispatcher`, cached in a thread-local so worker threads
persist across Criterion calibration passes. This replaces the earlier
approach of constructing a real platform per invocation, which had
process-global singleton issues, never ran foreground tasks (no run loop
pumped the main queue), and couldn't open windows on headless CI.
**Text shaping** uses `NoopTextSystem`: deterministic across
machines/font installations and CI-portable. Measured cost of this
trade: ~10% of editor draw time vs `MacTextSystem` (Noop still emits one
glyph per character at fixed advances, so downstream layout/paint
structure is preserved).
**GPU coverage (macOS only for now).** `PlatformHeadlessRenderer` gained
`render_scene`, which encodes and submits the scene to Metal against a
cached offscreen target without blocking on completion or reading pixels
back — matching production `present()` CPU cost (`render_scene_to_image`
would overstate it: it waits for the GPU and copies pixels back).
`TestWindow::draw` forwards scenes to the renderer, the real
`MetalAtlas` means glyph/SVG rasterization happens during paint, and
`bench_renderer` presents after each measured update. Platforms without
a headless renderer degrade to discarding the scene.
## Example
```rust
#[gpui::bench]
fn editor_render(cx: &mut BenchAppContext) {
init_context(cx);
let buffer = cx.update(|cx| { /* build a MultiBuffer */ });
let mut window = cx.add_empty_window();
let editor = window.update(|window, cx| {
let editor = window.replace_root(cx, |window, cx| {
let mut editor = Editor::new(EditorMode::full(), buffer, None, window, cx);
editor.set_style(editor::EditorStyle::default(), window, cx);
editor
});
window.focus(&editor.focus_handle(cx), cx);
editor
});
let mut move_down = true;
cx.bench_renderer(editor, move |editor, window, cx| {
if move_down {
editor.move_down(&MoveDown, window, cx);
} else {
editor.move_up(&MoveUp, window, cx);
}
move_down = !move_down;
});
}
```
## Example output (release, M-series)
```
editor_render time: [329.75 µs 330.17 µs 330.69 µs]
GPUI bench report (all observed iterations): editor_render
note: includes Criterion warmup/calibration
window dirty-to-draw:
samples: 31533
mean: 0.321ms
p50: 0.322ms
p90: 0.336ms
p95: 0.342ms
p99: 0.360ms
max: 0.504ms
frame budget overruns total: 0
frame budget overruns max: 0
window draw:
samples: 31533
mean: 0.295ms
p50: 0.295ms
p90: 0.307ms
p95: 0.313ms
p99: 0.330ms
max: 0.455ms
frame budget overruns total: 0
frame budget overruns max: 0
invalidations per frame: mean 5.00, max 5
```
(`invalidations per frame: mean 5.00` is real signal: each `move_down`
notifies the window five times before the draw.)
## Known limitations
- **Draw-per-flush**: the harness draws synchronously when effects flush
rather than coalescing invalidations to a vsync tick, so `dirty-to-draw`
excludes queueing delay, and `frame budget overruns` is a draw-time
budget proxy rather than actual missed presents. A frame-paced mode is
natural follow-up work.
- **GPU submission is measured on macOS only**; other platforms have no
headless renderer yet.
- The GPUI report includes Criterion warmup/calibration samples (noted
in the output); Criterion's `time` is the regression-gating number.
- `run_until_idle` waits for queued, running, and already-due work, but
not for timers that haven't reached their due time — the dispatcher runs
in real time and can't skip ahead like `TestDispatcher`'s virtual clock.
## Future work
- A vsync-like frame-pacing mode (suppress draw-on-flush; tick-driven
draw + present) so dirty-to-draw captures queueing delay
- Record present duration in `FrameTiming` so the report can split draw
vs present
- Benches that scroll through novel content (cold layout caches) and an
agent-panel render bench
- Headless renderers for Windows/Linux
- Move benches into a dedicated crate
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
Adds an `"Agent Compaction Completed"` telemetry event that fires for
both threshold-triggered auto-compaction and the manual `/compact`
command (both already behind the `handoff` flag). The event records the
model, model provider, thinking effort, the model's context window size,
the token counts immediately before and after compaction, whether the
compaction succeeded/failed/canceled (with the error string on failure),
the user's configured auto-compaction threshold (both the raw form and
the resolved absolute token count), whether auto-compaction is enabled,
and the number of retries.
Both compaction paths funnel through `stream_compaction`, so a
`CompactionTelemetry` snapshot is captured when a compaction starts and
stashed on the thread. On success, emission is deferred until the next
completion request reports usage, so `tokens_after` reflects the real
post-compaction context size rather than an estimate (we have no
token-counting API, and it's safe to assume a compaction is always
followed by another request). On failure or cancellation the event fires
immediately with no `tokens_after`. Retries are accumulated across
attempts so a single logical compaction produces exactly one event.
While wiring up retry counting I noticed the existing auto-compaction
retry path in `run_turn_internal` never increments `attempt`, so a
repeatedly-failing retryable compaction could retry without bound. I
left that behavior untouched as out of scope, but the new `retries`
field will surface it if it happens.
Release Notes:
- N/A
---------
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
The implementation for this is just below and the comment should have
been long removed.
At least one TODO less in the 100 existing ones 🎉
Release Notes:
- N/A
Fixes git graph showing an infinite loading state for repositories with
no commits. The bug happened because an empty `git log --all` result
completed successfully with zero commits, but the UI treated a loaded
graph with `0` commits as still loading instead of showing the empty
state.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#53399
Release Notes:
- Fixed git graph loading forever for empty repositories.
Anthropic now requires limited data retention for models it designates
as covered models (Mythos-class models, such as Claude Fable 5): prompts
and outputs are retained for 30 days for trust and safety purposes, on
every platform where these models are offered, including platforms with
zero-data-retention agreements. See [Anthropic's public
policy](https://support.claude.com/en/articles/15425996-data-retention-practices-for-mythos-class-models).
Our AI privacy docs previously described zero data retention as applying
to all Zed-hosted models unconditionally. This PR updates them to
document the exception:
- `docs/src/ai/privacy-and-security.md`: Adds a "Provider Safety
Retention for Designated Models" section covering what is retained, by
whom, for how long, that no-training commitments still apply, and that
bringing your own key does not avoid retention for covered models.
Qualifies the intro, request-path table, and provider commitments table
accordingly.
- `docs/src/ai/ai-improvement.md`: Qualifies the zero-data-retention
statements and links to the new section.
- `docs/src/business/privacy.md`: Qualifies the zero-data-retention
statement and links to the new section.
Release Notes:
- N/A
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes FR-67
Release Notes:
- N/A or Added/Fixed/Improved ...
Summary:
- Document `gpui_platform::application()` as the entry point for
standalone GPUI apps.
- Add platform-specific `gpui_platform` feature guidance for macOS,
Linux/FreeBSD, and Windows.
- Use Git dependencies for the repository-based setup example.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
This PR changes how base texts are managed by the `buffer_diff` crate,
to enable keeping two diff entities alive that share the same base text
buffer entity. Previously, each diff owned its own base text buffer and
edited it when calling `BufferDiff::set_snapshot`, so the only way to
reuse the same base text between two diffs was to have two independent
buffers for it, which is pretty inefficient.
After this PR, each diff still has a base text buffer, but
`set_snapshot` doesn't edit it. Instead, that responsibility moves into
the caller. For updating the base text buffer, this PR also introduces a
new pair of APIs, `Buffer::snapshot_with_edits` and
`Buffer::fast_forward`, which allow us to move the parsing of the new
base text into the background and then install the new syntax tree
synchronously on the foreground.
The git store uses the low-level APIs `set_snapshot` and `fast_forward`
directly, and manages the head text and index text buffers itself
(garbage-collecting them when they're no longer needed); this enables
adding an `open_staged_diff` API which returns a diff between the
managed index buffer and the managed head buffer (the latter is also
used for the uncommitted diff's base text). Other downstreams don't need
to reuse a base text buffer, and those have been migrated to use the
high-level `set_base_text` API, which now calls `set_snapshot` and
`fast_forward` internally, with a guard to prevent concurrent updates.
Another change worthy of note is that we now always diff the old base
text with the new base text to create `snapshot_with_edits`.
There are also some incidental bug fixes:
- Fixed an issue where a dangling weak unstaged diff could stick around
in the git store forever
- Restored the `IndexMatchesHead` optimization that had become
inoperative in the remote case
- Fixed a crash in the multibuffer due to the handling of
`BufferDiffEvent::LanguageChanged`, which could cause the multibuffer to
have transforms that were inconsistent with the diff base text.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes ZED-81P
Release Notes:
- Fixed a rare crash that could occur while using the uncommitted diff.
---------
Co-authored-by: Ben Kunkle <ben@zed.dev>
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
This PR updates the user menu to always show the list of organizations.
We had some logic in here to hide it if the user did not have an
organization selected, which was left over from before organizations
were fully rolled out.
Now that every user should be in at least one organization, we can
remove the old UI states.
Release Notes:
- N/A
Pins the remaining tag- and branch-referenced GitHub Actions and the
`postgres` service image to specific commit SHAs / digests, so workflow
runs resolve to fixed versions. Edited in the xtask workflow DSL and
regenerated with `cargo xtask workflows`.
- `bufbuild/buf-setup-action` → `a47c93e0` (v1.50.0)
- `bufbuild/buf-breaking-action` → `c57b3d84` (v1.1.4)
- `digitalocean/action-doctl` → `3cb39531` (v2.5.2)
- `postgres:15` → `@sha256:1b92e7a8…`
- `deploy_docs.yml` reusable workflow → pinned to a commit
Release Notes:
- N/A
The tokens are organization-specific (the organization id in the JWT
claims). Before this commit, the `LlmApiToken` cache was an
`Option<String>`, and `cached()` ignored the `organization_id` argument
on cache hit. Correctness relied on `RefreshLlmTokenListener` clearing
and refreshing the token when it observed an `OrganizationChanged`
event.
That leaves two windows where a token minted for the wrong organization
could be served from the cache:
- the refresh runs in a spawned task, so between the organization switch
and the task acquiring the write lock, any request calling `cached()`
would get the previous organization's token.
- `Client::authenticated_llm_request` snapshots the organization id at
call time; if the server demanded a token refresh after the user had
switched organizations mid-request, the retry path would mint a fresh
token for the old organization and write it into the shared cache,
poisoning it for all subsequent requests until the next refresh event.
The fix is to store the organization id corresponding to the token next
to it in the cache, and to check that the cached token is for the
correct organization in `cached()`.
Release Notes:
- Fixed a race where LLM and edit prediction requests made immediately
after switching organizations could be attributed to the previously
selected organization.
Fixes a macOS 27 beta regression where clicks on custom titlebar
controls were delayed by the system double-click interval.
After updating to macOS 27 dev beta, I noticed that our titlebar buttons
had a delay before click events took effect. After some digging, I
discovered that AppKit can treat that titlebar region as system-owned
and delay click delivery while waiting to disambiguate double-clicks. I
noticed that Slack had titlebar buttons that weren't affected by the
double-click disambiguation delay, so I had Claude dig through the
Chromium/Electron codebase to discover what they did differently.
Chromium uses a private AppKit SPI,
`_opaqueRectForWindowMoveWhenInTitlebar`, that allows them to set what
regions should be treated as owned by a view vs. owned by AppKit. My fix
uses the same API and returns the view bounds when
`NSWindowStyleMask::NSFullSizeContentViewWindowMask` is set, which
happens when a GPUI app uses a full-size content view for a custom
titlebar. Otherwise, we return bounds of `NSRect::new(NSPoint::new(0.,
0.), NSSize::new(0., 0.))` so apps using macOS's native titlebar still
work as expected.
### Before
https://github.com/user-attachments/assets/ba9e0d2d-b85c-4d98-bc7d-bea00368d9cf
### After
https://github.com/user-attachments/assets/b78bd7d4-6b43-48d3-a615-2c7a29e32e71
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed clicks on titlebar controls being delayed on the macOS 27 beta.