"""One bounded corrective request based solely on retrieval evidence.""" import json from tools.answers.answer_format import parse_answer, Answer, Claim from tools.answers.context_policy import answer_context_issues from tools.answers.render_answer import render_graph_answer def generate_checked_answer(question: str, context: dict, prompt: str, complete) -> dict: # Candidate provenance is used by the guard, but is not part of a Claim. # Keep the model's selection shape identical to the actual output schema. sent = { **context, "answer_candidates": [ {k: v for k, v in row.items() if k in Claim.model_fields} for row in context.get("answer_candidates", []) ], } aggregation = context.get("aggregation") if aggregation is not None: sent["aggregation"] = { k: v for k, v in aggregation.items() if k in {"count", "count_domain", "people", "complete"} } policy = "\nDo claims nevkladaj source_urls ani evidence_documents; source_urls patrí iba na vrchnú úroveň odpovede." if ( aggregation and aggregation.get("complete") is True and type(aggregation.get("count")) is int ): policy += ( "\nÚplná overená agregácia tohto dotazu má count=" + str(aggregation["count"]) + ". Pri status=ok zachovaj tento count; počet dodaných facts, claims ani answer_candidates ho nemení." ) messages = [ {"role": "system", "content": prompt + policy}, { "role": "user", "content": json.dumps( {"question": question, "graph_context": sent}, ensure_ascii=False ), }, ] result = {"attempts": [], "accepted_for_delivery": False} for number in range(2): record = {} text = "" try: response = complete(messages) result["response"] = response record["response"] = response text = response["choices"][0]["message"]["content"].strip() except Exception as error: result["error"] = type(error).__name__ result["reason"] = "model_unavailable" result["attempts"].append(record) return result result["attempts"].append(record) try: answer, normalized = parse_answer(text) record["answer"] = answer record["format_normalized"] = normalized except (ValueError, TypeError) as error: record["format_error"] = type(error).__name__ if number == 1: result["error"] = "InvalidAnswerFormat: two invalid JSON/schema responses" return result feedback = ( "Vráť jediný platný JSON objekt podľa schémy, bez zmeny faktov z pôvodného kontextu. Schéma: " + json.dumps(Answer.model_json_schema(), ensure_ascii=False) ) else: issues = answer_context_issues(answer, context, check_text=False) record["context_issues"] = issues result["answer"] = answer if not issues: rendered = render_graph_answer(answer, context) delivery_issues = answer_context_issues(rendered, context) if delivery_issues: issues = delivery_issues record["context_issues"] = issues else: record["rendered_answer"] = rendered result["model_answer"] = answer result["answer"] = rendered result["accepted_for_delivery"] = True return result if number == 1: result["context_rejected"] = True return result feedback = ( "Odpoveď porušila pravidlá dodaného kontextu: " + ", ".join(issues) + ". " "Oprav jediný JSON objekt výhradne z pôvodných podkladov. Použi iba source_urls zo sources. " "Typ práce nie je keyword. answer_candidates dokladajú spojenie požadovaného názvu alebo roku a tagu cez tú istú osobu. " "Answer ponechaj prázdny; text aj upozornenie zostaví aplikácia." ) messages += [{"role": "assistant", "content": text}, {"role": "user", "content": feedback}] return result