# -*- coding: utf-8 -*- """ User session / profile management for the Tax Torpedo Analyzer. Minimal profile with just the 3 inputs needed for torpedo analysis. """ from __future__ import annotations from dataclasses import dataclass from typing import Optional @dataclass class UserProfile: """Minimal financial profile for the Tax Torpedo Analyzer.""" filing_status: str = "MFJ" ssb_annual: float = 0.0 other_income: float = 0.0 # Computed (cached after analysis) tax_zone: Optional[str] = None zero_point: Optional[float] = None # analyst convention (ref. TI) confluence_point: Optional[float] = None # analyst convention (ref. TI) zero_point_oi: Optional[float] = None # raw other income value confluence_point_oi: Optional[float] = None # raw other income value ref_taxable_income: Optional[float] = None def to_dict(self) -> dict: return { "filing_status": self.filing_status, "ssb_annual": self.ssb_annual, "other_income": self.other_income, "tax_zone": self.tax_zone, "zero_point": self.zero_point, "confluence_point": self.confluence_point, "zero_point_oi": self.zero_point_oi, "confluence_point_oi": self.confluence_point_oi, "ref_taxable_income": self.ref_taxable_income, } @classmethod def from_dict(cls, d: dict) -> "UserProfile": if not d: return cls() return cls( filing_status=d.get("filing_status", "MFJ"), ssb_annual=d.get("ssb_annual", 0.0), other_income=d.get("other_income", 0.0), tax_zone=d.get("tax_zone"), zero_point=d.get("zero_point"), confluence_point=d.get("confluence_point"), zero_point_oi=d.get("zero_point_oi"), confluence_point_oi=d.get("confluence_point_oi"), ref_taxable_income=d.get("ref_taxable_income"), ) def summary_text(self) -> str: """Human-readable summary for system prompt context.""" lines = [ f"Filing Status: {self.filing_status_display(self.filing_status)}", f"Annual Social Security Benefit: ${self.ssb_annual:,.0f}", f"Total Other Taxable Income: ${self.other_income:,.0f}", ] if self.tax_zone: lines.append(f"Tax Zone: {self.tax_zone}") if self.zero_point is not None: lines.append(f"Zero Point (ref. taxable income): ${self.zero_point:,.0f}") if self.confluence_point is not None: lines.append(f"Confluence Point (ref. taxable income): ${self.confluence_point:,.0f}") if self.zero_point_oi is not None: lines.append(f"Zero Point (other income): ${self.zero_point_oi:,.0f}") if self.confluence_point_oi is not None: lines.append(f"Confluence Point (other income): ${self.confluence_point_oi:,.0f}") return "\n".join(lines) @staticmethod def filing_status_display(code: str) -> str: mapping = { "SGL": "Single", "MFJ": "Married Filing Jointly", "HOH": "Head of Household", "MFS": "Married Filing Separately", } return mapping.get(code, code)