Give the model full retrieved chunks instead of 400-character snippets
CI / backend (pull_request) Successful in 41s
CI / frontend (pull_request) Failing after 7s
CI / backend (push) Successful in 42s
CI / frontend (push) Failing after 6s

Compaction replaces a tool's text with its artifact, and the search artifact
only carries UI snippets, so the full chunk the retriever found never reached
the model. Search tools now attach the full text as model_context, which
compaction prefers and shortens under budget pressure while keeping source
ids; the persisted artifact and UI are unchanged. The per-chunk header drops
the raw metadata dict (about a fifth of search output tokens) for title, date
and source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 03:34:26 -04:00
parent 0b1600e524
commit b8ccc88b58
7 changed files with 222 additions and 35 deletions
+23
View File
@@ -85,6 +85,29 @@ class TestCreateArtifact:
assert result is None
assert await Artifact.all().count() == 0
async def test_drops_model_context_before_persisting(self, owner):
"""model_context carries the full chunk text for the model's own view;
it must never reach the DB (or, from there, the UI)."""
user, conversation, message = owner
artifact = await create_artifact_from_output(
output=_output(
{
"kind": "search.documents",
"title": "Search: vet",
"data": {"results": [{"snippet": "short"}]},
"model_context": {"results": [{"content": "x" * 5000}]},
}
),
tool="simba_search",
user=user,
conversation=conversation,
message=message,
)
assert artifact is not None
saved = await Artifact.get(id=artifact.id)
assert saved.data == {"results": [{"snippet": "short"}]}
assert "model_context" not in saved.data
async def test_plain_string_output(self, owner):
user, conversation, message = owner
result = await create_artifact_from_output(
+73
View File
@@ -464,6 +464,64 @@ def test_focused_note_heading_index_uses_absolute_content_lines():
assert msg.artifact["data"]["markdown"] == "full original"
def _search_artifact(chunk_text: str) -> dict:
return {
"kind": "search.documents",
"title": "Search: vet",
"data": {
"query": "vet",
"source": "paperless",
"results": [
{
"snippet": chunk_text[:50],
"title": "vet_invoice",
"source_id": "chunk-1",
"url": "/sources/chunk-1",
}
],
},
"model_context": {
"results": [
{
"content": chunk_text,
"title": "vet_invoice",
"source_id": "chunk-1",
"url": "/sources/chunk-1",
}
]
},
}
def test_search_result_compaction_keeps_full_chunk_text_under_a_generous_limit():
import json
chunk_text = "Rabies vaccine administered. " + "detail " * 200
msg = ToolMessage(
content="display", artifact=_search_artifact(chunk_text), tool_call_id="a"
)
projected = context.compact_tool_result(msg, 100_000)
parsed = json.loads(projected.content)
(result,) = parsed["data"]["results"]
assert result["content"] == chunk_text
assert "snippet" not in result
def test_search_result_compaction_shortens_content_but_keeps_source_ids_under_pressure():
import json
chunk_text = "Rabies vaccine administered. " + "detail " * 200
msg = ToolMessage(
content="display", artifact=_search_artifact(chunk_text), tool_call_id="a"
)
projected = context.compact_tool_result(msg, 700)
parsed = json.loads(projected.content)
(result,) = parsed["data"]["results"]
assert len(result["content"]) < len(chunk_text)
assert result["source_id"] == "chunk-1"
assert result["url"] == "/sources/chunk-1"
def _conversation(turns, size=1000):
messages = []
for i in range(turns):
@@ -542,3 +600,18 @@ def test_trim_drops_to_low_watermark_and_prefix_stays_stable():
# ...so the retained prefix is unchanged for several turns in between.
assert all(b - a >= 3 for a, b in zip(cuts, cuts[1:]))
assert len(cuts) <= 5
def test_search_result_compaction_keeps_source_ids_when_no_rows_fit():
import json
chunk_text = "Rabies vaccine administered. " + "detail " * 200
msg = ToolMessage(
content="display", artifact=_search_artifact(chunk_text), tool_call_id="a"
)
projected = json.loads(context.compact_tool_result(msg, 300).content)
data = projected["data"]
assert data["results"] == []
assert data["results_compaction"]["omitted_source_refs"] == [
{"source_id": "chunk-1", "url": "/sources/chunk-1"}
]
+26
View File
@@ -94,6 +94,32 @@ def test_artifact_citations_identify_exact_retrieved_chunk(monkeypatch):
assert result["headings"] == ["Budget", "Savings"]
async def test_serialized_chunk_header_is_compact_not_raw_metadata(monkeypatch):
identifier = str(uuid4())
doc = Document(
id=identifier,
page_content="Rabies vaccine administered",
metadata={
"source": "paperless",
"filename": "vet_invoice.pdf",
"created_date": datetime(2026, 9, 1, tzinfo=timezone.utc).timestamp(),
"document_type": "Invoice",
},
)
store = SimpleNamespace(
amax_marginal_relevance_search=AsyncMock(return_value=[doc])
)
monkeypatch.setattr(logic, "_get_vector_store", lambda: store)
text, _ = await logic.query_vector_store("vet", source="paperless")
assert "{'source'" not in text
assert str(doc.metadata) not in text
assert "Title: vet_invoice" in text
assert "Date: 2026-09-01" in text
assert "Source: paperless" in text
assert f"Citation: /sources/{identifier}" in text
assert "Content: Rabies vaccine administered" in text
def test_document_date_and_unknown_citations():
assert (
document_date(
+15
View File
@@ -521,6 +521,13 @@ async def test_simba_search(monkeypatch):
assert result["snippet"].startswith("Rabies vaccine administered. ")
assert len(result["snippet"]) <= SNIPPET_MAX_CHARS
(model_result,) = art["model_context"]["results"]
assert model_result["content"] == PAPERLESS_DOCS[0].page_content
assert len(model_result["content"]) > SNIPPET_MAX_CHARS
assert model_result["title"] == result["title"]
assert model_result["filename"] == result["filename"]
assert "snippet" not in model_result
async def test_simba_search_empty(monkeypatch):
monkeypatch.setattr(agents, "query_vector_store", AsyncMock(return_value=("", [])))
@@ -560,6 +567,14 @@ async def test_obsidian_search_notes(obsidian, monkeypatch):
"date": "2026-01-02",
}
]
assert art["model_context"]["results"] == [
{
"content": "Simba's vet is Dr Smith.",
"title": "simba",
"path": "pets/simba.md",
"date": "2026-01-02",
}
]
async def test_obsidian_search_notes_error(obsidian, monkeypatch):