Files
web-page-backend/agent-office/app/agents/lotto.py
gahusb b35fab777e feat(lotto-signals): LottoAgent.run_signal_check/run_daily_digest (텔레그램 X)
Phase 2: on_command에 signal_check/light_check/sim_check/deep_check/daily_digest 액션 추가.
run_signal_check는 lotto_signals DB INSERT만, run_daily_digest는 24h 발화 카운트 반환.
텔레그램 발송은 Task 9 (Phase 3)에서 추가 예정.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 02:54:09 +09:00

107 lines
5.0 KiB
Python

from .base import BaseAgent
from ..db import create_task, update_task_status, add_log
from ..curator.pipeline import curate_weekly, CuratorError
class LottoAgent(BaseAgent):
agent_id = "lotto"
display_name = "로또 큐레이터"
async def on_schedule(self) -> None:
if self.state != "idle":
return
await self._run(source="auto")
async def on_command(self, action: str, params: dict) -> dict:
if action in ("curate_now", "curate_weekly"):
return await self._run(source="manual")
if action == "status":
return {"ok": True, "message": f"{self.state}: {self.state_detail}"}
if action in ("signal_check", "light_check", "sim_check", "deep_check"):
source = action.replace("_check", "") if action != "signal_check" else "light"
return await self.run_signal_check(source=source)
if action == "daily_digest":
return await self.run_daily_digest()
return {"ok": False, "message": f"unknown action: {action}"}
async def on_approval(self, task_id: str, approved: bool, feedback: str = "") -> None:
pass
async def run_signal_check(self, source: str = "light") -> dict:
"""비-LLM 시그널 평가 (light/sim) 또는 deep_check (LLM 호출 후).
Phase 2: 텔레그램 발송 안 함. lotto_signals INSERT만.
Phase 3 (Task 9): urgent 시그널 텔레그램 발송 + throttle 추가.
"""
from ..curator.signal_runner import run_signal_check
from ..config import LOTTO_Z_NORMAL, LOTTO_Z_URGENT
from ..db import add_log
if self.state not in ("idle", "reporting"):
return {"ok": False, "message": f"busy ({self.state})"}
try:
curate_result = None
current_draw_no = None
if source == "deep":
from ..curator.pipeline import curate_weekly
cw = await curate_weekly(source="signal_deep")
# curate_weekly returns {"ok", "draw_no", "confidence", "tokens", "payload"}
curate_result = {"confidence": cw.get("confidence")}
current_draw_no = cw.get("draw_no")
outcome = await run_signal_check(
source=source,
z_normal=LOTTO_Z_NORMAL,
z_urgent=LOTTO_Z_URGENT,
curate_result=curate_result,
current_draw_no=current_draw_no,
)
add_log(
self.agent_id,
f"signal_check({source}) → overall={outcome['overall_fire']} results={len(outcome['results'])}",
)
return {"ok": True, **outcome}
except Exception as e:
add_log(self.agent_id, f"signal_check 예외: {e}", level="error")
return {"ok": False, "message": f"{type(e).__name__}: {e}"}
async def run_daily_digest(self) -> dict:
"""Phase 2: 발화 카운트만 반환. Phase 3 (Task 9)에서 텔레그램 발송 추가."""
from ..db import get_recent_lotto_signals, add_log
sigs = get_recent_lotto_signals(hours=24, min_fire="normal")
add_log(self.agent_id, f"daily_digest: 지난 24h 발화 {len(sigs)}")
return {"ok": True, "count": len(sigs), "signals": sigs}
async def _run(self, source: str) -> dict:
task_id = create_task(self.agent_id, "curate_weekly", {"source": source})
await self.transition("working", "후보 수집 및 AI 큐레이션 중...", task_id)
try:
result = await curate_weekly(source=source)
update_task_status(task_id, "succeeded", result_data={
k: v for k, v in result.items() if k != "payload"
})
await self.transition("reporting", f"#{result['draw_no']} 브리핑 저장 완료")
add_log(self.agent_id, f"큐레이션 완료: #{result['draw_no']} conf={result['confidence']}", task_id=task_id)
# 텔레그램 헤드라인 푸시 (실패해도 큐레이션은 성공으로 마감)
try:
from ..notifiers.telegram_lotto import send_curator_briefing
await send_curator_briefing(result["payload"])
except Exception as e:
add_log(self.agent_id, f"텔레그램 알림 실패: {e}", level="warning", task_id=task_id)
await self.transition("idle", "대기 중")
return {"ok": True, **{k: v for k, v in result.items() if k != "payload"}}
except CuratorError as e:
update_task_status(task_id, "failed", result_data={"error": str(e)})
add_log(self.agent_id, f"큐레이션 실패: {e}", level="error", task_id=task_id)
await self.transition("idle", "오류")
return {"ok": False, "message": str(e)}
except Exception as e:
update_task_status(task_id, "failed", result_data={"error": str(e)})
add_log(self.agent_id, f"큐레이션 예외: {e}", level="error", task_id=task_id)
await self.transition("idle", "오류")
return {"ok": False, "message": f"{type(e).__name__}: {e}"}