fix: three review findings — page budget in emitted units, demo cache… · VectifyAI/PageIndex@fc2dd3c · GitHub
Skip to content

Commit fc2dd3c

Browse files
committed
fix: three review findings — page budget in emitted units, demo cache cut, breakpoint docs
get_page_content sized its response budget in raw characters while the envelope is emitted as JSON, where every quote, backslash, newline and tab costs an escape character — quote-dense tables measured 108,777 and code-dense pages 116,506 against the 100,000 limit while the accounting said 94,400. The same sizing-units-vs-emitted-units defect was raised on the structure path in #393 and fixed there via _serialized_size; the sibling never got the fix. The budget now measures the serialized page entry plus json's ", " item separator, closing the two residual gaps an adversarial sweep still breached (per-entry shell: 300 short pages; separators: 4000 tiny pages, 102,274 emitted). All shapes now land under the limit except the deliberate first-page exception. The budget test's pages are now escape-dense — raw length under the budget, serialized length over — so it fails on the old accounting, and it asserts the real property: the emitted envelope stays within TOOL_RESPONSE_CHAR_LIMIT. The demo's .doc_id sidecar cache is deleted: the name lookup kept right below it resolves every re-run (submit's uniquing suffixes later duplicates only, the first copy keeps its plain name), so the cache bought one list_documents call on a local store ahead of a multi-minute index step, at the cost of a read/validate/unlink block, two write-backs, a disk artifact, and a .gitignore entry. Step 1 returns to its 0.2.9 shape, wait=True kept. Verified end to end against the seeded store. messages() docstring promised the top-level cache_control is skipped "when your own blocks already use all four breakpoints" — the managed prefix always holds one, so a caller placing four puts five marks on the wire and the API rejects the request. Now states the caller budget of three, matching the _cache_marks < 4 gate. Non-changes: _split_structure has the same separator undercount but its node counts are too small to breach (no measured overshoot); the first-page overshoot exception stays (one page must always return); the _split_oversized_node budget floor stays (trigger is ~16x beyond real summary sizes).
1 parent 86c257d commit fc2dd3c

5 files changed

Lines changed: 17 additions & 27 deletions

File tree

‎.gitignore‎

Lines changed: 0 additions & 1 deletion

‎examples/agentic_vectorless_rag_demo.py‎

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,13 @@
3232
from agents.stream_events import RawResponsesStreamEvent, RunItemStreamEvent
3333
from openai.types.responses import ResponseTextDeltaEvent, ResponseReasoningSummaryTextDeltaEvent
3434

35-
from pageindex import PageIndexAPIError, PageIndexLocalClient
35+
from pageindex import PageIndexLocalClient
3636
import pageindex.utils as utils
3737

3838
PDF_URL = "https://arxiv.org/pdf/2603.15031"
3939

4040
_EXAMPLES_DIR = Path(__file__).parent
4141
PDF_PATH = _EXAMPLES_DIR / "documents" / "attention-residuals.pdf"
42-
DOC_ID_PATH = _EXAMPLES_DIR / "documents" / "attention-residuals.doc_id"
4342
STORAGE_PATH = _EXAMPLES_DIR / ".pageindex"
4443

4544

@@ -127,27 +126,13 @@ async def _run():
127126
print("=" * 60)
128127
print("Step 1: Index PDF and view tree structure")
129128
print("=" * 60)
130-
doc_id = None
131-
if DOC_ID_PATH.exists():
132-
cached = DOC_ID_PATH.read_text().strip()
133-
try:
134-
client.get_document(cached)
135-
doc_id = cached
136-
except PageIndexAPIError:
137-
DOC_ID_PATH.unlink()
138-
if doc_id is None:
139-
# The .doc_id cache is gitignored — on a fresh clone with an
140-
# existing store, find the already-indexed copy by name instead of
141-
# re-indexing it.
142-
doc_id = next(
143-
(doc["id"] for doc in client.list_documents(limit=100)["documents"]
144-
if doc["name"] == PDF_PATH.name), None)
129+
doc_id = next(
130+
(doc["id"] for doc in client.list_documents(limit=100)["documents"]
131+
if doc["name"] == PDF_PATH.name), None)
145132
if doc_id:
146-
DOC_ID_PATH.write_text(doc_id)
147133
print(f"\nLoaded cached doc_id: {doc_id}")
148134
else:
149135
doc_id = client.submit_document(str(PDF_PATH), wait=True)["doc_id"]
150-
DOC_ID_PATH.write_text(doc_id)
151136
print(f"\nIndexed. doc_id: {doc_id}")
152137
print("\nTree Structure (top-level sections):")
153138
structure = client.get_tree(doc_id, node_summary=True)["result"]

‎pageindex/agent_tools.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,10 +1054,12 @@ def _get_page_content(client, doc_name: str, pages: str,
10541054
markdown = item.get("markdown") if item else None
10551055
text = (markdown if isinstance(markdown, str)
10561056
else f"Page {page} content not available")
1057-
if not included or budget - len(text) >= 0:
1058-
content.append({"page": page, "text": text})
1057+
entry = {"page": page, "text": text}
1058+
size = _serialized_size(entry) + 2 # +2: json ", " item separator
1059+
if not included or budget - size >= 0:
1060+
content.append(entry)
10591061
included.append(page)
1060-
budget -= len(text)
1062+
budget -= size
10611063
else:
10621064
remaining.append(page)
10631065

‎pageindex/client.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,8 +679,8 @@ def messages(
679679
append to your history. The managed system prompt carries a
680680
``cache_control`` breakpoint, and the request sets the top-level
681681
``cache_control`` so each turn re-reads the growing conversation
682-
from cache — skipped when your own blocks already use all four
683-
breakpoints.
682+
from cache — skipped when your own blocks already use the three
683+
remaining breakpoints (the managed prompt holds the fourth).
684684
685685
Args:
686686
messages: Native Messages-format history (including prior

‎tests/test_agent_tools.py‎

Lines changed: 6 additions & 2 deletions

0 commit comments

Comments
 (0)