Skip to content

§5 user-facing failure guidance: drive chat error-card CTA from structured user_action (#3408) #4734

Description

@maoxin1234

Why

Part of the reliability epic #3408. The daemon now emits a canonical failure classification on run_finished (failure_category / failure_stage / retryable / user_action, via run-failure-classification.ts from #4431), and §3 safe-retry already consumes retryable. But the web error card still maps its CTA off the raw error_code (apps/web/src/runtime/amr-guidance.ts resolveRunFailureUi()), so the canonical user_action the daemon already decided is ignored. New classes (prompt_too_large -> reduce_context, model_unavailable -> switch_model, rate_limit -> retry-vs-switch, upstream_unavailable -> retry) do not drive a matching CTA. This is the last open proposal piece (§5) under #3408; §3 is confirmed done.

What users will see

Failed-run error cards show a CTA that matches the actual failure reason — e.g. "reduce context" for an over-large prompt, "switch model" for an unavailable model, "recharge" for AMR balance — instead of a generic retry/authorize derived from a coarse error code.

Proposal

  1. resolveRunFailureUi() prefers the structured user_action from run_finished when present and maps it to the CTA at one choke point (login / recharge / retry / switch_model / reduce_context / install_cli / none), reusing the existing AMR promote path. CTA is driven by user_action, not re-derived from failure_category (trust the daemon decision; avoid the two layers diverging). failure_category is used for display only.
  2. Fallback chain: when user_action is absent or none, fall through to the existing error_code map so older/unclassified runs — and partially-classified runs (category present, action unresolved) — still render a real CTA rather than a blank one.
  3. Tests: resolver covered against every failure_category / user_action (mirroring the daemon classifier test as fixture source-of-truth); a classified run beats the raw-code map; an unclassified run still resolves via fallback; and the partial-classification edge (category set, user_action = none / absent -> reaches the error_code map, no blank CTA).

Scope is UI-side only; daemon classification and retry layers are untouched.

Relates to #3408.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions