- 人工智能
- AI 应用
- 交互助手
- AI Agent
【免费下载链接】ironclaw
IronClaw is an Agent OS focused on privacy, security and extensibility
本篇技术指南以 IronClaw 仓库内 test-tools 夹具包market-data的能力文档(prompt doc)为主线,完整解读market-data.snp500这个 S&P 500(SPX)行情快照工具的能力契约:它何时被调用、返回什么结构、背后的 WASM 实现如何产出"假数据",以及它在宿主侧触发network+use_secret义务链与密钥注入的完整机制。读完本文,你将掌握 IronClaw 沙箱工具"能力文档 → 输入/输出 Schema → WASM 实现 → 宿主义务管线"的完整链路,并能在本地构建、安装与触发该夹具工具。
能力文档是什么:模型侧的工具使用说明书
关联文档 snp500.md 位于test-tools/market-data/prompts/market-data/目录,是market-data扩展包中market-data.snp500能力的prompt doc(能力文档)。在 IronClaw 的扩展清单模型中,每个能力都可以通过prompt_doc_ref声明一段面向 LLM 的能力描述,由宿主在模型选择工具时注入上下文。这段文档正是模型判断"何时该调用这个工具"的依据。
从 manifest 中的声明可以看到该引用关系:
[[capability_provider.tools.capabilities]] id = "market-data.snp500" description = "Get the current S&P 500 (SPX) index snapshot — level, daily change, and percent change. Takes no arguments." ... prompt_doc_ref = "prompts/market-data/snp500.md"也就是说,manifest.toml 中的description与prompt_doc_ref共同构成了工具对模型的可观测面:前者是简短摘要,后者是展开后的完整行为说明。
行为契约:无参数、单一职责、明确的触发语义
能力文档原文定义了三条核心契约:
- 返回内容:当前 S&P 500(SPX)市场快照——指数点位(index level)、日涨跌(daily change)、涨跌百分比(percent change);
- 入参:无参数(Takes no arguments),调用方不需要也不允许传入任何参数;
- 触发语义:当用户询问 S&P 500、"SPX" 或整体股票市场水平(overall stock market level)时使用。
同时文档明确声明数据为 fixture/fake(无实时行情源)——这是一个测试夹具工具,返回值是罐头数据而非真实市场行情。这一声明与 test-tools/README.md 中"All data is canned — no fixture ever performs live egress"的总体设计一致:整个test-tools目录下的三个工具(ascii-renderer、hacker-news、market-data)都不做真实外呼,network声明只是用来驱动宿主侧的义务规划器。
输入/输出契约:空入参与十字段快照
能力文档的"无参数"语义在输入 Schema 中得到形式化约束。snp500.input.v1.json 是一个空对象 Schema:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "market-data.snp500 input", "type": "object", "properties": {}, "additionalProperties": false }additionalProperties: false意味着任何多余字段都会被拒绝,模型侧无法向该工具传递任何参数。
输出 Schema 则定义了完整的快照结构。snp500.output.v1.json 包含 10 个字段,其中 5 个为必填:
| 字段 | 类型 | 必填 | 语义 |
|---|---|---|---|
symbol | string | ✅ | 指数代码,如SPX |
price | number | ✅ | 当前指数点位 |
change | number | ✅ | 较昨收的绝对涨跌 |
change_percent | number | ✅ | 涨跌百分比 |
as_of | string | ✅ | 数据时间戳(ISO 8601) |
name | string | — | 指数名称,如S&P 500 |
previous_close | number | — | 上一交易日收盘点位 |
day_high | number | — | 当日最高 |
day_low | number | — | 当日最低 |
data_source | string | — | 数据源标签 |
这套 Schema 同时被宿主用于两个目的:参数校验(调用前按 input schema 校验模型生成的入参)与输出校验/泄露扫描(返回值在沙箱出口被扫描,防止秘密形数据外泄)。
源码实现:WASM 组件如何产出固定快照
能力文档描述的"返回快照"行为,由market-data的 WASM 工具实现承担。工具源码位于 wasm-src/src/lib.rs,基于wit-bindgen生成绑定,实现了sandboxed-toolworld 的tool接口(接口契约定义见 crates/lanes/ironclaw_wasm/wit/tool.wit)。
execute入口的行为与能力文档完全对应:不读取任何入参(_req被直接忽略),构造一个固定的Snp500Snapshot快照并序列化为 JSON 返回。核心数据点:
let snapshot = Snp500Snapshot { symbol: "SPX".to_string(), name: "S&P 500".to_string(), price: 5_487.03, change: 12.45, change_percent: 0.23, previous_close: 5_474.58, day_high: 5_492.10, day_low: 5_468.77, as_of: "2026-06-30T20:00:00Z".to_string(), data_source: "market_data_api (fake fixture data)".to_string(), };数据结构定义在 wasm-src/src/types.rs:Snp500Snapshot是一个Serialize派生结构体,字段与输出 Schema 一一对应。可以看到快照的as_of是一个固定的历史时间戳、data_source明确标注fake fixture data,与能力文档"数据是 fixture/fake"的声明互相印证。
序列化成功返回Response::Success(output);失败则返回Response::Failure,携带ErrorKind::Executor与code = "serialization_failed"。此外工具还实现了schema()(返回与 input schema 等价的空对象 JSON)和description()(与能力文档一致的模型侧描述)。
值得注意的工程细节:序列化失败在 WASM 工具里几乎不可能触发(固定结构体、无动态字段),但实现仍然以结构化GuestFailure上报而非 panic,符合 tool.wit 中"guest 上报失败必须使用封闭词表(closed vocabulary)的error-kind,且message会在沙箱出口被清洗与限长"的约束——这是 IronClaw 对沙箱工具失败路径的硬性安全要求。
宿主义务链:network + use_secret 双义务与密钥注入
能力文档本身没有提安全模型,但 manifest 揭示了它作为测试夹具的真正价值:market-data是 test-tools 三个夹具中义务最重的一个。对照 test-tools/README.md 的工具矩阵:
| 工具 | Effects | 凭据 | 覆盖的用例 |
|---|---|---|---|
ascii-renderer | dispatch_capability | 无 | 纯计算,无义务 |
hacker-news | + network | 无 | 仅出口 allowlist,无密钥 |
market-data | + network, use_secret | 租户共享market_data_api_key | 出口 allowlist + 宿主中介密钥注入 |
manifest 中关键声明:
[[capability_provider.tools.capabilities]] id = "market-data.snp500" effects = ["dispatch_capability", "network", "use_secret"] default_permission = "allow" origin_gate_matrix = { loop_run = "gated_unless_granted", product = "forbidden", automation = "forbidden" } visibility = "model" [[capability_provider.tools.capabilities.runtime_credentials]] handle = "market_data_api_key" source = { type = "secret_handle" } audience = { scheme = "https", host_pattern = "api.marketdata.example" } target = { type = "header", name = "x-api-key" } required = true这段声明的安全含义值得拆解:
use_secret+runtime_credentials:运行时凭据的handle = "market_data_api_key"会触发宿主侧的InjectSecretOnce义务,同时audience.host_pattern = "api.marketdata.example"填充出口 allowlist,触发ApplyNetworkPolicy义务——正如 manifest 注释所写,该能力同时获得两个义务;- 密钥永远不进入 WASM:凭据
target声明为 HTTP 请求头的x-api-key,由宿主在 egress 边界注入。这与 tool.wit 安全模型完全一致:"Secrets are NEVER exposed to WASM; credentials are injected at host boundary",WASM 侧只能通过secret-exists检查秘密是否存在,永远读不到值; - 夹具不真实外呼:由于返回罐头数据,注入的
x-api-key永远不会被真正发送,密钥的存在只是为了驱动宿主义务管线(pre-flight、gating、injection)而不是认证任何真实服务。
义务的执行逻辑在宿主侧有专门测试印证。在 crates/kernel/ironclaw_host_runtime/src/obligations/tests.rs 中,market_data_api_key被构造为SecretHandle,并验证了关键语义:InjectSecretOnce可由管理员设置的租户共享密钥满足——测试注释明确写道 "tenant-shared key satisfies InjectSecretOnce for a caller with no personal secret",即个人无密钥的用户也能通过租户共享凭据获得调用资格。这正是 manifest 注释中"admin installs it, provides the sharedmarket_data_api_key, and every user can use it"的完整实现闭环。义务处理器本身的调度逻辑位于 obligations/handler.rs,其中InjectSecretOnce与ApplyNetworkPolicy均被纳入义务管线枚举。
本地安装与运行:导入、密钥播种与构建
作为可上传的扩展包,market-data的完整使用路径如下。
1. 密钥播种(先于激活):租户共享密钥通过环境变量或管理员 API 注入,环境变量形式为IRONCLAW_REBORN_DEV_SECRET__market_data_api_key=<value>(见 test-tools/README.md)。未播种密钥时,工具的use_secret义务会使调度被AuthRequired门控拦截。
2. 打包导入:将test-tools/market-data/目录打成 zip 即为可上传的 bundle,通过 WebUI v2 的 Import Tool 流程(POST /api/webchat/v2/extensions/import,仅管理员)导入。导入校验要求:trust = "third_party"+capability_providerhost_api 形状(上传的 bundle 以ManifestSource::InstalledLocal校验,拒绝 first_party/系统信任声明与旧式顶层[[capabilities]]),manifest 声明的每个资产(WASM 模块、schemas、prompt docs)都必须存在于 zip 中,且拒绝重复 zip 条目与非 WASM 运行时。
3. 构建模块:WASM 组件需要wasm32-wasip2目标(该目标产出的是WASI component,宿主以wasmtime::component::Component::new加载;若误用wasm32-wasip1的核心模块,会在调度时以 "the tool manifest is invalid" 失败):
rustup target add wasm32-wasip2 # 一次性安装 bash scripts/build-test-tools.sh market-data # 构建单个工具构建脚本会把组件产物复制到 manifest 声明的[runtime].module路径(wasm/market_data_tool.wasm)并产出test-tools/market-data.zip。zip 与wasm-src/target/均为 git 忽略的构建产物,仓库只跟踪源码、manifest、schemas 与 prompts。
4. 触发调用:管理员导入并激活后,任意用户向 agent 询问"S&P 500"、"SPX"或整体股市水平时,模型依据能力文档选择market-data.snp500,宿主完成门控与密钥注入后调度 WASM,返回固定快照 JSON。
自动化测试保障:manifest 形状被 CI 锁定
test-tools的 manifest 并非一次性手写文件,而是被测试锁定的契约:Rust 测试套件通过include_str!内联这些 manifest 并断言其保持"可导入"形状(见 test-tools/README.md 提到的available_extensions::tests::test_tool_fixture_manifests_stay_importable),一旦 manifest 偏离合法的导入形状,CI 失败而非 demo 失败。E2E 套件则构建并上传这些 bundle 走完整导入流程。这意味着 manifest.toml 中trust、effects、runtime_credentials等字段的任何改动都会受到回归保护。
小结:一份能力文档背后完整的安全与测试链路
market-data.snp500的能力文档虽只有短短几行,但它串联起了 IronClaw 沙箱工具机制的完整链路:prompt doc 定义模型侧触发语义 → input/output Schema 定义参数与结果契约 → WASM 组件实现固定快照返回 → manifest 声明network+use_secret义务与运行时凭据 → 宿主在 egress 边界注入x-api-key头 → 义务管线测试验证租户共享密钥可满足InjectSecretOnce→ CI 锁定 manifest 可导入性。对于希望理解 IronClaw"能力声明 + 沙箱执行 + 宿主义务"三段式架构的开发者,这个夹具是一个最小但完整的可读样例。
- 人工智能
- AI 应用
- 交互助手
- AI Agent
【免费下载链接】ironclaw
IronClaw is an Agent OS focused on privacy, security and extensibility
相关推荐
EmDash CMS 插件 Hooks 完全指南:从沙箱声明到共享宿主管线的执行语义
EmDash CMS 插件 Hooks 完全指南:从沙箱声明到共享宿主管线的执行语义 导读 本文以 EmDash 插件开发技能库中的 Hooks 参考文档 ht
CMS后端前端插件系统IronClaw 宿主运行时(ironclaw_host_runtime)架构导航:能力中介执行、义务三权分立与首方工具边界
IronClaw 宿主运行时(ironclaw_host_runtime)架构导航:能力中介执行、义务三权分立与首方工具边界 导读 ironclaw_host_
人工智能AI 应用交互助手AI AgentOwncast 插件宿主集成深度解析:WebAssembly 沙箱、HostEnv 接线与事件分发
Owncast 插件宿主集成深度解析:WebAssembly 沙箱、HostEnv 接线与事件分发 Owncast 是自托管直播平台:服务端用 Go 编写,自带
音视频直播后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考