Skip to content

Tag-filtered retrieval (#59) - #71

Merged
7vignesh merged 1 commit into
mainfrom
feat/tag-filtered-retrieval
Oct 26, 2026
Merged

7vignesh merged 1 commit into
mainfrom
feat/tag-filtered-retrieval

Conversation

@7vignesh

Copy link
Copy Markdown
Owner

Closes #59. (Supersedes #70, which GitHub auto-closed when its stacked base branch fix/index-tags-in-fts merged and was deleted. Rebased onto main; now a clean single-commit diff.)

What

Expose an optional tag filter on both retrieval tools:

  • tags: array of tag labels to filter by.
  • tagMatch: "or" (default, keep any listed tag) or "and" (require all).

How

  • lib/context.makeTagFilter builds a case-insensitive whole-tag predicate; it returns a pass-through when no tags are given, so the default path is untouched.
  • fetchRepoContext runs every source (pinned, recent, search) through the predicate. When a filter is active it widens the candidate fetch to max(limit*4, 50) so matching rows ranked below the cut are not lost to a naive post-slice; output is still capped at limit.
  • search_memory applies the predicate to its FTS and vector legs and threads tags/tagMatch into its pinned+recent fallback.
  • Tools stay thin: zod validates tags/tagMatch, the logic lives in lib.

Out of scope (unchanged)

  • Default behaviour with no tags is byte-identical to before: pass-through predicate, fetchLimit === limit.
  • No LLM, no network.

Measurement

Does not touch ranking when no filter is set. npm run bench:check passes with no drift.

Tests

tests/tag-filter.test.ts: no filter, single tag, AND, OR, no-match, case-insensitivity, and the search-hit (not just backfill) path with a widened pool. tests/search-tag-filter.test.ts exercises search_memory end to end. npm run ci green.

Add an optional `tags` array plus `tagMatch: "and" | "or"` (default "or") to
get_context and search_memory. "or" keeps a memory sharing any listed tag;
"and" requires every listed tag. Matching is case-insensitive over whole tags.

The filter is a predicate (lib/context.makeTagFilter) threaded through the
shared retrieval pipeline: in fetchRepoContext every source (pinned, recent,
search) passes through it; search_memory applies it to its FTS and vector legs
and its fallback. When a filter is active the candidate fetch is widened
(max(limit*4, 50), bounded since limit caps at 50) so matching rows below the
cut are not lost to a naive post-slice; output is still capped at limit.

Default behaviour with no tags is identical to before: makeTagFilter returns a
pass-through predicate and fetchLimit stays at limit. bench:check confirms no
ranking drift.

Tools stay thin: zod validates the params, logic lives in lib.

Depends on #58 (tags indexed in FTS).
@vercel

vercel Bot commented Oct 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
fossel Ready Ready Preview Oct 26, 2026 1:21pm UTC

@7vignesh
7vignesh merged commit 20f5ff4 into main Oct 26, 2026
6 checks passed
@7vignesh
7vignesh deleted the feat/tag-filtered-retrieval branch October 26, 2026 17:50
@7vignesh 7vignesh mentioned this pull request Oct 27, 2026
7vignesh added a commit that referenced this pull request Oct 27, 2026
Release 2.1.0. Ships the backlog merged to main since v2.0.0, notably:
- Index memory tags in FTS (#58 / #69)
- Tag-filtered retrieval on get_context and search_memory (#59 / #71)

Pushing the v2.1.0 tag after this merges triggers the npm publish workflow,
which re-checks that the tag matches package.json before publishing.

This branch was successfully deployed

1 active deployment
Preview — 6ae98fce Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tag-filtered retrieval (tags filter with AND/OR)

1 participant