Inject dynamic registry subagents into the main prompt and simplify connector discovery.

This commit is contained in:
CREDO23 2026-05-02 00:44:02 +02:00
parent ffed829cf8
commit 4fd3c4fb27
4 changed files with 47 additions and 10 deletions

View file

@ -24,12 +24,13 @@ from app.agents.new_chat.feature_flags import AgentFeatureFlags, get_flags
from app.agents.new_chat.filesystem_backends import build_backend_resolver
from app.agents.new_chat.filesystem_selection import FilesystemMode, FilesystemSelection
from app.agents.new_chat.llm_config import AgentConfig
from app.agents.multi_agent_with_deepagents.subagents import (
get_subagents_to_exclude,
main_prompt_registry_subagent_lines,
)
from ..system_prompt import build_main_agent_system_prompt
from app.agents.new_chat.tools.invalid_tool import INVALID_TOOL_NAME, invalid_tool
from app.agents.new_chat.tools.registry import (
build_tools_async,
get_connector_gated_tools,
)
from app.agents.new_chat.tools.registry import build_tools_async
from app.db import ChatVisibility
from app.services.connector_service import ConnectorService
from app.utils.perf import get_perf_logger
@ -73,8 +74,7 @@ async def create_surfsense_deep_agent(
connector_types = await connector_service.get_available_connectors(
search_space_id
)
if connector_types:
available_connectors = _map_connectors_to_searchable_types(connector_types)
available_connectors = _map_connectors_to_searchable_types(connector_types)
available_document_types = await connector_service.get_available_document_types(
search_space_id
@ -119,7 +119,6 @@ async def create_surfsense_deep_agent(
)
modified_disabled_tools = list(disabled_tools) if disabled_tools else []
modified_disabled_tools.extend(get_connector_gated_tools(available_connectors))
if "search_knowledge_base" not in modified_disabled_tools:
modified_disabled_tools.append("search_knowledge_base")
@ -160,6 +159,11 @@ async def create_surfsense_deep_agent(
if isinstance(prof, str):
_model_name = prof
_connector_exclude = get_subagents_to_exclude(available_connectors)
_registry_subagent_prompt_lines = main_prompt_registry_subagent_lines(
_connector_exclude
)
if agent_config is not None:
system_prompt = build_main_agent_system_prompt(
today=None,
@ -170,6 +174,7 @@ async def create_surfsense_deep_agent(
use_default_system_instructions=agent_config.use_default_system_instructions,
citations_enabled=agent_config.citations_enabled,
model_name=_model_name or getattr(agent_config, "model_name", None),
registry_subagent_prompt_lines=_registry_subagent_prompt_lines,
)
else:
system_prompt = build_main_agent_system_prompt(
@ -178,6 +183,7 @@ async def create_surfsense_deep_agent(
disabled_tool_names=_user_disabled_tool_names,
citations_enabled=True,
model_name=_model_name,
registry_subagent_prompt_lines=_registry_subagent_prompt_lines,
)
_perf_log.info(
"[create_agent] System prompt built in %.3fs", time.perf_counter() - _t0

View file

@ -1,8 +1,7 @@
"""Assemble the **main-agent** deep-agent system string only.
Sections (order matters): core instructions provider flavour **citations policy**
SurfSense tool docs. Citations come before ``<tools>`` so citation on/off rules
apply before any tool text that mentions attribution.
Sections (order matters): core instructions provider citations dynamic
``<registry_subagents>`` SurfSense ``<tools>``.
"""
from __future__ import annotations
@ -13,6 +12,7 @@ from app.db import ChatVisibility
from .sections.citations import build_citations_section
from .sections.provider import build_provider_section
from .sections.registry_subagents import build_registry_subagents_section
from .sections.system_instruction import build_default_system_instruction_xml
from .sections.tools import build_tools_section
@ -27,6 +27,7 @@ def build_main_agent_system_prompt(
use_default_system_instructions: bool = True,
citations_enabled: bool = True,
model_name: str | None = None,
registry_subagent_prompt_lines: list[tuple[str, str]] | None = None,
) -> str:
resolved_today = (today or datetime.now(UTC)).astimezone(UTC).date().isoformat()
visibility = thread_visibility or ChatVisibility.PRIVATE
@ -43,6 +44,7 @@ def build_main_agent_system_prompt(
system_block += build_provider_section(model_name=model_name)
system_block += build_citations_section(citations_enabled=citations_enabled)
system_block += build_registry_subagents_section(registry_subagent_prompt_lines)
system_block += build_tools_section(
visibility=visibility,
enabled_tool_names=enabled_tool_names,

View file

@ -0,0 +1,27 @@
"""Dynamic ``<registry_subagents>`` block: **task** specialists actually built for this workspace."""
from __future__ import annotations
def build_registry_subagents_section(
registry_subagent_lines: list[tuple[str, str]] | None,
) -> str:
if registry_subagent_lines is None:
return ""
if not registry_subagent_lines:
return (
"\n<registry_subagents>\n"
"No registry specialists are listed for **task** in this workspace.\n"
"</registry_subagents>\n"
)
bullets = "\n".join(
f"- **{name}** — {desc}" for name, desc in registry_subagent_lines
)
return (
"\n<registry_subagents>\n"
"These specialists are registered for **task** (routes without a matching connector are omitted).\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"
"</registry_subagents>\n"
)

View file

@ -2,6 +2,8 @@
Use **task** for anything beyond your direct SurfSense tools: calendar, mail,
chat, tickets, documents in third-party systems, connector-specific discovery,
deliverables (reports, podcasts, images, etc.), and other specialized routes.
The live list of specialists you may target with **task** for this workspace is in
`<registry_subagents>` (later in this prompt).
Your **direct** SurfSense tools are only: **update_memory**, **web_search**,
**scrape_webpage**, and **search_surfsense_docs**. The runtime may also attach