fix(edge): Gemini 지연 서명을 보존한다

This commit is contained in:
toki 2026-08-15 10:45:45 +09:00
parent ead8b50056
commit bb0b916bf5
2 changed files with 22 additions and 2 deletions

View file

@ -644,8 +644,9 @@ func decodeOpenAIPresetSSE(body []byte) (normalizedStageOutput, error) {
stage := normalizedStageOutput{}
identity := &hotPathProviderIdentity{}
type toolState struct {
id, name string
args strings.Builder
id, name string
signature string
args strings.Builder
}
tools := make(map[int]*toolState)
for _, payload := range sseDataPayloads(body) {
@ -723,6 +724,9 @@ func decodeOpenAIPresetSSE(body []byte) (normalizedStageOutput, error) {
if delta.Function.Name != "" {
state.name = delta.Function.Name
}
if delta.ExtraContent.Google != nil && delta.ExtraContent.Google.ThoughtSignature != "" {
state.signature = delta.ExtraContent.Google.ThoughtSignature
}
state.args.WriteString(delta.Function.Arguments)
if delta.Function.Arguments != "" {
stage.Deltas = append(stage.Deltas, normalizedStageDelta{
@ -746,6 +750,9 @@ func decodeOpenAIPresetSSE(body []byte) (normalizedStageOutput, error) {
if !ok {
return normalizedStageOutput{}, fmt.Errorf("preset Chat stream tool indices are not contiguous")
}
if state.signature != "" && !strings.HasPrefix(state.id, geminiThoughtSignatureToolIDPrefix) {
state.id = encodeGeminiThoughtSignatureToolID(state.id, state.signature)
}
call, err := normalizedToolCallFromParts(state.id, state.name, state.args.String())
if err != nil {
return normalizedStageOutput{}, err

View file

@ -116,6 +116,19 @@ func TestOpenAIPresetSSESeparatesNewToolIDsWithoutIndices(t *testing.T) {
}
}
func TestOpenAIPresetSSECarriesLateGeminiThoughtSignature(t *testing.T) {
body := []byte("data: {\"id\":\"chat-1\",\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"call-1\",\"function\":{\"name\":\"read_file\",\"arguments\":\"{\\\"path\\\":\\\"plan.md\\\"}\"}}]}}]}\n\n" +
"data: {\"id\":\"chat-1\",\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"extra_content\":{\"google\":{\"thought_signature\":\"late-signature\"}},\"function\":{}}]}}]}\n\n" +
"data: {\"id\":\"chat-1\",\"choices\":[{\"delta\":{},\"finish_reason\":\"tool_calls\"}],\"usage\":{\"prompt_tokens\":1,\"completion_tokens\":1,\"total_tokens\":2}}\n\ndata: [DONE]\n\n")
stage, err := decodeOpenAIPresetSSE(body)
if err != nil {
t.Fatal(err)
}
if len(stage.ToolCalls) != 1 || !strings.HasPrefix(stage.ToolCalls[0].ProviderCallID, geminiThoughtSignatureToolIDPrefix) {
t.Fatalf("late Gemini signature was not retained: %+v", stage.ToolCalls)
}
}
func TestProviderChatTokenLimitNormalizationUsesSelectedProfile(t *testing.T) {
tests := []struct {
name string