fix(worker): убрать limits.turns — стоп без текста, дайджесты пустели
Репродукция: мин-тик с реальным контекстом → модель (auto/low effort)
каждый ход делала tool-вызов, никогда не выдавая чистый текст;
limits={'turns': 15} обрывал цикл на границе хода, result.message
оставался toolResult-сообщением → str(result)='' → DigestWritten len 0.
limit_turns — нативный стоп SDK, но он не кладёт в историю итоговый
ассистентский текст. Наш end_turn (AfterToolsEvent) кладёт: дайджест
не пустеет. Защита от таймаутов остаётся двойной: cancel_tool на
вызовы сверх лимита + end_turn после партии.
E2E-подтверждение: тот же промпт, stop_reason=end_turn, текст 465
символов ('Тик чистый. Проверил: ...').
This commit is contained in:
parent
1b8c27b292
commit
2d70740e76
3 changed files with 13 additions and 15 deletions
|
|
@ -123,9 +123,11 @@ sqlite, rag.db ~12.5k чанков по контексту/навыкам, herme
|
||||||
Защита в `_llm_worker`: `BeforeToolCallEvent.cancel_tool` отменяет
|
Защита в `_llm_worker`: `BeforeToolCallEvent.cancel_tool` отменяет
|
||||||
вызова сверх лимита, `AfterToolsEvent.end_turn` останавливает цикл
|
вызова сверх лимита, `AfterToolsEvent.end_turn` останавливает цикл
|
||||||
агента ПОСЛЕ партии инструментов (без него модель шлёт шаги снова —
|
агента ПОСЛЕ партии инструментов (без него модель шлёт шаги снова —
|
||||||
e2e: 20 отмен подряд), `limits={"turns": N}` — нативный кап ходов SDK.
|
e2e: 20 отмен подряд), кладя в историю ассистентский текст-итог.
|
||||||
Лимиты: `SIMBIOT_MAX_TOOL_CALLS` (по умолчанию 30, счёт по реальным
|
Нативный `limits={"turns": N}` НЕ используется: стоп на границе хода
|
||||||
исполнениям), `SIMBIOT_MAX_TURNS` (по умолчанию 15).
|
оставляет `result.message` = toolResult → пустой дайджест (04:18+).
|
||||||
|
Лимит: `SIMBIOT_MAX_TOOL_CALLS` (по умолчанию 30, счёт по реальным
|
||||||
|
исполнениям).
|
||||||
|
|
||||||
## Дашборд задач
|
## Дашборд задач
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,16 +238,16 @@ def main():
|
||||||
)
|
)
|
||||||
agent = _wire_trace_hooks(agent, es, trace_id)
|
agent = _wire_trace_hooks(agent, es, trace_id)
|
||||||
agent = _wire_budget_hooks(agent, level, trace_id)
|
agent = _wire_budget_hooks(agent, level, trace_id)
|
||||||
# хард-кап шагов (e-260930031800): двойная защита.
|
# хард-кап шагов (e-260930031800): cancel_tool + end_turn.
|
||||||
# 1) limits={"turns": N} — нативный механизм SDK: цикл агента
|
# ВАЖНО: НЕ используем limits={"turns": N} — нативный стоп SDK
|
||||||
# останавливается на границе хода (stop_reason="limit_turns"),
|
# обрывает цикл на границе хода, и result.message остаётся
|
||||||
# модель не может уйти в бесконечную цепочку tool-вызовов.
|
# toolResult-сообщением → str(result)='' → пустой дайджест
|
||||||
# 2) хук cancel_tool — страховка на случай параллельного блока
|
# (репродукция: stop_reason=limit_turns, text='', тики 04:18+).
|
||||||
# (20 вызовов одним блоком: turns их не режет, хук отменяет).
|
# Наш end_turn (AfterToolsEvent) кладёт в историю ассистентский
|
||||||
max_turns = int(os.environ.get("SIMBIOT_MAX_TURNS") or 15)
|
# текст с итогом — дайджест не пустеет.
|
||||||
agent = _wire_tool_budget(
|
agent = _wire_tool_budget(
|
||||||
agent, int(os.environ.get("SIMBIOT_MAX_TOOL_CALLS") or 30))
|
agent, int(os.environ.get("SIMBIOT_MAX_TOOL_CALLS") or 30))
|
||||||
result = agent(payload.get("prompt", ""), limits={"turns": max_turns})
|
result = agent(payload.get("prompt", ""))
|
||||||
usage = _extract_usage(agent)
|
usage = _extract_usage(agent)
|
||||||
_emit(payload, {"ok": True, "text": str(result), "usage": usage, "trace_id": trace_id})
|
_emit(payload, {"ok": True, "text": str(result), "usage": usage, "trace_id": trace_id})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,6 @@ os.environ["SIMBIOT_MAX_TOOL_CALLS"] = "7"
|
||||||
check("budget: env SIMBIOT_MAX_TOOL_CALLS читается",
|
check("budget: env SIMBIOT_MAX_TOOL_CALLS читается",
|
||||||
int(os.environ.get("SIMBIOT_MAX_TOOL_CALLS") or 30) == 7)
|
int(os.environ.get("SIMBIOT_MAX_TOOL_CALLS") or 30) == 7)
|
||||||
del os.environ["SIMBIOT_MAX_TOOL_CALLS"]
|
del os.environ["SIMBIOT_MAX_TOOL_CALLS"]
|
||||||
os.environ["SIMBIOT_MAX_TURNS"] = "15"
|
|
||||||
check("budget: env SIMBIOT_MAX_TURNS читается",
|
|
||||||
int(os.environ.get("SIMBIOT_MAX_TURNS") or 15) == 15)
|
|
||||||
del os.environ["SIMBIOT_MAX_TURNS"]
|
|
||||||
|
|
||||||
# ── 5. реальные strands-хуки: create_harness + add_hook не падают ──
|
# ── 5. реальные strands-хуки: create_harness + add_hook не падают ──
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue