65 lines
2.8 KiB
Markdown
65 lines
2.8 KiB
Markdown
---
|
||
tags:
|
||
- hermes
|
||
- bug
|
||
- gateway
|
||
- stream_consumer
|
||
- fixed
|
||
---
|
||
# No-edit (webhook) segment send bug
|
||
|
||
**Дата:** 20.06.2026
|
||
**Файл:** `gateway/stream_consumer.py` (lines 574, 581, 591)
|
||
**Статус:** ✅ Исправлено, закоммичено
|
||
|
||
## Симптом
|
||
|
||
При webhook-доставке (Zulip, Telegram через no-edit) текст, который модель генерирует между tool calls (перед tool call, после возврата результата), **не отправлялся промежуточно**. Весь текст накапливался в `_accumulated` и улетал единым куском только на `got_done`. Пользователь видел только tool calls и финальный ответ.
|
||
|
||
## Root Cause
|
||
|
||
В `stream_consumer.py` в `adapter_supports_edit=False` ветке:
|
||
|
||
```python
|
||
# Строка 574 — ДО (баг):
|
||
_has_nl = "\\\\n" in self._accumulated # ищет буквальный \n (2 символа: \ + n)
|
||
|
||
# Строка 581 — ДО (баг):
|
||
_should_send = _has_nl and _can_send # segment_break не отправляет без \n
|
||
|
||
# Строка 591 — ДО (баг):
|
||
_nl_pos = self._accumulated.rfind("\\\\n") # ищет 2 символа вместо 1
|
||
```
|
||
|
||
`"\\\\n"` в Python-файле — это **4 слеша**: Python видит `\\n` (строка из 2 символов: `\` + `n`). А `_accumulated` содержит реальные символы newline (ASCII 10, один символ). Проверка всегда возвращала `False`, поэтому:
|
||
- `_has_nl = False` → `_should_send = False` (даже с `got_segment_break=True`)
|
||
- Текст копился до `got_done`
|
||
|
||
## Фикс
|
||
|
||
```python
|
||
# Строка 574 — ПОСЛЕ:
|
||
_has_nl = "\\n" in self._accumulated # Python escape для newline
|
||
|
||
# Строка 581 — ПОСЛЕ:
|
||
_should_send = _can_send # segment break/got_done всегда отправляют
|
||
|
||
# Строка 591 — ПОСЛЕ:
|
||
_nl_pos = self._accumulated.rfind("\\n") # Python escape для newline
|
||
```
|
||
|
||
## Тесты
|
||
|
||
Новый файл: `tests/gateway/test_stream_consumer_no_edit.py`
|
||
|
||
Три теста:
|
||
1. `test_no_edit_sends_text_across_segment_breaks` — текст с \n, 3 сегмента → 3 sends
|
||
2. `test_no_edit_sends_text_without_newline_on_segment_break` — текст без \n, segment_break → отправляет
|
||
3. `test_no_edit_multiple_segments_are_separate_messages` — 4 сегмента → 4 sends
|
||
|
||
Все 92 существующих теста stream_consumer проходят зелеными.
|
||
|
||
## Верификация
|
||
|
||
После фикса тест с 3x вызова терминала + промежуточные фразы — все сообщения дошли до пользователя.
|