Skip to content
Open
3 changes: 3 additions & 0 deletions nanobot/agent/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def add_assistant_message(
tool_calls: list[dict[str, Any]] | None = None,
reasoning_content: str | None = None,
thinking_blocks: list[dict] | None = None,
reasoning_details: Any | None = None,
) -> list[dict[str, Any]]:
"""Add an assistant message to the message list."""
msg: dict[str, Any] = {"role": "assistant", "content": content}
Expand All @@ -160,5 +161,7 @@ def add_assistant_message(
msg["reasoning_content"] = reasoning_content
if thinking_blocks:
msg["thinking_blocks"] = thinking_blocks
if reasoning_details is not None:
msg["reasoning_details"] = reasoning_details
messages.append(msg)
return messages
2 changes: 2 additions & 0 deletions nanobot/agent/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ async def _run_agent_loop(
messages, response.content, tool_call_dicts,
reasoning_content=response.reasoning_content,
thinking_blocks=response.thinking_blocks,
reasoning_details=response.reasoning_details,
)

for tool_call in response.tool_calls:
Expand All @@ -243,6 +244,7 @@ async def _run_agent_loop(
messages = self.context.add_assistant_message(
messages, clean, reasoning_content=response.reasoning_content,
thinking_blocks=response.thinking_blocks,
reasoning_details=response.reasoning_details,
)
final_content = clean
break
Expand Down
12 changes: 12 additions & 0 deletions nanobot/agent/subagent.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,18 @@ async def _run_subagent(
"role": "assistant",
"content": response.content or "",
"tool_calls": tool_call_dicts,
**(
{"reasoning_content": response.reasoning_content}
if response.reasoning_content is not None else {}
),
**(
{"thinking_blocks": response.thinking_blocks}
if response.thinking_blocks else {}
),
**(
{"reasoning_details": response.reasoning_details}
if response.reasoning_details is not None else {}
),
})

# Execute tools
Expand Down
1 change: 1 addition & 0 deletions nanobot/providers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class LLMResponse:
usage: dict[str, int] = field(default_factory=dict)
reasoning_content: str | None = None # Kimi, DeepSeek-R1 etc.
thinking_blocks: list[dict] | None = None # Anthropic extended thinking
reasoning_details: Any | None = None # MiniMax interleaved CoT metadata

@property
def has_tool_calls(self) -> bool:
Expand Down
10 changes: 9 additions & 1 deletion nanobot/providers/litellm_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
from nanobot.providers.registry import find_by_model, find_gateway

# Standard chat-completion message keys.
_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", "reasoning_details"}
)
_ANTHROPIC_EXTRA_KEYS = frozenset({"thinking_blocks"})
_ALNUM = string.ascii_letters + string.digits

Expand Down Expand Up @@ -280,6 +282,11 @@ def _parse_response(self, response: Any) -> LLMResponse:

reasoning_content = getattr(message, "reasoning_content", None) or None
thinking_blocks = getattr(message, "thinking_blocks", None) or None
reasoning_details = getattr(message, "reasoning_details", None) or None
if reasoning_details is None:
psf = getattr(message, "provider_specific_fields", None) or {}
if isinstance(psf, dict):
reasoning_details = psf.get("reasoning_details")

return LLMResponse(
content=message.content,
Expand All @@ -288,6 +295,7 @@ def _parse_response(self, response: Any) -> LLMResponse:
usage=usage,
reasoning_content=reasoning_content,
thinking_blocks=thinking_blocks,
reasoning_details=reasoning_details,
)

def get_default_model(self) -> str:
Expand Down
6 changes: 5 additions & 1 deletion nanobot/providers/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,11 @@ def label(self) -> str:
detect_by_base_keyword="",
default_api_base="https://api.minimax.io/v1",
strip_model_prefix=False,
model_overrides=(),
model_overrides=(
("minimax-m2.5", {"reasoning_split": True}),
("minimax-m2.1", {"reasoning_split": True}),
("minimax-m2", {"reasoning_split": True}),
),
),

# === Local deployment (matched by config key, NOT by api_base) =========
Expand Down