152 lines
5.3 KiB
Python
152 lines
5.3 KiB
Python
"""Роли и их экземпляры: кто с каким промптом, скиллами, руками и границами."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING
|
|
|
|
from beaver_gateway.agents.claude import ClaudeAgent, ClaudeOptions
|
|
from beaver_gateway.agents.raycast import RaycastAgent, RemoteTool, UserPreferences
|
|
|
|
from beaver_agent import hands, prompts, skills
|
|
from beaver_agent.policy import (
|
|
DEEP_DISALLOWED,
|
|
DISPATCHER_DISALLOWED,
|
|
DISTILLER_DISALLOWED,
|
|
STRICT_ZONES,
|
|
TRIAGE_DISALLOWED,
|
|
VAULT_POLICY,
|
|
forbid_skills,
|
|
vault_zones,
|
|
)
|
|
from beaver_agent.vault import TZ, VAULT
|
|
from beaver_agent.voice import AGENT as VOICE
|
|
|
|
if TYPE_CHECKING:
|
|
from beaver_gateway.agents.base import BaseAgent
|
|
|
|
|
|
def dispatcher(name: str, model: str, effort: str) -> ClaudeAgent:
|
|
"""Мастер и ветки: полный голос, все руки, vault - дом."""
|
|
return ClaudeAgent(
|
|
name=name,
|
|
model=model,
|
|
cwd=VAULT,
|
|
prompts=prompts.DISPATCHER,
|
|
skill_sets=skills.DISPATCHER,
|
|
gateway_tools=("read_conversation", "spawn", "say", "schedule", "send_file"),
|
|
options=ClaudeOptions(effort=effort, disallowed_tools=DISPATCHER_DISALLOWED),
|
|
policy=(
|
|
*VAULT_POLICY,
|
|
forbid_skills(skills.MASTER_FORBIDDEN, kinds=("master",)),
|
|
),
|
|
expose_mcps=hands.DISPATCHER,
|
|
)
|
|
|
|
|
|
def deep(name: str, model: str, effort: str) -> ClaudeAgent:
|
|
"""Глубокий чат в файле vault; «ок, обсудили» - тулза close_chat."""
|
|
return ClaudeAgent(
|
|
name=name,
|
|
model=model,
|
|
cwd=VAULT,
|
|
prompts=prompts.DEEP,
|
|
skill_sets=skills.DEEP,
|
|
gateway_tools=("close_chat",),
|
|
options=ClaudeOptions(effort=effort, disallowed_tools=DEEP_DISALLOWED),
|
|
policy=VAULT_POLICY,
|
|
expose_mcps=hands.CLAUDE,
|
|
)
|
|
|
|
|
|
def distiller(name: str, model: str, effort: str) -> ClaudeAgent:
|
|
"""Форк закрытого чата и недельная чистка состояния: Read/Write в мета/бобер."""
|
|
return ClaudeAgent(
|
|
name=name,
|
|
model=model,
|
|
cwd=VAULT,
|
|
prompts=prompts.DISTILLER,
|
|
options=ClaudeOptions(
|
|
effort=effort,
|
|
tools=("Read", "Write"),
|
|
disallowed_tools=DISTILLER_DISALLOWED,
|
|
),
|
|
policy=(vault_zones(STRICT_ZONES),),
|
|
)
|
|
|
|
|
|
def curator(name: str, model: str, effort: str) -> ClaudeAgent:
|
|
"""Куратор памяти: раскладывает новое по наблюдениям, будит мастера через inject."""
|
|
return ClaudeAgent(
|
|
name=name,
|
|
model=model,
|
|
cwd=VAULT,
|
|
prompts=prompts.CURATOR,
|
|
gateway_tools=("inject",),
|
|
options=ClaudeOptions(
|
|
effort=effort,
|
|
tools=("Read", "Write", "Edit", "Grep", "Glob"),
|
|
disallowed_tools=DISTILLER_DISALLOWED,
|
|
),
|
|
policy=(vault_zones(STRICT_ZONES),),
|
|
)
|
|
|
|
|
|
def triage(name: str, model: str, effort: str) -> ClaudeAgent:
|
|
"""Дешёвый крон-тёрн без vault: решает, будить ли мастера."""
|
|
return ClaudeAgent(
|
|
name=name,
|
|
model=model,
|
|
cwd=Path("/tmp"), # noqa: S108
|
|
prompts=prompts.TRIAGE,
|
|
gateway_tools=("say", "inject"),
|
|
options=ClaudeOptions(
|
|
effort=effort, tools=(), disallowed_tools=TRIAGE_DISALLOWED
|
|
),
|
|
)
|
|
|
|
|
|
def voice(name: str, model: str) -> ClaudeAgent:
|
|
"""Колонки по квартире: чужие люди, поэтому ни vault, ни инструментов."""
|
|
return ClaudeAgent(
|
|
name=name,
|
|
model=model,
|
|
cwd=Path("/tmp"), # noqa: S108
|
|
prompts=prompts.VOICE_AGENT,
|
|
options=ClaudeOptions(tools=(), disallowed_tools=TRIAGE_DISALLOWED),
|
|
)
|
|
|
|
|
|
def raycast(name: str, model: str, effort: str) -> RaycastAgent:
|
|
"""Быстрые ответы через Raycast: веб и чтение страниц, vault через obsidian-fs."""
|
|
return RaycastAgent(
|
|
name=name,
|
|
model=model,
|
|
system_prompt=prompts.QUICK,
|
|
reasoning_effort=effort,
|
|
available_native_tools=(RemoteTool.WEB_SEARCH, RemoteTool.READ_PAGE),
|
|
user_preferences=lambda: UserPreferences(
|
|
locale="ru-RU", timezone=TZ, current_date=date.today().isoformat()
|
|
),
|
|
expose_mcps=hands.RAYCAST,
|
|
)
|
|
|
|
|
|
agents: list[BaseAgent] = [
|
|
dispatcher("beaver-dispatcher", "claude-opus-5", "high"),
|
|
deep("beaver-opus-high", "claude-opus-5", "high"),
|
|
deep("beaver-opus-medium", "claude-opus-5", "medium"),
|
|
deep("beaver-opus-xhigh", "claude-opus-5", "xhigh"),
|
|
deep("beaver-fable-high", "claude-fable-5-1", "high"),
|
|
deep("beaver-fable-medium", "claude-fable-5-1", "medium"),
|
|
distiller("beaver-distiller", "claude-opus-5", "medium"),
|
|
curator("beaver-curator", "claude-opus-5", "high"),
|
|
triage("beaver-triage", "claude-sonnet-5", "low"),
|
|
voice(VOICE, "claude-haiku-4-5-20251001"),
|
|
raycast("beaver-gemini-pro-high", "google-gemini-3.1-pro", "high"),
|
|
raycast("beaver-gemini-pro-low", "google-gemini-3.1-pro", "low"),
|
|
raycast("beaver-gemini-flash-high", "google-gemini-3.5-flash", "high"),
|
|
raycast("beaver-gemini-flash-low", "google-gemini-3.5-flash", "low"),
|
|
]
|