| """Node: deterministic format picker (no LLM). |
| |
| Per arch v2 §3 / §8 / picker.py, the chart-or-not decision is pure Python |
| heuristics on the result shape. The LLM never emits Vega-Lite. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from collections.abc import Callable |
|
|
| from nl_sql.agent.state import PipelineState |
| from nl_sql.render.formats import Sentence |
| from nl_sql.render.picker import pick_format |
|
|
|
|
| def make_format_node() -> Callable[[PipelineState], PipelineState]: |
| def node(state: PipelineState) -> PipelineState: |
| outcome = state.get("outcome") |
| trace = list(state.get("trace") or []) |
|
|
| if outcome is None or outcome.result is None: |
| |
| |
| |
| error_msg = state.get("error_message") or ( |
| outcome.error_message if outcome else "no result available" |
| ) |
| placeholder = Sentence(text=f"could not produce a result: {error_msg}") |
| trace.append({"node": "deterministic_format", "shape": "error_sentence"}) |
| return {"output_format": placeholder, "trace": trace} |
|
|
| result = outcome.result |
| formatted = pick_format(result.columns, result.rows) |
| trace.append( |
| { |
| "node": "deterministic_format", |
| "shape": type(formatted).__name__, |
| "row_count": result.row_count, |
| } |
| ) |
| return {"output_format": formatted, "trace": trace} |
|
|
| return node |
|
|