fix: complete loguru native formatting migration across all files

This commit is contained in:
Re-bin
2026-02-20 07:55:34 +00:00
parent 0bde1d89fa
commit 37252a4226
16 changed files with 53 additions and 53 deletions

View File

@@ -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)

View File

@@ -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."""

View File

@@ -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)

View File

@@ -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)

View File

@@ -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()

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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]")

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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