From 37252a4226214367abea1cef0fae4591b2dc00c4 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Fri, 20 Feb 2026 07:55:34 +0000 Subject: [PATCH] fix: complete loguru native formatting migration across all files --- nanobot/agent/loop.py | 12 ++++++------ nanobot/agent/subagent.py | 8 ++++---- nanobot/agent/tools/mcp.py | 6 +++--- nanobot/channels/dingtalk.py | 2 +- nanobot/channels/discord.py | 2 +- nanobot/channels/email.py | 2 +- nanobot/channels/feishu.py | 10 +++++----- nanobot/channels/manager.py | 24 ++++++++++++------------ nanobot/channels/qq.py | 2 +- nanobot/channels/slack.py | 4 ++-- nanobot/channels/telegram.py | 8 ++++---- nanobot/channels/whatsapp.py | 8 ++++---- nanobot/cron/service.py | 10 +++++----- nanobot/heartbeat/service.py | 4 ++-- nanobot/providers/transcription.py | 2 +- nanobot/session/manager.py | 2 +- 16 files changed, 53 insertions(+), 53 deletions(-) diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index cbab5aa..1620cb0 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -365,7 +365,7 @@ class AgentLoop: The chat_id field contains "original_channel:original_chat_id" to route the response back to the correct destination. """ - logger.info(f"Processing system message from {msg.sender_id}") + logger.info("Processing system message from {}", msg.sender_id) # Parse origin from chat_id (format: "channel:chat_id") if ":" in msg.chat_id: @@ -413,22 +413,22 @@ class AgentLoop: if archive_all: old_messages = session.messages keep_count = 0 - logger.info(f"Memory consolidation (archive_all): {len(session.messages)} total messages archived") + logger.info("Memory consolidation (archive_all): {} total messages archived", len(session.messages)) else: keep_count = self.memory_window // 2 if len(session.messages) <= keep_count: - logger.debug(f"Session {session.key}: No consolidation needed (messages={len(session.messages)}, keep={keep_count})") + logger.debug("Session {}: No consolidation needed (messages={}, keep={})", session.key, len(session.messages), keep_count) return messages_to_process = len(session.messages) - session.last_consolidated if messages_to_process <= 0: - logger.debug(f"Session {session.key}: No new messages to consolidate (last_consolidated={session.last_consolidated}, total={len(session.messages)})") + logger.debug("Session {}: No new messages to consolidate (last_consolidated={}, total={})", session.key, session.last_consolidated, len(session.messages)) return old_messages = session.messages[session.last_consolidated:-keep_count] if not old_messages: return - logger.info(f"Memory consolidation started: {len(session.messages)} total, {len(old_messages)} new to consolidate, {keep_count} keep") + logger.info("Memory consolidation started: {} total, {} new to consolidate, {} keep", len(session.messages), len(old_messages), keep_count) lines = [] for m in old_messages: @@ -482,7 +482,7 @@ Respond with ONLY valid JSON, no markdown fences.""" session.last_consolidated = 0 else: session.last_consolidated = len(session.messages) - keep_count - logger.info(f"Memory consolidation done: {len(session.messages)} messages, last_consolidated={session.last_consolidated}") + logger.info("Memory consolidation done: {} messages, last_consolidated={}", len(session.messages), session.last_consolidated) except Exception as e: logger.error("Memory consolidation failed: {}", e) diff --git a/nanobot/agent/subagent.py b/nanobot/agent/subagent.py index ae0e492..7d48cc4 100644 --- a/nanobot/agent/subagent.py +++ b/nanobot/agent/subagent.py @@ -86,7 +86,7 @@ class SubagentManager: # Cleanup when done bg_task.add_done_callback(lambda _: self._running_tasks.pop(task_id, None)) - logger.info(f"Spawned subagent [{task_id}]: {display_label}") + logger.info("Spawned subagent [{}]: {}", task_id, display_label) return f"Subagent [{display_label}] started (id: {task_id}). I'll notify you when it completes." async def _run_subagent( @@ -97,7 +97,7 @@ class SubagentManager: origin: dict[str, str], ) -> None: """Execute the subagent task and announce the result.""" - logger.info(f"Subagent [{task_id}] starting task: {label}") + logger.info("Subagent [{}] starting task: {}", task_id, label) try: # Build subagent tools (no message tool, no spawn tool) @@ -175,7 +175,7 @@ class SubagentManager: if final_result is None: final_result = "Task completed but no final response was generated." - logger.info(f"Subagent [{task_id}] completed successfully") + logger.info("Subagent [{}] completed successfully", task_id) await self._announce_result(task_id, label, task, final_result, origin, "ok") except Exception as e: @@ -213,7 +213,7 @@ Summarize this naturally for the user. Keep it brief (1-2 sentences). Do not men ) await self.bus.publish_inbound(msg) - logger.debug(f"Subagent [{task_id}] announced result to {origin['channel']}:{origin['chat_id']}") + logger.debug("Subagent [{}] announced result to {}:{}", task_id, origin['channel'], origin['chat_id']) def _build_subagent_prompt(self, task: str) -> str: """Build a focused system prompt for the subagent.""" diff --git a/nanobot/agent/tools/mcp.py b/nanobot/agent/tools/mcp.py index 4e61923..7d9033d 100644 --- a/nanobot/agent/tools/mcp.py +++ b/nanobot/agent/tools/mcp.py @@ -63,7 +63,7 @@ async def connect_mcp_servers( streamable_http_client(cfg.url) ) else: - logger.warning(f"MCP server '{name}': no command or url configured, skipping") + logger.warning("MCP server '{}': no command or url configured, skipping", name) continue session = await stack.enter_async_context(ClientSession(read, write)) @@ -73,8 +73,8 @@ async def connect_mcp_servers( for tool_def in tools.tools: wrapper = MCPToolWrapper(session, name, tool_def) registry.register(wrapper) - logger.debug(f"MCP: registered tool '{wrapper.name}' from server '{name}'") + logger.debug("MCP: registered tool '{}' from server '{}'", wrapper.name, name) - logger.info(f"MCP server '{name}': connected, {len(tools.tools)} tools registered") + logger.info("MCP server '{}': connected, {} tools registered", name, len(tools.tools)) except Exception as e: logger.error("MCP server '{}': failed to connect: {}", name, e) diff --git a/nanobot/channels/dingtalk.py b/nanobot/channels/dingtalk.py index 3ac233f..f6dca30 100644 --- a/nanobot/channels/dingtalk.py +++ b/nanobot/channels/dingtalk.py @@ -220,7 +220,7 @@ class DingTalkChannel(BaseChannel): if resp.status_code != 200: logger.error("DingTalk send failed: {}", resp.text) else: - logger.debug(f"DingTalk message sent to {msg.chat_id}") + logger.debug("DingTalk message sent to {}", msg.chat_id) except Exception as e: logger.error("Error sending DingTalk message: {}", e) diff --git a/nanobot/channels/discord.py b/nanobot/channels/discord.py index ee54eed..8baecbf 100644 --- a/nanobot/channels/discord.py +++ b/nanobot/channels/discord.py @@ -94,7 +94,7 @@ class DiscordChannel(BaseChannel): if response.status_code == 429: data = response.json() retry_after = float(data.get("retry_after", 1.0)) - logger.warning(f"Discord rate limited, retrying in {retry_after}s") + logger.warning("Discord rate limited, retrying in {}s", retry_after) await asyncio.sleep(retry_after) continue response.raise_for_status() diff --git a/nanobot/channels/email.py b/nanobot/channels/email.py index 8a1ee79..1b6f46b 100644 --- a/nanobot/channels/email.py +++ b/nanobot/channels/email.py @@ -162,7 +162,7 @@ class EmailChannel(BaseChannel): missing.append("smtp_password") if missing: - logger.error(f"Email channel not configured, missing: {', '.join(missing)}") + logger.error("Email channel not configured, missing: {}", ', '.join(missing)) return False return True diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 6f62202..c17bf1a 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -196,7 +196,7 @@ class FeishuChannel(BaseChannel): if not response.success(): logger.warning("Failed to add reaction: code={}, msg={}", response.code, response.msg) else: - logger.debug(f"Added {emoji_type} reaction to message {message_id}") + logger.debug("Added {} reaction to message {}", emoji_type, message_id) except Exception as e: logger.warning("Error adding reaction: {}", e) @@ -309,7 +309,7 @@ class FeishuChannel(BaseChannel): response = self._client.im.v1.image.create(request) if response.success(): image_key = response.data.image_key - logger.debug(f"Uploaded image {os.path.basename(file_path)}: {image_key}") + logger.debug("Uploaded image {}: {}", os.path.basename(file_path), image_key) return image_key else: logger.error("Failed to upload image: code={}, msg={}", response.code, response.msg) @@ -336,7 +336,7 @@ class FeishuChannel(BaseChannel): response = self._client.im.v1.file.create(request) if response.success(): file_key = response.data.file_key - logger.debug(f"Uploaded file {file_name}: {file_key}") + logger.debug("Uploaded file {}: {}", file_name, file_key) return file_key else: logger.error("Failed to upload file: code={}, msg={}", response.code, response.msg) @@ -364,7 +364,7 @@ class FeishuChannel(BaseChannel): msg_type, response.code, response.msg, response.get_log_id() ) return False - logger.debug(f"Feishu {msg_type} message sent to {receive_id}") + logger.debug("Feishu {} message sent to {}", msg_type, receive_id) return True except Exception as e: logger.error("Error sending Feishu {} message: {}", msg_type, e) @@ -382,7 +382,7 @@ class FeishuChannel(BaseChannel): for file_path in msg.media: if not os.path.isfile(file_path): - logger.warning(f"Media file not found: {file_path}") + logger.warning("Media file not found: {}", file_path) continue ext = os.path.splitext(file_path)[1].lower() if ext in self._IMAGE_EXTS: diff --git a/nanobot/channels/manager.py b/nanobot/channels/manager.py index 3e714c3..6fbab04 100644 --- a/nanobot/channels/manager.py +++ b/nanobot/channels/manager.py @@ -45,7 +45,7 @@ class ChannelManager: ) logger.info("Telegram channel enabled") except ImportError as e: - logger.warning(f"Telegram channel not available: {e}") + logger.warning("Telegram channel not available: {}", e) # WhatsApp channel if self.config.channels.whatsapp.enabled: @@ -56,7 +56,7 @@ class ChannelManager: ) logger.info("WhatsApp channel enabled") except ImportError as e: - logger.warning(f"WhatsApp channel not available: {e}") + logger.warning("WhatsApp channel not available: {}", e) # Discord channel if self.config.channels.discord.enabled: @@ -67,7 +67,7 @@ class ChannelManager: ) logger.info("Discord channel enabled") except ImportError as e: - logger.warning(f"Discord channel not available: {e}") + logger.warning("Discord channel not available: {}", e) # Feishu channel if self.config.channels.feishu.enabled: @@ -78,7 +78,7 @@ class ChannelManager: ) logger.info("Feishu channel enabled") except ImportError as e: - logger.warning(f"Feishu channel not available: {e}") + logger.warning("Feishu channel not available: {}", e) # Mochat channel if self.config.channels.mochat.enabled: @@ -90,7 +90,7 @@ class ChannelManager: ) logger.info("Mochat channel enabled") except ImportError as e: - logger.warning(f"Mochat channel not available: {e}") + logger.warning("Mochat channel not available: {}", e) # DingTalk channel if self.config.channels.dingtalk.enabled: @@ -101,7 +101,7 @@ class ChannelManager: ) logger.info("DingTalk channel enabled") except ImportError as e: - logger.warning(f"DingTalk channel not available: {e}") + logger.warning("DingTalk channel not available: {}", e) # Email channel if self.config.channels.email.enabled: @@ -112,7 +112,7 @@ class ChannelManager: ) logger.info("Email channel enabled") except ImportError as e: - logger.warning(f"Email channel not available: {e}") + logger.warning("Email channel not available: {}", e) # Slack channel if self.config.channels.slack.enabled: @@ -123,7 +123,7 @@ class ChannelManager: ) logger.info("Slack channel enabled") except ImportError as e: - logger.warning(f"Slack channel not available: {e}") + logger.warning("Slack channel not available: {}", e) # QQ channel if self.config.channels.qq.enabled: @@ -135,7 +135,7 @@ class ChannelManager: ) logger.info("QQ channel enabled") except ImportError as e: - logger.warning(f"QQ channel not available: {e}") + logger.warning("QQ channel not available: {}", e) async def _start_channel(self, name: str, channel: BaseChannel) -> None: """Start a channel and log any exceptions.""" @@ -156,7 +156,7 @@ class ChannelManager: # Start channels tasks = [] for name, channel in self.channels.items(): - logger.info(f"Starting {name} channel...") + logger.info("Starting {} channel...", name) tasks.append(asyncio.create_task(self._start_channel(name, channel))) # Wait for all to complete (they should run forever) @@ -178,7 +178,7 @@ class ChannelManager: for name, channel in self.channels.items(): try: await channel.stop() - logger.info(f"Stopped {name} channel") + logger.info("Stopped {} channel", name) except Exception as e: logger.error("Error stopping {}: {}", name, e) @@ -200,7 +200,7 @@ class ChannelManager: except Exception as e: logger.error("Error sending to {}: {}", msg.channel, e) else: - logger.warning(f"Unknown channel: {msg.channel}") + logger.warning("Unknown channel: {}", msg.channel) except asyncio.TimeoutError: continue diff --git a/nanobot/channels/qq.py b/nanobot/channels/qq.py index 1d00bc7..16cbfb8 100644 --- a/nanobot/channels/qq.py +++ b/nanobot/channels/qq.py @@ -34,7 +34,7 @@ def _make_bot_class(channel: "QQChannel") -> "type[botpy.Client]": super().__init__(intents=intents) async def on_ready(self): - logger.info(f"QQ bot ready: {self.robot.name}") + logger.info("QQ bot ready: {}", self.robot.name) async def on_c2c_message_create(self, message: "C2CMessage"): await channel._on_message(message) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index 7dd2971..79cbe76 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -36,7 +36,7 @@ class SlackChannel(BaseChannel): logger.error("Slack bot/app token not configured") return if self.config.mode != "socket": - logger.error(f"Unsupported Slack mode: {self.config.mode}") + logger.error("Unsupported Slack mode: {}", self.config.mode) return self._running = True @@ -53,7 +53,7 @@ class SlackChannel(BaseChannel): try: auth = await self._web_client.auth_test() self._bot_user_id = auth.get("user_id") - logger.info(f"Slack bot connected as {self._bot_user_id}") + logger.info("Slack bot connected as {}", self._bot_user_id) except Exception as e: logger.warning("Slack auth_test failed: {}", e) diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index 42db489..fa36c98 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -165,7 +165,7 @@ class TelegramChannel(BaseChannel): # Get bot info and register command menu bot_info = await self._app.bot.get_me() - logger.info(f"Telegram bot @{bot_info.username} connected") + logger.info("Telegram bot @{} connected", bot_info.username) try: await self._app.bot.set_my_commands(self.BOT_COMMANDS) @@ -221,7 +221,7 @@ class TelegramChannel(BaseChannel): try: chat_id = int(msg.chat_id) except ValueError: - logger.error(f"Invalid chat_id: {msg.chat_id}") + logger.error("Invalid chat_id: {}", msg.chat_id) return # Send media files @@ -344,14 +344,14 @@ class TelegramChannel(BaseChannel): transcriber = GroqTranscriptionProvider(api_key=self.groq_api_key) transcription = await transcriber.transcribe(file_path) if transcription: - logger.info(f"Transcribed {media_type}: {transcription[:50]}...") + logger.info("Transcribed {}: {}...", media_type, transcription[:50]) content_parts.append(f"[transcription: {transcription}]") else: content_parts.append(f"[{media_type}: {file_path}]") else: content_parts.append(f"[{media_type}: {file_path}]") - logger.debug(f"Downloaded {media_type} to {file_path}") + logger.debug("Downloaded {} to {}", media_type, file_path) except Exception as e: logger.error("Failed to download media: {}", e) content_parts.append(f"[{media_type}: download failed]") diff --git a/nanobot/channels/whatsapp.py b/nanobot/channels/whatsapp.py index 4d12360..f3e14d9 100644 --- a/nanobot/channels/whatsapp.py +++ b/nanobot/channels/whatsapp.py @@ -34,7 +34,7 @@ class WhatsAppChannel(BaseChannel): bridge_url = self.config.bridge_url - logger.info(f"Connecting to WhatsApp bridge at {bridge_url}...") + logger.info("Connecting to WhatsApp bridge at {}...", bridge_url) self._running = True @@ -112,11 +112,11 @@ class WhatsAppChannel(BaseChannel): # Extract just the phone number or lid as chat_id user_id = pn if pn else sender sender_id = user_id.split("@")[0] if "@" in user_id else user_id - logger.info(f"Sender {sender}") + logger.info("Sender {}", sender) # Handle voice transcription if it's a voice message if content == "[Voice Message]": - logger.info(f"Voice message received from {sender_id}, but direct download from bridge is not yet supported.") + logger.info("Voice message received from {}, but direct download from bridge is not yet supported.", sender_id) content = "[Voice Message: Transcription not available for WhatsApp yet]" await self._handle_message( @@ -133,7 +133,7 @@ class WhatsAppChannel(BaseChannel): elif msg_type == "status": # Connection status update status = data.get("status") - logger.info(f"WhatsApp status: {status}") + logger.info("WhatsApp status: {}", status) if status == "connected": self._connected = True diff --git a/nanobot/cron/service.py b/nanobot/cron/service.py index d2b9ef7..4c14ef7 100644 --- a/nanobot/cron/service.py +++ b/nanobot/cron/service.py @@ -157,7 +157,7 @@ class CronService: self._recompute_next_runs() self._save_store() self._arm_timer() - logger.info(f"Cron service started with {len(self._store.jobs if self._store else [])} jobs") + logger.info("Cron service started with {} jobs", len(self._store.jobs if self._store else [])) def stop(self) -> None: """Stop the cron service.""" @@ -222,7 +222,7 @@ class CronService: async def _execute_job(self, job: CronJob) -> None: """Execute a single job.""" start_ms = _now_ms() - logger.info(f"Cron: executing job '{job.name}' ({job.id})") + logger.info("Cron: executing job '{}' ({})", job.name, job.id) try: response = None @@ -231,7 +231,7 @@ class CronService: job.state.last_status = "ok" job.state.last_error = None - logger.info(f"Cron: job '{job.name}' completed") + logger.info("Cron: job '{}' completed", job.name) except Exception as e: job.state.last_status = "error" @@ -296,7 +296,7 @@ class CronService: self._save_store() self._arm_timer() - logger.info(f"Cron: added job '{name}' ({job.id})") + logger.info("Cron: added job '{}' ({})", name, job.id) return job def remove_job(self, job_id: str) -> bool: @@ -309,7 +309,7 @@ class CronService: if removed: self._save_store() self._arm_timer() - logger.info(f"Cron: removed job {job_id}") + logger.info("Cron: removed job {}", job_id) return removed diff --git a/nanobot/heartbeat/service.py b/nanobot/heartbeat/service.py index 8bdc78f..8b33e3a 100644 --- a/nanobot/heartbeat/service.py +++ b/nanobot/heartbeat/service.py @@ -78,7 +78,7 @@ class HeartbeatService: self._running = True self._task = asyncio.create_task(self._run_loop()) - logger.info(f"Heartbeat started (every {self.interval_s}s)") + logger.info("Heartbeat started (every {}s)", self.interval_s) def stop(self) -> None: """Stop the heartbeat service.""" @@ -118,7 +118,7 @@ class HeartbeatService: if HEARTBEAT_OK_TOKEN.replace("_", "") in response.upper().replace("_", ""): logger.info("Heartbeat: OK (no action needed)") else: - logger.info(f"Heartbeat: completed task") + logger.info("Heartbeat: completed task") except Exception as e: logger.error("Heartbeat execution failed: {}", e) diff --git a/nanobot/providers/transcription.py b/nanobot/providers/transcription.py index eb5969d..7a3c628 100644 --- a/nanobot/providers/transcription.py +++ b/nanobot/providers/transcription.py @@ -35,7 +35,7 @@ class GroqTranscriptionProvider: path = Path(file_path) if not path.exists(): - logger.error(f"Audio file not found: {file_path}") + logger.error("Audio file not found: {}", file_path) return "" try: diff --git a/nanobot/session/manager.py b/nanobot/session/manager.py index 44dcecb..9c0c7de 100644 --- a/nanobot/session/manager.py +++ b/nanobot/session/manager.py @@ -110,7 +110,7 @@ class SessionManager: if legacy_path.exists(): import shutil shutil.move(str(legacy_path), str(path)) - logger.info(f"Migrated session {key} from legacy path") + logger.info("Migrated session {} from legacy path", key) if not path.exists(): return None