fix(uploads): preserve separate bold spans in outline titles (#7150)

This commit is contained in:
Zicheng (Axelsen) Xie 2026-10-20 04:39:33 -04:00 committed by GitHub
parent d288935865
commit 1ce0b765de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 52 additions and 3 deletions

View File

@ -2638,6 +2638,8 @@ removing the worker's temporary source. Automatic conversion remains off by defa
Uploaded Markdown outlines recognize ATX heading syntax, clean closing markers with a linear suffix scan, and skip HTML comment blocks and fenced and indented code examples, so hashtags and code comments do not
crowd out real document sections from the agent's heading preview. Indented bold examples are also excluded; PDF-style bold headings with up to three leading spaces remain supported.
Whole-title bold wrappers and adjacent PDF bold spans are cleaned; separate bold
spans joined by ordinary text retain their markers instead of losing only the outer pair.
Split-bold numeric table rows, including parenthesized years, signed values, and
currency-prefixed amounts, are excluded when any block after the section number
is a numeric column, so they do not consume the outline's heading budget.

View File

@ -73,7 +73,8 @@ def _clean_bold_title(raw: str) -> str:
pymupdf4llm sometimes emits adjacent bold spans as ``**A** **B**`` instead
of a single ``**A B**`` block. This helper merges those fragments and then
strips the outermost ``**...**`` wrapper so the caller gets plain text.
strips a whole-title ``**...**`` wrapper. Mixed bold/plain text keeps its
delimiters rather than losing the ends of separate spans.
Examples::
@ -83,9 +84,10 @@ def _clean_bold_title(raw: str) -> str:
"""
# Merge adjacent bold spans: "** **" → " "
merged = re.sub(r"\*\*\s*\*\*", " ", raw).strip()
# Strip outermost **...** if the whole string is wrapped
# Strip one whole-title wrapper, not the ends of separate bold spans.
if m := re.fullmatch(r"\*\*(.+?)\*\*", merged, re.DOTALL):
return m.group(1).strip()
if "**" not in m.group(1):
return m.group(1).strip()
return merged

View File

@ -0,0 +1,37 @@
"""Mixed bold spans must not be mistaken for a whole-title wrapper."""
from pathlib import Path
import pytest
from deerflow.uploads.companions import register_companion
from deerflow.utils.file_outline import extract_outline_for_file
@pytest.mark.parametrize(
("heading", "title"),
[
("**Revenue** and **Profit**", "**Revenue** and **Profit**"),
("**收入**与**利润**", "**收入**与**利润**"),
("**Before** / **After**", "**Before** / **After**"),
("**Overview**", "Overview"),
("**UNITED STATES** **SECURITIES**", "UNITED STATES SECURITIES"),
("**A**\t**B**", "A B"),
("Revenue and **Profit**", "Revenue and **Profit**"),
("**Revenue** and Profit", "**Revenue** and Profit"),
("Plain title", "Plain title"),
],
)
@pytest.mark.parametrize("converted", [False, True])
def test_upload_outline_only_unwraps_a_whole_bold_title(tmp_path: Path, heading: str, title: str, converted: bool) -> None:
markdown = tmp_path / "report.md"
original = f"Introduction\r\n\r\n## {heading} ###\r\n# Next section\r\n".encode()
markdown.write_bytes(original)
source = markdown
if converted:
source = tmp_path / "report.pdf"
source.write_bytes(b"synthetic source; conversion not invoked")
register_companion(source, markdown)
assert extract_outline_for_file(source) == ([{"title": title, "line": 3}, {"title": "Next section", "line": 4}], [])
assert markdown.read_bytes() == original

View File

@ -83,6 +83,14 @@ class TestFormatOmittedSummary:
class TestListUploadedFiles:
def test_outline_preserves_separate_bold_spans(self, tmp_path):
uploads_dir = _uploads_dir(tmp_path)
(uploads_dir / "report.md").write_text("# **Revenue** and **Profit**\n", encoding="utf-8")
result = _list_uploaded_files_impl(include_outline=True, runtime=_runtime(), _paths=_paths(tmp_path))
assert result["files"][0]["outline"] == [{"title": "**Revenue** and **Profit**", "line": 1}]
def test_no_runtime_returns_empty(self):
result = _list_uploaded_files_impl(runtime=None)
assert result["files"] == []