mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
fix(coderd): improve error handling in chattest, chattool, and chats (#23047)
- Use t.Errorf in chattest non-streaming helpers so encoding failures fail the test - Thread testing.TB into writeResponsesAPIStreaming and log SSE write errors instead of silently dropping them - Bump createworkspace DB error log from Warn to Error - Use errors.Join for timeout + output error in execute.go
This commit is contained in:
@@ -243,7 +243,7 @@ func (s *anthropicServer) writeNonStreamingResponse(w http.ResponseWriter, resp
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("anthropic-version", "2023-06-01")
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
s.t.Logf("writeNonStreamingResponse: failed to encode response: %v", err)
|
||||
s.t.Errorf("writeNonStreamingResponse: failed to encode response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ func writeErrorResponse(t testing.TB, w http.ResponseWriter, errResp *ErrorRespo
|
||||
},
|
||||
}
|
||||
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||
t.Logf("writeErrorResponse: failed to encode error response: %v", err)
|
||||
t.Errorf("writeErrorResponse: failed to encode error response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ func (s *openAIServer) writeResponsesAPIResponse(w http.ResponseWriter, req *Ope
|
||||
http.Error(w, "handler returned streaming response for non-streaming request", http.StatusInternalServerError)
|
||||
return
|
||||
case hasStreaming:
|
||||
writeResponsesAPIStreaming(w, req.Request, resp.StreamingChunks)
|
||||
writeResponsesAPIStreaming(s.t, w, req.Request, resp.StreamingChunks)
|
||||
default:
|
||||
s.writeResponsesAPINonStreaming(w, resp.Response)
|
||||
}
|
||||
@@ -320,7 +320,7 @@ func writeSSEEvent(w http.ResponseWriter, v interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func writeResponsesAPIStreaming(w http.ResponseWriter, r *http.Request, chunks <-chan OpenAIChunk) {
|
||||
func writeResponsesAPIStreaming(t testing.TB, w http.ResponseWriter, r *http.Request, chunks <-chan OpenAIChunk) {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
@@ -351,6 +351,7 @@ func writeResponsesAPIStreaming(w http.ResponseWriter, r *http.Request, chunks <
|
||||
ItemID: itemID,
|
||||
OutputIndex: int64(outputIndex),
|
||||
}); err != nil {
|
||||
t.Logf("writeResponsesAPIStreaming: failed to write ResponseTextDoneEvent: %v", err)
|
||||
return
|
||||
}
|
||||
if err := writeSSEEvent(w, responses.ResponseOutputItemDoneEvent{
|
||||
@@ -360,10 +361,12 @@ func writeResponsesAPIStreaming(w http.ResponseWriter, r *http.Request, chunks <
|
||||
Type: "message",
|
||||
},
|
||||
}); err != nil {
|
||||
t.Logf("writeResponsesAPIStreaming: failed to write ResponseOutputItemDoneEvent: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := writeSSEEvent(w, responses.ResponseCompletedEvent{}); err != nil {
|
||||
t.Logf("writeResponsesAPIStreaming: failed to write ResponseCompletedEvent: %v", err)
|
||||
return
|
||||
}
|
||||
flusher.Flush()
|
||||
@@ -390,6 +393,7 @@ func writeResponsesAPIStreaming(w http.ResponseWriter, r *http.Request, chunks <
|
||||
Type: "message",
|
||||
},
|
||||
}); err != nil {
|
||||
t.Logf("writeResponsesAPIStreaming: failed to write ResponseOutputItemAddedEvent: %v", err)
|
||||
return
|
||||
}
|
||||
flusher.Flush()
|
||||
@@ -407,10 +411,12 @@ func writeResponsesAPIStreaming(w http.ResponseWriter, r *http.Request, chunks <
|
||||
|
||||
chunkBytes, err := json.Marshal(chunkData)
|
||||
if err != nil {
|
||||
t.Logf("writeResponsesAPIStreaming: failed to marshal chunk data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(w, "data: %s\n\n", chunkBytes); err != nil {
|
||||
t.Logf("writeResponsesAPIStreaming: failed to write chunk data: %v", err)
|
||||
return
|
||||
}
|
||||
flusher.Flush()
|
||||
@@ -421,7 +427,7 @@ func writeResponsesAPIStreaming(w http.ResponseWriter, r *http.Request, chunks <
|
||||
func (s *openAIServer) writeChatCompletionsNonStreaming(w http.ResponseWriter, resp *OpenAICompletion) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
s.t.Logf("writeChatCompletionsNonStreaming: failed to encode response: %v", err)
|
||||
s.t.Errorf("writeChatCompletionsNonStreaming: failed to encode response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +458,7 @@ func (s *openAIServer) writeResponsesAPINonStreaming(w http.ResponseWriter, resp
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
s.t.Logf("writeResponsesAPINonStreaming: failed to encode response: %v", err)
|
||||
s.t.Errorf("writeResponsesAPINonStreaming: failed to encode response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ func CreateWorkspace(options CreateWorkspaceOptions) fantasy.AgentTool {
|
||||
Valid: true,
|
||||
},
|
||||
}); err != nil {
|
||||
options.Logger.Warn(ctx, "failed to persist chat workspace association",
|
||||
options.Logger.Error(ctx, "failed to persist chat workspace association",
|
||||
slog.F("chat_id", options.ChatID),
|
||||
slog.F("workspace_id", workspace.ID),
|
||||
slog.Error(err),
|
||||
|
||||
@@ -3,12 +3,14 @@ package chattool
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/codersdk/workspacesdk"
|
||||
)
|
||||
@@ -248,15 +250,15 @@ func pollProcess(
|
||||
outputResp, outputErr := conn.ProcessOutput(bgCtx, processID)
|
||||
bgCancel()
|
||||
output := truncateOutput(outputResp.Output)
|
||||
timeoutMsg := fmt.Sprintf("command timed out after %s", timeout)
|
||||
timeoutErr := xerrors.Errorf("command timed out after %s", timeout)
|
||||
if outputErr != nil {
|
||||
timeoutMsg += fmt.Sprintf(" (failed to get output: %v)", outputErr)
|
||||
timeoutErr = errors.Join(timeoutErr, xerrors.Errorf("failed to get output: %w", outputErr))
|
||||
}
|
||||
return ExecuteResult{
|
||||
Success: false,
|
||||
Output: output,
|
||||
ExitCode: -1,
|
||||
Error: timeoutMsg,
|
||||
Error: timeoutErr.Error(),
|
||||
Truncated: outputResp.Truncated,
|
||||
}
|
||||
case <-ticker.C:
|
||||
|
||||
Reference in New Issue
Block a user