Skip to content

fix(recall): allow exact filtering of untagged/global observations (#2295)#2364

Merged
nicoloboschi merged 2 commits into
mainfrom
fix/recall-untagged-observations
Jun 23, 2026
Merged

fix(recall): allow exact filtering of untagged/global observations (#2295)#2364
nicoloboschi merged 2 commits into
mainfrom
fix/recall-untagged-observations

Conversation

@nicoloboschi

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2295. Supersedes #2322.

Allow recall to select only untagged/global observations by passing an empty tag
set ([] or omitted) together with tags_match="exact". This lets users switch
between shared and tagged observation scopes without a synthetic "global" tag or
a hand-maintained negative filter.

Root cause

The centralized tag filters treated None/[] as "no filter" in every mode,
returning every scope. There was no way to recall only the global/untagged scope —
the one that observation_scopes="shared" consolidation writes to.

Fix

In exact mode, an empty/absent tag set now means the global/untagged scope and
emits an untagged-only clause (tags IS NULL OR tags = '{}', matching both
historical NULLs and current empty-array storage). Applied consistently across:

  • the flat SQL builders (build_tags_where_clause, build_tags_where_clause_simple)
  • Python post-processing (filter_results_by_tags)
  • compound tag-group leaves (_build_group_clause, _match_group)
  • link-expansion post-filtering (run unconditionally so the empty exact scope applies)

No bind parameter is consumed for the empty-scope clause, so following parameter
indexes stay aligned. All other modes (any, all, any_strict, all_strict)
still treat empty/absent tags as "no filtering" — unchanged.

http.py field descriptions and the regenerated clients/OpenAPI/docs document the
new exact-empty scope.

Relationship to #2322

This implements the same fix as #2322 but additionally updates the RecallRequest
API descriptions and regenerates the client SDKs (Go/Python/TypeScript), OpenAPI
spec, and docs — so the user-facing surface is complete. It also adds the
parameter-offset regression test from #2322. Opening this to supersede #2322.

Tests

  • SQL builders: flat + compound, None and [], param-offset preserved
  • Python post-filter: NULL / empty / tagged results under exact-empty scope
  • Recall API: tags=[] + tags_match="exact" returns the untagged memory and
    excludes the tagged one

Verification

  • tests/test_tags_visibility.py tag-filtering tests pass (34 passed for the
    exact/untagged/empty/global subset incl. the recall API test)
  • ty check passed; ruff check + ruff format clean; generated files in sync

…2295)

An empty tag set with tags_match="exact" now selects only untagged
(global-scope) observations — the scope that observation_scopes="shared"
consolidation writes to. Previously empty/absent tags meant "no filter"
in every mode, so there was no way to recall only global observations
when mixing shared and tagged scopes.

- tags.py: in exact mode, empty/absent tags emit an untagged-only clause
  (tags IS NULL OR tags = '{}') with no bind param, across the flat SQL
  builders, Python post-filter, and compound tag-group leaves. All other
  modes keep treating empty/absent tags as "no filtering".
- link_expansion_retrieval.py: always run filter_results_by_tags so the
  exact-empty/global scope is applied (it's a no-op otherwise).
- http.py + regenerated clients/docs: document the exact-empty scope.
- Tests: SQL builders (flat + compound, param-offset preserved), Python
  post-filter, and a recall API test asserting only untagged memories
  return for tags=[] + tags_match="exact".
@wangzupeng12061

Copy link
Copy Markdown
Contributor

Thanks for mentioning #2322 and keeping the regression test. If appropriate, would it be possible to add me as a co-author for the root-cause investigation and the parameter-offset regression test contribution?

Regenerated skills/hindsight-docs/references via generate-docs-skill.sh so the
docs-skill mirror matches the updated recall/observations docs (and the canonical
configuration table). Unblocks verify-generated-files.
@nicoloboschi nicoloboschi merged commit 0ba613c into main Jun 23, 2026
98 checks passed
@nicoloboschi nicoloboschi deleted the fix/recall-untagged-observations branch June 23, 2026 09:08
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.

Allow filtering to untagged observations

2 participants