diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc index 353b069..863edce 100644 Binary files a/app/__pycache__/__init__.cpython-313.pyc and b/app/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/__pycache__/state.cpython-313.pyc b/app/__pycache__/state.cpython-313.pyc index cde691b..36f42cb 100644 Binary files a/app/__pycache__/state.cpython-313.pyc and b/app/__pycache__/state.cpython-313.pyc differ diff --git a/app/agents/__pycache__/contas_prompting.cpython-313.pyc b/app/agents/__pycache__/contas_prompting.cpython-313.pyc index 4564ff1..c2b649f 100644 Binary files a/app/agents/__pycache__/contas_prompting.cpython-313.pyc and b/app/agents/__pycache__/contas_prompting.cpython-313.pyc differ diff --git a/app/agents/__pycache__/contestacao_agent.cpython-313.pyc b/app/agents/__pycache__/contestacao_agent.cpython-313.pyc index 323e37f..ec3453a 100644 Binary files a/app/agents/__pycache__/contestacao_agent.cpython-313.pyc and b/app/agents/__pycache__/contestacao_agent.cpython-313.pyc differ diff --git a/app/agents/__pycache__/faturas_agent.cpython-313.pyc b/app/agents/__pycache__/faturas_agent.cpython-313.pyc index d286ead..5281f39 100644 Binary files a/app/agents/__pycache__/faturas_agent.cpython-313.pyc and b/app/agents/__pycache__/faturas_agent.cpython-313.pyc differ diff --git a/app/agents/__pycache__/prompting.cpython-313.pyc b/app/agents/__pycache__/prompting.cpython-313.pyc index 5edca05..95e7532 100644 Binary files a/app/agents/__pycache__/prompting.cpython-313.pyc and b/app/agents/__pycache__/prompting.cpython-313.pyc differ diff --git a/app/agents/__pycache__/runtime.cpython-313.pyc b/app/agents/__pycache__/runtime.cpython-313.pyc index ecdf114..76e1ef6 100644 Binary files a/app/agents/__pycache__/runtime.cpython-313.pyc and b/app/agents/__pycache__/runtime.cpython-313.pyc differ diff --git a/app/agents/__pycache__/suporte_contas_agent.cpython-313.pyc b/app/agents/__pycache__/suporte_contas_agent.cpython-313.pyc index 1fac5d1..2df8e81 100644 Binary files a/app/agents/__pycache__/suporte_contas_agent.cpython-313.pyc and b/app/agents/__pycache__/suporte_contas_agent.cpython-313.pyc differ diff --git a/app/agents/__pycache__/vas_agent.cpython-313.pyc b/app/agents/__pycache__/vas_agent.cpython-313.pyc index 1058b1d..d766142 100644 Binary files a/app/agents/__pycache__/vas_agent.cpython-313.pyc and b/app/agents/__pycache__/vas_agent.cpython-313.pyc differ diff --git a/app/domain/__pycache__/__init__.cpython-313.pyc b/app/domain/__pycache__/__init__.cpython-313.pyc index 896417b..6655eef 100644 Binary files a/app/domain/__pycache__/__init__.cpython-313.pyc and b/app/domain/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/__init__.cpython-313.pyc b/app/domain/contas/__pycache__/__init__.cpython-313.pyc index aeb1751..e00bc5f 100644 Binary files a/app/domain/contas/__pycache__/__init__.cpython-313.pyc and b/app/domain/contas/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/client.cpython-313.pyc b/app/domain/contas/__pycache__/client.cpython-313.pyc index db52de9..6e9e342 100644 Binary files a/app/domain/contas/__pycache__/client.cpython-313.pyc and b/app/domain/contas/__pycache__/client.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/contestation_rules.cpython-313.pyc b/app/domain/contas/__pycache__/contestation_rules.cpython-313.pyc index 49a7c5c..ead826e 100644 Binary files a/app/domain/contas/__pycache__/contestation_rules.cpython-313.pyc and b/app/domain/contas/__pycache__/contestation_rules.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/contestation_validation.cpython-313.pyc b/app/domain/contas/__pycache__/contestation_validation.cpython-313.pyc new file mode 100644 index 0000000..24f9bb8 Binary files /dev/null and b/app/domain/contas/__pycache__/contestation_validation.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/ic_tags.cpython-313.pyc b/app/domain/contas/__pycache__/ic_tags.cpython-313.pyc index 1506260..ca9110a 100644 Binary files a/app/domain/contas/__pycache__/ic_tags.cpython-313.pyc and b/app/domain/contas/__pycache__/ic_tags.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/informational_context.cpython-313.pyc b/app/domain/contas/__pycache__/informational_context.cpython-313.pyc index 6e1429a..de25caa 100644 Binary files a/app/domain/contas/__pycache__/informational_context.cpython-313.pyc and b/app/domain/contas/__pycache__/informational_context.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/invoice_context.cpython-313.pyc b/app/domain/contas/__pycache__/invoice_context.cpython-313.pyc index 72bdaf6..dd72002 100644 Binary files a/app/domain/contas/__pycache__/invoice_context.cpython-313.pyc and b/app/domain/contas/__pycache__/invoice_context.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/invoice_models.cpython-313.pyc b/app/domain/contas/__pycache__/invoice_models.cpython-313.pyc index 37bb05a..f63db7c 100644 Binary files a/app/domain/contas/__pycache__/invoice_models.cpython-313.pyc and b/app/domain/contas/__pycache__/invoice_models.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/invoice_resolver.cpython-313.pyc b/app/domain/contas/__pycache__/invoice_resolver.cpython-313.pyc index 66df3d0..0a795bb 100644 Binary files a/app/domain/contas/__pycache__/invoice_resolver.cpython-313.pyc and b/app/domain/contas/__pycache__/invoice_resolver.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/item_matcher.cpython-313.pyc b/app/domain/contas/__pycache__/item_matcher.cpython-313.pyc index 8257e58..4761afd 100644 Binary files a/app/domain/contas/__pycache__/item_matcher.cpython-313.pyc and b/app/domain/contas/__pycache__/item_matcher.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/pro_rata_rules.cpython-313.pyc b/app/domain/contas/__pycache__/pro_rata_rules.cpython-313.pyc index 6130d1d..d6209aa 100644 Binary files a/app/domain/contas/__pycache__/pro_rata_rules.cpython-313.pyc and b/app/domain/contas/__pycache__/pro_rata_rules.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/protocol_triplets.cpython-313.pyc b/app/domain/contas/__pycache__/protocol_triplets.cpython-313.pyc index f166a90..dfd4640 100644 Binary files a/app/domain/contas/__pycache__/protocol_triplets.cpython-313.pyc and b/app/domain/contas/__pycache__/protocol_triplets.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/rct_policy.cpython-313.pyc b/app/domain/contas/__pycache__/rct_policy.cpython-313.pyc index 7d7ad48..7c4a6fe 100644 Binary files a/app/domain/contas/__pycache__/rct_policy.cpython-313.pyc and b/app/domain/contas/__pycache__/rct_policy.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/service.cpython-313.pyc b/app/domain/contas/__pycache__/service.cpython-313.pyc index ea11392..e39a045 100644 Binary files a/app/domain/contas/__pycache__/service.cpython-313.pyc and b/app/domain/contas/__pycache__/service.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/string_metrics.cpython-313.pyc b/app/domain/contas/__pycache__/string_metrics.cpython-313.pyc index e9af98e..51c85f3 100644 Binary files a/app/domain/contas/__pycache__/string_metrics.cpython-313.pyc and b/app/domain/contas/__pycache__/string_metrics.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/vas_cancellation_message.cpython-313.pyc b/app/domain/contas/__pycache__/vas_cancellation_message.cpython-313.pyc index 62ef395..4127fad 100644 Binary files a/app/domain/contas/__pycache__/vas_cancellation_message.cpython-313.pyc and b/app/domain/contas/__pycache__/vas_cancellation_message.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/vas_variation.cpython-313.pyc b/app/domain/contas/__pycache__/vas_variation.cpython-313.pyc index a5536d0..bdb4c3f 100644 Binary files a/app/domain/contas/__pycache__/vas_variation.cpython-313.pyc and b/app/domain/contas/__pycache__/vas_variation.cpython-313.pyc differ diff --git a/app/domain/contas/__pycache__/workflow_actions.cpython-313.pyc b/app/domain/contas/__pycache__/workflow_actions.cpython-313.pyc index e5c598b..1bb3682 100644 Binary files a/app/domain/contas/__pycache__/workflow_actions.cpython-313.pyc and b/app/domain/contas/__pycache__/workflow_actions.cpython-313.pyc differ diff --git a/app/domain/contas/integrations/__pycache__/secure_pdf_crypto.cpython-313.pyc b/app/domain/contas/integrations/__pycache__/secure_pdf_crypto.cpython-313.pyc index 4705a2a..bd34556 100644 Binary files a/app/domain/contas/integrations/__pycache__/secure_pdf_crypto.cpython-313.pyc and b/app/domain/contas/integrations/__pycache__/secure_pdf_crypto.cpython-313.pyc differ diff --git a/app/domain/contas/invoice_context.py b/app/domain/contas/invoice_context.py index 2f5c802..282d6db 100644 --- a/app/domain/contas/invoice_context.py +++ b/app/domain/contas/invoice_context.py @@ -19,6 +19,10 @@ class InvoiceContext: complete_invoices: dict[str, Any] | None = None billing_analysis: dict[str, Any] | None = None invoice_detail: Any = None + invoice_amount: str = "" + invoice_amount_open: str = "" + invoice_period: str = "" + invoice_emissao: str = "" customer_id: str = "" error: str | None = None cache_hit: bool = False @@ -33,6 +37,10 @@ class InvoiceContext: "complete_invoices_payload": self.complete_invoices, "billing_analysis": self.billing_analysis, "invoice_detail": self.invoice_detail, + "invoice_amount": self.invoice_amount, + "invoice_amount_open": self.invoice_amount_open, + "invoice_period": self.invoice_period, + "invoice_emissao": self.invoice_emissao, "customer_id": self.customer_id, "invoice_context_error": self.error, "invoice_context_cache_hit": self.cache_hit, @@ -42,6 +50,55 @@ class InvoiceContext: } +def extract_invoice_summary_context(detail: Any) -> dict[str, str]: + """Extrai o resumo semântico da fatura detalhada. + + Mantém a paridade com o prefetch do Contas original: ``bill_pdf`` devolve + um envelope com ``parsed_content`` e o parser coloca o total em + ``total_geral``. Workflows e agentes não precisam conhecer a estrutura do + PDF para consumir ``invoice_amount``/``invoice_amount_open``. + """ + parsed = detail + if isinstance(detail, dict) and isinstance(detail.get("parsed_content"), dict): + parsed = detail["parsed_content"] + if not isinstance(parsed, dict): + return {} + + resumo = parsed.get("Fatura Resumo") + if not isinstance(resumo, list): + resumo = [] + + invoice_period = "" + invoice_emissao = "" + invoice_amount = "" + parsed_total = parsed.get("total_geral") + if parsed_total is not None and str(parsed_total).strip(): + invoice_amount = str(parsed_total).strip() + + for item in resumo: + if not isinstance(item, dict): + continue + desc = str(item.get("desc", "") or "").strip().casefold() + if desc in {"período", "periodo"}: + invoice_period = str(item.get("period", "") or "").strip() + elif desc in {"emissão", "emissao"}: + invoice_emissao = str(item.get("emissao", "") or "").strip() + if not invoice_amount and bool(item.get("is_total")) and str(item.get("value", "")).strip(): + invoice_amount = str(item.get("value", "")).strip() + if not invoice_amount and "total" in desc and str(item.get("value", "")).strip(): + invoice_amount = str(item.get("value", "")).strip() + + context: dict[str, str] = {} + if invoice_period: + context["invoice_period"] = invoice_period + if invoice_emissao: + context["invoice_emissao"] = invoice_emissao + if invoice_amount: + context["invoice_amount"] = invoice_amount + context["invoice_amount_open"] = invoice_amount + return context + + class InvoiceContextService: """Session-scoped invoice prefetch backed by the framework cache. @@ -155,6 +212,7 @@ class InvoiceContextService: detail = None detail_ms = 0.0 + summary: dict[str, str] = {} if include_detail and resolved_invoice_id: detail, detail_error, detail_ms = await self._timed_to_thread( "invoice_detail", self.client.bill_pdf, msisdn, resolved_invoice_id, customer_id, @@ -163,6 +221,8 @@ class InvoiceContextService: if detail_error: errors["invoice_detail"] = detail_error error_parts.append(f"invoice_detail: {detail_error}") + else: + summary = extract_invoice_summary_context(detail) metadata = { "cache_hit": False, @@ -177,7 +237,12 @@ class InvoiceContextService: msisdn=msisdn, invoice_id=resolved_invoice_id, complete_invoices=complete if isinstance(complete, dict) else None, billing_analysis=billing if isinstance(billing, dict) else None, - invoice_detail=detail, customer_id=customer_id, + invoice_detail=detail, + invoice_amount=summary.get("invoice_amount", ""), + invoice_amount_open=summary.get("invoice_amount_open", ""), + invoice_period=summary.get("invoice_period", ""), + invoice_emissao=summary.get("invoice_emissao", ""), + customer_id=customer_id, error="; ".join(error_parts) or None, cache_hit=False, business_events=events, errors=errors, metadata=metadata, ) @@ -219,7 +284,10 @@ class InvoiceContextService: await self.cache.set(key, { "msisdn": ctx.msisdn, "invoice_id": ctx.invoice_id, "complete_invoices": ctx.complete_invoices, "billing_analysis": ctx.billing_analysis, - "invoice_detail": ctx.invoice_detail, "customer_id": ctx.customer_id, + "invoice_detail": ctx.invoice_detail, + "invoice_amount": ctx.invoice_amount, "invoice_amount_open": ctx.invoice_amount_open, + "invoice_period": ctx.invoice_period, "invoice_emissao": ctx.invoice_emissao, + "customer_id": ctx.customer_id, "error": ctx.error, "cache_hit": False, "errors": dict(ctx.errors or {}), "metadata": dict(ctx.metadata or {}), "_fetched_at": time.time(), diff --git a/app/domain/contas/parsers/__pycache__/__init__.cpython-313.pyc b/app/domain/contas/parsers/__pycache__/__init__.cpython-313.pyc index 784b895..e003ed3 100644 Binary files a/app/domain/contas/parsers/__pycache__/__init__.cpython-313.pyc and b/app/domain/contas/parsers/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/domain/contas/parsers/__pycache__/bill_parser.cpython-313.pyc b/app/domain/contas/parsers/__pycache__/bill_parser.cpython-313.pyc index ba3be40..51b16a6 100644 Binary files a/app/domain/contas/parsers/__pycache__/bill_parser.cpython-313.pyc and b/app/domain/contas/parsers/__pycache__/bill_parser.cpython-313.pyc differ diff --git a/app/domain/contas/parsers/__pycache__/bill_processor.cpython-313.pyc b/app/domain/contas/parsers/__pycache__/bill_processor.cpython-313.pyc index 513d719..d39ca44 100644 Binary files a/app/domain/contas/parsers/__pycache__/bill_processor.cpython-313.pyc and b/app/domain/contas/parsers/__pycache__/bill_processor.cpython-313.pyc differ diff --git a/app/domain/contas/service.py b/app/domain/contas/service.py index c364b95..38ab459 100644 --- a/app/domain/contas/service.py +++ b/app/domain/contas/service.py @@ -36,8 +36,29 @@ class ContasDomainService: partial = [p for p in products if needle in str(p.get("name") or p.get("description") or "").lower() or str(p.get("name") or p.get("description") or "").lower() in needle] return partial[0] if partial else None - def consultar_faturas(self, *, msisdn: str, **_: Any) -> Any: - return self.client.consultar_faturas(msisdn) + def consultar_faturas(self, *, msisdn: str, **args: Any) -> Any: + """Consulta faturas e expõe o resumo semântico quando pré-carregado. + + A fonte de ``invoice_amount`` continua sendo a fatura detalhada (Bill PDF), + como no Contas original. O MCP apenas apresenta esse dado junto do retorno + de Complete Invoices; não altera o contrato do backend TIM nem inventa valor. + """ + complete = args.get("complete_invoices_payload") + if not isinstance(complete, dict): + complete = self.client.consultar_faturas(msisdn) + if not isinstance(complete, dict): + return complete + + result = dict(complete) + for key in ("invoice_amount", "invoice_amount_open", "invoice_period", "invoice_emissao"): + value = args.get(key) + if value not in (None, ""): + result[key] = value + if args.get("invoice_id") not in (None, ""): + result.setdefault("invoice_id", args.get("invoice_id")) + if args.get("customer_id") not in (None, ""): + result.setdefault("customer_id", args.get("customer_id")) + return result def consultar_plano(self, *, msisdn: str, **args: Any) -> dict[str, Any]: """Retorna somente os planos presentes na evidência de billing analysis. diff --git a/app/extensions/__pycache__/__init__.cpython-313.pyc b/app/extensions/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..f5836e5 Binary files /dev/null and b/app/extensions/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/extensions/__pycache__/tim_guardrails.cpython-313.pyc b/app/extensions/__pycache__/tim_guardrails.cpython-313.pyc new file mode 100644 index 0000000..8766e70 Binary files /dev/null and b/app/extensions/__pycache__/tim_guardrails.cpython-313.pyc differ diff --git a/app/extensions/__pycache__/tim_judges.cpython-313.pyc b/app/extensions/__pycache__/tim_judges.cpython-313.pyc new file mode 100644 index 0000000..62d813e Binary files /dev/null and b/app/extensions/__pycache__/tim_judges.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/__init__.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..595dd9d Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/aluc.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/aluc.cpython-313.pyc new file mode 100644 index 0000000..e19c23d Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/aluc.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/ausencia_oferta_proativa.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/ausencia_oferta_proativa.cpython-313.pyc new file mode 100644 index 0000000..3518332 Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/ausencia_oferta_proativa.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/fraseologia.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/fraseologia.cpython-313.pyc new file mode 100644 index 0000000..1a666ee Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/fraseologia.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/out_of_scope.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/out_of_scope.cpython-313.pyc new file mode 100644 index 0000000..3613988 Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/out_of_scope.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/revprec.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/revprec.cpython-313.pyc new file mode 100644 index 0000000..ea79b07 Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/revprec.cpython-313.pyc differ diff --git a/app/extensions/tim_prompts/__pycache__/rqlt.cpython-313.pyc b/app/extensions/tim_prompts/__pycache__/rqlt.cpython-313.pyc new file mode 100644 index 0000000..f605242 Binary files /dev/null and b/app/extensions/tim_prompts/__pycache__/rqlt.cpython-313.pyc differ diff --git a/app/observability/__pycache__/__init__.cpython-313.pyc b/app/observability/__pycache__/__init__.cpython-313.pyc index efc6004..f87dcee 100644 Binary files a/app/observability/__pycache__/__init__.cpython-313.pyc and b/app/observability/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/observability/__pycache__/telemetry_observer.cpython-313.pyc b/app/observability/__pycache__/telemetry_observer.cpython-313.pyc index 6baa56c..857b828 100644 Binary files a/app/observability/__pycache__/telemetry_observer.cpython-313.pyc and b/app/observability/__pycache__/telemetry_observer.cpython-313.pyc differ diff --git a/app/presentation/__pycache__/__init__.cpython-313.pyc b/app/presentation/__pycache__/__init__.cpython-313.pyc index 519a276..b8620a9 100644 Binary files a/app/presentation/__pycache__/__init__.cpython-313.pyc and b/app/presentation/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/presentation/__pycache__/tool_renderers.cpython-313.pyc b/app/presentation/__pycache__/tool_renderers.cpython-313.pyc index 4cd6bbb..91eb2f6 100644 Binary files a/app/presentation/__pycache__/tool_renderers.cpython-313.pyc and b/app/presentation/__pycache__/tool_renderers.cpython-313.pyc differ diff --git a/app/workflows/__pycache__/agent_graph.cpython-313.pyc b/app/workflows/__pycache__/agent_graph.cpython-313.pyc index e7bf5a2..6b4945e 100644 Binary files a/app/workflows/__pycache__/agent_graph.cpython-313.pyc and b/app/workflows/__pycache__/agent_graph.cpython-313.pyc differ diff --git a/contas_mcp/__pycache__/__init__.cpython-313.pyc b/contas_mcp/__pycache__/__init__.cpython-313.pyc index c1e2f94..6037aaf 100644 Binary files a/contas_mcp/__pycache__/__init__.cpython-313.pyc and b/contas_mcp/__pycache__/__init__.cpython-313.pyc differ diff --git a/contas_mcp/servers/__pycache__/__init__.cpython-313.pyc b/contas_mcp/servers/__pycache__/__init__.cpython-313.pyc index 978853b..3e72e8c 100644 Binary files a/contas_mcp/servers/__pycache__/__init__.cpython-313.pyc and b/contas_mcp/servers/__pycache__/__init__.cpython-313.pyc differ diff --git a/contas_mcp/servers/contas_mcp_server/__pycache__/__init__.cpython-313.pyc b/contas_mcp/servers/contas_mcp_server/__pycache__/__init__.cpython-313.pyc index fbef08d..dd27a35 100644 Binary files a/contas_mcp/servers/contas_mcp_server/__pycache__/__init__.cpython-313.pyc and b/contas_mcp/servers/contas_mcp_server/__pycache__/__init__.cpython-313.pyc differ diff --git a/contas_mcp/servers/contas_mcp_server/__pycache__/main.cpython-313.pyc b/contas_mcp/servers/contas_mcp_server/__pycache__/main.cpython-313.pyc index ea588b2..3b4c168 100644 Binary files a/contas_mcp/servers/contas_mcp_server/__pycache__/main.cpython-313.pyc and b/contas_mcp/servers/contas_mcp_server/__pycache__/main.cpython-313.pyc differ diff --git a/contas_mcp/servers/contas_mcp_server/main.py b/contas_mcp/servers/contas_mcp_server/main.py index 8af27d6..6e51f5f 100644 --- a/contas_mcp/servers/contas_mcp_server/main.py +++ b/contas_mcp/servers/contas_mcp_server/main.py @@ -71,7 +71,7 @@ class ToolCall(BaseModel): TOOLS: dict[str, dict[str, Any]] = { - "consultar_faturas": {"description": "Consulta faturas do cliente.", "input_schema": {"msisdn": "string"}}, + "consultar_faturas": {"description": "Consulta faturas do cliente, incluindo valor total quando disponível na fatura detalhada.", "input_schema": {"msisdn": "string"}}, "consultar_plano": {"description": "Consulta exclusivamente o plano ou planos contratados presentes na fatura.", "input_schema": {"msisdn": "string"}}, "invoice_explanation": {"description": "Executa o workflow de explicação de fatura com pause/resume pelo WorkflowRuntime do framework.", "input_schema": {"msisdn": "string"}}, "consultar_vas": {"description": "Consulta VAS ativos.", "input_schema": {"msisdn": "string"}}, @@ -307,17 +307,22 @@ def _preflight_subject(name: str, args: dict[str, Any]) -> dict[str, Any] | None return None async def _enrich_invoice_context(name: str, args: dict[str, Any]) -> None: - if name not in {"consultar_plano", "invoice_explanation", "cancelar_vas_avulso", "tratar_vas_estrategico", "contestar_cobranca"}: + if name not in {"consultar_faturas", "consultar_plano", "invoice_explanation", "cancelar_vas_avulso", "tratar_vas_estrategico", "contestar_cobranca"}: return msisdn = str(args.get("msisdn") or "").strip() if not msisdn: return - # If all required evidence is already present, preserve it exactly. - if isinstance(args.get("complete_invoices_payload"), dict) and isinstance(args.get("billing_analysis"), dict): + # If all required evidence is already present, preserve it exactly. For + # consultar_faturas/invoice_explanation the semantic amount also matters, so + # a cached pair without detail must still be enriched. + has_base = isinstance(args.get("complete_invoices_payload"), dict) and isinstance(args.get("billing_analysis"), dict) + needs_detail = name in {"consultar_faturas", "invoice_explanation", "cancelar_vas_avulso", "contestar_cobranca"} + has_detail = isinstance(args.get("invoice_detail"), dict) or args.get("invoice_amount") not in (None, "") + if has_base and (not needs_detail or has_detail): return session_id = str(args.get("session_id") or args.get("original_session_id") or args.get("conversation_key") or "").strip() invoice_id = str(args.get("invoice_id") or args.get("current_invoice_number") or "").strip() - include_detail = name in {"cancelar_vas_avulso", "contestar_cobranca"} and not isinstance(args.get("invoice_detail"), dict) + include_detail = name in {"consultar_faturas", "invoice_explanation", "cancelar_vas_avulso", "contestar_cobranca"} and not isinstance(args.get("invoice_detail"), dict) try: ctx = await get_invoice_context_service().get( session_id=session_id, diff --git a/tests/migration/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc index 5d62525..a2d3cf0 100644 Binary files a/tests/migration/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_adversarial_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_adversarial_parity.cpython-313-pytest-9.0.2.pyc index 01111d1..25109e3 100644 Binary files a/tests/migration/__pycache__/test_adversarial_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_adversarial_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_backend_wrapper_contract_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_backend_wrapper_contract_parity.cpython-313-pytest-9.0.2.pyc index bd9373a..0e0949f 100644 Binary files a/tests/migration/__pycache__/test_backend_wrapper_contract_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_backend_wrapper_contract_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_business_events_and_guardrails.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_business_events_and_guardrails.cpython-313-pytest-9.0.2.pyc index 76bc6f9..c11a914 100644 Binary files a/tests/migration/__pycache__/test_business_events_and_guardrails.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_business_events_and_guardrails.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_cancel_backend_wrapper_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_cancel_backend_wrapper_parity.cpython-313-pytest-9.0.2.pyc index 9cac1d5..9aab60b 100644 Binary files a/tests/migration/__pycache__/test_cancel_backend_wrapper_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_cancel_backend_wrapper_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_cancel_composite_workflow.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_cancel_composite_workflow.cpython-313-pytest-9.0.2.pyc index 288323d..412fc36 100644 Binary files a/tests/migration/__pycache__/test_cancel_composite_workflow.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_cancel_composite_workflow.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_cancel_wrapper_remaining_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_cancel_wrapper_remaining_parity.cpython-313-pytest-9.0.2.pyc index d53a90e..5d05cca 100644 Binary files a/tests/migration/__pycache__/test_cancel_wrapper_remaining_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_cancel_wrapper_remaining_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_contas_domain_mock.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_contas_domain_mock.cpython-313-pytest-9.0.2.pyc index 082b22b..159cacb 100644 Binary files a/tests/migration/__pycache__/test_contas_domain_mock.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_contas_domain_mock.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_contestation_business_rules_full.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_contestation_business_rules_full.cpython-313-pytest-9.0.2.pyc index 7fcb92f..327932c 100644 Binary files a/tests/migration/__pycache__/test_contestation_business_rules_full.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_contestation_business_rules_full.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_contestation_failure_mapping.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_contestation_failure_mapping.cpython-313-pytest-9.0.2.pyc index 120a20c..3e57082 100644 Binary files a/tests/migration/__pycache__/test_contestation_failure_mapping.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_contestation_failure_mapping.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_dispute_actions_remaining_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_dispute_actions_remaining_parity.cpython-313-pytest-9.0.2.pyc index fea6f92..5ff53b8 100644 Binary files a/tests/migration/__pycache__/test_dispute_actions_remaining_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_dispute_actions_remaining_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_external_guardrails_judges_spi.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_external_guardrails_judges_spi.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..55768e5 Binary files /dev/null and b/tests/migration/__pycache__/test_external_guardrails_judges_spi.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_finalization_parity_extended.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_finalization_parity_extended.cpython-313-pytest-9.0.2.pyc index 177edf9..475b282 100644 Binary files a/tests/migration/__pycache__/test_finalization_parity_extended.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_finalization_parity_extended.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_framework_llm_composition_directive.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_framework_llm_composition_directive.cpython-313-pytest-9.0.2.pyc index 055db2f..e59043a 100644 Binary files a/tests/migration/__pycache__/test_framework_llm_composition_directive.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_framework_llm_composition_directive.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_framework_native_structure.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_framework_native_structure.cpython-313-pytest-9.0.2.pyc index b51ccd6..9f4d480 100644 Binary files a/tests/migration/__pycache__/test_framework_native_structure.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_framework_native_structure.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_framework_rag_directive.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_framework_rag_directive.cpython-313-pytest-9.0.2.pyc index c927575..6f1cf4e 100644 Binary files a/tests/migration/__pycache__/test_framework_rag_directive.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_framework_rag_directive.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_framework_zero_legacy.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_framework_zero_legacy.cpython-313-pytest-9.0.2.pyc index dbaf3f3..429ccd1 100644 Binary files a/tests/migration/__pycache__/test_framework_zero_legacy.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_framework_zero_legacy.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_guardrail_binary_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_guardrail_binary_parity.cpython-313-pytest-9.0.2.pyc index 80d576a..5a277e5 100644 Binary files a/tests/migration/__pycache__/test_guardrail_binary_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_guardrail_binary_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_guardrail_context_dict_history.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_guardrail_context_dict_history.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..8ee818a Binary files /dev/null and b/tests/migration/__pycache__/test_guardrail_context_dict_history.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_guardrail_original_defaults_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_guardrail_original_defaults_parity.cpython-313-pytest-9.0.2.pyc index ea89901..ff78f95 100644 Binary files a/tests/migration/__pycache__/test_guardrail_original_defaults_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_guardrail_original_defaults_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_invoice_context_framework_native.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_invoice_context_framework_native.cpython-313-pytest-9.0.2.pyc index 12d4801..77ce2c2 100644 Binary files a/tests/migration/__pycache__/test_invoice_context_framework_native.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_invoice_context_framework_native.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_mcp_contestation_subject_guard.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_mcp_contestation_subject_guard.cpython-313-pytest-9.0.2.pyc index 9080b1d..898648f 100644 Binary files a/tests/migration/__pycache__/test_mcp_contestation_subject_guard.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_mcp_contestation_subject_guard.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_no_legacy_dependency.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_no_legacy_dependency.cpython-313-pytest-9.0.2.pyc index 9deb386..26419eb 100644 Binary files a/tests/migration/__pycache__/test_no_legacy_dependency.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_no_legacy_dependency.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_observability_code_mapping.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_observability_code_mapping.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..aecf86c Binary files /dev/null and b/tests/migration/__pycache__/test_observability_code_mapping.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_observability_default_overlay_compatibility.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_observability_default_overlay_compatibility.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..19c1c0b Binary files /dev/null and b/tests/migration/__pycache__/test_observability_default_overlay_compatibility.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_observability_mapping_provider_boundary.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_observability_mapping_provider_boundary.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..2887910 Binary files /dev/null and b/tests/migration/__pycache__/test_observability_mapping_provider_boundary.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_observability_mapping_registry_actions.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_observability_mapping_registry_actions.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..e03ee25 Binary files /dev/null and b/tests/migration/__pycache__/test_observability_mapping_registry_actions.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_compliance_anatel.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_compliance_anatel.cpython-313-pytest-9.0.2.pyc index 1458c6a..f86137e 100644 Binary files a/tests/migration/__pycache__/test_original_compliance_anatel.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_compliance_anatel.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_contestation_validation.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_contestation_validation.cpython-313-pytest-9.0.2.pyc index c5a527f..191195d 100644 Binary files a/tests/migration/__pycache__/test_original_contestation_validation.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_contestation_validation.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_item_matcher_transcription.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_item_matcher_transcription.cpython-313-pytest-9.0.2.pyc index d03276a..e221fb1 100644 Binary files a/tests/migration/__pycache__/test_original_item_matcher_transcription.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_item_matcher_transcription.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_vas_cancellation_message.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_vas_cancellation_message.cpython-313-pytest-9.0.2.pyc index 5f03a92..8cd338e 100644 Binary files a/tests/migration/__pycache__/test_original_vas_cancellation_message.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_vas_cancellation_message.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_vas_variation.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_vas_variation.cpython-313-pytest-9.0.2.pyc index b4b3504..15d1cff 100644 Binary files a/tests/migration/__pycache__/test_original_vas_variation.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_vas_variation.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_vas_variation_adversarial.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_vas_variation_adversarial.cpython-313-pytest-9.0.2.pyc index 3696800..e7f452d 100644 Binary files a/tests/migration/__pycache__/test_original_vas_variation_adversarial.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_vas_variation_adversarial.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_original_workflow_cases.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_original_workflow_cases.cpython-313-pytest-9.0.2.pyc index ec3cf2d..e6769f3 100644 Binary files a/tests/migration/__pycache__/test_original_workflow_cases.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_original_workflow_cases.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_output_supervisor_no_contract_hardcodes.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_output_supervisor_no_contract_hardcodes.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..ac620fe Binary files /dev/null and b/tests/migration/__pycache__/test_output_supervisor_no_contract_hardcodes.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_pro_rata_full_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_pro_rata_full_parity.cpython-313-pytest-9.0.2.pyc index 97520a6..2968512 100644 Binary files a/tests/migration/__pycache__/test_pro_rata_full_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_pro_rata_full_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_rag_resilience_and_informational_context.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_rag_resilience_and_informational_context.cpython-313-pytest-9.0.2.pyc index 590bfa0..26fadea 100644 Binary files a/tests/migration/__pycache__/test_rag_resilience_and_informational_context.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_rag_resilience_and_informational_context.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_real_legacy_integration_compat.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_real_legacy_integration_compat.cpython-313-pytest-9.0.2.pyc new file mode 100644 index 0000000..2dc0536 Binary files /dev/null and b/tests/migration/__pycache__/test_real_legacy_integration_compat.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_remaining_command_contracts.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_remaining_command_contracts.cpython-313-pytest-9.0.2.pyc index d5d3c1f..3f8f8fc 100644 Binary files a/tests/migration/__pycache__/test_remaining_command_contracts.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_remaining_command_contracts.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_tim_contract_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_tim_contract_parity.cpython-313-pytest-9.0.2.pyc index 3abaf8d..5f56a30 100644 Binary files a/tests/migration/__pycache__/test_tim_contract_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_tim_contract_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_tim_contracts_and_idempotency.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_tim_contracts_and_idempotency.cpython-313-pytest-9.0.2.pyc index ab2bdc3..5b74d75 100644 Binary files a/tests/migration/__pycache__/test_tim_contracts_and_idempotency.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_tim_contracts_and_idempotency.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_tim_event_metadata_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_tim_event_metadata_parity.cpython-313-pytest-9.0.2.pyc index e6a7ab4..423397d 100644 Binary files a/tests/migration/__pycache__/test_tim_event_metadata_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_tim_event_metadata_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_tool_policy_operation_types.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_tool_policy_operation_types.cpython-313-pytest-9.0.2.pyc index 45cecbd..7a4edf7 100644 Binary files a/tests/migration/__pycache__/test_tool_policy_operation_types.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_tool_policy_operation_types.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_vaa_dispute_parity.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_vaa_dispute_parity.cpython-313-pytest-9.0.2.pyc index ea3aaa7..568136d 100644 Binary files a/tests/migration/__pycache__/test_vaa_dispute_parity.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_vaa_dispute_parity.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_vas_response_renderer.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_vas_response_renderer.cpython-313-pytest-9.0.2.pyc index e68216e..12615a6 100644 Binary files a/tests/migration/__pycache__/test_vas_response_renderer.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_vas_response_renderer.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_workflow_execution_latch.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_workflow_execution_latch.cpython-313-pytest-9.0.2.pyc index d764781..131286a 100644 Binary files a/tests/migration/__pycache__/test_workflow_execution_latch.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_workflow_execution_latch.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/__pycache__/test_wrapper_last_contracts.cpython-313-pytest-9.0.2.pyc b/tests/migration/__pycache__/test_wrapper_last_contracts.cpython-313-pytest-9.0.2.pyc index 44de84c..87a1a37 100644 Binary files a/tests/migration/__pycache__/test_wrapper_last_contracts.cpython-313-pytest-9.0.2.pyc and b/tests/migration/__pycache__/test_wrapper_last_contracts.cpython-313-pytest-9.0.2.pyc differ diff --git a/tests/migration/test_invoice_context_framework_native.py b/tests/migration/test_invoice_context_framework_native.py index a07d589..9c9019a 100644 --- a/tests/migration/test_invoice_context_framework_native.py +++ b/tests/migration/test_invoice_context_framework_native.py @@ -25,7 +25,16 @@ class Client: def bill_pdf(self, msisdn, invoice_id, customer_id, **kwargs): self.pdf_calls += 1 - return {"119": {"SVA Detalhe Total": [{"desc": "Tamboro"}]}} + return { + "status": "SUCCESS", + "parsed_content": { + "total_geral": 191.97, + "Fatura Resumo": [ + {"desc": "Período", "period": "01/04/2026 a 30/04/2026"}, + {"desc": "Emissão", "emissao": "01/04/2026"}, + ], + }, + } @pytest.mark.asyncio @@ -196,3 +205,73 @@ async def test_invoice_context_cache_hit_expoe_cache_age_sem_republicar_eventos( assert cached.metadata["cache_hit"] is True assert cached.metadata["cache_age_ms"] >= 0 assert cached.business_events == [] + + +def test_extract_invoice_summary_context_restaura_semantica_do_original(): + from app.domain.contas.invoice_context import extract_invoice_summary_context + + result = extract_invoice_summary_context({ + "parsed_content": { + "total_geral": 191.97, + "Fatura Resumo": [ + {"desc": "Período", "period": "01/04/2026 a 30/04/2026"}, + {"desc": "Emissão", "emissao": "01/04/2026"}, + ], + } + }) + assert result == { + "invoice_amount": "191.97", + "invoice_amount_open": "191.97", + "invoice_period": "01/04/2026 a 30/04/2026", + "invoice_emissao": "01/04/2026", + } + + +@pytest.mark.asyncio +async def test_invoice_context_detail_expoe_invoice_amount_semantico(): + client = Client() + svc = InvoiceContextService(client, InMemoryCache(), ttl_seconds=60) # type: ignore[arg-type] + ctx = await svc.get(session_id="s1", msisdn="119", include_detail=True) + assert ctx.invoice_amount == "191.97" + assert ctx.invoice_amount_open == "191.97" + assert ctx.invoice_period == "01/04/2026 a 30/04/2026" + assert ctx.invoice_emissao == "01/04/2026" + assert ctx.as_dict()["invoice_amount"] == "191.97" + + +def test_consultar_faturas_reusa_prefetch_e_publica_valor_sem_reconsultar_backend(): + from app.domain.contas.service import ContasDomainService + + class C(Client): + def consultar_faturas(self, msisdn): + raise AssertionError("nao deveria consultar novamente") + + svc = ContasDomainService(client=C()) # type: ignore[arg-type] + result = svc.consultar_faturas( + msisdn="119", + complete_invoices_payload={"paymentItems": [{"invoiceId": "I1"}]}, + invoice_id="I1", + customer_id="C1", + invoice_amount="191.97", + invoice_amount_open="191.97", + ) + assert result["invoice_amount"] == "191.97" + assert result["invoice_amount_open"] == "191.97" + assert result["invoice_id"] == "I1" + assert result["customer_id"] == "C1" + +@pytest.mark.asyncio +async def test_mcp_consultar_faturas_enriquece_com_detail_e_valor(monkeypatch): + from contas_mcp.servers.contas_mcp_server import main + + client = Client() + context_service = InvoiceContextService(client, InMemoryCache(), ttl_seconds=60) # type: ignore[arg-type] + monkeypatch.setattr(main, "get_invoice_context_service", lambda: context_service) + + args = {"msisdn": "119", "session_id": "s1", "message_id": "m1"} + await main._enrich_invoice_context("consultar_faturas", args) + + assert client.pdf_calls == 1 + assert args["invoice_amount"] == "191.97" + assert args["invoice_amount_open"] == "191.97" + assert args["complete_invoices_payload"]["paymentItems"][0]["invoiceId"] == "I1"