From bc0f583a0fa99cea8f11cb54b7e7433180285c1a Mon Sep 17 00:00:00 2001 From: gahusb Date: Thu, 11 Jun 2026 02:38:56 +0900 Subject: [PATCH] =?UTF-8?q?feat(agent-office):=20issue=5Fapprove/reject/re?= =?UTF-8?q?gen=20=EC=BD=9C=EB=B0=B1=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- agent-office/app/agents/insta.py | 32 +++++++++++++++++++++ agent-office/tests/test_insta_autonomous.py | 26 +++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/agent-office/app/agents/insta.py b/agent-office/app/agents/insta.py index 461f322..2c308ed 100644 --- a/agent-office/app/agents/insta.py +++ b/agent-office/app/agents/insta.py @@ -226,6 +226,38 @@ class InstaAgent(BaseAgent): return {"ok": False} await self._render_and_push(kid) return {"ok": True} + if action in ("issue_approve", "issue_reject"): + sid = int(params.get("slate_id") or 0) + if not sid: + return {"ok": False} + decision = "approved" if action == "issue_approve" else "rejected" + await service_proxy.insta_decision(sid, decision) + if decision == "approved": + slate = await service_proxy.insta_get_slate(sid) + media = [] + for a in slate["assets"][:10]: + data = await service_proxy.insta_get_asset_bytes(sid, a["page_index"]) + media.append({"type": "photo", "_bytes": data}) + cap = f"{slate.get('suggested_caption','')}\n\n{' '.join(slate.get('hashtags', []) or [])}".strip() + await _send_media_group(media, caption=cap) + await messaging.send_raw(f"✅ 발행 완료 (slate {sid})") + else: + await messaging.send_raw(f"❌ 반려됨 (slate {sid})") + return {"ok": True} + if action == "issue_regen": + sid = int(params.get("slate_id") or 0) + if not sid: + return {"ok": False} + slate = await service_proxy.insta_get_slate(sid) + await service_proxy.insta_decision(sid, "rejected") + await self._generate_and_preview({ + "id": 0, + "keyword": slate["keyword"], + "category": slate["category"], + "final_score": None, + "breakdown": {}, + }) + return {"ok": True} return {"ok": False} async def on_approval(self, task_id: str, approved: bool, feedback: str = "") -> None: diff --git a/agent-office/tests/test_insta_autonomous.py b/agent-office/tests/test_insta_autonomous.py index a846d7a..d05054b 100644 --- a/agent-office/tests/test_insta_autonomous.py +++ b/agent-office/tests/test_insta_autonomous.py @@ -47,3 +47,29 @@ async def test_autonomous_issue_previews_eligible(monkeypatch): await agent.on_schedule() assert preview.await_count == 1 assert preview.await_args.args[0]["id"] == 1 + + +@pytest.mark.asyncio +async def test_callback_approve_publishes_and_delivers(monkeypatch): + agent = InstaAgent() + monkeypatch.setattr("app.agents.insta.service_proxy.insta_decision", + AsyncMock(return_value={"status": "published"})) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_get_slate", AsyncMock(return_value={ + "assets": [{"page_index": i} for i in range(1, 11)], + "suggested_caption": "cap", "hashtags": ["#a"]})) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_get_asset_bytes", AsyncMock(return_value=b"png")) + monkeypatch.setattr("app.agents.insta._send_media_group", AsyncMock(return_value={"ok": True})) + monkeypatch.setattr("app.agents.insta.messaging.send_raw", AsyncMock()) + res = await agent.on_callback("issue_approve", {"slate_id": 8}) + assert res["ok"] is True + + +@pytest.mark.asyncio +async def test_callback_reject_marks_rejected(monkeypatch): + agent = InstaAgent() + dec = AsyncMock(return_value={"status": "rejected"}) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_decision", dec) + monkeypatch.setattr("app.agents.insta.messaging.send_raw", AsyncMock()) + res = await agent.on_callback("issue_reject", {"slate_id": 8}) + assert res["ok"] is True + dec.assert_awaited_once_with(8, "rejected")