feat(site/src/pages/AgentsPage): wire chat search box to full-text search - #27375
feat(site/src/pages/AgentsPage): wire chat search box to full-text search#27375DanielleMaywood wants to merge 1 commit into
Conversation
…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.
|
/coder-agents-review |
|
Chat: Review posted | View chat Review history
deep-review v0.9.0 | Round 1 | Last posted: Round 1, 2 findings (1 P1, 1 P2), COMMENT. Review Finding inventoryFinding inventory - PR #27375Findings
Round logRound 1Netero-only first pass. 1 P1, 1 P2. Reviewed against acd0d7f..2069bb9. About deep-reviewCRF = Coder Review Finding (P0-P4, Nit, Note)
|
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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)
hasWebSearchQuotesonly 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 throughtoSearchPhraseunchanged and is emitted as a rawsearch:value.
Verified empirically against searchquery.Chats:
Fix "auth" middlewareemitssearch:Fix "auth" middleware->unsupported search term: "\"auth\" middleware",Search=""."fix race" OR deadlock -timeoutemitssearch:"fix race" OR deadlock -timeout->unsupported search term: "OR deadlock -timeout",Search=""."fix race condition"emitssearch:"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.
🤖
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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 phraseassertsnormalizeChatSearchInput('"fix race" OR deadlock -timeout')equalssearch:"fix race" OR deadlock -timeout. That output is rejected bysearchquery.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.
🤖
There was a problem hiding this comment.
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
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 asearch: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
searchvalue to be a single token (multi-word input likehello worldotherwise 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
Implementation notes
normalizeChatSearchInputinsite/src/pages/AgentsPage/components/ChatsSidebar/dialogs/searchQuery.ts: bare text and typedtitle:terms are merged into a singlesearch:FTS filter instead of atitle:ILIKE filter.toSearchPhrase/hasWebSearchQuoteshelpers: free text with a leading/trailing quote pair (websearch phrase syntax) passes through unchanged; everything else is wrapped insearch:"..."with stray quotes stripped (the backend parser has no escape handling for embedded quotes).has_unread,archived,pr_status,diff_url) are unchanged and remain compatible withsearch:.ChatSearchResults.tsxempty state updated to mention the periodic indexing lag (dbpurge sweep populatessearch_tsv).searchQuery.test.ts(10 unit tests) andChatSearchDialog.stories.tsx(20 interaction stories) for the new emitted syntax; error-state stories now usepr_status:badvaluesincetitle:no longer produces an invalid query.