返回 DeepSeek-Reasonix
tool_recovery_barrier.go
根目录 / internal / agent / tool_recovery_barrier.go
1 package agent
2
3 import (
4 "context"
5 "crypto/rand"
6 "errors"
7 "fmt"
8 "reasonix/internal/event"
9 "reasonix/internal/provider"
10 )
11
12 func (a *Agent) emitToolStarted(c provider.ToolCall) error {
13 readOnly := false
14 if t, _, ambiguous := a.svc.tools.ResolveCall(c.Name); t != nil && len(ambiguous) == 0 {
15 readOnly = t.ReadOnly()
16 }
17 ev := event.Tool{ID: c.ID, Name: c.Name, ReadOnly: readOnly, RunState: provider.ToolRunStarted}
18 if c.Recovery != nil {
19 ev.ReadOnly = c.Recovery.ReadOnly
20 ev.AttemptID = c.Recovery.Identity.AttemptID
21 }
22 return event.EmitChecked(a.svc.sink, event.Event{Kind: event.ToolStarted, Tool: ev})
23 }
24
25 func (a *Agent) finishRunRecovery(err *error) {
26 // Uncertain effects are durable facts for the next model turn. They do not
27 // turn an otherwise completed run into a host-level recovery error.
28 }
29 func (a *Agent) checkToolRecoveryStart(ctx context.Context, p *toolCallPlan) (toolOutcome, bool) {
30 if err := a.beginToolRecovery(ctx, p); err != nil {
31 return toolOutcome{runState: provider.ToolRunNotStarted, blocked: true, output: "blocked: " + err.Error(), errMsg: err.Error()}, true
32 }
33 return toolOutcome{}, false
34 }
35 func uncertainToolError(err error) bool {
36 return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)
37 }
38 func recoveryFailureState(err error) provider.ToolRunState {
39 if uncertainToolError(err) {
40 return provider.ToolRunUnknown
41 }
42 return provider.ToolRunFailed
43 }
44 func assignRecoveryCallIDs(calls []provider.ToolCall) error {
45 seen := map[string]bool{}
46 for i := range calls {
47 if calls[i].ID == "" {
48 calls[i].ID = "call_" + rand.Text()
49 }
50 if seen[calls[i].ID] {
51 return fmt.Errorf("provider returned duplicate tool call IDs")
52 }
53 seen[calls[i].ID] = true
54 }
55 return nil
56 }
57
57 lines GO