revert: restore context.py and manager.py to tanishra baseline (out of scope)

This commit is contained in:
Alexander Minges
2026-02-20 18:08:04 +01:00
parent e8a4671565
commit 52d086d46a
2 changed files with 52 additions and 43 deletions

View File

@@ -102,11 +102,8 @@ Your workspace is at: {workspace_path}
- Custom skills: {workspace_path}/skills/{{skill-name}}/SKILL.md - Custom skills: {workspace_path}/skills/{{skill-name}}/SKILL.md
IMPORTANT: When responding to direct questions or conversations, reply directly with your text response. IMPORTANT: When responding to direct questions or conversations, reply directly with your text response.
Use the 'message' tool only when you need explicit channel delivery behavior: Only use the 'message' tool when you need to send a message to a specific chat channel (like WhatsApp).
- Send to a different channel/chat than the current session For normal conversation, just respond with text - do not call the message tool.
- Send one or more file attachments via `media` (local file paths)
For normal conversation text, respond directly without calling the message tool.
Do not claim that attachments are impossible if a channel supports file send and you can provide local paths.
Always be helpful, accurate, and concise. Before calling tools, briefly tell the user what you're about to do (one short sentence in the user's language). Always be helpful, accurate, and concise. Before calling tools, briefly tell the user what you're about to do (one short sentence in the user's language).
When remembering something important, write to {workspace_path}/memory/MEMORY.md When remembering something important, write to {workspace_path}/memory/MEMORY.md

View File

@@ -16,29 +16,28 @@ from nanobot.config.schema import Config
class ChannelManager: class ChannelManager:
""" """
Manages chat channels and coordinates message routing. Manages chat channels and coordinates message routing.
Responsibilities: Responsibilities:
- Initialize enabled channels (Telegram, WhatsApp, etc.) - Initialize enabled channels (Telegram, WhatsApp, etc.)
- Start/stop channels - Start/stop channels
- Route outbound messages - Route outbound messages
""" """
def __init__(self, config: Config, bus: MessageBus): def __init__(self, config: Config, bus: MessageBus):
self.config = config self.config = config
self.bus = bus self.bus = bus
self.channels: dict[str, BaseChannel] = {} self.channels: dict[str, BaseChannel] = {}
self._dispatch_task: asyncio.Task | None = None self._dispatch_task: asyncio.Task | None = None
self._init_channels() self._init_channels()
def _init_channels(self) -> None: def _init_channels(self) -> None:
"""Initialize channels based on config.""" """Initialize channels based on config."""
# Telegram channel # Telegram channel
if self.config.channels.telegram.enabled: if self.config.channels.telegram.enabled:
try: try:
from nanobot.channels.telegram import TelegramChannel from nanobot.channels.telegram import TelegramChannel
self.channels["telegram"] = TelegramChannel( self.channels["telegram"] = TelegramChannel(
self.config.channels.telegram, self.config.channels.telegram,
self.bus, self.bus,
@@ -47,13 +46,14 @@ class ChannelManager:
logger.info("Telegram channel enabled") logger.info("Telegram channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"Telegram channel not available: {e}") logger.warning(f"Telegram channel not available: {e}")
# WhatsApp channel # WhatsApp channel
if self.config.channels.whatsapp.enabled: if self.config.channels.whatsapp.enabled:
try: try:
from nanobot.channels.whatsapp import WhatsAppChannel from nanobot.channels.whatsapp import WhatsAppChannel
self.channels["whatsapp"] = WhatsAppChannel(
self.channels["whatsapp"] = WhatsAppChannel(self.config.channels.whatsapp, self.bus) self.config.channels.whatsapp, self.bus
)
logger.info("WhatsApp channel enabled") logger.info("WhatsApp channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"WhatsApp channel not available: {e}") logger.warning(f"WhatsApp channel not available: {e}")
@@ -62,18 +62,20 @@ class ChannelManager:
if self.config.channels.discord.enabled: if self.config.channels.discord.enabled:
try: try:
from nanobot.channels.discord import DiscordChannel from nanobot.channels.discord import DiscordChannel
self.channels["discord"] = DiscordChannel(
self.channels["discord"] = DiscordChannel(self.config.channels.discord, self.bus) self.config.channels.discord, self.bus
)
logger.info("Discord channel enabled") logger.info("Discord channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"Discord channel not available: {e}") logger.warning(f"Discord channel not available: {e}")
# Feishu channel # Feishu channel
if self.config.channels.feishu.enabled: if self.config.channels.feishu.enabled:
try: try:
from nanobot.channels.feishu import FeishuChannel from nanobot.channels.feishu import FeishuChannel
self.channels["feishu"] = FeishuChannel(
self.channels["feishu"] = FeishuChannel(self.config.channels.feishu, self.bus) self.config.channels.feishu, self.bus
)
logger.info("Feishu channel enabled") logger.info("Feishu channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"Feishu channel not available: {e}") logger.warning(f"Feishu channel not available: {e}")
@@ -83,7 +85,9 @@ class ChannelManager:
try: try:
from nanobot.channels.mochat import MochatChannel from nanobot.channels.mochat import MochatChannel
self.channels["mochat"] = MochatChannel(self.config.channels.mochat, self.bus) self.channels["mochat"] = MochatChannel(
self.config.channels.mochat, self.bus
)
logger.info("Mochat channel enabled") logger.info("Mochat channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"Mochat channel not available: {e}") logger.warning(f"Mochat channel not available: {e}")
@@ -92,8 +96,9 @@ class ChannelManager:
if self.config.channels.dingtalk.enabled: if self.config.channels.dingtalk.enabled:
try: try:
from nanobot.channels.dingtalk import DingTalkChannel from nanobot.channels.dingtalk import DingTalkChannel
self.channels["dingtalk"] = DingTalkChannel(
self.channels["dingtalk"] = DingTalkChannel(self.config.channels.dingtalk, self.bus) self.config.channels.dingtalk, self.bus
)
logger.info("DingTalk channel enabled") logger.info("DingTalk channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"DingTalk channel not available: {e}") logger.warning(f"DingTalk channel not available: {e}")
@@ -102,8 +107,9 @@ class ChannelManager:
if self.config.channels.email.enabled: if self.config.channels.email.enabled:
try: try:
from nanobot.channels.email import EmailChannel from nanobot.channels.email import EmailChannel
self.channels["email"] = EmailChannel(
self.channels["email"] = EmailChannel(self.config.channels.email, self.bus) self.config.channels.email, self.bus
)
logger.info("Email channel enabled") logger.info("Email channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"Email channel not available: {e}") logger.warning(f"Email channel not available: {e}")
@@ -112,8 +118,9 @@ class ChannelManager:
if self.config.channels.slack.enabled: if self.config.channels.slack.enabled:
try: try:
from nanobot.channels.slack import SlackChannel from nanobot.channels.slack import SlackChannel
self.channels["slack"] = SlackChannel(
self.channels["slack"] = SlackChannel(self.config.channels.slack, self.bus) self.config.channels.slack, self.bus
)
logger.info("Slack channel enabled") logger.info("Slack channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"Slack channel not available: {e}") logger.warning(f"Slack channel not available: {e}")
@@ -122,7 +129,6 @@ class ChannelManager:
if self.config.channels.qq.enabled: if self.config.channels.qq.enabled:
try: try:
from nanobot.channels.qq import QQChannel from nanobot.channels.qq import QQChannel
self.channels["qq"] = QQChannel( self.channels["qq"] = QQChannel(
self.config.channels.qq, self.config.channels.qq,
self.bus, self.bus,
@@ -130,7 +136,7 @@ class ChannelManager:
logger.info("QQ channel enabled") logger.info("QQ channel enabled")
except ImportError as e: except ImportError as e:
logger.warning(f"QQ channel not available: {e}") logger.warning(f"QQ channel not available: {e}")
async def _start_channel(self, name: str, channel: BaseChannel) -> None: async def _start_channel(self, name: str, channel: BaseChannel) -> None:
"""Start a channel and log any exceptions.""" """Start a channel and log any exceptions."""
try: try:
@@ -143,23 +149,23 @@ class ChannelManager:
if not self.channels: if not self.channels:
logger.warning("No channels enabled") logger.warning("No channels enabled")
return return
# Start outbound dispatcher # Start outbound dispatcher
self._dispatch_task = asyncio.create_task(self._dispatch_outbound()) self._dispatch_task = asyncio.create_task(self._dispatch_outbound())
# Start channels # Start channels
tasks = [] tasks = []
for name, channel in self.channels.items(): for name, channel in self.channels.items():
logger.info(f"Starting {name} channel...") logger.info(f"Starting {name} channel...")
tasks.append(asyncio.create_task(self._start_channel(name, channel))) tasks.append(asyncio.create_task(self._start_channel(name, channel)))
# Wait for all to complete (they should run forever) # Wait for all to complete (they should run forever)
await asyncio.gather(*tasks, return_exceptions=True) await asyncio.gather(*tasks, return_exceptions=True)
async def stop_all(self) -> None: async def stop_all(self) -> None:
"""Stop all channels and the dispatcher.""" """Stop all channels and the dispatcher."""
logger.info("Stopping all channels...") logger.info("Stopping all channels...")
# Stop dispatcher # Stop dispatcher
if self._dispatch_task: if self._dispatch_task:
self._dispatch_task.cancel() self._dispatch_task.cancel()
@@ -167,7 +173,7 @@ class ChannelManager:
await self._dispatch_task await self._dispatch_task
except asyncio.CancelledError: except asyncio.CancelledError:
pass pass
# Stop all channels # Stop all channels
for name, channel in self.channels.items(): for name, channel in self.channels.items():
try: try:
@@ -175,15 +181,18 @@ class ChannelManager:
logger.info(f"Stopped {name} channel") logger.info(f"Stopped {name} channel")
except Exception as e: except Exception as e:
logger.error(f"Error stopping {name}: {e}") logger.error(f"Error stopping {name}: {e}")
async def _dispatch_outbound(self) -> None: async def _dispatch_outbound(self) -> None:
"""Dispatch outbound messages to the appropriate channel.""" """Dispatch outbound messages to the appropriate channel."""
logger.info("Outbound dispatcher started") logger.info("Outbound dispatcher started")
while True: while True:
try: try:
msg = await asyncio.wait_for(self.bus.consume_outbound(), timeout=1.0) msg = await asyncio.wait_for(
self.bus.consume_outbound(),
timeout=1.0
)
channel = self.channels.get(msg.channel) channel = self.channels.get(msg.channel)
if channel: if channel:
try: try:
@@ -192,23 +201,26 @@ class ChannelManager:
logger.error(f"Error sending to {msg.channel}: {e}") logger.error(f"Error sending to {msg.channel}: {e}")
else: else:
logger.warning(f"Unknown channel: {msg.channel}") logger.warning(f"Unknown channel: {msg.channel}")
except asyncio.TimeoutError: except asyncio.TimeoutError:
continue continue
except asyncio.CancelledError: except asyncio.CancelledError:
break break
def get_channel(self, name: str) -> BaseChannel | None: def get_channel(self, name: str) -> BaseChannel | None:
"""Get a channel by name.""" """Get a channel by name."""
return self.channels.get(name) return self.channels.get(name)
def get_status(self) -> dict[str, Any]: def get_status(self) -> dict[str, Any]:
"""Get status of all channels.""" """Get status of all channels."""
return { return {
name: {"enabled": True, "running": channel.is_running} name: {
"enabled": True,
"running": channel.is_running
}
for name, channel in self.channels.items() for name, channel in self.channels.items()
} }
@property @property
def enabled_channels(self) -> list[str]: def enabled_channels(self) -> list[str]:
"""Get list of enabled channel names.""" """Get list of enabled channel names."""