Files
beaver-agent/beaver_agent/hands/__init__.py
T

143 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Руки: какие 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", "org/room").split("/")[-1]
VIBEGRAM = (
Vibegram(
hub=os.environ["VIBEGRAM_HUB"],
token=os.environ["VIBEGRAM_TOKEN"],
nick=os.environ["VIBEGRAM_NICK"],
repo=VIBEGRAM_REPO if VIBEGRAM_REPO.exists() else None,
tz=TZ,
)
if env("VIBEGRAM_TOKEN") and env("VIBEGRAM_HUB") and env("VIBEGRAM_NICK")
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,
)