File size: 1,607 Bytes
942050b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""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:
            # Either we never executed, or execution failed and there's no
            # result payload. Surface a clear sentence so the user UI never
            # sees "format=null".
            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