Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(site/src/pages/AgentsPage): wire chat search box to full-text search - #27375

Closed
DanielleMaywood wants to merge 1 commit into
mainfrom
danielle/codagt-726-chat-search-ui-search-box-wiring
Closed

feat(site/src/pages/AgentsPage): wire chat search box to full-text search#27375
DanielleMaywood wants to merge 1 commit into
mainfrom
danielle/codagt-726-chat-search-ui-search-box-wiring

Conversation

@DanielleMaywood

Copy link
Copy Markdown
Contributor

Wires the Coder Agents chat search box up to the backend full-text search filter. Bare free text previously produced a title:"..." substring filter; it now produces a search: filter, so free text matches chat titles, PR titles, PR numbers, and message bodies via the FTS index added in #27126.

Bare free text is wrapped in a quoted phrase by default because the backend query tokenizer requires the search value to be a single token (multi-word input like hello world otherwise fails). Websearch operators (quoted phrases, OR, `-negation) still pass through when the user supplies a properly quoted phrase. The empty state notes that message content is indexed periodically, so very recent messages may not be searchable yet.

Refs CODAGT-726
Depends on #27126

Implemented by Coder Agents, reviewed and tested by a human.

Implementation notes
  • Core change is normalizeChatSearchInput in site/src/pages/AgentsPage/components/ChatsSidebar/dialogs/searchQuery.ts: bare text and typed title: terms are merged into a single search: FTS filter instead of a title: ILIKE filter.
  • Added toSearchPhrase/hasWebSearchQuotes helpers: free text with a leading/trailing quote pair (websearch phrase syntax) passes through unchanged; everything else is wrapped in search:"..." with stray quotes stripped (the backend parser has no escape handling for embedded quotes).
  • Structured filter pills (has_unread, archived, pr_status, diff_url) are unchanged and remain compatible with search:.
  • ChatSearchResults.tsx empty state updated to mention the periodic indexing lag (dbpurge sweep populates search_tsv).
  • Updated searchQuery.test.ts (10 unit tests) and ChatSearchDialog.stories.tsx (20 interaction stories) for the new emitted syntax; error-state stories now use pr_status:badvalue since title: no longer produces an invalid query.

…arch

The Coder Agents chat search dialog sent bare free text as a title
substring filter (title:"..."). Point it at the backend full-text
search filter (search:) so free text matches chat titles, PR titles,
PR numbers, and message bodies.

Bare free text is wrapped in a quoted phrase by default, since the
backend query tokenizer requires the search value to be a single
token. Websearch operators (quoted phrases, OR, -negation) still pass
through when the user supplies a proper quoted phrase. The empty
state notes that message content is indexed periodically.
@linear-code

linear-code Bot commented Jul 21, 2026

Copy link
Copy Markdown

CODAGT-726

@DanielleMaywood

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-07-21 12:49 UTC by @DanielleMaywood
Spend: $2.75 / $100.00

Review history
  • R1 (2026-07-21), 1 P1, 1 P2, COMMENT. Review

deep-review v0.9.0 | Round 1 | acd0d7f..2069bb9

Last posted: Round 1, 2 findings (1 P1, 1 P2), COMMENT. Review

Finding inventory

Finding inventory - PR #27375

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P1 Open searchQuery.ts:21 hasWebSearchQuotes matches interior quote pairs, emitting search values the backend rejects R1 Netero Yes
CRF-2 P2 Open searchQuery.test.ts:96 Tests assert backend-invalid emitted strings, codifying the CRF-1 bug as expected behavior R1 Netero Yes

Round log

Round 1

Netero-only first pass. 1 P1, 1 P2. Reviewed against acd0d7f..2069bb9.
LOC: +96 -44, no Law (effective additions 96 < 1000).
Orchestrator verified CRF-1 empirically against searchquery.Chats: search:Fix "auth" middleware and search:"fix race" OR deadlock -timeout return unsupported search term with empty Search; only a single fully-quoted phrase (search:"fix race condition") parses. CRF-2 verified: the two test assertions at searchQuery.test.ts:90 and :96 assert those rejected strings.
Panel not yet spawned (pre-panel round gated by P1). Panel reviews after these findings are addressed.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First-pass review only. These are mechanical findings from the first-pass reviewer; the full review panel has not yet reviewed this PR and will review after these findings are addressed. These are defects worth addressing before the panel spends parallel review time.

The core rename from title: ILIKE to the search: FTS filter is clean and consistent, the doc comments were updated alongside the code, and test density is healthy (~48%). The empty-state copy update reads well.

One blocker, though: the search: passthrough for websearch operators does not actually reach the backend. Verifying the emitted strings against the real searchquery.Chats parser shows that anything other than a single fully-quoted phrase is rejected as unsupported search term, and two tests bless that broken output.

Severity count: 1 P1, 1 P2.

Netero put it plainly: the tests "pass green while the feature is broken."

🤖 This review was automatically generated with Coder Agents.

const first = value.indexOf('"');
const last = value.lastIndexOf('"');
return (
first !== -1 && last > first && /\S/.test(value.slice(first + 1, last))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 [CRF-1] hasWebSearchQuotes matches any interior quote pair, so bare free text containing a quoted word or websearch operators is emitted verbatim as search:<text>, which the backend rejects. (Netero)

hasWebSearchQuotes only checks that a quote exists (indexOf) and a later quote exists (lastIndexOf) with non-whitespace between them. It does not verify the quotes bracket the whole string. Any input with an interior quote pair passes through toSearchPhrase unchanged and is emitted as a raw search: value.

Verified empirically against searchquery.Chats:

  • Fix "auth" middleware emits search:Fix "auth" middleware -> unsupported search term: "\"auth\" middleware", Search="".
  • "fix race" OR deadlock -timeout emits search:"fix race" OR deadlock -timeout -> unsupported search term: "OR deadlock -timeout", Search="".
  • "fix race condition" emits search:"fix race condition" -> Search="fix race condition" (the only shape that works).

The backend tokenizer (coderd/searchquery/search.go) splits on unquoted whitespace and rejects any non-key:value token, so only text entirely inside one search:"..." token reaches filter.Search. The PR description's claim that websearch operators pass through is false for every case except a single fully-quoted phrase. Fix: only pass through when the entire trimmed string is one balanced quoted phrase, otherwise strip and re-wrap the whole expression in search:"...". Verify the fix against searchquery.Chats, not just the emitted string.

🤖

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the successor PR #27973 (this PR was auto-closed as stale and could not be reopened after the rebase).

Dropped the hasWebSearchQuotes/toSearchPhrase passthrough entirely. Bare free text now always strips embedded double quotes and is wrapped in a single search:"..." phrase, so no input produces a rejected query. Verified empirically against searchquery.Chats: all emitted shapes (including Fix "auth" middleware and "fix race" OR deadlock -timeout) now parse with zero validation errors and the expected filter.Search. The PR description no longer claims websearch operators pass through.

🤖 Coder Agents

});

it("preserves websearch operators alongside a quoted phrase", () => {
expect(normalizeChatSearchInput('"fix race" OR deadlock -timeout')).toBe(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 [CRF-2] Test asserts an emitted string the backend rejects, codifying the CRF-1 bug as expected behavior. (Netero)

preserves websearch operators alongside a quoted phrase asserts normalizeChatSearchInput('"fix race" OR deadlock -timeout') equals search:"fix race" OR deadlock -timeout. That output is rejected by searchquery.Chats (unsupported search term: "OR deadlock -timeout"), so the test proves the function produces a specific string, not that the string works.

The sibling assertion at :90 (Fix "auth" middleware -> search:Fix "auth" middleware) has the same defect. Both check output shape and never verify backend acceptance, so they stay green while the feature is broken. A regression test for this path should assert against the backend parser's acceptance of the emitted query.

🤖

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the successor PR #27973 (this PR was auto-closed as stale and could not be reopened after the rebase).

Rewrote both tests to assert the strip-and-wrap behavior that the backend actually accepts: Fix "auth" middleware -> search:"Fix auth middleware" and "fix race" OR deadlock -timeout -> search:"fix race OR deadlock -timeout". The emitted outputs were verified against the real searchquery.Chats parser to confirm acceptance, addressing the "tests pass green while the feature is broken" concern.

🤖 Coder Agents

@github-actions github-actions Bot added the stale This issue is like stale bread. label Aug 5, 2026
@github-actions github-actions Bot closed this Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale This issue is like stale bread.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant