From 6ebc570632b8fa26feb4a5c39b19c35d8d33b2d8 Mon Sep 17 00:00:00 2001 From: chendelian <116870791@qq.com> Date: Sun, 16 Aug 2026 12:58:39 +0800 Subject: [PATCH] docs: precipitate Action/CRUD Lookup contract for skill authors --- CHANGELOG.md | 6 +++ SKILL.md | 2 +- assets/examples/README.md | 1 + assets/examples/lookup-action.example.json | 48 +++++++++++++++++ assets/schemas/skill-actions.schema.json | 56 +++++++++++++++++-- development/CHECKLIST.md | 1 + development/SKILL_ACTION_RUNTIME.md | 2 +- references/ACTIONS.md | 62 ++++++++++++++++++++-- references/SCHEMA.md | 17 ++++-- scripts/util/constants.py | 2 +- tests/test_docs_standards.py | 5 ++ 11 files changed, 187 insertions(+), 15 deletions(-) create mode 100644 assets/examples/lookup-action.example.json diff --git a/CHANGELOG.md b/CHANGELOG.md index f4a1334..c876eb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ - 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节 - 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段 +## 1.0.83 + +- 沉淀跨表 Lookup 契约:Action 可用内联 `lookup` 或绑列下拉,禁止让用户手填内部编号 +- 统一展示:`编号 · 名称`,可选 `extra_column` 时为 `编号 · 名称(额外)` +- 更新 `ACTIONS.md` / `SCHEMA.md` / `skill-actions.schema.json`、示例与验收清单 + ## 1.0.82 - 沉淀数据管理技能按钮可选悬停字段 `hoverHint`:短名看不懂或会覆盖数据时再写;不回退说明或确认黄条 diff --git a/SKILL.md b/SKILL.md index 3c6b16b..14f4801 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 技能开发模板(通用业务版) description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。" -version: 1.0.82 +version: 1.0.83 author: 深圳匠厂科技有限公司 metadata: openclaw: diff --git a/assets/examples/README.md b/assets/examples/README.md index 4bca364..eae6f0b 100644 --- a/assets/examples/README.md +++ b/assets/examples/README.md @@ -4,3 +4,4 @@ - `skill-policy-snapshot.*.example.json`:Data Policy Snapshot 形状参考(见 `references/POLICY.md`)。 - `skill-cell-presentation.example.json`:数据管理单元格呈现文档形状参考(见 `references/CELL_PRESENTATION.md`)。 - `render-html.action.example.json`:HTML 报告「重新生成」Action 形状参考(固定 id `render-html`;见 `references/ACTIONS.md`)。 +- `lookup-action.example.json`:Action 内联 Lookup 下拉形状参考(跨表引用勿填编号;见 `references/ACTIONS.md`「跨表引用:Lookup」)。 diff --git a/assets/examples/lookup-action.example.json b/assets/examples/lookup-action.example.json new file mode 100644 index 0000000..6c90da4 --- /dev/null +++ b/assets/examples/lookup-action.example.json @@ -0,0 +1,48 @@ +{ + "_comment": "形状参考:Action 参数引用同库另一张表时用 Lookup 下拉,勿让用户填内部编号。完整契约见 references/ACTIONS.md「跨表引用:Lookup」与 references/SCHEMA.md。", + "schemaVersion": 1, + "skill": "your-skill-slug", + "actions": [ + { + "id": "send-with-template", + "label": "按模板发送(示例)", + "description": "演示内联 lookup:从 message_templates 选模板;-- 表示自动挑选。", + "placements": ["toolbar"], + "executionProfile": "async", + "interaction": "form", + "bind": { + "tables": ["leads"] + }, + "entrypoint": { + "type": "cli", + "command": "engage", + "args": ["--template-id", "{{templateId}}", "--content", "{{content}}"] + }, + "inputSchema": { + "type": "object", + "properties": { + "content": { + "type": "string", + "title": "正文", + "description": "填了就按这里发;留空则用下面的话术模板。", + "display_type": "textarea" + }, + "templateId": { + "type": "number", + "title": "话术模板", + "description": "仅在正文留空时生效。选 -- = 自动挑选。", + "display_type": "lookup", + "lookup": { + "ref_table": "message_templates", + "value_column": "id", + "label_column": "name", + "extra_column": "channel", + "filter_column": "is_active", + "filter_value": 1 + } + } + } + } + } + ] +} diff --git a/assets/schemas/skill-actions.schema.json b/assets/schemas/skill-actions.schema.json index 25f5ac3..809beca 100644 --- a/assets/schemas/skill-actions.schema.json +++ b/assets/schemas/skill-actions.schema.json @@ -116,20 +116,66 @@ "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$", - "description": "可选。绑定业务表物理列名;replaces create/update 时宿主可复用该列的中文名与 lookup 下拉" + "description": "可选。绑定业务表物理列名;Action 弹窗(toolbar/batch)与 replaces create/update 抽屉均可复用该列的中文名与 lookup 下拉" }, "display_type": { "type": "string", - "enum": ["textarea", "date", "datetime_unix_seconds", "url", "email"], - "description": "可选。表单控件提示;与 format 二选一即可。须与 CRUD display_type 语义对齐(见 ACTIONS.md / SCHEMA.md)。" + "enum": ["textarea", "date", "datetime_unix_seconds", "url", "email", "lookup"], + "description": "可选。表单控件提示;与 format 二选一即可。lookup=关联下拉(须配 lookup 对象或绑到已有 lookup 列)。须与 CRUD display_type 语义对齐(见 ACTIONS.md / SCHEMA.md)。" }, "format": { "type": "string", - "enum": ["textarea", "date", "datetime_unix_seconds", "url", "email"], + "enum": ["textarea", "date", "datetime_unix_seconds", "url", "email", "lookup"], "description": "可选。display_type 别名,语义相同。" + }, + "lookup": { + "$ref": "#/$defs/lookupConfig", + "description": "可选。内联同库表关联 Lookup(与列 options_json lookup 对象同构)。用于当前表没有对应列时;推荐同时设 display_type=lookup。见 ACTIONS.md「跨表引用:Lookup」。" } } }, + "lookupConfig": { + "type": "object", + "required": ["ref_table", "value_column", "label_column"], + "additionalProperties": false, + "properties": { + "ref_table": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", + "description": "同库被引用表名" + }, + "value_column": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", + "description": "提交值列(编号 / 外键)" + }, + "label_column": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", + "description": "主文案列" + }, + "extra_column": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", + "description": "可选。第三展示列;有值时宿主拼成「value · label(extra)」" + }, + "filter_column": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$", + "description": "可选。等值过滤列" + }, + "filter_value": { + "type": ["string", "number", "boolean", "null"], + "description": "可选。与 filter_column 配对的等值" + } + }, + "description": "同库 FK 式 Lookup。展示:value · label;有 extra 时 value · label(extra)。宿主亦接受 camelCase 键名。" + }, "inputSchema": { "type": "object", "required": ["type", "properties"], @@ -203,7 +249,7 @@ "minLength": 1, "pattern": "^[a-z][a-z0-9_]*$" }, - "description": "可选。将 inputSchema 属性名映射到业务表物理列名,供 replaces create/update 抽屉复用列 displayName / lookup options。" + "description": "可选。将 inputSchema 属性名映射到业务表物理列名,供 Action 弹窗与 replaces create/update 抽屉复用列 displayName / lookup options。" } }, "description": "表级绑定;toolbar 必填。可选 inputMapping / columnMapping。concurrency/locks 勿写入。" diff --git a/development/CHECKLIST.md b/development/CHECKLIST.md index 370eeae..ef653b2 100644 --- a/development/CHECKLIST.md +++ b/development/CHECKLIST.md @@ -96,6 +96,7 @@ checklist_version: 1.0 - [ ] A4-3 **P0** 异步任务在任务中心能看到进行中与结束状态;结束有成功或失败结论 - [ ] A4-4 **P1** 进行中的进度/步骤信息对用户可理解 - [ ] A4-5 **P1** 已对外暴露的动作参数覆盖主路径关键输入(无“命令行能做、动作入口不能做”的关键缺口) +- [ ] A4-6 **P0** 若 Action 需引用同库另一张业务表(话术/平台/账号等):参数为 Lookup 下拉(内联 `lookup` 或绑列),**不是**手填内部编号;可选「自动」可留空提交 --- diff --git a/development/SKILL_ACTION_RUNTIME.md b/development/SKILL_ACTION_RUNTIME.md index 1f63614..ae2f45f 100644 --- a/development/SKILL_ACTION_RUNTIME.md +++ b/development/SKILL_ACTION_RUNTIME.md @@ -7,7 +7,7 @@ | 文档 | 职责 | |------|------| | 本文 | sync/async、任务中心、Agent 禁令、单内核编排、队列 pick、同步 vs 导出 | -| [`../references/ACTIONS.md`](../references/ACTIONS.md) | `actions.json` 字段、placements、`bind.tables`、inputSchema | +| [`../references/ACTIONS.md`](../references/ACTIONS.md) | `actions.json` 字段、placements、`bind.tables`、inputSchema、跨表 Lookup | | [`LOGGING.md`](LOGGING.md) | `job_context` / `emit` / `finish` / Run Journal | | [`DATA_PATHS.md`](DATA_PATHS.md) | 下载/导入等落盘路径 | diff --git a/references/ACTIONS.md b/references/ACTIONS.md index edebdbf..b588e8e 100644 --- a/references/ACTIONS.md +++ b/references/ACTIONS.md @@ -176,11 +176,12 @@ Action 是**可选能力**: - `update` / `delete` 可用 `inputMapping`(`$row.$pk`、`$selection.ids`)预填主键。 - 宿主导入仍直写:有 `replaces:create` 的表慎用宿主导入,或另做 import Action。 - 整表 `_jiangchang_tables.readonly=1` 时仍隐藏写按钮(优先于 `replaces`)。 -- **列元数据复用(lookup)**:create/update 抽屉可将 `inputSchema` 字段对齐业务列,复用中文名与 lookup 下拉: +- **列元数据复用(lookup)**:Action 表单(含 toolbar/batch 弹窗与 create/update 抽屉)可将 `inputSchema` 字段对齐业务列,复用中文名与 lookup 下拉: - 优先让属性名 = 物理列名(如 `platform_key`); - 或 `bind.columnMapping`:`{ "platform": "platform_key" }`; - 或字段上写 `"column": "platform_key"`。 - - **不要**在 actions.json 里写死会过期的全量平台 `enum`。 + - 当前表没有对应列时,用字段内联 `lookup`(见下文「跨表引用:Lookup」)。 + - **不要**在 actions.json 里写死会过期的全量平台 `enum`,也**不要**让用户手填内部编号。 ## `interaction`(点击交互方式) @@ -583,6 +584,57 @@ HINT: - [ ] 成功路径带 `refreshCatalog`(或等价让侧栏/预览看到更新) ## inputSchema 与参数表单 + +### 跨表引用:Lookup(宿主已支持;勿让用户填编号) + +当 Action 参数要引用**同库另一张业务表**的一行(话术模板、平台、账号等)时,必须用 Lookup 下拉,**禁止**做成「请填写编号」的数字框(用户记不住内部 id,体验差)。 + +| 场景 | 怎么配 | 说明 | +|------|--------|------| +| 当前表已有同含义列,且列上已是 CRUD lookup | `column` / `bind.columnMapping`,或属性名 = 列名 | toolbar/batch 弹窗与 create/update 抽屉都会复用该列已解析的选项 | +| 当前表没有该列(如在「潜客」表上选「话术模板」) | `display_type: "lookup"` + 字段内联 `lookup` 对象 | 打开表单时宿主按当前技能库解析选项 | + +内联 `lookup` 与列元数据 `options_json` **同构**(见 [`SCHEMA.md`](SCHEMA.md)「表关联 lookup」): + +```json +{ + "templateId": { + "type": "number", + "title": "话术模板", + "description": "仅在正文留空时生效;选 -- 表示自动挑选。", + "display_type": "lookup", + "lookup": { + "ref_table": "message_templates", + "value_column": "id", + "label_column": "name", + "extra_column": "channel", + "filter_column": "is_active", + "filter_value": 1 + } + } +} +``` + +| 字段 | 必填 | 说明 | +|------|------|------| +| `ref_table` | 是 | 同库被引用表 | +| `value_column` | 是 | 提交给 CLI 的值(编号 / 外键) | +| `label_column` | 是 | 主文案列 | +| `extra_column` | 否 | 第三展示列(任意列名,不限「备注」) | +| `filter_column` / `filter_value` | 否 | 等值过滤 | + +**下拉展示(宿主统一,技能只配列):** `{value} · {label}`;有非空 `extra_column` 时为 `{value} · {label}({extra})`。例:`2 · 通用私信-留资`、`2 · 通用私信-留资(dm)`。 + +**可选「自动」:** 字段不要放进 `required`;不要用 `minimum: 1` 卡死留空。宿主会省略空的可选数字参数,避免「提交的数据无效」。 + +**反模式(勿做):** + +- 标题写成「某某编号」,说明里教用户去左侧表抄 id +- 用静态 `enum` 罗列会增长/变更的业务行(会过期) +- 在技能里自己拼假 label 列代替宿主统一格式(难维护) + +形状参考:[`assets/examples/lookup-action.example.json`](../assets/examples/lookup-action.example.json)。 + ### 表单字段类型对照(须与 CRUD 对称) Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件语义**。CRUD 侧配置见 [`SCHEMA.md`](SCHEMA.md)「表单与展示:稳定字段类型」;本表只写 Action 怎么配。 @@ -595,7 +647,7 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件 | 数字 | `type: number` | `display_type: number` 或 INT/REAL/NUMERIC | | 开关 | `type: boolean` | `display_type: boolean` | | 枚举下拉 | `enum: [...]` | `options_json` 数组 | -| 关联下拉 | 绑列 lookup(`column` / `columnMapping`) | `display_type: lookup` | +| 关联下拉(Lookup) | 内联 `display_type: lookup` + `lookup`,或绑列 `column` / `columnMapping` | `display_type: lookup` + `options_json` 对象 | | 密码 | `sensitive: true` | 列 `sensitive` | | 日期(日) | `display_type` 或 `format`: `date` | `display_type: date` → 存 `YYYY-MM-DD` | | 日期时间 | `display_type` 或 `format`: `datetime_unix_seconds` | 同左;**存/传 Unix 秒** | @@ -617,9 +669,11 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件 - 根:`object`;属性:`string` / `number` / `boolean`(`object`/`array` 仅作 JSON 多行编辑兼容,新技能慎用) - `enum` / `default` / `required` / `sensitive` / `readOnly` -- `display_type` / `format`:`textarea` | `date` | `datetime_unix_seconds` | `url` | `email` +- `display_type` / `format`:`textarea` | `date` | `datetime_unix_seconds` | `url` | `email` | **`lookup`** +- 字段内联 `lookup`(与 CRUD `options_json` lookup 对象同构;可选 `extra_column`) - 属性级 `description`(表单标签下方灰字说明) - 简单模板替换(`{{fieldName}}`) +- 可选空数字字段提交时由宿主省略,避免 `""` 触发 number 校验失败 **与数据管理「新增 / 编辑」表单的分工(勿混用配置入口):** diff --git a/references/SCHEMA.md b/references/SCHEMA.md index ce5b9f3..bcdc77b 100644 --- a/references/SCHEMA.md +++ b/references/SCHEMA.md @@ -518,6 +518,7 @@ CREATE TABLE demo_items ( "ref_table": "platforms", "value_column": "platform_key", "label_column": "display_name", + "extra_column": "category", "filter_column": "enabled", "filter_value": 1 } @@ -526,13 +527,23 @@ CREATE TABLE demo_items ( | 字段 | 必填 | 说明 | |---|---|---| | `ref_table` | 是 | 同库被引用表名(snake_case 标识符) | -| `value_column` | 是 | 写入当前字段的值列 | -| `label_column` | 是 | 下拉展示名列 | +| `value_column` | 是 | 写入当前字段的值列(编号 / 外键) | +| `label_column` | 是 | 下拉主文案列(名称) | +| `extra_column` | 否 | 第三展示列(不必叫「备注」);有值时拼进括号 | | `filter_column` / `filter_value` | 否 | 等值过滤(如只列出 `enabled=1`) | 宿主在加载表 schema 时查询 `ref_table`,把结果展开成 `{value,label}` 下拉选项;**物理列仍存标量**(如 `platform_key` 文本、`account_id` 整数),不做嵌套子表。 -示例:账号表的平台字段 → 平台信息表;凭据表的账号编号 → 账号信息表。 +**统一展示文案(宿主固定一种,技能只配列):** + +- 默认:`{value} · {label}`,例如 `2 · 通用私信-留资`、`douyin · 抖音` +- 配置了 `extra_column` 且该行有非空值:`{value} · {label}({extra})` +- 未配置 `extra_column`、或额外列为空:不加 `()` +- `label` 为空或与 `value` 相同时:只显示 `value`(可再带额外括号) + +Action 弹窗内联 Lookup 与上表 **同构**(字段名一致),见 [`ACTIONS.md`](ACTIONS.md)「跨表引用:Lookup」。 + +示例:账号表的平台字段 → 平台信息表;凭据表的账号编号 → 账号信息表;私信 Action 选话术 → `message_templates`。 ## 幂等初始化标准 diff --git a/scripts/util/constants.py b/scripts/util/constants.py index 25bb0cc..bc07c5f 100644 --- a/scripts/util/constants.py +++ b/scripts/util/constants.py @@ -1,6 +1,6 @@ """技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。""" SKILL_SLUG = "your-skill-slug" -SKILL_VERSION = "1.0.82" +SKILL_VERSION = "1.0.83" LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug" PLATFORM_KIT_MIN_VERSION = "1.2.11" diff --git a/tests/test_docs_standards.py b/tests/test_docs_standards.py index dc7efbb..749ed75 100644 --- a/tests/test_docs_standards.py +++ b/tests/test_docs_standards.py @@ -341,6 +341,8 @@ class TestDocsStandards(unittest.TestCase): "表单与展示:稳定字段类型(宿主支持,须与 Action 对称)", "datetime_unix_seconds", "display_type: \"number\"", + "extra_column", + "{value} · {label}", "DEFAULT", "description", "文件 / 图片上传", @@ -354,6 +356,9 @@ class TestDocsStandards(unittest.TestCase): for marker in ( "inputSchema 与参数表单", "表单字段类型对照(须与 CRUD 对称)", + "跨表引用:Lookup", + "display_type: \"lookup\"", + "extra_column", "数据管理新增/编辑", "_jiangchang_columns.description", "datetime_unix_seconds",