0.167.22

Fixed

  • Cached-токены не читались в OpenAI-стриминге — метрика кэша всегда ноль в интерактивном чате ( — P2). Нестриминговый путь читал prompt_tokens_details.cached_tokens (openai_compat.go parseOpenAIResponse), стриминговый — нет: интерактивный чат всегда streaming, поэтому metrics.RecordLLMCall и llmlog получали CachedTokens=0, и экономия на промпт-кэше была невидима (Anthropic-путь читал кэш в обеих ветках — расхождение только на OpenAI-совместимых). Фикс: LLMResponse.Usage.CachedTokens в стриминговом результате читается из usage.prompt_tokens_details.cached_tokens последнего usage-чанка. Попутно закрыта мина аккумулятора SDK: ChatCompletionAccumulator суммирует usage по чанкам (streamaccumulator.go), и шлюз, повторяющий usage-объект в каждом чанке, умножал PromptTokens на их число — теперь ведётся отдельный tracking последнего usage-чанка (last-chunk-wins, семантика OpenAI-спеки: usage приходит один раз, полным, в финальном чанке), accumulator остаётся фолбэком когда usage-чанков нет вовсе. Вся инфраструктура отображения (llmlog saved_tokens, метрики, store-суммари, UI) уже была готова — не хватало только источника. Тесты: положительные — usage-чанк с prompt_tokens_details.cached_tokens: 768CachedTokens=768; без details → 0 без паники; отрицательный — шлюз повторяет один и тот же usage в 3 чанках → итог не умножается (42/7/49/32, а не ×3).