Commit Graph
39290 Commits
Author SHA1 Message Date
Kevin BravoandSmit Barmase 0c69ff7a3d markdown_preview: Open relative links at line (#60864)
Closes #60733

# Objective

Markdown Preview treats a relative `path:line[:column]` destination as a
literal filename. When that file does not exist, the link falls through
to the system URL handler instead of opening the workspace file at the
requested position.

## Solution

- Recognize position suffixes on relative Markdown links.
- Convert GitHub-style `#L42` fragments into the same positioned target
used by `path:42`, so both forms share one resolution and opening path.
- Resolve links with `workspace::path_link::possible_open_target` using
the Markdown source directory. This keeps the remote-project path
resolution added in #61438.
- Open resolved targets with `editor::items::open_resolved_target`,
including its one-based row and column handling.
- Preserve valid URI schemes and fall back to the existing Markdown link
behavior when no workspace target resolves.

## Testing

- Extended the Markdown Preview GPUI regression test to cover relative
`path:line:column`, GitHub-style `#Lline`, subfolder-relative
resolution, and custom URI schemes.
- `git diff --check` passes.
- The focused Rust test could not start in the current macOS environment
because the Rust toolchain binaries hang in the dynamic loader before
Cargo runs. PR Actions are awaiting maintainer approval.

## Self-Review Checklist:

- [x] I have reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed UI and icon guidelines
- [x] Tests cover the new and changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed Markdown Preview links using workspace-relative paths with line
and column suffixes.

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-07-28 05:45:13 +00:00
Ben Kunkle 1d61d7f42a agent: Report follow-up messages as tool permission denials (#61754)
# Objective

- Treat a follow-up sent during pending tool approval as a denial the
agent can understand.

## Solution

- Preserve the follow-up interruption through permission handling and
return a specific denial result to the model.

## 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: Fixed agents not recognizing follow-up messages as denial of
pending tool calls.
2026-07-28 03:18:02 +00:00
Conrad Irwin 298dde507b reqwest_client: Allow configuring a per-read idle timeout (#61753)
Long-lived streaming responses (LLM completions) can stall when the
socket goes silent but the connection is never closed, leaving a read
that never returns to hang the request indefinitely. Add an opt-in
read_timeout parameter.

Release Notes:

- N/A
2026-07-28 03:16:10 +00:00
Ben Kunkle 90483395af project: Fix panic when an inlay hint response outlives its buffer version (#61747)
# Objective

Fix a nightly crash where Zed aborts on a bounds-check panic in the
inlay hint cache.

`LspStore::inlay_hints` captures a `RowChunk` before awaiting the
language server, then reads the hint cache with that chunk's id
afterwards. If the buffer shrank meanwhile, `latest_lsp_data` has
already rebuilt the cache with fewer chunks, so the stale id indexes out
of bounds. Chunks are 50 rows, so the reported crash only needed a
~150-250 line deletion, not a drastic edit.

Regressed in #61523. Nightly only; the regressing commit is in no
release tag, so this never reached preview or stable.

Fixes ZED-AGY
Fixes FR-142

## Solution

- Return an empty result when the buffer version no longer matches, so a
stale chunk id can never index the rebuilt cache. The stale *writes*
were already guarded by this version check; only the read sat outside
it.
- An empty result is already treated as "not fetched", so the chunk is
simply re-requested on the next refresh.

## Testing

`test_inlay_hint_response_after_buffer_shrinks` reproduces the abort
deterministically and passes with the fix. Note that it drives the race
through a fake language server rather than a real one.

## 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:

- N/A
2026-07-27 21:04:36 +00:00
Finn Evers 380f9abbeb agent_ui: Use buffer font in more places (#61738)
Release Notes:

- N/A
2026-07-27 18:53:39 +00:00
Cameron Mcloughlin 6515e9889d release_channel: Allow compile time overrides that don't use include_str! (#61731)
Some crates in zed use `include_str!("../../zed/RELEASE_CHANNEL")`,
which breaks when used as a dependency in a crane nix build (each crate
is built in isolation).

This adds a compile time env var to skip that check, which allows crates
in the zed repo to be used as dependencies in a crane build.

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-27 18:20:35 +00:00
Ben Kunkle ecac6c00a6 Fix zoomed panels closing when focus moves within the panel (#59439)
Closes FR-139

Most focus-lost issues that close the agent panel in Zen mode stem from
panels returning a transient child editor's focus handle from
`Focusable::focus_handle`. The Zen-mode check closes the zoomed panel
when the focused element is not a descendant of the panel's focus
handle, so any focus movement inside the panel that landed outside that
child editor looked like the panel losing focus.

This PR separates the two roles that handle was serving:

- `Focusable::focus_handle` now always returns a stable handle tracked
at the panel's root element, used for containment checks (Zen-mode
auto-close, `toggle_panel_focus`, dock focus subscriptions).
- The new `Panel::activation_focus_handle` returns what should receive
focus when the panel is activated (e.g. a filter/commit/message editor)
and must be a focus-tree descendant of the root handle. All "focus the
panel" callsites in workspace/dock now use it.

Migrated panels: `AgentPanel` (including thread views and the toolbar
title editor), `CollabPanel`, `GitPanel`, `OutlinePanel`, and
`TerminalPanel` (previously delegated to the active pane, so focus in a
non-active pane dropped containment). `CollabPanel` activation falls
back to the panel root when signed out or collaboration is disabled,
since the filter editor isn't rendered in those states. Also fixes
duplicate element ids for tool calls with multiple content blocks.

Tests: a regression test that clicks tool-call output and focuses the
thread title editor while zoomed (both previously closed Zen mode), and
a dock-level test asserting the activation handle receives focus on
panel activation while the panel root reports containment.

Release Notes:

- Fixed zoomed panels (e.g. the agent panel in Zen mode) closing
unexpectedly when focus moved to elements inside the panel, such as tool
call output or the thread title editor.
2026-07-27 17:11:33 +00:00
Richard Feldman 1c2a643cde Fix Bedrock effort and regional routing (#61597)
Fixes Amazon Bedrock adaptive-thinking requests so the selected effort
reaches Anthropic models, and routes Claude Opus 4.7 and 4.8 through
their documented Japanese and Canadian inference profiles.

Release Notes:

- Fixed Amazon Bedrock effort selection and regional routing for Claude
Opus 4.7 and 4.8.
2026-07-27 15:59:19 +00:00
Levin Rickert 1c244c194b git_panel: Use specific label and prompt for reverting deleted file (#61554)
# Objective

I expected a different label for reverting a file deletion like Zed
already has for reverting a file creation.

## Solution

This PR implements a new label and prompt. VS Code also shows a
different prompt while keeping the label static but I think it makes
more sense to let both adapt.

## Testing

Just deleted a file and checked menu label and prompt.

## 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 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

## Showcase

<img width="363" height="139" alt="image"
src="https://github.com/user-attachments/assets/6be7e5b9-7250-449e-9cba-ea5a2099dd3a"
/>

<img width="349" height="240" alt="image"
src="https://github.com/user-attachments/assets/d87d5b4b-ff29-4976-8078-314c94a71896"
/>

---

Release Notes:

- Git Panel: Added specific label and prompt to context menu for
reverting a deleted file
2026-07-27 13:44:25 +00:00
saberoueslati 777b94dfb4 search: Preserve cleared query when reopening the text finder (#61585)
## Context

Closes #61394

The Text Finder persists the last query per workspace (in the
`text_finder_queries` table) so it can seed itself on reopen.
Persistence happens in `TextFinder::on_before_dismiss`, but it was
guarded by `if !query.is_empty()`, so clearing the query and dismissing
never wrote anything. The stale non-empty query stayed in the database
and got restored on the next open, making it impossible to "clear and
keep it cleared."

This removes the guard so dismissal always persists the current query,
including an empty one. The read side already treats an empty stored
query as "nothing to restore" (`load_last_search` returns `None` for an
empty string), so an empty write cleanly clears the seed instead of
leaving the previous query behind.

Manual test below :

[Screencast from 2026-07-24
15-24-33.webm](https://github.com/user-attachments/assets/ba305f54-8ec2-4d3d-be0b-e2eb001bb204)


## How to Review

**`crates/search/src/text_finder.rs`**

`on_before_dismiss` no longer gates the write on a non-empty query. It
always calls `store_last_search` with the picker's current query and
options. `store_last_search` still early-returns for workspaces without
a `database_id`, so unpersisted workspaces are unaffected, and
`load_last_search` still maps an empty persisted query to `None`, so
`seed_query` won't resurrect it. The active-item selection still takes
priority over the persisted value on reopen, so seeding from a live
editor selection is unchanged.

The tests' shared `init_test` now installs a test `db::AppDatabase`
global. This is required because the new test is the first one to
actually reach `TextFinderDb::global(cx)`. The existing
`test_dismiss_from_within_workspace_update` leaves the workspace's
`database_id` as `None`, so it short-circuits before touching the DB.

`test_clearing_query_does_not_restore_previous_query` exercises the real
persistence path: it assigns a workspace `database_id`
(`set_random_database_id` + `flush_serialization`), opens the finder
with a query, dismisses, and asserts the query round-trips through
`seed_query`; then it reopens, clears the query via `set_query("")`,
dismisses, and asserts `seed_query` is now `None`. The positive
round-trip assertion keeps the negative case from passing vacuously.

## 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:

- Fixed the project search / Text Finder restoring a previous query
after it had been cleared and dismissed
2026-07-27 12:59:33 +00:00
Tommy Hanandzed-zippy[bot] aefad70496 Revert force hardmark settings for documentation hover (#61622)
Closes https://github.com/zed-industries/zed/issues/60777

# Objective

- Due to #59426, forcing docString softmark to hardmark, an regression
has appeared. It causes all docString on different language to load
newLine (`\n`) by default, instead of soft wrap.
- By checking the issue, turns out we should not setting
`soft_break_as_hard_break: true`, this will make the hover docString
less
- Details can refer to #60777 

## Solution

- Revert settings by removing the line in `hover_popover.rs:742`

## Testing

- About the testing result and comparsion, you can refer to #60777
- Updated test `test_hover_markdown_preserves_soft_breaks` to
`test_hover_markdown_soft_breaks_reflow_per_commonmark`

## 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 an issue where hover documentation could have too many line
breaks.

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-27 12:43:36 +00:00
Tai Nguyenandzed-zippy[bot] 04e53be020 git_ui: Ensure discarding tracked changes respects staging state (#61608)
Closes #56020

Release Notes:

- Fixed Discard Tracked Changes discarding unstaged files

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-27 12:42:54 +00:00
Bobo db7d5ddd19 Skip [DONE] stream terminator in anthropic and google_ai SSE parsers (#61627)
## Problem

When `api_url` points to a proxy or gateway that appends `data: [DONE]`
to the SSE stream, every streaming completion fails with:

```
error deserializing Anthropic API response: expected value at line 1 column 2
```

In the UI this surfaces as **"error deserializing Anthropic API response
— Retrying (Attempt 3 of 3)"** followed by **"Connection Interrupted"**,
even though the proxy returned a well-formed stream and the model's full
response was already delivered before the terminator. The failure is
100% reproducible on multi-turn tool-use conversations (Zed reads the
stream to completion after each turn, so it always reaches the trailing
`[DONE]`) and intermittent on single-turn conversations (depending on
whether the connection closes before the line is read). The same class
of error appears in the `google_ai` crate as `Error parsing JSON: ...
"[DONE]"`.

Neither side is at fault here. Zed's current parser is a correct
implementation of the Anthropic and Gemini specs, which terminate
streams by connection close and never emit `[DONE]`; at the same time,
appending a `[DONE]` terminator is a common, legitimate convention among
SSE gateways. This PR is a compatibility improvement that makes Zed
robust to that widely-used stream shape, so streaming works whether or
not the upstream emits the terminator.

## Why Zed crashes but the Anthropic SDK does not

The Anthropic TypeScript and Python SDKs handle this correctly
**without** any explicit `[DONE]` check. Their SSE parser uses a
two-layer architecture:

1. **SSE framing layer** — parses `event:` / `data:` fields into
`{event, data}` objects without inspecting the data payload.
2. **Event dispatch layer** — only calls `JSON.parse` on events whose
`event` name is in a known whitelist (`message_start`,
`content_block_delta`, etc.). A bare `data:` line with no preceding
`event:` line yields `event: null`, which is not in the whitelist and is
silently ignored.

So when a proxy sends `data: [DONE]`, the SDK produces `{event: null,
data: "[DONE]"}`, the dispatch layer drops it, and `JSON.parse` is never
run on `[DONE]`. Claude Code and Cline both use the Anthropic SDK under
the hood, so they inherit this behavior and never crash on `[DONE]`.

Zed's `anthropic` and `google_ai` crates use a simpler single-layer
parser: strip the `data:` prefix, then unconditionally
`serde_json::from_str` the remainder. There is no event-name dispatch,
so `[DONE]` goes straight into the JSON parser — `[` looks like an array
start, `D` is not a valid value, serde reports `expected value at line 1
column 2`, and the stream dies.

## Fix

Add a one-line guard after prefix stripping: if the trimmed payload is
`[DONE]`, return `None` from the `filter_map` closure. This is a
lightweight equivalent of the SDK's whitelist-ignore behavior — same
result (silently skip the terminator), without restructuring the parser
into a full event-name dispatch architecture.

Two commits, one per crate:

1. `anthropic` — guard in `stream_completion_with_rate_limit_info`
2. `google_ai` — identical guard in `stream_generate_content`

## Scope

The other ten SSE-based providers in this repo (`open_ai`, `deepseek`,
`mistral`, `open_router`, `lmstudio`, `llama_cpp`, `copilot_chat`)
already handle `[DONE]` because their upstream specs (OpenAI-compatible)
define it as a required stream terminator. `ollama` (NDJSON) and
`bedrock` (AWS SDK event stream) do not use SSE. After this PR, every
SSE parser in Zed handles `[DONE]` without error.

## Safety

- Official Anthropic and Gemini APIs never send `[DONE]`; the guard is a
no-op on direct connections.
- `line.trim() == "[DONE]"` handles both `data: [DONE]` and
`data:[DONE]`.
- Returning `None` drops the line silently; the stream concludes on the
next EOF as usual.

Release Notes:

- Fixed streaming completions failing with "error deserializing
Anthropic API response" when the SSE endpoint appends a `[DONE]` stream
terminator (affects custom `api_url` proxies for Anthropic and Google
Gemini)
2026-07-27 12:07:31 +00:00
Mendel FeygelsonandMrSubidubi 9ec4826944 agent: Improve error messaging for edit_file tool (#61662)
# Objective

Currently, when a model provides the wrong parameters to the edit file
tool, it gets back the opaque error message `data did not match any
variant of untagged enum ValueOrJsonString`.

At least some models (DeepSeek in my experience) can't figure out what
to do from this point, and keep trying the same wrong parameter names in
the tool call before eventually falling back to using `ed`.

This may address https://github.com/zed-industries/zed/issues/58622.

## Solution

Rather than attempting to deserialize to the `ValueOrJsonString` enum,
try to deserialize as a JSON string and then as a value in turn, so that
deserialization errors better propagate.

## Testing

Using DeepSeek V4 Pro.

Tried it out in a reloaded conversation where the edit tool was
consistently failing.

Asked it to stress-test the edit tool. Only one edit failed after a few
successful attempts, and returned the error message "missing field
`new_text`".

Subsequent edits worked again rather than resulting in a doom loop. I
don't think the model noticed what happened, but it seemed to help.

<img width="366" height="551" alt="image"
src="https://github.com/user-attachments/assets/6f9c0c8d-bf94-4670-bad0-0ead5c1fff4e"
/>

...

<img width="346" height="153" alt="image"
src="https://github.com/user-attachments/assets/2afa2901-9a90-4142-aa9d-ff32a7be0d0c"
/>


---

Release Notes:

- Improved edit_file tool error messaging.

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
2026-07-27 12:06:13 +00:00
Ben Brandt cecc753582 acp: Validate and surface more elicitation warnings (#61708)
Eventually more of this should move into the SDK I think, but makes
several states with forms and urls clearer to the user.

Release Notes:

- N/A
2026-07-27 11:30:39 +00:00
Lori HoldenandFinn Evers b38f75dcce Add agent panel font family settings (#59629)
Objective:

Allow users to configure the font families used by agent panel content
separately from the main UI and buffer fonts.

Solution:

- Add `agent_ui_font_family` for agent responses in the agent panel.
- Add `agent_buffer_font_family` for the agent panel message editor and
user messages.
- Keep context menus on the primary UI font family.
- Document the new settings and expose them in the settings UI.

Testing:

- Ran `cargo fmt`.
- Ran `cargo check -p settings_content -p theme_settings -p markdown -p
agent_ui -p settings_ui -p ui`.
- Ran `git diff --check`.
- Manually tested the agent panel font behavior in a dev build.

Release Notes:

- Added settings for configuring agent panel UI and buffer font
families.

Co-authored-by: Finn Evers <finn@zed.dev>
2026-07-27 10:34:57 +00:00
Finn Evers 34eac8ff92 ci: Grant version bump token more permissions (#61709)
This should hopefully fix the issue with the version bumps we were
seeing - to bypass push protections, the token seems to need workflow
permissions for some reason as well.

Release Notes:

- N/A
2026-07-27 10:28:32 +00:00
shenghaiyang d9e2550e28 gpui: Make HSLA functions const (#61682)
# Objective

Make hsla functions `const`.

## Solution

Made Hsla-related functions `const fn`.

## Testing

> Did you test these changes? If so, how?

Ran `cargo test -p gpui color` to verify the color-related tests pass.

> Are there any parts that need more testing?

No additional testing is required since this change only changes
existing color functions to `const fn`.

> How can other people (reviewers) test your changes? Is there anything
specific they need to know?
 
Reviewers can run `cargo test -p gpui color` to verify the changes.

> If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

Tested on macOS. No platform-specific behavior is expected.

## 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:

- N/A
2026-07-27 09:23:49 +00:00
Ray Droplet d6f9136ca8 Fix typo in .rules (#61693)
## Objective

A phrase in `.rules` was missing a verb.

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable


---

Release Notes:

- N/A
2026-07-27 05:59:53 +00:00
Cole Miller 134275b0ae Avoid unnecessary git scan when the agent creates a checkpoint (#61271)
Agent checkpointing is implemented by staging selected files to a
temporary git index file, then creating a commit. To avoid checkpointing
commonly-excluded files even when the user doesn't have them in their
gitignore, we write a temporary override to .git/info/exclude while
running the staging. However, this causes us to do an unnecessary git
scan when a checkpoint happens, because in general we want to do this
when `.git/info/exclude` changes (the user might have edited it).

This PR fixes that by doing the staging in two steps:
- First, we stage any tracked files
- Then we get a list of untracked files to include and stage those
explicitly. The list is obtained by running `git ls-files` with a custom
ignore file in addition to the `--standard` ignores; we write that
custom ignore file to a path ending in `tmp` under .git, which means
that our worktree code will not start a git scan in response to its
events (the same way it already works for the temporary index file).
.git/info/exclude is never touched. Note that we already listed all
untracked files before this PR, in order to exclude the large ones.

Release Notes:
- Fixed Zed doing unnecessary work when the agent created a checkpoint.
2026-07-27 00:55:39 +00:00
MBandCole Miller ef0b6f158d fs: Fix crash loop from closedir panic during worktree scan (#59953)
# Objective

Fixes #59952.

Zed crash-loops on launch. The faulting thread aborts inside the Rust
standard library while closing a directory handle during background
worktree scanning: `std`'s `DirStream::drop`
(`library/std/src/sys/fs/unix.rs`) `assert!`s that `closedir()` succeeds
unless the error is `EINTR`. That handle originates in
`RealFs::read_dir`, which wraps `std::fs::read_dir(path)` in
`stream::iter(...)` and carries the live `ReadDir` across async
boundaries; the worktree `BackgroundScanner` (`scan_dir` →
`forcibly_load_paths`) later drops the stream. If `closedir()` returns a
non-`EINTR` error (e.g. `EBADF` under file-descriptor pressure — seen
alongside repeated `unable to start FSEvent stream` warnings on a large
dependency tree), `std` panics inside `Drop`. Zed's
`crashes::panic_hook` turns any panic into `process::abort()`, and
because the same workspace is re-scanned every launch, this is a
permanent crash loop. (`catch_unwind` can't help: the hook aborts before
unwinding.)

## Solution

Stop relying on `std`'s asserting close. Add a `read_dir_entries(path)`
helper that reads entries eagerly so the directory handle is opened and
closed within a single call:

- On unix, read via libc (`opendir`/`readdir`/`closedir`) and
**deliberately ignore a failing `closedir`**, so a close error degrades
gracefully instead of aborting the process.
- On non-unix, keep `std::fs::read_dir` (which has no such assert) but
collect eagerly so the handle is dropped within the call.

`RealFs::read_dir` now calls this helper. The change is scoped to
`crates/fs/src/fs.rs`; the watcher, scanner, and panic hook are
untouched.

## Testing

- Added unit tests in `crates/fs/src/fs.rs` for `read_dir_entries`:
entry listing, `.`/`..` exclusion, empty directories, and the
missing-directory error path.
- `cargo test -p fs read_dir` → 3 passed.
- `RUSTFLAGS="-D warnings" cargo build -p fs`, `cargo clippy -p fs
--all-features --all-targets -- -D warnings`, and `cargo fmt -p fs
--check` are all clean.
- Tested on macOS (aarch64). The `fs` crate compiles within the full
`cargo build -p zed` graph. I could not produce a running app binary in
my environment (the `gpui_macos` Metal step needs full Xcode, not just
Command Line Tools) — reviewers on a full Xcode setup can `cargo run -p
zed`.
- The original `closedir` `EBADF` is not deterministically reproducible,
so the fix is structural rather than verified against a live repro; the
tests guard the read path and behavior.

## 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 — N/A (no UI change)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed Zed crash-looping on launch when `closedir` fails during
background directory scanning
([#59952](https://github.com/zed-industries/zed/issues/59952)).

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-07-26 21:13:39 +00:00
Lukas Wirth b73d91382d workspace: Retain panes while saving (#61683)
Save tasks can suspend while waiting for prompts, formatting, or
filesystem I/O. Holding only a WeakEntity<Pane> allowed the pane to be
released during those suspension points, surfacing an internal 'entity
released' error as a failed save.

Instead upgrade the pane once the save operation starts so we can ensure
it finishes.


---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-26 19:59:54 +00:00
70ae02b99e Fall back to path-only mention for binary files in the agent panel (#61279)
## Summary

- Dragging a binary file (docx, xlsx, pdf, etc.) into the agent panel's
message editor inserted a mention link, then asynchronously tried to
load its content as a text buffer. That failed with "Binary files are
not supported", which surfaced an error toast **and** deleted the
mention text that had already been inserted.
- `confirm_mention_for_file` now catches that specific failure and falls
back to `Mention::Link` (a path-only reference, same as directory
mentions already use), instead of failing the whole mention and
reverting the edit.

## Test plan

- [ ] Drag a `.docx` or `.xlsx` file into the agent panel chat input —
the file path mention should stay inserted with no error toast.
- [ ] Drag a regular text file in — content mention still works as
before (unaffected code path).

Release Notes:

- Fixed dragging a binary file (docx, xlsx, pdf, etc.) into the agent
panel deleting the inserted reference and showing a "Binary files are
not supported" error

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cole Miller <cole@zed.dev>
2026-07-26 19:46:19 +00:00
Jakub Konka 55b2687062 editor: Check anchor validity for hovered links (#61686)
Closes FR-112

Otherwise, if a multibuffer snapshot changed under the hood for example
one of the paths changed, without doing an explicit validity check, we
would panic during comparison instead.

Release Notes:

- Fixed panic when hovering links during an under-the-hood multibuffer
changes.
2026-07-26 16:37:40 +00:00
Jakub Konka 19d5ca984a gpui_wgpu: Fix bidi paragraph shaping crash (#61651)
Closes FR-133

`cosmic-text`'s BiDi line shaping machinery (`ShapeLine::new`) asserts
that every BiDi paragraph is following the same direction. It turns out
that our `gpui_wgpu` line shaping adapter would not account for that
leading to panics if text contained multiple BiDi paragraphs with
multiple directions. Not super common but worth fixing as the fix is not
super complicated. At the same time, I'd like to point out that there is
a patch submitted to `cosmic-text` that redoes shaping logic so that
this is no longer illegal:
https://github.com/pop-os/cosmic-text/pull/508 If it gets accepted, we
can revert this fix.

Release Notes:
- Fixed panic in `gpui_wgpu` if text contained multiple BiDi paragraphs
with mismatched directions.
2026-07-26 14:31:25 +00:00
Oleksandr Kholiavko efc3ba73b5 csv_preview: Refine filter popover UI (#61138)
# Objective

- The column filter popover was a static `ContextMenu`: no search, and
it didn't scale to columns with many unique values.

## Solution

- Replaced it with a `Picker<ColumnFilterDelegate>` with fuzzy search
and match highlighting over the column's unique values.
- Row order is frozen at open time (available first, then values hidden
by other filters under a "Hidden by other filters" header) so toggling a
value doesn't reshuffle the list.
- Added a footer with `{selected} / {total} rows selected` and "Clear
all".
- Added `fuzzy` and `picker` deps to `csv_preview`.

## Testing

- Search narrows to fuzzy matches with highlighting.
- Toggling a value updates its checkmark and footer count without
closing or reordering the list.
- Values excluded by another column's filter show disabled under "Hidden
by other filters".
- "Clear all" clears the column's filters and keeps the popover open.

## 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 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
- [x] Performance impact has been considered and is acceptable



## Showcase

| Before | After |
| --- | --- |
| <img width="660" height="351" alt="image"
src="https://github.com/user-attachments/assets/c78084a2-d327-4d48-9c05-f35383455713"
/> | <img width="660" height="354" alt="image"
src="https://github.com/user-attachments/assets/910d52ef-4530-4ac7-91ac-3db318cf6c19"
/> |

**+ search**
<img width="972" height="574" alt="image"
src="https://github.com/user-attachments/assets/1a26d0fc-c96c-4973-818d-7d053e8cce73"
/>

---

Release Notes:

- N/A
2026-07-26 10:27:23 +00:00
Agus Zubiaga 0fd17feb17 gpui: Fix dropped frames when scrolling an unfocused window (#61600)
Scroll events are delivered to the window under the pointer even when it
isn't focused, but we cap inactive windows at ~30fps to save energy, so
scrolling an unfocused window visibly drops frames. We now exempt
high-rate input from the cap using the existing `InputRateTracker`: a
trackpad scroll stream lifts it while events are arriving and for one
second after the last burst, then the cap resumes on its own.

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed dropped frames when scrolling unfocused windows.
2026-07-26 05:33:42 +00:00
Eric Holk 5d2df6acd5 Fix crash when dumping debug buffers in a collab session (#61616)
The `dev: dump input latency histogram` and `dev: dump accessibility
tree` actions called `Project::create_local_buffer`, which panics on
remote projects — so running either one as a guest in a collab session
aborted the whole app. Both now use the async `Project::create_buffer` +
`set_text` instead (the same pattern `open_log_file` uses), which routes
through the collab protocol on remote projects.

Since the collab-created buffer is visible to other participants, the
latency report now includes a "Reported from <username>'s machine" line
when the project is shared, using the collab username so we don't expose
anything that isn't already shared with the session.

While restructuring the handler I also split snapshotting from
formatting: the histogram snapshot (and the delta baseline) is captured
synchronously when the action fires, and the report string is built on a
background task. The accessibility tree dump stays synchronous because
gpui doesn't currently expose the captured tree data outside the window
borrow, and adding public API for a debug action's JSON pretty-print
didn't seem worth it.

Release Notes:

- Fixed a crash when running the `dev: dump input latency histogram` or
`dev: dump accessibility tree` actions in a shared project.
2026-07-26 01:19:29 +00:00
ᴀᴍᴛᴏᴀᴇʀ e2f35dd8c8 agent_ui: Fix selection mentions from "Add to Agent Thread" not opening files (#61621)
# Objective

Fixes #59333.

Selection mentions created with "Add to Agent Thread" could not be
clicked to open the referenced file, while selection mentions created by
pasting were navigable.

## Solution

The ready selection-mention crease did not receive its `MentionUri` or
`Workspace`, so `MentionCrease` could not install its click handler.
Pass the workspace through the action-completion callback and provide
both values to the shared crease renderer, enabling its existing
navigation behavior.

## Testing

I tested these changes locally.

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

Before:


https://github.com/user-attachments/assets/8dd4a2d0-4b22-4fb3-8777-cf97b6436b91

After:


https://github.com/user-attachments/assets/cff1cdb3-804a-45d8-a9c5-fdd8b35b6f8f


---

Release Notes:

- Fixed selection mentions added with "Add to Agent Thread" not opening
their referenced files.
2026-07-25 20:42:21 +00:00
roboinandJohn Tur 94cb83400b gpui_windows: Align inactive GPUI popup behavior on Windows with other platforms (#61411)
*As an LLM was used to translate the PR message, the original text is
included alongside the translation in accordance with the contributing
guidelines.

# Objective

> On Windows, GPUI accepted `WindowKind::PopUp` and `focus: false`, but
the window creation path ignored both options. This caused two problems
with the notification popup shown when an agent finished its work:
> 
> * When another window had focus, the popup could appear behind it.
> * When Zed had focus, the popup could steal focus.
> 
> This pull request applies `WindowKind::PopUp` and `focus: false` to
windows on Windows, bringing popup behavior in line with other operating
systems.

Windows版GPUIでは、`WindowKind::PopUp`と`focus:
false`を指定しても、それらのオプションが実際のウィンドウ生成処理では無視されていました。そのため、エージェントの作業が完了したときに表示される通知で次のような問題が発生していました。

- ほかのウィンドウにフォーカスがある場合にポップアップがほかのウィンドウの背後に隠れてしまう
- Zedにフォーカスがある場合はポップアップがフォーカスを奪ってしまう

このプルリクエストでは、Windows上でも`WindowKind::PopUp`と`focus:
false`をウィンドウに反映させるようにし、ポップアップの挙動をほかのOSと一致させます。

## Solution

> This PR updates popup creation in GPUI on Windows to match the
behavior on other platforms. When you specify `WindowKind::PopUp` and
`focus: false`, GPUI now keeps the popup above other windows without
stealing focus.
> 
> Keeping a `focus: false` popup above other windows caused the IME to
commit text under composition when the popup appeared. This PR also
fixes that issue.


Windows版GPUIのポップアップの生成処理をほかのプラットフォームの挙動と一致するように変更しました。このPRでは、`WindowKind::PopUp`と`focus:
false`を指定したときにポップアップウィンドウを最前面に表示し、フォーカスを奪わないようにしました。

また、`focus:
false`のポップアップが最前面に表示されるようにしたことで、ポップアップが表示されたときにIMEで入力中のテキストが意図せず確定されるようになってしまったため、それに対する修正も含まれています。

## Testing

> I built Zed on Windows and displayed a test agent notification to
verify the following:
> 
> * The popup stays above other windows when another window has focus.
> * When Zed has focus, a popup with `focus: false` does not steal focus
or interrupt IME input.
> * The buttons in the popup remain clickable.

Windows上でZedをビルドし、テスト用のエージェント通知を表示して次の項目をテストしました。

- ほかのウィンドウにフォーカスがある場合でもポップアップが最前面に表示される
- Zedにフォーカスがある場合に`focus: false`のポップアップがフォーカスを奪わず、IMEを使った入力も阻害しない
- ポップアップ内のボタンをクリックできる

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

> Note: I added a button to display an agent notification for testing in
this video, but this PR does not include that button.

※この動画ではテスト目的でエージェント通知を表示するボタンを追加していますが、このPRの変更には含まれていません。

### Before

The popup window is hidden when another window has focus:


https://github.com/user-attachments/assets/5312729b-1409-4c81-a169-dd031099059b

A popup with `focus: false` steals focus:


https://github.com/user-attachments/assets/dd1ac2a2-d5e8-4f8f-bc47-6cc659a10951

### After

The popup window stays on top even when another window has focus:


https://github.com/user-attachments/assets/af058921-14fc-4ca5-9698-758202c4c888

A popup with `focus: false` does not steal focus or interrupt text
input:


https://github.com/user-attachments/assets/9bc487c6-ae68-4ec0-9073-1257b91e06a9

---

Release Notes:

- Fixed Windows agent notifications appearing behind other windows,
stealing input focus, or committing active IME composition.

---------

Co-authored-by: John Tur <john-tur@outlook.com>
2026-07-25 20:38:42 +00:00
Tatsuya_ydandNathan Sobo 0222e451f9 Fix: prevent completion labels and docs from being truncated (#61324)
# Objective

- Fixes #60374 

## Solution

- Moved the `documentation_label` from the `ListItem::end_slot` into the
main `h_flex` layout alongside the `main_label`.
- Added `.flex_shrink(1.0)` and `.truncate()` to the documentation
container.
  - To allow it to shrink gracefully when space is tight.
- Removed `.w_full()` from the main label's container. 
- To prevent it from aggressively occupying all available horizontal
space, allowing the layout to balance the width between the label and
the documentation.

## Testing
- Visual and layout fixes tested manually by verifying the completion
menu in `settings.json`.
- All unit tests in the affected crate passed: `cargo test -p editor`.

## 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

## Showcase
### Visual change
<img width="813" height="314" alt="スクリーンショット 2026-07-20 143707"
src="https://github.com/user-attachments/assets/1daa3fa4-a479-465a-b7fd-cc803242c8a2"
/>

---

Release Notes:

- Fixed(CompletionsMenu): prevent completion labels and docs from being
truncated.

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
2026-07-25 13:10:24 +00:00
Lukas Wirth fb813f70d6 worktree: Suppress bare .git events explained by filtered sibling events (#61636)
Fixes an infinite git-rescan loop on Windows introduced by #59876.

On Windows, creating or deleting a file directly inside .git updates the
directory's last-write time, so ReadDirectoryChangesW reports a bare
.git Changed event alongside the file's own event. Since #59876, bare
.git events schedule a git rescan (to cope with coalesced FSEvents on
macOS), so every filtered-out lock-file event still triggered a rescan
through its paired bare event. Because a rescan's own `git diff
--numstat HEAD` can take .git/index.lock (even under
--no-optional-locks, e.g. in jj-colocated repos whose index never
refreshes clean), each rescan re-triggered the next one, spawning ~9 git
processes per cycle, ~4 cycles/sec, indefinitely.

Bare .git events are now deferred while processing an event batch and
only trigger a rescan when the batch contains no filtered event for the
same git dir that explains the directory change. A standalone bare .git
event (the macOS coalescing case #59876 addressed) still triggers a
rescan, as does any batch containing a meaningful .git change.


Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-25 10:18:26 +00:00
Matthew ChisolmandKirill Bulatov 73be80748b Add sextant glyph support to terminal rendering (#51072)
The Zed integrated terminal shows a broken QR code for apps with Expo
SDK 55. This PR custom-paints the terminal block and sextant glyphs used
for QR codes rather than relying on font glyphs.

| SDK 55 Before | SDK 55 After | SDK 55 in Ghostty |
| --- | --- | --- |
| <img width="581" height="536" alt="Zed Nightly"
src="https://github.com/user-attachments/assets/11054401-e947-4628-918a-0088042ccbf9"
/> | <img width="563" height="535" alt="Zed dev build"
src="https://github.com/user-attachments/assets/22e0bed3-9927-436d-8e0b-1ad0839f7bee"
/> | <img width="576" height="502" alt="Ghostty"
src="https://github.com/user-attachments/assets/c5f544d8-43e5-4dad-8bcd-8a36c401e9a7"
/> |

### Other notes
- Expo recently merged https://github.com/expo/expo/pull/46148, which
causes Expo SDK 56 to fall back to the old QR code behavior when used in
Zed. Once this PR merges, Expo can remove that fallback and use the
compact QR code path in Zed again for Expo SDK 56+.

| Current Fallback QR Code for SDK 54 and 56 | Fallback with this PR |
| -- | -- |
| <img width="744" height="684" alt="SCR-20260622-jwco"
src="https://github.com/user-attachments/assets/414896aa-52bc-4de7-a6b9-59cd5af08de0"
/> | <img width="616" height="752" alt="SCR-20260622-kfjh"
src="https://github.com/user-attachments/assets/accbef7a-3365-480f-add3-08910141afa5"
/> |

This PR now also fixes TUIs in the integrated terminal for users using
some fonts.
| OpenCode w/ Monaco before change | OpenCode w/ Monaco after change |
| --- | --- |
| <img width="1512" height="982" alt="image"
src="https://github.com/user-attachments/assets/a40f01a6-adf9-4e8b-909a-be53945eb813"
/> | <img width="1512" height="982" alt="image"
src="https://github.com/user-attachments/assets/b40bb22c-ef7e-466a-9bcf-46eb951087cd"
/> |

Finally, shade characters are now handled in the integrated terminal.

| btop with tty graph before change | btop with tty graph after change |
| --- | --- |
| <img width="1516" height="863" alt="SCR-20260724-irpr-2"
src="https://github.com/user-attachments/assets/afb77f01-6d3d-428a-b1be-7abb3d0e3d4d"
/> | <img width="1516" height="876" alt="SCR-20260724-ises-2"
src="https://github.com/user-attachments/assets/42262858-70da-4ba2-a5e6-96243fcfaadd"
/> |

#### This PR
- Adds custom painting for terminal bitmap glyphs used by QR renderers:
`█`, `▀`, `▄`, `▌`, `▐`, and U+1FB00..U+1FB3B sextants
- Adds tests for handling sextants, blocks/half-blocks, and adjacent
block merging

Closes #50158
Closes #58830 

Before you mark this PR as ready for review, make sure that you have:
- [X] Added a solid test coverage and/or screenshots from doing manual
testing
- [X] Done a self-review taking into account security and performance
aspects
- [X] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- Fixed QR code rendering for Expo SDK 55 apps
- Fixed rendering TUIs in the integrated terminal for some users

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-25 07:32:05 +00:00
Anthony Eid 3b9b83b354 collab: Fix multiworkspace location out of sync bugs (#61598)
### Summary

This PR fixes three small bugs that could cause a multi-workspace's
reported location to be out of sync with its actual location, which
causes following to break in multiplayer collaboration sessions.

The first bug was that each child workspace's title bar within a
multi-workspace had its own `cx.observe_window_activation` subscription
that would set the associated child workspace's project location. This
caused problems because it ran for all child workspaces instead of just
the active workspace within the multi-workspace. The fix was moving
`cx.observe_window_activation` to the `cx.observe_new` call in the
`call` crate that tracks newly created windows/multi-workspaces.

The second bug was caused by an incorrect `if` statement in a
`MultiWorkspace` subscription that would return early if the window was
active and the event emitted by `MultiWorkspace` wasn't
`ActiveWorkspaceChanged`. This caused issues when the window was
inactive because it would incorrectly set the active call's location to
the wrong project. The fix was making the early return happen if the
window wasn't active.

The third bug was that every child `Workspace` also observed window
activation and called `update_active_view_for_followers`. This allowed
hidden workspaces to report their active view instead of only the active
workspace.

### Testing

I added a property test for bugs one/two and another prop test for bug 3


Release Notes:

- collab: Fix out of sync following bugs
2026-07-25 03:39:45 +00:00
27c897944c gpui: Fix images not being drawn with rounded corners when using ObjectFit::Cover (#61383)
# Objective

Fixes #44339

## Solution

The issue was taking place as image bounds where larger than the view
bounds. Hence, the rounding of the image happened outside the view
bounds, hence the corners where not rounded.
This solution changed the paint_image function in window.rs. Now, it
takes in 2 parameters, image bounds and bounds of the area to be draw.
Then, the function creates the tile field of PolychromeSprite by
cropping the image to fit the area to be drawn. This ensures that the
rounding happens correctly.

## Testing
Testing was done as per the issue and results where verified visually.

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

<img width="1409" height="1030" alt="image"
src="https://github.com/user-attachments/assets/3645b36d-f182-4853-bdfe-d66a4132d273"
/>


## Release Notes:

Fixed rounded corners not rendering on images when using
ObjectFit::Cover

---------

Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
Co-authored-by: Nathan Sobo <nathan@zed.dev>
2026-07-25 00:03:32 +00:00
saberoueslatiandNathan Sobo 69518271c9 workspace: Rename read-only tab controls from File to Tab (#61202)
## Context

The editor tab's read-only controls used "File" terminology in their
tooltips and the tab context menu ("Make File Read-Only", "Locked File",
"Read-Only File", etc.). This was misleading in two ways: the option
also appears on unsaved and non-file tabs that have no file on disk, and
the toggle only controls whether the buffer is editable in the editor,
it does not change filesystem permissions. This renames the labels to
lock/unlock "Tab" language, matching the lock icon shown when the tab is
toggled.

Closes #60079.

Behavior after the change :

[Screencast from 2026-07-17
15-35-30.webm](https://github.com/user-attachments/assets/5fb018cb-515f-449c-a57e-0c0bead250bd)


## How to Review

1 file changed:

**crates/workspace/src/pane.rs**
Renames three sets of user-facing strings, all pure text changes with no
behavior change. The read-only toggle button tooltips become "Unlock
Tab" / "This will make this tab editable" and "Locked Tab" / "This tab
is read-only". The tab tooltip meta label becomes "Read-Only Tab". The
context menu entry, whose label already depends on
`capability.editable()`, becomes "Lock Tab for Editing" (when currently
editable) and "Unlock Tab for Editing" (when currently read-only); the
click handler still calls `toggle_read_only`, so the mapping from label
to action is preserved.

## 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
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Improved read-only tab controls to use "Tab" instead of "File" in
tooltips and the tab context menu, since the toggle affects editability
in the editor rather than filesystem permissions.

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
2026-07-24 22:54:30 +00:00
Mikhail PertsevandNathan Sobo 127aa6dcd2 git_ui: Prevent Git panel bindings in repository selector (#61282)
# Objective

Fix Git panel keybindings intercepting input intended for the repository
selector.

With Vim mode enabled, pressing `i` in the selector focused the
commit-message editor instead of filtering repositories. Platform
keybindings could also intercept printable input such as spaces.

Fixes #57936

## Solution

Exclude the `GitRepositorySelector` context from the Git panel
changes-list bindings in the macOS, Linux, Windows, and Vim keymaps.

## Testing

Manually tested on macOS using a debug build with Vim mode enabled and a
workspace containing two Git repositories

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed Git repository selector input being intercepted by Git panel
keybindings, including in Vim mode.

Co-authored-by: Nathan Sobo <nathan@zed.dev>
2026-07-24 22:33:12 +00:00
Ibrahim Khan 8a24015e4f editor: Skip untitled buffers when saving a multi-buffer (#61380)
Closes #60041.

## Summary

When Project Search results contain both a saved file and an untitled
buffer, running `workspace: reload` did nothing (quitting hit the same
path). The log showed:

```
ERROR [.../workspace.rs] buffer doesn't have a file
```

## Root cause

The Project Search results view is an `Editor` over a multi-buffer, and
its `Item::save` delegates to `Editor::save`. For a multi-buffer,
`Editor::save` collects every dirty buffer and calls
`Project::save_buffers`. An untitled excerpt has no file, so
`BufferStore::save_buffer` returns `Err("buffer doesn't have a file")`.
That error propagates through `Pane::save_item` → `save_all_internal` →
`prepare_to_close`, which then reports the workspace as not ready to
close, so `reload`/quit silently aborts.

A singleton untitled buffer avoids this because `Editor::can_save`
returns `false` for it (the workspace routes it to `save_as`); for a
multi-buffer, `can_save` is always `true`.

## Fix

Exclude file-less (untitled) buffers when collecting the buffers to save
for a multi-buffer. Untitled buffers can only be written via `save_as`,
so a bulk multi-buffer save now persists the file-backed excerpts and
leaves untitled ones untouched. This also addresses the same latent
issue in other multi-buffer views (diagnostics, find-all-references)
that can excerpt an untitled buffer.

## Testing

- Added `test_save_multi_buffer_with_untitled_buffer_skips_untitled` in
`crates/editor/src/items.rs`: it builds a multi-buffer over a
file-backed buffer and an untitled buffer (both dirty), then asserts
`save` succeeds, the file-backed buffer is persisted, and the untitled
buffer stays dirty. Fails before this change (`buffer doesn't have a
file`), passes after.
- `cargo test -p editor --lib save` (13 tests) and `cargo test -p search
--lib project_search` (22 tests) pass.
- `./script/clippy -p editor` is clean.

Manual repro (before): new untitled buffer with text → Project Search
for a term matching both it and a saved file → `workspace: reload` →
no-op with `buffer doesn't have a file` in the log. After: reload
proceeds.

Release Notes:

- Fixed `workspace: reload` and quitting silently doing nothing when
Project Search results included an unsaved untitled buffer.
2026-07-24 22:19:11 +00:00
John Tur 907dd1f442 gpui_windows: Only flash the window once on request_attention (#61611)
The current behavior bothers me.

Release Notes:

- N/A
2026-07-24 21:44:30 +00:00
Richard Feldman 8457a4ccf4 Opus 5 BYOK Support (#61596)
<img width="844" height="404" alt="Screenshot 2026-07-24 at 3 47 04 PM"
src="https://github.com/user-attachments/assets/4691a246-bab9-4426-aa0b-6a7cfa2aa486"
/>
action support, and explicit thinking opt-out behavior.

Adds Claude Opus 5 to the Anthropic and Amazon Bedrock BYOK providers,
including its documented context and output limits, regional inference
profiles, fast mode and comp

Release Notes:

- Added Claude Opus 5 support for Anthropic and Amazon Bedrock BYOK
providers.
2026-07-24 19:56:07 +00:00
Tim Vermeulen 76e43838aa editor: Fix sticky header drag cancels autoscroll (#53592)
In #52636 I seem to have introduced this bug, where mouse-down on a
sticky header followed by an immediate mouse movements sometimes dropped
the pending autoscroll request (to jump to the sticky header line):
https://github.com/zed-industries/zed/blob/967ae5ea24376be68c41336fa0ff721f5ca5a3cf/crates/editor/src/scroll.rs#L453

Fixed by exiting early from `mouse_dragged` when
`editor.has_autoscroll_request()`.

What sometimes happened before this fix:


https://github.com/user-attachments/assets/b6dd6650-b5f0-4ea1-ae70-9c4cf69e31a0

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:

- Fixed bug where clicking on a sticky header would sometimes not jump
to that line in the editor
2026-07-24 18:49:53 +00:00
Nathan Sobo fe4f59add6 Add explicit OpenAI conversation compaction and fix Anthropic compaction (#61370)
# Objective

Add explicit conversation compaction for OpenAI Responses API models,
available through both direct OpenAI connections and Zed Cloud models.

Keep finalized replacement context provider-neutral and separate from
the lifecycle events emitted while automatic compaction is in progress.

## Solution

- Add opt-in explicit compaction support to the `LanguageModel` trait.
- Separate streamed `CompactionUpdate` lifecycle events from finalized
`CompactedContext`.
- Represent provider-native compacted context as an opaque, versioned
state owned by the originating provider.
- Construct compact requests through the same OpenAI request conversion
used for completions, then narrow the request to fields supported by
`/responses/compact`.
- Preserve and validate the complete canonical replacement window
returned by OpenAI.
- Replay the replacement window before messages sent after compaction,
without resending the superseded transcript.
- Support explicit compaction through both the direct OpenAI provider
and `CloudLanguageModel`.
- Update automatic OpenAI and Anthropic compaction to use the same
finalized context representation.
- Reject empty, malformed, incorrectly versioned, and incorrectly owned
provider state.

The corresponding Cloud change adds the `/completions/compact` proxy
route: https://github.com/zed-industries/cloud/pull/3099.

The downstream Delta UI integration is
https://github.com/zed-industries/delta/pull/1739.

## Testing

- `cargo nextest run -p anthropic -p open_ai -p language_models_cloud`
- `cargo check -p language_models --tests`
- `cargo fmt --all --check`
- `git diff --check`

The focused tests cover request construction, canonical-window
preservation and replay, direct and Cloud transports, automatic
compaction lifecycle events, malformed provider state, provider
ownership, format compatibility, and HTTP failure handling.

## 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: System messages are now sent through the `instructions` field
in OpenAI Responses API requests.
2026-07-24 16:53:45 +00:00
Eric Holk 413b457870 worktree: Reload git state when a watcher rescan covers a repository (#61541)
# Objective

When the OS file watcher loses sync (e.g. its event queue overflows
under heavy fs churn), it drops pending events and reports a single
`Rescan` event for the watched root. Git changes hidden behind such a
rescan were silently lost, leaving the git panel and branch indicator
stale until something else touched `.git`.

Contributes to #13176. May fix #60102, though that report predates
#60660 and may already be addressed by it on nightly (see Related PRs
below).

Two bugs caused this, and they masked each other:

1. **A rescan never triggered a git reload.** The `Rescan` event's path
is the worktree root, not something inside `.git`, so it never populated
`dot_git_abs_paths` in `process_events` — and since `.git` is excluded
from entry scanning, the rescan produced no `.git` events either. The
dropped git changes were simply never picked up.
2. **Re-scanning reset `git_dir_scan_id` to 0.** The snapshot diff
detects git changes by comparing scan ids, so re-inserting the
repository with a fresh id could wipe out a bump made earlier in the
same scan cycle, swallowing the corresponding `UpdatedGitRepositories`
signal.

The masking is why these fixes land together rather than as two PRs: the
root-rescan case in `test_dot_git_dir_event_does_not_suppress_children`
only passed on `main` because the buggy scan-id reset made the snapshot
diff fire spuriously. Fixing either bug alone turns that (currently
green) test red.

## Solution

- `process_events`: a `Rescan` event now schedules a git state reload
for every repository whose git directory (`dot_git`, `common_dir`, or
`repository_dir`) lies under the rescanned path, covering linked
worktrees and gitfile repositories, including git dirs watched outside
the worktree root.
- `insert_git_repository_for_path`: carry the existing `git_dir_scan_id`
forward when re-inserting a repository instead of resetting it to 0.
Deliberately *not* bumped either: re-insertion is snapshot bookkeeping,
not evidence of a git change — bumping would trigger spurious full
reloads on non-lossy paths (explicit refreshes, path-prefix scans). Only
`update_git_repositories` claims that git state changed.
- `changed_repos`: a `debug_assert` enforcing that `git_dir_scan_id`
never regresses, so future violations of this invariant fail loudly in
tests instead of manifesting as a stale git panel.

## Testing

New fault-injection infrastructure and tests:

- `FakeFs::simulate_watcher_overflow` models the kernel's watch queue
overflowing: buffered (undelivered) events are discarded and replaced by
a single `Rescan` for the given root, mirroring FSEvents
`kFSEventStreamEventFlagMustScanSubDirs`, inotify `IN_Q_OVERFLOW`, and
Windows `ERROR_NOTIFY_ENUM_DIR`.
- `test_watcher_overflow_rescan_reloads_git_state`: a git change whose
events are lost to an overflow must still be picked up via the rescan
(reproduces bug 1; fails on `main`).
- `test_git_update_in_same_batch_as_rescan_is_not_lost`: a git event
processed in the same batch as a rescan must not lose its scan-id bump
to the repository re-insertion (reproduces bug 2; fails on `main`).
- `test_random_git_updates_with_watcher_overflows`: randomized property
test (100 iterations) asserting that every git state change is
eventually signaled via `UpdatedGitRepositories` under random event
batching, delays, and overflows. Fails on `main` within the first few
seeds.
- `test_random_worktree_changes` now also injects watcher overflows,
extending its existing convergence property to rescan reconciliation of
worktree entries (this already passed; the injection guards it going
forward).

Full `worktree` and `fs` suites pass. Verified the directed tests
exercise the intended code paths via trace logging (the same-batch test
hits `update_git_repositories` stamping followed by re-insertion,
distinct from the overflow test where no `.git` event arrives at all).

## Related PRs

The recent stale-git-state reports trace back to three distinct
mechanisms that share one symptom. This PR addresses the third:

- **Events never generated** — #60660 (merged, in this PR's base):
Linux's non-recursive watcher missed nested `refs/` directories, so
external commits/fetches produced no events at all. That PR (together
with #60590, which explicitly rescans after Zed-initiated reset/fetch
and touches only `git_store.rs`) fixed #60348. No overlap with this PR;
a merge against current `main` is clean, and the refs-watching tests are
disjoint from the overflow/rescan tests added here.
- **Events coalesced** — #59876 (open, complementary): FSEvents can
merge `.git` child events into a bare `.git` `Changed` event; the signal
arrives, in a shape Zed ignores. @RemcoSmitsDev's review comment there
describes this PR's failure mode and calls the two fixes complementary;
this is effectively the follow-up promised in that comment. Both PRs
touch the same region of `process_events`, so whichever lands second
needs a trivial rebase, and #59876 flips the bare-`.git` expectation in
`test_dot_git_dir_event_does_not_suppress_children` Case 2, which this
PR preserves.
- **Events dropped** — this PR: the watcher generated events but lost
them to a queue overflow, and the resulting `Rescan` did not reach the
git reload path. #59976 and #60098 (merged) reduced how often this
happens; this PR makes git state recover correctly when it does.

## 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 the git panel and branch indicator showing stale state after
heavy file-system activity caused the file watcher to lose events
2026-07-24 16:50:57 +00:00
3d7c8e732e search: Escape seeded buffer search query in regex mode (#57748)
## What

When `seed_search_query_from_cursor` is enabled and regex mode is
active, the selected text is used verbatim as the regex pattern. This
means selecting text like `z.d` seeds the regex `z.d`, where `.` acts as
a wildcard — matching `zed`, `zXd`, etc. — rather than only the literal
string the user selected.

Fixes #57253.

## Why it was broken

`search_suggested()` in `BufferSearchBar` retrieves the raw selection
text from `query_suggestion()` and passes it directly to `search()`.
There was no escaping step, even when `default_options` had
`SearchOptions::REGEX` set.

## Fix

Run the seeded suggestion through `regex::escape()` before passing it to
`search()` when regex mode is enabled. This mirrors the identical
pattern already used in `crates/vim/src/normal/search.rs:485`.

```rust
// Before
let search = self
    .query_suggestion(seed_query_override, window, cx)
    .map(|suggestion| {
        self.search(&suggestion, Some(self.default_options), true, window, cx)
    });

// After
let search = self
    .query_suggestion(seed_query_override, window, cx)
    .map(|suggestion| {
        let suggestion = if self.default_options.contains(SearchOptions::REGEX) {
            regex::escape(&suggestion)
        } else {
            suggestion
        };
        self.search(&suggestion, Some(self.default_options), true, window, cx)
    });
```

## Test

Added `test_seeded_query_is_escaped_in_regex_mode` in
`buffer_search.rs`. It creates a buffer with `"z.d\nzed\n"`, enables
regex mode, selects `z.d`, seeds the search, and asserts:
- The query text becomes `z\.d` (escaped), not `z.d`
- Exactly 1 match is highlighted (the literal `z.d`), not 2

The `regex` crate was already a workspace dependency and is already used
in the `search` crate transitively; this adds it explicitly to
`crates/search/Cargo.toml`.

Release Notes:

- Fixed regex search seeded from cursor/selection matching more than the
selected text when the selection contained regex special characters
(e.g. `.`, `*`, `(`)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-07-24 15:45:41 +00:00
Anthony Eid ca267a68a3 gpui: Fix deadlock in performance profiler and reenable it (#61584)
### Summary

PR #58942 disabled the performance profiler within Zed because there was
a race condition that caused Zed to hang forever due to a deadlock
involving the foreground thread. This PR fixes the deadlock and
re-enables the performance profiler.

The deadlock happened because `ThreadTimings::drop()` locks
`GLOBAL_THREAD_TIMINGS`, and that drop could run in places where
`GLOBAL_THREAD_TIMINGS` was already locked: the collection paths
(`get_all_timings`, `take_all_stats`, `set_trace_enabled(false)`) held
the global lock while upgrading and then dropping per-thread
`Arc<GuardedTaskTimings>` handles. If a worker thread exited in that
window (e.g. GCD reclaiming an idle thread), the collector inherited the
last strong reference, and dropping it ran `ThreadTimings::drop` ->
`GLOBAL_THREAD_TIMINGS.lock()` reentrantly on the same thread. The
spinlock is not reentrant, so the thread spun forever while holding the
lock, hanging every other thread that touched the profiler.

The fix: hold `GLOBAL_THREAD_TIMINGS` only long enough to upgrade the
`Weak` handles (`upgraded_thread_timings()`), and release it before any
per-thread buffer is locked, copied, or dropped. A last-reference drop
now always runs with the global lock free. As a side benefit, the
up-to-16MiB per-thread buffer copies no longer happen under the global
lock.

### Diagram

```mermaid
sequenceDiagram
    participant C as Collector thread (get_all_timings)
    participant G as GLOBAL_THREAD_TIMINGS (spin::Mutex)
    participant T as Worker thread (exiting)

    Note over T: holds the only strong Arc<br/>in its THREAD_TIMINGS TLS
    C->>G: lock() — guard held for entire collection
    C->>C: Weak::upgrade() (strong: 1 → 2)
    T->>T: thread exits, TLS destructor drops its Arc (strong: 2 → 1)
    C->>C: temp Arc dropped at end of iteration (strong: 1 → 0)
    C->>C: ThreadTimings::drop() runs on collector thread
    C->>G: lock() again — already held by this thread
    Note over C,G: spin lock is not reentrant → spins forever,<br/>every other profiler user spins behind it

    Note over C,T: Fix: upgrade all Weaks under the lock, release it,<br/>then lock/copy/drop per-thread handles — the reentrant<br/>drop can now only ever run with the global lock free
```

Release Notes:

- Fixed a deadlock in the performance profiler and re-enabled it (`zed:
open performance profiler`)
2026-07-24 15:34:17 +00:00
025bf6bf70 Treat blank spawn_agent session IDs as absent (#60893)
# Objective

Fix `spawn_agent` calls that provide an empty or whitespace-only
`session_id`.

Currently, an empty string is deserialized as a real session id, so the
tool attempts to resume a session with an empty id instead of starting a
new subagent session. This can happen when callers serialize an optional
`session_id` field as `""`.

Related: Refs #55987. This addresses one concrete session-id failure
mode described there, but that issue also covers broader
OpenAI-compatible provider/subagent reliability concerns.

## Solution

- Add custom deserialization for `SpawnAgentToolInput.session_id`.
- Treat omitted, `null`, empty, and whitespace-only values as `None`.
- Preserve existing behavior for non-empty `session_id` values, so
follow-up calls still resume an existing subagent session.
- Clarify the field docs.
- Add a regression test covering omitted, `null`, empty,
whitespace-only, and non-empty values.

## Testing

Tested locally on macOS:

- `RUSTUP_TOOLCHAIN=1.95.0 cargo fmt --manifest-path zed/Cargo.toml
--package agent --check`
- `RUSTUP_TOOLCHAIN=1.95.0 cargo test --manifest-path zed/Cargo.toml -p
agent -p gpui_macos --features gpui_macos/runtime_shaders
deserializes_blank_session_id_as_absent`
- `RUSTUP_TOOLCHAIN=1.95.0 cargo build --manifest-path zed/Cargo.toml -p
zed -p gpui_platform --features gpui_platform/runtime_shaders`
- `RUSTUP_TOOLCHAIN=1.95.0 cargo clippy --manifest-path zed/Cargo.toml
-p agent -p gpui_macos --features gpui_macos/runtime_shaders --tests --
-D warnings`

The local build uses runtime shaders because this machine does not have
the full Xcode Metal CLI toolchain available. CI should cover the
standard build matrix.

## 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 `spawn_agent` handling so blank `session_id` values are treated
as absent and start a new subagent session.

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
2026-07-24 14:03:06 +00:00
Hugh L 982e4c3e38 agent_ui: Fix agent terminal close behavior with keyboard shortcuts (#58217)
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

What:
  - Closing the active terminal from the sidebar activated the remaining
terminal.But closing a terminal with Ctrl-D could leave the agent panel
in an
uninitialized `Zed Agent` state instead of activating the remaining
terminal.
<img width="804" height="380" alt="image"
src="https://github.com/user-attachments/assets/eaa67c6e-7f3d-4a1c-b72d-9cabfaab872b"
/>

How:
  - Terminal exits emit `TerminalCloseRequested`.
- The sidebar handles that request through the same close path used by
the
  sidebar close button.
- Neighbor activation, draft fallback, metadata cleanup, and
linked-worktree/
  archive handling stay centralized in the sidebar close flow.

Added test coverage for closing an active terminal via terminal exit and
  activating the remaining terminal neighbor.

Testing:
  - `cargo check -p agent_ui`
  - `cargo check -p sidebar`
  - Manually verified Ctrl-D terminal close behavior with multiple agent
  threads/terminals

Release Notes:

- Fixed closing an agent terminal with Ctrl-D leaving the agent panel
  uninitialized instead of activating the remaining terminal
2026-07-24 12:52:03 +00:00
29fb1fc131 agent: Add agent.compaction_model setting for context compaction (#60012)
# Objective

Add a new `agent.compaction_model` setting that lets users specify a
separate language model for context compaction (`/compact` and
auto-compaction), independent of the thread's active conversation model.

Compaction is just summarization — there's no reason to pay Opus prices
for it when a cheaper model does the job faster. We've also seen
reasoning models misbehave on this task (empty responses, repetition
loops at high effort), so picking a dedicated non-reasoning model for
compaction is useful.


## Solution

- New `compaction_model: Option<LanguageModelSelection>` field in
`AgentSettingsContent` and `AgentSettings`, mirroring
`thread_summary_model`.
- New `compaction_model: Option<ConfiguredModel>` slot on
`LanguageModelRegistry` with `select_/set_/compaction_model()` trio,
mirroring the existing pattern. The setter deliberately does **not**
emit a registry event in v1; callers read the slot lazily at compaction
time.
- New `Thread::compaction_model(&self, cx: &App)` helper that returns
the configured model or falls back to `self.model()`. Two call sites —
`Thread::compact` and `perform_compaction_if_needed` — now go through
this helper instead of reading `self.model()` directly.
- `build_compaction_telemetry` accepts the compaction model explicitly
so the `model` field reflects the model that actually streamed the
request. `max_tokens` still derives from `thread.model()` (threshold
semantics are unchanged).
- Documentation updated at `docs/src/ai/agent-settings.md` (new
user-facing setting).

**Example:**

```json
{
  "agent": {
    "default_model": {
      "provider": "anthropic",
      "model": "claude-opus-4-6"
    },
    "compaction_model": {
      "provider": "anthropic",
      "model": "claude-sonnet-4-5"
    }
  }
}
```

**Resolution chain:**

```
agent.compaction_model (if set & available)
  → thread.model()  (always available, current behavior)
```

**Behavior change:**

| Trigger | Before | After |
| --- | --- | --- |
| Manual `/compact` | Uses `thread.model()` | Uses
`agent.compaction_model` if set & available; else `thread.model()` |
| Auto-compaction | Uses `thread.model()` | Same as above |
| `/compact` when thread has no model | `NoModelConfiguredError` |
Succeeds if `compaction_model` resolves |
| `compaction_model` configured but provider missing / model id unknown
| n/a | Falls back to `thread.model()` and logs a one-time warning |

**Explicit non-goals:**

- No `Event::CompactionModelChanged`(no consumer; the `_cx` parameter on
`set_compaction_model` is intentionally accepted for future use).
- No GUI selector (consistent with all other feature-specific models).
- No per-profile override.
- No runtime API-error fallback — only config-time failure (provider not
registered, model id not in `provided_models`) triggers fallback. This
matches every other feature-specific model.
- No change to threshold calculation, auto-compact trigger, or
`COMPACTION_PROMPT`.
- No propagation to subagent threads.

## Testing

3 new unit tests in `crates/agent/src/thread.rs::tests`:

- `test_compaction_uses_configured_compaction_model` — manual `/compact`
routes to the configured model; thread's primary model receives no
request; telemetry reflects the configured model.
- `test_compaction_falls_back_when_compaction_model_unavailable` —
configured-but-unresolvable falls back to `thread.model()`; telemetry
reflects the fallback model.
- `test_auto_compaction_uses_compaction_model` — auto-compaction
triggered by threshold honors the same setting.

All 14 existing compaction tests still pass. Test suites in
`crates/agent_settings`, `crates/language_model`,
`crates/settings_content`, `crates/agent_ui` unchanged. `cargo clippy`
clean on the changed crates.

**How reviewers can test:**

1. Add `agent.compaction_model` to `settings.json` with a cheaper model
than the thread's primary model, run `/compact`, observe the cheaper
model receives the request.
2. Set `agent.compaction_model` to a non-existent provider/model id, run
`/compact`, observe fallback to thread model and a `log::warn!` line.
3. Trigger auto-compaction by reaching the threshold, observe it uses
`compaction_model`.

**Platforms tested:** local Linux (cargo check + cargo test on agent /
agent_settings / language_model / settings_content / agent_ui crates).

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments — no `unsafe`
blocks introduced
- [x] The content adheres to Zed's UI standards — N/A: settings-only
change, no UI touched
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable — model
resolution is an O(1) registry lookup, not on any hot path; no new work
in the streaming loop


Release Notes:

- agent: Add support for specifying which model is used for compaction
(`agent.compaction_model`)

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
2026-07-24 12:48:58 +00:00
Bennet Bo Fenner e387a55757 agent: Show effort selector for anthropic compatible providers (#61579)
Follow up to #57207

Release Notes:

- agent: Show reasoning effort selector for anthropic compatible
providers if model supports adaptive thinking
2026-07-24 12:48:41 +00:00
guopenghuianddino 8d0742b017 Fix adding breakpoint/bookmark via gutter context menu using the wrong row (#59269)
# Objective

Fixes #59265

## Solution

Use `display_point_to_anchor` to properly convert `DisplayRow` to
`Anchor`, instead of manually constructing `Point` directly as done
currently.

## Testing

- Tested manually, see video in issue
- Tested on windows

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase


<details>
  <summary>Click to view showcase</summary>

My super cool demos here

</details>

---

Release Notes:

- Fixed the gutter context menu adding breakpoints/bookmarks to the
wrong row in multibuffers.

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
2026-07-24 12:20:06 +00:00