Fix Remote speech stalls after pause and early completion

This commit is contained in:
ak47 committed 2026-11-06 22:11:29 -05:00
1 parent 6867d901b2
commit 19b789ef5c
6 files changed
+131 -30

No files matched your search

+53 -4
View File
@@ -7,6 +7,7 @@ package app
import (
"context"
"errors"
"fmt"
"strings"
"sync/atomic"
"testing"
@@ -188,10 +189,6 @@ func TestRemoteSpeechStreamCancelAndPause(t *testing.T) {
remote_stream_wait(t, f.send(t, effect))
remote_stream_wait(t, active.stopped)
remote_stream_wait(t, pendingRelease)
if kind == "pause" {
remote_stream_wait(t, f.speak(t, "discard while paused", 2))
f.barrier(t) // Resume accepts future speech only.
}
futureRelease := f.speak(t, "future", 0)
close(active.cleanup)
future := f.next(t, "future")
@@ -203,6 +200,24 @@ func TestRemoteSpeechStreamCancelAndPause(t *testing.T) {
}
}
func TestRemoteSpeechStreamFreshSpeechAfterPause(t *testing.T) {
for _, cancelFirst := range []bool{false, true} {
t.Run(map[bool]string{false: "speak", true: "cancel then speak"}[cancelFirst], func(t *testing.T) {
f := remote_stream_fixture(t, false)
paused := true
remote_stream_wait(t, f.send(t, tentaclewire.RemoteSpeech{Kind: "pause", Paused: &paused}))
if cancelFirst {
remote_stream_wait(t, f.send(t, tentaclewire.RemoteSpeech{Kind: "cancel"}))
}
released := f.speak(t, "new navigation", 0)
call := f.next(t, "new navigation")
call.finish <- nil
remote_stream_wait(t, released)
f.stop(t)
})
}
}
func TestRemoteSpeechStreamRevocationAndReplacement(t *testing.T) {
f := remote_stream_fixture(t, true)
leaseContext, revoke := context.WithCancel(f.ctx)
@@ -349,6 +364,40 @@ func TestRemoteSpeechStreamIsolatedBackendCancellation(t *testing.T) {
}
}
func TestRemoteSpeechStreamEarlyBackendCompletionKeepsReading(t *testing.T) {
for _, terminal := range []int{702, 703} {
t.Run(fmt.Sprint(terminal), func(t *testing.T) {
speaker, server := isolated_voice_fixture(t)
server.mutex.Lock()
server.queryReplies = map[string]string{"SPEAK": fmt.Sprintf(
"230 OK\r\n%d-1\r\n%d-1\r\n%d DONE\r\n225-1\r\n225 QUEUED\r\n", terminal, terminal, terminal)}
server.mutex.Unlock()
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
incoming := make(chan tentacle.RemoteSpeechDelivery, 8)
done := make(chan error, 1)
go func() {
done <- run_remote_speech_playback(ctx, speaker, incoming, func(tentacle.RemoteSpeechDelivery) bool { return true }, nil)
}()
lease := tentaclewire.RemoteLease{Lease: strings.Repeat("b", 32), Epoch: 1}
for _, text := range []string{"first", "second", "third"} {
released := make(chan struct{})
incoming <- tentacle.RemoteSpeechDelivery{Context: ctx, Lease: lease,
Speeches: []tentaclewire.RemoteSpeech{remote_render_frame(0, tentaclewire.RemoteSpeechPart{Text: text})},
Release: func() { close(released) }}
if got := server.next_utterance(t); got.text != text {
t.Fatalf("remote output = %q, want %q", got.text, text)
}
remote_stream_wait(t, released)
}
cancel()
if err := remote_render_result(t, done); !errors.Is(err, context.Canceled) {
t.Fatalf("stream shutdown: %v", err)
}
})
}
}
func TestRemoteSpeechStreamPolicyLossDuringAcquisition(t *testing.T) {
speaker, server := isolated_voice_fixture(t)
held, resume := make(chan struct{}), make(chan struct{})