• 简体中文
  • v6.6.0
  • 工具

    A3S Code 会保留工具注册表。toolNames() 返回当前会话的工具表面。这个表面由 工作区能力与会话级集成共同组装;因此非本地工作区可以有意隐藏它无法提供服务的工具。

    工具活动通过会话事件流传给客户端。界面可以直接展示开始、输出、错误和完成状态, 不需要解析终端文本。

    工具表面

    层级工具注册规则
    受工作区能力限制的内置工具readwriteeditpatchgrepgloblsbashgit仅在 WorkspaceServices 声明具备所需能力时注册。例如浏览器或 S3 工作区可以暴露文件工具,同时隐藏 bash 或本地 Git。
    运行时内置工具web_fetchweb_searchbatchprogram由核心工具执行器注册。batchprogram 接收当前有作用域的调用器,因此内部工具既受会话表面限制,也继承调用方的治理作用域。
    会话启动工具taskparallel_taskgenerate_objectsearch_skillsSkill构建 AgentSession 时加入。关闭手动委派后会移除委派工具;generate_object 需要已配置的大语言模型客户端;技能工具使用有效的技能注册表。
    TUI 工作流工具dynamic_workflow,以及 /login 后可选的宿主运行时工具a3s code 宿主注册。dynamic_workflow 通过 A3S Flow 回放支撑 ultracode 和 DeepResearch;宿主运行时工具属于登录后集成。
    动态集成mcp__<server>__<tool> 与宿主注册工具从 MCP 管理器或宿主代码发现后加入。

    当某个工作流依赖特定工具可见时,在测试或应用诊断中使用 toolNames() / toolDefinitions() 验证。工具可见性不是安全授权。sendrunstream 中的模型选择工具调用会经过当前技能限制、权限策略、确认、钩子、预算、队列与超时、 取消、递归调用保护、输出净化、制品上限与工作区路径检查。session.tool(...) 这类直接 SDK 调用使用另一条显式策略,见下文。activeTools() 回答的是另一个问题: 当前操作中有哪些工具调用正在运行。

    统一调用内核

    运行时会为每次调用标记来源:

    来源示例权限与确认策略
    智能体模型在 sendstream 中发出工具调用应用完整的模型侧策略与人工确认。
    受治理嵌套调用模型拥有的 batchprogram、工作流或公开 InvocationRuntime 的内部调用再次进入模型侧策略,并继承调用栈、取消、预算、钩子和沙箱;环境中的宿主直接调用上下文不能改变这个来源。
    宿主直接调用session.tool(...)、带类型的读写及 Git 辅助方法、session.program(...) 与直接任务辅助方法可信控制面:宿主已经选择该调用,因此跳过模型侧权限与人工确认。
    可信宿主直接嵌套调用宿主直接调用内置 batchprogram 或动态工作流后,由它执行宿主选定的子调用仅为该内置嵌套操作保留可信控制面权限;第三方工具不能通过公开 API 构造此来源。

    宿主直接调用的 Skill、Task 或自定义工具所创建的模型子运行会重新从“智能体”来源开始。 公开自定义工具只能通过 InvocationRuntime 发起嵌套调用,而这条路径始终创建受治理 嵌套来源;一次直接调用不会变成扩展代码可复用的授权令牌。

    所有来源都经过同一个调用内核。前置钩子可以阻止调用;预算检查在产生副作用前执行; 队列与超时、取消、递归保护、后置钩子以及安全提供程序的输出净化仍然有效。安装 有作用域的调用器后,嵌套调用不能回退到原始注册表。

    宿主直接调用策略不是面向终端用户的授权系统。嵌入式应用必须先完成用户身份认证和 授权,再把请求翻译成直接 SDK 辅助方法。关闭会话会通过会话取消作用域中止正在执行的 宿主直接调用工具。

    有边界的工具契约

    受治理的智能体、嵌套调用和会话调用会先根据工具缓存的 JSON Schema 校验参数,再进入 确认或副作用阶段。工具还会声明每次调用的调度能力,包括只读、幂等、可恢复、取消安全、 分页、最大并行度和输出类型。

    readlsglob、Git 日志/列表/差异和 web_fetch 会返回明确的续传游标或偏移量。 Shell 会对两个输出流执行字节上限,同时保留开头、结尾和精确计数;沙箱宿主仍能分别 读取 stdout 与 stderr。命令截止时间同时覆盖输出排空与 child.wait(),关闭输出管道 不能绕过超时。超时和取消会终止完整的 Unix 进程组。大文件修改不会把完整前后内容塞入 事件,而是返回有边界的预览、统一差异、哈希、大小与制品引用。

    仓库上下文模式

    已知相关路径时,使用 read.files 在一次有边界的响应中批量读取,减少工具回合:

    JSON
    {
    "files": [
    { "path": "src/lib.rs" },
    { "path": "src/config.rs", "offset": 40, "limit": 80 }
    ],
    "max_output_bytes": 65536
    }

    共享字节预算包含文件头和续传信息。结果保持请求顺序,单个文件不可读不会丢弃其他 成功结果。当 metadata.batch.truncatedtrue 时,把 metadata.batch.continuation 原样放入下一次调用的 files;其中的偏移量和剩余额度 会从未完成位置继续,不重复已经返回的行。

    grep.output_mode 用于选择满足任务所需的最小结果形状:

    模式结果
    content匹配行与可选上下文(默认)
    files_with_matches按词法顺序、使用游标分页的匹配路径
    count按词法顺序、使用游标分页的每文件匹配行计数
    summary完整扫描后的行数与文件数,不渲染匹配内容

    内置工作区后端在非内容模式下不会构造随后被丢弃的匹配文本。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 个相互独立的前台分支。每个分支接受 agentdescriptionprompt,以及可选的 max_stepsoutput_schemabackground 不是并行分支参数。min_success_count 仅能与 allow_partial_failure: true 一起使用, 并且必须介于 1 和提交任务数之间。Provider 和子运行时拥有类型化重试策略,扇出层不会 根据错误文本重放分支。

    web_search 会在元数据中报告 completepartialfailed。默认路径先执行 原生 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 状态错误保持普通状态失败,除非运行时掌握可以安全重试的类型化证据。

    直接工具调用

    TypeScript
    const files = await session.glob('src/**/*.rs');
    const hits = await session.grep('PermissionPolicy');
    const status = await session.git('status');
    const output = await session.bash('cargo test -p a3s-code-core');
    const raw = await session.tool('read', { file_path: 'README.md' });
    const schemas = session.toolDefinitions();
    const hitLines = hits.split('\n').filter(Boolean).length;
    console.log(files.length, hitLines, output.length, schemas.length);
    console.log(status.output);
    console.log(raw.output);

    直接工具调用在会话工作区下执行,应视为宿主侧特权操作。它们不更新对话记录, 因此不占用会话的单任务对话租约。session.tool(...)session.program(...)session.git(...)session.writeFile(...)session.ls(...)session.editFile(...)session.patchFile(...) 返回 ToolResult,读取 outputexitCode 和可选的 metadataJson。类型化 读取、搜索和命令行辅助方法返回更简单的值:readFilegrepbash 返回字符串, glob 返回字符串数组。长输出应在进入提示词前先摘要。

    结构化输出:generate_object

    generate_object 工具会让配置的大语言模型生成 JSON 值,对响应执行 JSON Schema 校验,并且只在零退出码结果中返回校验后的值。它支持根对象、数组、枚举、常量、组合 关键字和本地 $ref 定义。有效超时从获得模型生成准入后开始;支持活动传输预算的 客户端会收到这份超时,并且有边界的 Schema 修复过程始终受同一个截止时间约束。 它有两种使用方式:

    1. 智能体自主调用:大语言模型在工具列表中看到 generate_object,在需要结构化输出时自行决定调用。
    2. 直接调用:应用通过 session.tool('generate_object', ...) 绕过模型驱动的工具选择步骤;工具内部仍会调用配置的 LLM。
    TypeScript
    const result = await session.tool('generate_object', {
    schema: {
    type: 'object',
    required: ['sentiment', 'confidence'],
    properties: {
    sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
    confidence: { type: 'number', minimum: 0, maximum: 1 },
    },
    },
    prompt: '分类: "这个产品太棒了!"',
    schema_name: 'sentiment',
    mode: 'tool',
    max_repair_attempts: 2,
    });
    if (result.exitCode !== 0) {
    throw new Error(result.output);
    }
    const { object } = JSON.parse(result.output);
    // object = { sentiment: "positive", confidence: 0.95 }

    参数

    参数类型必填说明
    schema对象用于校验输出值的 JSON Schema
    prompt字符串非空白的生成或提取指令
    schema_name字符串1–59 个 ASCII 字母、数字、_-(默认 result
    schema_description字符串合成工具描述,最多 4,096 字节
    system字符串可选系统提示,最多 32,768 字节
    mode字符串"auto" / "strict" / "json" / "tool" / "prompt"(默认 auto
    max_repair_attempts整数0–5(默认 2)
    include_raw_text布尔值返回用于提取的 Provider 文本或工具参数(默认 false
    timeout_ms整数活动生成截止时间,1,000–600,000 毫秒(默认 120,000)

    模式

    • 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 毫秒发送一次;对象超过事件预算时,事件只发送字节计数,不重复携带完整值:

    TypeScript
    const stream = await session.stream('提取所有发票...');
    while (true) {
    const { value: ev, done } = await stream.next();
    if (done) break;
    if (!ev) continue;
    if (ev.type === 'tool_output_delta' && ev.toolName === 'generate_object') {
    const { object_partial } = JSON.parse(ev.text);
    renderProgress(object_partial);
    }
    }

    修复重试

    如果大语言模型输出未通过模式校验,工具会自动将校验错误反馈给模型并重试。这能处理缺少必填字段、枚举值错误等边界情况,无需应用层重试逻辑。

    委派子任务可以直接使用 SDK 辅助方法,它们底层仍是同一组核心工具:

    TypeScript
    await session.task({
    agent: 'explore',
    description: '查找认证文件',
    prompt: '检查认证相关文件,并返回紧凑证据列表。',
    });
    await session.tasks([
    { agent: 'explore', description: '查找测试', prompt: '定位认证测试。' },
    {
    agent: 'verification',
    description: '检查风险',
    prompt: '审查认证边界情况。',
    },
    ]);

    自动子智能体委派也使用同一组核心工具。autoParallel: false 只关闭自动并行扇出, 不会移除 parallel_tasksession.tasks(...)

    程序化工具调用

    程序化工具调用不是单次直接工具调用。program 工具会在内嵌 QuickJS 虚拟机中运行 受限 JavaScript 脚本;脚本定义 async function run(ctx, inputs),用一个有边界的 程序替代多轮模型工具调用。

    不要让模型反复消耗工具回合:

    Text
    grep -> read -> grep -> read -> summarize

    可以让模型请求 program 运行一个脚本:

    JavaScript
    // search-auth.js
    export default async function run(ctx, inputs) {
    const hits = await ctx.grep(inputs.query, { glob: '*.rs' });
    const files = await ctx.glob('crates/**/*.rs');
    const snippets = [];
    for (const file of files.slice(0, 20)) {
    const content = await ctx.readFile(file);
    if (content.includes(inputs.query)) {
    snippets.push({ file, preview: content.slice(0, 1200) });
    }
    }
    return {
    summary: `找到 ${snippets.length} 个与 ${inputs.query} 相关的候选文件`,
    evidence: snippets,
    rawSearch: hits,
    };
    }

    SDK 的 session.program(...) 支持内联 source,也支持 workspace 相对路径 .js.mjs 文件:

    JavaScript
    await session.program({
    path: 'scripts/ptc/search-auth.js',
    inputs: { query: 'PermissionPolicy' },
    allowedTools: ['grep', 'glob', 'read'],
    limits: {
    timeoutMs: 30000,
    maxToolCalls: 30,
    maxOutputBytes: 65536,
    },
    });

    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 不会允许递归调用 programdynamic_workflowparallel_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(...) 只有在运行 标识、原始查询和步骤标识全部匹配时,才会恢复一个已经完成的持久化步骤。它不是跨运行 查询缓存,也不会把未完成步骤提升为成功结果。

    验证

    使用验证命令把“已经完成”转换成可检查的证据:

    TypeScript
    const report = await session.verifyCommands('发布就绪检查', [
    {
    id: 'unit',
    kind: 'test',
    description: '运行核心测试',
    command: 'cargo test -p a3s-code-core',
    required: true,
    timeoutMs: 120000,
    },
    ]);