Skip to content

Add the text deriver, which embeds a segment's text without its trailing whitespace, as the default - #1857

Draft
edwinyyyu wants to merge 4 commits into
MemMachine:mainfrom
edwinyyyu:feat/trimmed-text-deriver
Draft

edwinyyyu wants to merge 4 commits into
MemMachine:mainfrom
edwinyyyu:feat/trimmed-text-deriver

Conversation

@edwinyyyu

@edwinyyyu edwinyyyu commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Purpose of the change

The default deriver embeds a segment's text exactly as stored, including the whitespace at its end. That whitespace carries no content, and because the text is embedded as a JSON string, a trailing newline reaches the embedder as the two characters \n inside the quotes. This change adds a deriver that embeds the text without the whitespace at its end and makes it the default. The whitespace at a segment's start stays: it is the indentation of the segment's first line, which embedders use in code. The existing deriver stays, so configurations that name it keep working.

Description

  • TextDeriver, configured as text, embeds text.rstrip(), keeping leading and inner whitespace, and gives a segment of whitespace alone no derivative. The name matches TextSegmenter (type: text) and says what the deriver reads, not how it prepares the text, so it stays true if that preparation changes.
  • text becomes the event backend's default deriver, in its own commit.
  • WholeTextDeriver (whole_text) is unchanged and still embeds the text exactly as stored. Whether to remove it is a separate decision.
  • SentenceTextDeriver is unchanged; it already strips each sentence.
  • The sample configurations name the new default and list both alternatives.

Embedded text. Changes for a configuration that names no deriver, wherever a message has whitespace at its end, for example a trailing newline: its derivative now ends at the last non-whitespace character. A message of whitespace alone no longer gets a derivative. Messages without trailing whitespace embed exactly as before, and a configuration that names whole_text is unaffected.

Fixes/Closes

No issue filed.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

  • Unit Test

  • test_text_deriver.py: TextDeriver embeds no trailing whitespace, keeps leading and inner whitespace, gives a whitespace-only segment no derivative, and keeps the segment's properties; WholeTextDeriver keeps edge whitespace.

  • test_configuration.py: the default deriver is text, and type: text loads.

  • test_service_locator.py: each deriver configuration builds its deriver.

Test Results:

  • uv run --frozen ruff check packages/server and uv run --frozen ruff format --check packages/server: clean.
  • uv run --frozen --all-extras ty check --project packages/server: clean.
  • uv run --frozen --all-extras pytest -q -p no:cacheprovider on the three test files above: 58 passed (Python 3.14, macOS).

Checklist

  • I have signed the commit(s) within this pull request
  • My code follows the style guidelines of this project (See STYLE_GUIDE.md)
  • I have performed a self-review of my own code
  • I have commented my code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added unit tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

  • Confirmed all checks passed
  • Contributor has signed the commit(s)
  • Reviewed the code
  • Run, Tested, and Verified the change(s) work as expected

Screenshots/Gifs

N/A

Further comments

  • Derivatives already stored keep their text; segments ingested after this change get trimmed derivatives.
  • Split text blocks into segments that join back to the block, without langchain-text-splitters #1855 keeps the whitespace between a text block's segments in the segments themselves, so a split block renders exactly: the earlier segment ends with it through its last newline, and the later one starts with the rest, a line's indentation. With this change, the whitespace at a segment's end stays out of the embedded text, and its indentation stays in.
  • Measured on code retrieval (802 docstring queries over 137 Python files, split by Split text blocks into segments that join back to the block, without langchain-text-splitters #1855 at 500 and 2,000 characters, MRR@10 with paired bootstrap): removing the whitespace at a segment's end lowered retrieval with none of text-embedding-3-small, embeddinggemma-300m, and Qwen3-Embedding-0.6B. Removing the indentation at its start lowered it with text-embedding-3-small at 500 characters (-0.9 points, 95% CI [-1.6, -0.1]) and with Qwen3-Embedding at both lengths.

🤖 Generated with Claude Code

edwinyyyu and others added 3 commits October 23, 2026 14:06
…xt deriver

WholeTextDeriver embedded a segment's text exactly as stored, so the
whitespace at its ends went into the quoted text the embedder reads.
json.dumps writes a newline as the two characters \n, so a message ending
in a newline was embedded with \n inside its quotes.

Embed the text without the whitespace at its ends, and give a segment of
whitespace alone no derivative. The name changes with the behavior:
WholeTextDeriver becomes TrimmedTextDeriver, configured as
`trimmed_text`, and it stays the default. `whole_text` is no longer a
deriver type. The sentence deriver already strips each sentence and is
unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Renaming the whole-text deriver broke every configuration that names
`whole_text`, and whether to drop it is a separate decision. Restore
WholeTextDeriver and `whole_text` unchanged, embedding a segment's text
exactly as stored.

Add the stripping deriver beside it as TextDeriver, configured as
`text`. The name matches the text segmenter and says what the deriver
reads, not how it prepares the text, so it stays true if that
preparation changes. It embeds a segment's text without the whitespace
at its ends and gives a segment of whitespace alone no derivative.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An event backend that names no deriver now embeds each segment's text
without the whitespace at its ends. A configuration that names
`whole_text` keeps embedding the text exactly as stored. The sample
configurations name the new default and list both alternatives.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@edwinyyyu edwinyyyu changed the title Embed a segment's text without its edge whitespace, as the trimmed-text deriver Add the text deriver, which embeds a segment's text without its edge whitespace, as the default Oct 23, 2026
@edwinyyyu
edwinyyyu marked this pull request as ready for review October 23, 2026 21:17
@edwinyyyu

Copy link
Copy Markdown
Contributor Author

This should have a couple of benefits:

  • Avoid embedding pure whitespace. Reduces costs and near-duplicates.
  • Embeddings are more focused on actual content.

Drawbacks:

  • Whitespace is no longer used as context. But this is unlikely to have a negative impact because I haven't seen embedding models work for similarly niche use cases like morse code (punctuation and whitespace) or simple ciphers.

A segment's leading whitespace is the indentation of its first line, and
embedders read indentation in code. On a code retrieval set, removing it
lowered retrieval with text-embedding-3-small at the default segment
length and with Qwen3-Embedding at every length tested, while removing
the whitespace at the end lowered retrieval with no embedder tested.

Embed the text without the whitespace at its end only. A segment of
whitespace alone still has no derivative.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@edwinyyyu edwinyyyu changed the title Add the text deriver, which embeds a segment's text without its edge whitespace, as the default Add the text deriver, which embeds a segment's text without its trailing whitespace, as the default Oct 28, 2026
@edwinyyyu
edwinyyyu marked this pull request as draft October 30, 2026 22:58

This branch has not been deployed

No deployments
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