1package modes
2
3import (
4 "testing"
5
6 "github.com/bnema/zut/packages/core"
7 "github.com/bnema/zut/packages/provider"
8)
9
10type metadataRecordingClient struct {
11 provider.Client
12 got []provider.Model
13}
14
15func (c *metadataRecordingClient) SetModelMetadata(m provider.Model) { c.got = append(c.got, m) }
16
17// A same-provider /model switch reuses the agent, so it must also adopt the
18// new model's output budget and context window. Keeping the previous model's
19// MaxTokens truncated responses (e.g. a 4096 budget carried onto a 128k model).
20func TestSameProviderModelSwapUpdatesModelLimits(t *testing.T) {
21 const from, to = "claude-3-5-haiku-20241022", "claude-opus-4-1-20250805"
22 fromModel, err := provider.FindModel("anthropic", from)
23 if err != nil {
24 t.Fatal(err)
25 }
26 toModel, err := provider.FindModel("anthropic", to)
27 if err != nil {
28 t.Fatal(err)
29 }
30 if fromModel.MaxOutput == toModel.MaxOutput || toModel.MaxOutput <= 0 {
31 t.Fatalf("test needs distinct positive limits, got %d and %d", fromModel.MaxOutput, toModel.MaxOutput)
32 }
33
34 client := &metadataRecordingClient{}
35 ag := core.NewAgent(client, from, "", nil)
36 ag.MaxTokens = fromModel.MaxOutput
37 ag.ContextWindow = fromModel.ContextWindow
38 i := &Interactive{agent: ag, cfg: InteractiveConfig{Provider: "anthropic", Model: from}}
39
40 i.swapModel("anthropic", to, nil, false)
41
42 if ag.Model != to {
43 t.Fatalf("agent model = %q, want %q", ag.Model, to)
44 }
45 if ag.MaxTokens != toModel.MaxOutput {
46 t.Fatalf("agent MaxTokens = %d, want %d", ag.MaxTokens, toModel.MaxOutput)
47 }
48 if ag.ContextWindow != toModel.ContextWindow {
49 t.Fatalf("agent ContextWindow = %d, want %d", ag.ContextWindow, toModel.ContextWindow)
50 }
51 if len(client.got) != 1 || client.got[0].ID != to || client.got[0].MaxOutput != toModel.MaxOutput {
52 t.Fatalf("client metadata = %+v, want %s", client.got, to)
53 }
54}