Files
DemonGatanjieu-Anomalous_Mo…/tests/test_tool_budget.py
T
DemonGatanjieuandClaude Opus 5.5 6289e895ee Take a misnamed needed argument as meant; second Flash exam
A call lacking its one needed argument but carrying one unknown
argument of that type is run with it (open_workflow {name} is
{workflow}), and the AI is told the right name. The timeline names
zoom_image steps; a test makes every tool have a name in both
languages. tool-exam.md records the second exam, all eight tasks
including the repaint one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 20:23:03 +08:00

52 lines
2.3 KiB
Python

"""The tool budget: what AI apps are handed stays small enough for a light model (Gemini Flash is the
yardstick). On 2026-10-26 Gemini 3.8 Flash ran about 570 calls over the full set in Antigravity with
hardly a wrong one, so the set as it is, is the ceiling: a new tool, or a longer description, has to
make room by merging or cutting. Raise a number here only together with a new Flash run that
shows it still goes well (docs/architecture/tool-exam.md)."""
import json
import sys
import unittest
from pathlib import Path
PLUGIN = Path(__file__).resolve().parents[1]
sys.path[:0] = [str(PLUGIN), str(PLUGIN.parents[1])]
from api import mcp_server # noqa: E402
MAX_TOOLS = 53
MAX_CHARS = 44000 # the full list as AI apps get it (about 11k tokens)
MAX_DESCRIPTION = 700 # a tool's own description
LONGER = {"show_panel": 2100} # its blocks have no schema of their own: the description is their format
MAX_REQUIRED = 2 # what a call needs at least; the rest has a default
INSTRUCTIONS_CHARS = 3400
def listed():
return mcp_server._tool_list(True)["tools"]
class BudgetTests(unittest.TestCase):
def test_the_set_does_not_grow(self):
tools = listed()
self.assertLessEqual(len(tools), MAX_TOOLS, "a new tool: merge or cut one")
self.assertLessEqual(len(json.dumps(tools, ensure_ascii=False)), MAX_CHARS)
self.assertLessEqual(len(mcp_server.INSTRUCTIONS), INSTRUCTIONS_CHARS)
def test_each_tool_is_short_and_needs_little(self):
for tool in listed():
with self.subTest(tool=tool["name"]):
self.assertLessEqual(len(tool.get("description") or ""), LONGER.get(tool["name"], MAX_DESCRIPTION))
self.assertLessEqual(len(tool["inputSchema"].get("required") or []), MAX_REQUIRED)
self.assertTrue(tool.get("description"), "every tool says what it is for")
def test_each_step_has_a_name_in_both_languages(self):
# The timeline names a step by aiTool_<tool> (web/modules/ai_task_view.js toolKey); the card's own calls are not steps.
words = (PLUGIN / "web" / "modules" / "locales.js").read_text(encoding="utf-8")
for name in set(mcp_server.TOOLS) - set(mcp_server.mcp_apps.APP_TOOLS):
with self.subTest(tool=name):
self.assertEqual(words.count(f"aiTool_{name}:"), 2)
if __name__ == "__main__":
unittest.main()