返回 DeepSeek-Reasonix
write_intent_dispatch_test.go
根目录 / internal / agent / write_intent_dispatch_test.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6 "errors"
7 "os"
8 "path/filepath"
9 "testing"
10
11 "reasonix/internal/agent/testutil"
12 "reasonix/internal/event"
13 "reasonix/internal/provider"
14 "reasonix/internal/tool"
15 "reasonix/internal/tool/builtin"
16 )
17
18 func TestPreparedToolContextPreservesDurableWriteIntentHook(t *testing.T) {
19 for _, fail := range []bool{false, true} {
20 name := "checkpoint_success"
21 if fail {
22 name = "checkpoint_failure"
23 }
24 t.Run(name, func(t *testing.T) {
25 root := t.TempDir()
26 target := filepath.Join(root, "written.txt")
27 reg := tool.NewRegistry()
28 for _, w := range builtin.ConfineWriters([]string{root}, builtin.SessionDataGuard{}, builtin.ManagedConfigPaths{}) {
29 if w.Name() == "write_file" {
30 reg.Add(w)
31 }
32 }
33 args, _ := json.Marshal(map[string]string{"path": target, "content": "durable marker"})
34 p := testutil.NewMock("fixture", testutil.Turn{ToolCalls: []provider.ToolCall{{ID: "write", Name: "write_file", Arguments: string(args)}}}, testutil.Turn{Text: "done"})
35 sess := NewSession("")
36 sink := &intentDispatchSink{recordSink: &recordSink{}, target: target, fail: fail}
37 a := New(p, reg, sess, Options{}, sink)
38 _ = a.Run(withNoClosedLoop(context.Background()), "write the marker")
39 if sink.intents != 1 {
40 t.Fatalf("intent hooks=%d", sink.intents)
41 }
42 data, err := os.ReadFile(target)
43 if fail {
44 if !os.IsNotExist(err) {
45 t.Fatalf("checkpoint failure still wrote file: err=%v", err)
46 }
47 } else if err != nil || string(data) != "durable marker" {
48 t.Fatalf("write failed: %v", err)
49 }
50 intents := 0
51 for _, m := range sess.Snapshot() {
52 for _, call := range m.ToolCalls {
53 intents += len(call.WriteIntents)
54 }
55 }
56 if intents != 1 {
57 t.Fatalf("recorded intents=%d", intents)
58 }
59 })
60 }
61 }
62
63 type intentDispatchSink struct {
64 *recordSink
65 target string
66 fail bool
67 intents int
68 }
69
70 func (s *intentDispatchSink) EmitChecked(e event.Event) error {
71 if e.WriteIntent {
72 s.intents++
73 if _, err := os.Stat(s.target); !os.IsNotExist(err) {
74 return errors.New("write started before checkpoint")
75 }
76 if s.fail {
77 return errors.New("injected intent persistence failure")
78 }
79 }
80 s.Emit(e)
81 return nil
82 }
83
83 lines GO