Skip to content

feat(chat): show specific turn failure reasons in the transcript - #1697

Merged
dcramer merged 5 commits into
mainfrom
feat/dashboard-failure-code-ui
Aug 26, 2026
Merged

feat(chat): show specific turn failure reasons in the transcript#1697
dcramer merged 5 commits into
mainfrom
feat/dashboard-failure-code-ui

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Failed turns in the conversation UI only said the model stopped early. That hid the real failure class and the specific reason.

This change keeps the stable lifecycle failureCode and adds an optional fixed failureReason on failed turns. Model service failures store the provider kind (network, rate_limit, capacity, auth, and so on). Empty or tool-stopped runs store a fixed run class.

The transcript, markdown export, and search render that reason when present. Example titles:

  • Model connection failed
  • Model rate limited
  • Empty model response
  • Internal error

Raw exception text still stays out of the report API.

Requested by David Cramer.

--

View Junior Session [Sentry]

sentry-junior Bot and others added 2 commits August 26, 2026 00:57
Surface the stable privacy-safe failureCode on failed turns so the UI can name the failure type instead of one generic agent error.

Co-Authored-By: David Cramer <david@sentry.io>
Use one report-schema failure code type across the API and transcript UI, and keep failure labels plain.

Co-Authored-By: David Cramer <david@sentry.io>
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview Aug 26, 2026 1:48am

Request Review

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Dashboard visual evidence

Mode: path-selected
Selected: gallery-index, conversations, conversation-detail, conversation-detail-focused

Triggered by:

  • packages/junior-dashboard/src/client/conversations/ConversationTranscript.tsx
  • packages/junior-dashboard/src/client/conversations/TranscriptFailureView.tsx
  • packages/junior-dashboard/src/client/conversations/eventTranscript.ts
  • packages/junior-dashboard/src/client/conversations/transcriptBottomPinning.ts
  • packages/junior-dashboard/src/client/conversations/transcriptFailure.ts
  • packages/junior-dashboard/src/client/conversations/transcriptRenderModel.ts
  • packages/junior-dashboard/src/client/conversations/transcriptSearch.tsx
  • packages/junior-dashboard/src/client/markdownExport.ts

Component gallery index · desktop

Component gallery index · desktop

Conversations · desktop

Conversations · desktop

Conversations · mobile

Conversations · mobile

Conversation detail · desktop

Conversation detail · desktop

Conversation detail · mobile

Conversation detail · mobile

Conversation detail · focused composer · mobile

Conversation detail · focused composer · mobile

Full-page screenshots from the mock dashboard. Not a pixel-diff gate.

@sentry-junior sentry-junior Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answering against the JUNIOR-8T / provider-network spike concerns from the Slack thread:

No — this does not cover those concerns.

This PR is useful on its own axis: it replaces the coarse failureKind (agent | delivery) with stable failureCodes and surfaces them in the transcript, export, and search. That helps the conversation UI name which lifecycle class failed.

What it does not address from that incident:

  1. Upstream stream failure after gateway HTTP 200 — the failing path was stopReason=error on openai/gpt-5.6-sol via AI Gateway, with 3 provider retries, not a dashboard labeling gap.
  2. Sentry diagnosis of provider errorsagent.turn.provider_error still collapses to AI provider error: network and intentionally omits the raw provider errorMessage, so the next spike is still hard to attribute (gateway/model stream vs junior).
  3. Finer failure class inside model executionmodel_execution_failed is still one bucket; it does not distinguish network/stream, capacity, auth, invalid_response, etc.

Ship this if you want better transcript failure UX. For the JUNIOR-8T concerns, the missing piece is still safer provider-error telemetry (and/or fixing the stream path), not dashboard copy.

Store a privacy-safe failureReason on failed turns and render the specific model/provider or execution reason in the transcript.

Co-Authored-By: David Cramer <david@sentry.io>
Share turn failure schemas from history, drop developer jargon from UI copy, and keep provider error kinds owned by the provider boundary.

Co-Authored-By: David Cramer <david@sentry.io>
@sentry-junior sentry-junior Bot changed the title feat(dashboard): show turn failure codes in the transcript feat(chat): show specific turn failure reasons in the transcript Aug 26, 2026
CI typecheck failed because nested failure switches did not prove a return on every path.
@dcramer
dcramer marked this pull request as ready for review August 26, 2026 01:54
@github-actions github-actions Bot added the risk: high PR risk score: high label Aug 26, 2026
@dcramer
dcramer merged commit 48d027a into main Aug 26, 2026
40 checks passed
@dcramer
dcramer deleted the feat/dashboard-failure-code-ui branch August 26, 2026 02:00
dcramer added a commit that referenced this pull request Aug 26, 2026
)

JUNIOR-8T showed `ProviderError: AI provider error: network` after AI
Gateway returned HTTP 200 and the model stream failed. Junior already
classified and retried correctly, but terminal Sentry events and retry
logs dropped the provider cause text. That left the spike looking like a
generic network outage with no way to tell stream-incomplete wording
from a true transport failure.

#1697 improved transcript failure codes and `app.ai.failure_reason`.
That names the lifecycle class. It still does not keep a safe provider
cause string on the provider-error path.

This keeps a short, redacted provider summary on the paths that matter:
- `app.ai.provider_error.summary` on terminal provider-error captures
- the same fields on `agent.turn.provider.retrying`, plus
`app.ai.provider_error.retry_attempt`
- `gen_ai.chat` span attributes/status when `stopReason=error`

Gateway JSON bodies are stripped so telemetry stays free of raw provider
payloads. User-facing copy is unchanged.

This does not stop upstream stream failures. It makes the next
JUNIOR-8T-style spike attributable, including the one-conversation
prompt/history hypothesis.

Evidence: https://sentry.sentry.io/issues/7692564933/

<!-- junior-request-attribution:start -->
Requested by **David Cramer**.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:slack%3AC0B595QDZLL%3A1787705529.828609 -->

--

[View Junior
Session](https://junior-prod.sentry.dev/conversations/slack%3AC0B595QDZLL%3A1787705529.828609)
[[Sentry]](https://sentry.sentry.io/explore/conversations/slack%3AC0B595QDZLL%3A1787705529.828609/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: David Cramer <david@sentry.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant