Files

187 lines
8.3 KiB
Python
Raw Permalink 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.
"""Всё, что gateway говорит модели и Бобру, по-русски."""
from __future__ import annotations
from typing import TYPE_CHECKING
from beaver_gateway.conversations.texts import ConversationTexts, EnvelopeTexts
from beaver_gateway.frontends.telegram import TelegramTexts
from beaver_agent.memory.handouts import (
distill_prompt,
handout_prompt,
new_day,
seed_body,
)
from beaver_agent.vault import GRANULES, read
if TYPE_CHECKING:
from beaver_gateway.conversations.injects import InjectContext
BEAVER_ORIGINS = frozenset({"panel", "api"})
"""Панель и API - это сам Бобёр; крон, watch, komodo, ротация - нет."""
ORIGINS = {
"merge": "слив",
"digest": "выжимка",
"rotation": "ротация",
"cap": "потолок",
"system": "система",
"agent": "агент",
}
INTERRUPTED_TURN = (
"[этот инжект прервал предыдущий тёрн: «Request interrupted» выше - "
"прерывание, не отказ от тулзы]"
)
def inject_header(ctx: InjectContext) -> str:
if ctx.origin in BEAVER_ORIGINS:
head = (
"[инжект из панели: это Бобёр, ответ он видит в панели; "
"в телегу - только через say]"
)
else:
origin = ORIGINS.get(ctx.origin, ctx.origin)
head = (
f"[инжект: {origin} - это не Бобёр, отвечать не нужно, голос не обязателен]"
)
return f"{head}\n{INTERRUPTED_TURN}" if ctx.interrupted_turn else head
ENVELOPE = EnvelopeTexts(
header=(
"[конверт - фоновый сигнал, не обращение; "
"реагируй, только если относится к вопросу]"
),
time="время: {stamp} ({zone})",
changed="vault, изменено {since}: {names}",
since="с {time}",
since_start="со старта",
truncated="… (потолок конверта)",
file_header="--- {path}, только добавленное ---",
more_lines="+ … ещё {count}",
)
MERGE_PROMPT = read(GRANULES / "слив.md") or (
"Ветка закрывается. Напиши слив для мастера: что решили, что сделано, "
"что не сделано и почему, открытые вопросы. Идентификаторы и ссылки - "
"дословно. Коротко, прошедшее время."
)
CONVERSATIONS = ConversationTexts(
merge_prompt=MERGE_PROMPT,
inject_header=inject_header,
bundle_header="[инжекты, накопившиеся с {since}; это не Бобёр]",
task_prompt="[субагент отчитался: {note}]",
interrupted="прервано",
answered="Пользователь ответил: {answer}",
unanswered=(
"Пользователь не ответил за {minutes} мин. Вопрос ему показан текстом; "
"заверши тёрн сейчас, ответ придёт следующим сообщением."
),
seed=seed_body,
seed_head="[сид: {seed}] {kind}{title}, {stamp}.",
seed_copy="История родителя скопирована ({scope}); продолжай в ней.",
seed_copy_window="последние {window} тёрнов",
seed_copy_all="вся история",
seed_morning_missing="Хендаут не приехал.",
handout=handout_prompt,
new_day=new_day,
moved_injects=" Инжектов переехало из старого мастера: {moved}.",
distill=distill_prompt,
closed="Закрыт глубокий чат [[{chat}]]{digest}.\n{text}",
closed_digest=", выжимка [[{digest}]]",
digest_missing="файл выжимки не появился",
too_long=(
"`{name}`: {lines} строк при потолке {max_lines}. Запись отбита, файл "
"возвращён к прежней версии. Сократи и перепиши."
),
cut_by_restart="тёрн {turn_id} оборван рестартом gateway",
repaired_tools=(
"; {fixed} незакрытых тул-коллов получили tool_result «{interrupted}»"
),
envelope=ENVELOPE,
)
TELEGRAM = TelegramTexts(
commands=(
("merge", "слить ветку в мастер"),
("new", "новая ветка: в General - новый топик, в топике - заново на нём"),
("chat", "открыть глубокий чат в vault: /chat тема"),
("status", "что с этим разговором"),
("help", "команды"),
),
help_head="General - мастер, любой другой топик - ветка.",
branch="ветка",
waiting="⏳ думаю",
thinking="🤔 думаю",
writing="✍️ пишу",
tool_labels={
"Read": "читаю vault",
"Glob": "ищу файлы",
"Grep": "ищу в vault",
"Edit": "правлю файл",
"Write": "пишу файл",
"MultiEdit": "правлю файлы",
"Bash": "выполняю команду",
"WebSearch": "ищу в сети",
"WebFetch": "читаю страницу",
"Task": "запустил сабагента",
"Agent": "запустил сабагента",
"AskUserQuestion": "спрашиваю",
"TodoWrite": "планирую",
"Skill": "открываю скилл",
"mcp__gateway__spawn": "открываю разговор",
"mcp__gateway__read_conversation": "читаю разговор",
"mcp__gateway__say": "говорю",
"mcp__gateway__schedule": "ставлю напоминание",
"mcp__gateway__inject": "передаю в другой разговор",
},
attachment_sticker="[вложение: стикер - не поддерживается]",
attachment_animation="[вложение: анимация - не поддерживается]",
attachment_kinds={
"photo": "фото",
"document": "файл",
"voice": "голосовое",
"audio": "аудио",
"video": "видео",
"video_note": "кружок",
},
attachment_too_big=(
"[вложение: {kind} {name}, {mb} МБ - больше 20 МБ, Telegram не отдаёт ботам]"
),
attachment_failed="[вложение: {kind} {name} - не скачалось: {error}]",
attachment_size=", {kb} КБ",
attachment="[вложение: {kind} {path}{size}]",
attachment_kept=(
"[вложение: {kind} {path}{size}; хранится {days} дн., "
"перенеси в vault, если нужно]"
),
merge_nothing="сливать нечего: это не открытая ветка",
merging="🔀 сливаю в мастер",
merged="✅ слито в мастер",
merge_failed="⚠️ слив не удался: {error}",
new_branch_topic="🌿 ветка «{title}» - в новом топике",
new_branch_here="🌿 новая ветка на этом топике",
chat_usage="/chat <тема>",
chat_failed="не вышло: {error}",
chat_opened="💬 глубокий чат: {where}",
status_unbound="этот топик ни к чему не привязан - напиши, и откроется ветка",
status_line="сессия: {live} · тёрн: {turn} · в очереди: {queued}",
status_live="живая",
status_dead="нет",
status_running="идёт",
status_idle="нет",
status_question="❓ ждёт ответа на вопрос",
status_pool="пул: {sessions} сессий, rss {mb} МБ",
status_outbox="outbox: {pending} в очереди",
turn_failed="⚠️ тёрн упал, смотри логи gateway",
background_failed="⚠️ фоновый тёрн ({origin}) упал, смотри логи gateway",
question_closed="вопрос уже закрыт",
question_timeout="⌛ время вышло - ответь текстом",
done_button="✅ готово",
mirrored="📝 из панели:\n{text}",
)