1package tui
2
3import (
4 "fmt"
5 "strconv"
6 "strings"
7 "testing"
8
9 "github.com/bnema/zut/packages/provider"
10)
11
12func BenchmarkViewBuildWithAnchorsToolStorm(b *testing.B) {
13 for _, width := range []int{48, 80, 160} {
14 for _, expanded := range []bool{false, true} {
15 for _, temperature := range []string{"cold", "warm"} {
16 name := fmt.Sprintf("width=%d/expanded=%t/%s", width, expanded, temperature)
17 b.Run(name, func(b *testing.B) {
18 base := benchmarkToolStormView(expanded)
19 if temperature == "warm" {
20 base.BuildWithAnchors(width)
21 }
22 b.ReportAllocs()
23 b.ResetTimer()
24 for n := 0; n < b.N; n++ {
25 view := base
26 if temperature == "cold" {
27 view.InvalidateRenderCache()
28 }
29 lines, anchors := view.BuildWithAnchors(width)
30 if len(lines) == 0 || len(anchors) == 0 {
31 b.Fatal("tool storm produced no rows or anchors")
32 }
33 }
34 })
35 }
36 }
37 }
38}
39
40func BenchmarkViewBuildWithAnchorsLiveToolStorm(b *testing.B) {
41 for _, width := range []int{48, 80, 160} {
42 for _, expanded := range []bool{false, true} {
43 name := "width=" + strconv.Itoa(width) + "/expanded=" + strconv.FormatBool(expanded)
44 b.Run(name, func(b *testing.B) {
45 view := &View{
46 Theme: Dark,
47 ExpandAll: expanded,
48 Messages: benchmarkToolStormMessages(24, 8),
49 MessagesRevision: 1,
50 ToolCalls: benchmarkLiveTools(8, 96),
51 }
52 liveResults := make([]string, len(view.ToolCalls))
53 for i := range liveResults {
54 liveResults[i] = benchmarkResult(96, i)
55 }
56 b.ReportAllocs()
57 b.ResetTimer()
58 for n := 0; n < b.N; n++ {
59 call := &view.ToolCalls[n%len(view.ToolCalls)]
60 call.Revision++
61 call.Result = liveResults[n%len(liveResults)]
62 lines, anchors := view.BuildWithAnchors(width)
63 if len(lines) == 0 || len(anchors) == 0 {
64 b.Fatal("live tool storm produced no rows or anchors")
65 }
66 }
67 })
68 }
69 }
70}
71
72func benchmarkToolStormView(expanded bool) *View {
73 return &View{
74 Theme: Dark,
75 ExpandAll: expanded,
76 Messages: benchmarkToolStormMessages(48, 96),
77 MessagesRevision: 1,
78 }
79}
80
81func benchmarkToolStormMessages(tools, resultLines int) []provider.Message {
82 messages := make([]provider.Message, 0, tools*3)
83 for i := 0; i < tools; i++ {
84 id := fmt.Sprintf("call-%d", i)
85 messages = append(messages,
86 provider.Message{
87 Role: provider.RoleUser,
88 Content: []provider.Content{provider.TextBlock{
89 Text: fmt.Sprintf("inspect result %d", i),
90 }},
91 },
92 provider.Message{
93 Role: provider.RoleAssistant,
94 Content: []provider.Content{provider.ToolCallBlock{
95 ID: id,
96 Name: "bash",
97 Arguments: []byte(`{"command":"printf storm"}`),
98 }},
99 },
100 provider.Message{
101 Role: provider.RoleTool,
102 Content: []provider.Content{provider.ToolResultBlock{
103 CallID: id,
104 Content: []provider.Content{provider.TextBlock{Text: benchmarkResult(resultLines, i)}},
105 }},
106 },
107 )
108 }
109 return messages
110}
111
112func benchmarkLiveTools(tools, resultLines int) []ToolCallView {
113 out := make([]ToolCallView, 0, tools)
114 for i := 0; i < tools; i++ {
115 out = append(out, ToolCallView{
116 ID: fmt.Sprintf("live-%d", i),
117 Name: "bash",
118 Revision: 1,
119 Args: "printf storm",
120 Result: benchmarkResult(resultLines, i),
121 Done: true,
122 })
123 }
124 return out
125}
126
127func benchmarkResult(lines, tool int) string {
128 var b strings.Builder
129 for line := 0; line < lines; line++ {
130 fmt.Fprintf(&b, "tool=%d line=%03d output payload for highlighting and wrapping\n", tool, line)
131 }
132 return b.String()
133}