sidebar: Improved search — content, archived, closed-ACP, scope alignment, ranking, collapse during search - #58219
Conversation
Extends the sidebar thread filter so a thread surfaces when the query appears in its conversation, not only in its title. The search scatters the query across every thread in the list: threads loaded in an agent panel are searched in-memory via AcpThread::to_markdown (covering external/ACP threads and unsaved, in-flight content), and unloaded native threads are loaded from the thread DB on demand. Work runs off the main thread, is debounced, cached by updated_at, and cancelled when a newer query supersedes it. Clicking a content match opens the thread with its in-thread search bar pre-seeded with the same query (ThreadView::open_search_with_query + ThreadSearchBar::set_query), so matches are highlighted immediately. Known gap: closed external/ACP threads are not searched (their history isn't stored locally); covering them requires loading on demand.
Archived threads are excluded from the normal sidebar list, but when a content search matches one it now appears inline rendered demoted (via ThreadItem::archived). Adds ThreadMetadataStore:: archived_entries_for_main_worktree_path so the rebuild can gather archived threads for a group, and injects content-matched archived threads into the filtered list. Closed external/ACP threads are still not covered (no local content store) — that's the next step.
The cheap content search can't read closed external/ACP threads (their history lives in the agent, not a local DB). This adds an on-demand "Search more" pass: a footer button loads each closed ACP thread in an open project from its agent (reusing the per-agent connection), searches its content, and surfaces matches progressively, with a live N/M count and a Stop control. Results merge into the filtered list; a query change clears them. Adds AgentPanel::load_session_content_for_search, which loads a session headlessly (no active-view takeover) for search.
Two fixes to cross-thread content search: 1. Scope: the sidebar matched a thread's full markdown (including thinking blocks and tool output), while the in-thread search bar only scans visible user/assistant text + tool-call labels. A sidebar match in hidden content opened to "0/0" in-thread. Now both the loaded-thread and native-DB paths use the same visible scope (AcpThread::searchable_text / Message::searchable_markdown), so every sidebar match is navigable in-thread and incidental matches disappear. 2. Ranking: filtered results are now ordered title/worktree matches first, then content matches by hit count (most relevant first), then recency — instead of purely by recency.
Archived external/ACP threads had no path to content search: the cheap search can't read them (not in the native DB, not loaded), and the "Search more" pass excluded them. They render through the archived injection in `rebuild_contents`, which only consulted the cheap content_matches set. Now: - `start_closed_acp_search` includes archived threads as candidates - `has_searchable_closed_acp_threads` doesn't exclude archived ones, so the footer button surfaces when only archived ACPs remain - The archived injection also consults `closed_search_matches`, so a match from "Search more" surfaces (demoted) under its group Also adds a regression test that typing a project name surfaces that project's threads via workspace-label match.
Typing a query forced every group to load its threads regardless of the user's collapsed state, so clicking the chevron during search did nothing. The chevron now actually folds/unfolds results during search. A header for a collapsed group is still surfaced when one of its threads matched by content (or by the "Search more" pass), so the group doesn't silently disappear from search — the user can expand it to see the hits.
There was a problem hiding this comment.
Hey @KevinLaveto ! 🙂
Thank you for working to improve the search experience for the threads sidebar. Since this pull request is fairly large and tackles six concerns at once, as you outlined in its description, I’d consider breaking it into multiple, more focused pull requests.
For a change of this scope, we’d also usually expect an issue or discussion where the Zed team has already confirmed we’re interested in shipping the idea.
I’ve compiled the changes, but I haven’t been able to get the new behavior working locally. Given the breadth and impact of these changes, it’s important to attach screenshots or a short screen recording showing the feature in action, as a recording would at least demonstrate that it’s functioning before we commit time to a full review
Given all of the above, I’m going to close this PR for now. That said, you’re very welcome to open a discussion about improving the search experience for the threads sidebar so we can first agree on the desired behavior and scope, and then iterate on it together.
Finally, our contributing guide outlines what we look for in contributions and offers tips for first‑time contributors. I’d recommend taking a look. Thanks!
|
In the meantime, I've created a skill to search across Zed threads. It autodetects the Zed profile and supports regular expressions and auto-expanding compressed blobs. |
Summary:
A bundle of improvements to the agent thread sidebar's "Search threads…"
filter. Previously it only matched titles. With this PR a query matches
the actual conversation content too, archived threads are reachable from
the same search box, and the result ordering and collapse behaviour
match what you'd expect coming from any cross-document search.
Builds on @dandv's in-thread search bar work in #57231 conceptually:
that PR added search inside a single open thread; this PR adds search
across threads, designed to match the same visible scope so a sidebar
match is always findable in dandv's bar once #57231 lands. See "Credit"
below.
What's in the PR:
Content search — typing in the sidebar filter now also matches
thread message content, not just titles. Loaded threads are searched
in memory; unloaded native threads are read from the local thread DB
on demand. Debounced + cached + cancelable.
Archived in content search — archived threads (normally hidden
from the sidebar) surface in results when their content matches the
query, rendered demoted via
ThreadItem::archived. New helperThreadMetadataStore::archived_entries_for_main_worktree_pathandper-group injection in
rebuild_contents."Search more (closed agent threads)" footer — closed
external/ACP threads can't be searched from local storage (their
history lives in the agent). An explicit "Search more" button runs
a progressive pass: load each one through its agent, search its
content, and surface matches as they're found, with a live N/M
progress and a Stop control. Per-agent connections are reused, so
one connection per agent (not per thread). New
AgentPanel::load_session_content_for_searchperforms the headlessload.
Scope alignment + ranking — the sidebar matched the thread's
full markdown (including thinking blocks and tool output), but the
in-thread search bar (agent_ui: Add in-thread search bar #57231) deliberately scans only the visible
text. A sidebar match in hidden content would open to "0/0" in the
bar. Now both paths use the same scope via new
AcpThread::searchable_textandagent::Message::searchable_markdownhelpers, so cross-thread results are always navigable in-thread.
Results are also ranked: title/worktree matches first, then content
matches by hit count, then recency.
"Search more" includes archived — archived external/ACP threads
are also covered by the on-demand pass, and matches surface through
the archived injection.
Respect collapse during search — typing a query no longer force-
loads every group's threads. Clicking the project chevron during a
search actually folds/unfolds results. Groups whose threads match by
title or content still show their header so the user can expand to
reveal the hits.
Credit:
This work builds directly on @dandv's open PR #57231 ("agent_ui: Add
in-thread search bar"):
"visible / searchable" for the in-thread Find bar (user messages,
assistant message chunks, tool-call labels; excluding thinking blocks
and tool output). This PR's
AcpThread::searchable_textandagent::Message::searchable_markdownmirror that exact scope, so asidebar match is guaranteed to be reachable in his bar once agent_ui: Add in-thread search bar #57231
lands.
it open his Find bar pre-filled with the same query is a tiny
follow-up we built but are holding back until agent_ui: Add in-thread search bar #57231 merges (it
modifies
thread_search_bar.rs/thread_view.rsdirectly). Willopen it as a small standalone PR after his lands.
Related PRs in this bundle:
Tests:
Self-Review Checklist:
Release Notes: