mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-10 22:32:16 +02:00
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>
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import type { TimelineItem, ToolCallItem } from "./types";
|
|
|
|
function asNonEmptyString(v: unknown): string | undefined {
|
|
return typeof v === "string" && v.trim().length > 0 ? v.trim() : undefined;
|
|
}
|
|
|
|
/**
|
|
* Explicit display labels for subagents whose title-cased id reads poorly.
|
|
* Legacy per-connector names (gmail, slack, ...) intentionally fall through
|
|
* to {@link titleCaseSubagent} so historical conversations keep their labels.
|
|
*/
|
|
const SUBAGENT_DISPLAY_LABELS: Record<string, string> = {
|
|
mcp_discovery: "Connected Apps",
|
|
};
|
|
|
|
/**
|
|
* Title-case a subagent identifier:
|
|
* "notion" → "Notion"
|
|
* "doc_research" → "Doc Research"
|
|
* "ux-review" → "Ux Review"
|
|
*/
|
|
export function titleCaseSubagent(raw: string): string {
|
|
return raw
|
|
.split(/[\s_-]+/)
|
|
.filter(Boolean)
|
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
.join(" ");
|
|
}
|
|
|
|
/**
|
|
* Display title for a tool-call item. For the ``task`` delegation
|
|
* primitive, substitute ``args.subagent_type`` (e.g. "Notion" instead
|
|
* of the generic "Task" label). Returns ``undefined`` if no rename
|
|
* applies — caller falls back to ``getToolDisplayName(toolName)``.
|
|
*/
|
|
export function resolveSubagentTitle(item: ToolCallItem): string | undefined {
|
|
if (item.toolName !== "task") return undefined;
|
|
const subagent = asNonEmptyString(item.args?.subagent_type);
|
|
if (!subagent) return undefined;
|
|
return SUBAGENT_DISPLAY_LABELS[subagent] ?? titleCaseSubagent(subagent);
|
|
}
|
|
|
|
/**
|
|
* Unified title resolver for any timeline item. Reasoning items use
|
|
* their own ``title``; tool-call items try the subagent rename first,
|
|
* then fall back to the resolver passed in (typically
|
|
* ``getToolDisplayName``).
|
|
*
|
|
* Pure: no React, no I/O. Trivially testable.
|
|
*/
|
|
export function resolveItemTitle(
|
|
item: TimelineItem,
|
|
getToolDisplayName: (toolName: string) => string
|
|
): string {
|
|
if (item.kind === "reasoning") return item.title;
|
|
return resolveSubagentTitle(item) ?? getToolDisplayName(item.toolName);
|
|
}
|