Record tool intent before execution and add file checkpoints
ci / vet-and-test (pull_request) Successful in 46s
ci / docker-checkout-hostgateway (pull_request) Successful in 1s

Why: a crash after a tool was about to run left the call unpaired, and workspace writes could not be rewound.
Evidence: GOWORK=off go test ./runtime/ ./runtime/llm/ ./runtime/checkpoint/ ./runtime/telemetry/ ./runtime/tools/ ./runtime/session/ ./adapters/native/
Impact: pending calls rerun only when both the stored and current replay declarations are safe; otherwise the result is an error. Empty fallback lists and a nil checkpoint log keep the previous behavior.
Refs: feature/durable-rewind
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-03 17:27:04 +00:00
co-authored by Cursor
parent ba90a7d9ae
commit fb2b3b796c
17 changed files with 1138 additions and 21 deletions
+14 -8
View File
@@ -14,6 +14,7 @@ import (
"agent-native/exec"
"agent-native/runtime"
"agent-native/runtime/checkpoint"
"agent-native/runtime/filestate"
"agent-native/runtime/hooks"
"agent-native/runtime/llm"
@@ -39,13 +40,15 @@ type ModelOptions struct {
// ToolOptions 是可选工具装配。nil 字段不注册对应工具。
type ToolOptions struct {
Search tools.SearchProvider
Exec *tools.ExecConfig
Fetch *tools.FetchConfig
MCP *mcp.Manager
SkillsRoots []string
Subagent subagent.Factory
HostTools []tools.Tool
Search tools.SearchProvider
Exec *tools.ExecConfig
Fetch *tools.FetchConfig
MCP *mcp.Manager
SkillsRoots []string
Subagent subagent.Factory
HostTools []tools.Tool
Checkpoints *checkpoint.Log
CheckpointAnchor func() string
}
// SessionOptions 是单次执行的会话预算与压缩。
@@ -58,6 +61,8 @@ type SessionOptions struct {
type ObserveOptions struct {
Log *logsys.Logger
ExecutionID string
// Trace 交给运行循环。nil 不采集。
Trace func(name string, attrs map[string]string) func()
}
// GateOptions 把直连已经使用的停止、提醒和工具钩子交给小队成员。零值不改变行为。
@@ -184,7 +189,7 @@ func (b *Backend) Execute(ctx context.Context, req exec.Request) (*exec.Result,
var reg *tools.Registry
if profile == exec.ToolProfileWorkspace {
reg = tools.WorkspaceToolsTracked(workDir, filestate.New())
reg = tools.WorkspaceToolsCheckpointed(workDir, filestate.New(), b.opts.Checkpoints, b.opts.CheckpointAnchor)
skills.RegisterLoader(reg, skillStore)
if b.opts.Search != nil {
tools.RegisterSearch(reg, b.opts.Search)
@@ -348,6 +353,7 @@ func (b *Backend) run(ctx context.Context, model string, budget *runtime.Budget,
Reminders: b.opts.Reminders,
RepeatGuard: b.opts.RepeatGuard,
Hooks: gateBus(b.opts.GateOptions),
Trace: b.opts.Trace,
OnEvent: func(ev runtime.Event) {
logs.WriteString(ev.Type)
if ev.Tool != "" {