diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc index 353b0693..863edce3 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 cde691b4..36f42cbe 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 4564ff1e..c2b649fd 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 323e37f1..ec3453a1 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 d286ead1..5281f39f 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 5edca052..95e7532a 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 ecdf114f..76e1ef65 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 1fac5d15..2df8e81d 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 1058b1d9..d7661427 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 896417bc..6655eef0 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 aeb1751b..e00bc5f7 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 db52de95..6e9e3423 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 49a7c5c2..ead826e3 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 00000000..24f9bb8e 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 1506260c..ca9110a1 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 6e1429aa..de25caa5 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 72bdaf63..dd72002c 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 37bb05a0..f63db7c9 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 66df3d03..0a795bbc 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 8257e58a..4761afd2 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 6130d1dc..d6209aae 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 f166a900..dfd46408 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 7d7ad482..7c4a6fe3 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 ea113928..e39a0451 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 e9af98ef..51c85f38 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 62ef395e..4127fada 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 a5536d02..bdb4c3f3 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 e5c598b3..1bb36829 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 4705a2ae..bd345564 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 2f5c8020..282d6db2 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 784b895d..e003ed32 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 ba3be408..51b16a6b 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 513d719b..d39ca44c 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 c364b95a..38ab459d 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 00000000..f5836e52 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 00000000..8766e70f 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 00000000..62d813e3 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 00000000..595dd9d4 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 00000000..e19c23d8 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 00000000..35183323 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 00000000..1a666ee9 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 00000000..3613988c 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 00000000..ea79b072 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 00000000..f6052422 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 efc6004c..f87dcee7 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 6baa56c8..857b8285 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 519a276f..b8620a95 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 4cd6bbbe..91eb2f6e 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 e7bf5a21..6b4945e5 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 c1e2f94d..6037aaf7 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 978853be..3e72e8c4 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 fbef08db..dd27a35e 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 ea588b2a..3b4c1680 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 8af27d68..6e51f5f0 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 5d625257..a2d3cf0a 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 01111d1f..25109e3f 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 bd9373a2..0e0949f7 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 76bc6f93..c11a914f 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 9cac1d57..9aab60bb 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 288323dd..412fc364 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 d53a90e0..5d05cca3 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 082b22b0..159cacb3 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 7fcb92fd..327932c6 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 120a20c4..3e570821 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 fea6f923..5ff53b8a 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 00000000..55768e52 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 177edf96..475b2827 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 055db2f8..e59043aa 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 b51ccd60..9f4d4806 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 c9275750..6f1cf4e3 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 dbaf3f36..429ccd17 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 80d576aa..5a277e57 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 00000000..8ee818aa 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 ea89901e..ff78f953 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 12d4801b..77ce2c25 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 9080b1df..898648f7 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 9deb3860..26419eb7 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 00000000..aecf86c0 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 00000000..19c1c0b8 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 00000000..28879103 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 00000000..e03ee25d 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 1458c6a3..f86137e5 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 c5a527f7..191195d9 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 d03276a0..e221fb19 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 5f03a92d..8cd338e5 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 b4b35042..15d1cff3 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 3696800e..e7f452d7 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 ec3cf2d3..e6769f3d 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 00000000..ac620fe5 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 97520a67..2968512a 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 590bfa02..26fadea1 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 00000000..2dc0536a 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 d5d3c1fe..3f8f8fc7 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 3abaf8d8..5f56a30b 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 ab2bdc3e..5b74d75f 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 e6a7ab42..423397de 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 45cecbd5..7a4edf7e 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 ea3aaa7f..568136d9 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 e68216e4..12615a66 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 d7647810..131286ac 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 44de84c8..87a1a37a 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 a07d589b..9c9019a3 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"