返回 DeepSeek-Reasonix
delegation_origin_test.go
根目录 / internal / agent / delegation_origin_test.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6 "testing"
7
8 "reasonix/internal/event"
9 "reasonix/internal/evidence"
10 "reasonix/internal/provider"
11 "reasonix/internal/tool"
12 )
13
14 type originProbe struct {
15 event.Sink
16 got []evidence.DelegationAudit
17 }
18
19 func (p *originProbe) RecordDelegationAudit(a evidence.DelegationAudit) { p.got = append(p.got, a) }
20
21 // runDelegationForOrigin spawns one real child through TaskTool that reads
22 // src/parser.go and src/scanner.go, and returns the audit the sink received.
23 func runDelegationForOrigin(t *testing.T, prompt string) evidence.DelegationAudit {
24 t.Helper()
25 probe := &originProbe{Sink: event.Discard}
26 reg := tool.NewRegistry()
27 reg.Add(fakeReadFileTool{})
28 prov := &scriptedProvider{name: "p", turns: [][]provider.Chunk{
29 {toolCallChunk("1", "read_file", `{"path":"src/parser.go"}`), {Type: provider.ChunkDone}},
30 {toolCallChunk("2", "read_file", `{"path":"src/scanner.go"}`), {Type: provider.ChunkDone}},
31 {{Type: provider.ChunkText, Text: "done"}, {Type: provider.ChunkDone}},
32 }}
33 task := NewTaskTool(prov, nil, reg, 20, 0, 0, 0, 0, 0, 0, 0.0, "", "sys", nil, 0, "", "", nil).
34 WithTranscripts(mustSubagentStore(t), t.TempDir(), "base", "high").
35 WithScheduler(NewSubagentScheduler(4, 4))
36 ctx := withCallContext(context.Background(), "call-1", probe, nil, false)
37 args, err := json.Marshal(map[string]string{"prompt": prompt})
38 if err != nil {
39 t.Fatal(err)
40 }
41 if _, err := task.Execute(ctx, args); err != nil {
42 t.Fatalf("task: %v", err)
43 }
44 if len(probe.got) != 1 {
45 t.Fatalf("got %d audits through the TaskTool path, want 1", len(probe.got))
46 }
47 return probe.got[0]
48 }
49
50 // A delegation that hands over no location leaves the child to find every file
51 // it reads. This is the number blind delegation would have to hold at zero.
52 func TestDelegationAuditScoresBlindDelegationAsFullyDiscovered(t *testing.T) {
53 audit := runDelegationForOrigin(t, "Determine why the failing test fails.")
54 if audit.ParentNamedFiles != 0 {
55 t.Errorf("ParentNamedFiles = %d, want 0", audit.ParentNamedFiles)
56 }
57 if audit.EvidencePaths != 2 || audit.DiscoveredPaths != 2 {
58 t.Errorf("discovered %d/%d, want 2/2", audit.DiscoveredPaths, audit.EvidencePaths)
59 }
60 }
61
62 // The parent's own text is the only channel that can leak a location, so a
63 // prompt naming one file must show up as a hint and cost the child credit for
64 // the evidence it did not have to find.
65 func TestDelegationAuditCreditsOnlyWhatTheChildFoundItself(t *testing.T) {
66 audit := runDelegationForOrigin(t, "The bug is in src/parser.go — confirm it.")
67 if audit.ParentNamedFiles != 1 {
68 t.Errorf("ParentNamedFiles = %d, want 1", audit.ParentNamedFiles)
69 }
70 if audit.EvidencePaths != 2 || audit.DiscoveredPaths != 1 {
71 t.Errorf("discovered %d/%d, want 1/2", audit.DiscoveredPaths, audit.EvidencePaths)
72 }
73 }
74
74 lines GO