| """Conservative, exact-match-safe final answer formatting."""
|
|
|
| from __future__ import annotations
|
|
|
| import re
|
| import unicodedata
|
| from decimal import Decimal, InvalidOperation
|
|
|
| _PREFIX = re.compile(
|
| r"^\s*(?:final\s+answer|answer|submitted\s+answer)\s*:\s*", re.IGNORECASE
|
| )
|
|
|
|
|
| def format_answer(value: object) -> str:
|
| """Remove presentation noise without changing answer semantics or case."""
|
| text = unicodedata.normalize("NFC", str(value or ""))
|
| text = text.replace("\r\n", "\n").replace("\r", "\n").strip()
|
| had_prefix = bool(_PREFIX.match(text))
|
| text = _PREFIX.sub("", text).strip()
|
| if text.startswith("```") and text.endswith("```"):
|
| lines = text.splitlines()
|
| if len(lines) >= 3:
|
| text = "\n".join(lines[1:-1]).strip()
|
| if len(text) >= 2 and text[0] == text[-1] and text[0] in {'"', "'", "`"}:
|
| text = text[1:-1].strip()
|
| text = re.split(
|
| r"\n+(?:explanation|reasoning|evidence|source)s?\s*:",
|
| text,
|
| maxsplit=1,
|
| flags=re.IGNORECASE,
|
| )[0]
|
| if had_prefix and "\n" in text:
|
| text = next((line.strip() for line in text.splitlines() if line.strip()), "")
|
| if had_prefix:
|
| text = re.split(
|
| r"\s+(?:because|since)\s+", text, maxsplit=1, flags=re.IGNORECASE
|
| )[0].strip()
|
|
|
|
|
| text = re.sub(r"\s+", " ", text).strip()
|
| if not text:
|
| raise ValueError("Agent returned an empty answer")
|
| return text
|
|
|
|
|
| def apply_requested_format(question: str, answer: object) -> str:
|
| """Apply only explicit output-format constraints from the question."""
|
| text = format_answer(answer)
|
| lowered = question.lower()
|
| if "usd" in lowered and "two decimal" in lowered:
|
| numeric = re.sub(r"[^0-9.\-]", "", text)
|
| try:
|
| return f"${Decimal(numeric):,.2f}"
|
| except InvalidOperation:
|
| return text
|
| if "ascending order" in lowered and (
|
| "comma-delimited" in lowered or "comma separated" in lowered
|
| ):
|
| values = re.findall(r"-?\d+(?:\.\d+)?", text)
|
| if values:
|
| values.sort(key=Decimal)
|
| return ", ".join(values)
|
| if "alphabet" in lowered and ("comma" in lowered or "list" in lowered):
|
| values = [item.strip() for item in text.split(",") if item.strip()]
|
| if len(values) > 1:
|
| return ", ".join(sorted(values, key=str.casefold))
|
| return text
|
|
|