
oh-my-pi 内部 schema 编写指南深入 omptype 的懒加载 JIT 校验器与 ArkType 兼容 DSL【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi导读本文是 oh-my-pi 仓库内部 schema 编写schema authoring的技术指南围绕 docs/omptype-guide.md 展开。oh-my-pi 的 AI 工具系统在 provider 边界需要把工具参数定义序列化为模型可消费的 JSON Schema同时对入参做高性能运行时校验为此项目自研了oh-my-pi/omptype——一个 ArkType 兼容、带懒加载 JIT 的校验器。读完本文你将掌握omptype 的性能契约与「检测契约」schema 与 JSON Schema 如何在 wire 上被区分、完整可复制的 ArkType 兼容字符串 DSL 定义语言、验证/断言/作用域/泛型/JSON Schema 互操作等核心用法以及 TypeBox/Zod 风格适配器与 Standard Schema V1 的接入方式并能基于仓库源码理解其内部实现原理。为什么是 omptype性能契约内部 schema 统一使用oh-my-pi/omptype——一个 ArkType 兼容、带懒加载 JIT 运行时的校验器实现位于 packages/omptype包说明见 packages/omptype/README.md。编写类型统一通过import { type } from oh-my-pi/omptype导入。其性能设计的关键点如下对应 packages/omptype/src/type.ts 的文档注释与JIT_THRESHOLD 3常量见 type.ts构造极廉价type()构造 schema 的成本大约是 arktype 的 1/100。它不做急切代码生成eager codegen、不做 node interningschema 从字符串 DSL 解析为 IR 的开销接近零。两段式执行schema 的前两次调用由树遍历解释器interp.ts执行第三次调用起通过new Function编译出专用校验器并热替换编译逻辑见 compile.ts。这样「每个请求新建、只校验一次」的冷 schema 不会为编译付税而热路径上被反复调用的 schema 校验耗时可降到几十纳秒级。失败路径零浪费失败只分配一个小的错误对象消息字符串按需懒构建见 errors.ts 的设计说明。没有函数级的jitless模式懒加载 JIT 已经把jitless想规避的启动开销移除了直接import { type }即可。ScopeOptions虽然接受jitless标志用于 ArkType 兼容但运行时从不读取它——这是兼容面不是功能开关。仓库自带的基准 packages/omptype/bench/bench.ts 展示了该设计的目标形态type()构造 509ns对比 ArkType 271.08µs快约 532 倍、热路径flat-small校验 25ns对比 ArkType 5.10µs等。这些数字来自 README 中 Apple M4 Max Bun 1.3.14 的单次代表性运行结果会随硬件、运行时与依赖版本变化应以本地复测为准bun packages/omptype/bench/bench.ts。检测契约omptype schema 与 JSON Schema 如何被区分在 provider 边界工具参数既可能由 omptype schemaArkType 风格可调用函数编写也可能来自遗留的 TypeBox 或纯 JSON Schema 文档。两者通过 packages/ai/src/utils/schema/wire.ts 统一归一化omptype可调用函数且带有.toJsonSchema与.assert方法——isArkSchema()正是按此判定见 wire.ts。JSON Schema普通对象直接按 JSON Schema 文档处理。在边界处toolWireSchema()见 wire.ts会调用toJsonSchema()生成 wire 表示然后做三类后处理剪除T | undefined分支undefined在 JSON Schema 中没有对应形态ArkType 会把它降级为空 schema 分支导致{ anyOf: [{ type: string }, {}] }这类任意值都匹配的形态严格 provider如 OpenAI/Codex会拒绝。pruneArkUndefinedUnionBranches()会从 ArkType 产出的anyOf/oneOf中丢弃无约束分支并内联唯一剩余分支见 wire.ts。闭合已声明对象递归地为声明了properties且没有additionalProperties/patternProperties的对象节点设置additionalProperties: false让模型面对的是闭合结构closeDeclaredObjects见 wire.ts。{}→true归一化把无约束空 schema 归一化为布尔true因为语法受限的采样器常把对象形态的{}理解成「生成空对象」而非「任意 JSON 值」见 wire.ts。此外.narrow()谓词与.pipe()morph 只在本地校验时生效在 wire 上会降级为其基础 schema——也就是说发送给模型的是结构约束模型产出的 JSON 仍会在本地接受这些谓词/morph 的二次校验。定义语言ArkType 兼容子集速查omptype 直接使用 ArkType 兼容的字符串 DSL 编写定义。以下是完整构造对照表源自指南原文已结合源码确认其 IR 语义构造形式基本类型string、number、boolean、null、undefined、unknown、object、bigint整数number.integerURL 字符串string.url字面量x、5、true联合a \| b、string \| null数组string[]、(string \| number)[]、[def, []]边界number 0、0 number 3600、1 string 10可选键{ limit?: number }或值后缀{ limit: number? }默认值{ count: number 10 }、type(string[]).default(() [])未声明键: reject失败/: delete剥离/ 默认保留记录{ [string]: number }—— 注意不是Recordstring, number运行时枚举type.enumerated(...RUNTIME_ARRAY)运行时拼装对象定义type.raw({...})返回BaseType关键字静态方法type.number.atLeast(5).atMost(300)、type.string几点实现佐证number.integer对应 IR 中int标志解释器在 interp.ts 用Number.isInteger(v)校验string.url对应url标志用URL.canParse(v)校验interp.ts。type.enumerated(...)把运行时数组的每个元素编译成字面量节点并合成联合见 type.tstype.raw(def)直接makeType(parseDef(def), [], {})见 type.ts。对象默认值在构造期会被预校验normalizeDefaults会用解释器跑一遍默认值非法默认值在type()时直接抛OmpTypeError见 type.ts可变静态默认值对象/数组会被拒绝必须写成工厂函数rejectMutableStaticDefault见 type.ts。验证与 arktype 相同的调用方式import { type } from oh-my-pi/omptype; const out schema(value); if (out instanceof type.errors) { // out.summary → 人类可读消息每个条目有 .path数组与 .problem throw new Error(out.summary); } // out 是验证/变形后的值默认值已填充、多余键已剥离关键语义失败返回OmpErrorsOmpError的数组type.errors OmpErrors。校验是快速失败fast-fail每次失败只产生一个错误条目。Morph 从不修改输入当默认值、: delete、pipes 生效时会返回全新对象。绝不要用.allows()做工具参数校验——它跳过 morphs/defaults/pipes。.infer/.inferIn仅用于类型推断type-only运行时无值。定义期错误坏 DSL、非法组合在type()时抛OmpTypeError。错误对象层面errors.ts单条OmpError暴露code、path、expected、actual、problem、message聚合OmpErrors暴露summary与byPath支持数组式迭代map/filter/[Symbol.iterator]。消息文本可经.configure()以字符串或回调覆盖。assert()失败时抛TraversalError携带errors见 type.ts 与 errors.ts。联合类型失败还有针对性细节当值明显指向某个分支时会深入该分支产出精确的嵌套错误路径、narrow 消息而不是笼统的 A or B 期望——unionFail/discriminateFailure会根据字面量判别属性如type: computer_call定位具体分支见 interp.ts。方法一览Fluent 方法全集对应 type.ts 的接口定义.describe(d)、.default(v | () v)、.or(TypeOrStringDef)、.and(Type)、.array()、.atLeastLength(n)/.atMostLength(n)字符串/数组长度、.atLeast(n)/.atMost(n)数值边界、.pipe(fn)、.narrow(fn)配合ctx.mustBe(...)使用、.allows(v)、.assert(v)、.toJsonSchema()。.or()的推断注意点schema 操作数和字符串操作数都能精确推断对象字面量操作数会降级为宽泛类型——先用type({...})包装再参与.or()。方法底层都是 IR 变换.atLeast(n)/.atMost(n)写入数值 min/maxwithNumericBound.matching(RegExp)与 pattern IR 求交日期边界.atOrAfter等编译为时间戳谓词 refine见 type.ts。.default()在构造期即用解释器验证默认值并缓存产出静态默认值缓存defaultOutput工厂默认值每次调用执行见 type.ts 与 type.ts。作用域、模块与泛型递归或互相引用的 schema 走具名作用域实现在 type.ts 的scope()/type.scope()import { type } from oh-my-pi/omptype; const types type.module({ tree: { value: number, children?: tree[] }, });type.scope(aliases)顶层也导出scope()返回一个TypeScope具备.type、.define、.resolve、.import、.export别名可以互相递归引用#private名称保持内部可见性不对外暴露。type.module({...})把具名模块编译等价于scope(...).export()成一组就绪 schema 的映射。type.generic(T, def)构造运行时泛型其他定义可在作用域内对它实例化。generic还支持带可选约束的柯里化形式见 type.ts。作用域采用惰性别名解析支持环cycles别名节点在解析前先注册占位递归引用会命中同一节点而非无限递归resolveRef的注册先于lower见 from-json-schema.ts。此外还提供type.define()保留字面定义用于复用模块type.fn(...)可为函数参数/返回值做运行时校验TypedFunction见 type.ts。JSON Schema 互操作.toJsonSchema()默认输出 draft-2020-12支持target: draft-07递归别名会发射$defs/$ref。选项还包括dialect、description、ioinput/output分别描述 morph 的输入或输出形态与fallback回调见 json-schema.ts。fromJsonSchema(schema)从 JSON Schema 文档重建可调用 schema——toJsonSchema()的逆操作。支持 draft-07 / draft-2020-12 的结构化关键字、字符串 formatemail、uuid、date-time、ipv4/ipv6、regex 等映射为内置关键字见 from-json-schema.ts、$defs递归、enum、anyOf/oneOf/allOf组合。未知或非结构化关键字被宽容忽略保留能表达的约束其余透传。additionalProperties: false会映射为extras: reject对象形态的additionalProperties映射为索引签名见 from-json-schema.ts。type.withJsonSchema(schema, json)包装一个仅做验证的 schema使其.toJsonSchema()即使嵌套在对象、数组或联合中也原样发射json带默认值或改变输出的 morph 的 schema 会被拒绝。每个 schema 通过~standard暴露Standard Schema V1同步validate可直接与t3-oss/env、tRPC 等 Standard Schema 消费者配合使用。实现内联在 type.ts~standard.validate调用run()jsonSchema.input/output委托toJsonSchema()且仅接受 draft-2020-12 与 draft-07 两种 target。适配器TypeBox 风格与 Zod 风格TypeBox 风格与 Zod 风格的编写 API 底层都是同一个 omptype 运行时产出的是真正的 omptype schema同样具备 JIT 校验与toJsonSchemaimport { Type, type Static } from oh-my-pi/omptype/typebox; import { z } from oh-my-pi/omptype/zod; const User z.object({ name: z.string() }); type User z.infertypeof User;Zod 适配器zod.ts提供parse/safeParse、min/max/int/positive/regex/url、optional/nullable/default/describe/refine/transform/catch、strict/passthrough/strip/partial等 Zod v4 风格 surface底层通过type.raw(embedded)与 morph/refine IR 落回 omptype 运行时。TypeBox 适配器typebox.ts与oh-my-pi/omptype/arkArkType 兼容门面复导出同一套type/scope实现同理。内部代码统一直接使用字符串 DSL 编写 schema即本文第二部分介绍的写法适配器主要面向需要迁移既有 Zod/TypeBox 代码的场景。何时校验把 omptype 放回 AI 工具管线回顾整体用法工具作者在本地用 omptype DSL 声明参数toolWireSchema()在边界把它转成 provider 消费的 JSON Schema剪undefined分支、闭合对象、归一化空 schema模型返回的 JSON 再经由同一 omptype schema 做带 morph/默认值的运行时校验谓词与 morph 只在本地位移生效。关键文件路径包入口与实现packages/omptype/src/index.ts、packages/omptype/src/type.ts、packages/omptype/src/interp.ts、packages/omptype/src/compile.ts、packages/omptype/src/errors.tsJSON Schema 发射与导入packages/omptype/src/json-schema.ts、packages/omptype/src/from-json-schema.tsProvider 边界归一化packages/ai/src/utils/schema/wire.ts包级说明与基准packages/omptype/README.md、packages/omptype/bench/bench.ts【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考