f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
380 lines
8.7 KiB
Go
380 lines
8.7 KiB
Go
package signals
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestComputeContextPressure_NoData(t *testing.T) {
|
|
got := ComputeContextPressure(nil, 0, "")
|
|
assert.Equal(t, 0, got.CompactionCount)
|
|
assert.Nil(t, got.PressureMax)
|
|
}
|
|
|
|
func TestCountCompactions(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
tokens []ContextTokenRow
|
|
want int
|
|
}{
|
|
{
|
|
"empty",
|
|
nil,
|
|
0,
|
|
},
|
|
{
|
|
"steady growth no drops",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 1000, HasContextTokens: true},
|
|
{ContextTokens: 2000, HasContextTokens: true},
|
|
{ContextTokens: 3000, HasContextTokens: true},
|
|
{ContextTokens: 4000, HasContextTokens: true},
|
|
},
|
|
0,
|
|
},
|
|
{
|
|
"one compaction over 30 percent drop",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
{ContextTokens: 6000, HasContextTokens: true},
|
|
},
|
|
1,
|
|
},
|
|
{
|
|
"two compactions",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
{ContextTokens: 5000, HasContextTokens: true},
|
|
{ContextTokens: 8000, HasContextTokens: true},
|
|
{ContextTokens: 3000, HasContextTokens: true},
|
|
},
|
|
2,
|
|
},
|
|
{
|
|
"drop exactly 30 percent not compaction",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
{ContextTokens: 7000, HasContextTokens: true},
|
|
},
|
|
0,
|
|
},
|
|
{
|
|
"drop 29 percent not compaction",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
{ContextTokens: 7100, HasContextTokens: true},
|
|
},
|
|
0,
|
|
},
|
|
{
|
|
"drop 31 percent is compaction",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
{ContextTokens: 6900, HasContextTokens: true},
|
|
},
|
|
1,
|
|
},
|
|
{
|
|
"skip rows without HasContextTokens",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
{ContextTokens: 0, HasContextTokens: false},
|
|
{ContextTokens: 0, HasContextTokens: false},
|
|
{ContextTokens: 5000, HasContextTokens: true},
|
|
},
|
|
1,
|
|
},
|
|
{
|
|
"all rows without HasContextTokens",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: false},
|
|
{ContextTokens: 5000, HasContextTokens: false},
|
|
},
|
|
0,
|
|
},
|
|
{
|
|
"single row no compaction",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 10000, HasContextTokens: true},
|
|
},
|
|
0,
|
|
},
|
|
{
|
|
"drop from zero prev not compaction",
|
|
[]ContextTokenRow{
|
|
{ContextTokens: 0, HasContextTokens: true},
|
|
{ContextTokens: 5000, HasContextTokens: true},
|
|
},
|
|
0,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equal(t, tt.want, countCompactions(tt.tokens))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestComputePressure(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
peak int
|
|
model string
|
|
wantNil bool
|
|
wantVal float64
|
|
wantPrec float64 // tolerance for float comparison
|
|
}{
|
|
{
|
|
"known model claude-sonnet-4-5",
|
|
100_000, "claude-sonnet-4-5",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"known model full window",
|
|
200_000, "claude-sonnet-4-5",
|
|
false, 1.0, 1e-9,
|
|
},
|
|
{
|
|
"known model gpt-4o",
|
|
64_000, "gpt-4o",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"unknown model returns nil",
|
|
100_000, "unknown-model-xyz",
|
|
true, 0, 0,
|
|
},
|
|
{
|
|
"zero peak returns nil",
|
|
0, "claude-sonnet-4-5",
|
|
true, 0, 0,
|
|
},
|
|
{
|
|
"negative peak returns nil",
|
|
-1, "claude-sonnet-4-5",
|
|
true, 0, 0,
|
|
},
|
|
{
|
|
"empty model returns nil",
|
|
100_000, "",
|
|
true, 0, 0,
|
|
},
|
|
{
|
|
"prefix match with version suffix",
|
|
100_000, "claude-sonnet-4-5-20250101",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"prefix match gpt-4o-mini before gpt-4o",
|
|
64_000, "gpt-4o-mini",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"prefix match gpt-4o-mini with suffix",
|
|
64_000, "gpt-4o-mini-2025-01-01",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"gemini prefix match",
|
|
500_000, "gemini-2.5-pro-preview",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"o3 exact match",
|
|
100_000, "o3",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
{
|
|
"o3 prefix match",
|
|
100_000, "o3-2025-04-16",
|
|
false, 0.5, 1e-9,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := computePressure(tt.peak, tt.model)
|
|
if tt.wantNil {
|
|
assert.Nil(t, got)
|
|
return
|
|
}
|
|
require.NotNil(t, got)
|
|
assert.LessOrEqual(t, math.Abs(*got-tt.wantVal), tt.wantPrec)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLookupWindowSize(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
model string
|
|
want int
|
|
}{
|
|
{"exact claude-opus-4-6", "claude-opus-4-6", 1_000_000},
|
|
{"exact gpt-4o-mini", "gpt-4o-mini", 128_000},
|
|
{"exact gpt-4o", "gpt-4o", 128_000},
|
|
{
|
|
"prefix claude-sonnet-4-5-20250101",
|
|
"claude-sonnet-4-5-20250101", 200_000,
|
|
},
|
|
{
|
|
"prefix gpt-4o-mini-2025",
|
|
"gpt-4o-mini-2025", 128_000,
|
|
},
|
|
{"unknown", "llama-3", 0},
|
|
{"empty", "", 0},
|
|
{
|
|
"gpt-4o with date suffix",
|
|
"gpt-4o-2024-08-06", 128_000,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equal(t, tt.want, lookupWindowSize(tt.model))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestComputeContextPressure_Combined(t *testing.T) {
|
|
tokens := []ContextTokenRow{
|
|
{ContextTokens: 50000, HasContextTokens: true},
|
|
{ContextTokens: 100000, HasContextTokens: true},
|
|
{ContextTokens: 150000, HasContextTokens: true},
|
|
{ContextTokens: 50000, HasContextTokens: true},
|
|
{ContextTokens: 80000, HasContextTokens: true},
|
|
}
|
|
got := ComputeContextPressure(
|
|
tokens, 150000, "claude-sonnet-4-5",
|
|
)
|
|
assert.Equal(t, 1, got.CompactionCount)
|
|
require.NotNil(t, got.PressureMax)
|
|
assert.LessOrEqual(t, math.Abs(*got.PressureMax-0.75), 1e-9)
|
|
}
|
|
|
|
func TestCountMidTaskCompactions(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
boundaryOrdinals []int
|
|
toolCalls []ToolCallOrdinal
|
|
wantMidTaskCount int
|
|
}{
|
|
{
|
|
name: "no boundaries",
|
|
toolCalls: []ToolCallOrdinal{{1, "Read"}},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "no tool calls",
|
|
boundaryOrdinals: []int{10},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "boundary at start no tools before",
|
|
boundaryOrdinals: []int{1},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Edit"},
|
|
},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "boundary at end no tools after",
|
|
boundaryOrdinals: []int{10},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Edit"},
|
|
},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "no overlap between before and after",
|
|
boundaryOrdinals: []int{5},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Read"}, {4, "Edit"},
|
|
{6, "Bash"}, {7, "Grep"}, {8, "Glob"},
|
|
},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "overlap one tool insufficient",
|
|
boundaryOrdinals: []int{5},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Bash"}, {4, "Grep"},
|
|
{6, "Read"}, {7, "Glob"}, {8, "Write"},
|
|
},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "overlap two tools triggers",
|
|
boundaryOrdinals: []int{5},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Edit"}, {4, "Bash"},
|
|
{6, "Read"}, {7, "Edit"}, {8, "Grep"},
|
|
},
|
|
wantMidTaskCount: 1,
|
|
},
|
|
{
|
|
name: "multiple boundaries each evaluated",
|
|
boundaryOrdinals: []int{5, 15},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Edit"},
|
|
{6, "Read"}, {7, "Edit"},
|
|
{12, "Bash"}, {13, "Grep"},
|
|
{16, "Bash"}, {17, "Grep"},
|
|
},
|
|
wantMidTaskCount: 2,
|
|
},
|
|
{
|
|
name: "before window limited to last 10",
|
|
boundaryOrdinals: []int{20},
|
|
// 11 distinct names before — only last 10 count.
|
|
toolCalls: []ToolCallOrdinal{
|
|
{1, "Read"}, {2, "Read"},
|
|
{3, "T1"}, {4, "T2"}, {5, "T3"},
|
|
{6, "T4"}, {7, "T5"}, {8, "T6"},
|
|
{9, "T7"}, {10, "T8"}, {11, "T9"},
|
|
{12, "T10"},
|
|
// After: includes Read which was first 2 ordinals,
|
|
// pushed out of the last-10 window.
|
|
{21, "Read"}, {22, "Read"},
|
|
},
|
|
// "Read" not in last-10 before window, so no overlap.
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
name: "after window limited to first 5",
|
|
boundaryOrdinals: []int{5},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Read"}, {3, "Edit"},
|
|
// First 5 after the boundary: A B C D E
|
|
{6, "A"}, {7, "B"}, {8, "C"},
|
|
{9, "D"}, {10, "E"},
|
|
// Read/Edit appear later, beyond the after window.
|
|
{11, "Read"}, {12, "Edit"},
|
|
},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
{
|
|
// Before has [Bash, Read]; after has Bash repeated.
|
|
// Raw match count is 4, but only one distinct tool
|
|
// name overlaps — should not trigger the threshold.
|
|
name: "single tool repeated does not inflate",
|
|
boundaryOrdinals: []int{5},
|
|
toolCalls: []ToolCallOrdinal{
|
|
{2, "Bash"}, {3, "Read"},
|
|
{6, "Bash"}, {7, "Bash"},
|
|
{8, "Bash"}, {9, "Bash"},
|
|
},
|
|
wantMidTaskCount: 0,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got := CountMidTaskCompactions(
|
|
tc.boundaryOrdinals, tc.toolCalls,
|
|
)
|
|
assert.Equal(t, tc.wantMidTaskCount, got)
|
|
})
|
|
}
|
|
}
|