fix(ai): hand an unanswered external turn out again after 3 minutes
참고 측정 1세트 첫 진단에서 클라이언트가 /external/next 로 가져간 2번째 턴의 출력을 잃어 답이 오지 않았고, 턴은 awaiting_reply 에 남아 진단이 데드라인까지 멈췄다. 가져간 뒤 RequeueAfter(기본 3분) 동안 답이 없는 턴은 새 reply_token 으로 큐 앞에 되돌려 다음 폴링이 다시 받게 한다(requeued 횟수 기록, 이전 토큰은 거부). 출력 유실은 재시도 한 번의 비용으로 끝나고 진단은 이어진다.
This commit is contained in:
1 parent
b0ff118841
commit
2a2f91a32c
2 files changed
+70
-5
No files matched your search
+39
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -137,6 +138,44 @@ func TestDeadlinesAndErrors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A taken turn whose reply never comes is handed out again after RequeueAfter with a new token; the old token is
|
||||
// refused and the new one completes the turn.
|
||||
func TestRequeueUnansweredTurn(t *testing.T) {
|
||||
r := New(10 * time.Second)
|
||||
r.RequeueAfter = 200 * time.Millisecond
|
||||
srv := httptest.NewServer(r.Handler())
|
||||
defer srv.Close()
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
resp, err := r.CreateResponse(context.Background(), openai.Request{Model: "external-x", Input: []openai.Item{{Type: "message", Role: "user", Content: "hi"}}})
|
||||
if err == nil && len(resp.FunctionCalls()) != 1 {
|
||||
err = fmt.Errorf("unexpected response %+v", resp)
|
||||
}
|
||||
ch <- err
|
||||
}()
|
||||
first := poll(t, srv.URL) // taken, never answered
|
||||
if first.Requeued != 0 {
|
||||
t.Fatalf("fresh turn marked requeued: %+v", first)
|
||||
}
|
||||
if code := get(t, srv.URL+"/external/next?wait=0"); code != 204 {
|
||||
t.Fatalf("taken turn must not be served again at once, got %d", code)
|
||||
}
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
second := poll(t, srv.URL)
|
||||
if second.TurnID != first.TurnID || second.ReplyToken == first.ReplyToken || second.Requeued != 1 {
|
||||
t.Fatalf("requeue: first=%+v second=%+v", first, second)
|
||||
}
|
||||
if code, _ := post(t, srv.URL+"/external/reply", `{"turn_id":"`+first.TurnID+`","reply_token":"`+first.ReplyToken+`","output":[{"type":"function_call","name":"x","arguments":{}}]}`); code != 403 {
|
||||
t.Fatalf("old token must be refused, got %d", code)
|
||||
}
|
||||
if code, _ := post(t, srv.URL+"/external/reply", `{"turn_id":"`+second.TurnID+`","reply_token":"`+second.ReplyToken+`","output":[{"type":"function_call","name":"x","arguments":{}}]}`); code != 200 {
|
||||
t.Fatalf("new token must be accepted, got %d", code)
|
||||
}
|
||||
if err := <-ch; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func poll(t *testing.T, base string) Turn {
|
||||
t.Helper()
|
||||
for i := 0; i < 20; i++ {
|
||||
|
||||
Reference in new issue
Block a user