feat(max-bot): implement mock-based message flow with WIP file queue
- MAX API integration (long polling) - MockPlatformClient for agent simulation - File download & workspace storage - Basic commands: /help, /start - Attachment queue: add works, list/remove need testing [WIP: attachment queue commands] [MOCK-ONLY: requires real agent for production]
This commit is contained in:
parent
961ee7bb0b
commit
b74277a189
6 changed files with 120 additions and 28 deletions
|
|
@ -33,13 +33,20 @@ from core.auth import AuthManager
|
|||
from core.chat import ChatManager
|
||||
from core.handler import EventDispatcher
|
||||
from core.handlers import register_all
|
||||
from core.protocol import Attachment, IncomingCommand, OutgoingEvent, OutgoingMessage
|
||||
from core.protocol import OutgoingNotification, OutgoingTyping, OutgoingUI
|
||||
from core.protocol import (
|
||||
Attachment,
|
||||
IncomingCommand,
|
||||
IncomingMessage,
|
||||
OutgoingEvent,
|
||||
OutgoingMessage,
|
||||
OutgoingNotification,
|
||||
OutgoingTyping,
|
||||
OutgoingUI
|
||||
)
|
||||
from core.settings import SettingsManager
|
||||
from core.store import InMemoryStore, StateStore
|
||||
from sdk.interface import PlatformClient, PlatformError
|
||||
from sdk.prototype_state import PrototypeStateStore
|
||||
from sdk.real import RealPlatformClient
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
|
@ -130,6 +137,7 @@ class MaxBotApp:
|
|||
self.registry: AgentRegistry = load_from_env()
|
||||
except (AgentRegistryError, OSError) as exc:
|
||||
raise RuntimeError("failed to load MAX agent registry") from exc
|
||||
|
||||
|
||||
self.chat_store = ChatStore()
|
||||
self.max_chat_handler = MaxChatHandler(self.chat_store)
|
||||
|
|
@ -138,22 +146,35 @@ class MaxBotApp:
|
|||
self.core_store: StateStore = InMemoryStore()
|
||||
self.prototype_state = PrototypeStateStore()
|
||||
|
||||
delegates: dict[str, RealPlatformClient] = {}
|
||||
for agent in self.registry.agents:
|
||||
base_raw = agent.base_url.strip() if agent.base_url else agent_base_url
|
||||
delegates[agent.agent_id] = RealPlatformClient(
|
||||
agent_id=agent.agent_id,
|
||||
agent_base_url=base_raw,
|
||||
prototype_state=self.prototype_state,
|
||||
platform="max",
|
||||
)
|
||||
backend_mode = os.environ.get("MAX_PLATFORM_BACKEND", "mock").strip().lower()
|
||||
logger.info("max_platform_backend_selected", backend=backend_mode)
|
||||
|
||||
default_client = next(iter(delegates.values()))
|
||||
self.platform: RoutedMaxPlatformClient = RoutedMaxPlatformClient(
|
||||
chat_store=self.chat_store,
|
||||
delegates=delegates,
|
||||
default_client=default_client,
|
||||
)
|
||||
if backend_mode == "real":
|
||||
from sdk.real import RealPlatformClient
|
||||
delegates: dict[str, RealPlatformClient] = {}
|
||||
for agent in self.registry.agents:
|
||||
base_raw = agent.base_url.strip() if agent.base_url else agent_base_url
|
||||
delegates[agent.agent_id] = RealPlatformClient(
|
||||
agent_id=agent.agent_id,
|
||||
agent_base_url=base_raw,
|
||||
prototype_state=self.prototype_state,
|
||||
platform="max",
|
||||
)
|
||||
|
||||
if not delegates:
|
||||
raise RuntimeError("No agents configured for real backend")
|
||||
|
||||
default_client = next(iter(delegates.values()))
|
||||
self.platform: RoutedMaxPlatformClient = RoutedMaxPlatformClient(
|
||||
chat_store=self.chat_store,
|
||||
delegates=delegates,
|
||||
default_client=default_client,
|
||||
)
|
||||
else:
|
||||
# Mock backend for local development/testing
|
||||
logger.warning("max_using_mock_backend", note="No real agent connection")
|
||||
from sdk.mock import MockPlatformClient
|
||||
self.platform = MockPlatformClient() # type: ignore[assignment]
|
||||
|
||||
self.chat_mgr = ChatManager(self.platform, self.core_store)
|
||||
self.auth_mgr = AuthManager(self.platform, self.core_store)
|
||||
|
|
@ -244,6 +265,10 @@ class MaxBotApp:
|
|||
return refreshed
|
||||
|
||||
async def process_message_created(self, payload: dict) -> None:
|
||||
logger.info(
|
||||
"DEBUG_PAYLOAD",
|
||||
body=payload.get("message", {}).get("body"),
|
||||
)
|
||||
message = payload.get("message")
|
||||
if not isinstance(message, dict):
|
||||
return
|
||||
|
|
@ -289,7 +314,9 @@ class MaxBotApp:
|
|||
attachments_core = await self._materialize_attachments(room, attachments_core, raw_meta)
|
||||
|
||||
if attachments_core and not text:
|
||||
logger.info("QUEUE_ADD", chat_key=chat_key, count=len(attachments_core))
|
||||
for att in attachments_core:
|
||||
logger.info("QUEUE_ITEM", filename=att.filename)
|
||||
self.chat_store.stage_attachment(chat_key, (att.workspace_path or "", att.filename or "file"))
|
||||
return
|
||||
|
||||
|
|
@ -345,6 +372,7 @@ class MaxBotApp:
|
|||
|
||||
async def _handle_local_attachment_command(self, incoming: IncomingCommand, chat_key: str) -> str:
|
||||
if incoming.command == "list":
|
||||
logger.info("QUEUE_LIST_REQUEST", chat_key=chat_key)
|
||||
return self.attach_handler.handle_list(chat_key)
|
||||
return self.attach_handler.handle_remove(chat_key, incoming.args[0] if incoming.args else "")
|
||||
|
||||
|
|
@ -463,7 +491,7 @@ class MaxBotApp:
|
|||
deeplink_note = f" (payload: {dl})"
|
||||
|
||||
welcome = (
|
||||
"Здравствуйте, я помогу с задачами Lambda. "
|
||||
"Здравствуйте, я бот Lambda, который готов помочь с задачами."
|
||||
f"Отправьте текст или файл.{deeplink_note}"
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue