feat(runtime): resume interrupted runs safely instead of parking them
- Dominant language
- TypeScript
- Stars
- 5.4k
- Forks
- 502
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 715
Description
Recovery classification is precise, but everything it learns is discarded at the UI.
`resolveRuntimeRecovery` distinguishes `completed` / `parked` / `definitely_not_dispatched` / `indeterminate` / `corruption`, and `buildResumePlanFromRuntimeEvents` turns any unresolved operation — including nested calls the model never sees — into `disposition: 'blocked'`. `runtime-kernel.ts:3107` then refuses to replay. That part is right: an unproven tool boundary must not be replayed silently.
What happens next is not. `runtime-resume-copy.ts` carries **30 distinct park reasons**, each with its own message, and `use-shell-resume.ts:67` collapses all of them into one error toast — "暂时无法继续这一轮" — with the action slot left `undefined`. The user is told the run cannot continue and is given nothing to do about it.
Failing loud is correct. Stopping there is not. **An agent's job is to finish the task**, not to hand the user an accurate error and let them figure it out.
What this should become:
1. **Resume automatically whenever it is provably safe.** `definitely_not_dispatched` already proves a tool never ran — those should replay without asking anyone.
2. **For `indeterminate`, verify instead of giving up.** We know which tool, which arguments, and which operation is unsettled. Checking the external state is often cheap and decidable.
3. **Ask the user only when verification is genuinely impossible**, and then ask about the specific operation — not with a generic toast, but with the choices that matter: I checked, continue / discard this turn / let me look first.
The classification data needed for all three already exists. Only the path from a decision to a user-visible resolution is missing.
Related: the rejection reasons are also flattened before they reach any of this — see #4423.
---
@M4n5ter @likun666661 — I'd like your read on this before anyone starts.
My position: failing loud is right, and I don't want to give that up. But stopping at "here is an accurate error, you figure it out" is not a defensible product state. **An agent exists to finish the task.** The recovery classification already tells us which operations are provably safe and which are genuinely unknown; we should be replaying the first group automatically and actively verifying the second, and only asking the user when verification is truly impossible.
Where I'm unsure is the middle step — what verifying external state should mean in general, given that the recovery ADR explicitly declines to derive absolute external-world state. Happy to be pushed back on any of it.
简体中文
恢复判定做得很精细,但它得出的结论在 UI 层被丢掉了。
`resolveRuntimeRecovery` 能区分 `completed` / `parked` / `definitely_not_dispatched` / `indeterminate` / `corruption`,任何未结算的操作(包括模型看不见的嵌套调用)都会让计划变成 `blocked`,`runtime-kernel.ts:3107` 随即拒绝回放。这部分是对的:不能证明终态的工具边界不该被静默重放。
问题在下一步。`runtime-resume-copy.ts` 里有 **30 种不同的 park 原因**,各有各的文案,而 `use-shell-resume.ts:67` 把它们全部收敛成一个 error toast「暂时无法继续这一轮」,action 位是 `undefined`。用户被告知不能继续,然后没有任何可做的事。
Fail loud 是对的,停在这里不对。**Agent 的价值是完成任务**,不是把一个准确的错误丢给用户,让用户自己想办法。
应该变成:
1. **能证明安全就自动续跑。** `definitely_not_dispatched` 已经证明工具没执行过,这类根本不需要问任何人。
2. **`indeterminate` 应该去核实,而不是放弃。** 我们知道是哪个工具、什么参数、哪个操作没结算,去检查外部状态往往成本很低且能得出结论。
3. **只有确实无法核实时才问用户**,而且要针对那个具体操作问,给出真正有意义的选项:我确认过了继续 / 放弃这一轮 / 我先看看。
这三步需要的判定数据都已经有了,缺的只是从判定到用户侧结论的那条路径。
@M4n5ter @likun666661 —— 想先听听你们的看法再动手。
我的立场:fail loud 是对的,这点不想放弃。但停在「给你一个准确的错误,你自己想办法」不是一个站得住的产品状态。**Agent 的存在就是为了完成任务。** 恢复判定已经能告诉我们哪些操作可证明安全、哪些是真的未知;前者应该自动重放,后者应该主动核实,只有确实无法核实时才问用户。
我不确定的是中间那一步 —— 「核实外部状态」在通用意义上到底该是什么,毕竟 recovery ADR 明确声明不承诺推导外部世界的绝对状态。欢迎在任何一点上反驳。
Contributor guide
Research direction
Trace resolveRuntimeRecovery and buildResumePlanFromRuntimeEvents into runtime-kernel.ts:3107, then follow runtime-resume-copy.ts and use-shell-resume.ts:67. Compare how each recovery classification and park reason reaches the UI, including the flattened rejection reasons in #4423. Done means safe non-dispatched work resumes automatically, indeterminate operations are handled through a defined verification path, and genuinely unverifiable cases expose operation-specific user choices.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- ai, backend, desktop
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100