Skip to content

Commit 96aeda0

Browse files
committed
brain: skip empty continuations for initial prompt
1 parent dd91591 commit 96aeda0

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

brain/speak.go

+47-3
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ func Think(ctx context.Context, s Interface, tag, prompt string) (string, []stri
3838

3939
var ids []string
4040
// We handle the first search specially.
41-
// TODO(zeph): skip terminating choices
42-
id, tok, l, err := next(ctx, s, tag, search.Slice())
41+
id, tok, err := first(ctx, s, tag, search.Slice())
4342
if len(tok) == 0 {
4443
return "", nil, err
4544
}
@@ -48,7 +47,8 @@ func Think(ctx context.Context, s Interface, tag, prompt string) (string, []stri
4847
ids = slices.Insert(ids, k, id)
4948
}
5049
w = append(w, tok...)
51-
search = search.DropEnd(search.Len() - l - 1).Prepend(ReduceEntropy(tok))
50+
search = search.Prepend(ReduceEntropy(tok))
51+
5252
for range 1024 {
5353
id, tok, l, err := next(ctx, s, tag, search.Slice())
5454
if len(tok) == 0 {
@@ -116,3 +116,47 @@ func term(ctx context.Context, s Interface, tag string, prompt []string, wid, wt
116116
}
117117
return n, seen, nil
118118
}
119+
120+
// first finds a single first term from a brain given a prompt.
121+
// Unlike next, it requires the entire prompt to match, and it skips empty
122+
// continuations if the prompt is not empty.
123+
func first(ctx context.Context, s Interface, tag string, prompt []string) (id, tok string, err error) {
124+
wid := make([]byte, 0, 64)
125+
wtok := make([]byte, 0, 64)
126+
var skip Skip
127+
var n uint64
128+
// Empty and non-empty prompts have different logic. We could merge them
129+
// into the same loop, but it's easier and probably more efficient to
130+
// split the control flow.
131+
if len(prompt) == 0 {
132+
_, _, err := term(ctx, s, tag, prompt, &wid, &wtok, &skip, 0)
133+
if err != nil {
134+
return "", "", fmt.Errorf("couldn't think of first term: %w", err)
135+
}
136+
return string(wid), string(wtok), nil
137+
}
138+
139+
var rid, rtok []byte
140+
for f := range s.Think(ctx, tag, prompt) {
141+
// The downside with a prompt is that we have to read every option so
142+
// that we only count non-empty continuations.
143+
wid, wtok = wid[:0], wtok[:0]
144+
if err := f(&wid, &wtok); err != nil {
145+
return "", "", fmt.Errorf("couldn't think of first term with prompt %q: %w", prompt, err)
146+
}
147+
if len(wtok) == 0 {
148+
// Empty suffix. Don't care.
149+
continue
150+
}
151+
if n > 0 {
152+
n--
153+
continue
154+
}
155+
// Save this result as the potential selection.
156+
// We could just assign id and tok here, but this reduces allocations.
157+
rid = append(rid[:0], wid...)
158+
rtok = append(rtok[:0], wtok...)
159+
n = skip.N(rand.Uint64(), rand.Uint64())
160+
}
161+
return string(rid), string(rtok), nil
162+
}

brain/speak_test.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,12 @@ func (t *testThinker) Think(ctx context.Context, tag string, prefix []string) it
4747
}
4848
}
4949

50-
// Forget implements brain.Brain.
5150
func (t *testThinker) Forget(ctx context.Context, tag string, id string) error {
5251
panic("unimplemented")
5352
}
54-
55-
// Learn implements brain.Brain.
5653
func (t *testThinker) Learn(ctx context.Context, tag string, msg *message.Received[userhash.Hash], tuples []brain.Tuple) error {
5754
panic("unimplemented")
5855
}
59-
60-
// Recall implements brain.Brain.
6156
func (t *testThinker) Recall(ctx context.Context, tag string, page string, out []message.Received[userhash.Hash]) (n int, next string, err error) {
6257
panic("unimplemented")
6358
}
@@ -110,7 +105,7 @@ func TestThink(t *testing.T) {
110105
id: "kessoku",
111106
tups: []brain.Tuple{
112107
{
113-
Prefix: []string{"nijika "},
108+
Prefix: []string{"nijika ", "ryo ", "bocchi "},
114109
Suffix: "kita",
115110
},
116111
},
@@ -124,7 +119,7 @@ func TestThink(t *testing.T) {
124119
id: "kessoku",
125120
tups: []brain.Tuple{
126121
{
127-
Prefix: []string{"nijika "},
122+
Prefix: []string{"nijika ", "ryo ", "bocchi "},
128123
Suffix: "KITA",
129124
},
130125
},

0 commit comments

Comments
 (0)