bots-garden/mini-mepublic Fork 0
d72271127802973540c648bfb372176cdaaa8e4f
Commits
Clone
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

gap_test.go · 130 lines · 3.9 KBGo Blame HistoryRaw
💾 Saved. d722711 k33g 7h ago1// Tests for the spacing of the streamed text. The bug they guard: the model
2// ends its sentence with line breaks — more and more of them as the turns go by
3// — and the screen hollowed out by as much. Reproducible end to end with
4// `SCENARIO=padding python3 ../03-one-agent-one-tool/docs/fake-engine.py`.
5package engine
6
7import "testing"
8
9// next is called once per streamed chunk; we check what gets printed for each
10// of them, in order.
11func TestGapHoldsTrailingBlanks(t *testing.T) {
12 cases := []struct {
13 name string
14 fragments []string
15 want []string
16 }{{
17 name: "plain text",
18 fragments: []string{"Hello"},
19 want: []string{"Hello"},
20 }, {
21 name: "trailing whitespace is not printed",
22 fragments: []string{"Let me look:\n\n"},
23 want: []string{"Let me look:"},
24 }, {
25 name: "it is printed when text follows, down to one blank line",
26 fragments: []string{"para one\n\n\n\n\n", "para two"},
27 want: []string{"para one", "\n\npara two"},
28 }, {
29 name: "leading whitespace is dropped before the first word",
30 fragments: []string{"\n\n", "Hello"},
31 want: []string{"", "Hello"},
32 }, {
33 name: "all-whitespace chunks: accumulated, then capped",
34 fragments: []string{"a", "\n", "\n", "\n", "\n", "b"},
35 want: []string{"a", "", "", "", "", "\n\nb"},
36 }, {
37 name: "the indentation of a code block survives",
38 fragments: []string{"code:", "\n fmt.Println()"},
39 want: []string{"code:", "\n fmt.Println()"},
40 }, {
41 name: "a single break between two lines stays single",
42 fragments: []string{"line one\n", "line two"},
43 want: []string{"line one", "\nline two"},
44 }, {
45 name: "empty chunk",
46 fragments: []string{"a", "", "b"},
47 want: []string{"a", "", "b"},
48 }}
49
50 for _, c := range cases {
51 t.Run(c.name, func(t *testing.T) {
52 var g gap
53 for i, frag := range c.fragments {
54 if got := g.next(frag); got != c.want[i] {
55 t.Errorf("chunk %d (%q): printed %q, want %q",
56 i, frag, got, c.want[i])
57 }
58 }
59 })
60 }
61}
62
63// drop is called when a tool is about to write: the whitespace held back
64// belonged to the text before it, and printing it after the 🛠️ line would
65// reopen the hole.
66func TestGapDropForgetsHeldBlanks(t *testing.T) {
67 var g gap
68 if got := g.next("Let me look:\n\n\n"); got != "Let me look:" {
69 t.Fatalf("printed %q", got)
70 }
71 g.drop() // 🛠️ bash: … gets printed here
72 if got := g.next("Now let me check:"); got != "Now let me check:" {
73 t.Errorf("after drop: printed %q, want %q with no whitespace in front",
74 got, "Now let me check:")
75 }
76}
77
78// The full scenario of the bug: four turns whose trailing whitespace grows, a
79// tool between each. None of that whitespace may be printed.
80func TestGapPaddingScenario(t *testing.T) {
81 var g gap
82 turns := []string{
83 "Let me look at the file:" + nl(2),
84 "Now let me check something else:" + nl(4),
85 "Let me try another approach:" + nl(7),
86 "Let me rebuild the program:" + nl(11),
87 }
88 for i, turn := range turns {
89 out := g.next(turn)
90 if hasBlank(out) {
91 t.Errorf("turn %d: %q contains trailing whitespace", i, out)
92 }
93 g.drop() // the tool writes its 🛠️ line
94 }
95}
96
97func TestSqueeze(t *testing.T) {
98 cases := map[string]string{
99 "": "",
100 "\n": "\n",
101 "\n\n": "\n\n",
102 "\n\n\n": "\n\n",
103 "\n\n\n\n\n\n\n\n": "\n\n",
104 "\n ": "\n ", // indentation preserved
105 "\n\n\n ": "\n\n ", // capped, indentation kept
106 "a\n\n\n\nb": "a\n\nb", // in the middle of the text too
107 " ": " ", // spaces are left alone
108 }
109 for in, want := range cases {
110 if got := squeeze(in); got != want {
111 t.Errorf("squeeze(%q) = %q, want %q", in, got, want)
112 }
113 }
114}
115
116func nl(n int) string {
117 s := ""
118 for range n {
119 s += "\n"
120 }
121 return s
122}
123
124func hasBlank(s string) bool {
125 if s == "" {
126 return false
127 }
128 last := s[len(s)-1]
129 return last == '\n' || last == ' ' || last == '\t' || last == '\r'
130}