From 2dd284661d04328d95c7225d6c51c50280fe107e Mon Sep 17 00:00:00 2001 From: Manus AI Date: Sun, 1 Feb 2026 14:36:15 -0500 Subject: [PATCH 1/2] feat: add Zhipu API support and set glm-4.7-flash as default model --- nanobot/cli/commands.py | 4 +++- nanobot/config/schema.py | 10 +++++++--- nanobot/providers/litellm_provider.py | 13 ++++++++++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 05513f0..79837ab 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -68,7 +68,7 @@ def onboard(): console.print(f"\n{__logo__} nanobot is ready!") console.print("\nNext steps:") console.print(" 1. Add your API key to [cyan]~/.nanobot/config.json[/cyan]") - console.print(" Get one at: https://openrouter.ai/keys") + console.print(" Get one at: https://openrouter.ai/keys or https://bigmodel.cn/ (Zhipu AI)") console.print(" 2. Chat: [cyan]nanobot agent -m \"Hello!\"[/cyan]") console.print("\n[dim]Want Telegram/WhatsApp? See: https://github.com/HKUDS/nanobot#-chat-apps[/dim]") @@ -624,10 +624,12 @@ def status(): has_openrouter = bool(config.providers.openrouter.api_key) has_anthropic = bool(config.providers.anthropic.api_key) has_openai = bool(config.providers.openai.api_key) + has_zhipu = bool(config.providers.zhipu.api_key) console.print(f"OpenRouter API: {'[green]✓[/green]' if has_openrouter else '[dim]not set[/dim]'}") console.print(f"Anthropic API: {'[green]✓[/green]' if has_anthropic else '[dim]not set[/dim]'}") console.print(f"OpenAI API: {'[green]✓[/green]' if has_openai else '[dim]not set[/dim]'}") + console.print(f"Zhipu AI API: {'[green]✓[/green]' if has_zhipu else '[dim]not set[/dim]'}") if __name__ == "__main__": diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 06c36e6..58089a4 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -28,7 +28,7 @@ class ChannelsConfig(BaseModel): class AgentDefaults(BaseModel): """Default agent configuration.""" workspace: str = "~/.nanobot/workspace" - model: str = "anthropic/claude-opus-4-5" + model: str = "glm-4.7-flash" max_tokens: int = 8192 temperature: float = 0.7 max_tool_iterations: int = 20 @@ -50,6 +50,7 @@ class ProvidersConfig(BaseModel): anthropic: ProviderConfig = Field(default_factory=ProviderConfig) openai: ProviderConfig = Field(default_factory=ProviderConfig) openrouter: ProviderConfig = Field(default_factory=ProviderConfig) + zhipu: ProviderConfig = Field(default_factory=ProviderConfig) class GatewayConfig(BaseModel): @@ -88,18 +89,21 @@ class Config(BaseSettings): return Path(self.agents.defaults.workspace).expanduser() def get_api_key(self) -> str | None: - """Get API key in priority order: OpenRouter > Anthropic > OpenAI.""" + """Get API key in priority order: OpenRouter > Anthropic > OpenAI > Zhipu.""" return ( self.providers.openrouter.api_key or self.providers.anthropic.api_key or self.providers.openai.api_key or + self.providers.zhipu.api_key or None ) def get_api_base(self) -> str | None: - """Get API base URL if using OpenRouter.""" + """Get API base URL if using OpenRouter or Zhipu.""" if self.providers.openrouter.api_key: return self.providers.openrouter.api_base or "https://openrouter.ai/api/v1" + if self.providers.zhipu.api_key: + return self.providers.zhipu.api_base return None class Config: diff --git a/nanobot/providers/litellm_provider.py b/nanobot/providers/litellm_provider.py index c84aa74..c71e776 100644 --- a/nanobot/providers/litellm_provider.py +++ b/nanobot/providers/litellm_provider.py @@ -21,7 +21,7 @@ class LiteLLMProvider(LLMProvider): self, api_key: str | None = None, api_base: str | None = None, - default_model: str = "anthropic/claude-opus-4-5" + default_model: str = "glm-4.7-flash" ): super().__init__(api_key, api_base) self.default_model = default_model @@ -41,6 +41,8 @@ class LiteLLMProvider(LLMProvider): os.environ.setdefault("ANTHROPIC_API_KEY", api_key) elif "openai" in default_model or "gpt" in default_model: os.environ.setdefault("OPENAI_API_KEY", api_key) + elif "zhipu" in default_model or "glm" in default_model or "zai" in default_model: + os.environ.setdefault("ZHIPUAI_API_KEY", api_key) if api_base: litellm.api_base = api_base @@ -75,6 +77,15 @@ class LiteLLMProvider(LLMProvider): if self.is_openrouter and not model.startswith("openrouter/"): model = f"openrouter/{model}" + # For Zhipu/Z.ai, ensure prefix is present + # Handle cases like "glm-4.7-flash" -> "zhipu/glm-4.7-flash" + if ("glm" in model.lower() or "zhipu" in model.lower()) and not ( + model.startswith("zhipu/") or + model.startswith("zai/") or + model.startswith("openrouter/") + ): + model = f"zhipu/{model}" + kwargs: dict[str, Any] = { "model": model, "messages": messages, From f61e7a596870a131a6a9a9721cd8849af876ef9b Mon Sep 17 00:00:00 2001 From: Manus Date: Mon, 2 Feb 2026 04:24:14 -0500 Subject: [PATCH 2/2] feat: improve tool execution logging (fix #10) --- nanobot/agent/loop.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 6fe2cfd..1d2b070 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -189,7 +189,8 @@ class AgentLoop: # Execute tools for tool_call in response.tool_calls: - logger.debug(f"Executing tool: {tool_call.name}") + args_str = json.dumps(tool_call.arguments) + logger.debug(f"Executing tool: {tool_call.name} with arguments: {args_str}") result = await self.tools.execute(tool_call.name, tool_call.arguments) messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result @@ -281,7 +282,8 @@ class AgentLoop: ) for tool_call in response.tool_calls: - logger.debug(f"Executing tool: {tool_call.name}") + args_str = json.dumps(tool_call.arguments) + logger.debug(f"Executing tool: {tool_call.name} with arguments: {args_str}") result = await self.tools.execute(tool_call.name, tool_call.arguments) messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result