From 5f84d46f96d2a5610eeb3ce95fcd82c53e9c2c66 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Fri, 1 May 2026 20:30:20 +0200 Subject: [PATCH] Add subagent spec packing and shared package exports. --- .../subagents/shared/__init__.py | 25 ++++++++++ .../subagents/shared/subagent_builder.py | 47 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/__init__.py create mode 100644 surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/subagent_builder.py diff --git a/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/__init__.py b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/__init__.py new file mode 100644 index 000000000..0dbccf126 --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/__init__.py @@ -0,0 +1,25 @@ +"""Cross-slice helpers for route subagents.""" + +from __future__ import annotations + +from app.agents.multi_agent_with_deepagents.subagents.shared.md_file_reader import ( + read_md_file, +) +from app.agents.multi_agent_with_deepagents.subagents.shared.permissions import ( + ToolPermissionItem, + ToolsPermissions, + merge_tools_permissions, + tool_permission_row, +) +from app.agents.multi_agent_with_deepagents.subagents.shared.subagent_builder import ( + pack_subagent, +) + +__all__ = [ + "ToolPermissionItem", + "ToolsPermissions", + "merge_tools_permissions", + "pack_subagent", + "read_md_file", + "tool_permission_row", +] diff --git a/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/subagent_builder.py b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/subagent_builder.py new file mode 100644 index 000000000..b6614afa9 --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/subagent_builder.py @@ -0,0 +1,47 @@ +"""Build delegated sub-agent specs from route-local pieces.""" + +from __future__ import annotations + +from collections.abc import Sequence +from typing import Any, cast + +from deepagents import SubAgent +from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware +from langchain_core.language_models import BaseChatModel +from langchain_core.tools import BaseTool + +from app.agents.new_chat.middleware import DedupHITLToolCallsMiddleware + + +def pack_subagent( + *, + name: str, + description: str, + system_prompt: str, + tools: list[BaseTool], + model: BaseChatModel | None = None, + extra_middleware: Sequence[Any] | None = None, + interrupt_on: dict[str, bool] | None = None, +) -> SubAgent: + """Pack the route-local pieces passed in into one sub-agent spec.""" + if not system_prompt.strip(): + msg = f"Subagent {name!r}: system_prompt is empty" + raise ValueError(msg) + + middleware: list[Any] = [ + *(extra_middleware or []), + PatchToolCallsMiddleware(), + DedupHITLToolCallsMiddleware(agent_tools=tools), + ] + spec: dict[str, Any] = { + "name": name, + "description": description, + "system_prompt": system_prompt, + "tools": tools, + "middleware": middleware, + } + if model is not None: + spec["model"] = model + if interrupt_on: + spec["interrupt_on"] = interrupt_on + return cast(SubAgent, spec)