Skip to content

Unify the document tree across local and cloud - #541

Merged
rejojer merged 3 commits into
mainfrom
feat/unified-tree
Oct 1, 2026
Merged

rejojer merged 3 commits into
mainfrom
feat/unified-tree

Conversation

@rejojer

@rejojer rejojer commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

What changes

get_tree returns one node shape in local and cloud mode:
{title, node_id, start_index, end_index, summary, text, nodes}.
page_index and prefix_summary no longer appear. Breaking for code that reads them.

The SDK only renames fields on the way out and never restructures a stored tree. A document indexed before this change keeps its own ranges and summaries, so every node's summary still matches its range.

New local indexes (standard and flash) are built in the unified shape:

  • A parent whose first child starts on a later page gets a first child titled "<parent title> (intro)" that holds those pages. A parent with no title gets "Intro".
  • A parent's range covers its whole subtree. Its summary is written from its children's summaries.
  • Standard mode now summarizes with summarize_tree, as flash does. A parent waits only for its own children, and calls run deepest first under the concurrency cap. Short leaves keep their raw text, and the prompts are flash's.
  • A node the model leaves unsummarized falls back to its subsection titles or its opening text. A run in which no call is answered still fails.
  • The standard large-node split acts on leaves only. It no longer replaces a parent's existing subsections.

Page boundaries: when a cut can't tell where a heading sits on a page, the page goes to both sides.

  • A parent's text runs onto the page its first child starts on. It is empty when the parent's intro holds those pages. The public helpers add_node_text and add_node_text_with_labels cut text by the same rule.
  • The flash Preface takes the first section's page unless that section's heading opens the page.
  • A heading with no Latin letter or digit counts as not at the top of its page.

When the cloud API returns a tree without end_index, the SDK fills each node's end from the next node's start. This costs one extra metadata request.

Tests

  • tests/test_tree_format.py: 10 new tests. Each one fails on main.
  • Local runs: 591 passed with agent frameworks, excluding test_local_chat, whose failures here come from an httpx environment issue and also fail on main. 601 passed and 218 skipped without frameworks.
  • 7 example PDFs indexed through flash with the model stubbed. Each stored tree meets the new invariants, and get_tree returns it unchanged.

Follow-ups (not in this PR)

  • Docs: get_tree in the SDK documents page and SKILL.md.
  • Release note for the get_tree change.

get_tree returns the same node shape in both modes: start_index and
end_index (no page_index) and summary (no prefix_summary). The SDK only
maps field names on the way out. A stored tree is never restructured,
so older documents keep their own ranges and summaries.

New local indexes, standard and flash, are built in the unified shape:
- a parent whose first child starts on a later page gets a first child
  "<parent title> (intro)" holding those pages
- a parent's range covers its whole subtree, and its summary is written
  from its children's summaries, deepest first
- a node the model leaves unsummarized falls back to its subsection
  titles or its opening text; a run with no answer at all still fails
- the standard large-node split acts on leaves only, so it no longer
  replaces a parent's existing subsections

A page cut that cannot tell where a heading sits gives the page to both
sides. A parent's text runs onto its first child's page, and is empty
when its intro holds those pages. The flash Preface takes the first
section's page unless that heading opens it. A heading with nothing to
match counts as not at the top of its page.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-01T11:42:43.643638Z 79d88e8 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

rejojer added a commit that referenced this pull request Oct 1, 2026
#541 makes the same change (a node's own start_index/end_index win) with
its own test, and the two versions conflict on merge. The node helpers
here don't depend on it.
rejojer added a commit that referenced this pull request Oct 1, 2026
create_node_mapping walked children with tree.get('nodes', []), so a
node carrying nodes: None raised TypeError while get_node and
get_node_path, which use `or []`, handled the same tree. Use `or []`
in the shared walker so every create_node_mapping caller is covered.
#541 does not touch this line; a trial merge with its head 79d88e8 is
clean.
A parent's text runs onto the page its first child starts on, and is empty
when its intro holds those pages. LocalAPI and the standard builder each
applied this rule themselves. utils.own_pages now holds it, and
add_node_text and add_node_text_with_labels use it, so both get the same
text as before.
Standard mode ran its section summaries level by level through a second,
slower copy of what summarize_tree already does for flash. It now calls
summarize_tree: a parent waits only for its own children, calls run deepest
first under the concurrency cap, short leaves keep their raw text, and the
prompts are flash's. generate_summaries_for_structure is back to its main
version.
@rejojer
rejojer merged commit 6d23caf into main Oct 1, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant