@@ -94,16 +94,55 @@ def _normalize_session_state(
9494def _normalize_turns (
9595 turns : list [TraceResponse | dict [str , Any ]],
9696) -> list [dict [str , Any ]]:
97- """Coerce a list of scoring responses / dicts to the rollup turn shape."""
97+ """Coerce a list of scoring responses / dicts to the rollup turn shape.
98+
99+ The rollup handler expects ``RollupTurnInput`` with fields
100+ ``scores``, ``risk_band``, ``file_attribution``, ``session_signals``,
101+ ``recommendation``, ``timestamp`` — NOT the flat ``TraceResponse``
102+ fields like ``score`` / ``band`` / ``success``.
103+ """
98104 out : list [dict [str , Any ]] = []
99105 for turn in turns :
100106 if isinstance (turn , TraceResponse ):
101- out .append (turn .model_dump (exclude_none = True ))
107+ d = turn .model_dump (exclude_none = True )
108+ out .append (_trace_response_to_rollup_turn (d ))
109+ elif isinstance (turn , dict ):
110+ if "scores" in turn or "risk_band" in turn :
111+ out .append (turn )
112+ else :
113+ out .append (_trace_response_to_rollup_turn (turn ))
102114 else :
103115 out .append (turn )
104116 return out
105117
106118
119+ def _trace_response_to_rollup_turn (d : dict [str , Any ]) -> dict [str , Any ]:
120+ """Map flat TraceResponse dict to the RollupTurnInput shape."""
121+ turn : dict [str , Any ] = {}
122+
123+ scores : dict [str , float | None ] = {}
124+ if "score" in d and d ["score" ] is not None :
125+ metric = d .get ("primary_metric" , "groundedness_v2" )
126+ scores [metric ] = d ["score" ]
127+ if "context_coverage_ratio" in d :
128+ scores ["context_coverage_ratio" ] = d ["context_coverage_ratio" ]
129+ if "context_usage_ratio" in d :
130+ scores ["context_usage_ratio" ] = d ["context_usage_ratio" ]
131+ if "nli_aggregate" in d :
132+ scores ["nli_aggregate" ] = d ["nli_aggregate" ]
133+ if scores :
134+ turn ["scores" ] = scores
135+
136+ if "band" in d :
137+ turn ["risk_band" ] = d ["band" ]
138+
139+ for passthrough in ("file_attribution" , "session_signals" , "recommendation" , "timestamp" ):
140+ if passthrough in d and d [passthrough ] is not None :
141+ turn [passthrough ] = d [passthrough ]
142+
143+ return turn
144+
145+
107146def _require_premise_lane (
108147 * ,
109148 raw_context : str | None ,
0 commit comments