mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
Problem: A refused write can pin a never-executed path through later model requests. Repeated failed restoration can also report success to an expired caller. Root cause: Admission merges every request into the run-retained extent before local preparation succeeds. Call cleanup only decrements in-flight accounting. Resume keeps its once-only result in per-invocation locals, and refused upgrades omit the terminal wait notice after registrar contention. Fix: Track identified provisional calls separately from retained extents and publish their remaining union through the existing claim registrar. Retain before possibly writing hooks or execution. Preserve earlier writes and parallel claims, report failed cleanup conservatively, validate lifetimes before and after reacquisition, and cache terminal callback outcomes. Close registrar waits on refusal and clear completed cleanup's wait state. Verification: Complete 238-package inventory and required builtin/boot pass on the final source; full workspacelease/agent race and focused real boot race pass. Compiling original execution, resume and upgrade-wait owners fail the selected deterministic regressions. Formatting, vet, lint and check pass. Local platform evidence is macOS only; hosted checks and review are separate. Refs #14025 Refs #14133
81 lines
2.5 KiB
Go
81 lines
2.5 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"reasonix/internal/contract/event"
|
|
"reasonix/internal/contract/tool"
|
|
"reasonix/internal/runtime/writeclaim"
|
|
"reasonix/internal/state/workspacelease"
|
|
)
|
|
|
|
func (a *Agent) workspaceWritePaths(plan *toolCallPlan) []string {
|
|
if toolHooksMayMutateWorkspace(a.svc.hooks) || plan.runTool == nil {
|
|
return nil
|
|
}
|
|
if !tool.WritesNamedPaths(plan.runTool) {
|
|
return nil
|
|
}
|
|
writer, ok := plan.runTool.(tool.WritePathResolver)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
paths, err := writer.WritePaths(plan.runArgs)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return paths
|
|
}
|
|
|
|
func workspaceLeaseConflictScope(err error) *event.WorkspaceLease {
|
|
var conflict *workspacelease.ConflictError
|
|
if !errors.As(err, &conflict) {
|
|
return nil
|
|
}
|
|
return &event.WorkspaceLease{Holder: conflict.Holder, HolderSessionID: conflict.SessionID,
|
|
Paths: conflict.Paths, RequestedPaths: conflict.RequestedPaths, Repository: conflict.Repository}
|
|
}
|
|
|
|
func workspaceLeaseRefusalCode(err error) string {
|
|
if errors.Is(err, workspacelease.ErrClaimTimeout) {
|
|
return workspacelease.CodeClaimTimeout
|
|
}
|
|
if errors.Is(err, workspacelease.ErrConflict) {
|
|
return workspacelease.CodeWriteConflict
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (a *Agent) parentToolWriteReservation(writer tool.Tool, args json.RawMessage) (writeclaim.WritePathSet, error) {
|
|
if resolver, ok := writer.(tool.WritePathResolver); ok {
|
|
paths, err := resolver.WritePaths(args)
|
|
if err != nil {
|
|
return writeclaim.WholeWorkspaceWriteClaim(a.writeWorkspaceRoot)
|
|
}
|
|
return parentResolvedWriteReservation(a.writeWorkspaceRoot, paths)
|
|
}
|
|
return parentWriteReservation(a.writeWorkspaceRoot, writer.Name(), args)
|
|
}
|
|
|
|
// holdWorkspaceLease provisionally claims paths before local preparation.
|
|
// Only entry into writing hooks or execution retains them for the run.
|
|
func (a *Agent) holdWorkspaceLease(ctx context.Context, plan *toolCallPlan) (context.Context, toolOutcome, bool) {
|
|
if !plan.mutates || a.svc.workspaceLease == nil {
|
|
return ctx, toolOutcome{}, false
|
|
}
|
|
heldCtx, preparation, err := a.svc.workspaceLease.PreparePaths(ctx, a.workspaceWritePaths(plan))
|
|
if err != nil {
|
|
return ctx, toolOutcome{
|
|
output: fmt.Sprintf("blocked: %v", err),
|
|
blocked: true,
|
|
errMsg: "blocked: workspace write lease unavailable",
|
|
refusalCode: workspaceLeaseRefusalCode(err),
|
|
workspaceLease: workspaceLeaseConflictScope(err),
|
|
}, true
|
|
}
|
|
plan.leasePreparation = preparation
|
|
return heldCtx, toolOutcome{}, false
|
|
}
|