返回 DeepSeek-Reasonix
small_window_admission_test.go
根目录 / internal / agent / small_window_admission_test.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6 "strings"
7 "testing"
8
9 "reasonix/internal/event"
10 "reasonix/internal/tool"
11 )
12
13 type largeSchemaTool struct {
14 description string
15 }
16
17 func (largeSchemaTool) Name() string { return "large_schema" }
18 func (t largeSchemaTool) Description() string { return t.description }
19 func (largeSchemaTool) Schema() json.RawMessage { return json.RawMessage(`{"type":"object"}`) }
20 func (largeSchemaTool) ReadOnly() bool { return true }
21 func (largeSchemaTool) Execute(context.Context, json.RawMessage) (string, error) {
22 return "ok", nil
23 }
24
25 func TestOutputBudgetReserveScalesWithWindow(t *testing.T) {
26 tests := []struct {
27 window int
28 want int
29 }{
30 {window: 0, want: 8 * 1024},
31 {window: 20_000, want: 256},
32 {window: 128_000, want: 1_000},
33 {window: 1_048_576, want: 8 * 1024},
34 {window: 2_000_000, want: 8 * 1024},
35 }
36 for _, tt := range tests {
37 if got := outputBudgetReserveForWindow(tt.window); got != tt.want {
38 t.Fatalf("window %d reserve = %d, want %d", tt.window, got, tt.want)
39 }
40 }
41 }
42
43 func TestPrepareSamplingRequestAdmitsCompactedSmallWindowDeadZone(t *testing.T) {
44 const window = 20_000
45 prov := &overflowSummaryProvider{}
46 reg := tool.NewRegistry()
47 reg.Add(largeSchemaTool{description: strings.Repeat("large deterministic schema. ", 1200)})
48 sess := foldableSessionOverForce(20)
49 a := New(prov, reg, sess, Options{
50 ContextWindow: window,
51 CompactRatio: defaultCompactRatio,
52 MaxOutputTokens: 8192,
53 }, event.Discard)
54
55 before := a.estimatedVisibleRequestTokens(a.modelVisibleMessages())
56 if before < a.compactTrigger() || before >= a.hardInputCeiling() {
57 t.Fatalf("fixture prompt = %d, want pressure range [%d, %d)", before, a.compactTrigger(), a.hardInputCeiling())
58 }
59
60 prepared, err := a.prepareSamplingRequest(context.Background())
61 if err != nil {
62 t.Fatalf("prepareSamplingRequest: %v", err)
63 }
64 if len(prov.requests) != 1 {
65 t.Fatalf("summary requests = %d, want 1", len(prov.requests))
66 }
67 adm := a.lastAdmission()
68 if adm.PromptTokens <= window-outputBudgetReserve {
69 t.Fatalf("fixture missed former admission dead zone: prompt = %d, old ceiling = %d", adm.PromptTokens, window-outputBudgetReserve)
70 }
71 if adm.ReserveTokens != outputBudgetReserveForWindow(window) {
72 t.Fatalf("reserve = %d, want scaled %d", adm.ReserveTokens, outputBudgetReserveForWindow(window))
73 }
74 if prepared.req.MaxTokens <= 0 || prepared.req.MaxTokens+adm.PromptTokens+adm.ReserveTokens > window {
75 t.Fatalf("prepared request does not fit: prompt=%d output=%d reserve=%d window=%d",
76 adm.PromptTokens, prepared.req.MaxTokens, adm.ReserveTokens, window)
77 }
78 }
79
79 lines GO