Add quiet loop verification endpoint

This commit is contained in:
2026-05-12 08:15:46 -05:00
parent 7286a241e4
commit 26db60f310
2 changed files with 79 additions and 0 deletions

View File

@@ -247,6 +247,7 @@ class AgentOrchestrator:
triggered_by_message_id=triggered_by_message_id, triggered_by_message_id=triggered_by_message_id,
) )
session_info["message_count"] += 1
logger.info( logger.info(
f"Agent response emitted. Session: {session_id}, Mode: {mode}, Sent: {sent}" f"Agent response emitted. Session: {session_id}, Mode: {mode}, Sent: {sent}"
) )
@@ -257,6 +258,61 @@ class AgentOrchestrator:
"action_id": action_id, "action_id": action_id,
} }
async def run_hearthkeeper_loop_test(
self,
session_id: str,
inactive_minutes: int = 16,
) -> dict:
"""Exercise the quiet-chat loop and verify it prompts exactly once."""
session_info = self.active_sessions.get(session_id)
if not session_info:
return {"passed": False, "reason": "session_not_found"}
simulated_activity_at = datetime.utcnow() - timedelta(minutes=inactive_minutes)
self.chat_activity.record_activity(
session_id=session_id,
occurred_at=simulated_activity_at,
)
session_info["last_hearthkeeper_prompt_at"] = None
before_count = await self._count_response_actions(
session_id=session_id,
mode="hearthkeeper",
)
first_tick = await self._tick_session(session_id)
second_tick = await self._tick_session(session_id)
after_count = await self._count_response_actions(
session_id=session_id,
mode="hearthkeeper",
)
prompts_created = after_count - before_count
return {
"passed": (
prompts_created == 1
and first_tick is not None
and second_tick is None
),
"session_id": session_id,
"inactive_minutes": inactive_minutes,
"prompts_created": prompts_created,
"first_tick": first_tick,
"second_tick": second_tick,
}
async def _count_response_actions(self, session_id: str, mode: str) -> int:
"""Count response actions for a mode in a session."""
async for db_session in get_session():
repo = Repository(db_session)
actions = await repo.get_session_actions(session_id)
return sum(
1
for action in actions
if action.action_type == AgentActionType.RESPONSE
and action.mode == mode
)
return 0
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:

View File

@@ -153,6 +153,29 @@ async def test_agent_response(
} }
@app.post("/admin/test-loop-inactivity")
async def test_loop_inactivity(
session_id: str = Form(...),
inactive_minutes: int = Form(16),
) -> dict:
"""Verify the quiet-chat loop records exactly one Hearthkeeper prompt."""
if not orchestrator:
raise HTTPException(status_code=503, detail="Orchestrator not initialized")
result = await orchestrator.run_hearthkeeper_loop_test(
session_id=session_id,
inactive_minutes=inactive_minutes,
)
if result.get("reason") == "session_not_found":
raise HTTPException(status_code=404, detail="Active session not found")
return {
"status": "passed" if result["passed"] else "failed",
"result": result,
"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."""