From 7c4d7b45347b3aa9954fb77f323e14ba8a5f759e Mon Sep 17 00:00:00 2001 From: gahusb Date: Wed, 15 Apr 2026 08:28:10 +0900 Subject: [PATCH] =?UTF-8?q?feat(agent-office):=20LottoAgent=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20+=20seed=20+=20=ED=85=94=EB=A0=88=EA=B7=B8=EB=9E=A8?= =?UTF-8?q?=20=EB=A9=94=ED=83=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agent-office/app/agents/__init__.py | 2 + agent-office/app/agents/lotto.py | 44 +++++++++++++++++++++ agent-office/app/db.py | 1 + agent-office/app/telegram/agent_registry.py | 4 ++ 4 files changed, 51 insertions(+) create mode 100644 agent-office/app/agents/lotto.py diff --git a/agent-office/app/agents/__init__.py b/agent-office/app/agents/__init__.py index 2efe4a2..4b913e2 100644 --- a/agent-office/app/agents/__init__.py +++ b/agent-office/app/agents/__init__.py @@ -2,6 +2,7 @@ from .stock import StockAgent from .music import MusicAgent from .blog import BlogAgent from .realestate import RealestateAgent +from .lotto import LottoAgent AGENT_REGISTRY = {} @@ -10,6 +11,7 @@ def init_agents(): AGENT_REGISTRY["music"] = MusicAgent() AGENT_REGISTRY["blog"] = BlogAgent() AGENT_REGISTRY["realestate"] = RealestateAgent() + AGENT_REGISTRY["lotto"] = LottoAgent() def get_agent(agent_id: str): return AGENT_REGISTRY.get(agent_id) diff --git a/agent-office/app/agents/lotto.py b/agent-office/app/agents/lotto.py new file mode 100644 index 0000000..ec858e1 --- /dev/null +++ b/agent-office/app/agents/lotto.py @@ -0,0 +1,44 @@ +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 not in ("idle", "break"): + 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}"} + 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(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=result) + await self.transition("reporting", f"#{result['draw_no']} 브리핑 저장 완료") + add_log(self.agent_id, f"큐레이션 완료: #{result['draw_no']} conf={result['confidence']}", task_id=task_id) + await self.transition("idle", "대기 중") + return {"ok": True, **result} + 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}"} diff --git a/agent-office/app/db.py b/agent-office/app/db.py index 857c76b..61aa7c2 100644 --- a/agent-office/app/db.py +++ b/agent-office/app/db.py @@ -92,6 +92,7 @@ def init_db() -> None: ("music", "음악 프로듀서"), ("blog", "블로그 마케터"), ("realestate", "청약 애널리스트"), + ("lotto", "로또 큐레이터"), ]: conn.execute( "INSERT OR IGNORE INTO agent_config(agent_id, display_name) VALUES(?,?)", diff --git a/agent-office/app/telegram/agent_registry.py b/agent-office/app/telegram/agent_registry.py index 3ac9478..5fdb736 100644 --- a/agent-office/app/telegram/agent_registry.py +++ b/agent-office/app/telegram/agent_registry.py @@ -11,6 +11,10 @@ AGENT_META = { "emoji": "🎵", "color": "#44aa88", }, + "lotto": { + "emoji": "🎱", + "display_name": "로또 큐레이터", + }, }