Correct a needed argument only from a known other name

A value of the right type under an unknown name may mean something
else (set_prompt {style: "anime"} is no prompt), so the correction now
takes only the other names light models were seen to write in the tool
exams (name/workflow_name, file/filename/image_name, text/positive,
model/id, node/id); any other name is answered with what the tool takes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DemonGatanjieu
2026-10-26 21:34:04 +08:00
co-authored by Claude Opus 5.5
parent db405a79f0
commit 1b03553946
5 changed files with 23 additions and 7 deletions
+2 -2
View File
@@ -9,7 +9,7 @@
- Fixed task resumption and answer waiting: resume by the latest unread user reply, including panel answers, rather than background updates; a task with a tool still running is excluded from automatic takeover. Reading answers without a panel now handles expired questions too. Timeout choices and user answers arriving at that boundary reach the AI in the same call; messages and pictures sent while it waits for a question are no longer consumed without delivery.
- AI 少走弯路、少猜:
- 只差一个必填参数、又正好多写了一个名字不对的参数(比如打开工作流时把 `workflow` 写成 `name`)时,AMB 直接照它的意思做,并告诉 AI 正确的名字,省一次来回。
- AI 把必填参数写成了常见的另一个名字(比如打开工作流时把 `workflow` 写成 `name`、看图时把 `image` 写成 `file`)时,AMB 直接照它的意思做,并告诉 AI 正确的名字,省一次来回。只认考试里见过的这几种叫法;别的名字照旧报错、列出该写什么,免得猜错意思。
- 时间线里 AI“放大看图”那一步显示成代码名,改成了中文名。
- 去掉了“给 AI 的工具”里的 **日常**:所有工具都直接给。Antigravity、Claude Code、Cursor、VS Code 这些软件会自己按需读工具说明,AMB 再做一层“现查现用”只会让 AI 多绕路(一次实测 29 次调用里 18 次花在查工具和转一道上)。
- AMB 更新以后,AI 软件还拿着旧的工具列表来调用时,任务标题下面会出现一行黄字,告诉你怎么让它重新连接;AI 那边也收到同样的提醒。AI 软件重新取了列表,黄字自己消失。
@@ -20,7 +20,7 @@
- 很久以前(两个多小时前)留下、AI 一直没收到的留言或标注,不再把一个新对话拉进那个旧任务。
- 关卡窗口新增 **等不到回答时**:**停下等我**(默认)或 **按推荐的继续**。选后者时,到了等待时间你还没答,AI 标了推荐项的选择题就按推荐的选,展台和“决策”里都写着“到时间,按推荐选了”;没有推荐项的问题、你已经动手写了回答的问题、关卡里“先问我”的事,永远不会替你答。
- The AI takes fewer detours and guesses less:
- When a call lacks its one needed argument and has one unknown argument of the right type instead (`name` for open_workflow's `workflow`), Anomalous takes it as meant and tells the AI the right name, saving a round trip.
- When a call writes its one needed argument under a known other name (`name` for open_workflow's `workflow`, `file` for `image`), Anomalous takes it as meant and tells the AI the right name, saving a round trip. Only the names seen in the exams count; any other is answered with what the tool takes, so no meaning is guessed.
- The timeline names the AI's "look closer at a picture" step instead of showing its code name.
- The tool set's **Daily** choice is gone: AI apps get every tool. Antigravity, Claude Code, Cursor and VS Code load tool descriptions as they need them, so looking tools up through Anomalous only added detours (in one run 18 of 29 calls).
- When an AI app still calls by the tool list of an older Anomalous, a yellow line under the task header says how to reconnect it, and the AI is told too; it goes once the app fetches the list again.
+15 -1
View File
@@ -1,5 +1,17 @@
"""Normalize an unambiguous argument name before approval, execution and task recording."""
"""Normalize an unambiguous argument name before approval, execution and task recording.
Only a known other name counts (ALIASES, names light models were seen to write in the tool exams,
docs/architecture/tool-exam.md): a value of the right type under any other name may mean something
else (set_prompt {style: "anime"} is not a prompt), and that call is answered with what the tool takes.
"""
ALIASES = { # needed argument -> other names that mean it
"workflow": {"name", "workflow_name"},
"image": {"file", "filename", "image_name"},
"prompt": {"text", "positive"},
"model_id": {"model", "id"},
"node_id": {"node", "id"},
}
JSON_TYPES = {"string": (str,), "integer": (int,), "number": (int, float), "boolean": (bool,), "array": (list,), "object": (dict,)}
@@ -10,6 +22,8 @@ def prepare_arguments(spec, arguments):
if len(unknown) != 1 or len(missing) != 1:
return arguments, None
wrong, right = next(iter(unknown)), missing[0]
if wrong not in ALIASES.get(right, ()):
return arguments, None
kinds = JSON_TYPES.get(spec["properties"][right].get("type"))
value = arguments[wrong]
if not kinds or not isinstance(value, kinds) or (isinstance(value, bool) and bool not in kinds):
+3 -1
View File
@@ -335,7 +335,9 @@ supported list. `initialize` selects the legacy shape (2025-03-26 to 2025-11-25)
session id is minted, so both eras are stateless. Unknown methods are -32601 (404 for
modern requests).
`api/mcp_arguments.py` owns unambiguous required-argument renaming. The MCP server normalizes
`api/mcp_arguments.py` owns unambiguous required-argument renaming: one needed argument missing,
one unknown argument whose name is a known other name for it (ALIASES, from the tool exams) and
whose value has its type. A same-typed value under any other name is not taken. The MCP server normalizes
before recording a step or checking a gate, so the approval signature, displayed arguments,
execution and result references all use the same names. Direct `mcp_tools.call_tool` callers
use the same normalization; the successful receipt tells the AI which name was corrected.
+1 -1
View File
@@ -70,6 +70,6 @@ AMB 给 AI 软件的工具,以轻量模型(Gemini Flash)能顺畅用为准
注意:`ask_user`、`get_answers` 参数写错时不进时间线,分数里也就没有(第 3 题的那次是从 Antigravity 的记录里数的)。
据此改了:只差一个必填参数、又正好多了一个不认识的参数、值的类型也对得上时,AMB 把它当成那个必填参数(`open_workflow {name: …}` 就是 `{workflow: …}`),回复里写一句"把 name 当成了 workflow",下次就写对。时间线里"放大看图"那一步原来显示成代码名,补了名字,并加了测试:每个工具都要有中英文名字。
据此改了:只差一个必填参数、又正好多了一个不认识的参数、这个名字是考试里见过的那个参数的另一种叫法(`api/mcp_arguments.py` 的 ALIASES)、值的类型也对得上时,AMB 把它当成那个必填参数(`open_workflow {name: …}` 就是 `{workflow: …}`);类型对得上但名字没见过的不算,意思可能不一样。回复里写一句"把 name 当成了 workflow",下次就写对。时间线里"放大看图"那一步原来显示成代码名,补了名字,并加了测试:每个工具都要有中英文名字。
看到但没改:任务做完(`report` 写了做完)以后 AI 又看了一下,会多出一个只有一步的空任务;Gemini 有时没先问就动手、用假问题试工具。
+2 -2
View File
@@ -474,9 +474,9 @@ class ArgumentTests(unittest.TestCase):
self.assertFalse(result["isError"])
self.assertEqual(result["structuredContent"]["opened"], "exam_txt2img")
self.assertIn("Took name as workflow", result["structuredContent"]["arguments_note"], "so the next call is right")
for wrong in ({"name": 3}, {"name": "a", "other": "b"}, {"name": True}):
for wrong in ({"name": 3}, {"name": "a", "other": "b"}, {"name": True}, {"style": "anime"}):
with self.subTest(arguments=wrong):
self.assertTrue(mcp_tools.call_tool(tools, "open", wrong)["isError"], "another type, or more than one guess: asked again")
self.assertTrue(mcp_tools.call_tool(tools, "open", wrong)["isError"], "another type, more than one guess, or a name not known to mean it: asked again")
if __name__ == "__main__":
unittest.main()