mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-08 22:22:17 +02:00
feat(chat): add intelligence_agent subagent over capability verbs
This commit is contained in:
parent
110beb4dd1
commit
7ad83760b5
9 changed files with 135 additions and 1 deletions
|
|
@ -26,6 +26,7 @@ CONNECTOR_TYPE_TO_CONNECTOR_AGENT_MAPS: dict[str, str] = {
|
|||
SUBAGENT_TO_REQUIRED_CONNECTOR_MAP: dict[str, frozenset[str]] = {
|
||||
"deliverables": frozenset(),
|
||||
"knowledge_base": frozenset(),
|
||||
"intelligence_agent": frozenset(),
|
||||
"airtable": frozenset({"AIRTABLE_CONNECTOR"}),
|
||||
"calendar": frozenset({"GOOGLE_CALENDAR_CONNECTOR"}),
|
||||
"clickup": frozenset({"CLICKUP_CONNECTOR"}),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
"""``intelligence_agent`` route: ``SurfSenseSubagentSpec`` builder for deepagents."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from langchain_core.language_models import BaseChatModel
|
||||
from langchain_core.tools import BaseTool
|
||||
|
||||
from app.agents.chat.multi_agent_chat.subagents.shared.md_file_reader import (
|
||||
read_md_file,
|
||||
)
|
||||
from app.agents.chat.multi_agent_chat.subagents.shared.spec import SurfSenseSubagentSpec
|
||||
from app.agents.chat.multi_agent_chat.subagents.shared.subagent_builder import (
|
||||
pack_subagent,
|
||||
)
|
||||
|
||||
from .tools.index import NAME, RULESET, load_tools
|
||||
|
||||
|
||||
def build_subagent(
|
||||
*,
|
||||
dependencies: dict[str, Any],
|
||||
model: BaseChatModel | None = None,
|
||||
middleware_stack: dict[str, Any] | None = None,
|
||||
mcp_tools: list[BaseTool] | None = None,
|
||||
) -> SurfSenseSubagentSpec:
|
||||
tools = [*load_tools(dependencies=dependencies), *(mcp_tools or [])]
|
||||
description = (
|
||||
read_md_file(__package__, "description").strip()
|
||||
or "Gathers and compares web intelligence for this workspace."
|
||||
)
|
||||
system_prompt = read_md_file(__package__, "system_prompt").strip()
|
||||
return pack_subagent(
|
||||
name=NAME,
|
||||
description=description,
|
||||
system_prompt=system_prompt,
|
||||
tools=tools,
|
||||
ruleset=RULESET,
|
||||
dependencies=dependencies,
|
||||
model=model,
|
||||
middleware_stack=middleware_stack,
|
||||
)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Specialist for web intelligence: fetch live pages and search the web, then compare against earlier findings.
|
||||
Use whenever a task needs current data pulled from specific URLs or discovered on the web — competitor/product monitoring, pricing, listings, "what changed since last time" — and answered from that evidence.
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
You are the SurfSense intelligence sub-agent.
|
||||
You receive delegated instructions from a supervisor agent and return structured results for supervisor synthesis.
|
||||
|
||||
<goal>
|
||||
Pull evidence from the live web with the web.* capability verbs and answer the delegated question, including "what changed" comparisons against evidence already in this conversation.
|
||||
</goal>
|
||||
|
||||
<available_tools>
|
||||
- `web_discover` — search the web for a query; returns ranked hits (url, title, snippet, provider).
|
||||
- `web_scrape` — fetch specific URLs; returns clean page content and metadata per URL.
|
||||
</available_tools>
|
||||
|
||||
<playbook>
|
||||
- If the request names exact URLs, call `web_scrape` on them directly.
|
||||
- If it does not, call `web_discover` first, pick the most relevant hits, then `web_scrape` those URLs to read them.
|
||||
- Batch URLs into a single `web_scrape` call when reading several pages (up to its limit) instead of many one-URL calls.
|
||||
- For "what changed" / monitoring requests, compare the freshly scraped values against the prior values already present in this conversation's earlier tool results, and report the concrete deltas (added, removed, changed old -> new). Do not claim a change you cannot point to.
|
||||
</playbook>
|
||||
|
||||
<tool_policy>
|
||||
- Use only tools in `<available_tools>`.
|
||||
- A `web_scrape` row with `status` other than `success` yielded no content — do not invent its content; report it as unavailable.
|
||||
- Never fabricate facts, URLs, prices, or quotes.
|
||||
</tool_policy>
|
||||
|
||||
<safety>
|
||||
- Report uncertainty explicitly when evidence is incomplete or conflicting.
|
||||
- Never present unverified claims as facts.
|
||||
</safety>
|
||||
|
||||
<failure_policy>
|
||||
- On tool failure, return `status=error` with a concise recovery `next_step`.
|
||||
- On no useful evidence, return `status=blocked` with a narrower query or the URLs you still need.
|
||||
</failure_policy>
|
||||
|
||||
<output_contract>
|
||||
Return **only** one JSON object (no markdown/prose):
|
||||
{
|
||||
"status": "success" | "partial" | "blocked" | "error",
|
||||
"action_summary": string,
|
||||
"evidence": {
|
||||
"findings": string[],
|
||||
"sources": string[],
|
||||
"confidence": "high" | "medium" | "low"
|
||||
},
|
||||
"next_step": string | null,
|
||||
"missing_fields": string[] | null,
|
||||
"assumptions": string[] | null
|
||||
}
|
||||
<include snippet="output_contract_base"/>
|
||||
Route-specific rules:
|
||||
- `evidence.findings`: max 10 entries, each a single sentence stating one distinct fact or delta. Do not paste raw scraped pages.
|
||||
- `evidence.sources`: max 10 URLs, one per finding when applicable. List each URL once.
|
||||
</output_contract>
|
||||
|
|
@ -0,0 +1 @@
|
|||
"""Intelligence-agent tools: the web.* capability verbs, generated from the registry."""
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
"""``intelligence_agent`` tools: web.* verbs generated from the capability registry."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from langchain_core.tools import BaseTool
|
||||
|
||||
from app.agents.chat.multi_agent_chat.shared.permissions import Ruleset
|
||||
from app.capabilities.access.agent import build_capability_tools
|
||||
from app.capabilities.web.discover.definition import WEB_DISCOVER
|
||||
from app.capabilities.web.scrape.definition import WEB_SCRAPE
|
||||
|
||||
NAME = "intelligence_agent"
|
||||
|
||||
RULESET = Ruleset(origin=NAME, rules=[])
|
||||
|
||||
_CI_VERBS = [WEB_DISCOVER, WEB_SCRAPE]
|
||||
|
||||
|
||||
def load_tools(
|
||||
*, dependencies: dict[str, Any] | None = None, **kwargs: Any
|
||||
) -> list[BaseTool]:
|
||||
d = {**(dependencies or {}), **kwargs}
|
||||
return build_capability_tools(
|
||||
workspace_id=d.get("workspace_id"),
|
||||
capabilities=_CI_VERBS,
|
||||
)
|
||||
|
|
@ -15,6 +15,9 @@ from app.agents.chat.multi_agent_chat.constants import (
|
|||
from app.agents.chat.multi_agent_chat.subagents.builtins.deliverables.agent import (
|
||||
build_subagent as build_deliverables_subagent,
|
||||
)
|
||||
from app.agents.chat.multi_agent_chat.subagents.builtins.intelligence_agent.agent import (
|
||||
build_subagent as build_intelligence_agent_subagent,
|
||||
)
|
||||
from app.agents.chat.multi_agent_chat.subagents.builtins.knowledge_base.agent import (
|
||||
build_subagent as build_knowledge_base_subagent,
|
||||
)
|
||||
|
|
@ -99,6 +102,7 @@ SUBAGENT_BUILDERS_BY_NAME: dict[str, SubagentBuilder] = {
|
|||
"dropbox": build_dropbox_subagent,
|
||||
"gmail": build_gmail_subagent,
|
||||
"google_drive": build_google_drive_subagent,
|
||||
"intelligence_agent": build_intelligence_agent_subagent,
|
||||
"jira": build_jira_subagent,
|
||||
"knowledge_base": build_knowledge_base_subagent,
|
||||
"linear": build_linear_subagent,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from app.agents.chat.multi_agent_chat.subagents.registry import (
|
|||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
# The full specialist roster the main agent composes from: 4 builtins + 15
|
||||
# The full specialist roster the main agent composes from: 5 builtins + 15
|
||||
# connector routes. Adding/removing a specialist is a deliberate product change
|
||||
# and must be reflected here.
|
||||
_EXPECTED_SUBAGENTS = frozenset(
|
||||
|
|
@ -33,6 +33,7 @@ _EXPECTED_SUBAGENTS = frozenset(
|
|||
"dropbox",
|
||||
"gmail",
|
||||
"google_drive",
|
||||
"intelligence_agent",
|
||||
"jira",
|
||||
"knowledge_base",
|
||||
"linear",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue