Skip to content

Commit 9b5c976

Browse files
ChingEnLinclaude
andcommitted
fix(query): resolve contradictory retry instruction and review feedback
Address claudebot review on PR #37: - Critical: GENERATE_PROMPT instruction #0 was still telling the model to "switch to let+pipeline form" on retry — leftover from before we discovered Cosmos rejects let/pipeline inside $lookup. Both CROSS_COLLECTION_GUIDANCE and EVALUATE_PROMPT already ban that form, so the retry loop would cycle. Rewrite to recommend the $addFields + $toObjectId/$toString pre-conversion pattern. - Medium: Replace the magic string "Could not fetch schema summary." with a SCHEMA_FETCH_FAILED module-level sentinel so routes/query.py is no longer coupled to an exact error string. - Low: Use logging.getLogger(__name__).warning(...) in routes/query.py instead of print() for the relationship-inference failure path. - CI: black formatting (re-run on react_agent_service.py). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent ed276a1 commit 9b5c976

3 files changed

Lines changed: 17 additions & 6 deletions

File tree

backend/routes/query.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
execute_mongo_query,
2424
transform_mongo_result,
2525
get_database_schema_summary,
26+
SCHEMA_FETCH_FAILED,
2627
)
2728
from models.analyze import AnalyzeRequest, AnalyzeResponse
2829
from services.analyze_service import analyze_query_result
@@ -36,9 +37,12 @@
3637
DeleteResult,
3738
)
3839
import ast
40+
import logging
3941
import re
4042
from google import genai
4143

44+
logger = logging.getLogger(__name__)
45+
4246
router = APIRouter()
4347

4448

@@ -105,7 +109,7 @@ def nl2query(prompt: QueryPrompt = Body(...), authorization: str = Header(...)):
105109
if (
106110
len(collections) > 1
107111
and schema_summary
108-
and schema_summary != "Could not fetch schema summary."
112+
and schema_summary != SCHEMA_FETCH_FAILED
109113
):
110114
try:
111115
rels = generate_schema_relationships(schema_summary, model=prompt.model)
@@ -117,7 +121,9 @@ def nl2query(prompt: QueryPrompt = Body(...), authorization: str = Header(...)):
117121
for r in rels.relationships
118122
)
119123
except Exception as e:
120-
print(f"[WARN] Relationship inference failed; continuing without it: {e}")
124+
logger.warning(
125+
"Relationship inference failed; continuing without it: %s", e
126+
)
121127

122128
return run_query_generator(
123129
user_input=prompt.user_input,

backend/services/mongo_service.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from bson import ObjectId
2+
3+
SCHEMA_FETCH_FAILED = "Could not fetch schema summary."
24
import pymongo
35
from pymongo.results import (
46
UpdateResult,
@@ -90,4 +92,4 @@ def get_database_schema_summary(
9092
return "\n\n".join(summary)
9193
except Exception as e:
9294
print(f"Error fetching schema summary: {e}")
93-
return "Could not fetch schema summary."
95+
return SCHEMA_FETCH_FAILED

backend/services/react_agent_service.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ class AgentState(TypedDict):
151151
{evaluation}
152152
153153
Instructions:
154-
0. If a Previous Attempt is shown above, your new query MUST be materially different from it — change the join form, fields, types, or stages in response to the critique. Producing the same query (or a trivial reformat) is a failure. In particular, if the previous attempt used `localField`/`foreignField` $lookup and returned empty for every doc, switch to the `let` + `pipeline` form with $toObjectId/$toString to fix likely type mismatches.
154+
0. If a Previous Attempt is shown above, your new query MUST be materially different — change the join form, fields, types, or stages in response to the critique. Producing the same query (or a trivial reformat) is a failure. If the previous $lookup returned empty arrays for every input doc, the cause is almost always a type mismatch on the join key: add an `$addFields` stage BEFORE the `$lookup` that applies `$toObjectId` (string→OID) or `$toString` (OID→string), then $lookup on the converted field. NEVER use `let` or `pipeline` inside `$lookup` — Cosmos rejects both with CommandNotSupported.
155155
1. Write ONLY the PyMongo query code.
156156
2. Use variables appropriately (e.g., db['collection_name'].find(...) or db['collection_name'].aggregate(...)).
157157
3. Do not include markdown formatting or explanations, just return the code, but you can use ```python if you must.
@@ -199,11 +199,14 @@ def generate_query_node(state: AgentState):
199199
database=state["database"],
200200
collections=", ".join(state["collections"]),
201201
schema_context=state["schema_context"],
202-
relationship_context=state.get("relationship_context") or "None (single collection or no inferred relationships).",
202+
relationship_context=state.get("relationship_context")
203+
or "None (single collection or no inferred relationships).",
203204
intermediate_context=state.get("intermediate_context", {}),
204205
previous_query=previous_query or "None (this is the first attempt).",
205206
evaluation=state.get("evaluation", "None"),
206-
cross_collection_guidance=CROSS_COLLECTION_GUIDANCE if is_multi_collection else "",
207+
cross_collection_guidance=(
208+
CROSS_COLLECTION_GUIDANCE if is_multi_collection else ""
209+
),
207210
)
208211

209212
try:

0 commit comments

Comments
 (0)