Files
openswarm/backend/tests/test_v2_label_logic.py
T

395 lines
13 KiB
Python

"""Mirror tests for the frontend label/result logic.
The JS implementations live in:
- frontend/src/app/pages/AgentChat/toolLabels.ts
- frontend/src/app/pages/AgentChat/ToolCallBubble.tsx (getResultSummary,
getInputSummary, parseMcpToolName, bashCommandDetail, prettyPath, prettyUrl,
quoteQuery)
We re-implement the rules in Python and pin them as tests so we get
regression coverage from `pytest` too. Any drift between the JS source
and these Python mirrors is the production-side breakage we want to
catch.
"""
from __future__ import annotations
import random
import re
import pytest
# =========================================================================== Mirror: parseMcpToolName.displayName (sentence-case rule) ===========================================================================
def parse_mcp_tool_name_display(raw_name: str) -> str | None:
"""Mirror of frontend parseMcpToolName().displayName."""
m = re.match(r"^mcp__([^_]+(?:-[^_]+)*)__(.+)$", raw_name)
if not m:
return None
action = m.group(2)
spaced = action.replace("_", " ").lower()
return spaced[0].upper() + spaced[1:] if spaced else ""
def test_parse_mcp_tool_name_get_message_details():
assert parse_mcp_tool_name_display(
"mcp__google-workspace__get_message_details"
) == "Get message details"
def test_parse_mcp_tool_name_send_email():
assert parse_mcp_tool_name_display(
"mcp__google-workspace__send_gmail_message"
) == "Send gmail message"
def test_parse_mcp_tool_name_search_emails():
assert parse_mcp_tool_name_display(
"mcp__google-workspace__query_gmail_emails"
) == "Query gmail emails"
def test_parse_mcp_tool_name_returns_none_for_non_mcp():
assert parse_mcp_tool_name_display("Bash") is None
assert parse_mcp_tool_name_display("Read") is None
def test_parse_mcp_tool_name_no_title_case():
"""Regression test: NEVER capitalize every word."""
bad = parse_mcp_tool_name_display("mcp__notion__create_a_new_page")
assert bad == "Create a new page"
assert "A New Page" not in bad
# =========================================================================== Mirror: getResultSummary (glyph-free regression test) ===========================================================================
def get_result_summary_bash_success(stdout: str, exit_code: int = 0) -> str:
"""Mirror of getResultSummary for bash success case."""
if exit_code != 0:
return f"exit {exit_code}"
lines = [l for l in stdout.split("\n") if l.strip()]
n = len(lines)
return f"{n} line{'s' if n != 1 else ''}"
def test_bash_success_summary_no_glyph():
"""Regression: bash success used to return '✓ N lines'. Must now be glyph-free."""
assert "✓" not in get_result_summary_bash_success("hello\nworld")
assert get_result_summary_bash_success("hello\nworld") == "2 lines"
assert get_result_summary_bash_success("just one line") == "1 line"
assert get_result_summary_bash_success("") == "0 lines"
def test_bash_failure_summary_no_glyph():
"""Failure summary too: 'exit 1' not '✗ exit 1'."""
assert get_result_summary_bash_success("", exit_code=1) == "exit 1"
assert "✗" not in get_result_summary_bash_success("", exit_code=1)
assert "✓" not in get_result_summary_bash_success("", exit_code=1)
def test_no_check_glyph_in_summaries():
"""Sweep: every plausible summary string never contains a check glyph."""
summaries = [
get_result_summary_bash_success("a"),
get_result_summary_bash_success("a\nb\nc"),
get_result_summary_bash_success("", exit_code=1),
get_result_summary_bash_success("", exit_code=127),
]
for s in summaries:
assert "✓" not in s and "✔" not in s and "✗" not in s and "✘" not in s
# =========================================================================== Mirror: bashCommandDetail extraction ===========================================================================
def bash_command_detail(raw_cmd: str) -> str:
"""Mirror of frontend bashCommandDetail."""
if not raw_cmd:
return ""
cmd = raw_cmd.strip()
# strip env var assignments + sudo/time/nice/env
cmd = re.sub(r"^(?:[A-Z_][A-Z0-9_]*=\S+\s+)+", "", cmd)
cmd = re.sub(r"^(?:sudo|time|nice|env)\s+", "", cmd)
tokens = cmd.split()
if not tokens:
return ""
bin_path = tokens[0].split("/")[-1]
if bin_path == "git":
sub = (tokens[1] if len(tokens) > 1 else "").lower()
if sub in ("commit", "status", "log", "diff", "pull", "push", "fetch"):
return ""
return tokens[2].split("/")[-1] if len(tokens) > 2 else ""
if bin_path in ("npm", "pnpm", "yarn", "bun", "pip", "pip3", "brew", "apt", "apt-get"):
if len(tokens) > 2:
args = [t for t in tokens[2:] if not t.startswith("-")][:2]
return " ".join(args)
return ""
# First non-flag positional arg
arg = next((t for t in tokens[1:] if not t.startswith("-")), "")
if not arg:
return ""
if "/" in arg or "\\" in arg:
# basename
cleaned = arg.rstrip("/\\")
parts = cleaned.replace("\\", "/").split("/")
return parts[-1] if parts[-1] else cleaned
return arg if len(arg) <= 50 else arg[:47] + "..."
def test_bash_detail_rm_extracts_path():
assert bash_command_detail("rm /tmp/foo.txt") == "foo.txt"
assert bash_command_detail("rm foo.txt") == "foo.txt"
def test_bash_detail_git_commit_empty():
"""git commit -m 'message' → no detail (verb covers it)."""
assert bash_command_detail("git commit -m 'fix bug'") == ""
assert bash_command_detail("git commit -m hi") == ""
def test_bash_detail_git_status_empty():
assert bash_command_detail("git status") == ""
def test_bash_detail_git_checkout_branch():
assert bash_command_detail("git checkout main") == "main"
def test_bash_detail_npm_install():
assert bash_command_detail("npm install lodash") == "lodash"
assert bash_command_detail("npm install lodash @types/node") == "lodash @types/node"
def test_bash_detail_strips_sudo():
assert bash_command_detail("sudo rm /etc/foo") == "foo"
def test_bash_detail_strips_env_assignments():
assert bash_command_detail("FOO=bar BAZ=qux rm /tmp/a") == "a"
def test_bash_detail_handles_empty():
assert bash_command_detail("") == ""
assert bash_command_detail(" ") == ""
# =========================================================================== Mirror: prettyPath (basename a path) ===========================================================================
def pretty_path(p: str) -> str:
if not p:
return ""
cleaned = p.rstrip("/\\")
parts = cleaned.replace("\\", "/").split("/")
return parts[-1] if parts[-1] else cleaned
def test_pretty_path_absolute():
assert pretty_path("/Users/eric/Downloads/openswarm/foo.ts") == "foo.ts"
def test_pretty_path_relative():
assert pretty_path("a/b/c.tsx") == "c.tsx"
def test_pretty_path_trailing_slash():
assert pretty_path("/a/b/c/") == "c"
def test_pretty_path_empty():
assert pretty_path("") == ""
# =========================================================================== Mirror: prettyUrl (host-only) ===========================================================================
def pretty_url(u: str) -> str:
if not u:
return ""
try:
from urllib.parse import urlparse
host = urlparse(u).hostname or ""
return host[4:] if host.startswith("www.") else host or u[:60]
except Exception:
no_proto = re.sub(r"^https?://", "", u).split("/")[0].split("?")[0].split("#")[0]
return no_proto[:60]
def test_pretty_url_https():
assert pretty_url("https://example.com/long/path?q=1") == "example.com"
def test_pretty_url_strips_www():
assert pretty_url("https://www.example.com/path") == "example.com"
def test_pretty_url_subdomain_kept():
assert pretty_url("https://api.example.com/v1") == "api.example.com"
def test_pretty_url_empty():
assert pretty_url("") == ""
# =========================================================================== Mirror: quoteQuery ===========================================================================
def quote_query(q: str, max_len: int = 60) -> str:
if not q:
return ""
trimmed = q if len(q) <= max_len else q[:max_len - 1] + "…"
return f'"{trimmed}"'
def test_quote_query_short():
assert quote_query("TODO") == '"TODO"'
def test_quote_query_long_truncated():
long = "a" * 100
result = quote_query(long)
assert result.startswith('"')
assert result.endswith('"')
assert len(result) <= 62 # 60 chars + 2 quotes
def test_quote_query_empty():
assert quote_query("") == ""
# =========================================================================== Mirror: stable-seeded variant pick (djb2 hash → mod n) ===========================================================================
def stable_index(seed: str | None, n: int) -> int:
"""Mirror of frontend _stableIndex."""
if n <= 1 or not seed:
return 0
h = 5381
for ch in seed:
h = ((h << 5) + h + ord(ch)) & 0xFFFFFFFF # 32-bit
# JS does `| 0` which produces signed int; Math.abs handles that
if h >= 0x80000000:
h -= 0x100000000
return abs(h) % n
def test_stable_index_same_seed_same_result():
"""Critical: same call.id always → same variant index."""
n = 5
for seed in ("abc-123", "xyz-789", "tool-call-uuid-deadbeef"):
a = stable_index(seed, n)
b = stable_index(seed, n)
c = stable_index(seed, n)
assert a == b == c, f"unstable for seed={seed!r}"
def test_stable_index_different_seeds_diverge():
"""Different seeds usually give different results (probabilistic)."""
n = 7
seeds = [f"seed-{i}-{random.randint(0, 99999)}" for i in range(50)]
indices = [stable_index(s, n) for s in seeds]
# All same is statistically extremely unlikely
assert len(set(indices)) > 1
def test_stable_index_in_range():
"""Index always in [0, n-1]."""
for _ in range(200):
seed = "".join(random.choices(string.ascii_letters + string.digits, k=20))
n = random.randint(2, 20)
idx = stable_index(seed, n)
assert 0 <= idx < n, f"out of range: {idx} for n={n}"
def test_stable_index_empty_seed_zero():
"""No seed → safe-default (index 0)."""
assert stable_index(None, 5) == 0
assert stable_index("", 5) == 0
def test_stable_index_n_one():
"""Single-variant pool → always index 0."""
assert stable_index("anything", 1) == 0
# =========================================================================== Mirror: bash verb extraction (the leading-binary lookup) ===========================================================================
BIN_VERB_MAP = {
"rm": ("Deleting", "Deleted"),
"mv": ("Moving", "Moved"),
"cp": ("Copying", "Copied"),
"mkdir": ("Creating folder", "Created folder"),
"ls": ("Listing folder", "Listed folder"),
"find": ("Hunting for files", "Hunted for files"),
"grep": ("Searching files", "Searched files"),
"cat": ("Reading", "Read"),
"echo": ("Printing", "Printed"),
"make": ("Building", "Built"),
}
GIT_VERB_MAP = {
"commit": ("Committing", "Committed"),
"push": ("Pushing to git", "Pushed to git"),
"pull": ("Pulling from git", "Pulled from git"),
"checkout": ("Switching branches", "Switched branches"),
"merge": ("Merging", "Merged"),
}
PKG_VERB_MAP_INSTALL = ("Installing packages", "Installed packages")
PKG_VERB_MAP_UNINSTALL = ("Removing packages", "Removed packages")
def bash_verb(cmd: str, past: bool = False):
if not cmd:
return None
stripped = re.sub(r"^(?:[A-Z_][A-Z0-9_]*=\S+\s+)+", "", cmd.strip())
stripped = re.sub(r"^(?:sudo|time|nice|env)\s+", "", stripped)
tokens = stripped.split()
if not tokens:
return None
bin_path = tokens[0].split("/")[-1].lower()
sub = (tokens[1] if len(tokens) > 1 else "").lower()
if bin_path == "git" and sub in GIT_VERB_MAP:
return GIT_VERB_MAP[sub][1 if past else 0]
if bin_path in ("npm", "pnpm", "yarn", "pip", "pip3", "brew"):
if sub in ("install", "add", "i"):
return PKG_VERB_MAP_INSTALL[1 if past else 0]
if sub in ("uninstall", "remove", "rm"):
return PKG_VERB_MAP_UNINSTALL[1 if past else 0]
if bin_path in BIN_VERB_MAP:
return BIN_VERB_MAP[bin_path][1 if past else 0]
return None
def test_bash_verb_rm_deleted():
assert bash_verb("rm foo", past=True) == "Deleted"
assert bash_verb("rm foo", past=False) == "Deleting"
def test_bash_verb_git_commit():
assert bash_verb("git commit -m hi", past=True) == "Committed"
def test_bash_verb_git_push():
assert bash_verb("git push origin main", past=True) == "Pushed to git"
def test_bash_verb_npm_install():
assert bash_verb("npm install lodash", past=True) == "Installed packages"
def test_bash_verb_unknown_returns_none():
"""Truly unknown command falls through to default 'Ran command'."""
assert bash_verb("supercustomtool foo bar") is None
def test_bash_verb_strips_sudo():
assert bash_verb("sudo rm -rf /tmp/x", past=True) == "Deleted"
def test_bash_verb_strips_env():
assert bash_verb("DEBUG=1 npm test", past=False) is None # 'test' isn't in pkg map for bash_verb
# string is needed for stable_index test
import string # noqa: E402