0.19.0

Итерация 15 плана аудита: память — token budgeting и кэш эмбеддингов.

Added

  • Пакет internal/tokens/ — эвристический подсчёт токенов (Count, CountForModel, CountMessages, TruncateByTokens, SplitWords); len/3.5 без внешних зависимостей, ±15% относительно tiktoken на смешанных корпусах. Корректная обрезка по rune-границе.
  • ContextBudget и ComputeBudget в internal/agent/context.go: масштабируемое распределение токенов по секциям (identity 200, soul 1500, profile 1000, skills 3000, rag 3500, completion 2000, history = остаток). Per-agent масштабирование от context_max_tokens (default 16000, min 4000).
  • pruneHistoryByTokens — отрезает историю по бюджету с сохранением парности assistant↔tool (если оставлен tool-result, обязательно тащит предшествующий assistant с tool_calls).
  • shouldSkipRAG — пропускает RAG-вызов для коротких реплик (< 4 слов: «ок», «да», «спасибо», «продолжай»). Исключение — наличие ?. Экономит embedding-вызовы и снижает latency.
  • internal/embeddings/cache.goCachedEmbedder: LRU-кэш одиночных Embed-запросов, capacity=1000, TTL=10min. SHA-256 ключ от model + text (изоляция между моделями), defensive copy результата, поточно-безопасен. Multi-text запросы (документ-чанки) проксируются мимо кэша. Подключён в cmd/taigaclaw/main.go:initEmbedder.
  • Per-agent поле context_max_tokens в agents (миграция 021_llm_usage_breakdown для SQLite + PG, up/down). 0 = «использовать дефолт пакета».
  • Поля system_tokens, rag_tokens, history_tokens в llm_usage и LLMUsageEntry/LLMUsageSummary. Заполняются ContextBuilder, агрегируются в GetLLMUsageSummary для аналитики и тюнинга бюджетов.
  • UI: поле «Размер контекстного окна» в модалке редактирования агента (web/src/routes/settings/+page.svelte). TS-типы Agent.context_max_tokens, UpdateAgentParams.context_max_tokens, LLMUsageSummary.total_*_tokens.
  • Тесты: 13 в internal/tokens, 12 в internal/embeddings/cache_test.go, 13 в internal/agent/context_test.go. Все проходят с -race.

Changed

  • ContextBuilder.BuildMessages переписан с учётом бюджетов: system-секции обрезаются по tokens.TruncateByTokens, RAG-секция — по budget.RAG, история — по pruneHistoryByTokens. LastSectionTokens фиксируется и пишется в llm_usage.
  • actor.recordUsage(ctxBuilder) — теперь принимает builder и сохраняет breakdown по секциям контекста.
  • AgentHandler.Update: принимает context_max_tokens (опционально, валидируется на >=0). Сохраняет WorkspacePath из существующего агента (раньше терялся при Update).

Fixed

  • SQLiteStore.UpdateAgent/PostgresStore.UpdateAgent: workspace_path сохранялся в SQL, но handler не передавал значение из existing — теперь явно копируется.