From f1a5f1c683b19110c1548a052e4cc8ce23340bb5 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Thu, 30 Apr 2026 00:59:58 +0200 Subject: [PATCH] Add multi_agent_chat routing tools and supervisor routing composition. --- .../multi_agent_chat/routing/__init__.py | 11 +++++ .../routing/from_domain_agents.py | 45 +++++++++++++++++++ .../routing/supervisor_routing.py | 27 +++++++++++ 3 files changed, 83 insertions(+) create mode 100644 surfsense_backend/app/agents/multi_agent_chat/routing/__init__.py create mode 100644 surfsense_backend/app/agents/multi_agent_chat/routing/from_domain_agents.py create mode 100644 surfsense_backend/app/agents/multi_agent_chat/routing/supervisor_routing.py diff --git a/surfsense_backend/app/agents/multi_agent_chat/routing/__init__.py b/surfsense_backend/app/agents/multi_agent_chat/routing/__init__.py new file mode 100644 index 000000000..783d1fad2 --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_chat/routing/__init__.py @@ -0,0 +1,11 @@ +"""Supervisor routing: domain-agent wrappers and composed routing tool lists.""" + +from app.agents.multi_agent_chat.routing.from_domain_agents import routing_tools_from_domain_agents +from app.agents.multi_agent_chat.routing.supervisor_routing import build_supervisor_routing_tools +from app.agents.multi_agent_chat.shared.invoke_output import extract_last_assistant_text + +__all__ = [ + "build_supervisor_routing_tools", + "extract_last_assistant_text", + "routing_tools_from_domain_agents", +] diff --git a/surfsense_backend/app/agents/multi_agent_chat/routing/from_domain_agents.py b/surfsense_backend/app/agents/multi_agent_chat/routing/from_domain_agents.py new file mode 100644 index 000000000..92ca14150 --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_chat/routing/from_domain_agents.py @@ -0,0 +1,45 @@ +"""LangChain ``@tool`` wrappers that invoke compiled domain-agent graphs (supervisor-facing only).""" + +from __future__ import annotations + +from typing import Any + +from langchain_core.tools import BaseTool, tool + +from app.agents.multi_agent_chat.shared.invoke_output import extract_last_assistant_text + + +def routing_tools_from_domain_agents( + *, + gmail_domain_agent: Any, + calendar_domain_agent: Any, +) -> list[BaseTool]: + """Build ``gmail`` / ``calendar`` tools that invoke the given graphs (factory, not import-time exports).""" + + @tool( + "gmail", + description=( + "Route Gmail-related work to the Gmail sub-agent. " + "Pass a clear natural-language task." + ), + ) + def call_gmail_agent(task: str) -> str: + result = gmail_domain_agent.invoke( + {"messages": [{"role": "user", "content": task}]} + ) + return extract_last_assistant_text(result) + + @tool( + "calendar", + description=( + "Route Google Calendar work to the Calendar sub-agent. " + "Pass a clear natural-language task." + ), + ) + def call_calendar_agent(task: str) -> str: + result = calendar_domain_agent.invoke( + {"messages": [{"role": "user", "content": task}]} + ) + return extract_last_assistant_text(result) + + return [call_gmail_agent, call_calendar_agent] diff --git a/surfsense_backend/app/agents/multi_agent_chat/routing/supervisor_routing.py b/surfsense_backend/app/agents/multi_agent_chat/routing/supervisor_routing.py new file mode 100644 index 000000000..a69528b8e --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_chat/routing/supervisor_routing.py @@ -0,0 +1,27 @@ +"""Compose domain agents + connector tool lists into supervisor ``gmail`` / ``calendar`` routing tools.""" + +from __future__ import annotations + +from collections.abc import Sequence + +from langchain_core.language_models import BaseChatModel +from langchain_core.tools import BaseTool + +from app.agents.multi_agent_chat.calendar import build_calendar_domain_agent +from app.agents.multi_agent_chat.gmail import build_gmail_domain_agent +from app.agents.multi_agent_chat.routing.from_domain_agents import routing_tools_from_domain_agents + + +def build_supervisor_routing_tools( + llm: BaseChatModel, + *, + gmail_tools: Sequence[BaseTool] | None = None, + calendar_tools: Sequence[BaseTool] | None = None, +) -> list[BaseTool]: + """Domain agents (with their connector tools) → ``gmail`` / ``calendar`` routing tools.""" + gmail_domain_agent = build_gmail_domain_agent(llm, list(gmail_tools or [])) + calendar_domain_agent = build_calendar_domain_agent(llm, list(calendar_tools or [])) + return routing_tools_from_domain_agents( + gmail_domain_agent=gmail_domain_agent, + calendar_domain_agent=calendar_domain_agent, + )