返回 DeepSeek-Reasonix
prose_mutation_scope_test.go
根目录 / internal / agent / prose_mutation_scope_test.go
1 package agent
2
3 import (
4 "context"
5 "sync/atomic"
6 "testing"
7
8 "reasonix/internal/agent/testutil"
9 "reasonix/internal/event"
10 "reasonix/internal/provider"
11 "reasonix/internal/tool"
12 )
13
14 func runOneWrite(t *testing.T, input string, planMode bool) (int32, string) {
15 t.Helper()
16 var calls int32
17 reg := tool.NewRegistry()
18 reg.Add(fakeTool{name: "write_file", calls: &calls})
19 mp := testutil.NewMock("m",
20 testutil.Turn{ToolCalls: []provider.ToolCall{{ID: "w1", Name: "write_file", Arguments: `{"path":"backend/login.go","content":"package backend"}`}}},
21 testutil.Turn{Text: "done"},
22 )
23 a := New(mp, reg, NewSession(""), Options{}, event.Discard)
24 a.SetPlanMode(planMode)
25 if err := a.Run(withNoClosedLoop(context.Background()), input); err != nil {
26 t.Fatalf("Run: %v", err)
27 }
28 return atomic.LoadInt32(&calls), lastToolResult(a.Session(), "write_file")
29 }
30
31 // The user's prose reaches the model as an instruction; only plan mode is a
32 // host-enforced read-only switch.
33 func TestUserProseDoesNotBanWritesForTheTurn(t *testing.T) {
34 for _, input := range []string{
35 "按方案实现登录模块,数据库结构不要改。",
36 "帮我新建登录模块的前后端文件,其他不要改",
37 "实现登录功能。接口不要修改",
38 "Implement login. The schema: do not modify",
39 "Do not modify anything else.",
40 "只分析支付流程。",
41 } {
42 t.Run(input, func(t *testing.T) {
43 calls, result := runOneWrite(t, input, false)
44 if calls != 1 {
45 t.Fatalf("write_file executed %d times, want 1; result=%q", calls, result)
46 }
47 })
48 }
49 }
50
51 func TestPlanModeStillBlocksWrites(t *testing.T) {
52 calls, result := runOneWrite(t, "实现登录功能", true)
53 if calls != 0 {
54 t.Fatalf("write_file executed %d times in plan mode, want 0; result=%q", calls, result)
55 }
56 }
57
57 lines GO