All hardcoded "Inara"/"Scott" strings replaced with settings.agent_name and settings.user_name, read from .env at startup: - config.py: AGENT_NAME and USER_NAME settings (defaults: Inara / Scott) - llm_client.py: conversation labels in prompt builder - session_logger.py: **Name:** labels in session log markdown - memory_distiller.py: distillation system prompts (mid + long) - routers/nextcloud_talk.py: @mention prefix strip - routers/google_chat.py: greeting message Second instance scaffolding: - holly/: identity directory with placeholder files (USER_NAME=Holly, AGENT_NAME to be chosen by Holly) - cortex/.env.holly: config for Holly's instance on port 8001 - cortex-holly.service: systemd unit for the second instance No behavioural change to the Inara/Scott instance — defaults unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
import asyncio
|
|
import logging
|
|
from fastapi import APIRouter, Request, Response
|
|
from context_loader import load_context
|
|
from llm_client import complete
|
|
from session_logger import log_turn
|
|
from session_store import load as load_session, save as save_session
|
|
from config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(prefix="/channels/google-chat")
|
|
|
|
|
|
@router.post("")
|
|
async def receive(request: Request):
|
|
body = await request.json()
|
|
event_type = body.get("type")
|
|
|
|
if event_type == "ADDED_TO_SPACE":
|
|
space_type = body.get("space", {}).get("type", "")
|
|
greeting = f"✨ Hello! I'm {settings.agent_name}. Send me a message and I'll do my best to help."
|
|
if space_type == "DM":
|
|
greeting = f"✨ Hello! I'm {settings.agent_name}. What can I help you with?"
|
|
return {"text": greeting}
|
|
|
|
if event_type == "REMOVED_FROM_SPACE":
|
|
return Response(status_code=200)
|
|
|
|
if event_type != "MESSAGE":
|
|
return Response(status_code=200)
|
|
|
|
message = body.get("message", {})
|
|
sender = message.get("sender", {})
|
|
space = body.get("space", {})
|
|
|
|
# argumentText strips the @BotName mention in Spaces; fall back to full text in DMs
|
|
user_text = (message.get("argumentText") or message.get("text", "")).strip()
|
|
if not user_text:
|
|
return Response(status_code=200)
|
|
|
|
sender_display = sender.get("displayName", "User")
|
|
space_name = space.get("name", "unknown")
|
|
space_type = space.get("type", "")
|
|
|
|
# Session keyed per space — one conversation per DM or Space
|
|
session_id = "gc_" + space_name.replace("/", "_")
|
|
|
|
logger.info("Google Chat message from %s in %s (%s)", sender_display, space_name, space_type)
|
|
|
|
system_prompt = load_context(settings.default_tier)
|
|
history = load_session(session_id)
|
|
history.append({"role": "user", "content": user_text})
|
|
|
|
try:
|
|
response_text, actual_backend = await asyncio.wait_for(
|
|
complete(
|
|
system_prompt=system_prompt,
|
|
messages=history,
|
|
model=settings.google_chat_backend,
|
|
),
|
|
timeout=settings.google_chat_timeout,
|
|
)
|
|
except asyncio.TimeoutError:
|
|
logger.warning("Google Chat request timed out for session %s", session_id)
|
|
return {"text": "⏳ Still thinking — this is taking a bit longer than usual. Try again in a moment."}
|
|
except Exception as e:
|
|
logger.error("Google Chat error for session %s: %s", session_id, e)
|
|
return {"text": f"⚠️ Something went wrong on my end. Try again shortly."}
|
|
|
|
history.append({"role": "assistant", "content": response_text})
|
|
save_session(session_id, history)
|
|
log_turn(session_id, user_text, response_text)
|
|
|
|
return {"text": response_text}
|