Skip to content

Commit 83ee580

Browse files
authored
Merge pull request #1352 from MODSetter/dev
feat: Add multi-agent orchestration
2 parents 9576d1f + 499c6be commit 83ee580

345 files changed

Lines changed: 21460 additions & 364 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.22
1+
0.0.23

surfsense_backend/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ LANGSMITH_PROJECT=surfsense
282282
# =============================================================================
283283
# OPTIONAL: New-chat agent feature flags
284284
# =============================================================================
285+
# Multi-agent orchestrator switch for authenticated chat streaming.
286+
# MULTI_AGENT_CHAT_ENABLED=false
287+
285288
# Master kill-switch — when true, every flag below is forced OFF.
286289
# SURFSENSE_DISABLE_NEW_AGENT_STACK=false
287290

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Deepagents-backed routes: ``subagents/``; main-agent graph under ``main_agent/`` (SRP subpackages)."""
2+
3+
from __future__ import annotations
4+
5+
from .main_agent import create_multi_agent_chat_deep_agent
6+
7+
__all__ = ["create_multi_agent_chat_deep_agent"]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Connector-type to subagent name; subagent name to availability tokens for build_subagents."""
2+
3+
from __future__ import annotations
4+
5+
CONNECTOR_TYPE_TO_CONNECTOR_AGENT_MAPS: dict[str, str] = {
6+
"GOOGLE_GMAIL_CONNECTOR": "gmail",
7+
"COMPOSIO_GMAIL_CONNECTOR": "gmail",
8+
"GOOGLE_CALENDAR_CONNECTOR": "calendar",
9+
"COMPOSIO_GOOGLE_CALENDAR_CONNECTOR": "calendar",
10+
"DISCORD_CONNECTOR": "discord",
11+
"TEAMS_CONNECTOR": "teams",
12+
"LUMA_CONNECTOR": "luma",
13+
"LINEAR_CONNECTOR": "linear",
14+
"JIRA_CONNECTOR": "jira",
15+
"CLICKUP_CONNECTOR": "clickup",
16+
"SLACK_CONNECTOR": "slack",
17+
"AIRTABLE_CONNECTOR": "airtable",
18+
"NOTION_CONNECTOR": "notion",
19+
"CONFLUENCE_CONNECTOR": "confluence",
20+
"GOOGLE_DRIVE_CONNECTOR": "google_drive",
21+
"COMPOSIO_GOOGLE_DRIVE_CONNECTOR": "google_drive",
22+
"DROPBOX_CONNECTOR": "dropbox",
23+
"ONEDRIVE_CONNECTOR": "onedrive",
24+
}
25+
26+
SUBAGENT_TO_REQUIRED_CONNECTOR_MAP: dict[str, frozenset[str]] = {
27+
"deliverables": frozenset(),
28+
"airtable": frozenset({"AIRTABLE_CONNECTOR"}),
29+
"calendar": frozenset({"GOOGLE_CALENDAR_CONNECTOR"}),
30+
"clickup": frozenset({"CLICKUP_CONNECTOR"}),
31+
"confluence": frozenset({"CONFLUENCE_CONNECTOR"}),
32+
"discord": frozenset({"DISCORD_CONNECTOR"}),
33+
"dropbox": frozenset({"DROPBOX_FILE"}),
34+
"gmail": frozenset({"GOOGLE_GMAIL_CONNECTOR"}),
35+
"google_drive": frozenset({"GOOGLE_DRIVE_FILE"}),
36+
"jira": frozenset({"JIRA_CONNECTOR"}),
37+
"linear": frozenset({"LINEAR_CONNECTOR"}),
38+
"luma": frozenset({"LUMA_CONNECTOR"}),
39+
"notion": frozenset({"NOTION_CONNECTOR"}),
40+
"onedrive": frozenset({"ONEDRIVE_FILE"}),
41+
"slack": frozenset({"SLACK_CONNECTOR"}),
42+
"teams": frozenset({"TEAMS_CONNECTOR"}),
43+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Main-agent deep agent: ``runtime/`` (factory), ``graph/`` (compile), ``system_prompt/``, etc."""
2+
3+
from __future__ import annotations
4+
5+
from .runtime import create_multi_agent_chat_deep_agent
6+
7+
__all__ = ["create_multi_agent_chat_deep_agent"]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Tool-name pruning for context editing (exclude lists without dropping protected tools)."""
2+
3+
from __future__ import annotations
4+
5+
from .prune_tool_names import PRUNE_PROTECTED_TOOL_NAMES, safe_exclude_tools
6+
7+
__all__ = ["PRUNE_PROTECTED_TOOL_NAMES", "safe_exclude_tools"]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Tool names excluded from context-editing prune when bound."""
2+
3+
from __future__ import annotations
4+
5+
from collections.abc import Sequence
6+
7+
from langchain_core.tools import BaseTool
8+
9+
PRUNE_PROTECTED_TOOL_NAMES: frozenset[str] = frozenset(
10+
{
11+
"generate_report",
12+
"generate_resume",
13+
"generate_podcast",
14+
"generate_video_presentation",
15+
"generate_image",
16+
"read_email",
17+
"search_emails",
18+
"invalid",
19+
},
20+
)
21+
22+
23+
def safe_exclude_tools(tools: Sequence[BaseTool]) -> tuple[str, ...]:
24+
"""Names from ``PRUNE_PROTECTED_TOOL_NAMES`` that appear in ``tools``."""
25+
enabled = {t.name for t in tools}
26+
return tuple(n for n in PRUNE_PROTECTED_TOOL_NAMES if n in enabled)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Sync compile of the main-agent LangGraph graph (middleware + ``create_agent``)."""
2+
3+
from __future__ import annotations
4+
5+
from .compile_graph_sync import build_compiled_agent_graph_sync
6+
7+
__all__ = ["build_compiled_agent_graph_sync"]
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Synchronous graph compile (middleware + ``create_agent``)."""
2+
3+
from __future__ import annotations
4+
5+
from collections.abc import Sequence
6+
from typing import Any
7+
8+
from deepagents import __version__ as deepagents_version
9+
from langchain.agents import create_agent
10+
from langchain_core.language_models import BaseChatModel
11+
from langchain_core.tools import BaseTool
12+
from langgraph.types import Checkpointer
13+
14+
from app.agents.multi_agent_chat.middleware import (
15+
build_main_agent_deepagent_middleware,
16+
)
17+
from app.agents.multi_agent_chat.subagents.shared.permissions import (
18+
ToolsPermissions,
19+
)
20+
from app.agents.new_chat.context import SurfSenseContextSchema
21+
from app.agents.new_chat.feature_flags import AgentFeatureFlags
22+
from app.agents.new_chat.filesystem_selection import FilesystemMode
23+
from app.db import ChatVisibility
24+
25+
26+
def build_compiled_agent_graph_sync(
27+
*,
28+
llm: BaseChatModel,
29+
tools: Sequence[BaseTool],
30+
final_system_prompt: str,
31+
backend_resolver: Any,
32+
filesystem_mode: FilesystemMode,
33+
search_space_id: int,
34+
user_id: str | None,
35+
thread_id: int | None,
36+
visibility: ChatVisibility,
37+
anon_session_id: str | None,
38+
available_connectors: list[str] | None,
39+
available_document_types: list[str] | None,
40+
mentioned_document_ids: list[int] | None,
41+
max_input_tokens: int | None,
42+
flags: AgentFeatureFlags,
43+
checkpointer: Checkpointer,
44+
subagent_dependencies: dict[str, Any],
45+
mcp_tools_by_agent: dict[str, ToolsPermissions] | None = None,
46+
disabled_tools: list[str] | None = None,
47+
):
48+
"""Sync compile: middleware + ``create_agent`` (run via ``asyncio.to_thread``)."""
49+
main_agent_middleware = build_main_agent_deepagent_middleware(
50+
llm=llm,
51+
tools=tools,
52+
backend_resolver=backend_resolver,
53+
filesystem_mode=filesystem_mode,
54+
search_space_id=search_space_id,
55+
user_id=user_id,
56+
thread_id=thread_id,
57+
visibility=visibility,
58+
anon_session_id=anon_session_id,
59+
available_connectors=available_connectors,
60+
available_document_types=available_document_types,
61+
mentioned_document_ids=mentioned_document_ids,
62+
max_input_tokens=max_input_tokens,
63+
flags=flags,
64+
subagent_dependencies=subagent_dependencies,
65+
checkpointer=checkpointer,
66+
mcp_tools_by_agent=mcp_tools_by_agent,
67+
disabled_tools=disabled_tools,
68+
)
69+
70+
agent = create_agent(
71+
llm,
72+
system_prompt=final_system_prompt,
73+
tools=list(tools),
74+
middleware=main_agent_middleware,
75+
context_schema=SurfSenseContextSchema,
76+
checkpointer=checkpointer,
77+
)
78+
return agent.with_config(
79+
{
80+
"recursion_limit": 10_000,
81+
"metadata": {
82+
"ls_integration": "deepagents",
83+
"versions": {"deepagents": deepagents_version},
84+
},
85+
}
86+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Async factory: wiring tools, prompts, MCP buckets, then graph compile."""
2+
3+
from __future__ import annotations
4+
5+
from .factory import create_multi_agent_chat_deep_agent
6+
7+
__all__ = ["create_multi_agent_chat_deep_agent"]

0 commit comments

Comments
 (0)