Skip to content

v0.9.24

@evalstate evalstate tagged this 25 Jul 11:51
* improve error logging; tool loop defaults

* version bump

* enhance logging

* x_search option

* improve SSE handling

* style: apply ruff format across the repo

The CI "format check" job ran `scripts/format.py`, which invokes the writing
form of `ruff format` rather than `--check`. It rewrote files in the ephemeral
checkout and always exited 0, so formatting drifted while the job stayed green.

This commit is the resulting sweep, with no functional change: every file here
parses to an identical AST before and after (173/173 verified with ast.dump).
Files that also carry hand edits are formatted in their own commits.

* feat(llm): stream diagnostics on the chat-completions path

Stream timing was collected for every provider using the idle-timeout wrapper
but only consumed by the Responses transport, so chat-completions models
(HuggingFace routes included) produced none of it. A GLM-5.2 benchmark run hit a
mid-stream TransferEncodingError and the retry telemetry could only report
`stream_events_received: null`, which hides whether a truncated stream died
early or nearly complete.

- move `stream_timing_payload` into streaming_timeouts so both transports share
  one formatter, replacing the private copy in responses.py
- report extended inter-event gaps and include stream timing in the idle-timeout
  error on the chat-completions path
- record how far a failed stream got for any mid-stream failure, not just idle
  timeouts, and surface it through the existing fast-agent-retry channel; the
  count is reset per attempt so it cannot leak between retries
- wire the same recording into the Responses SSE and websocket transports
- fix the retry notice, which showed "Attempt 1/2" while the telemetry for the
  same event said `max_attempts: 3`; retry_count counts retries, so total
  attempts is retry_count + 1, as the webdebug line already had it

* fix(llm): recover empty Responses payloads and report iteration limits

Work in progress that was already in the tree, committed as its own change.

- rebuild `output` from completed stream items when a terminal Responses payload
  arrives empty, shared across the SSE, OpenResponses and websocket transports
- add an explicit MAX_ITERATIONS stop reason so an exhausted tool loop is warned
  about and displayed rather than ending silently, mapped to the ACP
  `max_turn_requests` stop reason
- raise the default streaming idle timeout from 90s to 120s
- extract `flatten_event_data` so the console, file and HTTP log sinks all lift a
  nested `data=` payload consistently

* ci: make the format check actually check

`scripts/format.py` only had the writing form of `ruff format`, so the CI job
named "Run ruff format check" rewrote files in its checkout and could never fail.
Add `--check` and use it in CI.

Also drop `from rich import print` from the lint, format and typecheck scripts.
They used it to print a single unmarked-up error line, and pulling rich in
transitively via typer meant an unrelated rich problem could take out the whole
lint and typecheck gate.

* test: bound tool loop construction smoke test
Assets 2
Loading