"""Chunker: deterministic, content-addressed retrieval documents.""" from __future__ import annotations from datetime import datetime, timedelta from pathlib import Path from vivamais.adapters.persistence.inmemory import InMemoryRepository from vivamais.application.chunking import ( MESSAGE_WINDOW_SIZE, build_chunk_specs, ) from vivamais.application.qa_context import customer_facts from vivamais.domain.artifacts import ( ArtifactKind, MediaArtifact, PaymentProof, ) from vivamais.domain.entities import Customer, Message from vivamais.domain.enums import MessageKind from vivamais.domain.money import Money def _message(i: int, text: str = "", contact: str = "Maria Silva") -> Message: return Message( contact=contact, kind=MessageKind.TEXT, text=text or f"mensagem numero {i}", media_path=None, timestamp=datetime(2026, 5, 1, 10, 0) + timedelta(minutes=i), from_me=i % 2 == 0, ) def _repo_with_customer() -> InMemoryRepository: repo = InMemoryRepository() repo.save_customer(Customer(name="Maria Silva", contacts=["+55 11 99999-0000"])) return repo def test_facts_chunk_renders_customer_facts() -> None: repo = _repo_with_customer() repo.save_artifact( MediaArtifact( id="a1", kind=ArtifactKind.PAYMENT_PROOF, source_path="recibo.jpg", full_transcription="PIX R$ 100,00", customer_id="Maria Silva", payload=PaymentProof(payer="Maria Silva", amount=Money(cents=10000)), ) ) specs = build_chunk_specs(repo) facts = [s for s in specs if s.chunk.source == "facts"] assert len(facts) == 1 customer = repo.get_customer("Maria Silva") assert customer is not None assert facts[0].chunk.text == customer_facts(repo, customer) assert facts[0].chunk.id.startswith("facts:Maria Silva:") assert facts[0].chunk.customer_id == "Maria Silva" def test_message_windows_overlap_and_cover_all_messages() -> None: repo = _repo_with_customer() for i in range(20): repo.save_message(_message(i)) windows = [s.chunk for s in build_chunk_specs(repo) if s.chunk.source == "messages"] assert len(windows) == 2 assert "mensagem numero 0" in windows[0].text assert "mensagem numero 19" in windows[-1].text assert "mensagem numero 8" in windows[0].text or len(windows[0].text.splitlines()) <= ( MESSAGE_WINDOW_SIZE ) def test_chunk_ids_are_stable_across_runs() -> None: repo = _repo_with_customer() for i in range(5): repo.save_message(_message(i)) first = {s.chunk.id for s in build_chunk_specs(repo)} second = {s.chunk.id for s in build_chunk_specs(repo)} assert first == second def test_appending_a_message_changes_only_tail_window_ids() -> None: repo = _repo_with_customer() for i in range(5): repo.save_message(_message(i)) before = {s.chunk.id for s in build_chunk_specs(repo)} repo.save_message(_message(5)) after = {s.chunk.id for s in build_chunk_specs(repo)} assert before != after assert all(cid.split(":")[0] in {"facts", "msg", "art"} for cid in after) def test_artifact_chunk_degrades_to_text_when_media_missing(tmp_path: Path) -> None: repo = _repo_with_customer() repo.save_artifact( MediaArtifact( id="a1", kind=ArtifactKind.PAYMENT_PROOF, source_path="recibo-sumido.jpg", full_transcription="PIX R$ 250,00 Maria Silva", customer_id="Maria Silva", payload=PaymentProof(payer="Maria Silva", amount=Money(cents=25000)), ) ) specs = [ s for s in build_chunk_specs(repo, media_dir=str(tmp_path)) if s.chunk.id.startswith("art:") ] assert len(specs) == 1 assert specs[0].image is None assert "PIX R$ 250,00" in specs[0].chunk.text assert "Documento PAYMENT_PROOF" in specs[0].chunk.text assert "pagador Maria Silva" in specs[0].chunk.text def test_artifact_chunk_carries_image_bytes_when_file_exists(tmp_path: Path) -> None: media_dir = tmp_path (media_dir / "recibo.jpg").write_bytes(b"fake-jpeg-bytes") repo = _repo_with_customer() repo.save_artifact( MediaArtifact( id="a1", kind=ArtifactKind.PAYMENT_PROOF, source_path="recibo.jpg", full_transcription="PIX", customer_id="Maria Silva", payload=PaymentProof(payer="Maria Silva", amount=Money(cents=100)), ) ) specs = [ s for s in build_chunk_specs(repo, media_dir=str(media_dir)) if s.chunk.id.startswith("art:") ] assert specs[0].image == b"fake-jpeg-bytes" def test_empty_repo_yields_no_chunks() -> None: assert build_chunk_specs(InMemoryRepository()) == []