fix(gemini): parse stream usage from JSON, skip thoughtSignature

This commit is contained in:
hkfires
2025-11-22 16:07:12 +08:00
parent 88e566281e
commit 166fa9e2e6
2 changed files with 18 additions and 4 deletions

View File

@@ -257,10 +257,14 @@ func (e *GeminiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A
line := scanner.Bytes() line := scanner.Bytes()
appendAPIResponseChunk(ctx, e.cfg, line) appendAPIResponseChunk(ctx, e.cfg, line)
filtered := FilterSSEUsageMetadata(line) filtered := FilterSSEUsageMetadata(line)
if detail, ok := parseGeminiStreamUsage(filtered); ok { payload := jsonPayload(filtered)
if len(payload) == 0 {
continue
}
if detail, ok := parseGeminiStreamUsage(payload); ok {
reporter.publish(ctx, detail) reporter.publish(ctx, detail)
} }
lines := sdktranslator.TranslateStream(ctx, to, from, req.Model, bytes.Clone(opts.OriginalRequest), body, bytes.Clone(filtered), &param) lines := sdktranslator.TranslateStream(ctx, to, from, req.Model, bytes.Clone(opts.OriginalRequest), body, bytes.Clone(payload), &param)
for i := range lines { for i := range lines {
out <- cliproxyexecutor.StreamChunk{Payload: []byte(lines[i])} out <- cliproxyexecutor.StreamChunk{Payload: []byte(lines[i])}
} }

View File

@@ -111,13 +111,23 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR
if !inlineDataResult.Exists() { if !inlineDataResult.Exists() {
inlineDataResult = partResult.Get("inline_data") inlineDataResult = partResult.Get("inline_data")
} }
thoughtSignatureResult := partResult.Get("thoughtSignature")
if !thoughtSignatureResult.Exists() {
thoughtSignatureResult = partResult.Get("thought_signature")
}
// Skip thoughtSignature parts (encrypted reasoning not exposed downstream).
if thoughtSignatureResult.Exists() && thoughtSignatureResult.String() != "" {
continue
}
if partTextResult.Exists() { if partTextResult.Exists() {
text := partTextResult.String()
// Handle text content, distinguishing between regular content and reasoning/thoughts. // Handle text content, distinguishing between regular content and reasoning/thoughts.
if partResult.Get("thought").Bool() { if partResult.Get("thought").Bool() {
template, _ = sjson.Set(template, "choices.0.delta.reasoning_content", partTextResult.String()) template, _ = sjson.Set(template, "choices.0.delta.reasoning_content", text)
} else { } else {
template, _ = sjson.Set(template, "choices.0.delta.content", partTextResult.String()) template, _ = sjson.Set(template, "choices.0.delta.content", text)
} }
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant") template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
} else if functionCallResult.Exists() { } else if functionCallResult.Exists() {