Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions core/schemas/chatcompletions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1547,13 +1547,14 @@ type ChatStreamResponseChoice struct {

// ChatStreamResponseChoiceDelta represents a delta in the stream response
type ChatStreamResponseChoiceDelta struct {
Role *string `json:"role,omitempty"` // Only in the first chunk
Content *string `json:"content,omitempty"` // May be empty string or null
Refusal *string `json:"refusal,omitempty"` // Refusal content if any
Audio *ChatAudioMessageAudio `json:"audio,omitempty"` // Audio data if any
Reasoning *string `json:"reasoning,omitempty"` // May be empty string or null
Role *string `json:"role,omitempty"` // Only in the first chunk
Content *string `json:"content,omitempty"` // May be empty string or null
Refusal *string `json:"refusal,omitempty"` // Refusal content if any
Audio *ChatAudioMessageAudio `json:"audio,omitempty"` // Audio data if any
Reasoning *string `json:"reasoning,omitempty"` // May be empty string or null
ReasoningDetails []ChatReasoningDetails `json:"reasoning_details,omitempty"`
ToolCalls []ChatAssistantMessageToolCall `json:"tool_calls,omitempty"` // If tool calls used (supports incremental updates)
ToolCalls []ChatAssistantMessageToolCall `json:"tool_calls,omitempty"` // If tool calls used (supports incremental updates)
ExtraContent json.RawMessage `json:"extra_content,omitempty"` // Provider-specific metadata (e.g. Gemini thought markers, thought_signature)
}

// UnmarshalJSON implements custom unmarshalling for ChatStreamResponseChoiceDelta.
Expand Down
35 changes: 35 additions & 0 deletions core/schemas/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -760,9 +760,44 @@ func DeepCopyChatMessage(original ChatMessage) ChatMessage {
copyName := *toolCall.Function.Name
copyToolCall.Function.Name = &copyName
}
if len(toolCall.ExtraContent) > 0 {
copyToolCall.ExtraContent = append(json.RawMessage(nil), toolCall.ExtraContent...)
}
copy.ChatAssistantMessage.ToolCalls[i] = copyToolCall
}
}

// Deep copy ReasoningDetails
if original.ChatAssistantMessage.ReasoningDetails != nil {
copy.ChatAssistantMessage.ReasoningDetails = make([]ChatReasoningDetails, len(original.ChatAssistantMessage.ReasoningDetails))
for i, rd := range original.ChatAssistantMessage.ReasoningDetails {
copyRD := ChatReasoningDetails{
Index: rd.Index,
Type: rd.Type,
}
if rd.ID != nil {
copyID := *rd.ID
copyRD.ID = &copyID
}
if rd.Summary != nil {
copySummary := *rd.Summary
copyRD.Summary = &copySummary
}
if rd.Text != nil {
copyText := *rd.Text
copyRD.Text = &copyText
}
if rd.Signature != nil {
copySig := *rd.Signature
copyRD.Signature = &copySig
}
if rd.Data != nil {
copyData := *rd.Data
copyRD.Data = &copyData
}
copy.ChatAssistantMessage.ReasoningDetails[i] = copyRD
}
}
}

return copy
Expand Down
38 changes: 38 additions & 0 deletions plugins/jsonparser/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,39 @@ func (p *JsonParserPlugin) deepCopyChatStreamResponseChoiceDelta(original *schem
Reasoning: original.Reasoning, // Shallow copy
Refusal: original.Refusal, // Shallow copy
ToolCalls: original.ToolCalls, // Shallow copy - we don't modify tool calls
Audio: original.Audio, // Shallow copy
}

// Deep copy ReasoningDetails — elements contain pointer fields
if len(original.ReasoningDetails) > 0 {
result.ReasoningDetails = make([]schemas.ChatReasoningDetails, len(original.ReasoningDetails))
for i, rd := range original.ReasoningDetails {
copyRD := schemas.ChatReasoningDetails{
Index: rd.Index,
Type: rd.Type,
}
if rd.ID != nil {
v := *rd.ID
copyRD.ID = &v
}
if rd.Summary != nil {
v := *rd.Summary
copyRD.Summary = &v
}
if rd.Text != nil {
v := *rd.Text
copyRD.Text = &v
}
if rd.Signature != nil {
v := *rd.Signature
copyRD.Signature = &v
}
if rd.Data != nil {
v := *rd.Data
copyRD.Data = &v
}
result.ReasoningDetails[i] = copyRD
}
}

// Deep copy Content pointer if it exists (this is what we modify)
Expand All @@ -343,5 +376,10 @@ func (p *JsonParserPlugin) deepCopyChatStreamResponseChoiceDelta(original *schem
result.Content = &contentCopy
}

// Copy ExtraContent (provider metadata like google.thought / thought_signature)
if len(original.ExtraContent) > 0 {
result.ExtraContent = append(json.RawMessage(nil), original.ExtraContent...)
}

return result
}