Skip to content

feat: include all query-hit snippets for page chunks in retrieval responses - #245

Open
gdccyuen wants to merge 1 commit into
Ontos-AI:mainfrom
gdccyuen:feat/gdccyuen/page-snippets-in-retrieval
Open

feat: include all query-hit snippets for page chunks in retrieval responses#245
gdccyuen wants to merge 1 commit into
Ontos-AI:mainfrom
gdccyuen:feat/gdccyuen/page-snippets-in-retrieval

Conversation

@gdccyuen

@gdccyuen gdccyuen commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

What

Fixes retrieval for page chunks (e.g. a scanned telephone-directory page): the API was returning only the chunk's LLM summary — which rarely contains the queried name — making name lookups return "null"/useless results. Now the response includes every occurrence of the query terms from the full page content as bounded snippets.

Problem

  • A directory PDF produces one giant page chunk (183K chars) + image chunks
  • assemble_retrieval_results replaced page-chunk content with metadata.summary (content_source: 'summary') — a 2-line generic summary naming no one
  • Clients (e.g. knowhere-notebook) only ever saw that summary as evidence → queries like "Gordon" (which appears 2× in the page text) returned no useful content

Changes

packages/shared-python/shared/services/retrieval/hydration/page_snippets.py (new)

extract_page_snippets(content, query_tokens, *, context_chars=100, max_snippets=20):

  • Case-insensitive, word-boundary-aware matching (won't match "Gordonstoun")
  • Returns all occurrences in document order, each centered ±100 chars (configurable), trimmed at nearby word boundaries with markers
  • Deduplicates identical snippets; capped at 20 so pages with hundreds of hits stay bounded

result_assembly.py

  • assemble_retrieval_results gains query: str | None = None
  • Page chunks now return summary + "\n\n" + snippets with content_source='content_snippets' when hits exist; falls back to 'summary' unchanged when there are no hits

execution/routes.py

  • All three assemble_retrieval_results call sites pass query=context.query

Tests

  • packages/shared-python/shared/tests/test_page_snippets.py (6 unit tests: all-occurrences, cap, case/boundary, no-hits, dedupe, bounded)
  • apps/worker/tests/contract/test_page_memory_retrieval_contract.py (2 new: snippets appended when query matches; summary fallback without hits)
  • apps/api/tests/contract/test_retrieval_contract.py (1 new: query "Gordon" → both CHEUNG Hon-lam Gordon and YUEN Chun-cheung Gordon in the page result, content_source='content_snippets', evidence includes document)

Verified: pnpm-style lint (ruff) + pyright clean; 36 affected tests pass.

…ponses

Page chunks can be very large (whole scanned directory pages) and their
LLM summary rarely contains the exact queried term, so retrieval results
were unhelpful for name lookups. Extract every occurrence of the query
terms from the full page content as bounded snippets (±100 chars, capped
at 20, deduplicated) and append them after the summary.

- New shared/services/retrieval/hydration/page_snippets.py
- assemble_retrieval_results gains a query param; page chunks set
  content_source='content_snippets' when hits exist, else 'summary'
- Thread query=context.query through all assembly call sites in routes.py
- Unit tests (6) + worker contract tests (2) + API contract test (1)
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.

1 participant