main.pyBrutTélécharger
"""Google Chat (Workspace add-on, HTTP) -> agent on Agent Runtime.

Chat POSTs an event here; we forward the text to the agent and reply
synchronously with the agent's answer.
Auth: this Cloud Run service is private; only the Workspace add-ons service
account has roles/run.invoker, so Cloud Run itself rejects anyone else.
"""
import os

import agentplatform
from fastapi import FastAPI, Request

AGENT_NAME = os.environ["AGENT_NAME"]  # projects/.../locations/.../reasoningEngines/ID
_, PROJECT, _, LOCATION, *_ = AGENT_NAME.split("/")

agent = agentplatform.Client(project=PROJECT, location=LOCATION).runtimes.get(name=AGENT_NAME)
app = FastAPI()


def reply(text: str) -> dict:
    return {"hostAppDataAction": {"chatDataAction": {"createMessageAction": {"message": {"text": text}}}}}


async def session_for(user_id: str) -> str:
    # Stateless: reuse the user's most recent Agent Runtime session, else create one.
    # ponytail: one conversation per user across all spaces; key on space+user if you need separation.
    sessions = (await agent.async_list_sessions(user_id=user_id)).get("sessions", [])
    if sessions:
        return max(sessions, key=lambda s: s.get("lastUpdateTime", s.get("last_update_time", 0)))["id"]
    return (await agent.async_create_session(user_id=user_id))["id"]


@app.post("/")
async def chat_event(request: Request) -> dict:
    chat = (await request.json()).get("chat", {})

    if "addedToSpacePayload" in chat:
        return reply("Hi! Ask me to convert currencies, e.g. *100 USD to EUR*.")

    message = chat.get("messagePayload", {}).get("message")
    if not message:
        return {}  # other events (removed from space, etc.): nothing to say

    text = (message.get("argumentText") or message.get("text") or "").strip()  # argumentText drops the @mention
    user_id = message["sender"]["name"]  # "users/123..." — stable per person
    session_id = await session_for(user_id)

    answer = []
    async for event in agent.async_stream_query(user_id=user_id, session_id=session_id, message=text):
        answer += [p["text"] for p in (event.get("content") or {}).get("parts", []) if p.get("text")]
    return reply(answer[-1] if answer else "Sorry, I have no answer for that.")