Add OpenRouter reasoning support

This commit is contained in:
dwrz
2026-06-29 16:25:42 +00:00
parent ec9e0a80f8
commit d212a52120
3 changed files with 25 additions and 7 deletions

View File

@@ -444,6 +444,13 @@ func (c *Client) completionsStream(ctx context.Context, messages []Message, mode
ReasoningDelta: delta.ReasoningContent, ReasoningDelta: delta.ReasoningContent,
} }
} }
if delta.Reasoning != "" {
acc.reasoning.WriteString(delta.Reasoning)
events <- StreamEvent{
Type: streamEventReasoningDelta,
ReasoningDelta: delta.Reasoning,
}
}
// Accumulate tool call deltas by index. // Accumulate tool call deltas by index.
for _, tc := range delta.ToolCalls { for _, tc := range delta.ToolCalls {
idx := 0 idx := 0

View File

@@ -138,6 +138,7 @@ type Delta struct {
Content string `json:"content,omitempty"` Content string `json:"content,omitempty"`
Refusal string `json:"refusal,omitempty"` Refusal string `json:"refusal,omitempty"`
ReasoningContent string `json:"reasoning_content,omitempty"` ReasoningContent string `json:"reasoning_content,omitempty"`
Reasoning string `json:"reasoning,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"` ToolCalls []ToolCall `json:"tool_calls,omitempty"`
} }
@@ -199,6 +200,7 @@ type Message struct {
ContentParts []ContentPart `json:"content,omitempty"` ContentParts []ContentPart `json:"content,omitempty"`
Refusal string `json:"refusal,omitempty"` Refusal string `json:"refusal,omitempty"`
ReasoningContent string `json:"reasoning_content,omitempty"` ReasoningContent string `json:"reasoning_content,omitempty"`
Reasoning string `json:"reasoning,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,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"`
@@ -244,6 +246,10 @@ func (m *Message) UnmarshalJSON(data []byte) error {
m.ContentParts = append(m.ContentParts, part) m.ContentParts = append(m.ContentParts, part)
} }
} }
// Normalize: if ReasoningContent is empty but Reasoning is set, use Reasoning
if m.ReasoningContent == "" && m.Reasoning != "" {
m.ReasoningContent = m.Reasoning
}
return nil return nil
} }
@@ -254,6 +260,7 @@ type Model struct {
Object string `json:"object"` Object string `json:"object"`
OwnedBy string `json:"owned_by"` OwnedBy string `json:"owned_by"`
Meta *ModelMeta `json:"meta,omitempty"` Meta *ModelMeta `json:"meta,omitempty"`
ContextLength int `json:"context_length,omitempty"`
} }
// ModelMeta contains optional model metadata from the provider. // ModelMeta contains optional model metadata from the provider.

View File

@@ -833,8 +833,12 @@ func (svc *Service) models(w http.ResponseWriter, r *http.Request) {
for _, m := range models { for _, m := range models {
baseID, _, _ := strings.Cut(m.ID, ":") baseID, _, _ := strings.Cut(m.ID, ":")
available[baseID] = struct{}{} available[baseID] = struct{}{}
if m.Meta != nil && m.Meta.NCtx > 0 { cs := m.ContextLength
contextSizes[baseID] = m.Meta.NCtx if cs == 0 && m.Meta != nil {
cs = m.Meta.NCtx
}
if cs > 0 {
contextSizes[baseID] = cs
} }
} }