Module Structure
该组件以 TypeBox schema 同时提供 TypeScript 静态类型、运行时输入验证和公开输出投影;Web 构建直接别名到 CLI 的 browser-safe API 源码,避免复制 DTO。
Directory Layout
packages/cli/src/schema/index.ts—Runtime、Default、StringEnum和 TypeBox 导出packages/cli/src/schema/validation.ts— clone、default、validate、clean 和结构化错误packages/cli/src/api/schemas.ts— Session、Task、消息、权限、模型和设置公共合约packages/cli/src/api/browserSchemas.ts— Browser 导航与交互的封闭输入 unionpackages/cli/src/api/teamSchemas.ts— Team 快照和写请求合约packages/cli/src/api/attachmentLimits.ts— 多表面共享的消息与附件上限packages/cli/src/api/promptCacheMetrics.ts— Provider cache 指标的安全派生与展示packages/cli/src/tools/validation/schemaToJson.ts— Provider function schema 清理packages/cli/web/vite.config.ts— Web@api到 CLI API 源码的构建别名
Key Entry Points
Runtime(schema)— 给 TypeBox schema 增加不可枚举的parse/safeParsesafeParseSchema(schema, value)— 返回 discriminated result,不抛异常parseSchema(schema, value)— 校验失败时抛SchemaValidationErrorschemaToFunctionSchema(schema)— 生成不含 TypeBox runtime 注解的封闭 JSON SchemaSessionSchema/CreateTaskRequestSchema/PermissionResponseSchema— 跨 Server/Web 高频公共合约
API Surface
Runtime Schema Helpers
Runtime(schema)— 保留标准 JSON Schema 可序列化形状,并附加非枚举解析方法Default(schema, value)— 输入字段可省略,解析结果应用默认值StringEnum(values, options?)— 生成所有 pi-ai Provider 都能接受的字符串 enum JSON SchemasafeParseSchema(schema, value)— 适合 HTTP 入口映射 4xxparseSchema(schema, value)— 适合可信内部边界和输出投影SchemaValidationError.issues— 提供解码后的字段路径、keyword、消息和原值
Shared Contracts
SessionSchema— 公开 Session 身份、lineage、任务状态和资源选择,不包含内部 lease 对象CreateTaskRequestSchema/CreateTaskResponseSchema— Task 默认隔离、权限模式和准入状态SendMessageRequestSchema— 消息、模型、附件与 structured output 输入边界BrowserActionSchema— Browser 交互 discriminated union,显式禁止额外属性TeamSnapshotSchema— Team 成员和任务图的跨表面只读投影
Usage Examples
Hono 路由验证请求
const parsed = safeParseSchema(CreateTaskRequestSchema, body);
if (!parsed.success) {
throw new BadRequestError('Invalid task request');
}
Web 客户端验证服务端响应
const res = await fetch(`${API_BASE}/sessions/catalog?${params.toString()}`);
if (!res.ok) throw new Error('Failed to load session catalog');
return SessionCatalogPageSchema.parse(await res.json());
Gotchas
Runtime()的parse和safeParse必须保持不可枚举;若直接把方法赋到 schema,对 Provider 序列化工具声明时会泄漏非 JSON Schema 字段 (packages/cli/src/schema/index.ts,packages/cli/src/tools/validation/schemaToJson.ts)- 解析顺序是 clone → 应用 default → 首次校验 →
Value.Clean删除未知字段 → 再校验;因此 schema 既会补默认值,也会把内部字段从公开响应中裁掉 (packages/cli/src/schema/validation.ts) Default()刻意把输入标记为 optional、把解析后的静态类型保持为 required;改成普通Type.Optional会迫使所有下游重新处理本应已默认化的undefined(packages/cli/src/schema/index.ts)StringEnum()使用标准type: string + enum而不是 TypeBox 特有 union 注解,避免不同 pi-ai Provider 对函数 schema 的兼容差异 (packages/cli/src/schema/index.ts)- Server 不能只校验请求而直接返回领域对象;
SessionSchema.parse()等输出投影负责移除taskWorktree、宿主路径和其他私有字段 (packages/cli/src/api/schemas.ts,packages/cli/tests/unit/integrations/api/schemas.test.ts) SessionSchema会为缺失的taskStatus默认completed;读取旧会话时不能用字段缺失推断“未知”或“仍运行” (packages/cli/src/api/schemas.ts)SendMessageRequestSchema的 1,000,000 字符上限不是内联阈值;超过 32 KiB 但未超过 4 MiB 的文本仍合法,后续由 prompt artifact 边界卸载 (packages/cli/src/api/attachmentLimits.ts,packages/cli/tests/unit/integrations/api/schemas.test.ts)- TypeBox 只限制单附件 content,Task 路由还会累计所有附件字节并执行共享 5 MiB 上限;新增入口时必须复用同一聚合检查 (
packages/cli/src/api/schemas.ts,packages/cli/src/server/routes/task.ts) - Browser action 对象显式
additionalProperties: false,用于防止模型或客户端把未审阅字段带入浏览器副作用;扩展 action 必须同步修改 union,而不是旁路读取原始 body (packages/cli/src/api/browserSchemas.ts) - Web 通过
@api直接打包packages/cli/src/api;该目录新增 Node-only 顶层依赖会破坏浏览器 bundle,即使服务端类型检查仍通过 (packages/cli/web/vite.config.ts) schemaToFunctionSchema()会剥离所有~runtime 注解,并递归为对象补additionalProperties: false;把 Runtime schema 直接发给 Provider 会丢失这层闭合保证 (packages/cli/src/tools/validation/schemaToJson.ts)- 公共 API schema 持续高频跨 Server、Web、ACP 和持久化层共改;字段重命名属于多表面迁移,不能只在
schemas.ts做局部修复 (packages/cli/src/api/schemas.ts,git:e7ae302d)
Architecture
packages/cli/src/schema/是通用运行时 schema 层,packages/cli/src/api/只放跨表面安全契约;领域内部对象先投影后才能进入 HTTP、SSE 或 Web Store (packages/cli/src/schema/index.ts,packages/cli/src/api/schemas.ts)- Hono 路由通常以
safeParseSchema()把不可信输入映射为BadRequestError,而 Web service 以.parse()验证成功响应,形成双向契约检查 (packages/cli/src/server/routes/task.ts,packages/cli/web/src/services/sessionService.ts) - 大型领域合约从主文件拆到
browserSchemas.ts和teamSchemas.ts,但继续复用同一 Runtime helper 和 Web alias (packages/cli/src/api/browserSchemas.ts,packages/cli/src/api/teamSchemas.ts)
Decisions
- 项目从 Zod 迁移到 TypeBox,以单份 schema 原生生成 JSON Schema 并服务工具协议,同时保留类似
parse的调用体验 (packages/cli/src/schema/index.ts,git:311ba368) - Session 公共 schema只保存稳定复合身份和可恢复 metadata,不公开内部 worktree lease、Provider 错误正文或资源句柄 (
packages/cli/src/api/schemas.ts) - session title 与 prompt-cache 指标放在共享 API 目录中是为了让 CLI、Web 和 ACP 使用确定性算法,而不是由各表面独立格式化 (
packages/cli/src/api/sessionTitle.ts,packages/cli/src/api/promptCacheMetrics.ts)
Consumer Analysis
- Server 路由是最大运行时校验消费者,请求使用 safe parse,领域结果使用 parse 做安全投影 (
packages/cli/src/server/routes/) - Web services 对 Session、Task、Team 和 Browser 响应再次解析,阻止后端漂移进入 Store (
packages/cli/web/src/services/) - 内置工具和工具构造器使用 TypeBox 定义参数,再转为 Provider function schema (
packages/cli/src/tools/builtin/,packages/cli/src/tools/core/) - Commands 与 CLI 复用 Runtime helper 校验 Headless 选项、JSONL 事件和配置输入 (
packages/cli/src/commands/,packages/cli/src/cli/) - MCP 与插件系统用同一解析器校验协议 payload、凭据账本和插件 manifest (
packages/cli/src/mcp/,packages/cli/src/plugins/)