返回 DeepSeek-Reasonix
dispatch_generation_test.go
根目录 / internal / agent / dispatch_generation_test.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6 "strings"
7 "testing"
8
9 "reasonix/internal/provider"
10 "reasonix/internal/tool"
11 )
12
13 type genShiftTool struct {
14 gen string
15 }
16
17 func (g *genShiftTool) Name() string { return "shift" }
18 func (g *genShiftTool) Description() string { return "" }
19 func (g *genShiftTool) Schema() json.RawMessage { return json.RawMessage(`{"type":"object"}`) }
20 func (g *genShiftTool) ReadOnly() bool { return true }
21 func (g *genShiftTool) Execute(context.Context, json.RawMessage) (string, error) {
22 return "", nil
23 }
24 func (g *genShiftTool) ClassifyCall(json.RawMessage) tool.CallClass {
25 return tool.CallClass{Known: true, ReadOnly: true, ParallelSafe: true, Generation: g.gen}
26 }
27
28 func TestDispatchGenerationGateBlocksStaleClassification(t *testing.T) {
29 target := &genShiftTool{gen: "v1"}
30 a := &Agent{}
31 a.turn.loop.setDispatchClasses(map[string]tool.CallClass{
32 "c1": {Known: true, ReadOnly: true, ParallelSafe: true, Generation: "v1"},
33 })
34 plan := &toolCallPlan{
35 call: provider.ToolCall{ID: "c1", Name: "shift", Arguments: `{}`},
36 tool: target,
37 }
38 if _, blocked := a.applyDispatchGenerationGate(plan); blocked {
39 t.Fatal("matching generation must dispatch")
40 }
41 target.gen = "v2"
42 out, blocked := a.applyDispatchGenerationGate(plan)
43 if !blocked || !strings.Contains(out.output, "generation changed") {
44 t.Fatalf("stale generation outcome = %+v", out)
45 }
46 }
47
47 lines GO