mcpField
C
core

core

github.com/vercel-labs开发18.8k15.3k 次安装5 天前更新
代码仓库

关于 core

@json-render/core 是用于构建 json-render 应用的 TypeScript 核心包,面向需要定义规范、组件目录并处理 AI 生成界面的开发者。它提供规范流、验证和状态表达式,也包含实验性的决策模型组合 API。

主要功能

  1. 01定义 schema 和组件目录
  2. 02生成提示词并流式处理规范
  3. 03解析状态绑定与可见性表达式
  4. 04验证并修复规范结构
  5. 05组合和编辑决策模型规范

适用场景

  1. 01为界面生成定义组件目录
  2. 02逐步处理 JSONL 规范流
  3. 03验证生成的界面规范
  4. 04按候选组件组合或修改界面

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vercel-labs/json-render --skill core

安装后在 Claude Code 中输入/core确认已加载。

详细介绍

@json-render/core

用于定义架构、创建目录和流式传输规范的核心包。

核心概念

  • Schema:定义规范和目录的结构(使用 defineSchema)
  • Catalog:将组件/操作名称映射到其定义(使用 defineCatalog)
  • Spec:符合架构的 AI JSON 输出
  • SpecStream:用于渐进式构建规范的 JSONL 流式格式

实验性决策模型组合

要组合决策模型,请从 @json-render/core 导入 experimental_composeSpec 和 experimental_createEvaluator。这些 API 自 v0.21.0 起可用;请固定使用精确版本,并确保所有 json-render 包的版本相同。实验性导出和 Experimental_ 类型可能在任何版本中发生变化。

  • 在服务端使用 { model: "typesafe-ai/jev", apiKey: process.env.AI_GATEWAY_API_KEY! } 运行 Gateway 评估器。必须使用纯模型标识符;Jev 是当前示例;不要导入提供商构造函数。
  • 调用 experimental_composeSpec({ catalog, candidates, prompt, evaluate, initialState, signal })。它是异步生成器;将 step.spec 快照流式传给现有渲染器,并检查 complete.stopReason(finish、limit、unavailable)。错误和取消会抛出异常;保留最后一个快照作为部分 UI。
  • 新树默认使用 strategy: "batch":一次评估选择根元素和成员,必要时再进行第二次评估来排列所选元素。第一个快照会将所选内容按目录顺序放在根元素的默认/首个插槽下。资源变体共用一个互斥问题;重复计数包含根元素。对于相同的配方/资源,根元素选择优先于冲突的推测成员关系。位置相同的同级元素保留目录顺序。组合布局会在发布前进行验证;出现循环或深度超限时会抛出异常。maxElements 限制批量创建的元素数量(默认值为 32)。选择被限制截断或缺少必要布局调用时,会返回 limit。对于旧版 next/parent 适配器或顺序创建,请使用 strategy: "sequential"。编辑始终按顺序进行。
  • 批量追踪步骤使用 choice: "select" | "layout" 和 answers 记录。每条追踪都计为一次评估,其令牌和延迟也只计算一次。自定义评估器必须回答所有已提供的问题;名称/选项均为不透明值。批量操作依次包含 root/select_*,然后是 parent_*/order_*。
  • 对于后续编辑,将选定版本作为 initialSpec 传入。它会被克隆并验证;评估器可以添加、替换、移除非根子树,或移动/重新排序这些子树。不变的 ID、绑定和状态会保留。可选的 elementDescriptions 会共享用于识别的描述,但不会暴露原始 props/state。initialState 会覆盖种子状态。种子必须是符合目录、表达式子集和深度限制的有效树。匹配配方会消耗使用次数/资源限制;移除/替换会释放这些限制。替换/移动需要两次评估(选择目标,然后选择配方/目的地),每次都计入预算。将操作键和位置键视为不透明值。
  • 提供原子候选项 { id, description, element: { type, props, on?, visible? }, root?, maxUses?, resource? }。仅有目录并不足够:应用必须提供值和绑定配方。Jev 只选择元素和父级插槽,不会生成自由文本或代码。它不会执行操作。
  • 候选项是已配置的组件实例,而不是页面模板。根据当前应用记录/操作构建候选项,或将 props 绑定到 initialState;为图表类型、字段配置和布局变体提供明确选项。模型会在这些选项范围内选择分组和顺序。在提示词中注明必需的部分;结构有效并不意味着语义完整。
  • V1 支持扁平 Spec 目录、命名插槽、字面量、$state、$bindState 和状态可见性。不支持预置子元素、repeat/watch、computed/template/conditional props 或自定义指令。成功/错误回调必须引用允许的操作。事件必须在组件目录中声明。
  • Props 和操作参数会根据初始状态进行验证,但不会应用 schema 转换/默认值。请提供有效的初始值,并在运行时验证/授权操作调用。没有参数 schema 的内置项只会进行名称验证。
  • root 默认值为 true,maxUses 默认值为 one,共享的 resource 值会使候选项互斥。默认值:32 次评估(包含终止调用;批量操作不会额外进行 finish 调用)、深度为 8、每次 Gateway 调用超时为 10 秒。请提供整体中止信号。
  • 候选项描述、提示词、指令、拓扑和显式 context 会发送给评估器。初始状态和原始 props/绑定值不会自动发送。
  • 对于自定义提供商,请实现 Experimental_CompositionEvaluator:接收 { state, questions, signal },返回 { answers: { [question]: { choice, confidence? } }, usage?: { inputTokens? } }。仅返回已提供的 criteria 键。 请参阅 packages/core/README.md 和 /docs/jev,了解应用集成和安装说明。Web playground 是一个示例使用方,并非 API 的依赖项。

定义 Schema

import { defineSchema } from "@json-render/core";

export const schema = defineSchema((s) => ({
  spec: s.object({
    // Define spec structure
  }),
  catalog: s.object({
    components: s.map({
      props: s.zod(),
      description: s.string(),
    }),
  }),
}), {
  promptTemplate: myPromptTemplate, // Optional custom AI prompt
});

创建目录

import { defineCatalog } from "@json-render/core";
import { schema } from "./schema";
import { z } from "zod";

export const catalog = defineCatalog(schema, {
  components: {
    Button: {
      props: z.object({
        label: z.string(),
        variant: z.enum(["primary", "secondary"]).nullable(),
      }),
      description: "Clickable button component",
    },
  },
});

生成 AI 提示词

const systemPrompt = catalog.prompt(); // Uses schema's promptTemplate
const systemPrompt = catalog.prompt({ customRules: ["Rule 1", "Rule 2"] });

SpecStream 工具

用于流式传输 AI 响应(JSONL 补丁):

import { createSpecStreamCompiler } from "@json-render/core";

const compiler = createSpecStreamCompiler<MySpec>();

// Process streaming chunks
const { result, newPatches } = compiler.push(chunk);

// Get final result
const finalSpec = compiler.getResult();

操作处理程序中的表单值

使用 findFormValue("email", params, state),读取直接参数、点分隔的参数键(例如 "form.email")、匹配的扁平状态键,或嵌套状态中的斜杠分隔路径(例如 "/form/email")。参数值按字面处理,因此电子邮件和 URL 中的点号会保留。对于读取嵌套状态的操作绑定,请使用 { $state: "/form/email" };解析器会将该值传递给处理程序。单独的 "email" 字段名不会搜索嵌套的 state.form.email。

动态 Prop 表达式

任何 prop 值都可以是渲染时解析的动态表达式:

  • { "$state": "/state/key" } - 读取状态模型中的值(单向读取)
  • { "$bindState": "/path" } - 双向绑定:读取状态并启用写回。在表单组件的自然值 prop(value、checked、pressed 等)上使用。
  • { "$bindItem": "field" } - 双向绑定到重复项字段。在重复项作用域内使用。
  • { "$cond": <condition>, "$then": <value>, "$else": <value> } - 计算可见性条件并选择一个分支
  • { "$template": "Hello, ${/user/name}!" } - 使用状态值插入 ${/path} 引用
  • { "$computed": "fnName", "args": { "key": <expression> } } - 使用解析后的参数调用已注册函数

$cond 使用与可见性条件相同的语法($state、eq、neq、not,数组表示 AND)。$then 和 $else 本身也可以是表达式(递归)。

组件不使用 statePath prop 进行双向绑定。相反,请在自然值 prop(例如 value、checked、pressed)上使用 { "$bindState": "/path" }。

{
  "color": {
    "$cond": { "$state": "/activeTab", "eq": "home" },
    "$then": "#007AFF",
    "$else": "#8E8E93"
  },
  "label": { "$template": "Welcome, ${/user/name}!" },
  "fullName": {
    "$computed": "fullName",
    "args": {
      "first": { "$state": "/form/firstName" },
      "last": { "$state": "/form/lastName" }
    }
  }
}
import { resolvePropValue, resolveElementProps } from "@json-render/core";

const resolved = resolveElementProps(element.props, { stateModel: myState });

状态观察器

元素可以声明 watch 字段(顶层,与 type/props/children 同级),在状态值发生变化时触发操作:

{
  "type": "Select",
  "props": { "value": { "$bindState": "/form/country" }, "options": ["US", "Canada"] },
  "watch": {
    "/form/country": { "action": "loadCities", "params": { "country": { "$state": "/form/country" } } }
  },
  "children": []
}

观察器只会在值发生变化时触发,不会在初始渲染时触发。

验证

内置验证函数:required、email、url、numeric、minLength、maxLength、min、max、pattern、matches、equalTo、lessThan、greaterThan、requiredIf。

跨字段验证在参数中使用 $state 表达式:

import { check } from "@json-render/core";

check.required("Field is required");
check.matches("/form/password", "Passwords must match");
check.lessThan("/form/endDate", "Must be before end date");
check.greaterThan("/form/startDate", "Must be after start date");
check.requiredIf("/form/enableNotifications", "Required when enabled");

用户提示词构建器

构建结构化的用户提示词,可选择优化 spec 并加入状态上下文:

import { buildUserPrompt } from "@json-render/core";

// Fresh generation
buildUserPrompt({ prompt: "create a todo app" });

// Refinement with edit modes (default: patch-only)
buildUserPrompt({ prompt: "add a toggle", currentSpec: spec, editModes: ["patch", "merge"] });

// With runtime state
buildUserPrompt({ prompt: "show data", state: { todos: [] } });

可用的编辑模式:"patch"(RFC 6902 JSON Patch)、"merge"(RFC 7396 Merge Patch)、"diff"(统一 diff)。

Spec 验证

验证 spec 结构并自动修正常见问题:

import { validateSpec, autoFixSpec } from "@json-render/core";

const { valid, issues } = validateSpec(spec);
// issues include: missing_child, invalid_visible (malformed conditions),
// repeat_without_children, repeat_item_outside_scope, repeat_state_mismatch

const { spec: fixed, fixDetails } = autoFixSpec(spec);
// fixDetails entries are { message, lossy }. Lossless fixes relocate
// misplaced fields; lossy fixes prune dangling children references.
// In a repair loop, withhold lossy fixes until retries are exhausted:
const attempt = autoFixSpec(spec, { lossy: retriesExhausted });

可见性条件

使用基于状态的条件控制元素可见性。VisibilityContext 是 { stateModel: StateModel }。

import { visibility } from "@json-render/core";

// Syntax
{ "$state": "/path" }                    // truthiness
{ "$state": "/path", "not": true }      // falsy
{ "$state": "/path", "eq": value }      // equality
[ cond1, cond2 ]                         // implicit AND

// Helpers
visibility.when("/path")                 // { $state: "/path" }
visibility.unless("/path")               // { $state: "/path", not: true }
visibility.eq("/path", val)              // { $state: "/path", eq: val }
visibility.and(cond1, cond2)             // { $and: [cond1, cond2] }
visibility.or(cond1, cond2)              // { $or: [cond1, cond2] }
visibility.always                        // true
visibility.never                         // false

Schema 中的内置操作

Schema 可以声明 builtInActions ——始终可在运行时使用并自动注入提示词的操作:

const schema = defineSchema(builder, {
  builtInActions: [
    { name: "setState", description: "Update a value in the state model" },
  ],
});

这些操作会在提示词中显示为 [built-in],且无需在 defineRegistry 中设置处理程序。

StateStore

StateStore 接口允许将外部状态管理库(Redux、Zustand、XState 等)接入 json-render 渲染器。createStateStore 工厂会创建一个简单的内存实现:

import { createStateStore, type StateStore } from "@json-render/core";

const store = createStateStore({ count: 0 });

store.get("/count");         // 0
store.set("/count", 1);      // updates and notifies subscribers
store.update({ "/a": 1, "/b": 2 }); // batch update

store.subscribe(() => {
  console.log(store.getSnapshot()); // { count: 1 }
});

StateStore 接口:get(path)、set(path, value)、update(updates)、getSnapshot()、subscribe(listener)。

主要导出

导出用途
defineSchema创建新架构
defineCatalog根据架构创建目录
createStateStore创建与框架无关的内存 StateStore
resolvePropValue根据数据解析单个属性表达式
resolveElementProps解析元素中的所有属性表达式
buildUserPrompt构建包含优化和状态上下文的用户提示词
buildEditUserPrompt构建用于编辑现有规范的用户提示词
buildEditInstructions生成包含可用编辑模式的提示词部分
isNonEmptySpec检查规范是否包含根节点和至少一个元素
deepMergeSpecRFC 7396 深度合并(null 表示删除,数组替换,递归合并对象)
diffToPatches根据对象差异生成 RFC 6902 JSON Patch 操作
EditMode类型:"patch" | "merge" | "diff"
validateSpec验证规范结构
autoFixSpec自动修复常见的规范问题;将修复分为有损和无损,{ lossy: false } 会禁用剪枝
createSpecStreamCompiler将 JSONL 补丁流式写入规范
createJsonRenderTransform用于在混合流中分离文本与 JSONL 的 TransformStream
parseSpecStreamLine解析单行 JSONL
applySpecStreamPatch将补丁应用于对象
StateStore用于接入外部状态管理的接口
ComputedFunction$computed 表达式的函数签名
check用于创建验证检查项的 TypeScript 辅助工具
BuiltInAction内置操作定义的类型(name + description)
ActionBinding操作绑定类型(包含 preventDefault 字段)

评论

支持 Markdown