mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 13:16:24 +00:00
fix(uploads): exclude indented bold lines from outlines (#6194)
* fix(uploads): exclude indented bold lines from outlines * refactor(uploads): name the indented-code pattern
This commit is contained in:
parent
20bd989fc1
commit
830de11c66
@ -1907,8 +1907,8 @@ AIO directory listings discard missing shell sessions so the next request can re
|
||||
After a dropped connection, directory listings and persistent shell commands report an
|
||||
unknown outcome without replaying the operation; later calls use a fresh session.
|
||||
|
||||
Uploaded Markdown outlines recognize ATX heading syntax, clean closing markers with a linear suffix scan, and skip fenced code examples, so hashtags and code comments do not
|
||||
crowd out real document sections from the agent's heading preview.
|
||||
Uploaded Markdown outlines recognize ATX heading syntax, clean closing markers with a linear suffix scan, and skip 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.
|
||||
UTF-8 Markdown files with or without a byte-order mark (BOM) produce the same
|
||||
outlines and fallback previews, with original line numbers preserved.
|
||||
Outline titles are limited to 200 characters and fallback previews to 2,000
|
||||
|
||||
@ -32,6 +32,12 @@ optional leading UTF-8 BOM cannot hide a first-line heading or code fence, or
|
||||
occupy a preview line. Preserve physical line numbers, embedded U+FEFF
|
||||
characters, and the original file bytes.
|
||||
|
||||
All outline heading styles skip root-level indented code (four leading spaces
|
||||
or a tab after up to three spaces), including PDF-style single and split bold
|
||||
headings. Keep legitimate bold headings with up to three spaces and the shared
|
||||
conversion-companion path working. Regression coverage lives in
|
||||
`tests/test_file_outline_indented_bold.py`.
|
||||
|
||||
### Active Content MIME Types
|
||||
|
||||
`text_detection.py::_is_active_content_mime_type` is the shared download-safety
|
||||
|
||||
@ -51,6 +51,10 @@ _CODE_FENCE_RE = re.compile(r"^ {0,3}(`{3,}|~{3,})(.*)$")
|
||||
# Match the original indentation so indented code cannot become a heading.
|
||||
_ATX_HEADING_RE = re.compile(r"^ {0,3}#{1,6}(?:[ \t]+(.*))?$")
|
||||
|
||||
# Root-level indented code starts at four columns, including
|
||||
# a tab after up to three spaces. Do not strip it into a heading.
|
||||
_INDENTED_CODE_RE = re.compile(r"^( {4}| {0,3}\t)")
|
||||
|
||||
|
||||
def _strip_atx_closing_hashes(raw: str) -> str:
|
||||
"""Remove a whitespace-separated terminal hash run in linear time."""
|
||||
@ -141,6 +145,9 @@ def extract_outline(md_path: Path) -> list[dict]:
|
||||
fence_length = len(marker)
|
||||
continue
|
||||
|
||||
if _INDENTED_CODE_RE.match(line):
|
||||
continue
|
||||
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
continue
|
||||
|
||||
51
backend/tests/test_file_outline_indented_bold.py
Normal file
51
backend/tests/test_file_outline_indented_bold.py
Normal file
@ -0,0 +1,51 @@
|
||||
"""Indented bold examples must not displace document headings in outlines."""
|
||||
|
||||
import pytest
|
||||
|
||||
from deerflow.uploads.companions import register_companion
|
||||
from deerflow.utils.file_outline import MAX_OUTLINE_ENTRIES, extract_outline, extract_outline_for_file
|
||||
|
||||
|
||||
@pytest.mark.parametrize("indent", [" ", "\t", " \t", " \t", " \t"])
|
||||
@pytest.mark.parametrize("text", ["**PART II**", "**1** **Code example**"])
|
||||
def test_indented_bold_code_preserves_real_heading_lines(tmp_path, indent, text):
|
||||
path = tmp_path / "guide.md"
|
||||
path.write_text(f"# Overview\n\n{indent}{text}\n\n## Findings\n", encoding="utf-8")
|
||||
|
||||
assert extract_outline(path) == [{"title": "Overview", "line": 1}, {"title": "Findings", "line": 5}]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("indent", [" ", "\t"])
|
||||
@pytest.mark.parametrize("text", ["**PART II**", "**1** **Code example**"])
|
||||
def test_indented_bold_examples_cannot_exhaust_outline_slots(tmp_path, indent, text):
|
||||
path = tmp_path / "guide.md"
|
||||
path.write_text((indent + text + "\n") * (MAX_OUTLINE_ENTRIES + 1) + "\n# Actual findings\n", encoding="utf-8")
|
||||
|
||||
assert extract_outline(path) == [{"title": "Actual findings", "line": MAX_OUTLINE_ENTRIES + 3}]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("indent", ["", " ", " ", " "])
|
||||
def test_bold_headings_with_up_to_three_spaces_are_preserved(tmp_path, indent):
|
||||
path = tmp_path / "report.md"
|
||||
path.write_text(f"{indent}**PART II**\n{indent}**1** **概述**\n", encoding="utf-8")
|
||||
|
||||
assert extract_outline(path) == [{"title": "PART II", "line": 1}, {"title": "1 概述", "line": 2}]
|
||||
|
||||
|
||||
def test_owned_conversion_uses_the_same_indentation_rule(tmp_path):
|
||||
uploads = tmp_path / "thread/user-data/uploads"
|
||||
uploads.mkdir(parents=True)
|
||||
original = uploads / "report.pdf"
|
||||
markdown = uploads / "report.md"
|
||||
original.write_bytes(b"synthetic source fixture; converter not invoked")
|
||||
markdown.write_text(" **PART II**\n\n# Actual section\n", encoding="utf-8")
|
||||
register_companion(original, markdown)
|
||||
|
||||
assert extract_outline_for_file(original) == ([{"title": "Actual section", "line": 3}], [])
|
||||
|
||||
|
||||
def test_existing_fenced_code_and_heading_styles_are_preserved(tmp_path):
|
||||
path = tmp_path / "guide.md"
|
||||
path.write_text("~~~\n**PART II**\n~~~\n# Section\n**PART III**\n**2** **Details**\n", encoding="utf-8")
|
||||
|
||||
assert extract_outline(path) == [{"title": "Section", "line": 4}, {"title": "PART III", "line": 5}, {"title": "2 Details", "line": 6}]
|
||||
Loading…
x
Reference in New Issue
Block a user