mirror of
https://github.com/vxcontrol/langchaingo.git
synced 2026-08-25 11:10:02 -04:00
fix(googleai): keep the partial response when a stream callback fails
GenerateContent discarded the accumulated response whenever the inner layer returned an error, so a caller that stops a stream from its StreamingFunc got (nil, err) and could not read the text produced before the abort. The streaming path already returns the pair, and the structured-output path below returns it too — this aligns the exported entry point with both. PAGI-125 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -192,7 +192,7 @@ func (g *GoogleAI) GenerateContent(
|
||||
response, err = g.generateFromMessages(ctx, opts.GetModel(), messages, config, &opts)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return response, err
|
||||
}
|
||||
|
||||
// When structured output was requested, validate each normal-final candidate
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package googleai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/vxcontrol/langchaingo/llms"
|
||||
"github.com/vxcontrol/langchaingo/llms/streaming"
|
||||
"google.golang.org/genai"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
@@ -920,3 +925,36 @@ func TestValidateGoogleStructuredOutput(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type stubStreamTransport struct{ body string }
|
||||
|
||||
func (t stubStreamTransport) RoundTrip(*http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: http.Header{"Content-Type": []string{"text/event-stream"}},
|
||||
Body: io.NopCloser(strings.NewReader(t.body)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestGenerateContentKeepsPartialResponseWhenStreamingFuncFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
chunk := `{"candidates":[{"content":{"parts":[{"text":"partial answer"}],` +
|
||||
`"role":"model"},"finishReason":"STOP","index":0}]}`
|
||||
llm, err := New(t.Context(),
|
||||
WithAPIKey("test-api-key"),
|
||||
WithRest(),
|
||||
WithHTTPClient(&http.Client{Transport: stubStreamTransport{body: "data: " + chunk + "\n\n"}}),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
errAbort := errors.New("caller stopped the stream")
|
||||
resp, err := llm.GenerateContent(t.Context(),
|
||||
[]llms.MessageContent{llms.TextParts(llms.ChatMessageTypeHuman, "hi")},
|
||||
llms.WithStreamingFunc(func(context.Context, streaming.Chunk) error { return errAbort }),
|
||||
)
|
||||
|
||||
require.ErrorIs(t, err, errAbort)
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, "partial answer", resp.Choices[0].Content)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user