V8 隔离单元里用 JS await 工具、显式输出与 cell_id 续跑、store 跨 exec 传数据,以及不会绕过审批与沙箱。
找到合适工具后,若有几份资料可一起读、另一步必须等结果——关系怎么表达清楚?若每步都由模型发一条调用、等一次返回再决定下一条,简单数据整理也可能占好几次往返。Code Mode 允许模型写一段 JS,把工具调用、等待与结果整理放在一起。第九章讲固定源码里的 exec / await 路径、背后的 V8 运行单元(外部 Node 是另一类工具,本章不展开)。
代码与工具的分工
这段代码可以保存变量、判断条件、遍历结果,也可以同时等待几次工具调用。真正读文件、跑命令、访问外部服务,仍交给提供给它的工具。JS 运行环境本身没有 Node,也没有直接的文件系统、网络和 console;要交给模型的结果用 test 等显式输出接口;读文件就调相应工具。适合把几步机械处理放进短代码(先读两份独立材料、提取需比较字段、只输出关键内容),模型仍负责判断结果是否足够以及后面怎么改代码。不必把整个任务一次性写成大程序——依赖清除、结果易检查的一小步更利于出错时定位。
调用 exec:原始 JS,不是包在 JSON 里
传入原始 JS 文本,不是包着代码的 JSON,也不是 Markdown 代码块。第一行可带执行提示(多久先返回、本次直接输出预算等)。处理器解析输入,准备本次允许嵌套调用的工具清单,经 Code Mode 服务创建运行单元,得到 cell_id,底层建立新的 V8 隔离实例。代码很快结束就直接返回结果;仍在运行则后续等待靠 cell_id 找到同一份执行状态。Code Mode 需要对应运行服务可用——不是模型写了 JS,任何客户端都能自动执行。
await tools.xxx:桥接到宿主
看起来像普通函数调用,实际经桥接把请求交给宿主;运行时知道方法对应哪个真实工具,并带上运行单元与调用编号。进入核心后,函数类型工具把输入整理成 JSON 对象;自由文本工具接收字符串——不合适就返回错误,不能靠 JS 宽松类型猜成正确调用。之后进入正常工具调度路径,当前步骤上下文跟着这次执行保留。把调用写进代码不会绕过工具本来的审批、执行约束或错误处理——改变的是组织调用的方式。工具完成后结果交回代码,等待中的 Promise 继续处理。
并行与顺序
修改测试前,相关用例与实现文件往往可独立读取:可先发出两次读取再等待。若希望分别检查成功/失败,可用 Promise.allSettled。这只是 JS 如何等待;底层是否真并发,还要看工具支持与运行时调度约束。修改文件与改后测试有明确先后——修改未完成就启动测试,读到的可能是旧内容,应按序 await,不能为了显得快全部塞进并行列表。整体求值结束后隔离实例生命周期也结束;未被等待的 Promise 可能被丢弃,需要结果的工作要明确等到完成点。
输出必须显式交出
工具数据到了代码里,赋给变量不会自动变成模型看到的最终内容——要调用 test 或合适的图片/音频输出接口明确放进输出。可先筛出与空字符串行为有关的字段再输出,避免模型重读大堆无关字段;整理也可能丢信息,要保留足够证据让下一步可追溯。输出预算控制的是这一层返回给模型的内容;过长可能被截断,且不会消除后端工具读取数据的成本。notify 可提前发文本,yield_control 可提前交回当前输出,时机各自决定。
先返回与执行结束
工具调用较慢时,exec 不一定一直等到结束:到了设定等待时机可先返回已有输出与 cell_id,说明代码还在运行;主动 yield_control 也可交回。后续 await 传同一编号,等待新输出或最终结果——返回的是自上次交回以来的新增内容,避免每次重复拿全部输出。要把「先返回」和「执行结束」分开:看到 cell_id 要观察状态,看到最终结果再检查有无报错。运行单元结束只说明代码到了结束状态,不能代替业务验收。停止执行时 await 支持终止选项,针对的是代码运行单元;嵌套工具已产生的文件修改或远程动作,不会因停止等待自动恢复原样。
会话 store:跨 exec 传数据
每次 exec 都有新隔离实例,上一段局部变量不能当下一段全局状态。运行环境提供 store/load:按键保存可序列化数据,按键取出,没有则 undefined。函数或活动链接等对象不能当普通 JSON 原样保存。新运行单元启动时会取得会话存储快照,写入先记在当前执行里,结束时再提交——不要在另一份代码仍在运行时假定所有 store 已实时可见。实践上让前一份明确结束再让后一份读。这是当前会话内传递方式,不承诺应用重启后一定保留,也不要当成多任务共享的事务数据库。
两层错误
- JS 语法不对或等待调用直接拒绝 → 影响脚本执行;
- 工具正常返回对象,但对象里带着失败状态。
Promise.allSettled 里某项 fulfilled 只说明 Promise 正常完成,不能自动当成业务成功——还要按工具返回说明检查状态与内容。一批读取中有一项失败,可把成功项与失败原因都整理出来再决定补偿;涉及修改的批次更要反复查看——后面的错误不会自动撤回前面已完成的操作。把运行单元错误、嵌套调用错误与业务结果错误分开记录。
中断与副作用
exec 执行、观察与停止围绕同一份代码运行单元;关闭后清理调度登记。外部动作可能已发生:写入文件成功后代码在处理下一份结果时被中断,文件不会自动回到原内容。恢复任务前先检查工作区与工具实际状态;尤其不要因为上次没拿到最终输出,就盲目重发带副作用的诊断代码——缺少结果 ≠ 操作没有执行。
串一遍短代码编排
用短代码发起对相关用例与实现的两次独立读取 → 逐项检查返回 → 把需比较内容交给模型 → 看清空字符串与预期后再决定修改 → 有依赖则等修改完成再跑测试 → 测试慢则分别观察代码单元与命令工具状态(编号不要混用)→ 失败带着明确错误继续定位 → 最终报告只写实际收到的修改与检查,不把脚本正常结束当成测试已通过。
合集下一集是运行中干预:用户临时改需求时,追加输入与立即中断分别怎么走。(Computer Use 等集未收录于本合集文字稿。)