mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-23 03:18:09 +08:00
140 lines
6.0 KiB
Markdown
140 lines
6.0 KiB
Markdown
# ADR-0133:不可变 Tool Registry 与 Policy-fenced Invocation Plan
|
||
|
||
- 状态:Accepted(profile-neutral ToolDefinition registry、受限 JSON Schema、
|
||
Project Policy 聚合、Agent Approval 判定和 digest-bound invocation plan 已实现;
|
||
handler、StepRun、preview、ApprovalRequest publisher、MCP/HTTP adapter 与生产组合仍
|
||
未开放)
|
||
- 日期:2026-07-24
|
||
- 关联 RFC:QL-RFC-0001 D-08、D-09、D-131
|
||
|
||
## 背景
|
||
|
||
AI Agent、MCP、Package 和内置功能都需要调用 Tool。如果每个入口各自:
|
||
|
||
- 解析一份 Tool schema;
|
||
- 猜测权限和审批要求;
|
||
- 直接持有 handler;
|
||
- 在运行期注册或扫描 Tool;
|
||
|
||
就会出现权限旁路、不同输入语义、插件移除后的行为漂移和低配设备常驻开销。
|
||
现有 `ProjectPolicyEngine` 已经提供稳定 Principal、Project permission 和
|
||
Project/RoleBinding version fence;Tool 层必须复用它,不能建立第二套 RBAC。
|
||
|
||
## 决策
|
||
|
||
### 1. Tool Registry 留在 `@qinglong/runtime-core`
|
||
|
||
新增 `tool-registry` subpath,不新增 workspace package或第三方依赖。Registry 在受信
|
||
composition root 中一次性接收 0–128 个 definition,构造后冻结,不提供 `register`、
|
||
目录扫描、watcher、timer、socket、数据库或 handler 注入。
|
||
|
||
同一 `(name, version)` 只能出现一次。Tool name 必须是小写分段标识,version 必须
|
||
是 canonical SemVer。调用必须精确指定 version,不提供 latest、wildcard 或运行期
|
||
fallback。
|
||
|
||
### 2. 首版只实现有界 JSON Schema 子集
|
||
|
||
QL3 不在核心中接受任意 JSON Schema draft。首版只允许:
|
||
|
||
- `null`、`boolean`;
|
||
- 有显式 `maxLength` 的 `string`,可选 `minLength` 和有界 enum;
|
||
- 有显式安全上下界的 `number`、`integer`;
|
||
- 有显式 `maxItems` 的 array,可选 `minItems`、`uniqueItems`;
|
||
- `additionalProperties: false` 的 object,显式 properties 和 required。
|
||
|
||
拒绝 `$ref`、`oneOf`、`anyOf`、任意 regex、默认值、coercion、未知 keyword 和
|
||
开放 additional properties。Schema 深度最多 8、节点最多 256、object properties
|
||
最多 64、enum 最多 64、array 最多 256 项。
|
||
|
||
Tool input 根必须是 object。canonical input 最大 64 KiB,output 最大 256 KiB。
|
||
没有 `outputSchema` 的 Tool 只能返回 `null`,不能把“未声明 output”解释为任意输出。
|
||
|
||
### 3. Registry 不拥有执行能力
|
||
|
||
Definition 只包含:
|
||
|
||
- name、version、description;
|
||
- input/output schema;
|
||
- `read | write | execute | external` effect;
|
||
- `low | medium | high | critical` risk;
|
||
- 最多 16 个 Project permission;
|
||
- 1–3600 秒 timeout。
|
||
|
||
Registry 只规范化 definition/input/output 和生成 invocation plan。Definition、
|
||
Registry 和 plan 均不包含 `execute`、handler、数据库 service 或网络 client。
|
||
Package、MCP 或 Agent 不能通过注册 Definition 把代码注入控制面。
|
||
|
||
### 4. 每次调用先 Policy,后解析输入
|
||
|
||
`prepareToolInvocation` 固定执行:
|
||
|
||
1. 精确解析 request envelope 和 Tool identity;
|
||
2. 验证当前 Principal;
|
||
3. 对 `tool.call:{name}` 和 Definition 的每项 required permission 调用既有
|
||
`ProjectPolicyEngine.authorize` 端口;
|
||
4. 任一 deny 立即停止,且不解析 Tool input;
|
||
5. 所有非 deny decision 必须包含完全相同的 Project/RoleBinding fence;
|
||
6. 任一 decision 为 `require_approval` 时生成 `approval_required` plan;
|
||
7. 只有之后才按 schema 规范化 input,并生成 input/action SHA-256。
|
||
|
||
Policy 存储异常、畸形 decision、空 fence 或不同 fence 混用全部失败关闭。这样多
|
||
permission Tool 不能把不同 Project 版本或 revoke 前后的授权拼成一个调用。
|
||
|
||
### 5. Action digest 是 Approval/Dispatch 的稳定输入,不是执行授权
|
||
|
||
action digest 绑定:
|
||
|
||
- `qinglong/tool-invocation@v1`;
|
||
- Project、稳定 actor subject;
|
||
- exact Tool name/version;
|
||
- `tool.call:{name}` 和 required permissions;
|
||
- effect、risk、timeout;
|
||
- canonical input digest。
|
||
|
||
它不保存 input、Prompt、Secret 或 handler,也不等于已审批。`approval_required`
|
||
仍必须由后续 preview builder 产生 preview digest,再进入既有
|
||
ApprovalRequest/immutable dispatch/start barrier。`ready` plan 也必须由受审 handler
|
||
registry、StepRun/Trace/Audit 组合消费;本 ADR 不提供直接 execute seam。
|
||
|
||
## 影响
|
||
|
||
- AI Agent 通过真实 Project Policy 调用任意 Tool 时,`tool.call:*` 继续返回
|
||
`require_approval`。
|
||
- MCP、Package 和内置 Tool 共用同一 schema、permission 和 fence 语义。
|
||
- edge 只在显式 Tool 调用时支付 schema/input 规范化成本;禁用 Tool 时零 timer、
|
||
socket、数据库和后台进程。
|
||
- `packages/` 数量不增加,runtime-core 只增加一个源码文件和 subpath。
|
||
|
||
## 未完成边界
|
||
|
||
以下内容仍需独立闭环:
|
||
|
||
- built-in/package Tool handler registry;
|
||
- ADR-0150 已完成 Package Tool JSON 到 ToolDefinition 的来源/PackageLock/
|
||
generation 绑定;全部 active generation 的全局 immutable snapshot 仍未完成;
|
||
- preview/dry-run 和 ApprovalRequest publisher;
|
||
- Approved Action handler、receipt/evidence provider;
|
||
- StepRun、Trace、redaction 和 durable audit;
|
||
- MCP Server、MCP Client、HTTP/API 与 Agent adapter;
|
||
- Tool version retirement 与历史 Run/PackageLock 解析。
|
||
|
||
在这些能力完成前,Tool Registry 保持 production unreachable。
|
||
|
||
## 验证
|
||
|
||
测试必须覆盖:
|
||
|
||
1. immutable registry、exact version 和无 runtime register;
|
||
2. root/subpath 导出一致;
|
||
3. JSON Schema exact subset;
|
||
4. schema depth/node/property 上限;
|
||
5. canonical input/output、未知字段与 unique array;
|
||
6. 无 output schema 时只允许 null;
|
||
7. 同一 Policy fence 的 digest-bound ready plan;
|
||
8. 真实 Project Policy 下 Agent Tool call 需要审批;
|
||
9. deny 在 input 解析前短路;
|
||
10. Policy unavailable、畸形 decision 和 mixed fence;
|
||
11. 过期 Principal 与扩展 request 拒绝;
|
||
12. canonical envelope byte budget;
|
||
13. 无 filesystem/process/network/timer/execute authority。
|