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"`
|
Role string `json:"role"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
Reasoning string `json:"reasoning,omitempty"`
|
||||||
|
Thinking string `json:"thinking,omitempty"`
|
||||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +91,8 @@ func SerializeMessages(messages []Message) []any {
|
||||||
Role: m.Role,
|
Role: m.Role,
|
||||||
Content: m.Content,
|
Content: m.Content,
|
||||||
ReasoningContent: m.ReasoningContent,
|
ReasoningContent: m.ReasoningContent,
|
||||||
|
Reasoning: m.Reasoning,
|
||||||
|
Thinking: m.Thinking,
|
||||||
ToolCalls: m.ToolCalls,
|
ToolCalls: m.ToolCalls,
|
||||||
ToolCallID: m.ToolCallID,
|
ToolCallID: m.ToolCallID,
|
||||||
})
|
})
|
||||||
|
|
@ -127,6 +131,12 @@ func SerializeMessages(messages []Message) []any {
|
||||||
if m.ReasoningContent != "" {
|
if m.ReasoningContent != "" {
|
||||||
msg["reasoning_content"] = 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)
|
out = append(out, msg)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|
@ -142,6 +152,7 @@ func ParseResponse(body io.Reader) (*LLMResponse, error) {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ReasoningContent string `json:"reasoning_content"`
|
ReasoningContent string `json:"reasoning_content"`
|
||||||
Reasoning string `json:"reasoning"`
|
Reasoning string `json:"reasoning"`
|
||||||
|
Thinking string `json:"thinking"`
|
||||||
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
||||||
ToolCalls []struct {
|
ToolCalls []struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
@ -208,10 +219,22 @@ func ParseResponse(body io.Reader) (*LLMResponse, error) {
|
||||||
toolCalls = append(toolCalls, toolCall)
|
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{
|
return &LLMResponse{
|
||||||
Content: choice.Message.Content,
|
Content: content,
|
||||||
ReasoningContent: choice.Message.ReasoningContent,
|
ReasoningContent: choice.Message.ReasoningContent,
|
||||||
Reasoning: choice.Message.Reasoning,
|
Reasoning: choice.Message.Reasoning,
|
||||||
|
Thinking: choice.Message.Thinking,
|
||||||
ReasoningDetails: choice.Message.ReasoningDetails,
|
ReasoningDetails: choice.Message.ReasoningDetails,
|
||||||
ToolCalls: toolCalls,
|
ToolCalls: toolCalls,
|
||||||
FinishReason: choice.FinishReason,
|
FinishReason: choice.FinishReason,
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,9 @@ func parseStreamResponse(
|
||||||
onChunk func(accumulated string),
|
onChunk func(accumulated string),
|
||||||
) (*LLMResponse, error) {
|
) (*LLMResponse, error) {
|
||||||
var textContent strings.Builder
|
var textContent strings.Builder
|
||||||
|
var reasoningContent strings.Builder
|
||||||
|
var reasoning strings.Builder
|
||||||
|
var thinking strings.Builder
|
||||||
var finishReason string
|
var finishReason string
|
||||||
var usage *UsageInfo
|
var usage *UsageInfo
|
||||||
|
|
||||||
|
|
@ -273,8 +276,11 @@ func parseStreamResponse(
|
||||||
var chunk struct {
|
var chunk struct {
|
||||||
Choices []struct {
|
Choices []struct {
|
||||||
Delta struct {
|
Delta struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ToolCalls []struct {
|
ReasoningContent string `json:"reasoning_content"`
|
||||||
|
Reasoning string `json:"reasoning"`
|
||||||
|
Thinking string `json:"thinking"`
|
||||||
|
ToolCalls []struct {
|
||||||
Index int `json:"index"`
|
Index int `json:"index"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Function *struct {
|
Function *struct {
|
||||||
|
|
@ -301,13 +307,24 @@ func parseStreamResponse(
|
||||||
}
|
}
|
||||||
|
|
||||||
choice := chunk.Choices[0]
|
choice := chunk.Choices[0]
|
||||||
|
delta := choice.Delta
|
||||||
|
|
||||||
// Accumulate text content
|
// Accumulate text content with fallback to reasoning/thinking
|
||||||
if choice.Delta.Content != "" {
|
if delta.Content != "" {
|
||||||
textContent.WriteString(choice.Delta.Content)
|
textContent.WriteString(delta.Content)
|
||||||
if onChunk != nil {
|
} else if delta.Thinking != "" {
|
||||||
onChunk(textContent.String())
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if onChunk != nil {
|
||||||
|
onChunk(textContent.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate tool call deltas
|
// Accumulate tool call deltas
|
||||||
|
|
@ -366,10 +383,13 @@ func parseStreamResponse(
|
||||||
}
|
}
|
||||||
|
|
||||||
return &LLMResponse{
|
return &LLMResponse{
|
||||||
Content: textContent.String(),
|
Content: textContent.String(),
|
||||||
ToolCalls: toolCalls,
|
ReasoningContent: reasoningContent.String(),
|
||||||
FinishReason: finishReason,
|
Reasoning: reasoning.String(),
|
||||||
Usage: usage,
|
Thinking: thinking.String(),
|
||||||
|
ToolCalls: toolCalls,
|
||||||
|
FinishReason: finishReason,
|
||||||
|
Usage: usage,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,11 @@ type FunctionCall struct {
|
||||||
type LLMResponse struct {
|
type LLMResponse struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
Reasoning string `json:"reasoning,omitempty"`
|
||||||
|
Thinking string `json:"thinking,omitempty"`
|
||||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
FinishReason string `json:"finish_reason"`
|
FinishReason string `json:"finish_reason"`
|
||||||
Usage *UsageInfo `json:"usage,omitempty"`
|
Usage *UsageInfo `json:"usage,omitempty"`
|
||||||
Reasoning string `json:"reasoning"`
|
|
||||||
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,6 +68,8 @@ type Message struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Media []string `json:"media,omitempty"`
|
Media []string `json:"media,omitempty"`
|
||||||
ReasoningContent string `json:"reasoning_content,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
|
SystemParts []ContentBlock `json:"system_parts,omitempty"` // structured system blocks for cache-aware adapters
|
||||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue