Skip to content

Commit 5d76ec8

Browse files
fix(tree_renderer): truncate overlong node titles in summary headings
The no-TOC fallback structure generator sometimes copies an entire source sentence verbatim into a node's title when there's no natural short heading to extract (see VectifyAI/PageIndex#341), producing unreadable multi-line Markdown headings in the rendered summary. Truncate titles over 80 chars with an ellipsis when rendering the heading. The full title is still available from the underlying PageIndex tree; this only affects display in wiki/summaries/*.md.
1 parent 3889e97 commit 5d76ec8

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

openkb/tree_renderer.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ def _yaml_frontmatter(source_name: str, doc_id: str, description: str = "") -> s
1515
return "---\n" + "\n".join(lines) + "\n---\n"
1616

1717

18+
_MAX_TITLE_LEN = 80
19+
20+
21+
def _short_title(title: str) -> str:
22+
"""Truncate a title for heading display.
23+
24+
The no-TOC fallback structure generator sometimes copies an entire
25+
source sentence verbatim into ``title`` when there's no natural short
26+
heading to extract; left unshortened that produces unreadable
27+
multi-line Markdown headings (see PageIndex#341).
28+
"""
29+
if len(title) <= _MAX_TITLE_LEN:
30+
return title
31+
return title[:_MAX_TITLE_LEN].rstrip() + "…"
32+
33+
1834
def _render_nodes_summary(nodes: list[dict], depth: int) -> str:
1935
"""Recursively render nodes for the *summary* view (summaries only)."""
2036
lines: list[str] = []
@@ -26,7 +42,7 @@ def _render_nodes_summary(nodes: list[dict], depth: int) -> str:
2642
summary = node.get("summary", "")
2743
children = node.get("nodes", [])
2844

29-
lines.append(f"{heading_prefix} {title} (pages {start}{end})\n")
45+
lines.append(f"{heading_prefix} {_short_title(title)} (pages {start}{end})\n")
3046
if summary:
3147
lines.append(f"Summary: {summary}\n")
3248
if children:

tests/test_tree_renderer.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,38 @@ def test_summary_md_has_type_and_description():
5252
assert 'full_text: "sources/my-doc.json"' in md
5353

5454

55+
def test_overlong_title_is_truncated_in_heading():
56+
long_title = (
57+
"This is an entire source sentence copied verbatim into the title "
58+
"field because the no-TOC fallback found no natural short heading "
59+
"to extract from this section of the document."
60+
)
61+
tree = {
62+
"structure": [
63+
{
64+
"title": long_title,
65+
"start_index": 1,
66+
"end_index": 2,
67+
"summary": "x",
68+
"nodes": [],
69+
}
70+
]
71+
}
72+
md = render_summary_md(tree, "my-doc", "doc-123")
73+
assert long_title not in md
74+
assert f"# {long_title[:80]}…" in md
75+
76+
77+
def test_short_title_is_not_truncated():
78+
tree = {
79+
"structure": [
80+
{"title": "Background", "start_index": 1, "end_index": 2, "summary": "x", "nodes": []}
81+
]
82+
}
83+
md = render_summary_md(tree, "my-doc", "doc-123")
84+
assert "# Background (pages 1–2)" in md
85+
86+
5587
def test_summary_full_text_quoted_yaml_safe():
5688
import yaml
5789

0 commit comments

Comments
 (0)