关于 action-creator
action-creator 是用于在 Datex Studio 分支上创建或修改服务端操作的技能。它聚焦于事务边界内组合实体 CRUD 与其他操作,并通过函数提供 UI 调用桥接。
主要功能
- 01创建或修改服务端操作
- 02组合实体 CRUD 与其他操作
- 03配置事务提交与回滚逻辑
- 04通过 CLI 验证并提交配置
- 05检查调用方参数契约
适用场景
- 01实现需要原子提交或回滚的写入
- 02编排多个操作完成事务流程
- 03为 UI 操作创建函数调用桥接
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ datex/ skills --skill action-creator安装后在 Claude Code 中输入/action-creator确认已加载。
附带文件evals/evals.jsonreferences/actions.md
详细介绍
Action Creator
在分支上创建或修改 Datex Studio action(configurationTypeId=18)——在单个提交/回滚边界内组合实体 CRUD 和其他 action 的服务器端事务流。UI 不会直接调用 action——需要用函数包装 action 调用,作为 UI → action 桥接。
参考资料
- ../datex-studio-shared/branch-setup.md — 分支/连接选择(多个技能共用)
- references/actions.md — 权威的 action 编写参考:文件结构、运行时全局变量、调用契约、错误处理规则、预检清单
- ../datex-studio-conventions/file-format.md —
configurationTypeId表和 TypeScript 表达式编码规则 - ../datex-studio-conventions/naming-conventions.md —
_action标识与-footprintFlow.json文件后缀(非对称命名) - ../datex-studio-runtime/runtime-globals.md — action 代码中可用的平台注入全局变量(
$flow、$flows、$datasources、$api等) - ../datex-studio-runtime/calling-conventions.md — 完整的调用方→被调用方层级矩阵(UI 不能直接调用 action;action 不能调用 function)
- ../function-creator/references/functions.md — 非事务性对应项及 UI 桥接
- ../datasource-creator/references/datasources.md — action 层级的数据源目标(
-footprintDatasource.json) - ../component-wiring-check/references/component-wiring.md — 适用于 action 调用方的调用方
configParameters契约
依赖项
requirements-gathering技能 — 如果当前对话上下文中尚无需求简报,则调用该技能生成一份function-creator技能 — 如果尚不存在包装 UI 函数(UI→action 桥接),或需求实际上是非事务性的(action 与 function 的选择更倾向于 function),则调用该技能datasource-creator技能 — 如果 action 需要的-footprintDatasource.json(FPDS)在当前分支上尚不存在,则调用该技能component-wiring-check技能 — 推送前审查 action 调用方的configParameters↔ 目标inParams契约backend-test-creator技能 — 编写 mocha 测试套件来覆盖 action 时调用该技能(这是正确的做法,避免滥用 action 作为临时测试工具)impact-analysis技能 — 修改现有 action 的inParams/outParams时调用该技能(检测签名变更是否造成破坏)
CLI 生命周期
Action 的编写通过 dxs configuration 完成——这是适用于所有平台配置类型的通用 CRUD 基元。没有 dxs action 子命令,也不支持字段级补丁;需要构建(或获取并提取)完整 JSON 主体,编辑后再将其整体推送回去。CLI 中的类型标识符是 footprintflow(小写,与 ConfigurationEndpoints.normalize_type 的输出一致),而不是 footprintFlow。
创建新 action:
# 1. Build body.json from scratch (see references/actions.md → Minimal Valid Skeleton)
# 2. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI
dxs configuration validate footprintflow -b <branchId> -D body.json
# 3. Create
dxs configuration upsert footprintflow -b <branchId> -D body.json
编辑现有 action:
# 1. Fetch — note the envelope wrapper
dxs configuration get footprintflow <configId> -b <branchId> -O envelope.json
# 2. EXTRACT THE INNER BODY (round-trip footgun guard — see "Round-trip rule" below)
jq .json envelope.json > body.json
# 3. Edit body.json
# 4. Validate — gates the push. Exit 1 = errors found (read validation_errors, fix, re-run), not a broken CLI
dxs configuration validate footprintflow -b <branchId> -D body.json
# 5. Push
dxs configuration upsert footprintflow -b <branchId> -D body.json
往返规则(关键)
编辑现有配置时,绝不要将 envelope.json 直接通过管道传入 dxs configuration upsert——这会悄无声息地破坏配置内容。上面更正后的步骤(先用 jq 提取内部的 .json,再进行编辑)是所有往返操作的强制要求。规范的往返流程及其背后的错误,请参阅 ../datex-studio-shared/configuration-roundtrip.md。
对于操作,这条规则尤为重要,因为操作 JSON 包含两个 code 字段——Datex Studio 执行的运行时字段是 nodes[0].stepConfig.executeCodeConfig.code;顶层的 action['code'] 是一个反规范化副本。只写入其中一个字段,用 grep 检查时可能看不出来,但会破坏运行时。请参阅 references/actions.md → 上线前检查清单第 5 项。
工作流
[Phase 1: Setup + Requirements]
Follow branch-setup.md for branch/connection selection
|
[requirements brief in context?]
+-----+-----+
| |
YES NO -> invoke `requirements-gathering`
| |
+-----+------+
|
[Phase 2: Action vs Function decision]
Consult references/actions.md → "Purpose & When to Use":
- transactional / entity CRUD / FPDS access -> action
- pure read/transform / UI-facing / no atomicity -> function
If function -> invoke `function-creator` instead and stop here.
If action but UI needs to invoke it -> the UI calls a function
that wraps the action; invoke `function-creator` for the wrapper
in addition to authoring this action.
|
[Phase 3: Author action body]
Build body.json:
- File shape (configurationTypeId=18, apiSettingName=FootprintApi,
referenceName ends _action, file suffix -footprintFlow.json)
- Step graph (ExecuteCodeActivity in nodes[0])
- inParams/outParams with FULL fat parameter-descriptor boilerplate
- code string with \r\n line endings inside the JSON
- Error handling: every try/catch either format-and-rethrows
or is REMOVED. Bare swallows leave the transaction unresolved
and surface elsewhere as "Transaction must begin first".
- $datasources.* targets FPDS only; no $db; no $apis
- Invoke `datasource-creator` if an FPDS dependency is missing
- Invoke `component-wiring-check` to audit callers' configParameters
|
[Phase 4: Validate + push]
dxs configuration validate footprintflow -b <branchId> -D body.json
|
+----+----+
| |
CREATE MODIFY-EXISTING
| |
| use the corrected round-trip
| (get -O envelope -> jq .json -> body)
| |
| if inParams/outParams changed:
| invoke `impact-analysis`
| |
+----+----+
|
v
dxs configuration upsert footprintflow -b <branchId> -D body.json
(upsert creates or updates by referenceName — one command for both)
|
[Phase 5: Verify in Studio (optional)]
Exercise the action via its wrapping function (or via a
backend-test-creator mocha suite). Watch for delayed
"Transaction must begin first" symptoms in unrelated flows
— that's the silent-swallow signature.
|
[invoke `post-edit-verification`; then `component-validator`]
阶段详情
阶段 1:设置 + 需求
- 按照 ../datex-studio-shared/branch-setup.md 选择分支和连接。绝不要猜测分支 ID——请用户确认。
- 检查对话上下文中是否已有需求简报(由
requirements-gathering或其他调用技能生成)。- 已有简报——使用该简报。简报应说明原子性需求(操作是否需要作为一个整体回滚?)、涉及的实体/数据源,以及操作的调用方式(函数包装器、另一个操作、后端测试)。
- 没有简报——先调用
requirements-gathering技能。原子性问题是下一阶段决定使用操作还是函数的关键依据。
阶段 2:决定使用操作还是函数
编写前,请参阅 references/actions.md → 用途与适用场景。这并非风格上的选择——操作和函数位于不同层级,运行时能力也不可互换。
符合以下情况时,选择操作:
- 工作必须是原子的(实体写入要么全部提交,要么全部回滚)。
- 逻辑需要组合其他操作或实体 CRUD。
- 代码需要访问
-footprintDatasource.json(FPDS)数据源——这类数据源仅限操作层使用。
符合以下情况时,改用函数:
- 工作仅涉及读取/转换。
- 调用方是 UI(UI 无法直接调用操作——请参阅 ../datex-studio-runtime/calling-conventions.md)。
- 不需要事务边界。
如果答案是“函数”,请停止并调用 function-creator。如果答案是“操作,但 UI 需要触发它”,仍然需要一个函数——UI 调用函数,函数再通过 $apis.<Package>.FootprintApi.extendedActions.<action_name>({ ... }) 调用操作。在此处编写操作,并调用 function-creator 创建包装器。
阶段 3:编写 action 主体
根据 references/actions.md → 最小有效骨架 中的骨架构建 body.json。要点:
-
文件基础信息。
configurationTypeId: 18。apiSettingName: "FootprintApi"。referenceName以_action结尾(例如update_task_status_action)。非对称命名:文件后缀为-footprintFlow.json(不是-action.json);_action标识仅位于referenceName中 — 另请参阅通用检查项(../datex-studio-conventions/universal-checklist.md)。详见 references/actions.md → 文件位置与命名 和 ../datex-studio-conventions/naming-conventions.md。 -
inParams/outParams样板结构。 每个条目都使用完整的参数描述符 — 共 14 个字段,不可省略。缺少字段是导入被拒的常见原因。确切结构请参阅最小有效骨架。 -
code字符串。 步骤图通常只有一个位于nodes[0]的ExecuteCodeActivity。在 JSON 内,换行符转义为\\r\\n(解码为\r\n)。编辑嵌入代码时,优先使用 Python 的json.load/json.dump,不要直接替换原始字符串。 -
Action JSON 中有两个
code字段;只有内层字段会运行。 运行时字段是nodes[0].stepConfig.executeCodeConfig.code。顶层的action['code']是反规范化镜像 — 只写入该字段不会影响运行时,但通过json.load和 grep 查看文件时看起来仍然正确。重新打包时,同时写入两个字段并断言它们一致。详见 references/actions.md → 推送前检查清单第 5 项。 -
错误处理会影响运行。 Action 在事务中运行。悄悄吞掉错误会导致事务无法解决,随后调用的无关 action 会报出误导性的
"Transaction must begin first"。这是最常见的 action 错误。规则:
- 除非 catch 能带来价值,否则不要捕获。 只吞掉错误或直接重新抛出的
try/catch,严格来说比不使用try/catch更糟 — 删除它,让异常继续传播。 - 捕获时,格式化错误后重新抛出。 仅在需要补充正在尝试执行的操作以及涉及的 key/id 时才捕获,然后
throw new Error(...)。
// Good — enriches with context and rethrows try { await $flows.Utilities.crud_update_entity({ entity: 'Tasks', keys, properties }); } catch (e) { throw new Error(`Failed to update task ${keys[0].value}: ${e.message}`); } // Bad — swallows; transaction never closes; next action throws "Transaction must begin first" try { await $flows.Utilities.crud_update_entity(...); } catch (e) { /* nothing */ } // Bad — pointless rewrap; just delete the try/catch try { await $flows.Utilities.crud_update_entity(...); } catch (e) { throw e; }诊断
"Transaction must begin first"错误时,问题几乎从不出在抛出该错误的 action 中 — 而是出在之前某个不同代码路径上吞掉错误的 action 中。通过impact-analysis/dxs source explore枚举该分支上的功能相关 action,并检查每个 action 是否存在裸catch块,将其作为首要诊断步骤。 - 除非 catch 能带来价值,否则不要捕获。 只吞掉错误或直接重新抛出的
-
code字符串中的层级合规性。 使用$flows.<Package>.<action_name>调用另一个 action。$datasources.<Package>.<name>.get({...})只能用于 FPDS(-footprintDatasource.json)— 在 action 中调用-datasource.json属于跨层级违规。Action 中无法使用$db(仅限函数层级)。Action 中很少使用$apis(这是函数→action 的调用方向)。详见 ../datex-studio-runtime/runtime-globals.md 和 ../datex-studio-runtime/calling-conventions.md。 -
如果缺少 FPDS 依赖项, 在推送 action 之前调用
datasource-creator添加该依赖项。 -
调用方契约审计。 此 action 的每个调用方都必须声明完整的
configParameters契约 — 此 action 声明的每个 inParam 都必须在调用方中有对应条目,包括未使用且value: null的条目。推送前调用component-wiring-check审计引用契约。详见 ../component-wiring-check/references/component-wiring.md。
阶段 4:验证并推送
# Validate the body locally against the branch. Exit 1 = validation found errors
# (read validation_errors, fix body.json, re-run) — not a broken CLI. Do not push on exit 1.
dxs configuration validate footprintflow -b <branchId> -D body.json
# For a new action
dxs configuration upsert footprintflow -b <branchId> -D body.json
# For modify-existing (round-trip — never skip the jq extract)
dxs configuration get footprintflow <configId> -b <branchId> -O envelope.json
jq .json envelope.json > body.json
# ... edit body.json ...
dxs configuration upsert footprintflow -b <branchId> -D body.json
如果要更改现有操作的 inParams / outParams,请在推送前调用 impact-analysis 技能,找出所有调用方;在同一轮编辑中逐一协调处理(函数、其他操作、后端测试),或者取得用户对破坏性更改的明确批准。
验证会在推送前发现缺少必填字段、参数描述符形状错误和引用错误。它无法捕获静默吞掉错误 / "Transaction must begin first" 这一类问题——这是行为问题,只会在运行时显现。推送前请逐项检查 references/actions.md → 推送前检查清单,尤其要注意不得静默吞掉错误的 try/catch 项。
阶段 5:在 Studio 中验证(可选)
通过常规调用路径测试操作:
- 通过封装函数(UI 桥接)——打开触发该函数的屏幕,并确认操作按设计提交 / 回滚。
- 通过另一项操作——从编排操作的流程中调用,并验证组合事务能成功或原子性回滚。
- 通过 mocha 测试套件——使用
backend-test-creator编写。与其滥用操作作为临时测试工具,这才是正确的替代方案。
留意下游流程中无关位置出现的延迟 "Transaction must begin first" 症状——这是静默吞掉错误的特征。如果发现此问题,请返回阶段 3 的步骤 5,审查刚刚编辑的操作(以及它组合调用的任何操作)中的 try/catch 块。
如果运行中的应用不可用,请重新获取配置(使用修正后的 jq .json 提取模式),并与 body.json 比对,确认推送已生效。
推送前检查清单
推送前,请完整检查 references/actions.md → 推送前检查清单。快速版如下:
- 命名不对称。 文件后缀为
-footprintFlow.json。referenceName以_action结尾。两者不同——不要将它们统一。 - 顶层常量。
configurationTypeId: 18、apiSettingName: "FootprintApi"、description非空且不超过 100 个字符,并且已设置accessModifier。 - 每个
inParams/outParams条目都使用完整的参数描述符样板——共 14 个字段,不得省略。 code的行尾符在解码后的字符串中为\r\n(JSON 层会转义为\\r\\n)。- 两个
code字段均已写入且内容一致——顶层镜像与nodes[0].stepConfig.executeCodeConfig.code必须一致;只有嵌套字段会运行。 - 所有
$datasources.*调用均指向 FPDS(-footprintDatasource.json)。不得使用$db.*(仅限函数层)。 - 每个
try/catch要么格式化错误后重新抛出,要么移除。 不得静默吞掉错误,也不得直接使用throw e。这是最重要的一条规则。 - 调用方声明完整的
configParameters合约——此操作声明的每个 inParam 都必须在调用方中有对应条目,包括未使用且value: null的参数。使用component-wiring-check进行审查。
常见错误
| 错误 | 修正方法 |
|---|---|
使用会吞掉错误或直接重新抛出错误的 try/catch | 删除此代码块。事务会保持打开状态;下一个无关操作会抛出 "Transaction must begin first"。仅在需要添加上下文信息以格式化错误并重新抛出时才使用 catch。 |
通过读取抛出 "Transaction must begin first" 的操作来诊断此错误 | 问题几乎总是出在上游——之前某个操作在另一条代码路径上吞掉了错误。使用 impact-analysis 枚举分支上该功能的操作,然后逐一检查是否存在裸 catch 代码块。 |
文件名使用 *-action.json,而不是 *-footprintFlow.json | 命名不对称:_action 标识仅出现在 referenceName 中;文件后缀仍为 -footprintFlow.json。 |
在操作代码中通过 $datasources 调用 -datasource.json | 违反层级规则。操作层只能访问 -footprintDatasource.json(FPDS)。如有需要,使用 datasource-creator 添加 FPDS 变体。 |
在操作代码中调用 $db.* | $db 仅限函数层使用。将读取操作移到函数中,并从包装函数调用该函数。 |
只写入顶层 action['code'] 镜像,而不更新 nodes[0].stepConfig.executeCodeConfig.code | 运行时无法识别——运行时执行的是嵌套字段。两处都要写入,并断言两者一致。 |
| UI 流程尝试直接调用操作 | UI 无法调用操作。编写一个包装该操作的函数,并让 UI 调用此函数。调用 function-creator 创建包装函数。 |
将 dxs configuration get -O envelope.json 的输出直接传入 dxs configuration upsert -D envelope.json | 这会静默破坏配置内容。编辑前务必先运行 jq .json envelope.json > body.json。请参阅上文“往返规则”。 |
使用简写的 inParams/outParams 描述符(省略 objectTypeDef、isCollection 等字段) | 导入会被拒绝——参数描述符的模板包含 14 个字段,要求非常严格。请使用骨架中的完整结构。 |
description 超过 100 个字符 | SQL 列长度有限制——推送时验证会失败。请精简。 |
修改现有操作的 inParams/outParams,但未检查调用方 | 会悄无声息地或明显地破坏所有调用方。先调用 impact-analysis;并在同一次编辑中协调好调用方。 |
编辑后,调用 post-edit-verification,以发现 description/JSON/schema 违规问题。最终审核时,调用 component-validator。