mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-08 22:22:17 +02:00
feat(subagents): add google_maps builtin subagent
This commit is contained in:
parent
f31823f765
commit
2c76ef1f57
9 changed files with 143 additions and 1 deletions
|
|
@ -28,6 +28,7 @@ SUBAGENT_TO_REQUIRED_CONNECTOR_MAP: dict[str, frozenset[str]] = {
|
|||
"knowledge_base": frozenset(),
|
||||
"web_crawler": frozenset(),
|
||||
"youtube": frozenset(),
|
||||
"google_maps": frozenset(),
|
||||
"airtable": frozenset({"AIRTABLE_CONNECTOR"}),
|
||||
"calendar": frozenset({"GOOGLE_CALENDAR_CONNECTOR"}),
|
||||
"clickup": frozenset({"CLICKUP_CONNECTOR"}),
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
"""``google_maps`` builtin subagent: structured Google Maps place/review data."""
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
"""``google_maps`` 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 "Pulls structured data from Google Maps — places and their reviews."
|
||||
)
|
||||
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 @@
|
|||
Google Maps specialist: pulls structured data from Google Maps — finds places by search query (optionally scoped to a location), or resolves a Maps URL / place ID into place details (name, address, category, phone, website, rating, review count, coordinates, opening hours), and fetches a place's reviews (author, text, star rating, owner response, dates). Also compares fresh Maps data against earlier findings in this chat.
|
||||
Use whenever the task involves Google Maps places, local businesses, or a google.com/maps link. Triggers include "find <business type> near/in X", "get details for this place", "phone/address/hours/rating of X", "how many reviews", "get the reviews for this place", "what are people saying about this business", and recurring "what changed" checks on Maps data. Not for general web pages (use the web crawling specialist) or YouTube (use the YouTube specialist).
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
You are the SurfSense Google Maps sub-agent.
|
||||
You receive delegated instructions from a supervisor agent and return structured results for supervisor synthesis.
|
||||
|
||||
<goal>
|
||||
Answer the delegated question from live Google Maps data gathered with your verbs, including "what changed" comparisons against evidence already in this conversation.
|
||||
</goal>
|
||||
|
||||
<available_tools>
|
||||
- `google_maps_scrape`
|
||||
- `google_maps_reviews`
|
||||
</available_tools>
|
||||
|
||||
<playbook>
|
||||
- Finding places on a topic: call `google_maps_scrape` with `search_queries`, adding `location` to scope them (e.g. "coffee shops" in "Austin, USA").
|
||||
- Known place links or IDs: call `google_maps_scrape` with the links in `urls` or the IDs in `place_ids`.
|
||||
- Need richer detail (opening hours, popular times, extra contact info): set `include_details=true`.
|
||||
- Reviews / sentiment on specific places: call `google_maps_reviews` with the place `urls` or `place_ids`.
|
||||
- Batch multiple queries, URLs, or place IDs into one call rather than many single-item calls.
|
||||
- "What changed" / monitoring: pull the current values, compare against the prior values in this conversation's earlier tool results, and report concrete deltas (added, removed, old -> new).
|
||||
</playbook>
|
||||
|
||||
<tool_policy>
|
||||
- Use only tools in `<available_tools>`.
|
||||
- An item whose `status` is not `success` returned no data — report it unavailable, never invent it.
|
||||
- Report only deltas you can point to in the evidence. Never fabricate facts, counts, quotes, ratings, or URLs.
|
||||
</tool_policy>
|
||||
|
||||
<out_of_scope>
|
||||
- Do not generate deliverables or perform connector mutations; return findings for the supervisor to act on.
|
||||
- Non-Maps web pages belong to the web crawling specialist; YouTube belongs to the YouTube specialist.
|
||||
</out_of_scope>
|
||||
|
||||
<safety>
|
||||
- Report uncertainty explicitly when evidence is incomplete or conflicting.
|
||||
- Never present unverified claims as facts.
|
||||
</safety>
|
||||
|
||||
<failure_policy>
|
||||
- Underspecified request — no usable search query, URL, or place ID — return `status=blocked` with the missing fields.
|
||||
- Tool failure: return `status=error` with a concise recovery `next_step`.
|
||||
- No useful evidence: return `status=blocked` with a narrower query or the URLs/IDs 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 payloads.
|
||||
- `evidence.sources`: max 10 URLs, one per finding when applicable. List each URL once.
|
||||
</output_contract>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
"""``google_maps`` sub-agent tools: the Google Maps scrape + reviews capability verbs."""
|
||||
|
||||
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.core.access.agent import build_capability_tools
|
||||
from app.capabilities.google_maps.reviews.definition import GOOGLE_MAPS_REVIEWS
|
||||
from app.capabilities.google_maps.scrape.definition import GOOGLE_MAPS_SCRAPE
|
||||
|
||||
NAME = "google_maps"
|
||||
|
||||
RULESET = Ruleset(origin=NAME, rules=[])
|
||||
|
||||
_CI_VERBS = [GOOGLE_MAPS_SCRAPE, GOOGLE_MAPS_REVIEWS]
|
||||
|
||||
|
||||
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.google_maps.agent import (
|
||||
build_subagent as build_google_maps_subagent,
|
||||
)
|
||||
from app.agents.chat.multi_agent_chat.subagents.builtins.knowledge_base.agent import (
|
||||
build_subagent as build_knowledge_base_subagent,
|
||||
)
|
||||
|
|
@ -102,6 +105,7 @@ SUBAGENT_BUILDERS_BY_NAME: dict[str, SubagentBuilder] = {
|
|||
"dropbox": build_dropbox_subagent,
|
||||
"gmail": build_gmail_subagent,
|
||||
"google_drive": build_google_drive_subagent,
|
||||
"google_maps": build_google_maps_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: 5 builtins + 15
|
||||
# The full specialist roster the main agent composes from: 6 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",
|
||||
"google_maps",
|
||||
"jira",
|
||||
"knowledge_base",
|
||||
"linear",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue