Skip to content
This repository was archived by the owner on Sep 23, 2026. It is now read-only.

fix(kosong): round-trip empty reasoning content - #2446

Merged
RealKai42 merged 1 commit into
mainfrom
fix-reasoning-empty-string
Jun 10, 2026
Merged

RealKai42 merged 1 commit into
mainfrom
fix-reasoning-empty-string

Conversation

@RealKai42

@RealKai42 RealKai42 commented Jun 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Keep reasoning_content when a ThinkPart exists even if its text is empty.
  • Avoid adding reasoning_content to messages that never contained reasoning content.
  • Apply the same behavior to Kimi and OpenAI legacy provider conversion paths.

Tests

  • Added regression coverage for empty reasoning_content round-tripping.
  • cd packages/kosong && uv run pytest tests/api_snapshot_tests/test_kimi.py tests/api_snapshot_tests/test_openai_legacy.py -v

Open in Devin Review

Track whether a message contained ThinkPart separately from whether the
reasoning text is non-empty so empty reasoning_content is still sent for
Kimi and OpenAI legacy providers. Add regression coverage for empty
reasoning content round-tripping.
Copilot AI review requested due to automatic review settings June 10, 2026 06:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes message conversion in kosong so that an empty ThinkPart is still preserved as empty reasoning_content when converting to OpenAI-compatible request payloads, while avoiding emitting reasoning_content for messages that never had any thinking parts. This aligns Kimi and OpenAI legacy provider conversion behavior and adds regression tests to prevent reintroducing the issue.

Changes:

  • Track the presence of ThinkPart via a boolean flag so reasoning_content is emitted even when its text is empty.
  • Apply the same “emit only if a ThinkPart existed” logic to both Kimi and OpenAI legacy request conversion paths.
  • Add snapshot/regression tests covering empty reasoning_content round-tripping.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
packages/kosong/src/kosong/contrib/chat_provider/openai_legacy.py Emit reasoning_content based on presence of ThinkPart (not string truthiness), enabling empty-string preservation.
packages/kosong/src/kosong/chat_provider/kimi.py Same conversion fix for Kimi: preserve empty reasoning when a ThinkPart exists; avoid adding reasoning otherwise.
packages/kosong/tests/api_snapshot_tests/test_openai_legacy.py Add regression test asserting empty reasoning_content is included in outgoing OpenAI legacy request body.
packages/kosong/tests/api_snapshot_tests/test_kimi.py Extend message-conversion snapshot coverage for assistant messages with empty reasoning.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@RealKai42
RealKai42 added this pull request to the merge queue Jun 10, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Asymmetry between response parsing and message conversion for empty reasoning

The PR ensures empty reasoning_content is preserved when sending messages to the API (via has_reasoning flag). However, the response parsing side in both providers still uses walrus-operator truthiness checks that will silently drop empty reasoning content from API responses:

  • kimi.py:423: if reasoning_content := getattr(message, "reasoning_content", None): — empty string is falsy, so ThinkPart won't be yielded
  • kimi.py:456: same pattern for streaming
  • openai_legacy.py:271 and openai_legacy.py:305: same pattern

This means if an API returns reasoning_content: "", it won't be converted to a ThinkPart(think="") on ingestion. So while a manually-constructed ThinkPart(think="") is now properly round-tripped through message conversion, an API response with empty reasoning won't produce one in the first place. This is pre-existing behavior and may be intentional (APIs rarely return empty reasoning), but worth noting the asymmetry.

(Refers to lines 423-425)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Merged via the queue into main with commit eca4334 Jun 10, 2026
22 checks passed
@RealKai42
RealKai42 deleted the fix-reasoning-empty-string branch June 10, 2026 06:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants