Merge PR #1330: fix thinking mode support (reasoning_content + thinking_blocks)
This commit is contained in:
@@ -150,6 +150,7 @@ Reply directly with text for conversations. Only use the 'message' tool to send
|
|||||||
content: str | None,
|
content: str | None,
|
||||||
tool_calls: list[dict[str, Any]] | None = None,
|
tool_calls: list[dict[str, Any]] | None = None,
|
||||||
reasoning_content: str | None = None,
|
reasoning_content: str | None = None,
|
||||||
|
thinking_blocks: list[dict] | None = None,
|
||||||
) -> list[dict[str, Any]]:
|
) -> list[dict[str, Any]]:
|
||||||
"""Add an assistant message to the message list."""
|
"""Add an assistant message to the message list."""
|
||||||
msg: dict[str, Any] = {"role": "assistant", "content": content}
|
msg: dict[str, Any] = {"role": "assistant", "content": content}
|
||||||
@@ -157,5 +158,7 @@ Reply directly with text for conversations. Only use the 'message' tool to send
|
|||||||
msg["tool_calls"] = tool_calls
|
msg["tool_calls"] = tool_calls
|
||||||
if reasoning_content is not None:
|
if reasoning_content is not None:
|
||||||
msg["reasoning_content"] = reasoning_content
|
msg["reasoning_content"] = reasoning_content
|
||||||
|
if thinking_blocks:
|
||||||
|
msg["thinking_blocks"] = thinking_blocks
|
||||||
messages.append(msg)
|
messages.append(msg)
|
||||||
return messages
|
return messages
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ class AgentLoop:
|
|||||||
messages = self.context.add_assistant_message(
|
messages = self.context.add_assistant_message(
|
||||||
messages, response.content, tool_call_dicts,
|
messages, response.content, tool_call_dicts,
|
||||||
reasoning_content=response.reasoning_content,
|
reasoning_content=response.reasoning_content,
|
||||||
|
thinking_blocks=response.thinking_blocks,
|
||||||
)
|
)
|
||||||
|
|
||||||
for tool_call in response.tool_calls:
|
for tool_call in response.tool_calls:
|
||||||
@@ -238,6 +239,7 @@ class AgentLoop:
|
|||||||
break
|
break
|
||||||
messages = self.context.add_assistant_message(
|
messages = self.context.add_assistant_message(
|
||||||
messages, clean, reasoning_content=response.reasoning_content,
|
messages, clean, reasoning_content=response.reasoning_content,
|
||||||
|
thinking_blocks=response.thinking_blocks,
|
||||||
)
|
)
|
||||||
final_content = clean
|
final_content = clean
|
||||||
break
|
break
|
||||||
@@ -451,7 +453,7 @@ class AgentLoop:
|
|||||||
"""Save new-turn messages into session, truncating large tool results."""
|
"""Save new-turn messages into session, truncating large tool results."""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
for m in messages[skip:]:
|
for m in messages[skip:]:
|
||||||
entry = {k: v for k, v in m.items() if k != "reasoning_content"}
|
entry = dict(m)
|
||||||
role, content = entry.get("role"), entry.get("content")
|
role, content = entry.get("role"), entry.get("content")
|
||||||
if role == "assistant" and not content and not entry.get("tool_calls"):
|
if role == "assistant" and not content and not entry.get("tool_calls"):
|
||||||
continue # skip empty assistant messages — they poison session context
|
continue # skip empty assistant messages — they poison session context
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class LLMResponse:
|
|||||||
finish_reason: str = "stop"
|
finish_reason: str = "stop"
|
||||||
usage: dict[str, int] = field(default_factory=dict)
|
usage: dict[str, int] = field(default_factory=dict)
|
||||||
reasoning_content: str | None = None # Kimi, DeepSeek-R1 etc.
|
reasoning_content: str | None = None # Kimi, DeepSeek-R1 etc.
|
||||||
|
thinking_blocks: list[dict] | None = None # Anthropic extended thinking
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_tool_calls(self) -> bool:
|
def has_tool_calls(self) -> bool:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from nanobot.providers.registry import find_by_model, find_gateway
|
|||||||
|
|
||||||
# Standard OpenAI chat-completion message keys plus reasoning_content for
|
# Standard OpenAI chat-completion message keys plus reasoning_content for
|
||||||
# thinking-enabled models (Kimi k2.5, DeepSeek-R1, etc.).
|
# thinking-enabled models (Kimi k2.5, DeepSeek-R1, etc.).
|
||||||
_ALLOWED_MSG_KEYS = frozenset({"role", "content", "tool_calls", "tool_call_id", "name", "reasoning_content"})
|
_ALLOWED_MSG_KEYS = frozenset({"role", "content", "tool_calls", "tool_call_id", "name", "reasoning_content", "thinking_blocks"})
|
||||||
_ALNUM = string.ascii_letters + string.digits
|
_ALNUM = string.ascii_letters + string.digits
|
||||||
|
|
||||||
def _short_tool_id() -> str:
|
def _short_tool_id() -> str:
|
||||||
@@ -271,6 +271,7 @@ class LiteLLMProvider(LLMProvider):
|
|||||||
}
|
}
|
||||||
|
|
||||||
reasoning_content = getattr(message, "reasoning_content", None) or None
|
reasoning_content = getattr(message, "reasoning_content", None) or None
|
||||||
|
thinking_blocks = getattr(message, "thinking_blocks", None) or None
|
||||||
|
|
||||||
return LLMResponse(
|
return LLMResponse(
|
||||||
content=message.content,
|
content=message.content,
|
||||||
@@ -278,6 +279,7 @@ class LiteLLMProvider(LLMProvider):
|
|||||||
finish_reason=choice.finish_reason or "stop",
|
finish_reason=choice.finish_reason or "stop",
|
||||||
usage=usage,
|
usage=usage,
|
||||||
reasoning_content=reasoning_content,
|
reasoning_content=reasoning_content,
|
||||||
|
thinking_blocks=thinking_blocks,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_default_model(self) -> str:
|
def get_default_model(self) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user