fix(providers): add thinking and reasoning fallback for OpenAI-compatible providers (Ollama)
This commit is contained in:
parent
6148ccc529
commit
2a34ef048c
3 changed files with 60 additions and 14 deletions
|
|
@ -73,6 +73,8 @@ type openaiMessage struct {
|
|||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
Reasoning string `json:"reasoning,omitempty"`
|
||||
Thinking string `json:"thinking,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
|
@ -89,6 +91,8 @@ func SerializeMessages(messages []Message) []any {
|
|||
Role: m.Role,
|
||||
Content: m.Content,
|
||||
ReasoningContent: m.ReasoningContent,
|
||||
Reasoning: m.Reasoning,
|
||||
Thinking: m.Thinking,
|
||||
ToolCalls: m.ToolCalls,
|
||||
ToolCallID: m.ToolCallID,
|
||||
})
|
||||
|
|
@ -127,6 +131,12 @@ func SerializeMessages(messages []Message) []any {
|
|||
if m.ReasoningContent != "" {
|
||||
msg["reasoning_content"] = m.ReasoningContent
|
||||
}
|
||||
if m.Reasoning != "" {
|
||||
msg["reasoning"] = m.Reasoning
|
||||
}
|
||||
if m.Thinking != "" {
|
||||
msg["thinking"] = m.Thinking
|
||||
}
|
||||
out = append(out, msg)
|
||||
}
|
||||
return out
|
||||
|
|
@ -142,6 +152,7 @@ func ParseResponse(body io.Reader) (*LLMResponse, error) {
|
|||
Content string `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content"`
|
||||
Reasoning string `json:"reasoning"`
|
||||
Thinking string `json:"thinking"`
|
||||
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
||||
ToolCalls []struct {
|
||||
ID string `json:"id"`
|
||||
|
|
@ -208,10 +219,22 @@ func ParseResponse(body io.Reader) (*LLMResponse, error) {
|
|||
toolCalls = append(toolCalls, toolCall)
|
||||
}
|
||||
|
||||
content := choice.Message.Content
|
||||
if content == "" {
|
||||
if choice.Message.Thinking != "" {
|
||||
content = choice.Message.Thinking
|
||||
} else if choice.Message.Reasoning != "" {
|
||||
content = choice.Message.Reasoning
|
||||
} else if choice.Message.ReasoningContent != "" {
|
||||
content = choice.Message.ReasoningContent
|
||||
}
|
||||
}
|
||||
|
||||
return &LLMResponse{
|
||||
Content: choice.Message.Content,
|
||||
Content: content,
|
||||
ReasoningContent: choice.Message.ReasoningContent,
|
||||
Reasoning: choice.Message.Reasoning,
|
||||
Thinking: choice.Message.Thinking,
|
||||
ReasoningDetails: choice.Message.ReasoningDetails,
|
||||
ToolCalls: toolCalls,
|
||||
FinishReason: choice.FinishReason,
|
||||
|
|
|
|||
|
|
@ -241,6 +241,9 @@ func parseStreamResponse(
|
|||
onChunk func(accumulated string),
|
||||
) (*LLMResponse, error) {
|
||||
var textContent strings.Builder
|
||||
var reasoningContent strings.Builder
|
||||
var reasoning strings.Builder
|
||||
var thinking strings.Builder
|
||||
var finishReason string
|
||||
var usage *UsageInfo
|
||||
|
||||
|
|
@ -274,6 +277,9 @@ func parseStreamResponse(
|
|||
Choices []struct {
|
||||
Delta struct {
|
||||
Content string `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content"`
|
||||
Reasoning string `json:"reasoning"`
|
||||
Thinking string `json:"thinking"`
|
||||
ToolCalls []struct {
|
||||
Index int `json:"index"`
|
||||
ID string `json:"id"`
|
||||
|
|
@ -301,14 +307,25 @@ func parseStreamResponse(
|
|||
}
|
||||
|
||||
choice := chunk.Choices[0]
|
||||
delta := choice.Delta
|
||||
|
||||
// Accumulate text content with fallback to reasoning/thinking
|
||||
if delta.Content != "" {
|
||||
textContent.WriteString(delta.Content)
|
||||
} else if delta.Thinking != "" {
|
||||
thinking.WriteString(delta.Thinking)
|
||||
textContent.WriteString(delta.Thinking) // Surface reasoning to user
|
||||
} else if delta.Reasoning != "" {
|
||||
reasoning.WriteString(delta.Reasoning)
|
||||
textContent.WriteString(delta.Reasoning) // Surface reasoning to user
|
||||
} else if delta.ReasoningContent != "" {
|
||||
reasoningContent.WriteString(delta.ReasoningContent)
|
||||
textContent.WriteString(delta.ReasoningContent) // Surface reasoning to user
|
||||
}
|
||||
|
||||
// Accumulate text content
|
||||
if choice.Delta.Content != "" {
|
||||
textContent.WriteString(choice.Delta.Content)
|
||||
if onChunk != nil {
|
||||
onChunk(textContent.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate tool call deltas
|
||||
for _, tc := range choice.Delta.ToolCalls {
|
||||
|
|
@ -367,6 +384,9 @@ func parseStreamResponse(
|
|||
|
||||
return &LLMResponse{
|
||||
Content: textContent.String(),
|
||||
ReasoningContent: reasoningContent.String(),
|
||||
Reasoning: reasoning.String(),
|
||||
Thinking: thinking.String(),
|
||||
ToolCalls: toolCalls,
|
||||
FinishReason: finishReason,
|
||||
Usage: usage,
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@ type FunctionCall struct {
|
|||
type LLMResponse struct {
|
||||
Content string `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
Reasoning string `json:"reasoning,omitempty"`
|
||||
Thinking string `json:"thinking,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Usage *UsageInfo `json:"usage,omitempty"`
|
||||
Reasoning string `json:"reasoning"`
|
||||
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +68,8 @@ type Message struct {
|
|||
Content string `json:"content"`
|
||||
Media []string `json:"media,omitempty"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
Reasoning string `json:"reasoning,omitempty"`
|
||||
Thinking string `json:"thinking,omitempty"`
|
||||
SystemParts []ContentBlock `json:"system_parts,omitempty"` // structured system blocks for cache-aware adapters
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue