feat: remvoe other default tools
This commit is contained in:
@@ -169,14 +169,16 @@ _TOOL_CATEGORIES: dict[str, list[str]] = {
|
||||
# user-added custom queen IDs that we don't know about.
|
||||
|
||||
QUEEN_DEFAULT_CATEGORIES: dict[str, list[str]] = {
|
||||
# Head of Technology — builds and operates systems; full toolkit.
|
||||
# Head of Technology — builds and operates systems. Security tools
|
||||
# (port_scan, subdomain_enumerate, etc.) are intentionally NOT in the
|
||||
# default — users opt in via the Tool Library when an engagement
|
||||
# actually needs reconnaissance.
|
||||
"queen_technology": [
|
||||
"file_ops",
|
||||
"terminal_basic",
|
||||
"browser_basic",
|
||||
"browser_interaction",
|
||||
"research",
|
||||
"security",
|
||||
"time_context",
|
||||
],
|
||||
# Head of Growth — data, experiments, competitor research; no security.
|
||||
@@ -253,6 +255,49 @@ def has_role_default(queen_id: str) -> bool:
|
||||
return queen_id in QUEEN_DEFAULT_CATEGORIES
|
||||
|
||||
|
||||
def list_category_names() -> list[str]:
|
||||
"""Return every category name defined in the table, in declaration order."""
|
||||
return list(_TOOL_CATEGORIES.keys())
|
||||
|
||||
|
||||
def queen_role_categories(queen_id: str) -> list[str]:
|
||||
"""Return the category names assigned to ``queen_id`` by role default.
|
||||
|
||||
Returns an empty list for queens not in the persona table (they fall
|
||||
through to allow-all and have no implicit category membership).
|
||||
"""
|
||||
return list(QUEEN_DEFAULT_CATEGORIES.get(queen_id, []))
|
||||
|
||||
|
||||
def resolve_category_tools(
|
||||
category: str,
|
||||
mcp_catalog: dict[str, list[dict[str, Any]]] | None = None,
|
||||
) -> list[str]:
|
||||
"""Expand a single category to its concrete tool names.
|
||||
|
||||
Mirrors ``resolve_queen_default_tools`` but for a single category, so
|
||||
callers (e.g. the Tool Library API) can present per-category tool
|
||||
membership without re-implementing the ``@server:NAME`` shorthand
|
||||
expansion.
|
||||
"""
|
||||
names: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for entry in _TOOL_CATEGORIES.get(category, []):
|
||||
if entry.startswith("@server:"):
|
||||
server_name = entry[len("@server:") :]
|
||||
if mcp_catalog is None:
|
||||
continue
|
||||
for tool in mcp_catalog.get(server_name, []) or []:
|
||||
tname = tool.get("name") if isinstance(tool, dict) else None
|
||||
if tname and tname not in seen:
|
||||
seen.add(tname)
|
||||
names.append(tname)
|
||||
elif entry not in seen:
|
||||
seen.add(entry)
|
||||
names.append(entry)
|
||||
return names
|
||||
|
||||
|
||||
def resolve_queen_default_tools(
|
||||
queen_id: str,
|
||||
mcp_catalog: dict[str, list[dict[str, Any]]] | None = None,
|
||||
|
||||
@@ -35,6 +35,11 @@ from framework.agents.queen.queen_tools_config import (
|
||||
tools_config_exists,
|
||||
update_queen_tools_config,
|
||||
)
|
||||
from framework.agents.queen.queen_tools_defaults import (
|
||||
list_category_names,
|
||||
queen_role_categories,
|
||||
resolve_category_tools,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -326,10 +331,36 @@ async def handle_get_tools(request: web.Request) -> web.Response:
|
||||
mcp_tool_names_by_server=catalog,
|
||||
enabled_mcp_tools=enabled_mcp_tools,
|
||||
),
|
||||
"categories": _render_categories(queen_id, catalog),
|
||||
}
|
||||
return web.json_response(response)
|
||||
|
||||
|
||||
def _render_categories(
|
||||
queen_id: str,
|
||||
mcp_catalog: dict[str, list[dict[str, Any]]],
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Expose the role-default category table to the frontend.
|
||||
|
||||
Each entry carries the category name, the resolved member tool names
|
||||
(after ``@server:NAME`` shorthand expansion against the live catalog),
|
||||
and ``in_role_default`` to flag categories that contribute to this
|
||||
queen's role-based default. Lets the Tool Library group tools by
|
||||
category alongside the per-server view.
|
||||
"""
|
||||
applied = set(queen_role_categories(queen_id))
|
||||
out: list[dict[str, Any]] = []
|
||||
for name in list_category_names():
|
||||
out.append(
|
||||
{
|
||||
"name": name,
|
||||
"tools": resolve_category_tools(name, mcp_catalog),
|
||||
"in_role_default": name in applied,
|
||||
}
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
async def handle_patch_tools(request: web.Request) -> web.Response:
|
||||
"""PATCH /api/queen/{queen_id}/tools — persist the MCP tool allowlist.
|
||||
|
||||
|
||||
@@ -217,6 +217,41 @@ async def test_get_tools_applies_role_default(queen_dir, monkeypatch):
|
||||
assert "fluffy_unknown_tool" not in enabled
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_tools_exposes_categories(queen_dir, monkeypatch):
|
||||
"""Response includes the category catalog with role-default flags."""
|
||||
monkeypatch.setattr(routes_queen_tools, "ensure_default_queens", lambda: None)
|
||||
_, queen_id = queen_dir # queen_technology
|
||||
|
||||
manager = _FakeManager()
|
||||
manager._mcp_tool_catalog = {
|
||||
"files-tools": [
|
||||
{"name": "read_file", "description": "", "input_schema": {}},
|
||||
{"name": "edit_file", "description": "", "input_schema": {}},
|
||||
],
|
||||
}
|
||||
|
||||
app = await _make_app(manager=manager)
|
||||
async with TestClient(TestServer(app)) as client:
|
||||
resp = await client.get(f"/api/queen/{queen_id}/tools")
|
||||
assert resp.status == 200
|
||||
body = await resp.json()
|
||||
|
||||
cats = {c["name"]: c for c in body["categories"]}
|
||||
# Categories that contribute to queen_technology's role default
|
||||
assert cats["file_ops"]["in_role_default"] is True
|
||||
assert cats["browser_basic"]["in_role_default"] is True
|
||||
# Spreadsheet category is exposed even though queen_technology doesn't
|
||||
# use it — frontend can group/show it.
|
||||
assert "spreadsheet_advanced" in cats
|
||||
assert cats["spreadsheet_advanced"]["in_role_default"] is False
|
||||
# Security was removed from queen_technology defaults.
|
||||
assert cats["security"]["in_role_default"] is False
|
||||
# @server:files-tools shorthand expanded against the catalog.
|
||||
assert "read_file" in cats["file_ops"]["tools"]
|
||||
assert "edit_file" in cats["file_ops"]["tools"]
|
||||
|
||||
|
||||
def test_resolve_queen_default_tools_expands_server_shorthand():
|
||||
"""@server:NAME shorthand expands against the provided catalog."""
|
||||
from framework.agents.queen.queen_tools_defaults import resolve_queen_default_tools
|
||||
@@ -379,7 +414,10 @@ async def test_delete_restores_role_default(queen_dir, monkeypatch):
|
||||
manager._mcp_tool_catalog = {
|
||||
"files-tools": [
|
||||
{"name": "read_file", "description": "", "input_schema": {}},
|
||||
{"name": "port_scan", "description": "", "input_schema": {}},
|
||||
# pdf_read lives in hive_tools but is named explicitly in the
|
||||
# file_ops category, so we stage it in any server here just to
|
||||
# surface it through the catalog.
|
||||
{"name": "pdf_read", "description": "", "input_schema": {}},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -400,11 +438,14 @@ async def test_delete_restores_role_default(queen_dir, monkeypatch):
|
||||
assert body["is_role_default"] is True
|
||||
assert not tools_path.exists()
|
||||
|
||||
# The new effective list is the role default for queen_technology,
|
||||
# which includes both read_file (file_read) and port_scan (security).
|
||||
# The new effective list is the role default for queen_technology;
|
||||
# security tools were intentionally removed, so port_scan must NOT
|
||||
# appear, while file_ops members like read_file/pdf_read do.
|
||||
enabled = set(body["enabled_mcp_tools"] or [])
|
||||
assert "read_file" in enabled
|
||||
assert "port_scan" in enabled
|
||||
assert "pdf_read" in enabled
|
||||
assert "port_scan" not in enabled
|
||||
assert "subdomain_enumerate" not in enabled
|
||||
|
||||
# GET confirms.
|
||||
resp = await client.get(f"/api/queen/{queen_id}/tools")
|
||||
|
||||
@@ -28,6 +28,16 @@ export interface McpServerTools {
|
||||
tools: Array<ToolMeta & { enabled: boolean }>;
|
||||
}
|
||||
|
||||
export interface ToolCategory {
|
||||
/** Category id (e.g. "spreadsheet_advanced", "browser_basic"). */
|
||||
name: string;
|
||||
/** Concrete tool names that belong to this category, after expansion
|
||||
* of any ``@server:NAME`` shorthands against the live MCP catalog. */
|
||||
tools: string[];
|
||||
/** True when this category contributes to the queen's role-based default. */
|
||||
in_role_default: boolean;
|
||||
}
|
||||
|
||||
export interface QueenToolsResponse {
|
||||
queen_id: string;
|
||||
enabled_mcp_tools: string[] | null;
|
||||
@@ -39,6 +49,10 @@ export interface QueenToolsResponse {
|
||||
lifecycle: ToolMeta[];
|
||||
synthetic: ToolMeta[];
|
||||
mcp_servers: McpServerTools[];
|
||||
/** Curated category groupings (file_ops, browser_basic, security, …)
|
||||
* with resolved tool members. ``in_role_default`` flags categories
|
||||
* baked into this queen's default allowlist. */
|
||||
categories: ToolCategory[];
|
||||
}
|
||||
|
||||
export interface QueenToolsUpdateResult {
|
||||
|
||||
Reference in New Issue
Block a user