0.167.13

Fixed

  • tokens.Count считает байты вместо рун — кириллица переоценивалась ~вдвое, компакция срабатывала преждевременно ( — P1). Все бюджеты и пороги контекстного слоя (ComputeBudget, CompactSoftThreshold/trimInLoopMessages, ToolResultPruneTokens/ToolResultTrimToTokens, enforceMemoryContextBudget, триггер AutoCompact, TruncateByTokens) опираются на internal/tokens.Count, который делил len(s) (байты) на EstimateRatio=3.5 — вопреки собственному doc-комментарию, обещавшему подсчёт по рунам. Кириллица в UTF-8 — 2 байта/руна → оценка ~0.57 токена на руну против ~0.3–0.4 у современных BPE-токенизаторов (o200k_base, Claude, llama3): русскоязычная история сжималась и обрезалась сильно раньше реального заполнения контекста. Фикс: метрика переведена на rune-веса tokens.RuneWeight — ASCII ≈ 0.25 токена/руна, кириллица ≈ 0.4 (компромисс между эффективными o200k/Claude ~0.3 и llama3/Ollama ~0.45; кириллица той же длины в рунах теперь оценивается в ~1.6× латиницы, а не в 2×), прочие многобайтные скрипты ≈ 0.5, CJK (хань/кана/хангыль/fullwidth/CJK-пунктуация) ≈ 1.0; EstimateRatio удалён. Синхронно переведены на новую метрику обе внешние обрезки, использовавшие байтовую пропорцию: TruncateToolResult (head+tail теперь считается по rune-весам, а не maxTokens×3.5 байт — раньше кириллический результат обрезался до ~0.6 бюджета) и tokenOverlapTail в memory/indexer (RAG-overlap). Токен-константы (ToolResultPruneTokens=50000, ToolResultTrimToTokens=4000, toolResultBudgetCap=100000, defaultMemoryContextBudgetDivisor=4) не изменены: новая метрика даёт меньшие либо равные оценки, пороги срабатывают не раньше прежнего — ровно то, что требовалось (устранение преждевременной компакции). Тесты: tokens_test.go переписан под метрику — латиница 120 рун → 24..36 (~0.25/руну), паритет кириллицы с латиницей той же rune-длины (строго < 2×, но не дешевле латиницы), CJK ≈ числу рун, пустая → 0 / пробел → 1, TruncateByTokens rune-safe на кириллице и CJK (utf8.ValidString) и в бюджете (+маркер «…»); tool_result_truncate_test.go перекалиброван под 0.25/руну (16000-символьный кейс, ровно 4000 токенов по новой метрике, заменён на 20000).