feat: rebuild AI commands and migrate config to TOML

This commit is contained in:
Azimkin
2026-09-14 13:03:04 +02:00
parent 01d3173254
commit 4421c9cd31
53 changed files with 1840 additions and 3464 deletions

View File

@@ -2,13 +2,12 @@ from __future__ import annotations
import logging
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any
from pyrogram import Client, idle
from app.ai import AIService
from app.commands import DEFAULT_REGISTRY, CommandRegistry, RuntimeAclStore, load_persistent_commands
from app.agentic import AgentSessionStore
from app.commands import DEFAULT_REGISTRY, CommandRegistry, RuntimeAclStore
from app.config import AccountConfig, AppConfig
from app.github_webhook import GitHubWebhookServer
from app.handlers import register_common_handlers
@@ -23,27 +22,19 @@ class AccountState:
acl_store: RuntimeAclStore | None = None
status: str = "pending"
error: str | None = None
started_at: datetime | None = None
me: Any | None = None
ai_sessions: AgentSessionStore = field(default_factory=AgentSessionStore)
@dataclass(slots=True)
class AccountManager:
config: AppConfig
ai_service: AIService | None = field(init=False)
command_registry: CommandRegistry = field(init=False)
states: list[AccountState] = field(init=False)
github_webhook_server: GitHubWebhookServer = field(init=False)
def __post_init__(self) -> None:
self.command_registry = DEFAULT_REGISTRY
if self.config.ai is not None:
loaded = load_persistent_commands(self.config.ai.workspace_dir / "commands", self.command_registry)
if loaded:
log.info("Loaded persistent commands: %s", ", ".join(loaded))
self.ai_service = (
AIService(self.config.ai, self.command_registry) if self.config.ai is not None else None
)
self.states = [AccountState(config=account) for account in self.config.accounts]
self.github_webhook_server = GitHubWebhookServer(self, self.config.github_webhook)
@@ -92,7 +83,6 @@ class AccountManager:
try:
await client.start()
state.me = await client.get_me()
state.started_at = datetime.now(timezone.utc)
state.status = "running"
log.info("Started account %s (%s)", account.name, account.session)
except Exception as exc:
@@ -109,6 +99,7 @@ class AccountManager:
async def stop_all(self) -> None:
for state in reversed(self.states):
state.ai_sessions.clear()
if state.client is None:
continue
if state.status not in {"running", "starting"}:
@@ -133,8 +124,6 @@ class AccountManager:
parts.append(
f"acl={stats['allow_rules']} allow / {stats['deny_rules']} deny"
)
if self.ai_service is not None and self.config.ai is not None:
parts.append(f"ai={self.config.ai.default_model}")
if state.me is not None:
display_name = (
getattr(state.me, "full_name", None)
@@ -157,12 +146,8 @@ class AccountManager:
raise RuntimeError("No accounts were started successfully")
try:
if self.ai_service is not None:
await self.ai_service.initialize()
await self.github_webhook_server.start()
await idle()
finally:
await self.github_webhook_server.stop()
await self.stop_all()
if self.ai_service is not None:
self.ai_service.close()