Skip to content

fix(web): keep provider failures visible after the run goes idle - #875

Open
tt-a1i wants to merge 1 commit into
mainfrom
cursor/provider-failure-visible-3251
Open

tt-a1i wants to merge 1 commit into
mainfrom
cursor/provider-failure-visible-3251

Conversation

@tt-a1i

@tt-a1i tt-a1i commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

Fixes #469.

Provider 或限流错误结束一轮之后,Web 会回到普通空闲输入框,失败原因从界面上消失。用户只看到自己的消息和可继续输入的 composer,无法判断任务为什么停、要不要重试或改配置。这和启动前的 prompt_failed 不同:Pi 已经开始模型调用,并把结果记成 stopReason: "error"。

Value

用户能把成功、取消、失败和仍在重试区分开。限流耗尽或 Provider 错误会留下可读原因,直到用户关闭提示或开始下一轮;刷新快照不会把它清掉。已有的部分回答仍留在会话里,转录里的失败记录也继续保留。

Approach

在运行时事件边界记住本轮最后一条 assistant 错误,自动重试失败时用 finalError 覆盖它,但在 turn_settled 且结果为 failed 之前不展示。重试进行中不把最终失败提前画出来。结算后,composer 用 alert 显示这条有界、已脱敏的原因。用户关闭、发送下一条,或下一轮 turn_started 才会把它拿掉。成功结算不会沿用上一轮的失败。

Validation

  • 新增 tests/web/provider-failure-idle.spec.ts。去掉 composer 的失败 alert 后,测试在空闲输入框上找不到失败原因而失败;恢复后通过。断言的是可见的 alert 文本,不是内部标签。
  • 该测试不使用定时器、重试或放宽超时:重试结束前没有失败提示,结算后显示最终的 429 rate limit exhausted 而不是中途的 temporary 502,快照刷新后仍在,关闭后消失,成功轮次不显示,下一轮开始后清除。
  • node node_modules/vitest/vitest.mjs run tests/web/provider-failure-idle.spec.ts tests/web/provider-error.spec.ts tests/web/web-store.spec.ts tests/web/app-render.spec.ts:4 files, 341 passed。
  • node scripts/run-tests.mjs ui:100 files, 1532 passed。
  • bun run check:通过。
  • bun run test 的 Node 套件:2657 passed,1 failed,9 skipped。失败是 tests/extensions/shared/setup-config.test.ts 的 “a waiting setup writer recovers after the lock owner dies”,子进程 stderr 出现了 Node 的 ExperimentalWarning: Type Stripping,与本次 Web 改动无关。Vitest 套件因此没有在同一次 bun run test 里继续,已单独跑完并通过。

Impact

  • 用户可见行为:Provider / 限流失败结束后,composer 保持显示失败原因,直到用户关闭或开始下一轮。转录中的历史失败记录不变。
  • 模型可见上下文 / 工具:无。
  • 运行时 / 生命周期:只在现有 turn 事件上保留失败原因;不改变重试、取消或结算所有权。
  • 持久化配置 / 数据:无。
  • 兼容性 / 风险:turnFailure 只存在于当前页面状态。刷新页面后,失败事实仍由已保存的 assistant 错误消息呈现。
Open in Web Open in Cursor 

A rate-limit or provider error settled back to an ordinary composer with
no failure the user could read. Keep the final reason on screen until the
user dismisses it or starts another turn.

Co-authored-by: tt-a1i <tt-a1i@users.noreply.github.com>
@cursor

cursor Bot commented Oct 16, 2026

Copy link
Copy Markdown

Manual end-to-end check for #469. Both runs used the real openpi web host and a local OpenAI-compatible endpoint. The endpoint returned HTTP 429 or HTTP 502, and Pi exhausted its default retry policy (1 request plus 3 retries, about 2s / 4s / 8s apart) before the turn went idle. No UI state was mocked.

Main (708a44b, before this fix), after the 429 failure. The transcript records the error, and the composer returns to the ordinary idle placeholder with no failure alert:

Main composer after HTTP 429, no failure alert

PR head (e7e360c), after the same 429 failure. The composer keeps “Model request failed” and the rate-limit reason:

PR head composer showing the 429 failure alert

Closing that alert removes it:

PR head composer after the 429 alert is dismissed

A separate message that receives HTTP 502 shows a new alert with the 502 reason, not the earlier 429 text:

PR head composer showing the 502 failure alert

Sending the next message, which the endpoint accepts, clears the alert. The assistant reply is “Manual verification reply.”:

PR head composer after the next successful message clears the alert

This branch has not been deployed

No deployments
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.

bug(web): Provider 运行失败后错误消失,界面没有失败提示

2 participants