diff --git a/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/md_file_reader.py b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/md_file_reader.py new file mode 100644 index 000000000..2fce413a6 --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/md_file_reader.py @@ -0,0 +1,14 @@ +"""Load markdown files shipped alongside a route package.""" + +from __future__ import annotations + +from importlib import resources + + +def read_md_file(package: str, stem: str) -> str: + """Load ``{stem}.md`` from ``package`` via importlib resources, or return empty.""" + ref = resources.files(package).joinpath(f"{stem}.md") + if not ref.is_file(): + return "" + text = ref.read_text(encoding="utf-8") + return text.rstrip("\n") diff --git a/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/permissions.py b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/permissions.py new file mode 100644 index 000000000..20a9433e7 --- /dev/null +++ b/surfsense_backend/app/agents/multi_agent_with_deepagents/subagents/shared/permissions.py @@ -0,0 +1,39 @@ +"""Typed tool-permission rows: allow vs ask (``name`` + optional ``tool``).""" + +from __future__ import annotations + +from typing import NotRequired, TypedDict + +from langchain_core.tools import BaseTool + + +class ToolPermissionItem(TypedDict): + """``name`` is always set; ``tool`` is present when a bound tool exists.""" + + name: str + tool: NotRequired[BaseTool] + + +class ToolsPermissions(TypedDict): + """Same shape for native factories and MCP name-only policy rows.""" + + allow: list[ToolPermissionItem] + ask: list[ToolPermissionItem] + + +def tool_permission_row(tool: BaseTool) -> ToolPermissionItem: + """Build one allow/ask row for a loaded tool.""" + return {"name": getattr(tool, "name", "") or "", "tool": tool} + + +def merge_tools_permissions( + base: ToolsPermissions, + extra: ToolsPermissions | None, +) -> ToolsPermissions: + """Concatenate allow/ask lists (e.g. native factory + MCP bucket) before building HITL maps.""" + if not extra: + return base + return { + "allow": [*base["allow"], *extra["allow"]], + "ask": [*base["ask"], *extra["ask"]], + }