Prompt repeatedly during quiet chat
This commit is contained in:
@@ -36,6 +36,9 @@ class AgentOrchestrator:
|
|||||||
"""Initialize the orchestrator and all modes."""
|
"""Initialize the orchestrator and all modes."""
|
||||||
self.llm_client = LLMClient()
|
self.llm_client = LLMClient()
|
||||||
self.loop_interval_seconds = loop_interval_seconds
|
self.loop_interval_seconds = loop_interval_seconds
|
||||||
|
self.hearthkeeper_prompt_interval = timedelta(
|
||||||
|
minutes=settings.HEARTHKEEPER_PROMPT_INTERVAL_MINUTES
|
||||||
|
)
|
||||||
|
|
||||||
# Initialize modes
|
# Initialize modes
|
||||||
self.hearthkeeper = HearthkeeperMode(self.llm_client)
|
self.hearthkeeper = HearthkeeperMode(self.llm_client)
|
||||||
@@ -93,7 +96,10 @@ class AgentOrchestrator:
|
|||||||
sessions = await repo.get_active_sessions()
|
sessions = await repo.get_active_sessions()
|
||||||
|
|
||||||
for session in sessions:
|
for session in sessions:
|
||||||
recent_messages = await repo.get_recent_messages(session.id, limit=1)
|
recent_messages = await repo.get_recent_human_messages(
|
||||||
|
session.id,
|
||||||
|
limit=1,
|
||||||
|
)
|
||||||
message_count = await repo.count_messages(session.id)
|
message_count = await repo.count_messages(session.id)
|
||||||
last_activity_at = (
|
last_activity_at = (
|
||||||
recent_messages[0].timestamp if recent_messages else session.started_at
|
recent_messages[0].timestamp if recent_messages else session.started_at
|
||||||
@@ -189,7 +195,7 @@ class AgentOrchestrator:
|
|||||||
recent_messages = []
|
recent_messages = []
|
||||||
async for db_session in get_session():
|
async for db_session in get_session():
|
||||||
repo = Repository(db_session)
|
repo = Repository(db_session)
|
||||||
recent_messages = await repo.get_messages_since(
|
recent_messages = await repo.get_human_messages_since(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
since=datetime.utcnow() - timedelta(minutes=1),
|
since=datetime.utcnow() - timedelta(minutes=1),
|
||||||
)
|
)
|
||||||
@@ -285,19 +291,32 @@ class AgentOrchestrator:
|
|||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
mode="hearthkeeper",
|
mode="hearthkeeper",
|
||||||
)
|
)
|
||||||
|
session_info["last_hearthkeeper_prompt_at"] = (
|
||||||
|
datetime.utcnow() - self.hearthkeeper_prompt_interval
|
||||||
|
)
|
||||||
|
third_tick = await self._tick_session(session_id)
|
||||||
|
final_count = await self._count_response_actions(
|
||||||
|
session_id=session_id,
|
||||||
|
mode="hearthkeeper",
|
||||||
|
)
|
||||||
prompts_created = after_count - before_count
|
prompts_created = after_count - before_count
|
||||||
|
prompts_created_after_interval = final_count - before_count
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"passed": (
|
"passed": (
|
||||||
prompts_created == 1
|
prompts_created == 1
|
||||||
and first_tick is not None
|
and first_tick is not None
|
||||||
and second_tick is None
|
and second_tick is None
|
||||||
|
and third_tick is not None
|
||||||
|
and prompts_created_after_interval == 2
|
||||||
),
|
),
|
||||||
"session_id": session_id,
|
"session_id": session_id,
|
||||||
"inactive_minutes": inactive_minutes,
|
"inactive_minutes": inactive_minutes,
|
||||||
"prompts_created": prompts_created,
|
"prompts_created": prompts_created,
|
||||||
|
"prompts_created_after_interval": prompts_created_after_interval,
|
||||||
"first_tick": first_tick,
|
"first_tick": first_tick,
|
||||||
"second_tick": second_tick,
|
"second_tick": second_tick,
|
||||||
|
"third_tick_after_interval": third_tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _count_response_actions(self, session_id: str, mode: str) -> int:
|
async def _count_response_actions(self, session_id: str, mode: str) -> int:
|
||||||
@@ -323,6 +342,9 @@ class AgentOrchestrator:
|
|||||||
"""Get background loop configuration and current session count."""
|
"""Get background loop configuration and current session count."""
|
||||||
return {
|
return {
|
||||||
"interval_seconds": self.loop_interval_seconds,
|
"interval_seconds": self.loop_interval_seconds,
|
||||||
|
"hearthkeeper_prompt_interval_minutes": int(
|
||||||
|
self.hearthkeeper_prompt_interval.total_seconds() / 60
|
||||||
|
),
|
||||||
"active_session_count": len(self.active_sessions),
|
"active_session_count": len(self.active_sessions),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +366,7 @@ class AgentOrchestrator:
|
|||||||
recent_messages = []
|
recent_messages = []
|
||||||
async for db_session in get_session():
|
async for db_session in get_session():
|
||||||
repo = Repository(db_session)
|
repo = Repository(db_session)
|
||||||
recent_messages = await repo.get_messages_since(
|
recent_messages = await repo.get_human_messages_since(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
since=datetime.utcnow() - timedelta(minutes=1),
|
since=datetime.utcnow() - timedelta(minutes=1),
|
||||||
)
|
)
|
||||||
@@ -362,7 +384,13 @@ class AgentOrchestrator:
|
|||||||
|
|
||||||
last_activity_at = self.chat_activity.last_activity_at(session_id)
|
last_activity_at = self.chat_activity.last_activity_at(session_id)
|
||||||
last_prompt_at = session_info.get("last_hearthkeeper_prompt_at")
|
last_prompt_at = session_info.get("last_hearthkeeper_prompt_at")
|
||||||
if last_prompt_at and last_activity_at and last_prompt_at >= last_activity_at:
|
if last_activity_at and last_prompt_at and last_activity_at > last_prompt_at:
|
||||||
|
session_info["last_hearthkeeper_prompt_at"] = None
|
||||||
|
last_prompt_at = None
|
||||||
|
if (
|
||||||
|
last_prompt_at
|
||||||
|
and datetime.utcnow() - last_prompt_at < self.hearthkeeper_prompt_interval
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
# Agent loop
|
# Agent loop
|
||||||
AGENT_LOOP_INTERVAL_SECONDS: float = 60.0
|
AGENT_LOOP_INTERVAL_SECONDS: float = 60.0
|
||||||
|
HEARTHKEEPER_PROMPT_INTERVAL_MINUTES: int = 15
|
||||||
|
|
||||||
# Export
|
# Export
|
||||||
EXPORT_PATH: str = "exports"
|
EXPORT_PATH: str = "exports"
|
||||||
|
|||||||
@@ -105,6 +105,22 @@ class Repository:
|
|||||||
result = await self.session.execute(stmt)
|
result = await self.session.execute(stmt)
|
||||||
return list(result.scalars().all())
|
return list(result.scalars().all())
|
||||||
|
|
||||||
|
async def get_recent_human_messages(
|
||||||
|
self, session_id: str, limit: int = 50
|
||||||
|
) -> list[ChatMessage]:
|
||||||
|
"""Get recent non-bot chat messages from a session."""
|
||||||
|
stmt = (
|
||||||
|
select(ChatMessage)
|
||||||
|
.where(
|
||||||
|
ChatMessage.session_id == session_id,
|
||||||
|
ChatMessage.is_bot.is_(False),
|
||||||
|
)
|
||||||
|
.order_by(ChatMessage.timestamp.desc())
|
||||||
|
.limit(limit)
|
||||||
|
)
|
||||||
|
result = await self.session.execute(stmt)
|
||||||
|
return list(result.scalars().all())
|
||||||
|
|
||||||
async def count_messages(self, session_id: str) -> int:
|
async def count_messages(self, session_id: str) -> int:
|
||||||
"""Count chat messages stored for a session."""
|
"""Count chat messages stored for a session."""
|
||||||
stmt = select(func.count()).select_from(ChatMessage).where(
|
stmt = select(func.count()).select_from(ChatMessage).where(
|
||||||
@@ -128,6 +144,22 @@ class Repository:
|
|||||||
result = await self.session.execute(stmt)
|
result = await self.session.execute(stmt)
|
||||||
return list(result.scalars().all())
|
return list(result.scalars().all())
|
||||||
|
|
||||||
|
async def get_human_messages_since(
|
||||||
|
self, session_id: str, since: datetime
|
||||||
|
) -> list[ChatMessage]:
|
||||||
|
"""Get non-bot messages recorded since a specific timestamp."""
|
||||||
|
stmt = (
|
||||||
|
select(ChatMessage)
|
||||||
|
.where(
|
||||||
|
ChatMessage.session_id == session_id,
|
||||||
|
ChatMessage.is_bot.is_(False),
|
||||||
|
ChatMessage.timestamp >= since,
|
||||||
|
)
|
||||||
|
.order_by(ChatMessage.timestamp.desc())
|
||||||
|
)
|
||||||
|
result = await self.session.execute(stmt)
|
||||||
|
return list(result.scalars().all())
|
||||||
|
|
||||||
# Agent Action operations
|
# Agent Action operations
|
||||||
|
|
||||||
async def record_action(
|
async def record_action(
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ services:
|
|||||||
LLM_API_KEY: ${LLM_API_KEY:-}
|
LLM_API_KEY: ${LLM_API_KEY:-}
|
||||||
LLM_MODEL: ${LLM_MODEL:-gpt-3.5-turbo}
|
LLM_MODEL: ${LLM_MODEL:-gpt-3.5-turbo}
|
||||||
AGENT_LOOP_INTERVAL_SECONDS: ${AGENT_LOOP_INTERVAL_SECONDS:-60}
|
AGENT_LOOP_INTERVAL_SECONDS: ${AGENT_LOOP_INTERVAL_SECONDS:-60}
|
||||||
|
HEARTHKEEPER_PROMPT_INTERVAL_MINUTES: ${HEARTHKEEPER_PROMPT_INTERVAL_MINUTES:-15}
|
||||||
EXPORT_PATH: /app/exports
|
EXPORT_PATH: /app/exports
|
||||||
volumes:
|
volumes:
|
||||||
- ./exports:/app/exports
|
- ./exports:/app/exports
|
||||||
|
|||||||
Reference in New Issue
Block a user