Skip to content

fix(chunkers): resolve missing protect_urls in SimpleTextSplitter fallback - #2189

Open
RerankerGuo wants to merge 1 commit into
MemTensor:mainfrom
RerankerGuo:fix/issue-2115-simple-text-splitter-protect-urls
Open

fix(chunkers): resolve missing protect_urls in SimpleTextSplitter fallback#2189
RerankerGuo wants to merge 1 commit into
MemTensor:mainfrom
RerankerGuo:fix/issue-2115-simple-text-splitter-protect-urls

Conversation

@RerankerGuo

Copy link
Copy Markdown
Contributor

Background

Issue #2115 reports that the file-parsing fallback branch fails with AttributeError: protect_urls when langchain-style chunkers are unavailable and the code path falls back to SimpleTextSplitter. The splitter referenced self.protect_urls / self.restore_urls without inheriting them from the base BaseChunker, which is where those helpers are defined.

Changes

  • memos/chunkers/simple_chunker.py: SimpleTextSplitter now inherits from BaseChunker. The explicit chunk_size / chunk_overlap constructor is preserved (callers in the read_multi_modal pipeline rely on it). A minimal BaseChunkerConfig is synthesized so that the base class behaves correctly while retaining the existing positional-constructor API.
  • tests/chunkers/test_simple_chunker.py: New tests covering:
    • Constructor exposes protect_urls / restore_urls helpers and round-trip URL preservation.
    • Empty / whitespace inputs yield no chunks.
    • Short input yields one chunk.
    • Long input yields multiple chunks with bounded size.
    • URL protection keeps URLs whole across chunk boundaries.
    • Sentence boundaries are preferred when slicing.

Verification

  • Ruff: ruff format + ruff check --fix pass.
  • python3 -m py_compile succeeds for modified files.

Impact

  • Backwards compatible: existing call sites continue to work unchanged.
  • Resolves the AttributeError in the fallback parser pipeline so that document / knowledge ingestion no longer crashes when optional deps are missing.

…nheritance

SimpleTextSplitter called self.protect_urls/restore_urls without defining
them, which caused AttributeErrors in the file parsing fallback branch
when langchain-style splitters were unavailable. Fix: inherit from
BaseChunker and synthesize a minimal BaseChunkerConfig so the URL
preservation helpers are always available. Closes MemTensor#2115.
@Memtensor-AI Memtensor-AI added area:core MOS 编排层 / 框架底座 / 跨模块问题 status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Jul 31, 2026
@Memtensor-AI
Memtensor-AI requested a review from WeiminLee July 31, 2026 02:14
@Memtensor-AI

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2189
Task: 525644d6c2efa3a1
Base: main
Head: fix/issue-2115-simple-text-splitter-protect-urls

🔍 OpenCodeReview found 4 issue(s) in this PR.


1. src/memos/chunkers/simple_chunker.py (L17-L21)

Passing "simple" is misleading: the field's docstring says supported values are 'tiktoken' or a HuggingFace tokenizer name, and SimpleTextSplitter never uses this field for tokenization. Use None (the field's actual default) to avoid confusion.

💡 Suggested Change

Before:

        config = BaseChunkerConfig(
            tokenizer_or_token_counter="simple",
            chunk_size=chunk_size,
            chunk_overlap=chunk_overlap,
        )

After:

        config = BaseChunkerConfig(
            chunk_size=chunk_size,
            chunk_overlap=chunk_overlap,
        )

2. src/memos/chunkers/simple_chunker.py (L39)

The protected_text and guard is redundant. The outer if not protected_text already short-circuits when protected_text is falsy, so this inner check is dead code.

💡 Suggested Change

Before:

            chunks = [protected_text] if protected_text and protected_text.strip() else []

After:

            chunks = [protected_text] if protected_text.strip() else []

3. tests/chunkers/test_simple_chunker.py (L29-L30)

This assertion is a no-op for two reasons:

  1. splitter.protect_urls(text) is called again on the original text, producing a fresh placeholder map that is unrelated to the placeholders embedded in chunk by the earlier splitter.chunk(text) call. The two runs may assign different placeholder indices, so the map is mismatched.
  2. assert splitter.restore_urls(...) only checks that the return value is truthy — any non-empty string passes, so it never validates that the URL was actually preserved.

Suggested fix: capture the url_map from the actual chunk() internals (if exposed) or simply assert that url in splitter.restore_urls(chunk, url_map) using the map produced alongside the chunks. Alternatively, the existing assert url in joined above already covers the intent; remove this block if it adds no additional coverage.

💡 Suggested Change

Before:

            if "__URL_" in chunk:
                assert splitter.restore_urls(chunk, splitter.protect_urls(text)[1])

After:

        protected, url_map = splitter.protect_urls(text)
        for chunk in chunks:
            if "__URL_" in chunk:
                assert url in splitter.restore_urls(chunk, url_map)

4. tests/chunkers/test_simple_chunker.py (L61)

The or " " in chunks[0] escape hatch makes this assertion vacuous: any English chunk containing a space (virtually guaranteed for natural-language text) will pass, meaning the endswith condition is never enforced. The test will pass even if the chunker splits mid-sentence.

Suggested fix: remove the or fallback and assert only the sentence-boundary condition.

💡 Suggested Change

Before:

        assert chunks[0].rstrip().endswith((".", "。", "!", "?")) or " " in chunks[0]

After:

        assert chunks[0].rstrip().endswith((".", "。", "!", "?"))

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (6/6 executed). memos_python_core/changed-repo-python: 6/6. Duration: 5s [advisory, non-gating] AI-generated tests on branch test/auto-gen-525644d6c2efa3a1-20260731104118: 96/98 passed, 2 failed — these do NOT affect the PR verdict; review the branch manually.

Branch: fix/issue-2115-simple-text-splitter-protect-urls

@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core MOS 编排层 / 框架底座 / 跨模块问题 status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants