Files
LineWalker 7050b7d165 fix(linsight): bound write_file truncation loop with tool-loop breaker + salvage
Root cause: a large write_file `content` arg is truncated (finish_reason=length)
before its bytes are emitted, so parse_partial_json drops the key and every retry
re-raises "content: Field required", spinning to recursion_limit=200 (~19min). Not
a model-can't-count-2-args problem — the huge tool argument gets cut off/parsed away.

- L2: detect finish_reason=length + a truncated tool call in the resilience
  middleware, nudge to write in smaller parts, bounded retry (truncation_retry_limit).
- L3: new LinsightToolLoopBreakerMiddleware — soft corrective hint then hard stop
  (aafter_model raises LinsightToolLoopError) on consecutive same-tool failures,
  with guards against aborting a model that recovered / switched tools.
- L4: classify GraphRecursionError / LinsightToolLoopError as TASK_ABORTED.
- Salvage: _handle_task_partial renders the intermediate analysis + retrieved
  knowledge as a normal (COMPLETED) result instead of a raw recursion error;
  shared across the fresh/resume/continue drivers via _stash_partial_abort.
- Config (LinsightConf): tool_failure_soft_limit=3 / tool_failure_hard_limit=8 /
  truncation_retry_limit=2.

72 unit tests + 1 integration test (aafter_model raise propagates through a real
create_agent().ainvoke(), beating recursion_limit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 17:32:12 +08:00
..