refactor: split config.py into the beaver_agent package (vault, prompts, skills, policy, hands, agents, frontends, texts, memory, jobs)

This commit is contained in:
hh
2026-09-02 00:24:31 +02:00
parent f4043a7bfd
commit ac4a8d1fae
38 changed files with 1302 additions and 935 deletions
+142
View File
@@ -0,0 +1,142 @@
"""Руки: какие MCP есть у сетапа и кому из агентов какая рука выдана.
Секреты MCP - только через env подпроцесса, никогда argv: процесс модели
видит `ps` всего контейнера. Рука, чей env не задан, просто не появляется.
"""
from __future__ import annotations
import os
from pathlib import Path
from beaver_gateway.agents.base import ExposedMcp
from beaver_gateway.mcp.types import McpServer, McpServerT
from beaver_agent.hands.calendars import calendars
from beaver_agent.hands.homeassistant import HomeAssistant
from beaver_agent.hands.komodo import Komodo
from beaver_agent.hands.vibegram import Vibegram
from beaver_agent.vault import TZ
env = os.environ.get
obsidian = McpServer.stdio(
name="obsidian-fs",
command=["bunx", "-y", "@modelcontextprotocol/server-filesystem", "/vault"],
lenient=True,
)
"""Файловые тулзы для тех, у кого нет своих (Raycast); у Claude vault смонтирован."""
firefly = (
McpServer.stdio(
name="firefly",
command=["bunx", "-y", "@firefly-iii-mcp/local", "--preset", "default"],
env={
"FIREFLY_III_PAT": os.environ["FIREFLY_PAT"],
"FIREFLY_III_BASE_URL": os.environ["FIREFLY_BASE_URL"],
},
lenient=True,
)
if env("FIREFLY_PAT")
else None
)
firefly_exposed = (ExposedMcp(name="firefly", deny=("delete_*",)),) if firefly else ()
telegram = (
McpServer.http(name="telegram", url=os.environ["BEAVERGRAM_MCP"])
if env("BEAVERGRAM_MCP")
else None
)
"""beavergram: история чатов Бобра в Telegram."""
calendar_servers = calendars(env("CALENDAR_MCPS", ""))
calendar_exposed = tuple(ExposedMcp(name=m.name) for m in calendar_servers)
KOMODO = (
Komodo(
url=os.environ["KOMODO_URL"],
key=os.environ["KOMODO_KEY"],
secret=os.environ["KOMODO_SECRET"],
)
if env("KOMODO_URL")
else None
)
"""Флот: перечислимые действия, ключ остаётся в gateway."""
komodo = McpServer.python_tool(name="komodo", tools=[KOMODO.komodo]) if KOMODO else None
komodo_exposed = (ExposedMcp(name="komodo"),) if KOMODO else ()
HA = (
HomeAssistant(url=os.environ["HA_URL"], token=os.environ["HA_TOKEN"])
if env("HA_URL") and env("HA_TOKEN")
else None
)
"""Дом: HA живёт на хосте, из контейнера - host.docker.internal."""
ha = McpServer.python_tool(name="ha", tools=[HA.ha]) if HA else None
ha_exposed = (ExposedMcp(name="ha"),) if HA else ()
VIBEGRAM_REPO = Path("/vibegram") / env("VIBEGRAM_REPO", "x/room").split("/")[-1]
VIBEGRAM = (
Vibegram(
hub=env("VIBEGRAM_HUB", "https://vibegram.example.com"),
token=os.environ["VIBEGRAM_TOKEN"],
nick=env("VIBEGRAM_NICK", "beaver-test"),
repo=VIBEGRAM_REPO if VIBEGRAM_REPO.exists() else None,
tz=TZ,
)
if env("VIBEGRAM_TOKEN")
else None
)
"""Комната агентов: диспетчер сидит в ней сам; клон репы комнаты - том `vibegram`."""
vibegram = (
McpServer.python_tool(name="vibegram", tools=[VIBEGRAM.vibegram])
if VIBEGRAM
else None
)
vibegram_exposed = (ExposedMcp(name="vibegram"),) if VIBEGRAM else ()
t3code = (
McpServer.http(name="t3code", url=env("T3CODE_MCP", "http://t3code-mcp:8000/mcp"))
if "t3" in env("COMPOSE_PROFILES", "").split(",")
else None
)
"""t3code-mcp - сосед по compose (профиль t3); машины и allowlist в его t3code.toml."""
t3code_exposed = (ExposedMcp(name="t3code"),) if t3code else ()
msos = (
McpServer.http(name="msos", url=os.environ["MSOS_MCP"]) if env("MSOS_MCP") else None
)
"""Таскер рабочих проектов (скилл `задачи`)."""
msos_exposed = (ExposedMcp(name="msos"),) if msos else ()
mcps: list[McpServerT] = [
m
for m in (
obsidian,
firefly,
telegram,
*calendar_servers,
komodo,
ha,
vibegram,
t3code,
msos,
)
if m is not None
]
CLAUDE = (
*firefly_exposed,
ExposedMcp(name="telegram"),
*calendar_exposed,
*komodo_exposed,
*ha_exposed,
)
"""Руки любого Claude-агента: firefly без delete, телега, календари, флот, дом."""
DISPATCHER = (*CLAUDE, *t3code_exposed, *vibegram_exposed, *msos_exposed)
"""Диспетчер ещё ходит в код, в комнату агентов и в таскер; глубоким это не даётся."""
RAYCAST = (
ExposedMcp(name="obsidian-fs"),
*firefly_exposed,
ExposedMcp(name="telegram"),
*calendar_exposed,
)