Add outbound agent response boundary
This commit is contained in:
@@ -13,10 +13,12 @@ from app.agent.modes.steward import StewardMode
|
|||||||
from app.agent.modes.warden import WardenMode
|
from app.agent.modes.warden import WardenMode
|
||||||
from app.agent.modes.librarian import LibrarianMode
|
from app.agent.modes.librarian import LibrarianMode
|
||||||
from app.agent.modes.scribe import ScribeMode
|
from app.agent.modes.scribe import ScribeMode
|
||||||
|
from app.config import settings
|
||||||
from app.llm.client import LLMClient
|
from app.llm.client import LLMClient
|
||||||
from app.memory.database import get_session
|
from app.memory.database import get_session
|
||||||
from app.memory.models import AgentActionType
|
from app.memory.models import AgentActionType
|
||||||
from app.memory.repository import Repository
|
from app.memory.repository import Repository
|
||||||
|
from app.twitch.chat import send_chat_message
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -212,6 +214,49 @@ class AgentOrchestrator:
|
|||||||
"actions_taken": actions,
|
"actions_taken": actions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async def emit_agent_response(
|
||||||
|
self,
|
||||||
|
session_id: str,
|
||||||
|
message: str,
|
||||||
|
mode: str,
|
||||||
|
triggered_by_message_id: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
"""Send an agent response through the outbound chat boundary."""
|
||||||
|
session_info = self.active_sessions.get(session_id)
|
||||||
|
if not session_info:
|
||||||
|
logger.warning(f"Session {session_id} not found")
|
||||||
|
return {"sent": False, "reason": "session_not_found"}
|
||||||
|
|
||||||
|
channel_name = session_info["channel_name"]
|
||||||
|
sent = await send_chat_message(channel_name=channel_name, message=message)
|
||||||
|
bot_username = settings.TWITCH_BOT_USERNAME or "sanctum_chronicler"
|
||||||
|
|
||||||
|
async for db_session in get_session():
|
||||||
|
repo = Repository(db_session)
|
||||||
|
bot_message_id = await repo.add_chat_message(
|
||||||
|
session_id=session_id,
|
||||||
|
username=bot_username,
|
||||||
|
content=message,
|
||||||
|
is_bot=True,
|
||||||
|
)
|
||||||
|
action_id = await repo.record_action(
|
||||||
|
session_id=session_id,
|
||||||
|
action_type=AgentActionType.RESPONSE,
|
||||||
|
mode=mode,
|
||||||
|
description=message,
|
||||||
|
triggered_by_message_id=triggered_by_message_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Agent response emitted. Session: {session_id}, Mode: {mode}, Sent: {sent}"
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"sent": sent,
|
||||||
|
"channel": channel_name,
|
||||||
|
"message_id": bot_message_id,
|
||||||
|
"action_id": action_id,
|
||||||
|
}
|
||||||
|
|
||||||
def set_loop_interval(self, interval_seconds: float) -> None:
|
def set_loop_interval(self, interval_seconds: float) -> None:
|
||||||
"""Update how frequently the background agent loop runs."""
|
"""Update how frequently the background agent loop runs."""
|
||||||
if interval_seconds < 1:
|
if interval_seconds < 1:
|
||||||
@@ -269,20 +314,17 @@ class AgentOrchestrator:
|
|||||||
theme=session_info.get("theme")
|
theme=session_info.get("theme")
|
||||||
)
|
)
|
||||||
session_info["last_hearthkeeper_prompt_at"] = datetime.utcnow()
|
session_info["last_hearthkeeper_prompt_at"] = datetime.utcnow()
|
||||||
|
delivery = await self.emit_agent_response(
|
||||||
async for db_session in get_session():
|
|
||||||
repo = Repository(db_session)
|
|
||||||
await repo.record_action(
|
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
action_type=AgentActionType.RESPONSE,
|
message=agent_response,
|
||||||
mode="hearthkeeper",
|
mode="hearthkeeper",
|
||||||
description=agent_response,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"session_id": session_id,
|
"session_id": session_id,
|
||||||
"actions_taken": ["HEARTHKEEPER_PROMPT"],
|
"actions_taken": ["HEARTHKEEPER_PROMPT"],
|
||||||
"agent_response": agent_response,
|
"agent_response": agent_response,
|
||||||
|
"delivery": delivery,
|
||||||
"reason": "inactive_chat",
|
"reason": "inactive_chat",
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
25
app/main.py
25
app/main.py
@@ -128,6 +128,31 @@ async def test_message(session_id: str = Form(...), message: str = Form(...), us
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/admin/test-agent-response")
|
||||||
|
async def test_agent_response(
|
||||||
|
session_id: str = Form(...),
|
||||||
|
message: str = Form(...),
|
||||||
|
mode: str = Form("admin"),
|
||||||
|
) -> dict:
|
||||||
|
"""Send a test agent response through the outbound boundary."""
|
||||||
|
if not orchestrator:
|
||||||
|
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
|
||||||
|
|
||||||
|
delivery = await orchestrator.emit_agent_response(
|
||||||
|
session_id=session_id,
|
||||||
|
message=message,
|
||||||
|
mode=mode,
|
||||||
|
)
|
||||||
|
if not delivery.get("sent"):
|
||||||
|
raise HTTPException(status_code=404, detail=delivery.get("reason", "send_failed"))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "agent_response_emitted",
|
||||||
|
"delivery": delivery,
|
||||||
|
"timestamp": datetime.utcnow().isoformat(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/admin/ledger")
|
@app.get("/admin/ledger")
|
||||||
async def get_ledger(session_id: str) -> dict:
|
async def get_ledger(session_id: str) -> dict:
|
||||||
"""Get the markdown ledger for a session."""
|
"""Get the markdown ledger for a session."""
|
||||||
|
|||||||
Reference in New Issue
Block a user