返回 DeepSeek-Reasonix
tool_recovery_test.go
根目录 / internal / control / tool_recovery_test.go
1 package control
2
3 import (
4 "context"
5 "encoding/json"
6 "strings"
7 "testing"
8
9 "reasonix/internal/agent"
10 "reasonix/internal/event"
11 "reasonix/internal/provider"
12 "reasonix/internal/tool"
13 )
14
15 func TestToolRecoverySnapshotStripsArgumentsAndIsStable(t *testing.T) {
16 const secret = "RECOVERY-ARGUMENT-MUST-STAY-LOCAL"
17 a := agent.New(nil, tool.NewRegistry(), agent.NewSession("system"), agent.Options{}, event.Discard)
18 a.Session().Add(provider.Message{Role: provider.RoleAssistant, ToolCalls: []provider.ToolCall{{ID: "call", Name: "write_file", Arguments: `{"path":"x"}`, Recovery: &provider.ToolCallRecord{Identity: provider.ActionIdentity{AttemptID: "attempt", CallID: "call"}, Arguments: json.RawMessage(`{"content":"` + secret + `"}`), State: provider.ToolRunUnknown}}}})
19 c := newOwnedTestController(t, Options{Executor: a, Sink: event.Discard})
20 s := c.ToolRecoverySnapshot()
21 b, err := json.Marshal(s)
22 if err != nil {
23 t.Fatal(err)
24 }
25 if strings.Contains(string(b), secret) {
26 t.Fatal("snapshot leaked raw recovery arguments")
27 }
28 if len(s.Calls) != 1 || s.Calls[0].Identity.AttemptID != "attempt" {
29 t.Fatalf("snapshot=%+v", s)
30 }
31 if len(s.Calls[0].Arguments) != 0 {
32 t.Fatal("snapshot retained arguments")
33 }
34 if s.Revision == "" {
35 t.Fatal("snapshot revision missing")
36 }
37 if s.Revision != c.ToolRecoverySnapshot().Revision {
38 t.Fatal("unchanged snapshot revision moved")
39 }
40 }
41
42 func TestToolRecoveryActionsAreRetired(t *testing.T) {
43 c := newOwnedTestController(t, Options{Sink: event.Discard})
44 v := c.ToolRecoverySnapshot()
45 v.Revision = "stale"
46 _, err := c.ResolveToolRecovery(context.TODO(), ToolRecoveryRequest{SessionPath: v.SessionPath, RuntimeEpoch: v.RuntimeEpoch, Revision: v.Revision, Action: "confirm"})
47 if err == nil || !strings.Contains(err.Error(), "tool_recovery_retired") {
48 t.Fatalf("err=%v", err)
49 }
50 }
51
51 lines GO