Skip to content

session_search recovers paraphrased multi-word queries via OR-relaxed retry on a zero-result miss - #88030

Merged
teknium1 merged 3 commits into
mainfrom
ironclaw-port/session-search-or-fallback
Sep 15, 2026
Merged

teknium1 merged 3 commits into
mainfrom
ironclaw-port/session-search-or-fallback

Conversation

@teknium1

Copy link
Copy Markdown
Collaborator

Summary

session_search now recovers paraphrased multi-word queries: when the exact FTS5 match (and the substring fallbacks) return zero rows, the same query is retried with its terms OR-joined and bm25-ranked, so a fact saved as "Sarah prefers the standup meeting scheduled early on Thursday mornings" is found by "when does Sarah like her standup scheduled".

Ported from nearai/ironclaw#7553 (Filter::FtsRanked): FTS5's implicit AND requires every query term to appear, so a query worded even slightly differently from the stored sentence returns nothing.

Changes

  • hermes_state_search.py: new _or_relaxed_query() helper (OR-joins searchable units, preserves quoted phrases as units, declines on explicit OR/NOT or single-term queries) + a zero-result-gated retry at the tail of search_messages's fallback chain, reusing the already-built SQL so all source/role/sort filters apply.
  • tests/state/test_search_or_relaxed_fallback.py: 13 tests — helper semantics + end-to-end paraphrased recall (verified to fail with the helper sabotaged out).
  • tests/tools/test_session_search.py: one rewind-exclusion test tightened from "count == 0" to "the rewound row never surfaces" (the OR retry may legitimately surface other active rows sharing a common term).

Adaptation notes

  • IronClaw adds a separate Filter::FtsRanked variant at the storage layer and switches the memory-native search path onto it. Hermes' session search already has a layered fallback chain (unicode61 → CJK-bigram → trigram → LIKE), so the port slots in as one more strictly-additive zero-result retry rather than a new filter mode — exact-match semantics and ordering are untouched for queries that hit.
  • Explicit boolean queries (OR / NOT) are never relaxed; CJK-routed queries keep their own substring semantics.

Validation

Before After
search_messages("when does Sarah like her standup scheduled") [] standup row, bm25-ranked
exact query "standup Thursday" exact match unchanged (retry never fires)
standup NOT Thursday excludes Thursday unchanged (not relaxed)
targeted suites (state/tools/cjk/slow-log) — 91 passed

Infographic

Session search OR-relaxed retry

@github-actions

github-actions Bot commented Aug 17, 2026 •

Copy link
Copy Markdown

૮ >ﻌ< ა ci review

ran on fcf9e52 — test(session-search): collapse OR-relaxed tests to three inv

⚠️ Warnings

OSV vulnerability scan · View job

76 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


CI timings · View report · View job

Wall time 7m55s vs 6m9s (+28.7%). 11 job(s) slower, 3 faster,

  • Python tests / e2e: +13.0s
  • Python lints / Windows footguns (blocking): +12.0s
  • Python lints / ruff enforcement (blocking): +9.0s
  • OS-specific tests / macOS-only tests: +9.0s
  • OSV scan / Scan lockfiles / osv-scan: -8.0s

@alt-glitch alt-glitch added type/feature New feature or request comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 17, 2026
@alt-glitch alt-glitch mentioned this pull request Aug 25, 2026
@teknium1
teknium1 force-pushed the ironclaw-port/session-search-or-fallback branch from d3f9d4e to 7712cf2 Compare September 15, 2026 01:50
@teknium1 teknium1 changed the title feat(session-search): OR-relaxed retry recovers paraphrased recall (port of ironclaw#7553) session_search recovers paraphrased multi-word queries via OR-relaxed retry on a zero-result miss Sep 15, 2026
Port from nearai/ironclaw#7553 (Filter::FtsRanked): FTS5's implicit AND
between terms means a paraphrased multi-word query misses a stored
sentence that lacks even one of the words. When the exact-match search
and the substring fallbacks all return zero rows, retry the same
unicode61 FTS index with the terms OR-joined, ranked by bm25 so rows
covering more terms surface first.

Strictly additive: gated on a zero-result miss, so successful searches
keep exact-match semantics and ordering. Queries with explicit OR/NOT,
single-term queries, and CJK-routed queries are left untouched. Quoted
phrases relax as whole units.

Adapted for hermes-agent: implemented inside SessionSearchMixin's
zero-result fallback chain (after the CJK-bigram/trigram substring
retries) rather than as a separate filter variant, reusing the already-
built SQL/params so all source/role/sort filters apply to the retry.
The discovery payload exposes hits under `results`, not `matches`, so the
loop over `result_rewind.get("matches", [])` never iterated and the
invariant (the rewound row never surfaces, even via the OR-relaxed retry)
was not being checked. Assert on the anchor message id and snippet of each
returned result instead.
…comment says sort applies

The retry passes ``route`` through unchanged, so the caller's ``sort`` (newest/oldest) still
drives ORDER BY; the comment claimed bm25 ranking unconditionally. Say what the code does
rather than force rank order — a user who asked for newest-first should get newest-first
from the relaxed hits too.

Tests: the seven ``_or_relaxed_query`` helper cases become one parametrized test; one DB
recovery test (exact untouched, paraphrase recovered, all partial rows, role_filter honoured)
and one negative (explicit NOT not relaxed, true miss stays empty, CJK route never reaches
the rewrite). Drops the upstream product name from module prose (credit stays in the PR body).
@teknium1
teknium1 force-pushed the ironclaw-port/session-search-or-fallback branch from 7712cf2 to fcf9e52 Compare September 15, 2026 04:14
@teknium1
teknium1 merged commit 1a2b5a3 into main Sep 15, 2026
65 of 66 checks passed
@teknium1
teknium1 deleted the ironclaw-port/session-search-or-fallback branch September 15, 2026 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants