Skip to content

feat(search): add natural-language query support to dirctl search and SearchService#1770

Merged
paralta merged 5 commits into
mainfrom
feat/nl-search
Jul 10, 2026
Merged

feat(search): add natural-language query support to dirctl search and SearchService#1770
paralta merged 5 commits into
mainfrom
feat/nl-search

Conversation

@paralta

@paralta paralta commented Jul 8, 2026

Copy link
Copy Markdown
Member

feat(search): add natural-language search to dirctl

Adds dirctl search "<free-text query>" as a new search mode backed by the OASF extractor provisioned by dirctl init. The extractor runs locally and decomposes the query into skill, domain, and keyword signals; each signal is fanned out as a parallel SearchCIDs call and results are ranked client-side by how many signals matched each record. This requires no server-side ranking changes — scoring happens entirely in the CLI, so the only server additions are a new RECORD_QUERY_TYPE_DESCRIPTION query type (wildcard-matching the record description field) and SORT_MODE_RELEVANCE in the proto (which maps to recency on the server, since fan-out queries don't need a specific server-side order).

  • Keyword signals query both NAME and DESCRIPTION fields concurrently and union the results before scoring, so a keyword matched in either field counts as exactly one hit per record — not two.
  • Taxonomy signals (skills, domains) are only used when the extractor returns a cosine-similarity score ≥ 0.3; the extractor always returns at least one result per category regardless of relevance, so without this threshold weak matches add noise with no recall benefit.
  • --verbose prints signal decomposition and per-signal CID counts to stderr, which is useful for understanding why specific records appear in results.
  • --sort is also added to the structured search path for completeness (recency, popularity, relevance).

⚠️ Warning
Signal decomposition is intentionally implemented client-side (in the CLI) rather than in the server. The OASF extractor is a local sentence-transformer model (~89 MB) provisioned per-user by dirctl init; embedding it in the server would add a large runtime dependency and make horizontal scaling significantly harder. The trade-off is that the gateway (AI Catalog) cannot offer NL search today — any gateway endpoint that wants to expose free-text queries would need either a server-side extractor service that accepts a raw query string and performs decomposition server-side.

Example output

.bin/dirctl search "I need a MCP server to connect to a agntcy directory" --sort relevance --verbose
[nl-search] signals extracted (5):
  keyword   *mcp*                                                 score=1.00
  keyword   *server*                                              score=1.00
  keyword   *connect*                                             score=1.00
  keyword   *agntcy*                                              score=1.00
  keyword   *directory*                                           score=1.00
[nl-search] per-signal hits:
  keyword   *server*                                              → 0 CIDs
  keyword   *mcp*                                                 → 1 CIDs
  keyword   *connect*                                             → 1 CIDs
  keyword   *directory*                                           → 1 CIDs
  keyword   *agntcy*                                              → 1 CIDs
[nl-search] ranked results (2 unique, 5 signals):
  baeareiagqjzcdyasx66j5zxmbkb2w7ejty3d4pa3ato6a6jp2guovqx6km  hits=2/5  signals=[keyword:*mcp*, keyword:*connect*]
  baeareiblucjmsiq6j6a4lwgjwtod33v6jip6tz47hildt2tl22256zwzz4  hits=2/5  signals=[keyword:*directory*, keyword:*agntcy*]
Record CIDs found: [baeareiagqjzcdyasx66j5zxmbkb2w7ejty3d4pa3ato6a6jp2guovqx6km baeareiblucjmsiq6j6a4lwgjwtod33v6jip6tz47hildt2tl22256zwzz4]

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

The latest Buf updates on your PR. Results from workflow Buf CI / verify-proto (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed⏩ skipped⏩ skipped✅ passedJul 9, 2026, 3:09 PM

@github-actions github-actions Bot added the size/M Denotes a PR that changes 200-999 lines label Jul 8, 2026
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

paralta added 3 commits July 9, 2026 09:36
…E_TEXT

Signed-off-by: Catarina Paralta <clouropa@cisco.com>
Signed-off-by: Catarina Paralta <clouropa@cisco.com>
Signed-off-by: Catarina Paralta <clouropa@cisco.com>
@paralta
paralta marked this pull request as ready for review July 9, 2026 09:08
@paralta
paralta requested a review from a team as a code owner July 9, 2026 09:08
Signed-off-by: Catarina Paralta <clouropa@cisco.com>
Signed-off-by: Catarina Paralta <clouropa@cisco.com>
@paralta
paralta merged commit eb14954 into main Jul 10, 2026
33 checks passed
@paralta
paralta deleted the feat/nl-search branch July 10, 2026 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Denotes a PR that changes 200-999 lines

Projects

None yet

2 participants