mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-19 18:45:15 +02:00
multi_agent_chat: drop general_purpose subagent and dead permission plumbing
This commit is contained in:
parent
3fb1976886
commit
3f77c74daf
12 changed files with 9 additions and 307 deletions
|
|
@ -21,7 +21,6 @@ def build_registry_subagents_section(
|
||||||
"\n<registry_subagents>\n"
|
"\n<registry_subagents>\n"
|
||||||
"These specialists are registered for **task** (routes without a matching connector are omitted).\n"
|
"These specialists are registered for **task** (routes without a matching connector are omitted).\n"
|
||||||
f"{bullets}\n"
|
f"{bullets}\n"
|
||||||
"The runtime may also offer a general-purpose **task** helper with your tools in a separate context.\n"
|
|
||||||
"Pick the specialist by **name**. Put full instructions in the task prompt; they do not see this thread.\n"
|
"Pick the specialist by **name**. Put full instructions in the task prompt; they do not see this thread.\n"
|
||||||
"</registry_subagents>\n"
|
"</registry_subagents>\n"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
<tool_routing>
|
<tool_routing>
|
||||||
Use **task** for any work beyond your direct SurfSense tools. Two builtin
|
Use **task** for any work beyond your direct SurfSense tools. The
|
||||||
specialists are always available:
|
**knowledge_base** specialist is always available:
|
||||||
|
|
||||||
- **knowledge_base** — owns the user's workspace (documents and folders). Route
|
- **knowledge_base** — owns the user's workspace (documents and folders). Route
|
||||||
here whenever the user wants to create, read, edit, search, organise, or
|
here whenever the user wants to create, read, edit, search, organise, or
|
||||||
remove a document or folder (e.g. *"save these notes to my KB"*, *"find my Q2
|
remove a document or folder (e.g. *"save these notes to my KB"*, *"find my Q2
|
||||||
roadmap"*, *"rename this folder"*).
|
roadmap"*, *"rename this folder"*).
|
||||||
- **general_purpose** — ad-hoc multi-step work that doesn't fit any specialist.
|
|
||||||
|
|
||||||
The connector specialists listed in `<registry_subagents>` (later in this
|
The connector specialists listed in `<registry_subagents>` (later in this
|
||||||
prompt) cover calendar, mail, chat, tickets, third-party documents,
|
prompt) cover calendar, mail, chat, tickets, third-party documents,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
"""File-intent classifier that gates strict write contracts."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
|
||||||
|
|
||||||
from app.agents.new_chat.middleware import FileIntentMiddleware
|
|
||||||
|
|
||||||
|
|
||||||
def build_file_intent_mw(llm: BaseChatModel) -> FileIntentMiddleware:
|
|
||||||
return FileIntentMiddleware(llm=llm)
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
"""Permission rulesets fanned out to parent / general-purpose / subagent stacks."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from .context import PermissionContext, build_permission_context
|
|
||||||
from .middleware import build_full_permission_mw
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"PermissionContext",
|
|
||||||
"build_full_permission_mw",
|
|
||||||
"build_permission_context",
|
|
||||||
]
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
"""Derive shared permission context once; fan out to all three stack layers.
|
|
||||||
|
|
||||||
The context carries:
|
|
||||||
- ``rulesets``: full ask/deny/allow rules for the main-agent permission middleware.
|
|
||||||
- ``general_purpose_interrupt_on``: ``ask`` rules mirrored as deepagents
|
|
||||||
``interrupt_on`` so HITL still triggers from inside ``task`` runs (subagents
|
|
||||||
bypass the main-agent permission middleware).
|
|
||||||
- ``subagent_deny_mw``: a deny-only ``PermissionMiddleware`` instance shared
|
|
||||||
across the general-purpose and registry subagent stacks.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
from langchain_core.tools import BaseTool
|
|
||||||
|
|
||||||
from app.agents.new_chat.feature_flags import AgentFeatureFlags
|
|
||||||
from app.agents.new_chat.filesystem_selection import FilesystemMode
|
|
||||||
from app.agents.new_chat.middleware import PermissionMiddleware
|
|
||||||
from app.agents.new_chat.permissions import Rule, Ruleset
|
|
||||||
from app.agents.new_chat.tools.registry import BUILTIN_TOOLS
|
|
||||||
|
|
||||||
from ..flags import enabled
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class PermissionContext:
|
|
||||||
rulesets: list[Ruleset]
|
|
||||||
general_purpose_interrupt_on: dict[str, bool]
|
|
||||||
subagent_deny_mw: PermissionMiddleware | None
|
|
||||||
|
|
||||||
|
|
||||||
def build_permission_context(
|
|
||||||
*,
|
|
||||||
flags: AgentFeatureFlags,
|
|
||||||
filesystem_mode: FilesystemMode,
|
|
||||||
tools: Sequence[BaseTool],
|
|
||||||
available_connectors: list[str] | None,
|
|
||||||
) -> PermissionContext:
|
|
||||||
is_desktop_fs = filesystem_mode == FilesystemMode.DESKTOP_LOCAL_FOLDER
|
|
||||||
permission_enabled = enabled(flags, "enable_permission")
|
|
||||||
|
|
||||||
rulesets: list[Ruleset] = []
|
|
||||||
if permission_enabled or is_desktop_fs:
|
|
||||||
rulesets.append(
|
|
||||||
Ruleset(
|
|
||||||
rules=[Rule(permission="*", pattern="*", action="allow")],
|
|
||||||
origin="surfsense_defaults",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if is_desktop_fs:
|
|
||||||
rulesets.append(
|
|
||||||
Ruleset(
|
|
||||||
rules=[
|
|
||||||
Rule(permission="rm", pattern="*", action="ask"),
|
|
||||||
Rule(permission="rmdir", pattern="*", action="ask"),
|
|
||||||
Rule(permission="move_file", pattern="*", action="ask"),
|
|
||||||
Rule(permission="edit_file", pattern="*", action="ask"),
|
|
||||||
Rule(permission="write_file", pattern="*", action="ask"),
|
|
||||||
],
|
|
||||||
origin="desktop_safety",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
tool_names_in_use = {t.name for t in tools}
|
|
||||||
|
|
||||||
if permission_enabled:
|
|
||||||
available_set = set(available_connectors or [])
|
|
||||||
synthesized: list[Rule] = []
|
|
||||||
for tool_def in BUILTIN_TOOLS:
|
|
||||||
if tool_def.name not in tool_names_in_use:
|
|
||||||
continue
|
|
||||||
rc = tool_def.required_connector
|
|
||||||
if rc and rc not in available_set:
|
|
||||||
synthesized.append(
|
|
||||||
Rule(permission=tool_def.name, pattern="*", action="deny")
|
|
||||||
)
|
|
||||||
if synthesized:
|
|
||||||
rulesets.append(Ruleset(rules=synthesized, origin="connector_synthesized"))
|
|
||||||
|
|
||||||
general_purpose_interrupt_on: dict[str, bool] = {
|
|
||||||
rule.permission: True
|
|
||||||
for rs in rulesets
|
|
||||||
for rule in rs.rules
|
|
||||||
if rule.action == "ask" and rule.permission in tool_names_in_use
|
|
||||||
}
|
|
||||||
|
|
||||||
deny_rulesets = [
|
|
||||||
Ruleset(
|
|
||||||
rules=[r for r in rs.rules if r.action == "deny"],
|
|
||||||
origin=rs.origin,
|
|
||||||
)
|
|
||||||
for rs in rulesets
|
|
||||||
]
|
|
||||||
deny_rulesets = [rs for rs in deny_rulesets if rs.rules]
|
|
||||||
|
|
||||||
subagent_deny_mw: PermissionMiddleware | None = (
|
|
||||||
PermissionMiddleware(rulesets=deny_rulesets) if deny_rulesets else None
|
|
||||||
)
|
|
||||||
|
|
||||||
return PermissionContext(
|
|
||||||
rulesets=rulesets,
|
|
||||||
general_purpose_interrupt_on=general_purpose_interrupt_on,
|
|
||||||
subagent_deny_mw=subagent_deny_mw,
|
|
||||||
)
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
"""Main-agent permission middleware (full ask/deny/allow rules)."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from app.agents.new_chat.middleware import PermissionMiddleware
|
|
||||||
from app.agents.new_chat.permissions import Ruleset
|
|
||||||
|
|
||||||
|
|
||||||
def build_full_permission_mw(rulesets: list[Ruleset]) -> PermissionMiddleware | None:
|
|
||||||
return PermissionMiddleware(rulesets=rulesets) if rulesets else None
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Resilience middleware shared as the same instances across parent / general-purpose / registry."""
|
"""Resilience middleware shared as the same instances across parent / registry."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,6 @@ from app.agents.multi_agent_chat.subagents import (
|
||||||
build_subagents,
|
build_subagents,
|
||||||
get_subagents_to_exclude,
|
get_subagents_to_exclude,
|
||||||
)
|
)
|
||||||
from app.agents.multi_agent_chat.subagents.builtins.general_purpose.agent import (
|
|
||||||
build_subagent as build_general_purpose_subagent,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.subagents.builtins.knowledge_base.agent import (
|
from app.agents.multi_agent_chat.subagents.builtins.knowledge_base.agent import (
|
||||||
build_subagent as build_knowledge_base_subagent,
|
build_subagent as build_knowledge_base_subagent,
|
||||||
)
|
)
|
||||||
|
|
@ -56,10 +53,6 @@ from .shared.compaction import build_compaction_mw
|
||||||
from .shared.kb_context_projection import build_kb_context_projection_mw
|
from .shared.kb_context_projection import build_kb_context_projection_mw
|
||||||
from .shared.memory import build_memory_mw
|
from .shared.memory import build_memory_mw
|
||||||
from .shared.patch_tool_calls import build_patch_tool_calls_mw
|
from .shared.patch_tool_calls import build_patch_tool_calls_mw
|
||||||
from .shared.permissions import (
|
|
||||||
build_full_permission_mw,
|
|
||||||
build_permission_context,
|
|
||||||
)
|
|
||||||
from .shared.resilience import build_resilience_bundle
|
from .shared.resilience import build_resilience_bundle
|
||||||
from .shared.todos import build_todos_mw
|
from .shared.todos import build_todos_mw
|
||||||
from .subagent.extras import build_subagent_extras
|
from .subagent.extras import build_subagent_extras
|
||||||
|
|
@ -87,34 +80,14 @@ def build_main_agent_deepagent_middleware(
|
||||||
disabled_tools: list[str] | None = None,
|
disabled_tools: list[str] | None = None,
|
||||||
) -> list[Any]:
|
) -> list[Any]:
|
||||||
"""Ordered middleware for ``create_agent`` (None entries already stripped)."""
|
"""Ordered middleware for ``create_agent`` (None entries already stripped)."""
|
||||||
permissions = build_permission_context(
|
|
||||||
flags=flags,
|
|
||||||
filesystem_mode=filesystem_mode,
|
|
||||||
tools=tools,
|
|
||||||
available_connectors=available_connectors,
|
|
||||||
)
|
|
||||||
resilience = build_resilience_bundle(flags)
|
resilience = build_resilience_bundle(flags)
|
||||||
|
|
||||||
# Single instance threaded into both the main-agent stack and the general-purpose subagent.
|
|
||||||
memory_mw = build_memory_mw(
|
memory_mw = build_memory_mw(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
search_space_id=search_space_id,
|
search_space_id=search_space_id,
|
||||||
visibility=visibility,
|
visibility=visibility,
|
||||||
)
|
)
|
||||||
|
|
||||||
general_purpose_subagent = build_general_purpose_subagent(
|
|
||||||
llm=llm,
|
|
||||||
tools=tools,
|
|
||||||
backend_resolver=backend_resolver,
|
|
||||||
filesystem_mode=filesystem_mode,
|
|
||||||
search_space_id=search_space_id,
|
|
||||||
user_id=user_id,
|
|
||||||
thread_id=thread_id,
|
|
||||||
permissions=permissions,
|
|
||||||
resilience=resilience,
|
|
||||||
memory_mw=memory_mw,
|
|
||||||
)
|
|
||||||
|
|
||||||
knowledge_base_subagent = build_knowledge_base_subagent(
|
knowledge_base_subagent = build_knowledge_base_subagent(
|
||||||
llm=llm,
|
llm=llm,
|
||||||
backend_resolver=backend_resolver,
|
backend_resolver=backend_resolver,
|
||||||
|
|
@ -122,14 +95,12 @@ def build_main_agent_deepagent_middleware(
|
||||||
search_space_id=search_space_id,
|
search_space_id=search_space_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
thread_id=thread_id,
|
thread_id=thread_id,
|
||||||
permissions=permissions,
|
|
||||||
resilience=resilience,
|
resilience=resilience,
|
||||||
)
|
)
|
||||||
|
|
||||||
subagents_registry: list[SubAgent] = []
|
subagents_registry: list[SubAgent] = []
|
||||||
try:
|
try:
|
||||||
subagent_extras = build_subagent_extras(
|
subagent_extras = build_subagent_extras(
|
||||||
permissions=permissions,
|
|
||||||
resilience=resilience,
|
resilience=resilience,
|
||||||
)
|
)
|
||||||
subagents_registry = build_subagents(
|
subagents_registry = build_subagents(
|
||||||
|
|
@ -145,15 +116,14 @@ def build_main_agent_deepagent_middleware(
|
||||||
[s["name"] for s in subagents_registry],
|
[s["name"] for s in subagents_registry],
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Degrade to general-purpose-only rather than aborting the turn:
|
# Degrade to KB-only rather than aborting the turn:
|
||||||
# one bad subagent dep should not deny the user a response.
|
# one bad subagent dep should not deny the user a response.
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"Subagents registry build failed; falling back to general-purpose only"
|
"Subagents registry build failed; falling back to knowledge_base only"
|
||||||
)
|
)
|
||||||
subagents_registry = []
|
subagents_registry = []
|
||||||
|
|
||||||
subagents: list[SubAgent] = [
|
subagents: list[SubAgent] = [
|
||||||
general_purpose_subagent,
|
|
||||||
knowledge_base_subagent,
|
knowledge_base_subagent,
|
||||||
*subagents_registry,
|
*subagents_registry,
|
||||||
]
|
]
|
||||||
|
|
@ -209,7 +179,6 @@ def build_main_agent_deepagent_middleware(
|
||||||
resilience.retry,
|
resilience.retry,
|
||||||
resilience.fallback,
|
resilience.fallback,
|
||||||
build_repair_mw(flags=flags, tools=tools),
|
build_repair_mw(flags=flags, tools=tools),
|
||||||
build_full_permission_mw(permissions.rulesets),
|
|
||||||
build_doom_loop_mw(flags),
|
build_doom_loop_mw(flags),
|
||||||
build_action_log_mw(
|
build_action_log_mw(
|
||||||
flags=flags,
|
flags=flags,
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,23 @@
|
||||||
|
|
||||||
Registry subagents are scoped to one domain (deliverables, research, memory,
|
Registry subagents are scoped to one domain (deliverables, research, memory,
|
||||||
connectors, MCP) and never read or write the SurfSense filesystem — that
|
connectors, MCP) and never read or write the SurfSense filesystem — that
|
||||||
capability belongs to the main agent and is delegated to the general-purpose
|
capability belongs to the ``knowledge_base`` subagent. Keeping FS off the
|
||||||
subagent as an escape hatch. Keeping FS off the registry stacks avoids
|
registry stacks avoids polluting their tool surface with FS tools they
|
||||||
polluting their tool surface with FS tools they never act on.
|
never act on.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from ..shared.permissions import PermissionContext
|
|
||||||
from ..shared.resilience import ResilienceBundle
|
from ..shared.resilience import ResilienceBundle
|
||||||
from ..shared.todos import build_todos_mw
|
from ..shared.todos import build_todos_mw
|
||||||
|
|
||||||
|
|
||||||
def build_subagent_extras(
|
def build_subagent_extras(
|
||||||
*,
|
*,
|
||||||
permissions: PermissionContext,
|
|
||||||
resilience: ResilienceBundle,
|
resilience: ResilienceBundle,
|
||||||
) -> list[Any]:
|
) -> list[Any]:
|
||||||
extras: list[Any] = [build_todos_mw()]
|
extras: list[Any] = [build_todos_mw()]
|
||||||
if permissions.subagent_deny_mw is not None:
|
|
||||||
extras.append(permissions.subagent_deny_mw)
|
|
||||||
extras.extend(resilience.as_list())
|
extras.extend(resilience.as_list())
|
||||||
return extras
|
return extras
|
||||||
|
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
"""General-purpose subagent for the multi-agent main agent."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import Any, cast
|
|
||||||
|
|
||||||
from deepagents import SubAgent
|
|
||||||
from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware
|
|
||||||
from deepagents.middleware.subagents import GENERAL_PURPOSE_SUBAGENT
|
|
||||||
from langchain_anthropic.middleware import AnthropicPromptCachingMiddleware
|
|
||||||
from langchain_core.language_models import BaseChatModel
|
|
||||||
from langchain_core.tools import BaseTool
|
|
||||||
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.anthropic_cache import (
|
|
||||||
build_anthropic_cache_mw,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.compaction import (
|
|
||||||
build_compaction_mw,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.file_intent import (
|
|
||||||
build_file_intent_mw,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.filesystem import (
|
|
||||||
build_filesystem_mw,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.patch_tool_calls import (
|
|
||||||
build_patch_tool_calls_mw,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.permissions import (
|
|
||||||
PermissionContext,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.resilience import (
|
|
||||||
ResilienceBundle,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.todos import build_todos_mw
|
|
||||||
from app.agents.new_chat.filesystem_selection import FilesystemMode
|
|
||||||
from app.agents.new_chat.middleware import MemoryInjectionMiddleware
|
|
||||||
|
|
||||||
NAME = "general-purpose"
|
|
||||||
|
|
||||||
|
|
||||||
def build_subagent(
|
|
||||||
*,
|
|
||||||
llm: BaseChatModel,
|
|
||||||
tools: Sequence[BaseTool],
|
|
||||||
backend_resolver: Any,
|
|
||||||
filesystem_mode: FilesystemMode,
|
|
||||||
search_space_id: int,
|
|
||||||
user_id: str | None,
|
|
||||||
thread_id: int | None,
|
|
||||||
permissions: PermissionContext,
|
|
||||||
resilience: ResilienceBundle,
|
|
||||||
memory_mw: MemoryInjectionMiddleware,
|
|
||||||
) -> SubAgent:
|
|
||||||
"""Deny + resilience inserts encapsulated here so the orchestrator never mutates the list."""
|
|
||||||
middleware: list[Any] = [
|
|
||||||
build_todos_mw(),
|
|
||||||
memory_mw,
|
|
||||||
build_file_intent_mw(llm),
|
|
||||||
build_filesystem_mw(
|
|
||||||
backend_resolver=backend_resolver,
|
|
||||||
filesystem_mode=filesystem_mode,
|
|
||||||
search_space_id=search_space_id,
|
|
||||||
user_id=user_id,
|
|
||||||
thread_id=thread_id,
|
|
||||||
),
|
|
||||||
build_compaction_mw(llm),
|
|
||||||
build_patch_tool_calls_mw(),
|
|
||||||
build_anthropic_cache_mw(),
|
|
||||||
]
|
|
||||||
|
|
||||||
if permissions.subagent_deny_mw is not None:
|
|
||||||
patch_idx = next(
|
|
||||||
(
|
|
||||||
i
|
|
||||||
for i, m in enumerate(middleware)
|
|
||||||
if isinstance(m, PatchToolCallsMiddleware)
|
|
||||||
),
|
|
||||||
len(middleware),
|
|
||||||
)
|
|
||||||
middleware.insert(patch_idx, permissions.subagent_deny_mw)
|
|
||||||
|
|
||||||
resilience_mws = resilience.as_list()
|
|
||||||
if resilience_mws:
|
|
||||||
cache_idx = next(
|
|
||||||
(
|
|
||||||
i
|
|
||||||
for i, m in enumerate(middleware)
|
|
||||||
if isinstance(m, AnthropicPromptCachingMiddleware)
|
|
||||||
),
|
|
||||||
len(middleware),
|
|
||||||
)
|
|
||||||
for offset, mw in enumerate(resilience_mws):
|
|
||||||
middleware.insert(cache_idx + offset, mw)
|
|
||||||
|
|
||||||
spec: dict[str, Any] = {
|
|
||||||
**GENERAL_PURPOSE_SUBAGENT,
|
|
||||||
"model": llm,
|
|
||||||
"tools": tools,
|
|
||||||
"middleware": middleware,
|
|
||||||
}
|
|
||||||
if permissions.general_purpose_interrupt_on:
|
|
||||||
spec["interrupt_on"] = permissions.general_purpose_interrupt_on
|
|
||||||
return cast(SubAgent, spec)
|
|
||||||
|
|
@ -11,7 +11,6 @@ from __future__ import annotations
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from deepagents import SubAgent
|
from deepagents import SubAgent
|
||||||
from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware
|
|
||||||
from langchain_anthropic.middleware import AnthropicPromptCachingMiddleware
|
from langchain_anthropic.middleware import AnthropicPromptCachingMiddleware
|
||||||
from langchain_core.language_models import BaseChatModel
|
from langchain_core.language_models import BaseChatModel
|
||||||
|
|
||||||
|
|
@ -30,9 +29,6 @@ from app.agents.multi_agent_chat.middleware.shared.kb_context_projection import
|
||||||
from app.agents.multi_agent_chat.middleware.shared.patch_tool_calls import (
|
from app.agents.multi_agent_chat.middleware.shared.patch_tool_calls import (
|
||||||
build_patch_tool_calls_mw,
|
build_patch_tool_calls_mw,
|
||||||
)
|
)
|
||||||
from app.agents.multi_agent_chat.middleware.shared.permissions import (
|
|
||||||
PermissionContext,
|
|
||||||
)
|
|
||||||
from app.agents.multi_agent_chat.middleware.shared.resilience import (
|
from app.agents.multi_agent_chat.middleware.shared.resilience import (
|
||||||
ResilienceBundle,
|
ResilienceBundle,
|
||||||
)
|
)
|
||||||
|
|
@ -55,10 +51,9 @@ def build_subagent(
|
||||||
search_space_id: int,
|
search_space_id: int,
|
||||||
user_id: str | None,
|
user_id: str | None,
|
||||||
thread_id: int | None,
|
thread_id: int | None,
|
||||||
permissions: PermissionContext,
|
|
||||||
resilience: ResilienceBundle,
|
resilience: ResilienceBundle,
|
||||||
) -> SubAgent:
|
) -> SubAgent:
|
||||||
"""Deny + resilience inserts encapsulated here so the orchestrator never mutates the list."""
|
"""Resilience inserts encapsulated here so the orchestrator never mutates the list."""
|
||||||
description = read_md_file(__package__, "description").strip()
|
description = read_md_file(__package__, "description").strip()
|
||||||
if not description:
|
if not description:
|
||||||
description = (
|
description = (
|
||||||
|
|
@ -86,17 +81,6 @@ def build_subagent(
|
||||||
build_anthropic_cache_mw(),
|
build_anthropic_cache_mw(),
|
||||||
]
|
]
|
||||||
|
|
||||||
if permissions.subagent_deny_mw is not None:
|
|
||||||
patch_idx = next(
|
|
||||||
(
|
|
||||||
i
|
|
||||||
for i, m in enumerate(middleware)
|
|
||||||
if isinstance(m, PatchToolCallsMiddleware)
|
|
||||||
),
|
|
||||||
len(middleware),
|
|
||||||
)
|
|
||||||
middleware.insert(patch_idx, permissions.subagent_deny_mw)
|
|
||||||
|
|
||||||
resilience_mws = resilience.as_list()
|
resilience_mws = resilience.as_list()
|
||||||
if resilience_mws:
|
if resilience_mws:
|
||||||
cache_idx = next(
|
cache_idx = next(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue