56 lines
2.4 KiB
Python
56 lines
2.4 KiB
Python
"""Keep optional retrieval guidance consistent across the Python and TS hosts."""
|
|
|
|
import ast
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
INTEGRATIONS = ROOT.parent
|
|
|
|
|
|
def test_python_and_typescript_share_the_same_search_guidance():
|
|
tree = ast.parse((ROOT / "python/mcp_server.py").read_text())
|
|
guidance = next(
|
|
ast.literal_eval(node.value)
|
|
for node in tree.body
|
|
if isinstance(node, ast.Assign) and any(getattr(t, "id", "") == "SEARCH_GUIDANCE" for t in node.targets)
|
|
)
|
|
typescript = (ROOT / "typescript/src/search_guidance.ts").read_text()
|
|
ts_guidance = "".join(json.loads(value) for value in re.findall(r'"(?:[^"\\]|\\.)*"', typescript))
|
|
assert guidance == ts_guidance
|
|
assert "skip another search when the context already answers it" in guidance
|
|
assert "Search again only if a specific gap remains" in guidance
|
|
for relative in (
|
|
"opencode-plugin/opencode-mem0.ts",
|
|
"pi-agent-plugin/src/prompt.ts",
|
|
"pi-agent-plugin/src/memory/tools.ts",
|
|
"openclaw/tools/memory-search.ts",
|
|
"openclaw/skill-loader.ts",
|
|
"deepseek-plugin/src/index.ts",
|
|
):
|
|
source = (INTEGRATIONS / relative).read_text()
|
|
assert 'import {SEARCH_GUIDANCE}' in source or 'import { SEARCH_GUIDANCE }' in source, relative
|
|
assert source.count("SEARCH_GUIDANCE") >= 2, relative
|
|
|
|
|
|
def test_prompts_do_not_require_speculative_or_repeated_searches():
|
|
sources = [ROOT / "python/mcp_server.py", ROOT / "skills/search/SKILL.md.tmpl"]
|
|
for plugin in (
|
|
"claude-code-plugin", "cursor-plugin", "codex-plugin", "kimi-plugin", "antigravity-plugin",
|
|
"opencode-plugin", "pi-agent-plugin", "openclaw", "deepseek-plugin",
|
|
):
|
|
for path in (INTEGRATIONS / plugin).rglob("*"):
|
|
if {"node_modules", "dist", "core"} & set(path.parts) or ".test." in path.name:
|
|
continue
|
|
if path.suffix in {".md", ".ts"} and path.name != "README.md":
|
|
sources.append(path)
|
|
strict = re.compile(
|
|
r"always call .{0,35}search|search memory before answering|proactively before answering|"
|
|
r"multi-hop|run (?:2-4|2|several) (?:parallel )?(?:`search_memories` calls|searches)|"
|
|
r"one search is rarely enough|always rewrite the query",
|
|
re.IGNORECASE,
|
|
)
|
|
for path in sources:
|
|
assert not strict.search(" ".join(path.read_text().split())), path
|