返回 DeepSeek-Reasonix
delegation_admission_test.go
根目录 / internal / agent / delegation_admission_test.go
1 package agent
2
3 import (
4 "testing"
5
6 "reasonix/internal/event"
7 "reasonix/internal/provider"
8 )
9
10 func TestDelegationAdmissionVerdicts(t *testing.T) {
11 cases := []struct {
12 name, input, args, verdict, reason string
13 }{
14 {"local fix, plain query", "fix the config serializer bug in parser.go",
15 `{"prompt":"how does the serializer format keys"}`, "allow", "model_decides"},
16 {"user asked for research", "research the best TOML library and fix the loader",
17 `{"prompt":"compare toml libraries"}`, "allow", "model_decides"},
18 {"external source cited", "fix the retry logic to match the upstream spec",
19 `{"prompt":"read https://example.com/spec and summarize backoff rules"}`, "allow", "model_decides"},
20 {"advisory turn", "how does our retry budget compare to industry practice?",
21 `{"prompt":"survey retry budget conventions"}`, "allow", "model_decides"},
22 }
23 for _, c := range cases {
24 verdict, reason, _ := delegationAdmission(c.input, c.args)
25 if verdict != c.verdict || reason != c.reason {
26 t.Errorf("%s: got %s/%s, want %s/%s", c.name, verdict, reason, c.verdict, c.reason)
27 }
28 }
29 }
30
31 type admissionSink struct {
32 audits []event.DelegationAdmissionAudit
33 }
34
35 func (s *admissionSink) Emit(event.Event) {}
36 func (s *admissionSink) RecordDelegationAdmission(a event.DelegationAdmissionAudit) {
37 s.audits = append(s.audits, a)
38 }
39
40 func TestObserveDelegationAdmissionRecordsOnlyGatedTools(t *testing.T) {
41 sink := &admissionSink{}
42 a := &Agent{svc: agentServices{sink: sink}}
43 a.turn.recoveryTaskSummary = "fix the failing date parser"
44 a.observeDelegationAdmission([]provider.ToolCall{
45 {Name: "read_file", Arguments: `{"path":"a.go"}`},
46 {Name: "research", Arguments: `{"prompt":"date formats"}`},
47 {Name: "task", Arguments: `{"prompt":"sub work"}`},
48 })
49 // read_file is not a delegation and must never be audited; research and task
50 // both are, since a paired measurement priced task/fleet delegation at 2-4x
51 // the cost of doing the same work directly.
52 if len(sink.audits) != 2 {
53 t.Fatalf("got %d audits, want research + task", len(sink.audits))
54 }
55 for _, got := range sink.audits {
56 if got.Tool == "read_file" {
57 t.Fatalf("a non-delegation tool was audited: %+v", got)
58 }
59 if got.Verdict != "allow" || got.Reason != "model_decides" {
60 t.Fatalf("audit = %+v, want allow/model_decides", got)
61 }
62 }
63 }
64
64 lines GO