Skip to content

fix: an unusable reply's error names the provider's finish reason - #741

Merged
tgockel merged 1 commit into
version/0.3.xfrom
fix/721-failure-causes-shown
Oct 28, 2026
Merged

tgockel merged 1 commit into
version/0.3.xfrom
fix/721-failure-causes-shown

Conversation

@tgockel

@tgockel tgockel commented Oct 27, 2026

Copy link
Copy Markdown
Owner

A reply the provider ended with finish_reason: "content_filter" and no content read only as rig's "Response contained no message or tool call (empty)". RetryingModel passed rig's ResponseError through unchanged, and the retry line, model.attempt.error, model.retry.error, the failover's error, model.round.failed.error and run-new's [outrig] error: line are all made from it. RetryingModel::attempt now puts the finish reason the answered body names first in that message -- finish reason content_filter: Response contained ... -- first so the status line's 60 characters keep it.

The page and the screen also showed less than the events carry:

  • render-session.py names an attempt's finish reason, says a failed one failed, and opens the error of an attempt, a retry and a move. A field a handler does not read is shown as a collapsed part named for it, so a field added later is not dropped unseen; a handler marks what it leaves off on purpose with Read.leave. Retries and moves now show their call and attempt ids, and a round its total and descendants.
  • run-new's status line names the model a call moved from and why, until the model it moved to answers. An unfamiliar event's failure fields are taken out of its JSON before the 400-character cut and shown whole, so a hosted call's traceback is not cut. A child agent's failed round is a detail entry naming the child, and model.usage.refused is shown as an unfamiliar kind.
  • Line mode prints the notes the screen puts in the conversation, through the same code, which adds a bindings process's exit cause.

The issue asked for a test that fails when a new failure field is not shown. In outrig-cli the events are #[non_exhaustive], so no test there can notice a new field, and there is none; on the page the fallback covers it instead. A failed attempt gets no screen line of its own: the retry, move or failed round that follows it carries the same text.

outrig run's copy of the retry layer never holds the body, so its text is unchanged; plan/next/outrig-run-names-the-finish-reason.md has the work.

Fixes #721

Summary

What does this change, and why?

Checklist

  • cargo fmt --all -- --check passes
  • cargo clippy --workspace --all-targets -- -D warnings is clean
  • cargo test --workspace passes
  • Docs in doc/ updated if behavior changed (mdbook build still clean)
  • CHANGELOG updated for user-visible changes

Notes for reviewers

Anything worth calling out -- tricky bits, follow-ups, or intentionally out-of-scope items.

A reply the provider ended with `finish_reason: "content_filter"` and
no content read only as rig's "Response contained no message or tool
call (empty)". RetryingModel passed rig's ResponseError through
unchanged, and the retry line, `model.attempt.error`,
`model.retry.error`, the failover's error, `model.round.failed.error`
and run-new's `[outrig] error:` line are all made from it.
`RetryingModel::attempt` now puts the finish reason the answered body
names first in that message -- `finish reason content_filter: Response
contained ...` -- first so the status line's 60 characters keep it.

The page and the screen also showed less than the events carry:

- render-session.py names an attempt's finish reason, says a failed one
  failed, and opens the error of an attempt, a retry and a move. A field
  a handler does not read is shown as a collapsed part named for it, so
  a field added later is not dropped unseen; a handler marks what it
  leaves off on purpose with `Read.leave`. Retries and moves now show
  their call and attempt ids, and a round its total and descendants.
- run-new's status line names the model a call moved from and why,
  until the model it moved to answers. The `model.call` that sends that
  model the call has the move's call id, so it keeps the move; another
  call's clears it. An unfamiliar event's failure
  fields are taken out of its JSON before the 400-character cut and
  shown whole, so a hosted call's traceback is not cut. A child agent's
  failed round is a detail entry naming the child, and
  `model.usage.refused` is shown as an unfamiliar kind.
- Line mode prints the notes the screen puts in the conversation,
  through the same code, which adds a bindings process's exit cause.

The issue asked for a test that fails when a new failure field is not
shown. In outrig-cli the events are #[non_exhaustive], so no test there
can notice a new field, and there is none; on the page the fallback
covers it instead. A failed attempt gets no screen line of its own: the
retry, move or failed round that follows it carries the same text.

`outrig run`'s copy of the retry layer never holds the body, so its
text is unchanged; plan/next/outrig-run-names-the-finish-reason.md has
the work.

Fixes #721
@tgockel
tgockel force-pushed the fix/721-failure-causes-shown branch from 556aafd to b4c5c91 Compare October 28, 2026 00:41
@tgockel
tgockel merged commit b4c5c91 into version/0.3.x Oct 28, 2026
9 of 11 checks passed
@tgockel
tgockel deleted the fix/721-failure-causes-shown branch October 28, 2026 01:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant