-
Notifications
You must be signed in to change notification settings - Fork 7.2k
Fix #5878: Preserve reasoning_content from DeepSeek thinking mode in conversation history #5880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d93040e
e716541
ce4399e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1330,14 +1330,18 @@ def call_llm_native_tools( | |
| self.state.pending_tool_calls = list(answer) | ||
| return "native_tool_calls" | ||
|
|
||
| reasoning = self._get_llm_reasoning_content() | ||
|
|
||
| if isinstance(answer, BaseModel): | ||
| self.state.current_answer = AgentFinish( | ||
| thought="", | ||
| output=answer, | ||
| text=answer.model_dump_json(), | ||
| ) | ||
| self._invoke_step_callback(self.state.current_answer) | ||
| self._append_message_to_state(answer.model_dump_json()) | ||
| self._append_message_to_state( | ||
| answer.model_dump_json(), reasoning_content=reasoning | ||
| ) | ||
|
Comment on lines
+1333
to
+1344
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tool-call responses still lose This propagation only covers final-answer branches. If the LLM returns tool calls, routing exits before using Suggested fix@@
- # Check if the response is a list of tool calls
+ reasoning = self._get_llm_reasoning_content()
+
+ # Check if the response is a list of tool calls
if isinstance(answer, list) and answer and self._is_tool_call_list(answer):
# Store tool calls for sequential processing
self.state.pending_tool_calls = list(answer)
return "native_tool_calls"
-
- reasoning = self._get_llm_reasoning_content()
@@
if tool_calls_to_report:
assistant_message: LLMMessage = {
"role": "assistant",
"content": None,
"tool_calls": tool_calls_to_report,
}
+ reasoning = self._get_llm_reasoning_content()
+ if reasoning is not None:
+ assistant_message["reasoning_content"] = reasoning
if all(type(tc).__qualname__ == "Part" for tc in pending_tool_calls):
assistant_message["raw_tool_call_parts"] = list(pending_tool_calls)
self.state.messages.append(assistant_message)Also applies to: 1355-1367 🤖 Prompt for AI Agents |
||
| return self._route_finish_with_todos("native_finished") | ||
|
|
||
| # Text response - this is the final answer | ||
|
|
@@ -1348,7 +1352,7 @@ def call_llm_native_tools( | |
| text=answer, | ||
| ) | ||
| self._invoke_step_callback(self.state.current_answer) | ||
| self._append_message_to_state(answer) | ||
| self._append_message_to_state(answer, reasoning_content=reasoning) | ||
|
|
||
| return self._route_finish_with_todos("native_finished") | ||
|
|
||
|
|
@@ -1359,7 +1363,7 @@ def call_llm_native_tools( | |
| text=str(answer), | ||
| ) | ||
| self._invoke_step_callback(self.state.current_answer) | ||
| self._append_message_to_state(str(answer)) | ||
| self._append_message_to_state(str(answer), reasoning_content=reasoning) | ||
|
|
||
| return self._route_finish_with_todos("native_finished") | ||
|
|
||
|
|
@@ -2813,16 +2817,26 @@ def _handle_step_callback_task_result(self, task: asyncio.Task[Any]) -> None: | |
| color="red", | ||
| ) | ||
|
|
||
| def _get_llm_reasoning_content(self) -> str | None: | ||
| """Return reasoning_content from the last LLM response, if any.""" | ||
| return getattr(self.llm, "reasoning_content", None) | ||
|
|
||
| def _append_message_to_state( | ||
| self, text: str, role: Literal["user", "assistant", "system"] = "assistant" | ||
| self, | ||
| text: str, | ||
| role: Literal["user", "assistant", "system"] = "assistant", | ||
| reasoning_content: str | None = None, | ||
| ) -> None: | ||
| """Add message to state conversation history. | ||
|
|
||
| Args: | ||
| text: Message content. | ||
| role: Message role (default: assistant). | ||
| reasoning_content: Optional reasoning content from the LLM response. | ||
| """ | ||
| self.state.messages.append(format_message_for_llm(text, role=role)) | ||
| self.state.messages.append( | ||
| format_message_for_llm(text, role=role, reasoning_content=reasoning_content) | ||
| ) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| def _show_start_logs(self) -> None: | ||
| """Emit agent start event.""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1232,6 +1232,15 @@ def _handle_non_streaming_response( | |
| 0 | ||
| ].message | ||
| text_response = response_message.content or "" | ||
|
|
||
| # Store reasoning_content for models that return it (e.g. DeepSeek thinking mode) | ||
| self.reasoning_content: str | None = getattr( | ||
| response_message, "reasoning_content", None | ||
| ) or ( | ||
| response_message.get("reasoning_content") | ||
| if hasattr(response_message, "get") | ||
| else None | ||
| ) | ||
|
Comment on lines
+1236
to
+1243
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Async path is missing reasoning_content reset/extraction parity. Line 1754 resets state only in Suggested parity patch@@
async def _ahandle_non_streaming_response(
@@
response_message = cast(Choices, cast(ModelResponse, response).choices)[
0
].message
text_response = response_message.content or ""
+
+ # Store reasoning_content for models that return it (e.g. DeepSeek thinking mode)
+ self.reasoning_content = getattr(
+ response_message, "reasoning_content", None
+ ) or (
+ response_message.get("reasoning_content")
+ if hasattr(response_message, "get")
+ else None
+ )
@@
async def acall(
@@
- with llm_call_context() as call_id:
+ self.reasoning_content: str | None = None
+ with llm_call_context() as call_id:Also applies to: 1754-1754 🤖 Prompt for AI Agents |
||
| # --- 3) Handle callbacks with usage info | ||
| if callbacks and len(callbacks) > 0: | ||
| for callback in callbacks: | ||
|
|
@@ -1742,6 +1751,7 @@ def call( | |
| ValueError: If response format is not supported | ||
| LLMContextLengthExceededError: If input exceeds model's context limit | ||
| """ | ||
| self.reasoning_content = None | ||
| with llm_call_context() as call_id: | ||
| crewai_event_bus.emit( | ||
| self, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,4 +27,5 @@ class LLMMessage(TypedDict): | |
| name: NotRequired[str] | ||
| tool_calls: NotRequired[list[dict[str, Any]]] | ||
| raw_tool_call_parts: NotRequired[list[Any]] | ||
| reasoning_content: NotRequired[str | None] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix ruff formatting before merge (CI is failing). Pipeline is failing on 🤖 Prompt for AI Agents |
||
| files: NotRequired[dict[str, FileInput]] | ||
Uh oh!
There was an error while loading. Please reload this page.