feat(t3code): thread events as master injects, hook job without dedupe

This commit is contained in:
hh
2026-08-29 22:48:45 +02:00
parent ab6812f3ee
commit 6f8711c1a8
3 changed files with 56 additions and 0 deletions
+48
View File
@@ -2,6 +2,7 @@ import logging
import os
from datetime import UTC, date, datetime, timedelta
from pathlib import Path
from typing import Any
from zoneinfo import ZoneInfo
from beaver_gateway.agents.base import BaseAgent, ExposedMcp
@@ -589,6 +590,51 @@ async def memory(run: JobRun) -> None:
)
T3CODE_QUESTION_HINT = (
"Если ответ следует из задания - ответь сам: t3_answer(thread_id, "
"{id вопроса: label}). Не знаешь - спроси Бобра через say своими словами, "
"потом t3_answer. Тред стоит, пока не ответят."
)
def t3code_text(p: dict[str, Any]) -> str:
head = (
f"t3code: тред «{p.get('title')}» ({p.get('machine')}, {p.get('project')}, "
f"thread_id {p.get('thread_id')})"
)
event = p.get("event")
if event in ("question", "approval"):
lines = [f"{head} - спрашивает."]
for q in (p.get("question") or {}).get("questions", []):
multi = " (можно несколько)" if q.get("multi_select") else ""
lines.append(
f"- [{q['id']}] {q.get('header') or ''}: {q['question']}{multi}"
)
lines.extend(
f" · {o['label']}"
+ (f" - {o['description']}" if o.get("description") else "")
for o in q.get("options", [])
)
lines.append(T3CODE_QUESTION_HINT)
return "\n".join(lines)
if event == "completed":
lines = [f"{head} - завершён."]
elif event == "interrupted":
lines = [f"{head} - прерван."]
else:
lines = [f"{head} - упал: {p.get('error') or 'без текста ошибки'}."]
if p.get("text"):
lines.append(f"Ответ треда:\n{p['text']}")
if p.get("files"):
lines.append("Файлы: " + ", ".join(f["path"] for f in p["files"]))
return "\n".join(lines)
async def t3code_event(run: JobRun) -> None:
"""§5, §8.6: t3code-mcp следит за тредами по WS и присылает сюда события."""
await run.inject_master(t3code_text(run.payload), urgency="urgent", origin="t3code")
async def komodo_alert(run: JobRun) -> None:
payload = run.payload
summary = payload.get("raw") or {k: v for k, v in payload.items() if k != "trigger"}
@@ -602,6 +648,8 @@ jobs = [
Job("память", memory, cron="30 4 * * 0", critical=False),
Job("deploy", deploy, webhook=True),
Job("komodo", komodo_alert, webhook=True),
# события идут подряд (вопрос и завершение) - схлопывать нельзя
Job("t3code", t3code_event, webhook=True, dedupe=False),
]
gateway = Gateway(