MCP consolidation:
- Route all MCP-capable connectors (Slack, Jira, Linear, ClickUp, Airtable,
Notion, Confluence, interim Gmail/Calendar, custom MCP) through a single
`mcp_discovery` subagent. Drive/OneDrive/Dropbox stay native to enrich the KB.
- Deprecate Discord/Teams/Luma: no viable official MCP server.
Google-only web search:
- Remove the main-agent `web_search` tool and the SearXNG platform service;
all public web search now flows through the `google_search` subagent via task().
- Deprecate the Tavily/SearXNG/Linkup/Baidu search connectors (HTTP 410 on
create, "Deprecated" badge); guide heavy users to the custom MCP connector.
- Remove web search from anonymous chat (pure Q&A).
- Tear SearXNG out of docker compose + install scripts; drop tavily-python
and linkup-sdk deps and their config/env vars.
Fix:
- metrics._package_version() now swallows any metadata lookup failure. A
malformed editable-install distribution with no `Version` field raised
KeyError deep in importlib.metadata, and since it runs on every
record_subagent_invoke_duration call it was crashing every task()
delegation. Verified end-to-end against live GPT-5.4.
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve conflicts against the new native google-maps actor + repo-wide
ruff-format pass:
- Keep legacy webcrawler KB indexer + its test deleted (modify/delete).
- test_validators: keep WEBCRAWLER case removed (validator gone).
- test_fetch_resilience: keep platforms.youtube import path (our reorg).
- Relocate google_maps actor + tests scrapers/ -> platforms/ to match the
reorg convention (youtube already there); rewrite imports + fixture paths.
- Add missing __init__.py across the capabilities/ test subtree so duplicate
test basenames get unique module paths under importlib mode.
Note: google_maps fixture-backed tests error on ci_mvp too (fixtures/*.json
never committed upstream) - pre-existing, out of scope here.
Apply the same rename to surfsense_backend/tests: workspace_id fields/vars,
Workspace* classes/schemas, table name searchspaces -> workspaces in raw SQL,
and the API URL spellings -> /workspaces. Preserves the carve-out wire literals
tests assert (Celery task names, OTel key "search_space.id").
Phase 1 (rename DB) commit 1i: rename the SearchSpace table to workspaces
and flip all 24 inbound FK target strings (20 in db.py + the 4 satellite
models), plus the raw-SQL searchspaces references in the obsidian and
google-unification integration fixtures.
This completes the ORM half of Phase 1. The SearchSpace class name,
relationship/back_populates attribute names, and the /searchspaces API
route URLs are intentionally left for Phase 2.
Verified: unit 2375 passed/1 skip, integration 346 passed (baseline
parity); create_all builds every table with the workspaces name and all
FKs resolving to workspaces.id.
Phase 1 (rename DB) commit 1h: rename the roles table and flip both
inbound FKs (memberships.role_id, invites.role_id), plus the matching
raw-SQL cleanup in the obsidian plugin test.
Phase 1 (rename DB) commit 1g: rename the memberships table (no inbound
FKs reference it) and update the matching raw-SQL cleanup in the obsidian
plugin test. Relationship attribute names stay until Phase 2.
Phase 1 (rename DB) commit 1a: shim every search_space_id /
owner_search_space_id column to the renamed physical column
(workspace_id / owner_workspace_id) via Column("workspace_id", ...),
keeping the ORM attribute name unchanged so existing callers are
untouched. Flip all Table-level references that resolve by column key
(inner __table_args__ strings, the ck_connections_scope_owner CHECK
text, and the _INDEX_DEFINITIONS runtime DDL) plus the searchspace-named
constraint/index names to workspace_id. Update the three raw-SQL test
fixtures that referenced the physical column.
Note: SQLAlchemy defaults a column's key to its name, so passing an
explicit "workspace_id" name moves the Table.c key to workspace_id;
Table-level string refs must therefore change in this phase (the
opposite of the original plan's finding 1). The ORM attribute, the
SearchSpace class, relationships, table names, and FK target strings are
intentionally left for later commits/Phase 2.
Verified: unit 2375 passed/1 skip, integration 346 passed (baseline
parity); create_all builds every table with workspace_id.
- Updated main-agent middleware to clarify that both filesystem reads/writes and knowledge-base retrieval are handled by the `knowledge_base` subagent.
- Introduced `_forward_mention_pins` function to carry `@`-mention pins into subagent state.
- Revised system prompts to reflect the new retrieval method and ensure proper citation handling.
- Removed the `search_knowledge_base` tool and its related tests, consolidating functionality under the `task` tool.
- Enhanced documentation to guide usage of the new retrieval approach and citation practices.
The pull-based KB design (on-demand search_knowledge_base tool + pre-injected
workspace tree) fully replaced the old eager retrieval path. Remove its last
remnants:
- Delete KnowledgePriorityMiddleware (knowledge_search.py) and its tests.
- Drop the kb_priority state field + reducer default; trim
KbContextProjectionMiddleware to project only workspace_tree_text.
- Remove the now-dead feature flags enable_kb_priority_preinjection and
enable_kb_planner_runnable across backend (flags, route schema, tests,
env examples) and frontend (settings toggle, zod schema).
- Scrub <priority_documents> and stale KnowledgePriorityMiddleware references
from prompts, docstrings, and the ADR.
No functional change: nothing wrote kb_priority and neither flag gated live
behavior after the cutover. Full backend suite green (pre-existing unrelated
failures aside).
Rewrite the main-agent citation contract to a single [n] channel and sync
the orphaned system_prompt_composer surface to match; drop stale
[citation:chunk_id] / <chunk_index> references from dynamic_context and
provider hints. Reuse the shared hybrid search in the deliverables report
(citations omitted for now) and delete the orphaned report KB helper.
Remove the dead eager KnowledgePriorityMiddleware wiring (knowledge_priority
+ stack) and its legacy browse test. Update ADR 0001 to reflect the cutover.
The main agent's search_knowledge_base tool runs the hybrid spine, renders
a <retrieved_context> of numbered [n] passages, and persists the registry.
KB subagent prompts teach citing [n] from <document view="full"> reads
(evidence.chunk_ids -> evidence.citations). Delete the now-unused
search->read highlighting hand-off: the kb_matched_chunk_ids state field,
its reducer default, the tool's _matched_chunk_ids writer, and the dead
KnowledgePriorityMiddleware writes.
Two integration tests pinning the connector index endpoint's authorization:
- cross-space index (attacker owns space B, connector lives in victim's
space A, request passes search_space_id=B) is rejected with 404 at the
search-space reconciliation, before the permission check (which would
otherwise pass for the attacker's own space).
- same-space index authorizes check_permission against the connector's
own search space, not the caller-supplied query param.
Mirrors the existing tests/integration harness (direct handler calls with
the savepoint-rolled-back db_session; check_permission patched so the test
needs no real RBAC wiring).