Priority
P1
Area
Query Engine / Session State
Problem
The search API is stateless. Users cannot refine searches conversationally (e.g. 'Show me high protein snacks' -> 'Which ones have the least sugar?' -> 'Only vegan ones'). The second turn currently evaluates as a brand new query, losing the 'high protein snacks' context.
Why This Matters
Real users search conversationally and incrementally. Losing context between turns frustrates users and forces them to retype long, complex queries. Maintaining cumulative constraint state makes AskOFF feel responsive and intelligent while preserving deterministic retrieval.
Current Behaviour
backend/query/pipeline.py processes each query string independently from scratch.
backend/query/constraint_extractor.py extracts filters afresh without prior context.
- No session or query state merger exists in
backend/.
Expected Behaviour
- Conversation context is represented explicitly in API payloads or session state.
- Follow-up constraints are combined correctly without silently losing prior constraints.
- Core subject noun ('snacks') is retained unless explicitly replaced.
- Ambiguous references are handled safely.
- Search retrieval remains 100% deterministic OpenSearch queries.
- Tests cover multi-turn query sequences.
Proposed Implementation
- Deterministic Constraint Merger: Implement
refine(previous_query: SearchQuery, follow_up_text: str) -> SearchQuery in backend/query/pipeline.py:
- Retain core subject unless follow-up introduces a new subject.
- Merge boolean filters (e.g.
high_protein: True + vegan: True).
- Combine numeric bounds without overwrite unless explicitly updated.
- Update ranking preferences (e.g. adding
sort_nutrient: sugars, order: asc).
- State Payload in API: Support receiving active constraints in
POST /search/refine or POST /bot/chat.
- Inspectable State: Expose cumulative merged state in
SearchQuery.metadata.
Acceptance Criteria
Implementation Prompt
First inspect the existing implementation and tests before making changes. Understand the current behaviour and identify the smallest appropriate change. Implement the requested functionality without unrelated refactoring. Add or update regression tests. Run the relevant tests, linting/type checks, and verification commands. Do not modify unrelated components.
Inspect `backend/query/pipeline.py`, `backend/query/search_query.py`, and `backend/query/constraint_extractor.py`.
Implement conversational query constraint merging:
1. In `backend/query/pipeline.py`, add a method `refine(previous_query: SearchQuery, follow_up_text: str) -> SearchQuery`.
2. Process the follow_up_text through normalizers and ConstraintExtractor.
3. Intelligently merge constraints: preserve existing boolean flags, combine numeric bounds, update ranking preferences, and retain the core subject noun unless explicitly replaced.
4. Expose the merged state in SearchQuery.metadata so the client can inspect applied cumulative filters.
5. Add unit tests in `backend/tests/test_conversational_query.py` demonstrating 3-turn refinement scenarios.
Verification Plan
Run conversational query tests:
pytest backend/tests/test_conversational_query.py -v
pytest backend/tests/test_query_engine.py -v
Dependencies
Backlog IDs 2 and 15
Maintainer Decision Required
No maintainer decision required.
Out of Scope
- Storing user chat histories indefinitely in a database.
- Using an LLM to rewrite search queries.
Relevant Files
backend/query/pipeline.py
backend/query/search_query.py
backend/query/constraint_extractor.py
backend/api/routes.py
backend/tests/test_conversational_query.py
Priority
P1
Area
Query Engine / Session State
Problem
The search API is stateless. Users cannot refine searches conversationally (e.g. 'Show me high protein snacks' -> 'Which ones have the least sugar?' -> 'Only vegan ones'). The second turn currently evaluates as a brand new query, losing the 'high protein snacks' context.
Why This Matters
Real users search conversationally and incrementally. Losing context between turns frustrates users and forces them to retype long, complex queries. Maintaining cumulative constraint state makes AskOFF feel responsive and intelligent while preserving deterministic retrieval.
Current Behaviour
backend/query/pipeline.pyprocesses each query string independently from scratch.backend/query/constraint_extractor.pyextracts filters afresh without prior context.backend/.Expected Behaviour
Proposed Implementation
refine(previous_query: SearchQuery, follow_up_text: str) -> SearchQueryinbackend/query/pipeline.py:high_protein: True+vegan: True).sort_nutrient: sugars, order: asc).POST /search/refineorPOST /bot/chat.SearchQuery.metadata.Acceptance Criteria
high protein snacks) + Turn 2 (lowest sugar) queries snacks with high protein sorted by sugar ascending.only vegan) adds vegan flag without losing previous constraints.Implementation Prompt
Verification Plan
Run conversational query tests:
Dependencies
Backlog IDs 2 and 15
Maintainer Decision Required
No maintainer decision required.
Out of Scope
Relevant Files
backend/query/pipeline.pybackend/query/search_query.pybackend/query/constraint_extractor.pybackend/api/routes.pybackend/tests/test_conversational_query.py