Skip to content

chore(wren-ai-service): improve text2sql (ai-env-changed) - #1936

Merged
cyyeh merged 7 commits into
mainfrom
chore/ai-service/improve-text2sql
Sep 5, 2025
Merged

chore(wren-ai-service): improve text2sql (ai-env-changed)#1936
cyyeh merged 7 commits into
mainfrom
chore/ai-service/improve-text2sql

Conversation

@cyyeh

@cyyeh cyyeh commented Sep 4, 2025

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Adds an automatic SQL diagnosis step that returns structured reasoning and a can-be-corrected indicator to guide fixes.
  • Improvements

    • Correction retry flow now consults diagnosis and skips futile correction attempts.
    • Error responses surface engine-provided SQL variants for clearer debugging.
  • Documentation

    • Configuration examples across providers updated to include the new diagnosis step.
  • Chores

    • Introduces a config flag to enable/disable SQL diagnosis (default: enabled).

@coderabbitai

coderabbitai Bot commented Sep 4, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a new SQL diagnosis generation pipeline and integrates it into Ask and AskFeedback flows; exposes SQLDiagnosis in exports; updates sql_correction to accept sql_functions; preserves original_sql across invalid results; adjusts engine error payloads; adds allow_sql_diagnosis config flag and pipeline entries in runtime/docs configs.

Changes

Cohort / File(s) Summary of changes
Pipeline wiring
wren-ai-service/src/globals.py
Registers _sql_diagnosis_pipeline and injects sql_diagnosis into AskService (after sql_functions_retrieval) and AskFeedbackService (after sql_correction).
New pipeline module & export
wren-ai-service/src/pipelines/generation/sql_diagnosis.py, wren-ai-service/src/pipelines/generation/__init__.py
Adds SQLDiagnosis pipeline implementation, prompts, SqlDiagnosisResult model, model kwargs, prompt/generate/post-process functions; exports SQLDiagnosis.
SQL correction changes
wren-ai-service/src/pipelines/generation/sql_correction.py
Adds SqlFunction support: propagate sql_functions into prompt builder and pipeline run; update prompt templates and function/method signatures to accept sql_functions.
Invalid result shaping
wren-ai-service/src/pipelines/generation/utils/sql.py
Preserve original_sql on invalid paths; prefer error_sql when present for returned sql fields; adjust unpacking of DRY_RUN success flag.
Engine error handling
wren-ai-service/src/providers/engine/wren.py
On GraphQL errors extract dialectSql/plannedSql as error_sql and read correlationId from errors[0].extensions.other.correlationId; return error_sql when available.
Service flows (Ask / AskFeedback)
wren-ai-service/src/web/v1/services/ask.py, wren-ai-service/src/web/v1/services/ask_feedback.py
Add allow_sql_diagnosis flag to constructors; on invalid dry-run optionally run sql_diagnosis (contexts, original_sql, invalid_sql, error_message, language), branch on can_be_corrected, and pass diagnostic reasoning into sql_correction along with sql_functions.
Config flag
wren-ai-service/src/config.py
Adds allow_sql_diagnosis: bool = Field(default=True) to Settings.
Deployment & runtime configs
deployment/kustomizations/base/cm.yaml, docker/config.example.yaml, wren-ai-service/tools/config/config.example.yaml, wren-ai-service/tools/config/config.full.yaml
Insert - name: sql_diagnosis (with llm: litellm_llm.default) into pipeline pipes lists after sql_tables_extraction.
Docs config examples
wren-ai-service/docs/config_examples/*
Many example configs updated to add or replace a pipes entry with - name: sql_diagnosis (uses llm: litellm_llm.default), placed after or replacing sql_tables_extraction.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant AskSvc as AskService
  participant Gen as SQLGenerator
  participant Exec as SQLDryRun
  participant Diag as SQLDiagnosis
  participant Corr as SQLCorrection

  User->>AskSvc: Ask question
  AskSvc->>Gen: generate SQL
  Gen-->>AskSvc: generation_result
  AskSvc->>Exec: dry-run SQL
  Exec-->>AskSvc: error_response (error_message, error_sql?)

  alt error_response present
    AskSvc->>Diag: contexts (schema), original_sql, invalid_sql, error_message, language
    Diag-->>AskSvc: {reasoning, can_be_corrected}
    alt can_be_corrected == true
      AskSvc->>Corr: contexts, invalid_generation_result{sql: original_sql, error: reasoning}, sql_functions
      Corr-->>AskSvc: {valid_sql | invalid_sql}
      AskSvc->>Exec: dry-run corrected SQL (if valid)
      Exec-->>AskSvc: {ok | error}
    else cannot be corrected
      AskSvc-->>User: report diagnostic reasoning / stop retries
    end
  else no error
    AskSvc-->>User: return results
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Feedback as AskFeedbackService
  participant Diag as SQLDiagnosis
  participant Corr as SQLCorrection

  User->>Feedback: feedback with invalid SQL
  alt invalid SQL
    Feedback->>Diag: table_ddls, original_sql, invalid_sql, error_message, language
    Diag-->>Feedback: {reasoning, can_be_corrected}
    alt can_be_corrected == true
      Feedback->>Corr: contexts, invalid_generation_result{sql: original_sql, error: reasoning}, sql_functions, project_id
      Corr-->>Feedback: {valid | invalid}
    else cannot be corrected
      Feedback-->>User: return original invalid SQL/error
    end
  else valid
    Feedback-->>User: proceed normally
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • yichieh-lu
  • paopa
  • imAsterSun

Poem

I hop through schemas, sniff the trace,
I nudge the bug, and find its place.
I answer with reason, a boolean cheer,
"Fixable!" I say — or "Stop here."
Tiny paws, big logs, carrot-powered cheer. 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/ai-service/improve-text2sql

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@cyyeh cyyeh added module/ai-service ai-service related ci/ai-service ai-service related labels Sep 4, 2025
@github-actions github-actions Bot changed the title chore(wren-ai-service): improve text2sql chore(wren-ai-service): improve text2sql (ai-env-changed) Sep 4, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
wren-ai-service/src/pipelines/generation/sql_correction.py (2)

110-126: Guard against missing/empty replies to prevent runtime errors.

If the generator returns no replies, this will raise at post-processing time. Add a defensive check.

 async def post_process(
     generate_sql_correction: dict,
     post_processor: SQLGenPostProcessor,
     data_source: str,
     project_id: str | None = None,
     use_dry_plan: bool = False,
     allow_dry_plan_fallback: bool = True,
 ) -> dict:
-    return await post_processor.run(
-        generate_sql_correction.get("replies"),
+    replies = generate_sql_correction.get("replies") or []
+    if not replies:
+        raise ValueError("SQLCorrection: generator returned no replies")
+    return await post_processor.run(
+        replies,
         project_id=project_id,
         use_dry_plan=use_dry_plan,
         data_source=data_source,
         allow_dry_plan_fallback=allow_dry_plan_fallback,
     )

74-79: Ensure invalid_generation_result always includes .error
The prompt template in sql_correction.py (lines 75–76) reads {{ invalid_generation_result.error }}, but in wren-ai-service/src/pipelines/generation/utils/sql.py all the invalid_generation_result branches only set keys like "sql", "original_sql", "type" or use "error_sql"—there’s no "error" key. Add an "error" field (e.g. from error_message or addition.get("error_message")) in every branch that builds invalid_generation_result.

🧹 Nitpick comments (19)
wren-ai-service/docs/config_examples/config.qwen3.yaml (1)

186-187: Consider a JSON-strong LLM alias for structured outputs.

If sql_diagnosis expects JSON, prefer the alias configured with response_format: json_object (you already defined qwen3-32b).

-  - name: sql_diagnosis
-    llm: litellm_llm.default
+  - name: sql_diagnosis
+    llm: litellm_llm.qwen3-32b
docker/config.example.yaml (1)

164-165: Good addition; keep ordering consistent with examples.

sql_diagnosis follows sql_tables_extraction as expected.

If the diagnosis step emits structured fields, consider pointing it to an alias with deterministic JSON mode in this example to guide users.

wren-ai-service/tools/config/config.full.yaml (1)

175-176: LGTM; mirrors docker example.

Placement and wiring look correct.

Optionally document in this file that sql_diagnosis benefits from an LLM/alias configured for JSON responses.

wren-ai-service/docs/config_examples/config.groq.yaml (1)

147-148: Consistent addition; confirm model supports desired output format.

Groq model wiring is fine. If sql_diagnosis relies on JSON output, add response_format: { type: json_object } to the chosen model or select an alias configured for JSON.

wren-ai-service/docs/config_examples/config.azure.yaml (1)

156-157: Clarify coexistence with sql_tables_extraction.

You’ve added sql_diagnosis while sql_tables_extraction remains defined above. If sql_diagnosis supersedes the old step in your runtime pipelines, consider removing sql_tables_extraction from example configs to avoid confusion. Otherwise, add a brief comment explaining when each is used.

wren-ai-service/src/providers/engine/wren.py (1)

89-102: Good capture of error_sql; unify correlation_id extraction and log it.

Nice addition pulling dialectSql/plannedSql into error_sql. To improve observability and consistency, extract correlation_id the same way for success and error paths and include it in the error log.

Apply this diff within execute_sql’s error return and log:

-                logger.error(f"Error executing SQL: {error_message}")
+                # include correlation id when available
+                logger.error(
+                    f"Error executing SQL: {error_message} "
+                    f"(correlation_id={res_json.get('errors', [{}])[0].get('extensions', {}).get('other', {}).get('correlationId', res_json.get('correlationId', ''))})"
                 )
@@
-                        "correlation_id": (
-                            res_json.get("errors", [{}])[0]
-                            .get("extensions", {})
-                            .get("other", {})
-                            .get("correlationId")
-                        ),
+                        "correlation_id": res_json.get("errors", [{}])[0]
+                        .get("extensions", {})
+                        .get("other", {})
+                        .get("correlationId", res_json.get("correlationId", "")),

Additionally, mirror this correlation_id fallback in the success-path returns (not shown in this hunk) so all paths use the same logic.

Outside this hunk, consider a small helper to DRY it up:

def _cid(j: dict) -> str:
    return (
        j.get("errors", [{}])[0]
         .get("extensions", {})
         .get("other", {})
         .get("correlationId")
        or j.get("correlationId", "")
        or ""
    )

Then use "correlation_id": _cid(res_json) everywhere.

Also applies to: 111-115

wren-ai-service/src/globals.py (2)

152-153: Verify intended order of sql_diagnosis in AskService.

It currently runs after sql_functions_retrieval (and after sql_correction earlier in the dict). If the intention is to diagnose before correction, move it earlier; otherwise add a short comment indicating it is a post-correction diagnostic.

Example reordering if you intended pre-correction:

-                "sql_correction": _sql_correction_pipeline,
-                "followup_sql_generation": generation.FollowUpSQLGeneration(
-                    **pipe_components["followup_sql_generation"],
-                ),
-                "sql_functions_retrieval": _sql_functions_retrieval_pipeline,
-                "sql_diagnosis": _sql_diagnosis_pipeline,
+                "sql_diagnosis": _sql_diagnosis_pipeline,
+                "sql_correction": _sql_correction_pipeline,
+                "followup_sql_generation": generation.FollowUpSQLGeneration(
+                    **pipe_components["followup_sql_generation"],
+                ),
+                "sql_functions_retrieval": _sql_functions_retrieval_pipeline,

172-173: AskFeedbackService: confirm diagnosis placement.

Same concern: sql_diagnosis comes after sql_correction. If the goal is to surface actionable diagnostics before correction, swap their order.

-                "sql_correction": _sql_correction_pipeline,
-                "sql_diagnosis": _sql_diagnosis_pipeline,
+                "sql_diagnosis": _sql_diagnosis_pipeline,
+                "sql_correction": _sql_correction_pipeline,
wren-ai-service/docs/config_examples/config.zhipu.yaml (1)

194-195: Keep examples focused: remove legacy step or document both.

You added sql_diagnosis but still list sql_tables_extraction. If only one is expected in typical setups, prune the other; otherwise annotate when to use each to prevent misconfiguration.

wren-ai-service/docs/config_examples/config.ollama.yaml (1)

146-147: Same as above—avoid dual steps unless both are required.

Consider removing sql_tables_extraction or adding a brief note clarifying why both appear and how they’re used by services.

wren-ai-service/docs/config_examples/config.anthropic.yaml (1)

143-144: Confirm sql_diagnosis placement and remove legacy step if unused.

If sql_tables_extraction is deprecated in favor of sql_diagnosis, consider removing it here to avoid confusion and unnecessary pipeline registrations. Otherwise, document why both are needed and their intended order.

wren-ai-service/src/web/v1/services/ask.py (3)

518-533: Short-circuit is fine; add a minimal log for diagnoser verdict.

A tiny debug log before break will help triage non-syntax failures observed by users.

-                        if not is_sql_syntax_issue:
-                            break
+                        if not is_sql_syntax_issue:
+                            logger.debug("sql_diagnosis: non-syntax issue detected; skipping correction")
+                            break

498-505: Don’t charge a retry when no correction is attempted.

Increment retries only when proceeding to sql_correction to preserve attempts for genuine corrections.

-                        current_sql_correction_retries += 1
+                        # increment only when a correction attempt will be made (see below)

And after confirming is_sql_syntax_issue:

-                        if not is_sql_syntax_issue:
-                            break
+                        if not is_sql_syntax_issue:
+                            break
+                        current_sql_correction_retries += 1

596-603: Surface TIME_OUT distinctly for better UX.

When prior loop breaks on TIME_OUT, error_message may be None and users only see “No relevant SQL”. Consider propagating a clearer timeout message.

-                            message=error_message or "No relevant SQL",
+                            message=error_message or "SQL validation timed out or no relevant SQL",
wren-ai-service/src/web/v1/services/ask_feedback.py (1)

201-208: Add a small debug crumb for diagnoser output.

Helps correlate user-facing failures with diagnoser decisions.

-                        sql_diagnosis_results = await self._pipelines[
+                        sql_diagnosis_results = await self._pipelines[
                             "sql_diagnosis"
                         ].run(
                             contexts=table_ddls,
                             original_sql=original_sql,
                             invalid_sql=invalid_sql,
                             error_message=error_message,
                         )
+                        logger.debug("sql_diagnosis completed for feedback path")
wren-ai-service/src/pipelines/generation/sql_correction.py (2)

33-36: Fix prompt typos and tighten wording.

Minor text issues in the instructions (e.g., “firgure”). Tighten phrasing for clarity.

-1. First, think hard about the error message, and firgure out the root cause first.
-2. Then, generate the reasoning behind the correction.
-3. Finally, generate the syntactically correct ANSI SQL query based on the reasoning to correct the error.
-4. You could try to use other methods(new functions, etc.) to rewrite the SQL query to correct the error, but you should not change the original semantics of the SQL query.
+1. Carefully analyze the error message and identify the root cause.
+2. Provide concise reasoning for the correction.
+3. Produce a syntactically correct ANSI SQL query based on that reasoning.
+4. You may use alternative methods (e.g., new functions) to correct the SQL, but do not change its original semantics.

103-108: Return type annotation mismatches actual return (trace_cost expects a tuple).

The function returns (result, generator_name) before the decorator unwraps it. Annotate accordingly to avoid confusion with type checkers.

-async def generate_sql_correction(
-    prompt: dict, generator: Any, generator_name: str
-) -> dict:
+async def generate_sql_correction(
+    prompt: dict, generator: Any, generator_name: str
+) -> tuple[dict, str]:
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (2)

27-31: Polish diagnosis instructions for clarity.

-1. First, think hard about the error message, and analyze the invalid SQL query to figure out the root cause and which part is incorrect.
-2. Then, map the incorrect part of the invalid SQL query to the corresponding part of the original SQL query.
-3. Then, return the reasoning behind the diagnosis.(You should give me the part of the original SQL query that is incorrect and the reason why it is incorrect)
-4. Also, return a boolean value to indicate whether the issue is a SQL syntax issue.
+1. Carefully analyze the error message and the invalid SQL to identify the root cause and the incorrect part.
+2. Map the incorrect part of the invalid SQL to the corresponding part of the original SQL.
+3. Provide concise reasoning for the diagnosis (include the specific part of the original SQL and why it is incorrect).
+4. Indicate whether the issue is a SQL syntax issue with a boolean flag.

78-84: Return type annotation mismatches actual return (trace_cost expects a tuple).

Align the type hint with the pre-decorator return.

-async def generate_sql_diagnosis(
-    prompt: dict, generator: Any, generator_name: str
-) -> dict:
+async def generate_sql_diagnosis(
+    prompt: dict, generator: Any, generator_name: str
+) -> tuple[dict, str]:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a207202 and 8f3c1f6.

📒 Files selected for processing (25)
  • deployment/kustomizations/base/cm.yaml (1 hunks)
  • docker/config.example.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.anthropic.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.azure.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.bedrock.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.deepseek.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.google_ai_studio.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.google_vertexai.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.grok.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.groq.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.lm_studio.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.ollama.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.open_router.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.qwen3.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.zhipu.yaml (1 hunks)
  • wren-ai-service/src/globals.py (3 hunks)
  • wren-ai-service/src/pipelines/generation/__init__.py (2 hunks)
  • wren-ai-service/src/pipelines/generation/sql_correction.py (7 hunks)
  • wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1 hunks)
  • wren-ai-service/src/pipelines/generation/utils/sql.py (3 hunks)
  • wren-ai-service/src/providers/engine/wren.py (1 hunks)
  • wren-ai-service/src/web/v1/services/ask.py (2 hunks)
  • wren-ai-service/src/web/v1/services/ask_feedback.py (1 hunks)
  • wren-ai-service/tools/config/config.example.yaml (1 hunks)
  • wren-ai-service/tools/config/config.full.yaml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-03-18T10:28:10.593Z
Learnt from: andreashimin
PR: Canner/WrenAI#1414
File: wren-ui/src/apollo/server/utils/error.ts:0-0
Timestamp: 2025-03-18T10:28:10.593Z
Learning: The typo in error code enum names ("IDENTIED_AS_GENERAL" and "IDENTIED_AS_MISLEADING_QUERY" instead of "IDENTIFIED_AS_GENERAL" and "IDENTIFIED_AS_MISLEADING_QUERY") in wren-ui/src/apollo/server/utils/error.ts was recognized but intentionally not fixed as it was considered out of scope for PR #1414.

Applied to files:

  • wren-ai-service/src/providers/engine/wren.py
🧬 Code graph analysis (6)
wren-ai-service/src/pipelines/generation/__init__.py (1)
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1)
  • SQLDiagnosis (112-152)
wren-ai-service/src/pipelines/generation/sql_correction.py (3)
wren-ai-service/src/pipelines/generation/utils/sql.py (2)
  • construct_instructions (480-489)
  • run (29-69)
wren-ai-service/src/pipelines/retrieval/sql_functions.py (1)
  • SqlFunction (20-47)
wren-ai-service/src/pipelines/generation/sql_generation.py (1)
  • run (177-219)
wren-ai-service/src/web/v1/services/ask.py (2)
wren-ai-service/src/pipelines/generation/sql_correction.py (1)
  • run (176-206)
wren-ai-service/src/pipelines/generation/sql_generation.py (1)
  • run (177-219)
wren-ai-service/src/web/v1/services/ask_feedback.py (3)
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1)
  • run (134-152)
wren-ai-service/src/pipelines/generation/sql_correction.py (1)
  • run (176-206)
wren-ai-service/src/web/v1/services/ask.py (1)
  • AskResult (49-52)
wren-ai-service/src/globals.py (1)
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1)
  • SQLDiagnosis (112-152)
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (4)
wren-ai-service/src/core/pipeline.py (1)
  • BasicPipeline (14-20)
wren-ai-service/src/core/provider.py (1)
  • LLMProvider (6-18)
wren-ai-service/src/pipelines/common.py (1)
  • clean_up_new_lines (111-112)
wren-ai-service/src/utils.py (1)
  • trace_cost (164-182)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pytest
  • GitHub Check: pytest
  • GitHub Check: Analyze (go)
🔇 Additional comments (17)
wren-ai-service/docs/config_examples/config.lm_studio.yaml (1)

146-147: sql_diagnosis added in the right spot; deps look correct

SQLDiagnosis is LLM-only, so adding it after sql_tables_extraction with just llm is appropriate. No engine/document_store needed here.

wren-ai-service/docs/config_examples/config.bedrock.yaml (1)

159-160: Bedrock config: sql_diagnosis placement and wiring look good

Consistent with other examples and the pipeline’s LLM-only requirement. Nothing else to change here.

deployment/kustomizations/base/cm.yaml (1)

214-215: Verified end-to-end wiring for sql_diagnosis: class, export, service integration, config examples, and tooling configs are all correctly updated.

wren-ai-service/src/pipelines/generation/__init__.py (1)

13-13: Public export for SQLDiagnosis is correct

Import + all entry are in line with other pipelines; no circularity concerns from the new module.

Also applies to: 32-32

wren-ai-service/docs/config_examples/config.grok.yaml (1)

148-149: Grok config: sql_diagnosis added correctly

Matches the intended pattern (after sql_tables_extraction; LLM-only). Looks good.

wren-ai-service/tools/config/config.example.yaml (1)

175-176: Approve sql_diagnosis pipe addition — verified wiring and configuration
SQLDiagnosis class is defined and exported, globals register pipe_components["sql_diagnosis"], and all config examples include the new pipe.

wren-ai-service/docs/config_examples/config.google_ai_studio.yaml (1)

152-153: Config example updated with sql_diagnosis — OK

The new pipe entry is aligned with other configs and uses the default LLM as expected.

wren-ai-service/docs/config_examples/config.google_vertexai.yaml (1)

160-161: Vertex AI config: sql_diagnosis entry is consistent

Good placement and binding to litellm_llm.default.

wren-ai-service/docs/config_examples/config.deepseek.yaml (1)

166-167: DeepSeek config: sql_diagnosis added — consistent

Matches the pattern used across configs; no issues spotted.

wren-ai-service/src/pipelines/generation/utils/sql.py (1)

168-171: ADD_QUOTES path is consistent

Here original_sql equals the raw generation_result, which matches the intended semantics.

wren-ai-service/src/globals.py (1)

82-84: Shared SQLDiagnosis instance: confirm statelessness under concurrency.

You reuse one _sql_diagnosis_pipeline across services. If any internal component keeps mutable state between runs, this can cause cross-request leakage. Confirm the pipeline is stateless/thread-safe; otherwise instantiate per service.

wren-ai-service/src/web/v1/services/ask.py (2)

433-441: Optional: cache sql_functions across retries.

You already retrieve sql_functions once; ensure it’s reused inside the retry loop without re-fetching (current code does this—LGTM).


518-548: Great integration of diagnosis-before-correction.

The diagnose-then-correct flow with is_sql_syntax_issue gating reduces futile corrections and should improve latency and quality.

wren-ai-service/src/web/v1/services/ask_feedback.py (1)

229-245: LGTM on conditional correction.

Only correcting when is_sql_syntax_issue is true is a sensible scope cut for Ask Feedback.

wren-ai-service/src/pipelines/generation/sql_correction.py (1)

60-66: Nice propagation of sql_functions through the prompt and pipeline inputs.

Conditional rendering in the template + passing through the prompt and run inputs looks correct and keeps the feature optional.

Also applies to: 89-99, 196-201

wren-ai-service/src/pipelines/generation/sql_diagnosis.py (2)

96-109: Structured output via JSON schema: good.

Using a Pydantic model to drive response_format and wiring it through the generator is solid and future-proof.

Also applies to: 112-131


134-152: No changes required
Downstream callers use sql_diagnosis_results["post_process"].get(...), confirming they expect and handle a Python dict from post_process.

Comment thread wren-ai-service/docs/config_examples/config.open_router.yaml
Comment thread wren-ai-service/src/pipelines/generation/sql_diagnosis.py
Comment thread wren-ai-service/src/pipelines/generation/utils/sql.py
Comment thread wren-ai-service/src/pipelines/generation/utils/sql.py
Comment thread wren-ai-service/src/web/v1/services/ask_feedback.py
Comment thread wren-ai-service/src/web/v1/services/ask_feedback.py
Comment thread wren-ai-service/src/web/v1/services/ask.py
Comment thread wren-ai-service/src/web/v1/services/ask.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
wren-ai-service/src/config.py (1)

39-46: Pass settings.allow_sql_diagnosis into AskService in globals.py
In wren-ai-service/src/globals.py’s AskService instantiation (around line 115), add allow_sql_diagnosis=settings.allow_sql_diagnosis so it doesn’t fall back to the service’s True default.

wren-ai-service/src/web/v1/services/ask.py (1)

569-572: Avoid None crash on next retry iteration.

If correction returns no invalid_generation_result, the next loop iteration will subscript None.

-                        failed_dry_run_result = sql_correction_results["post_process"][
-                            "invalid_generation_result"
-                        ]
+                        failed_dry_run_result = sql_correction_results["post_process"][
+                            "invalid_generation_result"
+                        ]
+                        if not failed_dry_run_result:
+                            break
♻️ Duplicate comments (4)
wren-ai-service/src/web/v1/services/ask.py (2)

505-507: Guard against missing keys in failed_dry_run_result.

Direct indexing can KeyError; fall back safely.

-                        original_sql = failed_dry_run_result["original_sql"]
-                        invalid_sql = failed_dry_run_result["sql"]
-                        error_message = failed_dry_run_result["error"]
+                        original_sql = failed_dry_run_result.get("original_sql") or failed_dry_run_result.get("sql", "")
+                        invalid_sql = failed_dry_run_result.get("sql", "")
+                        error_message = failed_dry_run_result.get("error")

544-549: Ensure non-empty sql and error in correction payload.

sql_diagnosis_reasoning can be empty/None; passing None where str is expected may break the correction pipeline.

-                            invalid_generation_result={
-                                "sql": original_sql,
-                                "error": sql_diagnosis_reasoning
-                                if allow_sql_diagnosis
-                                else error_message,
-                            },
+                            invalid_generation_result={
+                                "sql": original_sql or invalid_sql or "",
+                                "error": (sql_diagnosis_reasoning || error_message || "SQL diagnosis provided no reasoning")
+                                if allow_sql_diagnosis
+                                else (error_message || "Unknown SQL error"),
+                            },
wren-ai-service/src/web/v1/services/ask_feedback.py (2)

194-197: Prevent KeyError on missing fields from invalid_generation_result.

-                        original_sql = failed_dry_run_result["original_sql"]
-                        invalid_sql = failed_dry_run_result["sql"]
-                        error_message = failed_dry_run_result["error"]
+                        original_sql = failed_dry_run_result.get("original_sql") or failed_dry_run_result.get("sql", "")
+                        invalid_sql = failed_dry_run_result.get("sql", "")
+                        error_message = failed_dry_run_result.get("error")

222-236: Harden correction payload with safe fallbacks.

-                                invalid_generation_result={
-                                    "sql": original_sql,
-                                    "error": sql_diagnosis_reasoning
-                                    if allow_sql_diagnosis
-                                    else error_message,
-                                },
+                                invalid_generation_result={
+                                    "sql": original_sql or invalid_sql or "",
+                                    "error": (sql_diagnosis_reasoning || error_message || "SQL diagnosis provided no reasoning")
+                                    if allow_sql_diagnosis
+                                    else (error_message || "Unknown SQL error"),
+                                },
🧹 Nitpick comments (3)
wren-ai-service/src/web/v1/services/ask.py (1)

97-106: Constructor default should match Settings.default (False).

To keep behavior consistent across entry points, make allow_sql_diagnosis default False (or always pass it from Settings).

-        allow_sql_diagnosis: bool = True,
+        allow_sql_diagnosis: bool = False,
wren-ai-service/src/web/v1/services/ask_feedback.py (2)

59-66: Constructor default should match Settings.default (False).

Keep allow_sql_diagnosis default consistent across Settings/Ask/AskFeedback.

-        allow_sql_diagnosis: bool = True,
+        allow_sql_diagnosis: bool = False,

238-253: Optional: use .get() when re-reading failed correction result.

Minor resilience; avoids subscripting errors if schema changes.

-                                invalid_sql = failed_dry_run_result["sql"]
-                                error_message = failed_dry_run_result["error"]
+                                invalid_sql = failed_dry_run_result.get("sql", "")
+                                error_message = failed_dry_run_result.get("error")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8f3c1f6 and 2a8e440.

📒 Files selected for processing (4)
  • wren-ai-service/src/config.py (1 hunks)
  • wren-ai-service/src/globals.py (3 hunks)
  • wren-ai-service/src/web/v1/services/ask.py (5 hunks)
  • wren-ai-service/src/web/v1/services/ask_feedback.py (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wren-ai-service/src/globals.py
🧰 Additional context used
🧬 Code graph analysis (2)
wren-ai-service/src/web/v1/services/ask_feedback.py (4)
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1)
  • run (134-152)
wren-ai-service/src/pipelines/generation/sql_correction.py (1)
  • run (176-206)
wren-ai-service/src/pipelines/retrieval/sql_functions.py (1)
  • run (104-125)
wren-ai-service/src/web/v1/services/ask.py (1)
  • AskResult (49-52)
wren-ai-service/src/web/v1/services/ask.py (1)
wren-ai-service/src/pipelines/generation/sql_correction.py (1)
  • run (176-206)
🔇 Additional comments (8)
wren-ai-service/src/web/v1/services/ask.py (4)

115-120: Good: internal flag stored once.

The private flag mirrors the constructor parameter cleanly.


168-172: Local snapshot of flags is fine.

Capturing allow_sql_diagnosis for flow control improves readability.


521-538: Diagnosis handling: clarify None/unknown semantics.

If is_sql_syntax_issue is None (missing), the current logic breaks the loop. Confirm that “unknown” should be treated as non-syntax to skip correction; otherwise default to attempting correction.


553-553: Nice: pass sql_functions into correction.

This keeps corrections aware of available functions.

wren-ai-service/src/web/v1/services/ask_feedback.py (4)

71-73: Good: store flag.


100-102: Local snapshots are fine.


133-141: Good: function retrieval gated by flag.


205-221: Diagnosis default semantics.

You default is_sql_syntax_issue to True, then overwrite. If the key is absent (None), correction is skipped. Confirm this is intended “fail-closed” behavior.

Comment on lines 255 to 256
invalid_sql = failed_dry_run_result["sql"]
error_message = failed_dry_run_result["error"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

TIME_OUT branch: also guard against missing fields.

-                        invalid_sql = failed_dry_run_result["sql"]
-                        error_message = failed_dry_run_result["error"]
+                        invalid_sql = failed_dry_run_result.get("sql", "")
+                        error_message = failed_dry_run_result.get("error")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
invalid_sql = failed_dry_run_result["sql"]
error_message = failed_dry_run_result["error"]
invalid_sql = failed_dry_run_result.get("sql", "")
error_message = failed_dry_run_result.get("error")
🤖 Prompt for AI Agents
In wren-ai-service/src/web/v1/services/ask_feedback.py around lines 255 to 256,
the TIME_OUT branch assumes failed_dry_run_result contains "sql" and "error"
keys and can raise KeyError; change the code to safely access these fields using
dictionary .get(...) with sensible defaults (e.g., empty string or a descriptive
fallback) and/or check for key presence before using them so invalid_sql and
error_message are always defined and non-None when used further.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
wren-ai-service/src/pipelines/generation/utils/sql.py (2)

127-129: Preserve raw original SQL for diagnosis (use generation_result, not quoted_sql).

original_sql should capture the unquoted LLM output so downstream diagnosis works on the true source text.

-                            "sql": addition.get("error_sql", quoted_sql),
-                            "original_sql": quoted_sql,
+                            "sql": addition.get("error_sql", quoted_sql),
+                            "original_sql": generation_result,

157-159: Same: keep unmodified original SQL in PREVIEW error path.

Mirror the change here so preview errors also retain the raw input.

-                            "sql": addition.get("error_sql", quoted_sql),
-                            "original_sql": quoted_sql,
+                            "sql": addition.get("error_sql", quoted_sql),
+                            "original_sql": generation_result,
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1)

93-98: post_process: fix return type and harden parsing with schema validation.

  • Annotated as -> str but returns a parsed object.
  • Accessing replies[0] without checks may raise.
    Use the Pydantic schema to validate.
-@observe(capture_input=False)
-async def post_process(
-    generate_sql_diagnosis: dict,
-) -> str:
-    return orjson.loads(generate_sql_diagnosis.get("replies")[0])
+@observe(capture_input=False)
+async def post_process(
+    generate_sql_diagnosis: dict,
+) -> dict:
+    replies = generate_sql_diagnosis.get("replies") or []
+    if not replies:
+        raise ValueError("SQLDiagnosis: generator returned no replies")
+    try:
+        return SqlDiagnosisResult.model_validate_json(replies[0]).model_dump()
+    except Exception as e:
+        logger.exception("SQLDiagnosis: failed to parse JSON reply: %s", e)
+        raise
wren-ai-service/src/web/v1/services/ask.py (2)

505-507: Guard against missing keys in failed_dry_run_result.

Upstream may omit original_sql; avoid KeyError and ensure sensible fallbacks.

-                        original_sql = failed_dry_run_result["original_sql"]
-                        invalid_sql = failed_dry_run_result["sql"]
-                        error_message = failed_dry_run_result["error"]
+                        original_sql = failed_dry_run_result.get("original_sql") or failed_dry_run_result.get("sql", "")
+                        invalid_sql = failed_dry_run_result.get("sql", "")
+                        error_message = failed_dry_run_result.get("error")

545-550: Harden correction payload: ensure non-empty sql and error message.

Fallback to invalid_sql and original error when diagnosis is disabled or empty.

-                            invalid_generation_result={
-                                "sql": original_sql,
-                                "error": sql_diagnosis_reasoning
-                                if allow_sql_diagnosis
-                                else error_message,
-                            },
+                            invalid_generation_result={
+                                "sql": original_sql or invalid_sql,
+                                "error": (sql_diagnosis_reasoning or error_message) if allow_sql_diagnosis else (error_message or "SQL diagnosis unavailable"),
+                            },
🧹 Nitpick comments (5)
wren-ai-service/src/pipelines/generation/utils/sql.py (3)

71-79: Fix return type annotation of _classify_generation_result.

The function returns a 2-tuple, but the annotation says Dict[str, str]. Update to a precise tuple type to avoid misleading callers and static analysis tools.

-    ) -> Dict[str, str]:
+    ) -> tuple[dict, dict]:

41-46: Be robust when detecting JSON-wrapped replies.

Relying on startswith("{") can misclassify content with leading whitespace. Prefer a try/except parse.

-            if cleaned_generation_result.startswith("{"):
-                cleaned_generation_result = orjson.loads(cleaned_generation_result)[
-                    "sql"
-                ]
+            try:
+                parsed = orjson.loads(cleaned_generation_result)
+                if isinstance(parsed, dict) and "sql" in parsed:
+                    cleaned_generation_result = parsed["sql"]
+            except orjson.JSONDecodeError:
+                pass

233-235: Nit: fix typo in RULES string.

“table/columnalias” → “table/column alias”.

- - ONLY USE table/column alias in the final SELECT clause; don't use table/columnalias in the other clauses.
+ - ONLY USE table/column alias in the final SELECT clause; don't use table/column alias in the other clauses.
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1)

85-91: Return type annotation does not match actual return.

Function returns (result, generator_name) for trace_cost, but annotation says dict. Align the signature.

-async def generate_sql_diagnosis(
-    prompt: dict, generator: Any, generator_name: str
-) -> dict:
+async def generate_sql_diagnosis(
+    prompt: dict, generator: Any, generator_name: str
+) -> tuple[dict, str]:
wren-ai-service/src/web/v1/services/ask.py (1)

521-539: Optional: guard diagnosis outputs.

If the diagnosis pipeline returns an empty object, .get(...) is fine; consider defaulting can_be_corrected to True to avoid prematurely breaking out. Not blocking.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc8e0a and 1dc9283.

📒 Files selected for processing (6)
  • wren-ai-service/src/config.py (1 hunks)
  • wren-ai-service/src/pipelines/generation/sql_correction.py (5 hunks)
  • wren-ai-service/src/pipelines/generation/sql_diagnosis.py (1 hunks)
  • wren-ai-service/src/pipelines/generation/utils/sql.py (3 hunks)
  • wren-ai-service/src/web/v1/services/ask.py (5 hunks)
  • wren-ai-service/src/web/v1/services/ask_feedback.py (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • wren-ai-service/src/config.py
  • wren-ai-service/src/pipelines/generation/sql_correction.py
  • wren-ai-service/src/web/v1/services/ask_feedback.py
🧰 Additional context used
🧬 Code graph analysis (3)
wren-ai-service/src/web/v1/services/ask.py (2)
wren-ai-service/src/pipelines/generation/sql_correction.py (1)
  • run (157-187)
wren-ai-service/src/pipelines/generation/utils/sql.py (1)
  • run (29-69)
wren-ai-service/src/pipelines/generation/utils/sql.py (1)
wren-ai-service/src/providers/engine/wren.py (3)
  • execute_sql (26-123)
  • execute_sql (143-191)
  • execute_sql (262-312)
wren-ai-service/src/pipelines/generation/sql_diagnosis.py (5)
wren-ai-service/src/core/pipeline.py (1)
  • BasicPipeline (14-20)
wren-ai-service/src/core/provider.py (1)
  • LLMProvider (6-18)
wren-ai-service/src/pipelines/common.py (1)
  • clean_up_new_lines (111-112)
wren-ai-service/src/utils.py (1)
  • trace_cost (164-182)
wren-ai-service/src/pipelines/generation/sql_correction.py (3)
  • prompt (81-96)
  • run (157-187)
  • post_process (108-122)
🔇 Additional comments (2)
wren-ai-service/src/web/v1/services/ask.py (2)

104-119: New allow_sql_diagnosis flag wiring looks good.

Constructor and instance wiring are consistent with existing flags.


170-171: Localizing allow_sql_diagnosis looks good.

Using the instance-level flag is consistent with other toggles.

@cyyeh
cyyeh merged commit 224655f into main Sep 5, 2025
12 checks passed
@cyyeh
cyyeh deleted the chore/ai-service/improve-text2sql branch September 5, 2025 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants