Skip to content

fix(formatter): preserve reasoning content on surviving assistant turns#1538

Open
Alexxigang wants to merge 1 commit intoagentscope-ai:mainfrom
Alexxigang:fix/reasoning-content-injection
Open

fix(formatter): preserve reasoning content on surviving assistant turns#1538
Alexxigang wants to merge 1 commit intoagentscope-ai:mainfrom
Alexxigang:fix/reasoning-content-injection

Conversation

@Alexxigang
Copy link
Contributor

Summary

  • preserve reasoning_content for assistant messages that are still present after the base formatter runs
  • stop treating dropped thinking-only assistant turns as a hard mismatch
  • add unit coverage for dropped thinking-only turns and assistant-turn alignment

Why this fix

FileBlockSupportFormatter collected reasoning blocks before calling the base formatter, but then required the input and output assistant counts to match exactly. AgentScope drops assistant turns that only contain thinking blocks, so the counts diverged and CoPaw skipped every reasoning_content injection while logging a warning on every request.

This change aligns reasoning injection only against assistant messages that actually survive formatting, which preserves valid reasoning payloads without spamming mismatch warnings.

Fixes #1532.

Validation

$env:PYTHONPATH='D:/project/me/githubAutoPR/copaw-git/src'; pytest tests/unit/agents/test_model_factory_reasoning_content.py -q

Result: 2 passed

@Alexxigang Alexxigang requested a deployment to maintainer-approved March 15, 2026 16:25 — with GitHub Actions Waiting
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where 'reasoning_content' was not being correctly injected into assistant messages due to a strict message count comparison after formatting. Previously, if AgentScope's formatter dropped assistant turns containing only thinking blocks, it caused a mismatch, leading to 'reasoning_content' being skipped and warnings logged. The changes introduce a more robust mechanism to identify and align 'reasoning_content' only with assistant messages that genuinely survive the formatting process, ensuring proper payload injection and eliminating erroneous warnings.

Highlights

  • Reasoning Content Preservation: Implemented logic to preserve 'reasoning_content' for assistant messages that remain after the base formatter processes them.
  • Mismatch Handling Improvement: Modified the formatter to no longer consider dropped assistant turns that contain only thinking blocks as a hard mismatch, preventing unnecessary warnings.
  • Unit Test Coverage: Added new unit tests to cover scenarios involving dropped thinking-only turns and the correct alignment of reasoning content with surviving assistant messages.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/copaw/agents/model_factory.py
    • Added a new helper function '_assistant_message_survives_format' to determine if an assistant message will be kept by AgentScope formatters.
    • Modified the '_format' method within 'FileBlockSupportFormatter' to use '_assistant_message_survives_format' when identifying input assistant messages, ensuring 'reasoning_content' is only applied to messages that are not dropped.
    • Removed the strict 'len(in_assistant) != len(out_assistant)' check and associated warning, as the new logic correctly handles message count discrepancies caused by dropped thinking-only turns.
  • tests/unit/agents/test_model_factory_reasoning_content.py
    • Added a new test file to provide dedicated unit coverage for 'reasoning_content' injection logic.
    • Included a test case to verify that 'reasoning_content' is correctly injected and no warnings are logged when thinking-only assistant messages are dropped by the formatter.
    • Added a test case to ensure 'reasoning_content' remains properly aligned with the correct surviving assistant messages after formatting.
Activity
  • The author provided validation steps, including a 'pytest' command, which resulted in '2 passed' tests.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses an issue where reasoning_content was being dropped from assistant messages. The introduction of _assistant_message_survives_format to predict which messages persist after formatting is a smart solution to correctly align reasoning content and prevent erroneous warnings. The accompanying unit tests are well-written and cover the key scenarios. I have a couple of suggestions to enhance the robustness and readability of the implementation.

Comment on lines +184 to +196
in_assistant = [
m for m in msgs if _assistant_message_survives_format(m)
]
out_assistant = [
m for m in messages if m.get("role") == "assistant"
]
if len(in_assistant) != len(out_assistant):
logger.warning(
"Assistant message count mismatch after formatting "
"(%d before, %d after). "
"Skipping reasoning_content injection.",
len(in_assistant),
len(out_assistant),
)
else:
for in_msg, out_msg in zip(
in_assistant,
out_assistant,
):
reasoning = reasoning_contents.get(id(in_msg))
if reasoning:
out_msg["reasoning_content"] = reasoning
for in_msg, out_msg in zip(
in_assistant,
out_assistant,
):
reasoning = reasoning_contents.get(id(in_msg))
if reasoning:
out_msg["reasoning_content"] = reasoning
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Removing the length check between the predicted surviving messages and the actual formatted messages could hide future bugs. Since _assistant_message_survives_format is a 'best-effort' check, if the underlying formatter's logic changes, this could lead to silent misalignment or dropping of reasoning_content. It would be safer to reintroduce a warning log if a mismatch occurs. This would provide a valuable signal for debugging if the prediction logic becomes inaccurate over time.

                in_assistant = [
                    m for m in msgs if _assistant_message_survives_format(m)
                ]
                out_assistant = [
                    m for m in messages if m.get("role") == "assistant"
                ]
                if len(in_assistant) != len(out_assistant):
                    logger.warning(
                        "Assistant message count mismatch after formatting "
                        "(%d predicted, %d actual). "
                        "Reasoning content may be misaligned.",
                        len(in_assistant),
                        len(out_assistant),
                    )
                for in_msg, out_msg in zip(
                    in_assistant,
                    out_assistant,
                ):
                    reasoning = reasoning_contents.get(id(in_msg))
                    if reasoning:
                        out_msg["reasoning_content"] = reasoning

Comment on lines +114 to +120
if block_type == "thinking":
continue
if block_type == "text":
if block.get("text"):
return True
continue
return True
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The logic within this for loop can be simplified for improved readability and maintainability. By restructuring the conditions, you can make the code more concise while preserving the existing functionality.

Suggested change
if block_type == "thinking":
continue
if block_type == "text":
if block.get("text"):
return True
continue
return True
if block_type == "thinking":
continue
if block_type == "text" and not block.get("text"):
continue
# Any other block type, or a text block with content, survives.
return True

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.

reasoning_content injection fails with "Assistant message count mismatch" warning in FileBlockSupportFormatter

1 participant