返回 DeepSeek-Reasonix
plan_contract_test.go
根目录 / internal / agent / plan_contract_test.go
1 package agent
2
3 import (
4 "context"
5 "reasonix/internal/event"
6 "reasonix/internal/plancontract"
7 "reasonix/internal/provider"
8 "reasonix/internal/tool"
9 "reflect"
10 "testing"
11 )
12
13 func contractPlan() plancontract.Plan {
14 return plancontract.Plan{
15 Objective: "make the cache key model-aware",
16 Steps: []plancontract.Step{
17 {
18 ID: "p1", Title: "thread the model ref through",
19 VerifiedFiles: []string{"internal/provider/cache.go"},
20 CandidateFiles: []string{"internal/boot/boot.go"},
21 Risks: []string{"warm caches invalidate once"},
22 Acceptance: []plancontract.Criterion{
23 {Text: "two model refs never share an entry"},
24 {Text: "existing hits keep hitting", Regression: true},
25 {Text: "the hit rate is logged", Optional: true},
26 },
27 Verification: []plancontract.Verification{{Command: "go test ./internal/provider/"}},
28 },
29 },
30 }.Normalize()
31 }
32
33 func TestApprovedPlanRemainsInstructionData(t *testing.T) {
34 plan := contractPlan()
35 a := New(nil, tool.NewRegistry(), NewSession(""), Options{}, event.Discard)
36 a.SetPlanContract(&plan)
37 if !reflect.DeepEqual(a.planContractSnapshot(), &plan) {
38 t.Fatal("plan content changed")
39 }
40 if !a.ReadinessResult().Ready {
41 t.Fatal("plan content created a quality gate")
42 }
43 }
44 func TestCoordinatorClearsThePlanContractEachTurn(t *testing.T) {
45 planner := &mockProvider{name: "planner", streams: submitPlanCall(e2ePlanArgs)}
46 exec := &mockProvider{name: "executor", chunks: []provider.Chunk{
47 {Type: provider.ChunkText, Text: "Done."},
48 {Type: provider.ChunkDone},
49 }}
50 coord, executor := submitPlanCoordinator(t, planner, exec, event.Discard)
51
52 if err := coord.Run(withNoClosedLoop(context.Background()), "fix the cache key"); err != nil {
53 t.Fatalf("Run: %v", err)
54 }
55 if executor.planContractSnapshot() == nil {
56 t.Fatal("the approved plan never reached the executor's contract")
57 }
58
59 coord.plannerPolicy = func(context.Context, string) PlannerDecision {
60 return PlannerDecision{Route: PlannerRouteExecutorOnly, Reason: "test"}
61 }
62 if err := coord.Run(withNoClosedLoop(context.Background()), "just answer me"); err != nil {
63 t.Fatalf("Run: %v", err)
64 }
65 if executor.planContractSnapshot() != nil {
66 t.Fatal("an executor-only turn inherited the previous turn's plan")
67 }
68 }
69
69 lines GO