返回 DeepSeek-Reasonix
write_recovery.go
根目录 / internal / agent / write_recovery.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "slices"
8 "time"
9
10 "reasonix/internal/event"
11 "reasonix/internal/provider"
12 "reasonix/internal/tool"
13 )
14
15 func (s *Session) addWriteIntent(callID string, raw json.RawMessage) bool {
16 s.mu.Lock()
17 defer s.mu.Unlock()
18 for i := range slices.Backward(s.Messages) {
19 for j, c := range s.Messages[i].ToolCalls {
20 if c.ID != callID {
21 continue
22 }
23 calls := append([]provider.ToolCall(nil), s.Messages[i].ToolCalls...)
24 calls[j].WriteIntents = append(append([]json.RawMessage(nil), c.WriteIntents...), append(json.RawMessage(nil), raw...))
25 s.Messages[i].ToolCalls = calls
26 s.version++
27 s.rewriteVersion++
28 return true
29 }
30 }
31 return false
32 }
33
34 func (a *Agent) withWriteRecovery(ctx context.Context, call provider.ToolCall) context.Context {
35 return tool.WithWriteIntentHook(ctx, func(intent tool.FileWriteIntent) error {
36 raw, err := json.Marshal(intent)
37 if err != nil {
38 return err
39 }
40 if !a.sess.conversation.addWriteIntent(call.ID, raw) {
41 return fmt.Errorf("write intent has no durable tool call: %s", call.ID)
42 }
43 return event.EmitChecked(a.svc.sink, event.Event{Kind: event.Notice, WriteIntent: true})
44 })
45 }
46
47 func (a *Agent) verifyInterruptedWrites(ctx context.Context, r *provider.InterruptedTurnRecovery) *provider.InterruptedTurnRecovery {
48 // Recovery preserves the original execution facts. Current file contents
49 // cannot prove that an earlier call succeeded, and uncertain calls never
50 // become execution barriers or synthetic successes.
51 return r
52 }
53
54 // A terminal length limit can leave syntactically valid but incomplete args.
55 func (a *Agent) recordTruncatedToolResults(ctx context.Context, calls []provider.ToolCall) error {
56 for _, call := range calls {
57 outcome := toolOutcome{output: "error: tool was not executed because the model output reached its length limit; regenerate complete arguments", errMsg: "truncated tool arguments"}
58 committedMessage := a.buildBatchToolResult(ctx, call, outcome)
59 if err := a.emitBatchToolResult(ctx, call, outcome, committedMessage, 0, 0, false, time.Time{}); err != nil {
60 return err
61 }
62 a.sess.conversation.Add(committedMessage)
63 }
64 return nil
65 }
66
66 lines GO