工具
A3S Code 会保留工具注册表。toolNames() 返回当前会话的工具表面。这个表面由
工作区能力与会话级集成共同组装;因此非本地工作区可以有意隐藏它无法提供服务的工具。
工具活动通过会话事件流传给客户端。界面可以直接展示开始、输出、错误和完成状态, 不需要解析终端文本。
工具表面
当某个工作流依赖特定工具可见时,在测试或应用诊断中使用 toolNames() /
toolDefinitions() 验证。工具可见性不是安全授权。send、run、stream
中的模型选择工具调用会经过当前技能限制、权限策略、确认、钩子、预算、队列与超时、
取消、递归调用保护、输出净化、制品上限与工作区路径检查。session.tool(...)
这类直接 SDK 调用使用另一条显式策略,见下文。activeTools() 回答的是另一个问题:
当前操作中有哪些工具调用正在运行。
统一调用内核
运行时会为每次调用标记来源:
宿主直接调用的 Skill、Task 或自定义工具所创建的模型子运行会重新从“智能体”来源开始。
公开自定义工具只能通过 InvocationRuntime 发起嵌套调用,而这条路径始终创建受治理
嵌套来源;一次直接调用不会变成扩展代码可复用的授权令牌。
所有来源都经过同一个调用内核。前置钩子可以阻止调用;预算检查在产生副作用前执行; 队列与超时、取消、递归保护、后置钩子以及安全提供程序的输出净化仍然有效。安装 有作用域的调用器后,嵌套调用不能回退到原始注册表。
宿主直接调用策略不是面向终端用户的授权系统。嵌入式应用必须先完成用户身份认证和 授权,再把请求翻译成直接 SDK 辅助方法。关闭会话会通过会话取消作用域中止正在执行的 宿主直接调用工具。
有边界的工具契约
受治理的智能体、嵌套调用和会话调用会先根据工具缓存的 JSON Schema 校验参数,再进入 确认或副作用阶段。工具还会声明每次调用的调度能力,包括只读、幂等、可恢复、取消安全、 分页、最大并行度和输出类型。
read、ls、glob、Git 日志/列表/差异和 web_fetch 会返回明确的续传游标或偏移量。
Shell 会对两个输出流执行字节上限,同时保留开头、结尾和精确计数;沙箱宿主仍能分别
读取 stdout 与 stderr。命令截止时间同时覆盖输出排空与 child.wait(),关闭输出管道
不能绕过超时。超时和取消会终止完整的 Unix 进程组。大文件修改不会把完整前后内容塞入
事件,而是返回有边界的预览、统一差异、哈希、大小与制品引用。
仓库上下文模式
已知相关路径时,使用 read.files 在一次有边界的响应中批量读取,减少工具回合:
共享字节预算包含文件头和续传信息。结果保持请求顺序,单个文件不可读不会丢弃其他
成功结果。当 metadata.batch.truncated 为 true 时,把
metadata.batch.continuation 原样放入下一次调用的 files;其中的偏移量和剩余额度
会从未完成位置继续,不重复已经返回的行。
grep.output_mode 用于选择满足任务所需的最小结果形状:
内置工作区后端在非内容模式下不会构造随后被丢弃的匹配文本。S3 结果会设置
metadata.search.truncated;当对象扫描上限导致总数或路径不完整时还会给出警告。
glob 默认保留后端的相关性或最近使用顺序。需要稳定的词法分页时,在游标分页前设置
sort: "path"。
对固定字符串修改,先以 dry_run: true 调用 edit,获取与真实写入相同的前后差异
元数据,但不写文件。应用修改时,把预览得到的数量放入 expected_replacements,并可用
max_replacements 设置独立上限。Dry run 会声明为只读,可安全参与 batch 并行执行。
batch 最多接受 32 个调用,并行度最高为 16。只有全部子调用都声明为安全、只读且幂等
时才会扇出;修改型或能力未知的工具会串行执行。部分失败会标出失败索引,并把编排本身
视为已完成,调用方只需重试失败项。parallel_task 同样最多接受 32 个任务,并会先
结算已经取消的子任务,再发布终止状态。
parallel_task 要求 2–32 个相互独立的前台分支。每个分支接受 agent、
description、prompt,以及可选的 max_steps 和 output_schema;background
不是并行分支参数。min_success_count 仅能与 allow_partial_failure: true 一起使用,
并且必须介于 1 和提交任务数之间。Provider 和子运行时拥有类型化重试策略,扇出层不会
根据错误文本重放分支。
web_search 会在元数据中报告 complete、partial 或 failed。默认路径先执行
原生 API;只有合并结果未达到通用质量下限时,才运行普通 HTTP/RSS 引擎;前两层仍不
足够时,才初始化并运行无头浏览器引擎。因此浏览器发现和池创建都是惰性的。会话级
closed/open/half-open 熔断状态会跳过已知的配额、权限、限流、传输、重复空结果和超时
故障,避免每个请求都重试;服务端的 Retry-After 会被保留。显式传入 engines
时只执行请求的层级。含引擎错误的空结果属于失败,而不是成功的空搜索。超时、取消、
无效参数、部分失败和限流会携带结构化错误类型;层级决策、质量信号、引擎结果、尝试
耗时和重试上下文保留在元数据中。
web_fetch 同样保留失败语义,不从渲染后的文本推断是否重试。请求或响应体 I/O 失败、
HTTP 408 和 HTTP 5xx 使用类型化 transport;HTTP 429 使用 rate_limited,并在
服务端提供时携带解析后的 Retry-After 延迟;工具外层截止时间使用 timeout。其他
HTTP 状态错误保持普通状态失败,除非运行时掌握可以安全重试的类型化证据。
直接工具调用
直接工具调用在会话工作区下执行,应视为宿主侧特权操作。它们不更新对话记录,
因此不占用会话的单任务对话租约。session.tool(...)、
session.program(...)、session.git(...)、session.writeFile(...)、
session.ls(...)、session.editFile(...) 和 session.patchFile(...) 返回
ToolResult,读取 output、exitCode 和可选的 metadataJson。类型化
读取、搜索和命令行辅助方法返回更简单的值:readFile、grep、bash 返回字符串,
glob 返回字符串数组。长输出应在进入提示词前先摘要。
结构化输出:generate_object
generate_object 工具会让配置的大语言模型生成 JSON 值,对响应执行 JSON Schema
校验,并且只在零退出码结果中返回校验后的值。它支持根对象、数组、枚举、常量、组合
关键字和本地 $ref 定义。有效超时从获得模型生成准入后开始;支持活动传输预算的
客户端会收到这份超时,并且有边界的 Schema 修复过程始终受同一个截止时间约束。
它有两种使用方式:
- 智能体自主调用:大语言模型在工具列表中看到
generate_object,在需要结构化输出时自行决定调用。 - 直接调用:应用通过
session.tool('generate_object', ...)绕过模型驱动的工具选择步骤;工具内部仍会调用配置的 LLM。
参数
模式
tool:Provider 支持强制工具调用时,要求调用一个参数符合 Schema 的合成工具。prompt:将 Schema 指令追加到提示词中。它适合作为纯提示词回退路径,但更依赖模型遵循指令。auto:优先选择强制工具模式,不支持时退回提示词模式。strict:Provider 支持时使用原生严格 JSON Schema,否则安全退回强制工具或提示词模式。json:Provider 支持时使用原生 JSON 对象模式,否则安全退回强制工具或提示词模式。
每一种解析后的模式都会把面向 Provider 的响应 Schema 保留为仅宿主可见的校验元数据;
它不会作为额外字段序列化进 Provider 请求。Rust 组合客户端可以使用
structured::is_complete_streamed_value(...),只接受完整且通过该 Schema 校验的
JSON 值,包括缺少终止流事件的端点。客户端还可以先检查
LlmClient::has_distinct_non_streaming_transport(),再决定阻塞调用能否作为独立回退,
避免把同一种流式故障换一个方法名后再次执行。
流式
通过 session.stream() 调用时,部分对象以 tool_output_delta 事件发出。快照最多每
100 毫秒发送一次;对象超过事件预算时,事件只发送字节计数,不重复携带完整值:
修复重试
如果大语言模型输出未通过模式校验,工具会自动将校验错误反馈给模型并重试。这能处理缺少必填字段、枚举值错误等边界情况,无需应用层重试逻辑。
委派子任务可以直接使用 SDK 辅助方法,它们底层仍是同一组核心工具:
自动子智能体委派也使用同一组核心工具。autoParallel: false 只关闭自动并行扇出,
不会移除 parallel_task 或 session.tasks(...)。
程序化工具调用
程序化工具调用不是单次直接工具调用。program 工具会在内嵌 QuickJS 虚拟机中运行
受限 JavaScript 脚本;脚本定义 async function run(ctx, inputs),用一个有边界的
程序替代多轮模型工具调用。
不要让模型反复消耗工具回合:
可以让模型请求 program 运行一个脚本:
SDK 的 session.program(...) 支持内联 source,也支持 workspace 相对路径 .js 或 .mjs 文件:
session.program(...) 等价于 session.tool('program', { type: 'script', language: 'javascript', ... }),只是使用 SDK 原生命名。如果省略 allowedTools / allowed_tools,脚本可以调用除 program 之外的所有已注册工具。需要更小能力面时,再显式传入 allow-list。
QuickJS VM 不获得文件系统、网络、子进程或环境变量权限。脚本唯一有用的能力来自 ctx,这些方法会回到 A3S Code 的受控工具执行路径。PTC 会返回可读的 ToolResult.output,结构化数据位于 ToolResult.metadataJson。原始大输出不应反复塞进 prompt;应先总结发现、证据引用、风险和建议下一步。
在 a3s code 中,DynamicWorkflowRuntime 也会使用 PTC。默认 TUI PTC allow-list
不会允许递归调用 program、dynamic_workflow 和 parallel_task。动态工作流需要本地
并行子智能体时,会调度名为 parallel_task 的 Flow 步骤;TUI 宿主在 QuickJS 外执行
原生 parallel_task。完成 /login 且会话中已经注册宿主运行时工具后,动态工作流的
PTC 步骤还可以调用 ctx.tool("runtime", ...)。
动态工作流的结构化生成默认单路执行。只有相互独立的 generate_object 步骤需要扇出
时,才把 limits.maxConcurrentGenerations 设置为 2–4;每个获得准入的步骤都会得到
绑定到精确运行和步骤身份的客户端 fork。无法 fork 会话的 Provider 仍保持单路执行。
Rust 辅助函数 dynamic_workflow::recover_dynamic_workflow_step_output(...) 只有在运行
标识、原始查询和步骤标识全部匹配时,才会恢复一个已经完成的持久化步骤。它不是跨运行
查询缓存,也不会把未完成步骤提升为成功结果。
验证
使用验证命令把“已经完成”转换成可检查的证据: