Shorten the daily tools' descriptions and begin_task's rules
The descriptions of the daily set are rewritten without the repeats and roundabout phrasing. Their rules and don'ts stay: no cropping or editing pictures with code, no reading ComfyUI's folders, ask the user in the workbench. So do the shared property texts: the query words, node ids, the task id. tools/list for the daily set drops from about 27,300 to 22,200 characters, and the full one from 46,000 to 40,700. begin_task's note, read at the start of every task, drops from about 1,900 to 900 characters. The replacements were made with ast, so each description's adjacent literals changed as one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6246df480d
commit
f7d8a69e75
+4
-2
@@ -15,6 +15,8 @@
|
||||
- The answer that first tells the AI its run ended, run_status or any other, carries up to four thumbnails of the run's pictures, once per run, so it need not fetch them with get_image_info.
|
||||
- 跑完叫我:关卡窗口新增“等跑图”,默认“跑完叫我”。AI 提交后最多等 15 秒,还没跑完就告诉你在跑,然后收工,不再一遍遍查进度(以前一张图要查 10 次左右)。跑完后,AI 工作台那一步下面有几句话,点一下复制,粘到 AI 的对话框里,它就接着看结果和图;AI 知道结果后这几句话自动消失。选“AI 自己等”就和以前一样。
|
||||
- Tell AI when done: a new setting in the Gates window, on by default. The AI waits up to 15 s after queueing and, if the run still goes, says so and ends its turn instead of polling run_status. When the run ends, its step offers lines to copy into the AI's chat; they go once the AI knows. "AI waits" keeps the old way.
|
||||
- 工具说明压短:日常工具集里每个工具的说明重写,去掉重复和绕的话,规则和“不要做”的都保留;AI 要读的从约 2.7 万字减到约 2.2 万字,开始任务时收到的规则从约 1900 字减到约 900 字。
|
||||
- Shorter tool descriptions: the daily tools' descriptions are rewritten without repeats, keeping their rules, about 22,000 characters instead of 27,000; begin_task's rules are about 900 characters instead of 1,900.
|
||||
|
||||
- 修复任务画布标签关闭或切换失败后误用当前工作流的问题:操作会明确报错,重新打开或明确指定新画布后才能继续。下载缺失模型现在也跟随任务画布;留言里的 `@` 搭配和工作流按完整名称查找,不再因模糊搜索前几项占满而误报缺失。
|
||||
- Task canvas actions now fail when their recorded tab is closed or cannot be activated instead of using another workflow. Missing-model downloads follow the task tab, and message references resolve exact combo/workflow names before search limits.
|
||||
@@ -73,8 +75,8 @@
|
||||
- **宽窗口里时间线收在中间**:右边一栏关着、窗口又很宽时,时间线、标题和输入框不再横跨整个窗口,而是收成中间约 880 像素宽的一列(像聊天软件那样),滚动条仍在最右边。时间线里的图片按自己的大小从左排开,一张图不再被撑成横跨整行的大灰框。
|
||||
- **AI 每一步都知道下一步做什么**:开始任务、出图和看进度、加节点连线、问你问题得到回答,这些回复里都多了一句 `next`:比如“还在跑,等 55 秒再看”“跑完了,先放大看图再告诉你结果”“还缺这几根线,照清单连”“缺模型,先查缺哪个”。小模型不擅长自己规划,但很会照着做。
|
||||
- Answers of begin_task, run_workflow and run_status, the canvas changes and an answered ask_user carry next: the one thing to do now.
|
||||
- **给 AI 的工具可以选“日常”**:关卡窗口里多了 **给 AI 的工具:日常 / 完整**。日常只给 AI 19 个常用工具(照着跑、看图、换模型或 LoRA、查缺的模型、问你、留言、现状一览),AI 要读的说明从约 4.2 万字减到约 1.9 万字,Gemini Flash 这类小模型日常跑图不容易绕晕;要连线搭工作流、画面板、下载时选完整。换了以后在 AI 软件里开个新对话才生效。
|
||||
- The Gates window offers AI apps either every tool or a daily set of 19 (runs of saved workflows, pictures, models, the task's own): half the reading for a small model. Calls are not limited by it; apps see a change in a new chat.
|
||||
- **给 AI 的工具可以选“日常”**:关卡窗口里多了 **给 AI 的工具:日常 / 完整**。日常只给 AI 常用工具(照着跑、看图、换模型或 LoRA、查缺的模型、问你、留言、现状一览,以及自动接线搭工作流),AI 要读的说明约 2.2 万字,完整的约 4.1 万字,Gemini Flash 这类小模型日常跑图不容易绕晕;要画面板、下载时选完整。换了以后在 AI 软件里开个新对话才生效。
|
||||
- The Gates window offers AI apps either every tool or a daily set (runs of saved workflows, pictures, models, the task's own, canvas building): about half the reading for a small model. Calls are not limited by it; apps see a change in a new chat.
|
||||
- **照着跑:日常出图一步完成**:AI 出图时可以直接说“用哪个存好的工作流、改什么”:`run_workflow` 带上工作流名,再带上要改的提示词、反向提示词、种子、尺寸或一张图(比如你标注过的重绘图),AMB 就在任务专用标签页里打开它(第一次打开,之后接着用同一个标签页),填好这几处,其余照存好的样子不动,然后出图、等结果。尺寸只改起始的空白潜空间,高清修复里的 Latent 放大保持原来的放大尺寸。原来要 6、7 步(找工作流、打开、看画布、改提示词、改种子……),现在一步,小模型也不容易绕晕。填的内容和出图一起算一步,改画布那部分同样能 Ctrl+Z;如果你给“改画布”设的关卡比“用显卡”严,这一步按改画布的关卡来问你。画布报错是因为缺模型时,“现状一览”会让 AI 先查缺哪个模型,而不是乱换选项。
|
||||
- run_workflow takes blanks for a daily run in one call: workflow (a saved one, opened in the task's tab once and reused), prompt, negative, seed, width, height and image (image_node for several LoadImage nodes); the rest stays as saved. The size goes to the latent a run starts from, never to a hires fix's latent upscale. With blanks a run asks as the stricter of the GPU's and the canvas's gate.
|
||||
- **现状一览,AI 一次就知道到哪一步了**:新工具 `get_situation`,AI 调一次就拿到:任务(你最后说了什么、有几个问题在等你、定了哪些决策、出过哪些图、“AMB 之外”几次)、画布简报(每个节点一行:谁接到谁;**还缺哪几根线、各要什么类型、画布上哪些现有输出能接上**;ComfyUI 报错的节点)、最近一次出图,以及**下一步该做什么**。回复控制在约 3600 字以内,Antigravity 不会把它存成文件再让 AI 去读。新开对话或拿不准时先调它;连接说明里的那句话和规则也写上了。小模型(比如 Gemini Flash)不用再把整张图记在脑子里。
|
||||
|
||||
+15
-21
@@ -238,7 +238,7 @@ def speak(ctx, character, text, seed=None, language="auto"):
|
||||
|
||||
# ---------------------------------------------------------------- registry
|
||||
|
||||
_NODE = {"type": "integer", "description": "A node id from describe_canvas."}
|
||||
_NODE = {"type": "integer", "description": "A node id."}
|
||||
_MODEL = {"type": "string", "description": "model_id from search_models."}
|
||||
|
||||
|
||||
@@ -268,10 +268,8 @@ ACTIONS = dict([
|
||||
"Puts a model into a loader node (checkpoint, LoRA, VAE…) on the canvas, replacing the one it had.",
|
||||
set_model, {"node_id": _NODE, "model_id": _MODEL}, ["node_id", "model_id"], destructive=True),
|
||||
_action("add_lora", "Add a LoRA",
|
||||
"Inserts a LoRA loader after node after_node_id (default: the workflow's main model loader, past "
|
||||
"the LoRAs already on it) and moves everything that node fed behind it. LoRAs that train the text "
|
||||
"encoder also take the CLIP line (from the same node, or a UNet workflow's CLIP loader); others "
|
||||
"patch the model only.",
|
||||
"Inserts a LoRA loader after after_node_id (default: the main model loader, past its LoRAs) and moves "
|
||||
"what that node fed behind it; the CLIP line too when the LoRA trains the text encoder.",
|
||||
add_lora, {"model_id": _MODEL, "after_node_id": _NODE,
|
||||
"strength_model": {"type": "number", "default": 1.0}, "strength_clip": {"type": "number", "default": 1.0}},
|
||||
["model_id"]),
|
||||
@@ -281,12 +279,11 @@ ACTIONS = dict([
|
||||
"changes; ports to nodes outside the combo (sampler…) stay open.",
|
||||
place_combo, {"name": {"type": "string", "description": "Combo name from list_combos."}}, ["name"]),
|
||||
_action("check_workflow_models", "Check missing models",
|
||||
"Which models the open workflow needs that this computer does not have under that name, and which "
|
||||
"of them Anomalous can put back (same file found by hash, or a likely candidate).",
|
||||
"Models the open workflow names that this computer lacks, and which Anomalous can put back (the same "
|
||||
"file by hash, or a likely one).",
|
||||
check_workflow_models, read_only=True),
|
||||
_action("fix_workflow_models", "Fix missing models",
|
||||
"Puts back every missing model that Anomalous found with certainty (same file by hash). "
|
||||
"Likely candidates are left for the user. One Ctrl+Z step.",
|
||||
"Puts back every missing model found by hash; likely ones are left to the user. One Ctrl+Z step.",
|
||||
fix_workflow_models, destructive=True),
|
||||
_action("download_missing_models", "Download missing models",
|
||||
"Downloads the models the open workflow is missing whose source is certain: Civitai found by the "
|
||||
@@ -306,24 +303,21 @@ ACTIONS = dict([
|
||||
_action("download_status", "Downloads", "How the downloads of this ComfyUI run are going.", download_status,
|
||||
read_only=True),
|
||||
_action("run_workflow", "Run the workflow",
|
||||
"Queues the open workflow in ComfyUI, like pressing Run. Uses the GPU. Follow it with run_status, which "
|
||||
"says where it stands and gives its pictures when done; do not look in the output folder for them. "
|
||||
"A daily run in one call: workflow (a saved one, list_workflows names them) opens it in the task's tab "
|
||||
"the first time and reuses it after; prompt and negative fill its prompt boxes, seed every sampler's "
|
||||
"seed, width and height its empty latent, image (a picture from search_images, or in the input folder, "
|
||||
"like an inpaint_image) its LoadImage; values any other setting by name ({\"steps\": 30}; "
|
||||
"{\"12\": {\"denoise\": 0.5}} when several nodes have it, as set_values); the rest stays as saved. "
|
||||
"Without workflow they fill the open canvas. No describe_canvas, set_prompt or set_values needed for these.",
|
||||
"Queues the workflow (uses the GPU). In the same call: workflow (a saved one) opens in the task's tab "
|
||||
"once and is reused; prompt, negative, seed (every sampler), width/height (the start latent), image "
|
||||
"(its LoadImage) and values (any setting by name: {\"steps\": 30}, or {\"12\": {\"denoise\": 0.5}} when "
|
||||
"several nodes have it) fill it in; the rest stays. Without workflow they fill the open canvas. Then "
|
||||
"run_status, never the output folder.",
|
||||
run_workflow, {"batch": {"type": "integer", "minimum": 1, "maximum": 8, "default": 1},
|
||||
"wait_seconds": {"type": "number", "minimum": 0, "maximum": 55, "default": 15,
|
||||
"description": "Wait for execution after submission; returns actual state/results. Never resubmit while running."},
|
||||
"workflow": {"type": "string", "description": "A saved workflow's name (list_workflows)."},
|
||||
"description": "Seconds to wait for it to end."},
|
||||
"workflow": {"type": "string", "description": "A name from list_workflows."},
|
||||
"prompt": {"type": "string"}, "negative": {"type": "string"},
|
||||
"seed": {"type": "integer", "minimum": 0},
|
||||
"width": {"type": "integer", "minimum": 16, "maximum": 16384},
|
||||
"height": {"type": "integer", "minimum": 16, "maximum": 16384},
|
||||
"image": {"type": "string", "description": "subfolder/name.png in the output or input folder."},
|
||||
"image_node": {"type": "integer", "description": "The LoadImage to fill when the workflow has several."},
|
||||
"image": {"type": "string", "description": "subfolder/name.png, output or input folder."},
|
||||
"image_node": {"type": "integer", "description": "Which LoadImage, when there are several."},
|
||||
"values": {"type": "object", "description": "Other settings by name, any node's."}}),
|
||||
_action("open_in_anomalous", "Show a model",
|
||||
"Opens Anomalous Model Browser on this model's page, so the user sees its cover and details.",
|
||||
|
||||
+25
-32
@@ -258,61 +258,54 @@ def open_workflow(ctx, name):
|
||||
return _page("open_workflow", {"filename": filename, "name": name}, timeout=60)
|
||||
|
||||
|
||||
_NODE_ID = {"type": "integer", "description": "A node id from describe_canvas or a tool's answer."}
|
||||
_VALUES = {"type": "object", "description": "{setting name: value}; a choice takes one of its choices exactly."}
|
||||
_NODE_ID = {"type": "integer", "description": "A node id."}
|
||||
_VALUES = {"type": "object", "description": "{setting: value}; a choice exactly as listed."}
|
||||
_NEIGHBOURS = {"oneOf": [_NODE_ID, {"type": "array", "items": _NODE_ID, "minItems": 1, "maxItems": 8}]}
|
||||
|
||||
CANVAS_TOOLS = dict([
|
||||
_action("find_nodes", "Look up node types",
|
||||
"Find built-in and custom node types. query returns up to five brief candidates, without bulky choice "
|
||||
"lists. types=[chosen type] gives inputs, settings, choices, ranges and output slots when needed. "
|
||||
"Use add_node with insert_after or wire_from/wire_to to add and wire in one call.",
|
||||
"Node types, built in and custom. query: up to 5 brief candidates; types=[...]: their inputs, "
|
||||
"choices, ranges and outputs.",
|
||||
find_nodes, {"query": {"type": "string"}, "types": {"type": "array", "items": {"type": "string"}, "maxItems": MAX_FOUND}},
|
||||
read_only=True),
|
||||
_action("add_node", "Add a node",
|
||||
"Add and wire a node in ONE call. wire_from: nodes that feed it; wire_to: nodes it feeds, where an input "
|
||||
"already fed is spliced (its old source feeds the new node: a ControlNet or LoRA put in front of a KSampler). "
|
||||
"insert_after=ID splices it behind that node instead; with several branches, wire_to picks them. Unique "
|
||||
"types, or same-type sockets of the same name (positive to positive), wire automatically. Ambiguity changes "
|
||||
"nothing and lists candidates. replace:true lets it replace an input it cannot splice. One undo step; "
|
||||
"returns connections and reaches_output.",
|
||||
"Adds a node, wired in the same call: wire_from feeds it, wire_to takes its output (an input already "
|
||||
"fed is spliced, its old source now feeding the new node: a ControlNet or LoRA before a KSampler); "
|
||||
"insert_after=ID splices it behind a node. Same type or same socket name wires itself; anything "
|
||||
"ambiguous changes nothing and lists the choices; replace:true replaces what it cannot splice. One "
|
||||
"Ctrl+Z step.",
|
||||
add_node, {"type": {"type": "string", "description": "A node type from find_nodes, e.g. KSampler."},
|
||||
"values": _VALUES, "title": {"type": "string"}, "near_node_id": _NODE_ID,
|
||||
"insert_after": _NODE_ID, "insert_type": {"type": "string", "description": "Only if needed: through type, e.g. IMAGE."},
|
||||
"insert_after": _NODE_ID, "insert_type": {"type": "string", "description": "Through type, only if asked (e.g. IMAGE)."},
|
||||
"wire_from": _NEIGHBOURS, "wire_to": _NEIGHBOURS, "replace": {"type": "boolean"}}, ["type"]),
|
||||
_action("add_nodes", "Add a group of nodes",
|
||||
"Adds several nodes to the open workflow in ONE call, laid out as a block: nodes in ComfyUI's API form "
|
||||
"({\"a\": {\"class_type\": \"VAEEncode\", \"inputs\": {\"pixels\": [\"#12\", 0], \"vae\": [\"#4\", \"VAE\"]}}, "
|
||||
"\"b\": {\"class_type\": \"SetLatentNoiseMask\", \"inputs\": {\"samples\": [\"a\", 0], ...}, \"wire_to\": 15}}): "
|
||||
"a link names a node of the group or a canvas node as \"#id\", and an output by slot or name; wire_to feeds "
|
||||
"canvas nodes as add_node does (an input already fed is spliced; replace:true lets it replace one it "
|
||||
"cannot splice). Everything is checked first; one Ctrl+Z step. The answer maps your keys to node ids "
|
||||
"and lists what is still unwired.",
|
||||
"Adds a group of nodes in one call, as one block, in ComfyUI's API form: {\"a\": {\"class_type\": "
|
||||
"\"VAEEncode\", \"inputs\": {\"pixels\": [\"#12\", 0], \"vae\": [\"#4\", \"VAE\"]}}, \"b\": {..., \"inputs\": "
|
||||
"{\"samples\": [\"a\", 0]}, \"wire_to\": 15}}. A link names a key of the group or a canvas node \"#id\", and "
|
||||
"an output slot or name; wire_to as in add_node. Checked first; one Ctrl+Z step; the answer maps keys "
|
||||
"to node ids.",
|
||||
add_nodes, {"nodes": {"type": "object"}, "near_node_id": _NODE_ID, "replace": {"type": "boolean"}}, ["nodes"]),
|
||||
_action("connect_nodes", "Wire two nodes",
|
||||
"Wire two nodes by ID: unique matching types, and same-type sockets of the same name (positive to "
|
||||
"positive), connect in one undo step. No guessing a lone CONDITIONING into positive or negative, or "
|
||||
"wildcard sockets: ambiguity lists candidates, changes nothing. "
|
||||
"Optional output/input select sockets explicitly; replace:true permits replacing existing wires in auto mode.",
|
||||
"Wires two nodes: every unique matching type, and same-type sockets of the same name (positive to "
|
||||
"positive). Anything ambiguous (a lone CONDITIONING into positive or negative, wildcards) changes "
|
||||
"nothing and lists the choices; then give output and input. replace:true lets it replace wires. One "
|
||||
"Ctrl+Z step.",
|
||||
connect_nodes, {"from_node_id": _NODE_ID, "output": {"type": "string", "description": "Optional output slot number or name."},
|
||||
"to_node_id": _NODE_ID, "input": {"type": "string"}, "replace": {"type": "boolean"}},
|
||||
["from_node_id", "to_node_id"]),
|
||||
_action("set_values", "Change a node's settings",
|
||||
"Sets settings (steps, cfg, denoise, a sampler, a file choice, a third-party node's own…), checked "
|
||||
"against what each takes. values {setting name: value} goes to the one node that has that setting; a "
|
||||
"name several nodes have takes the node: {\"12\": {\"denoise\": 0.5}}. node_id sets that node's values. "
|
||||
"For prompts set_prompt, for models set_model find the right ones. One Ctrl+Z step.",
|
||||
"Changes settings of any node, a third party's too, checked against what each takes: {setting: value} "
|
||||
"goes to the one node that has it; name the node when several do: {\"12\": {\"denoise\": 0.5}}; or "
|
||||
"node_id with its settings. Prompts: set_prompt; models: set_model. One Ctrl+Z step.",
|
||||
set_values, {"node_id": _NODE_ID, "values": _VALUES}, ["values"], destructive=True),
|
||||
_action("remove_nodes", "Remove nodes",
|
||||
"Removes nodes from the open workflow, with their wires. One Ctrl+Z step.",
|
||||
remove_nodes, {"node_ids": {"type": "array", "items": _NODE_ID, "maxItems": MAX_REMOVE}}, ["node_ids"],
|
||||
destructive=True),
|
||||
_action("new_workflow", "Start a new workflow",
|
||||
"Opens a new workflow tab in ComfyUI, leaving the user's open one as it was: blank, or built and laid "
|
||||
"out from nodes, a workflow in ComfyUI's API form ({\"1\": {\"class_type\": \"CheckpointLoaderSimple\", "
|
||||
"\"inputs\": {\"ckpt_name\": \"x.safetensors\"}}, \"2\": {\"class_type\": \"CLIPTextEncode\", \"inputs\": "
|
||||
"{\"text\": \"...\", \"clip\": [\"1\", 1]}}}: a value or [node id, output slot]). Everything is checked "
|
||||
"before the tab opens. The answer maps your ids to the canvas's node ids.",
|
||||
"Opens a new workflow tab, the user's open one untouched: blank, or built from nodes in ComfyUI's API "
|
||||
"form ({\"1\": {\"class_type\": \"CLIPTextEncode\", \"inputs\": {\"text\": \"...\", \"clip\": [\"2\", 1]}}}: a value "
|
||||
"or [node id, output slot]). Checked before it opens; the answer maps your ids to node ids.",
|
||||
new_workflow, {"name": {"type": "string"}, "nodes": {"type": "object"}}),
|
||||
_action("open_workflow", "Open a saved workflow",
|
||||
"Opens one of the user's saved workflows (list_workflows names them) in a new tab, leaving the open one "
|
||||
|
||||
+7
-9
@@ -67,22 +67,20 @@ def zoom_image(image, region=None, folder="output", compare_with="", compare_fol
|
||||
return answer, extra
|
||||
|
||||
|
||||
_REGION = {"type": "object", "description": "Fractions 0-1 of the picture, as the user's marks give theirs; default the whole picture.",
|
||||
_REGION = {"type": "object", "description": "Fractions 0-1, like the user's marks; default all.",
|
||||
"properties": {name: {"type": "number", "minimum": 0, "maximum": 1} for name in ("x", "y", "width", "height")}}
|
||||
_FOLDER = {"type": "string", "enum": ["output", "input", "temp"], "default": "output"}
|
||||
|
||||
LOOK_TOOLS = dict([
|
||||
_tool("zoom_image", "Look closer at a picture",
|
||||
"Part of a picture shown larger, attached: to check a hand, a face, a seam or a mark's area at full detail. "
|
||||
"folder: output (results), input (what LoadImage reads, e.g. inpaint_image), temp (a run's previews). "
|
||||
"compare_with: a second picture, the same region attached beside it (a before and an after). Reads only. "
|
||||
"Use it instead of cropping or comparing pictures with code of your own; change a picture only by running "
|
||||
"a ComfyUI workflow (inpaint and the like), never by editing its file.",
|
||||
zoom_image, {"image": {"type": "string", "description": "As search_images, get_image_info or run_status name it."},
|
||||
"Part of a picture larger, at full detail (a hand, a face, a seam). folder: output, input or temp. "
|
||||
"compare_with: a second picture, the same region beside it. Use it instead of cropping with code; "
|
||||
"change pictures only by running a workflow, never by editing their files.",
|
||||
zoom_image, {"image": {"type": "string", "description": "As the other tools name it."},
|
||||
"region": _REGION, "folder": _FOLDER,
|
||||
"compare_with": {"type": "string", "description": "A second picture to show the same region of."},
|
||||
"compare_with": {"type": "string", "description": "A second picture."},
|
||||
"compare_folder": {"type": "string", "enum": ["output", "input", "temp"],
|
||||
"description": "compare_with's folder; default the same as folder."},
|
||||
"description": "Default: folder."},
|
||||
"size": {"type": "integer", "minimum": MIN_SIZE, "maximum": MAX_SIZE, "default": DEFAULT_SIZE}},
|
||||
["image"]),
|
||||
])
|
||||
|
||||
@@ -140,13 +140,12 @@ def move_model(ctx, model_id, to_type):
|
||||
|
||||
MODEL_TOOLS = dict([
|
||||
_action("search_models", "Search models",
|
||||
"Find model files (checkpoints, LoRAs, VAEs…) by name, trigger word or base model. Returns model_id for "
|
||||
"get_model, and loaded_by: the node types whose drop-down lists the file (use one of them). A file in the "
|
||||
"wrong folder for what it is comes with belongs_in and placement instead: nothing loads it where it is.",
|
||||
"Model files by name, trigger word or base model: model_id, and loaded_by (the node types that list "
|
||||
"the file). A misfiled one comes with belongs_in: nothing loads it where it is.",
|
||||
search_models, {
|
||||
"query": _QUERY,
|
||||
"type": {"type": "string", "description": "ComfyUI models folder, e.g. checkpoints, loras, vae, diffusion_models, model_patches."},
|
||||
"base_model": {"type": "string", "description": "Part of the base model name, e.g. SDXL, Pony, Flux, SD 1.5."},
|
||||
"type": {"type": "string", "description": "A models folder: checkpoints, loras, vae…"},
|
||||
"base_model": {"type": "string", "description": "e.g. SDXL, Pony, Flux."},
|
||||
"source": {"type": "string", "enum": ["civitai", "inferred_from_file", "not_scanned"],
|
||||
"description": "Where the model's information came from."},
|
||||
"limit": _LIMIT}, read_only=True),
|
||||
|
||||
@@ -88,12 +88,10 @@ def get_situation(ctx, task=None):
|
||||
SITUATION_TOOLS = {
|
||||
"get_situation": {"run": get_situation, "context": True, "spec": {
|
||||
"name": "get_situation", "title": "Where things stand",
|
||||
"description": "One call, the whole picture: the task (what the user asked last, what waits for them, "
|
||||
"decisions, pictures made), the canvas in brief (bounded flow chains, node lines, "
|
||||
"missing inputs with matching outputs, ComfyUI's errors), the "
|
||||
"latest run, and next: the one thing to do now. Call it first in a new chat on a task, and "
|
||||
"whenever you are unsure, instead of describe_canvas, find_nodes or reading files.",
|
||||
"inputSchema": _schema({"task": {"type": "string", "description": "Optional task id returned by begin_task."}}),
|
||||
"description": "The whole picture in one call: the task (what the user asked last, what waits for them, decisions, "
|
||||
"pictures), the canvas in brief (flow chains, inputs nothing feeds and what fits them, errors), the "
|
||||
"latest run, and next: the one thing to do now. Call it first in a new chat, and whenever unsure.",
|
||||
"inputSchema": _schema({"task": {"type": "string", "description": "begin_task's id (optional)."}}),
|
||||
"annotations": {"title": "Where things stand", "readOnlyHint": True, "destructiveHint": False,
|
||||
"idempotentHint": True, "openWorldHint": False},
|
||||
}},
|
||||
|
||||
+36
-64
@@ -18,26 +18,15 @@ def begin_task(ctx, title, new_task=False):
|
||||
ctx.get("client") or "AI", title, new_task=bool(new_task),
|
||||
session=ctx.get("session") or "", task_id=ctx.get("task"),
|
||||
)
|
||||
answer = {"task": task["id"], "title": task["title"], "note": "Continue this task; do not begin another for its individual steps. "
|
||||
"Ask the user anything with ask_user: they answer in Anomalous's AI workbench, not in your chat. "
|
||||
"Use run_workflow to submit and see real execution progress. If you submit via /prompt or another tool, "
|
||||
"immediately call track_run(prompt_ids, task) with the exact IDs from YOUR submission response. "
|
||||
"External work is invisible until attached; never guess ownership from the global queue. "
|
||||
"When the user's setting is a tab of the task's own, Anomalous keeps your canvas work in it "
|
||||
"(it copies their open workflow there before your first change); do not switch tabs yourself. "
|
||||
"Every AMB tool call from now on is a step of this task in Anomalous's AI workbench, "
|
||||
"where the user sees, opens and undoes them. Call report to explain a choice "
|
||||
"or to hand in pictures you made another way; report with done=true at the end. "
|
||||
"The user's models, pictures, node types, canvas and runs are all in AMB's tools (search_models "
|
||||
"says which node loads a model, move_model fixes a misfiled one, find_nodes lists node types, "
|
||||
"search_images and get_image_info read pictures, zoom_image shows a part larger or "
|
||||
"compares two, run_status lists a run's previews): do not read ComfyUI's folders or "
|
||||
"source, run preprocessors or call its routes yourself; each of those asks the user to "
|
||||
"allow it in your app. Change pictures only by running ComfyUI workflows (inpaint and "
|
||||
"the like): never edit, paint over or overwrite picture files with code of your own. "
|
||||
"If you still use another tool (a command, a script, reading or writing files), "
|
||||
"call log_outside right after with what you ran and why. Unsure where things stand "
|
||||
"(a new chat, many changes): get_situation gives the task, the canvas in brief and the next step."}
|
||||
answer = {"task": task["id"], "title": task["title"], "note": (
|
||||
"Continue this task; do not begin another for its steps. Every AMB call is a step the user sees, opens and "
|
||||
"undoes in Anomalous's AI workbench. Ask them with ask_user (they answer there, not in your chat); report "
|
||||
"explains a choice or hands in pictures, done=true at the end. Run with run_workflow; a run queued another "
|
||||
"way needs track_run(prompt_ids) with your own IDs. In the task's own tab, do not switch tabs yourself. "
|
||||
"Everything is in AMB's tools (models, pictures, node types, the canvas, runs and their previews): do not "
|
||||
"read ComfyUI's folders or source, run preprocessors or call its routes yourself. Change pictures only by "
|
||||
"running workflows, never by editing files with code. If you use another tool anyway, log_outside right "
|
||||
"after. Unsure where things stand: get_situation.")}
|
||||
answer["next"] = ("get_situation shows where things stand; a daily run is one call: run_workflow(workflow: a saved "
|
||||
"one, with the prompt, seed or size to change).")
|
||||
box = ai_toolbox.effective(ai_tasks.get_task(task["id"]))
|
||||
@@ -249,7 +238,7 @@ BLOCKS_HELP = (
|
||||
"Plain text only (no markup, no links); up to 30 blocks, 12 pictures or models a block."
|
||||
)
|
||||
|
||||
_TASK_PROP = {"type": "string", "description": "Optional task id returned by begin_task."}
|
||||
_TASK_PROP = {"type": "string", "description": "begin_task's id (optional)."}
|
||||
|
||||
|
||||
def _task_tool(name, title, description, run, properties, required=()):
|
||||
@@ -271,41 +260,32 @@ TASK_TOOLS = dict([
|
||||
ai_run_tracking.track_run, {"prompt_ids": {"type": "array", "items": {"type": "string"}, "minItems": 1, "maxItems": 8},
|
||||
"task": _TASK_PROP, "wait_seconds": {"type": "number", "minimum": 0, "maximum": 55, "default": 15}}, ["prompt_ids"]),
|
||||
_task_tool("begin_task", "Begin a task",
|
||||
"Call first when you start what the user asked for: names it in Anomalous's AI workbench, where the "
|
||||
"user sees each of your steps with what it made, and can open or undo it. Reuses the user's waiting "
|
||||
"task or your active task, including any preliminary reads. Use new_task=true only for a separate "
|
||||
"user request, never for another step of the same work.",
|
||||
"Call first: names what the user asked for in Anomalous's AI workbench, where they see, open and undo "
|
||||
"each of your steps. Continues the waiting or active task; new_task=true only for a separate request.",
|
||||
begin_task, {"title": {"type": "string", "description": "A few words, in the user's language."},
|
||||
"new_task": {"type": "boolean", "default": False}},
|
||||
["title"]),
|
||||
_task_tool("report", "Tell the user",
|
||||
"Leaves a note in the AI workbench, where the user reads your work: why you chose something, what to "
|
||||
"look at, what is left, and your answers to them. Write there what you would tell them in your chat; "
|
||||
"headings (#), lists (- or 1.), **bold** and `code` are laid out. reply_to: the id of the user's message "
|
||||
"or marks you answer (user_messages[].id), so your reply shows under it. images: pictures you made in "
|
||||
"ComfyUI's output folder (subfolder/name.png) that Anomalous's tools did not make, so they are kept "
|
||||
"with the task. done=true ends the task.",
|
||||
"A note in the AI workbench, where the user reads your work: your choices, what to look at, what is "
|
||||
"left, your answers. Markdown headings, lists, bold and code are laid out. reply_to: the id of the "
|
||||
"user's message you answer. images: output pictures (subfolder/name.png) to keep with the task. "
|
||||
"done=true ends it.",
|
||||
report, {"text": {"type": "string"},
|
||||
"images": {"type": "array", "items": {"type": "string"}, "maxItems": MAX_LIMIT},
|
||||
"done": {"type": "boolean", "default": False},
|
||||
"reply_to": {"type": "string", "description": "user_messages[].id of what you answer."},
|
||||
"reply_to": {"type": "string", "description": "The message id you answer."},
|
||||
"task": _TASK_PROP}),
|
||||
_task_tool("log_outside", "Say what you did outside Anomalous",
|
||||
"Right after you used a tool that is not Anomalous's (a shell command, a script, reading or writing "
|
||||
"files, another server), say so here: what (the command or change, in a line), why (what Anomalous's "
|
||||
"tools did not do for it), files (what it read, wrote or changed). The user sees it in the task's "
|
||||
"timeline; Anomalous sees only the calls made to it. Prefer Anomalous's tools where they do the job.",
|
||||
"Right after using a tool that is not Anomalous's (a command, a script, files, another server): what "
|
||||
"you ran, why, and the files it touched, for the task's timeline. Prefer Anomalous's tools.",
|
||||
log_outside, {"what": {"type": "string"}, "why": {"type": "string"},
|
||||
"files": {"type": "array", "items": {"type": "string"}, "maxItems": ai_outside.MAX_FILES},
|
||||
"task": _TASK_PROP},
|
||||
["what"]),
|
||||
_task_tool("log_decision", "Record a decision",
|
||||
"Keeps a key decision of the task in Anomalous's AI workbench, where the user looks back on how the "
|
||||
"task went. Talk it over wherever you like, your own chat too; once you and the user settle something "
|
||||
"(a style, a model, a fix, what to drop), record it here: title (what it is about), decision (what was "
|
||||
"settled), reason, rejected (the options left out), by (user: they chose; ai: your own call; "
|
||||
"together), related (ids of this task's steps it is about: a run, the marks, a panel). The user's own "
|
||||
"choices in Anomalous (panel answers, allowing a step, materials) are kept already; record the rest.",
|
||||
"Records a settled decision of the task (a style, a model, a fix, what to drop) where the user looks "
|
||||
"back on it: title, decision, reason, rejected options, by (user, ai or together), related step ids. "
|
||||
"The user's own choices in Anomalous are kept already.",
|
||||
log_decision, {"title": {"type": "string"}, "decision": {"type": "string"}, "reason": {"type": "string"},
|
||||
"rejected": {"type": "array", "items": {"type": "string"}, "maxItems": ai_decisions.MAX_REJECTED},
|
||||
"by": {"type": "string", "enum": list(ai_decisions.BY), "default": "user"},
|
||||
@@ -322,12 +302,10 @@ TASK_TOOLS = dict([
|
||||
"task": _TASK_PROP},
|
||||
["title", "blocks"]),
|
||||
_task_tool("ask_user", "Ask the user",
|
||||
"Asks the user in Anomalous's AI workbench, where they watch your work, and waits for the answer: "
|
||||
"a question with options to press (2-8 {label, detail, recommended}: mark the one you suggest with "
|
||||
"recommended=true instead of writing it into the label) and, unless other=false, a line for their own "
|
||||
"answer; no options: a question they answer in a line. Use it for every choice or preference that is "
|
||||
"the user's while you work on an Anomalous task, never your own chat's question form. Returns the "
|
||||
"choice (or their text); if they have not answered within wait_seconds, keep waiting with get_answers.",
|
||||
"Asks the user in the AI workbench and waits: a question with 2-8 options ({label, detail, "
|
||||
"recommended}; mark your suggestion recommended=true), and a line for their own answer unless "
|
||||
"other=false; no options: a free answer. Use it for every choice that is the user's, not your chat's "
|
||||
"question form. Unanswered within wait_seconds: wait on with get_answers.",
|
||||
ask_user, {"question": {"type": "string"},
|
||||
"options": {"type": "array", "maxItems": 8, "items": {"type": "object", "properties": {
|
||||
"label": {"type": "string"}, "detail": {"type": "string"}, "recommended": {"type": "boolean"}}}},
|
||||
@@ -346,12 +324,10 @@ TASK_TOOLS = dict([
|
||||
"blocks": {"type": "array", "items": {"type": "object"}, "maxItems": ai_panels.MAX_BLOCKS},
|
||||
"closed": {"type": "boolean"}, "task": _TASK_PROP}, ["panel"]),
|
||||
_task_tool("run_status", "How the run is going",
|
||||
"Where your task's latest workflow run stands: none (no run yet), queued (how many runs are ahead), running (which node, "
|
||||
"its steps, percent, nodes done of all), done (with the pictures it saved; the first answer telling you it "
|
||||
"ended, this or any other, attaches up to 4 thumbnails, so get_image_info is not needed) or failed; summary says it "
|
||||
"in one sentence. wait_seconds (up to 55) waits for it to end. Runs take a while: call this instead of "
|
||||
"guessing, looking in the output folder or at the screen. While a run goes, your other tools' answers "
|
||||
"carry the same news as your_run, and once more when it ends.",
|
||||
"Your task's latest run: none, queued (runs ahead), running (node, steps, percent), done (its "
|
||||
"pictures; the first answer telling you it ended attaches up to 4) or failed; summary says it in a "
|
||||
"sentence. wait_seconds (up to 55) waits for the end. Call it instead of guessing or looking in "
|
||||
"folders.",
|
||||
run_status, {"wait_seconds": {"type": "number", "minimum": 0, "maximum": ai_task_runs.MAX_STATUS_WAIT, "default": 0},
|
||||
"task": _TASK_PROP}),
|
||||
_task_tool("show_run_map", "Show what the run really was",
|
||||
@@ -362,9 +338,8 @@ TASK_TOOLS = dict([
|
||||
"explanation with report. title: a few words in the user's language.",
|
||||
show_run_map, {"title": {"type": "string"}, "run": {"type": "string"}, "task": _TASK_PROP}, ["title"]),
|
||||
_task_tool("stop_run", "Stop the run",
|
||||
"Stops your task's run that is still going: its prompts still queued leave ComfyUI's queue and the one "
|
||||
"running is interrupted (never anyone else's). Use it when run_status warns that the run is far too big "
|
||||
"or slow and the user agrees (ask_user), or when the user asks you to stop.",
|
||||
"Stops your task's run: its queued prompts leave the queue, the running one is interrupted (never "
|
||||
"anyone else's). When run_status warns it is far too big and the user agrees, or when the user asks.",
|
||||
stop_run, {"task": _TASK_PROP}),
|
||||
_task_tool("get_toolbox", "What the user picked for you",
|
||||
"The node types, whole custom node packs, combos, saved workflows, prompts and models the user picked in "
|
||||
@@ -374,13 +349,10 @@ TASK_TOOLS = dict([
|
||||
"begin_task says when there are any.",
|
||||
get_toolbox, {"task": _TASK_PROP}),
|
||||
_task_tool("get_answers", "Read the user's answers and messages",
|
||||
"What the user picked or typed on your panels, and what they wrote to you in the AI workbench "
|
||||
"(messages: a change of mind, 'stop', 'make it brighter'; kind=change: something they changed "
|
||||
"themselves in Anomalous while you worked, keep it), since you last asked; each once. For one "
|
||||
"panel (and its task's messages), or all of yours. wait_seconds (up to 55) waits when nothing is there "
|
||||
"yet: for that panel's open questions, or with no panel for anything the user sends. still_waiting "
|
||||
"lists the questions not answered; skipped=true is a question the user chose not to answer (go on with your "
|
||||
"own judgement). Check it between steps of longer work.",
|
||||
"What the user picked or typed on your panels and wrote to you in the AI workbench since you last "
|
||||
"asked, each once (kind=change: something they changed themselves; keep it). panel: one panel. "
|
||||
"wait_seconds (up to 55) waits when nothing is there. still_waiting: questions not answered; "
|
||||
"skipped=true: they chose not to answer, go on with your own judgement.",
|
||||
get_answers, {"panel": {"type": "string"},
|
||||
"wait_seconds": {"type": "number", "minimum": 0, "maximum": ai_panels.MAX_WAIT, "default": 0},
|
||||
"task": _TASK_PROP}),
|
||||
|
||||
+7
-10
@@ -475,7 +475,7 @@ def _schema(properties=None, required=()):
|
||||
return schema
|
||||
|
||||
|
||||
_QUERY = {"type": "string", "description": "Words that must all appear (case-insensitive); empty lists everything."}
|
||||
_QUERY = {"type": "string", "description": "Words that must all appear; empty lists all."}
|
||||
_LIMIT = {"type": "integer", "minimum": 1, "maximum": MAX_LIMIT, "default": 20}
|
||||
|
||||
|
||||
@@ -496,18 +496,15 @@ TOOLS = dict([
|
||||
"Which models are matched on Civitai, which are not and why, which were never scanned, and what the last scan did.",
|
||||
scan_report),
|
||||
_tool("search_images", "Search output images",
|
||||
"Find images ComfyUI generated, newest first, by words in their prompt, model or settings (e.g. a LoRA "
|
||||
"name or 'seed:123'). Returns image paths for get_image_info. with_pictures attaches the first 6 "
|
||||
"themselves (512 px), in the listed order, so you can look at them at once.",
|
||||
"Output images, newest first, by words in their prompt, model or settings (a LoRA name, 'seed:123'). "
|
||||
"with_pictures attaches the first 6 (512 px).",
|
||||
search_images, {"query": _QUERY, "limit": _LIMIT, "page": {"type": "integer", "minimum": 1, "default": 1},
|
||||
"with_pictures": {"type": "boolean", "default": False}}),
|
||||
_tool("get_image_info", "Image generation settings",
|
||||
"The nodes and settings that produced an output image (prompts, models, seed, sampler…) and whether the "
|
||||
"user kept it as a recipe, combo or prompt. With folder=input, a picture in ComfyUI's input folder (what "
|
||||
"LoadImage reads, e.g. the inpaint_image Anomalous put there), with folder=temp a run's preview (run_status "
|
||||
"lists them): its size and the area LoadImage gives as MASK. include_image attaches a 512 px copy; "
|
||||
"zoom_image shows a part larger. No need to look at these files any other way.",
|
||||
get_image_info, {"image": {"type": "string", "description": "From search_images, e.g. 'ComfyUI_00012_.png'; with folder=input, the name LoadImage takes."},
|
||||
"How an output image was made (prompts, models, seed, sampler…) and whether the user kept it. "
|
||||
"folder=input: a picture LoadImage reads; folder=temp: a run's preview; both with their size and MASK "
|
||||
"area. include_image attaches a 512 px copy; zoom_image shows a part larger.",
|
||||
get_image_info, {"image": {"type": "string", "description": "From search_images; for folder=input, the name LoadImage takes."},
|
||||
"include_image": {"type": "boolean", "default": False},
|
||||
"folder": {"type": "string", "enum": ["output", "input", "temp"], "default": "output"}}, ["image"]),
|
||||
_tool("list_combos", "Combos",
|
||||
|
||||
Reference in New Issue
Block a user