Skip to content

Conversation

@shitiandmw
Copy link

@shitiandmw shitiandmw commented Nov 18, 2025

Background

As reported in #1070 by @LubyRuffy, different OpenAI-compatible providers use different field names for reasoning content:

  • DeepSeek: uses reasoning_content
  • LM Studio, Ollama, and other LLM providers: use reasoning

This PR provides transparent support for both formats without breaking existing implementations.

Changes

  • Modified ChatCompletionMessage.UnmarshalJSON to support the reasoning field
  • Added custom UnmarshalJSON method for ChatCompletionStreamChoiceDelta
  • Both reasoning_content and reasoning fields map to the same ReasoningContent property
  • Priority handling: reasoning_content takes precedence over reasoning (backward compatible)
  • Updated documentation comments to reflect support for both styles

Implementation Details

The implementation uses custom unmarshaling with a fallback mechanism:

  1. First attempts to unmarshal reasoning_content (existing behavior)
  2. If empty, falls back to reasoning field
  3. Always exposes data through the unified ReasoningContent field

This approach ensures:

  • Zero breaking changes - existing code continues to work
  • Transparent to users - no API changes required
  • Performance optimized - single JSON unmarshal operation
  • Compatible with all providers - works with DeepSeek, LM Studio, Ollama, etc.

Testing

Added comprehensive test coverage in chat_reasoning_test.go:

  • ✅ DeepSeek style (reasoning_content) support
  • ✅ OpenAI style (reasoning) support
  • ✅ Priority handling when both fields are present
  • ✅ MultiContent message support
  • ✅ Real-world streaming response parsing
  • ✅ Marshal/Unmarshal consistency

All existing tests pass without modification.

Example Usage

// Works with both DeepSeek and LM Studio responses
stream, err := client.CreateChatCompletionStream(ctx, req)
for {
response, err := stream.Recv()
// ReasoningContent will be populated regardless of provider
reasoning := response.Choices[0].Delta.ReasoningContent
}## Breaking Changes
None. This is a fully backward-compatible enhancement.

Checklist

- Support both reasoning_content (DeepSeek style) and reasoning (OpenAI style)
- Add custom UnmarshalJSON to handle field mapping transparently
- Add comprehensive tests for reasoning field support
- Maintain backward compatibility with existing code
@codecov
Copy link

codecov bot commented Nov 18, 2025

Codecov Report

❌ Patch coverage is 95.83333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.52%. Comparing base (5d7a276) to head (c980c5d).

Files with missing lines Patch % Lines
chat_stream.go 90.90% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1092      +/-   ##
==========================================
- Coverage   99.59%   99.52%   -0.07%     
==========================================
  Files          34       34              
  Lines        2209     1887     -322     
==========================================
- Hits         2200     1878     -322     
+ Misses          6        5       -1     
- Partials        3        4       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Add test for empty reasoning_content with reasoning fallback
- Add error handling tests for invalid JSON
- Coverage increased to 99.9%
- Add test for non-empty reasoning_content with empty reasoning
- Add test for all fields including FunctionCall and ToolCalls
- Ensure all code paths are tested
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant