mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 12:17:45 +02:00
[shawn] chore: drop unused private helpers from agent_manager.py
Removed: - _build_connected_tools_context (L452, 96 lines) - _approx_tokens (L939, 7 lines) - _summarize_message_block (L947, 57 lines) Verified zero callers via: grep -rn '_build_connected_tools_context' backend electron frontend/src grep -rn '_approx_tokens' backend electron frontend/src grep -rn '_summarize_message_block' backend electron frontend/src All three return only the definition line. 802 tests pass.
This commit is contained in:
@@ -449,103 +449,6 @@ class AgentManager:
|
||||
logger.info(f"[MCP-DEBUG] Final mcp_servers: {list(mcp_servers.keys())}")
|
||||
return mcp_servers
|
||||
|
||||
def _build_connected_tools_context(self, allowed_tools: list[str]) -> str | None:
|
||||
"""Build a context block describing connected MCP tools and their accounts.
|
||||
|
||||
Tools set to 'deny' and fully-denied servers are excluded.
|
||||
"""
|
||||
all_tools = load_all_tools()
|
||||
mcp_tools = [t for t in all_tools if t.mcp_config and t.enabled and t.auth_status in ("configured", "connected")]
|
||||
|
||||
sections = []
|
||||
for tool in mcp_tools:
|
||||
tool_ref = f"mcp:{tool.name}"
|
||||
if tool_ref not in allowed_tools and allowed_tools != get_all_tool_names():
|
||||
continue
|
||||
|
||||
if _is_fully_denied(tool):
|
||||
continue
|
||||
|
||||
server_name = _sanitize_server_name(tool.name)
|
||||
denied = _get_denied_tool_names(tool)
|
||||
tool_descs = {
|
||||
k: v for k, v in tool.tool_permissions.get("_tool_descriptions", {}).items()
|
||||
if k not in denied
|
||||
}
|
||||
if not tool_descs:
|
||||
continue
|
||||
|
||||
lines = [f"MCP Server: {server_name}"]
|
||||
lines.append(f" Status: {tool.auth_status}")
|
||||
|
||||
if tool.connected_account_email:
|
||||
lines.append(f" Connected account: {tool.connected_account_email}")
|
||||
lines.append(
|
||||
f" IMPORTANT: When calling tools from this server that require an email "
|
||||
f"parameter (e.g. user_google_email, user_email), always use "
|
||||
f"\"{tool.connected_account_email}\" automatically — do NOT ask the user."
|
||||
)
|
||||
|
||||
# Instagram and LinkedIn enforce strict per-account rate limits to
|
||||
# prevent platform bans. When a tool call comes back with
|
||||
# rate_limited: true OR a deny reason mentioning "RATE LIMIT HIT",
|
||||
# the agent MUST stop the task, tell the user the retry-after, and
|
||||
# NOT retry. Without this guidance, agents tend to loop trying
|
||||
# alternative tools or even shell out to filesystem search.
|
||||
if tool.name.lower() in ("instagram", "linkedin", "telegram"):
|
||||
lines.append(
|
||||
f" RATE LIMIT BEHAVIOR (HARD RULE): If a {tool.name} tool returns "
|
||||
"rate_limited: true, or any tool call here returns a 'deny' with "
|
||||
"'RATE LIMIT HIT' in the message, this is FINAL for the current turn. "
|
||||
"Do NOT retry the same tool. Do NOT try alternative tools to accomplish "
|
||||
"the same goal. Do NOT shell out to Bash/curl/find to look up the package "
|
||||
"source. Tell the user the retry-after time in plain English and END the "
|
||||
"task. Looping makes the platform ban risk worse, not better."
|
||||
)
|
||||
|
||||
# Discord guild scoping — hard restriction. The bot may technically
|
||||
# be in other servers (across other OpenSwarm users), but this
|
||||
# specific user only authorized these guild IDs.
|
||||
if tool.name.lower() == "discord":
|
||||
guilds = tool.oauth_tokens.get("guilds") or []
|
||||
if guilds:
|
||||
guild_descriptions = ", ".join(
|
||||
f"{g.get('name', 'Unknown')} ({g.get('id', '')})" for g in guilds
|
||||
)
|
||||
allowed_ids = [g.get("id", "") for g in guilds if g.get("id")]
|
||||
lines.append(
|
||||
f" AUTHORIZED DISCORD SERVERS (guild_ids): {guild_descriptions}"
|
||||
)
|
||||
lines.append(
|
||||
f" HARD RESTRICTION: You MUST only call Discord tools that operate on "
|
||||
f"these guild_ids: {allowed_ids}. NEVER call Discord tools on any other "
|
||||
f"guild_id even if the bot has access to it. NEVER list, search, or "
|
||||
f"enumerate servers outside this list. If a user asks about a server "
|
||||
f"not in this list, refuse and tell them to authorize it via the Connect "
|
||||
f"Discord button. This is a security boundary, not a preference."
|
||||
)
|
||||
else:
|
||||
lines.append(
|
||||
f" No Discord servers authorized yet. Tell the user to click "
|
||||
f"'Connect Discord' to add a server before attempting any Discord actions."
|
||||
)
|
||||
|
||||
tool_names = list(tool_descs.keys())
|
||||
if tool_names:
|
||||
lines.append(f" Available tools ({len(tool_names)}): {', '.join(tool_names)}")
|
||||
|
||||
sections.append("\n".join(lines))
|
||||
|
||||
if not sections:
|
||||
return None
|
||||
return (
|
||||
"<connected_mcp_tools>\n"
|
||||
"The following MCP tool servers are connected and available. "
|
||||
"Use them directly when relevant to the user's request.\n\n"
|
||||
+ "\n\n".join(sections)
|
||||
+ "\n</connected_mcp_tools>"
|
||||
)
|
||||
|
||||
def _build_browser_context(self, dashboard_id: str | None, selected_browser_ids: list[str] | None = None) -> str | None:
|
||||
"""Build a context block listing browser cards and delegation instructions.
|
||||
|
||||
@@ -935,72 +838,6 @@ class AgentManager:
|
||||
# surfaces from the catch-all
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _approx_tokens(text: str) -> int:
|
||||
"""Conservative chars/4 estimate. Used for the pre-send guard
|
||||
and the compaction trigger when a precise count_tokens isn't
|
||||
cheap (or the route isn't Anthropic). Errs slightly high so we
|
||||
compact a touch earlier than strictly necessary."""
|
||||
return max(1, len(text or "") // 4)
|
||||
|
||||
@staticmethod
|
||||
def _summarize_message_block(messages: list) -> str:
|
||||
"""Programmatic, no-LLM summary of a message slice. Mirrors the
|
||||
shape of browser_agent._summarize_messages: extracts the original
|
||||
user task, counts tool calls, captures the last assistant text.
|
||||
Cheap, deterministic, and never makes a network call — so
|
||||
compaction itself adds zero latency to the user's turn.
|
||||
"""
|
||||
if not messages:
|
||||
return ""
|
||||
|
||||
initial_task = ""
|
||||
for m in messages:
|
||||
if getattr(m, "role", "") == "user":
|
||||
content = getattr(m, "content", "")
|
||||
txt = content if isinstance(content, str) else str(content)
|
||||
if txt.strip():
|
||||
initial_task = txt.strip()[:400]
|
||||
break
|
||||
|
||||
tool_calls_by_name: dict[str, int] = {}
|
||||
last_tool_results = 0
|
||||
last_assistant_text = ""
|
||||
for m in messages:
|
||||
role = getattr(m, "role", "")
|
||||
if role == "tool_call":
|
||||
content = getattr(m, "content", {}) or {}
|
||||
name = (content.get("tool") if isinstance(content, dict) else None) or "unknown"
|
||||
tool_calls_by_name[name] = tool_calls_by_name.get(name, 0) + 1
|
||||
elif role == "tool_result":
|
||||
last_tool_results += 1
|
||||
elif role == "assistant":
|
||||
content = getattr(m, "content", "")
|
||||
if isinstance(content, str) and content.strip():
|
||||
last_assistant_text = content.strip()
|
||||
elif isinstance(content, list):
|
||||
for block in content:
|
||||
if isinstance(block, dict) and block.get("type") == "text":
|
||||
txt = (block.get("text") or "").strip()
|
||||
if txt:
|
||||
last_assistant_text = txt
|
||||
|
||||
parts = ["<compacted_history>"]
|
||||
parts.append("[The following is a programmatic summary of earlier turns in this session. Originals are preserved on disk and viewable via the chat UI's compaction drawer.]")
|
||||
if initial_task:
|
||||
parts.append(f'Initial user request: "{initial_task}"')
|
||||
if tool_calls_by_name:
|
||||
total = sum(tool_calls_by_name.values())
|
||||
top = sorted(tool_calls_by_name.items(), key=lambda kv: -kv[1])[:8]
|
||||
parts.append(f"Tool calls so far ({total} total): " + ", ".join(f"{n}×{c}" for n, c in top))
|
||||
if last_tool_results:
|
||||
parts.append(f"Tool results received: {last_tool_results}")
|
||||
if last_assistant_text:
|
||||
parts.append("Last assistant message:")
|
||||
parts.append(last_assistant_text[:1200])
|
||||
parts.append("</compacted_history>")
|
||||
return "\n".join(parts)
|
||||
|
||||
def _maybe_compact(self, session: AgentSession, force: bool = False) -> bool:
|
||||
"""Run summarizer when ctx_used_pct >= compact_threshold_pct (or force).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user