mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-17 18:35:19 +02:00
multi_agent_chat/connectors: every route declares its own RULESET + flat load_tools()
This commit is contained in:
parent
d45dfbfbd6
commit
3bb90124d2
30 changed files with 588 additions and 800 deletions
|
|
@ -1,29 +1,22 @@
|
||||||
"""`airtable` route: ``SubAgent`` spec for deepagents."""
|
"""``airtable`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools come exclusively from MCP. The connector's own approval ruleset is
|
||||||
|
declared in :data:`tools.index.RULESET`; the orchestrator layers it into
|
||||||
|
a per-subagent :class:`PermissionMiddleware`.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET
|
||||||
|
|
||||||
NAME = "airtable"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,20 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
description = (
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
read_md_file(__package__, "description").strip()
|
||||||
tools = [
|
or "Handles airtable tasks for this workspace."
|
||||||
row["tool"]
|
)
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles airtable tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=list(mcp_tools or []),
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,21 @@
|
||||||
|
"""``airtable`` permission ruleset (rules over MCP tool names)."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from app.agents.new_chat.permissions import Rule, Ruleset
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
NAME = "airtable"
|
||||||
ToolsPermissions,
|
|
||||||
|
RULESET = Ruleset(
|
||||||
|
origin=NAME,
|
||||||
|
rules=[
|
||||||
|
Rule(permission="list_bases", pattern="*", action="allow"),
|
||||||
|
Rule(permission="search_bases", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_tables_for_base", pattern="*", action="allow"),
|
||||||
|
Rule(permission="get_table_schema", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_records_for_table", pattern="*", action="allow"),
|
||||||
|
Rule(permission="search_records", pattern="*", action="allow"),
|
||||||
|
Rule(permission="create_records_for_table", pattern="*", action="ask"),
|
||||||
|
Rule(permission="update_records_for_table", pattern="*", action="ask"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
|
||||||
) -> ToolsPermissions:
|
|
||||||
_ = {**(dependencies or {}), **kwargs}
|
|
||||||
return {
|
|
||||||
"allow": [
|
|
||||||
{"name": "list_bases"},
|
|
||||||
{"name": "search_bases"},
|
|
||||||
{"name": "list_tables_for_base"},
|
|
||||||
{"name": "get_table_schema"},
|
|
||||||
{"name": "list_records_for_table"},
|
|
||||||
{"name": "search_records"},
|
|
||||||
],
|
|
||||||
"ask": [
|
|
||||||
{"name": "create_records_for_table"},
|
|
||||||
{"name": "update_records_for_table"},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`calendar` route: ``SubAgent`` spec for deepagents."""
|
"""``calendar`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity with MCP-backed connectors.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "calendar"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles calendar tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles calendar tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,39 @@
|
||||||
|
"""``calendar`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies, so the
|
||||||
|
ruleset just falls through to the SurfSense allow-by-default rules.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_event import create_create_calendar_event_tool
|
from .create_event import create_create_calendar_event_tool
|
||||||
from .delete_event import create_delete_calendar_event_tool
|
from .delete_event import create_delete_calendar_event_tool
|
||||||
from .search_events import create_search_calendar_events_tool
|
from .search_events import create_search_calendar_events_tool
|
||||||
from .update_event import create_update_calendar_event_tool
|
from .update_event import create_update_calendar_event_tool
|
||||||
|
|
||||||
|
NAME = "calendar"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
resolved_dependencies = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
session_dependencies = {
|
common = {
|
||||||
"db_session": resolved_dependencies["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": resolved_dependencies["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": resolved_dependencies["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
|
||||||
search = create_search_calendar_events_tool(**session_dependencies)
|
|
||||||
create = create_create_calendar_event_tool(**session_dependencies)
|
|
||||||
update = create_update_calendar_event_tool(**session_dependencies)
|
|
||||||
delete = create_delete_calendar_event_tool(**session_dependencies)
|
|
||||||
return {
|
|
||||||
"allow": [self_gated_tool_permission_row(search)],
|
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(create),
|
|
||||||
self_gated_tool_permission_row(update),
|
|
||||||
self_gated_tool_permission_row(delete),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
return [
|
||||||
|
create_search_calendar_events_tool(**common),
|
||||||
|
create_create_calendar_event_tool(**common),
|
||||||
|
create_update_calendar_event_tool(**common),
|
||||||
|
create_delete_calendar_event_tool(**common),
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`clickup` route: ``SubAgent`` spec for deepagents."""
|
"""``clickup`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools come exclusively from MCP. The connector's own approval ruleset is
|
||||||
|
declared in :data:`tools.index.RULESET`; the orchestrator layers it into
|
||||||
|
a per-subagent :class:`PermissionMiddleware`.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET
|
||||||
|
|
||||||
NAME = "clickup"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,20 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
description = (
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
read_md_file(__package__, "description").strip()
|
||||||
tools = [
|
or "Handles clickup tasks for this workspace."
|
||||||
row["tool"]
|
)
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles clickup tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=list(mcp_tools or []),
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,20 @@
|
||||||
|
"""``clickup`` permission ruleset (rules over MCP tool names)."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from app.agents.new_chat.permissions import Rule, Ruleset
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
NAME = "clickup"
|
||||||
ToolsPermissions,
|
|
||||||
|
RULESET = Ruleset(
|
||||||
|
origin=NAME,
|
||||||
|
rules=[
|
||||||
|
Rule(permission="clickup_search", pattern="*", action="allow"),
|
||||||
|
Rule(permission="clickup_get_task", pattern="*", action="allow"),
|
||||||
|
Rule(permission="clickup_get_workspace_hierarchy", pattern="*", action="allow"),
|
||||||
|
Rule(permission="clickup_get_list", pattern="*", action="allow"),
|
||||||
|
Rule(permission="clickup_find_member_by_name", pattern="*", action="allow"),
|
||||||
|
Rule(permission="clickup_create_task", pattern="*", action="ask"),
|
||||||
|
Rule(permission="clickup_update_task", pattern="*", action="ask"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
|
||||||
) -> ToolsPermissions:
|
|
||||||
_ = {**(dependencies or {}), **kwargs}
|
|
||||||
return {
|
|
||||||
"allow": [
|
|
||||||
{"name": "clickup_search"},
|
|
||||||
{"name": "clickup_get_task"},
|
|
||||||
{"name": "clickup_get_workspace_hierarchy"},
|
|
||||||
{"name": "clickup_get_list"},
|
|
||||||
{"name": "clickup_find_member_by_name"},
|
|
||||||
],
|
|
||||||
"ask": [
|
|
||||||
{"name": "clickup_create_task"},
|
|
||||||
{"name": "clickup_update_task"},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`confluence` route: ``SubAgent`` spec for deepagents."""
|
"""``confluence`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "confluence"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles confluence tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles confluence tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,37 @@
|
||||||
|
"""``confluence`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_page import create_create_confluence_page_tool
|
from .create_page import create_create_confluence_page_tool
|
||||||
from .delete_page import create_delete_confluence_page_tool
|
from .delete_page import create_delete_confluence_page_tool
|
||||||
from .update_page import create_update_confluence_page_tool
|
from .update_page import create_update_confluence_page_tool
|
||||||
|
|
||||||
|
NAME = "confluence"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
resolved_dependencies = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
session_dependencies = {
|
common = {
|
||||||
"db_session": resolved_dependencies["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": resolved_dependencies["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": resolved_dependencies["user_id"],
|
"user_id": d["user_id"],
|
||||||
"connector_id": resolved_dependencies.get("connector_id"),
|
"connector_id": d.get("connector_id"),
|
||||||
}
|
|
||||||
create = create_create_confluence_page_tool(**session_dependencies)
|
|
||||||
update = create_update_confluence_page_tool(**session_dependencies)
|
|
||||||
delete = create_delete_confluence_page_tool(**session_dependencies)
|
|
||||||
return {
|
|
||||||
"allow": [],
|
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(create),
|
|
||||||
self_gated_tool_permission_row(update),
|
|
||||||
self_gated_tool_permission_row(delete),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
return [
|
||||||
|
create_create_confluence_page_tool(**common),
|
||||||
|
create_update_confluence_page_tool(**common),
|
||||||
|
create_delete_confluence_page_tool(**common),
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`discord` route: ``SubAgent`` spec for deepagents."""
|
"""``discord`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "discord"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles discord tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles discord tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,36 @@
|
||||||
|
"""``discord`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .list_channels import create_list_discord_channels_tool
|
from .list_channels import create_list_discord_channels_tool
|
||||||
from .read_messages import create_read_discord_messages_tool
|
from .read_messages import create_read_discord_messages_tool
|
||||||
from .send_message import create_send_discord_message_tool
|
from .send_message import create_send_discord_message_tool
|
||||||
|
|
||||||
|
NAME = "discord"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
list_ch = create_list_discord_channels_tool(**common)
|
return [
|
||||||
read_msg = create_read_discord_messages_tool(**common)
|
create_list_discord_channels_tool(**common),
|
||||||
send = create_send_discord_message_tool(**common)
|
create_read_discord_messages_tool(**common),
|
||||||
return {
|
create_send_discord_message_tool(**common),
|
||||||
"allow": [
|
]
|
||||||
self_gated_tool_permission_row(list_ch),
|
|
||||||
self_gated_tool_permission_row(read_msg),
|
|
||||||
],
|
|
||||||
"ask": [self_gated_tool_permission_row(send)],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`dropbox` route: ``SubAgent`` spec for deepagents."""
|
"""``dropbox`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "dropbox"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles dropbox tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles dropbox tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,34 @@
|
||||||
|
"""``dropbox`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_file import create_create_dropbox_file_tool
|
from .create_file import create_create_dropbox_file_tool
|
||||||
from .trash_file import create_delete_dropbox_file_tool
|
from .trash_file import create_delete_dropbox_file_tool
|
||||||
|
|
||||||
|
NAME = "dropbox"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
create = create_create_dropbox_file_tool(**common)
|
return [
|
||||||
delete = create_delete_dropbox_file_tool(**common)
|
create_create_dropbox_file_tool(**common),
|
||||||
return {
|
create_delete_dropbox_file_tool(**common),
|
||||||
"allow": [],
|
]
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(create),
|
|
||||||
self_gated_tool_permission_row(delete),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`gmail` route: ``SubAgent`` spec for deepagents."""
|
"""``gmail`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "gmail"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles gmail tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles gmail tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
|
"""``gmail`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_draft import create_create_gmail_draft_tool
|
from .create_draft import create_create_gmail_draft_tool
|
||||||
from .read_email import create_read_gmail_email_tool
|
from .read_email import create_read_gmail_email_tool
|
||||||
|
|
@ -16,31 +18,25 @@ from .send_email import create_send_gmail_email_tool
|
||||||
from .trash_email import create_trash_gmail_email_tool
|
from .trash_email import create_trash_gmail_email_tool
|
||||||
from .update_draft import create_update_gmail_draft_tool
|
from .update_draft import create_update_gmail_draft_tool
|
||||||
|
|
||||||
|
NAME = "gmail"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
search = create_search_gmail_tool(**common)
|
return [
|
||||||
read = create_read_gmail_email_tool(**common)
|
create_search_gmail_tool(**common),
|
||||||
draft = create_create_gmail_draft_tool(**common)
|
create_read_gmail_email_tool(**common),
|
||||||
send = create_send_gmail_email_tool(**common)
|
create_create_gmail_draft_tool(**common),
|
||||||
trash = create_trash_gmail_email_tool(**common)
|
create_send_gmail_email_tool(**common),
|
||||||
updraft = create_update_gmail_draft_tool(**common)
|
create_trash_gmail_email_tool(**common),
|
||||||
return {
|
create_update_gmail_draft_tool(**common),
|
||||||
"allow": [
|
]
|
||||||
self_gated_tool_permission_row(search),
|
|
||||||
self_gated_tool_permission_row(read),
|
|
||||||
],
|
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(draft),
|
|
||||||
self_gated_tool_permission_row(send),
|
|
||||||
self_gated_tool_permission_row(trash),
|
|
||||||
self_gated_tool_permission_row(updraft),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`google_drive` route: ``SubAgent`` spec for deepagents."""
|
"""``google_drive`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "google_drive"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles google drive tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles google drive tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,34 @@
|
||||||
|
"""``google_drive`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_file import create_create_google_drive_file_tool
|
from .create_file import create_create_google_drive_file_tool
|
||||||
from .trash_file import create_delete_google_drive_file_tool
|
from .trash_file import create_delete_google_drive_file_tool
|
||||||
|
|
||||||
|
NAME = "google_drive"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
create = create_create_google_drive_file_tool(**common)
|
return [
|
||||||
delete = create_delete_google_drive_file_tool(**common)
|
create_create_google_drive_file_tool(**common),
|
||||||
return {
|
create_delete_google_drive_file_tool(**common),
|
||||||
"allow": [],
|
]
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(create),
|
|
||||||
self_gated_tool_permission_row(delete),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`jira` route: ``SubAgent`` spec for deepagents."""
|
"""``jira`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools come exclusively from MCP. The connector's own approval ruleset is
|
||||||
|
declared in :data:`tools.index.RULESET`; the orchestrator layers it into
|
||||||
|
a per-subagent :class:`PermissionMiddleware`.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET
|
||||||
|
|
||||||
NAME = "jira"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,20 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
description = (
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
read_md_file(__package__, "description").strip()
|
||||||
tools = [
|
or "Handles jira tasks for this workspace."
|
||||||
row["tool"]
|
)
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles jira tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=list(mcp_tools or []),
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,24 @@
|
||||||
|
"""``jira`` permission ruleset (rules over MCP tool names)."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from app.agents.new_chat.permissions import Rule, Ruleset
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
NAME = "jira"
|
||||||
ToolsPermissions,
|
|
||||||
|
RULESET = Ruleset(
|
||||||
|
origin=NAME,
|
||||||
|
rules=[
|
||||||
|
Rule(permission="getAccessibleAtlassianResources", pattern="*", action="allow"),
|
||||||
|
Rule(permission="getVisibleJiraProjects", pattern="*", action="allow"),
|
||||||
|
Rule(permission="searchJiraIssuesUsingJql", pattern="*", action="allow"),
|
||||||
|
Rule(permission="getJiraIssue", pattern="*", action="allow"),
|
||||||
|
Rule(permission="getJiraProjectIssueTypesMetadata", pattern="*", action="allow"),
|
||||||
|
Rule(permission="getJiraIssueTypeMetaWithFields", pattern="*", action="allow"),
|
||||||
|
Rule(permission="getTransitionsForJiraIssue", pattern="*", action="allow"),
|
||||||
|
Rule(permission="lookupJiraAccountId", pattern="*", action="allow"),
|
||||||
|
Rule(permission="createJiraIssue", pattern="*", action="ask"),
|
||||||
|
Rule(permission="editJiraIssue", pattern="*", action="ask"),
|
||||||
|
Rule(permission="transitionJiraIssue", pattern="*", action="ask"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
|
||||||
) -> ToolsPermissions:
|
|
||||||
_ = {**(dependencies or {}), **kwargs}
|
|
||||||
return {
|
|
||||||
"allow": [
|
|
||||||
{"name": "getAccessibleAtlassianResources"},
|
|
||||||
{"name": "getVisibleJiraProjects"},
|
|
||||||
{"name": "searchJiraIssuesUsingJql"},
|
|
||||||
{"name": "getJiraIssue"},
|
|
||||||
{"name": "getJiraProjectIssueTypesMetadata"},
|
|
||||||
{"name": "getJiraIssueTypeMetaWithFields"},
|
|
||||||
{"name": "getTransitionsForJiraIssue"},
|
|
||||||
{"name": "lookupJiraAccountId"},
|
|
||||||
],
|
|
||||||
"ask": [
|
|
||||||
{"name": "createJiraIssue"},
|
|
||||||
{"name": "editJiraIssue"},
|
|
||||||
{"name": "transitionJiraIssue"},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`linear` route: ``SubAgent`` spec for deepagents."""
|
"""``linear`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools come exclusively from MCP. The connector's own approval ruleset is
|
||||||
|
declared in :data:`tools.index.RULESET`; the orchestrator layers it into
|
||||||
|
a per-subagent :class:`PermissionMiddleware`.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET
|
||||||
|
|
||||||
NAME = "linear"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,20 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
description = (
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
read_md_file(__package__, "description").strip()
|
||||||
tools = [
|
or "Handles linear tasks for this workspace."
|
||||||
row["tool"]
|
)
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles linear tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=list(mcp_tools or []),
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,31 @@
|
||||||
|
"""``linear`` permission ruleset (rules over MCP tool names)."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from app.agents.new_chat.permissions import Rule, Ruleset
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
NAME = "linear"
|
||||||
ToolsPermissions,
|
|
||||||
|
RULESET = Ruleset(
|
||||||
|
origin=NAME,
|
||||||
|
rules=[
|
||||||
|
Rule(permission="list_issues", pattern="*", action="allow"),
|
||||||
|
Rule(permission="get_issue", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_my_issues", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_issue_statuses", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_issue_labels", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_comments", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_users", pattern="*", action="allow"),
|
||||||
|
Rule(permission="get_user", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_teams", pattern="*", action="allow"),
|
||||||
|
Rule(permission="get_team", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_projects", pattern="*", action="allow"),
|
||||||
|
Rule(permission="get_project", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_project_labels", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_cycles", pattern="*", action="allow"),
|
||||||
|
Rule(permission="list_documents", pattern="*", action="allow"),
|
||||||
|
Rule(permission="get_document", pattern="*", action="allow"),
|
||||||
|
Rule(permission="search_documentation", pattern="*", action="allow"),
|
||||||
|
Rule(permission="save_issue", pattern="*", action="ask"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
|
||||||
) -> ToolsPermissions:
|
|
||||||
_ = {**(dependencies or {}), **kwargs}
|
|
||||||
return {
|
|
||||||
"allow": [
|
|
||||||
{"name": "list_issues"},
|
|
||||||
{"name": "get_issue"},
|
|
||||||
{"name": "list_my_issues"},
|
|
||||||
{"name": "list_issue_statuses"},
|
|
||||||
{"name": "list_issue_labels"},
|
|
||||||
{"name": "list_comments"},
|
|
||||||
{"name": "list_users"},
|
|
||||||
{"name": "get_user"},
|
|
||||||
{"name": "list_teams"},
|
|
||||||
{"name": "get_team"},
|
|
||||||
{"name": "list_projects"},
|
|
||||||
{"name": "get_project"},
|
|
||||||
{"name": "list_project_labels"},
|
|
||||||
{"name": "list_cycles"},
|
|
||||||
{"name": "list_documents"},
|
|
||||||
{"name": "get_document"},
|
|
||||||
{"name": "search_documentation"},
|
|
||||||
],
|
|
||||||
"ask": [
|
|
||||||
{"name": "save_issue"}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`luma` route: ``SubAgent`` spec for deepagents."""
|
"""``luma`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "luma"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles luma tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles luma tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,36 @@
|
||||||
|
"""``luma`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_event import create_create_luma_event_tool
|
from .create_event import create_create_luma_event_tool
|
||||||
from .list_events import create_list_luma_events_tool
|
from .list_events import create_list_luma_events_tool
|
||||||
from .read_event import create_read_luma_event_tool
|
from .read_event import create_read_luma_event_tool
|
||||||
|
|
||||||
|
NAME = "luma"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
list_ev = create_list_luma_events_tool(**common)
|
return [
|
||||||
read_ev = create_read_luma_event_tool(**common)
|
create_list_luma_events_tool(**common),
|
||||||
create = create_create_luma_event_tool(**common)
|
create_read_luma_event_tool(**common),
|
||||||
return {
|
create_create_luma_event_tool(**common),
|
||||||
"allow": [
|
]
|
||||||
self_gated_tool_permission_row(list_ev),
|
|
||||||
self_gated_tool_permission_row(read_ev),
|
|
||||||
],
|
|
||||||
"ask": [self_gated_tool_permission_row(create)],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`notion` route: ``SubAgent`` spec for deepagents."""
|
"""``notion`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "notion"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles notion tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles notion tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,36 @@
|
||||||
|
"""``notion`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_page import create_create_notion_page_tool
|
from .create_page import create_create_notion_page_tool
|
||||||
from .delete_page import create_delete_notion_page_tool
|
from .delete_page import create_delete_notion_page_tool
|
||||||
from .update_page import create_update_notion_page_tool
|
from .update_page import create_update_notion_page_tool
|
||||||
|
|
||||||
|
NAME = "notion"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
create = create_create_notion_page_tool(**common)
|
return [
|
||||||
update = create_update_notion_page_tool(**common)
|
create_create_notion_page_tool(**common),
|
||||||
delete = create_delete_notion_page_tool(**common)
|
create_update_notion_page_tool(**common),
|
||||||
return {
|
create_delete_notion_page_tool(**common),
|
||||||
"allow": [],
|
]
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(create),
|
|
||||||
self_gated_tool_permission_row(update),
|
|
||||||
self_gated_tool_permission_row(delete),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`onedrive` route: ``SubAgent`` spec for deepagents."""
|
"""``onedrive`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "onedrive"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles onedrive tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles onedrive tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,34 @@
|
||||||
|
"""``onedrive`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .create_file import create_create_onedrive_file_tool
|
from .create_file import create_create_onedrive_file_tool
|
||||||
from .trash_file import create_delete_onedrive_file_tool
|
from .trash_file import create_delete_onedrive_file_tool
|
||||||
|
|
||||||
|
NAME = "onedrive"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
create = create_create_onedrive_file_tool(**common)
|
return [
|
||||||
delete = create_delete_onedrive_file_tool(**common)
|
create_create_onedrive_file_tool(**common),
|
||||||
return {
|
create_delete_onedrive_file_tool(**common),
|
||||||
"allow": [],
|
]
|
||||||
"ask": [
|
|
||||||
self_gated_tool_permission_row(create),
|
|
||||||
self_gated_tool_permission_row(delete),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`slack` route: ``SubAgent`` spec for deepagents."""
|
"""``slack`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools come exclusively from MCP. The connector's own approval ruleset is
|
||||||
|
declared in :data:`tools.index.RULESET`; the orchestrator layers it into
|
||||||
|
a per-subagent :class:`PermissionMiddleware`.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET
|
||||||
|
|
||||||
NAME = "slack"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,20 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
description = (
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
read_md_file(__package__, "description").strip()
|
||||||
tools = [
|
or "Handles slack tasks for this workspace."
|
||||||
row["tool"]
|
)
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles slack tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=list(mcp_tools or []),
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,19 @@
|
||||||
|
"""``slack`` permission ruleset (rules over MCP tool names)."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from app.agents.new_chat.permissions import Rule, Ruleset
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
NAME = "slack"
|
||||||
ToolsPermissions,
|
|
||||||
|
RULESET = Ruleset(
|
||||||
|
origin=NAME,
|
||||||
|
rules=[
|
||||||
|
Rule(permission="slack_search_channels", pattern="*", action="allow"),
|
||||||
|
Rule(permission="slack_search_messages", pattern="*", action="allow"),
|
||||||
|
Rule(permission="slack_search_users", pattern="*", action="allow"),
|
||||||
|
Rule(permission="slack_read_channel", pattern="*", action="allow"),
|
||||||
|
Rule(permission="slack_read_thread", pattern="*", action="allow"),
|
||||||
|
Rule(permission="slack_send_message", pattern="*", action="ask"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
|
||||||
) -> ToolsPermissions:
|
|
||||||
_ = {**(dependencies or {}), **kwargs}
|
|
||||||
return {
|
|
||||||
"allow": [
|
|
||||||
{"name": "slack_search_channels"},
|
|
||||||
{"name": "slack_search_messages"},
|
|
||||||
{"name": "slack_search_users"},
|
|
||||||
{"name": "slack_read_channel"},
|
|
||||||
{"name": "slack_read_thread"},
|
|
||||||
],
|
|
||||||
"ask": [
|
|
||||||
{"name": "slack_send_message"},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,22 @@
|
||||||
"""`teams` route: ``SubAgent`` spec for deepagents."""
|
"""``teams`` route: ``SurfSenseSubagentSpec`` builder for deepagents.
|
||||||
|
|
||||||
|
Tools self-gate inside their bodies via :func:`request_approval`; the
|
||||||
|
empty :data:`tools.index.RULESET` is layered into a per-subagent
|
||||||
|
:class:`PermissionMiddleware` for uniformity.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.middleware_gated import (
|
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import read_md_file
|
||||||
middleware_gated_interrupt_on,
|
from app.agents.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||||
)
|
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import pack_subagent
|
||||||
from app.agents.multi_agent_chat.subagents.shared.md_file_reader import (
|
|
||||||
read_md_file,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.subagent_builder import (
|
|
||||||
pack_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
merge_tools_permissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .tools.index import load_tools
|
from .tools.index import NAME, RULESET, load_tools
|
||||||
|
|
||||||
NAME = "teams"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
def build_subagent(
|
||||||
|
|
@ -31,26 +24,21 @@ def build_subagent(
|
||||||
dependencies: dict[str, Any],
|
dependencies: dict[str, Any],
|
||||||
model: BaseChatModel | None = None,
|
model: BaseChatModel | None = None,
|
||||||
middleware_stack: dict[str, Any] | None = None,
|
middleware_stack: dict[str, Any] | None = None,
|
||||||
extra_tools_bucket: ToolsPermissions | None = None,
|
mcp_tools: list[BaseTool] | None = None,
|
||||||
) -> SubAgent:
|
) -> SurfSenseSubagentSpec:
|
||||||
buckets = load_tools(dependencies=dependencies)
|
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||||
merged_tools_bucket = merge_tools_permissions(buckets, extra_tools_bucket)
|
description = (
|
||||||
tools = [
|
read_md_file(__package__, "description").strip()
|
||||||
row["tool"]
|
or "Handles teams tasks for this workspace."
|
||||||
for row in (*merged_tools_bucket["allow"], *merged_tools_bucket["ask"])
|
)
|
||||||
if row.get("tool") is not None
|
|
||||||
]
|
|
||||||
interrupt_on = middleware_gated_interrupt_on(merged_tools_bucket)
|
|
||||||
description = read_md_file(__package__, "description").strip()
|
|
||||||
if not description:
|
|
||||||
description = "Handles teams tasks for this workspace."
|
|
||||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||||
return pack_subagent(
|
return pack_subagent(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
description=description,
|
description=description,
|
||||||
system_prompt=system_prompt,
|
system_prompt=system_prompt,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
interrupt_on=interrupt_on,
|
ruleset=RULESET,
|
||||||
|
flags=dependencies["flags"],
|
||||||
model=model,
|
model=model,
|
||||||
middleware_stack=middleware_stack,
|
middleware_stack=middleware_stack,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,36 @@
|
||||||
|
"""``teams`` native tools and (empty) permission ruleset.
|
||||||
|
|
||||||
|
Tools self-gate via :func:`request_approval` in their bodies.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
|
from langchain_core.tools import BaseTool
|
||||||
self_gated_tool_permission_row,
|
|
||||||
)
|
from app.agents.new_chat.permissions import Ruleset
|
||||||
from app.agents.multi_agent_chat.subagents.shared.tool_kinds import (
|
|
||||||
ToolsPermissions,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .list_channels import create_list_teams_channels_tool
|
from .list_channels import create_list_teams_channels_tool
|
||||||
from .read_messages import create_read_teams_messages_tool
|
from .read_messages import create_read_teams_messages_tool
|
||||||
from .send_message import create_send_teams_message_tool
|
from .send_message import create_send_teams_message_tool
|
||||||
|
|
||||||
|
NAME = "teams"
|
||||||
|
|
||||||
|
RULESET = Ruleset(origin=NAME, rules=[])
|
||||||
|
|
||||||
|
|
||||||
def load_tools(
|
def load_tools(
|
||||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||||
) -> ToolsPermissions:
|
) -> list[BaseTool]:
|
||||||
d = {**(dependencies or {}), **kwargs}
|
d = {**(dependencies or {}), **kwargs}
|
||||||
common = {
|
common = {
|
||||||
"db_session": d["db_session"],
|
"db_session": d["db_session"],
|
||||||
"search_space_id": d["search_space_id"],
|
"search_space_id": d["search_space_id"],
|
||||||
"user_id": d["user_id"],
|
"user_id": d["user_id"],
|
||||||
}
|
}
|
||||||
list_ch = create_list_teams_channels_tool(**common)
|
return [
|
||||||
read_msg = create_read_teams_messages_tool(**common)
|
create_list_teams_channels_tool(**common),
|
||||||
send = create_send_teams_message_tool(**common)
|
create_read_teams_messages_tool(**common),
|
||||||
return {
|
create_send_teams_message_tool(**common),
|
||||||
"allow": [
|
]
|
||||||
self_gated_tool_permission_row(list_ch),
|
|
||||||
self_gated_tool_permission_row(read_msg),
|
|
||||||
],
|
|
||||||
"ask": [self_gated_tool_permission_row(send)],
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue