Codemode 脚本
需要连续调用几个工具、筛选结果再输出时,Anyy 可以使用 Codemode。它运行 JavaScript,但没有 Node.js、直接文件系统、网络全局对象或定时器;读文件和访问外部服务都必须调用当前会话已有工具。沙箱不要求安装 Node.js。
先确认会话已启用
在 Dashboard → Tools → Built-in → codemode 保存 Profile 默认,或对一个空闲、没有排队输入的会话执行 Apply to Session。这两项操作独立,保存默认不会替已有会话重选工具,详见页面设置。
CLI 也可选择:
anyy --tools '+codemode'
anyy --resume SESSION_ID --tools '+codemode,+tool_search'
+ 从 Profile 默认工具集合计算,不是对恢复会话当前活动列表增量修改,也不写配置。符合条件的 MCP 还可自动激活 Codemode,显式排除和父范围限制优先。
模式 on 保留直接工具声明,only 将可经脚本调用的直接声明从模型请求隐藏,句柄和 canonical 记录仍保留。模式不负责激活,也不改变 Role。codemode.inline_budget 默认约 3000 个估算 token,只控制内联嵌套工具说明;没内联的工具仍可发现,不是整个上下文预算。工具组说明手工配置。
从一个简单读取开始
下面是供模型提交的脚本正文,不带 Markdown 围栏。顶层可以 await 和 return:
const result = await tools.bash({command: "git status --short"});
if (result.exit_code !== 0) {
throw new Error("git status failed with " + result.exit_code);
}
text(result.output);
工具的 canonical 参数是必需字符串 code 的对象,例如:
{"code":"text(await tools.read({path: \"README.md\", limit: 30}));"}
只有 native model 标记 compat.supportsOpenAIGrammarTools 且 Provider 支持该路径时,请求才使用原始 grammar JavaScript。其他模型仍传 JSON code,两条路径保存相同 canonical 参数,不要求用户另开 grammar 设置。
程序对象不能只按 Promise 是否 resolve 判断成功。bash 非零退出仍可返回对象,应看 exit_code;MCP 要看 isError,产品结构化结果要看其状态。没有结构化返回的工具失败通常 reject,可用正常异常处理。
发现并调用工具
别猜远端工具名。先检索、看声明,再按声明参数调用:
const matches = await searchTools("documentation search", {limit: 3});
text(matches);
for (const match of matches) text(await describeTool(match.name));
| 脚本 API | 读取什么 |
|---|---|
ALL_TOOLS | 本次可调用库存中的名称和描述 |
searchTools(query, {limit?, namespace?}) | 同一库存的相关工具,默认 limit 8 |
describeTool(name) | 一个工具的描述/TypeScript 声明;不存在为 undefined |
describeNamespace(name) | namespace 描述、instructions 和工具标识符;不存在为 undefined |
tools.<identifier>({...}) | 经既有 host 执行一次已存在的工具调用 |
规范化将标点等字符改成 _,发现结果会给脚本标识符;describeTool 也接受 canonical 名。namespace 只是分组元数据,不扩张权限。重名时以当前声明为准,hidden 和 model-only 工具不能通过脚本调用。
searchTools 只搜当前可调用快照,不抓另一份远端目录,也不改变下一请求的活动声明。需要激活模型工具时,使用独立的 tool_search。
所有已启动调用应等待完成。并发适合互不依赖的读取;后续操作依赖前一结果时顺序 await。脚本结束后,仍未完成的工具调用会被取消。
输出、超时和分支状态
可在第一行指定选项:
// @options: {"timeout_ms": 30000, "max_output_tokens": 1500}
const page = await tools.read({path: "README.md", limit: 40});
text(page);
store("last-inspected-file", "README.md");
timeout_ms 是不超过 2147483647 的正整数,含首次加载和 VM 启动;省略时不另外增加脚本超时,但父调用取消和工具时限仍生效。max_output_tokens 是非负整数,默认 10000,按近似字符预算截短文本。
text(value)和顶层return增加输出,对象按 JSON 输出。image(dataURLOrBlock)接受 base64 PNG/JPEG/GIF/WebP,保存临时图片并输出,不接受远程 URL。console.log(...)进入单独 console 输出块。exit()成功结束脚本。store(key, value)保存 JSON 值,load(key)读取,store(key, undefined)删除。
每次调用重建 VM 和全局变量。只有成功结束的 store 变更提交到所选对话分支;切换分支读取该分支提交值,数据库重开后仍可读。失败、取消、超时丢弃本次 staged store,保留过去已提交值,但不会撤回工具已经造成的修改。
store 单值 JSON 最多 262144 字符,key 与 JSON 值合计最多 1048576 字符;请存小状态,不存凭据或整份文件。VM 内存上限 256 MiB。输出超过 16777216 个 JavaScript 字符或 100000 次 text/image/console 调用会使脚本失败。
失败可带已有部分输出和错误。按预算截短文本时保留首尾并给出临时全输出文件路径;文件存在期间可用 read 的 offset/limit 读取,它不是持久附件承诺。逻辑引用、完整证据与会话总预算见工具结果。
分类和图片模型
脚本还可直接使用当前配置的模型 API。完整类型说明在工具声明指向的只读文件 <ProfileHome>/system/docs/pi-v1.2.0/codemode.md,可先用 read 阅读。
找模型时先指定类型:chat、image、classifier。getModelsOfType(type, provider?) 列配置目录;getAvailableOfType(type, provider?) 再按 Provider 启用及本地可解析凭据筛选,不是远端健康探测。
精确查找要给三个独立字符串:
const selected = await models.getModelOfType("classifier", "provider-id", "model-id");
if (!selected) { text("配置目录没有这个模型"); exit(); }
text(selected);
未知 provider/id 得到 undefined。执行时传目录中的 model 对象,不能传拼接的 provider/id 字符串或自造 Endpoint。列出 chat 模型不代表存在脚本 chat 生成函数。
分类输入
models.classify(model, context) 要求 state 对象、非空 questions 对象,可选 base64 images。每个问题必须有 instructions、type、criteria;choice 是标签到含义的映射,score 是从低到高的字符串层级,bool 给 true/false 两个字符串含义。
const candidates = await models.getAvailableOfType("classifier");
if (!candidates.length) { text("请先配置分类模型"); exit(); }
const result = await models.classify(candidates[0], {
state: {note: "下周三之前交付样稿"},
questions: {
urgency: {
type: "choice", instructions: "根据备注判断时间要求",
criteria: {dated: "有明确期限", undated: "未给期限"}
}
}
});
if (result.stopReason !== "stop") throw new Error(result.errorMessage || result.stopReason);
text(result);
图片输入与结果
models.generateImages(model, context) 的 input 是非空块数组,文本块给提示词,base64 图片块可作参考:
const candidates = await models.getAvailableOfType("image");
if (!candidates.length) { text("请先配置图片模型"); exit(); }
const result = await models.generateImages(candidates[0], {
input: [{type: "text", text: "白底,简洁的绿色叶片图标"}]
});
if (result.stopReason !== "stop") throw new Error(result.errorMessage || result.stopReason);
for (const part of result.output) {
if (part.type === "image") image(part);
else if (part.type === "text") text(part.text);
}
单个脚本最多同时运行四个分类/生成操作,usage 汇入 Codemode 结果。Provider 失败通常返回 stopReason 为 error/aborted 和 errorMessage,不一定抛异常;参数错误可在远端调用开始前拒绝。计费、凭据及接受的图片格式仍按已配置服务执行。