feat(platform): let chat find entities by words in a question - #3106
feat(platform): let chat find entities by words in a question#3106Israeltheminer wants to merge 1 commit into
Conversation
|
Superseded by #3123, which does this against the Postgres backend. Eight of the ten files this branch touches were deleted by #3107, including #3123 carries the same decision — word matching added alongside the phrase match, never replacing it — and covers two legs this one did not. The 0.5 chat shim reimplemented the tasks and projects legs as SQL with a whole-phrase Worth closing this once #3123 lands. |
|
Closing: superseded by #3123, which is open and still needed — Every one of the ten files this branch touches was deleted by #3125, so it cannot be rebased. #3123 carries the same decision (word matching added alongside the phrase match, never replacing it) and covers two legs this branch never touched: the port had reimplemented the tasks and projects legs as SQL with a whole-phrase The epic #2992 tracks the remainder. |
Chat can now find a contact, product or knowledge entry from a multi-word question. Before this it compared the whole question as one string, so it found nothing.
Last code item on #2992.
Why
The entity legs pass a natural-language question straight through as a search term, and the queries match it as a single substring. "do we have red running shoes" only matches text literally containing that phrase, so it never matches. The tasks and projects legs already split the term into words; these three did not.
What changed
Word matching is added ALONGSIDE each entity's existing phrase match, never in place of it. A row matches if any meaningful word hits, or if the whole phrase hits as it does today.
That combination is the point. The phrase check reaches fields the word-match config cannot express — a product's translated name and description among them — so swapping to words alone would have quietly shrunk what is searchable. A customer running their catalogue in German would have found chat unable to locate a product by the name they actually use, while the products page still could.
Opt-in per call. The contacts and products pages search exactly as they do today; only the chat legs pass
matchWords, because only they pass a question.'any'mode is what makes a question usable: it drops stopwords and single characters, and requires a word-START match rather than any substring — without that floor, "ad" would pull in every row containing "overhead".Risk
The two field lists differ on purpose. The word config covers a product's name, description, category, tags and code; the phrase check also covers translations. Anyone "tidying" one to match the other would silently delete translation search. Both strategy files say so.
Knowledge entries deliberately exclude
content. The agent listing filters on topic alone, and matching whole bodies would turn a topic filter into a full-text search over every entry.Two code paths in products.
queryProductsfilters in memory whenexternalIdis an array, separately from the paginated walk. Both thread the word term, and both are tested — the first mutation I ran passed because it hit the untested branch, which is how I found out.Tests
Seven cases: a multi-word question finding a product, the same question finding nothing without opting in, a translated name and a translated description both still found, a stopword-only question matching nothing, a mid-word fragment not matching while a real word does, and the
externalId-array path.Four deliberate breakages, all caught: word matching off, the opt-in ignored on each of the two paths, and
allinstead ofany.Scope
Adds matching; removes none. Ranking is unchanged — this decides whether a row matches, not how matches are ordered.
Gate: repo-wide typecheck,
oxlint --type-aware, oxfmt, knip, SAST 0 findings, platform suite 75,819 passing.