From 164ff320316db2dcaa3f6d1feedbad93ea8fac5b Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Thu, 27 Aug 2026 17:30:29 +0000 Subject: [PATCH] fix(memory): retry cu split la eroare de context Ollama in indexare KB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chunk-urile mari (tabele dense cu IP-uri/cod) treceau de split-ul pe paragrafe dar depaseau limita reala de tokeni a all-minilm, nu doar un prag fix de caractere — 18/20 chunk-uri din infrastructure.md esuau silentios la fiecare heartbeat. embed_chunk() acum injumatateste textul recursiv la eroare 500 si retrimite pana reuseste. Co-Authored-By: Claude Sonnet 5 --- src/memory_search.py | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/memory_search.py b/src/memory_search.py index 0264f8d..32d2d70 100644 --- a/src/memory_search.py +++ b/src/memory_search.py @@ -113,6 +113,28 @@ def get_embedding(text: str) -> list[float]: raise ConnectionError(f"Ollama API error: {e.response.status_code}") +def embed_chunk(text: str, max_depth: int = 6) -> list[tuple[str, list[float]]]: + """Embed text, halving on Ollama context-length errors until it fits. + + The model's context limit is token-based, not character-based, so dense + content (tables, IPs, code) can overflow well under _CHUNK_MAX chars. This + self-corrects instead of guessing a safe static threshold. + """ + try: + return [(text, get_embedding(text))] + except ConnectionError: + if max_depth <= 0 or len(text) < _CHUNK_MIN: + raise + mid = len(text) // 2 + split_at = text.rfind("\n", 0, mid) + if split_at <= 0: + split_at = mid + left, right = text[:split_at].strip(), text[split_at:].strip() + if not left or not right: + raise + return embed_chunk(left, max_depth - 1) + embed_chunk(right, max_depth - 1) + + def serialize_embedding(embedding: list[float]) -> bytes: """Pack floats to bytes for SQLite storage.""" return struct.pack(f"{len(embedding)}f", *embedding) @@ -194,15 +216,17 @@ def index_file(file_path: Path) -> int: conn = get_db() try: conn.execute("DELETE FROM chunks WHERE file_path = ?", (rel_path,)) - for i, chunk_text in enumerate(chunks): - embedding = get_embedding(chunk_text) - conn.execute( - """INSERT INTO chunks (file_path, chunk_index, chunk_text, embedding, updated_at) - VALUES (?, ?, ?, ?, ?)""", - (rel_path, i, chunk_text, serialize_embedding(embedding), now), - ) + i = 0 + for chunk_text in chunks: + for sub_text, embedding in embed_chunk(chunk_text): + conn.execute( + """INSERT INTO chunks (file_path, chunk_index, chunk_text, embedding, updated_at) + VALUES (?, ?, ?, ?, ?)""", + (rel_path, i, sub_text, serialize_embedding(embedding), now), + ) + i += 1 conn.commit() - return len(chunks) + return i finally: conn.close()