@thinkingai/ae-cli 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +229 -0
  2. package/bin/ae-cli.js +2 -0
  3. package/dist/auth-JXELJNDS.js +19 -0
  4. package/dist/auth-L3G3A74I.js +67 -0
  5. package/dist/chunk-3GM5LJZR.js +145 -0
  6. package/dist/chunk-JD5DXMKL.js +172 -0
  7. package/dist/chunk-KM57HI5B.js +107 -0
  8. package/dist/chunk-OVQOK35G.js +108 -0
  9. package/dist/chunk-RJNLN3KQ.js +217 -0
  10. package/dist/client-5QSQBBDB.js +16 -0
  11. package/dist/community-GMALVSRF.js +684 -0
  12. package/dist/config-Q7J3Z7Z2.js +242 -0
  13. package/dist/index.js +277 -0
  14. package/dist/raw-ZNVURYMR.js +59 -0
  15. package/dist/te-analysis-7NN3SY3I.js +871 -0
  16. package/dist/te-audience-P43BWMHM.js +350 -0
  17. package/dist/te-common-H3IPTI2I.js +144 -0
  18. package/dist/te-dataops-WCGDBJLF.js +1853 -0
  19. package/dist/te-engage-UTRVNTGU.js +1470 -0
  20. package/dist/te-meta-HGYNXVGF.js +479 -0
  21. package/package.json +53 -0
  22. package/skills/te-analysis/SKILL.md +107 -0
  23. package/skills/te-analysis/references/build-entity-details-sql.md +58 -0
  24. package/skills/te-analysis/references/build-event-details-sql.md +61 -0
  25. package/skills/te-analysis/references/create-alert.md +47 -0
  26. package/skills/te-analysis/references/create-dashboard.md +49 -0
  27. package/skills/te-analysis/references/create-or-update-dashboard-note.md +39 -0
  28. package/skills/te-analysis/references/create-public-access-link.md +43 -0
  29. package/skills/te-analysis/references/create-report.md +60 -0
  30. package/skills/te-analysis/references/create-result-cluster.md +73 -0
  31. package/skills/te-analysis/references/drilldown-user-events.md +72 -0
  32. package/skills/te-analysis/references/drilldown-users.md +75 -0
  33. package/skills/te-analysis/references/get-alert-definition-schema.md +32 -0
  34. package/skills/te-analysis/references/get-alert.md +31 -0
  35. package/skills/te-analysis/references/get-analysis-query-schema.md +36 -0
  36. package/skills/te-analysis/references/get-filter-schema.md +33 -0
  37. package/skills/te-analysis/references/get-groupby-schema.md +33 -0
  38. package/skills/te-analysis/references/get-report-definition.md +33 -0
  39. package/skills/te-analysis/references/get-table-columns.md +38 -0
  40. package/skills/te-analysis/references/list-alerts.md +33 -0
  41. package/skills/te-analysis/references/list-dashboards.md +33 -0
  42. package/skills/te-analysis/references/list-public-access-links.md +31 -0
  43. package/skills/te-analysis/references/list-reports.md +33 -0
  44. package/skills/te-analysis/references/load-filters.md +44 -0
  45. package/skills/te-analysis/references/query-adhoc.md +71 -0
  46. package/skills/te-analysis/references/query-dashboard-detail.md +35 -0
  47. package/skills/te-analysis/references/query-dashboard-report-data.md +60 -0
  48. package/skills/te-analysis/references/query-entity-details.md +60 -0
  49. package/skills/te-analysis/references/query-event-details.md +63 -0
  50. package/skills/te-analysis/references/query-report-data.md +65 -0
  51. package/skills/te-analysis/references/update-alert.md +49 -0
  52. package/skills/te-analysis/references/update-dashboard.md +45 -0
  53. package/skills/te-analysis/references/update-public-access-link.md +41 -0
  54. package/skills/te-audience/SKILL.md +63 -0
  55. package/skills/te-audience/references/create-cluster.md +65 -0
  56. package/skills/te-audience/references/create-tag.md +60 -0
  57. package/skills/te-audience/references/get-cluster-definition-schema.md +37 -0
  58. package/skills/te-audience/references/get-clusters-by-name.md +32 -0
  59. package/skills/te-audience/references/get-tag-definition-schema.md +32 -0
  60. package/skills/te-audience/references/get-tags-by-name.md +32 -0
  61. package/skills/te-audience/references/list-cluster-members.md +35 -0
  62. package/skills/te-audience/references/list-clusters.md +32 -0
  63. package/skills/te-audience/references/list-tag-members.md +36 -0
  64. package/skills/te-audience/references/list-tags.md +32 -0
  65. package/skills/te-audience/references/refresh-cluster.md +31 -0
  66. package/skills/te-audience/references/refresh-tag.md +31 -0
  67. package/skills/te-audience/references/update-cluster.md +59 -0
  68. package/skills/te-audience/references/update-tag.md +60 -0
  69. package/skills/te-common/SKILL.md +135 -0
  70. package/skills/te-common/references/get-resource-url.md +32 -0
  71. package/skills/te-common/references/list-projects.md +37 -0
  72. package/skills/te-community/SKILL.md +133 -0
  73. package/skills/te-community/references/community-activity-analysis.md +68 -0
  74. package/skills/te-community/references/community-analyzing-official-content.md +72 -0
  75. package/skills/te-community/references/community-analyzing-theme-comment.md +124 -0
  76. package/skills/te-community/references/community-character-analysis.md +71 -0
  77. package/skills/te-community/references/community-daily-report.md +82 -0
  78. package/skills/te-community/references/community-hottopic-insight.md +120 -0
  79. package/skills/te-community/references/community-release-analysis.md +79 -0
  80. package/skills/te-community/references/community-weekly-report.md +84 -0
  81. package/skills/te-community/references/get_channel_info.md +21 -0
  82. package/skills/te-community/references/get_comment_tag_analysis.md +30 -0
  83. package/skills/te-community/references/get_comments_summary.md +33 -0
  84. package/skills/te-community/references/get_corpus_tags.md +21 -0
  85. package/skills/te-community/references/get_daily_summary.md +23 -0
  86. package/skills/te-community/references/get_hot_topics.md +26 -0
  87. package/skills/te-community/references/get_livestream_analysis.md +23 -0
  88. package/skills/te-community/references/get_livestream_detail.md +34 -0
  89. package/skills/te-community/references/get_livestream_list.md +26 -0
  90. package/skills/te-community/references/get_livestream_overview.md +25 -0
  91. package/skills/te-community/references/get_livestream_room_metrics.md +26 -0
  92. package/skills/te-community/references/get_livestream_rooms.md +26 -0
  93. package/skills/te-community/references/get_overview_metrics.md +26 -0
  94. package/skills/te-community/references/get_post_detail.md +38 -0
  95. package/skills/te-community/references/get_risk_content.md +43 -0
  96. package/skills/te-community/references/get_sentiment_overview.md +34 -0
  97. package/skills/te-community/references/get_tag_trends.md +28 -0
  98. package/skills/te-community/references/get_topic_detail.md +27 -0
  99. package/skills/te-community/references/search_posts.md +48 -0
  100. package/skills/te-dataops/SKILL.md +645 -0
  101. package/skills/te-dataops/references/dataops-flow-create.md +163 -0
  102. package/skills/te-dataops/references/dataops-flow-monitor.md +118 -0
  103. package/skills/te-dataops/references/dataops-integration.md +246 -0
  104. package/skills/te-dataops/references/dataops-operations.md +107 -0
  105. package/skills/te-dataops/references/dataops-query.md +111 -0
  106. package/skills/te-dataops/references/dataops-table.md +122 -0
  107. package/skills/te-engage/SKILL.md +211 -0
  108. package/skills/te-engage/references/add-approver.md +24 -0
  109. package/skills/te-engage/references/add-channel.md +74 -0
  110. package/skills/te-engage/references/approver-list.md +19 -0
  111. package/skills/te-engage/references/cancel-query-by-request-id.md +23 -0
  112. package/skills/te-engage/references/channel-detail.md +52 -0
  113. package/skills/te-engage/references/channel-list.md +41 -0
  114. package/skills/te-engage/references/config-channel-detail.md +32 -0
  115. package/skills/te-engage/references/config-channel-list.md +27 -0
  116. package/skills/te-engage/references/config-item-analysis-report.md +34 -0
  117. package/skills/te-engage/references/config-item-detail.md +30 -0
  118. package/skills/te-engage/references/config-item-list.md +19 -0
  119. package/skills/te-engage/references/config-item-strategy-comparison.md +25 -0
  120. package/skills/te-engage/references/config-item-trigger-report.md +42 -0
  121. package/skills/te-engage/references/copy-config-template.md +29 -0
  122. package/skills/te-engage/references/delete-channel.md +24 -0
  123. package/skills/te-engage/references/delete-config-channel.md +24 -0
  124. package/skills/te-engage/references/delete-config-item.md +25 -0
  125. package/skills/te-engage/references/delete-flow.md +24 -0
  126. package/skills/te-engage/references/flow-ab-split-node-report.md +54 -0
  127. package/skills/te-engage/references/flow-detail.md +79 -0
  128. package/skills/te-engage/references/flow-list.md +19 -0
  129. package/skills/te-engage/references/flow-node-config-schema.md +44 -0
  130. package/skills/te-engage/references/flow-node-detail-report.md +55 -0
  131. package/skills/te-engage/references/flow-node-overview-report.md +52 -0
  132. package/skills/te-engage/references/flow-process-report.md +59 -0
  133. package/skills/te-engage/references/manage-flow.md +94 -0
  134. package/skills/te-engage/references/manage-strategy.md +74 -0
  135. package/skills/te-engage/references/manage-task.md +37 -0
  136. package/skills/te-engage/references/modify-flow-base-info.md +27 -0
  137. package/skills/te-engage/references/save-flow.md +870 -0
  138. package/skills/te-engage/references/strategy-detail.md +73 -0
  139. package/skills/te-engage/references/strategy-list.md +21 -0
  140. package/skills/te-engage/references/task-data-detail.md +81 -0
  141. package/skills/te-engage/references/task-data-overview.md +48 -0
  142. package/skills/te-engage/references/task-detail.md +61 -0
  143. package/skills/te-engage/references/task-experiment-report.md +51 -0
  144. package/skills/te-engage/references/task-list.md +91 -0
  145. package/skills/te-engage/references/task-metric-detail.md +56 -0
  146. package/skills/te-engage/references/task-stats.md +89 -0
  147. package/skills/te-engage/references/update-channel-status.md +32 -0
  148. package/skills/te-engage/references/update-config-channel-status.md +32 -0
  149. package/skills/te-engage/references/validate-flow-node-config.md +52 -0
  150. package/skills/te-engage/references/whitelist-list.md +19 -0
  151. package/skills/te-meta/SKILL.md +71 -0
  152. package/skills/te-meta/references/batch-create-metadata.md +37 -0
  153. package/skills/te-meta/references/batch-edit-metadata.md +36 -0
  154. package/skills/te-meta/references/create-metric.md +62 -0
  155. package/skills/te-meta/references/create-project-mark-time.md +38 -0
  156. package/skills/te-meta/references/create-virtual-event.md +64 -0
  157. package/skills/te-meta/references/create-virtual-property.md +69 -0
  158. package/skills/te-meta/references/delete-project-mark-times.md +34 -0
  159. package/skills/te-meta/references/delete-track-items.md +35 -0
  160. package/skills/te-meta/references/get-metric.md +32 -0
  161. package/skills/te-meta/references/get-project-config.md +32 -0
  162. package/skills/te-meta/references/get-track-program.md +31 -0
  163. package/skills/te-meta/references/list-entities.md +34 -0
  164. package/skills/te-meta/references/list-events.md +33 -0
  165. package/skills/te-meta/references/list-metrics.md +33 -0
  166. package/skills/te-meta/references/list-project-mark-times.md +33 -0
  167. package/skills/te-meta/references/list-project-users.md +32 -0
  168. package/skills/te-meta/references/list-properties.md +35 -0
  169. package/skills/te-meta/references/save-track-items.md +34 -0
  170. package/skills/te-meta/references/update-metric.md +61 -0
  171. package/skills/te-meta/references/update-project-mark-time.md +39 -0
  172. package/skills/te-shared/SKILL.md +115 -0
@@ -0,0 +1,870 @@
1
+ # te-engage `+save-flow`
2
+
3
+ 创建或更新流程画布草稿。
4
+
5
+ 映射命令:`te-cli te-engage +save-flow`
6
+
7
+ 这份文档目标不是只解释 `save_flow` 接口本身,而是提供一条**从用户需求到 CLI 入参**的完整路径:
8
+
9
+ 1. 先做意图识别
10
+ 2. 再把意图映射成流程画布 `req`
11
+ 3. 最后调用 CLI 提交
12
+
13
+ ---
14
+
15
+ ## 1. 总原则
16
+
17
+ `+save-flow` 直接接收的不是自然语言,也不是模糊业务描述,而是**最终可提交的流程画布请求体**。
18
+
19
+ 因此,必须先把用户需求整理成一个统一的中间意图结构,再根据映射规则生成:
20
+
21
+ - `flowName`
22
+ - `flowDesc`
23
+ - `nodeList`
24
+ - `edgeList`
25
+ - 以及可选的 `groupId`、`tzOffset`、`flowUuid`、`parentFlowUuid`、`versionType`
26
+
27
+ 最终再用 CLI 调用:
28
+
29
+ ```bash
30
+ te-cli te-engage +save-flow --project-id <projectId> --req '<req-json>'
31
+ ```
32
+
33
+ ---
34
+
35
+ ## 2. 工作流
36
+
37
+ 推荐按下面 5 步执行:
38
+
39
+ 1. 从用户输入中识别流程意图,生成统一的意图 JSON。
40
+ 2. 调用 `te-cli te_audience +get_cluster_definition_schema --cluster_type condition`,拿到 condition cluster definition schema,用于后续拼装条件相关字段。
41
+ 3. 调用 `te-cli te-engage +channel-list --project-id <projectId>`,拿到项目下可用通道,为触达节点匹配真实 `channelId`。
42
+ 4. 将意图 JSON 映射成最终 `req`:`flowName`、`flowDesc`、`nodeList`、`edgeList`。
43
+ 5. 调用 `te-cli te-engage +save-flow --project-id <projectId> --req '<req-json>'` 提交。
44
+
45
+ ---
46
+
47
+ ## 3. 第一步:意图识别
48
+
49
+ ### 3.1 必须先确认的信息
50
+
51
+ 在生成任何 `req` 之前,至少要确认这 4 类信息:
52
+
53
+ | 信息 | 说明 |
54
+ |---|---|
55
+ | 业务场景 | 这是一个什么流程,比如新用户激活、流失召回、付费转化 |
56
+ | 目标用户 | 谁能进入流程,比如最近 14 天未登录用户、今日注册用户 |
57
+ | 触达方式 | 用什么渠道触达,比如 Push、微信订阅、Webhook |
58
+ | 分流条件 | 是否需要分组处理;如果需要,要知道按什么条件分组 |
59
+
60
+ 如果这 4 类信息有缺失,不要直接构建 `req`。
61
+
62
+ ### 3.2 意图识别输出格式
63
+
64
+ 先把用户需求整理成如下意图 JSON。这个 JSON 是中间表示,不是最终 `save_flow.req`。
65
+
66
+ ```json
67
+ {
68
+ "flow_type": "<string>",
69
+ "flow_name": "<string>",
70
+ "flow_desc": "<string>",
71
+ "entry": {
72
+ "type": "<single_trigger|repeat_trigger|event_trigger>",
73
+ "segment": "<string|null>",
74
+ "schedule": "<string|null>",
75
+ "start_date": "<YYYY-MM-DD|YYYY-MM-DD HH:mm|null>",
76
+ "end_date": "<YYYY-MM-DD|YYYY-MM-DD HH:mm|null>",
77
+ "trigger_event": {
78
+ "event": "<string|null>",
79
+ "op": "<string|null>",
80
+ "count": "<number|null>",
81
+ "property_filter": "<object|null>",
82
+ "time_window": "<string|null>"
83
+ }
84
+ },
85
+ "nodes": [
86
+ {
87
+ "nid": "n1",
88
+ "node_type": "<split|judge|action|wait|end>",
89
+ "type": "<具体节点语义类型>",
90
+ "name": "<string|null>",
91
+ "content": "<string|null>",
92
+ "channel_name": "<string|null>",
93
+ "languages": ["default"],
94
+ "condition": "<object|null>",
95
+ "event": "<object|null>",
96
+ "wait_time": "<string|null>",
97
+ "duration": "<string|null>",
98
+ "split_flow_type": "<1|2|null>",
99
+ "branches": [
100
+ {
101
+ "bid": "b1",
102
+ "label": "<string>",
103
+ "condition": "<object|null>",
104
+ "time_limit": "<string|null>",
105
+ "percentage": "<number|null>"
106
+ }
107
+ ]
108
+ }
109
+ ],
110
+ "edges": [
111
+ {
112
+ "source": "n1",
113
+ "target": "n2",
114
+ "branch": "<branch label|null>"
115
+ }
116
+ ]
117
+ }
118
+ ```
119
+
120
+ ### 3.3 字段含义
121
+
122
+ - `entry`
123
+ 描述用户如何进入流程。
124
+ - `nodes`
125
+ 描述业务语义节点,还不是最终画布节点。
126
+ - `edges`
127
+ 描述业务语义上的连接关系。
128
+ - `channel_name`
129
+ 先保留为语义字段,后面再去项目通道列表里匹配真实 `channelId`。
130
+ - `branches`
131
+ 只描述分支语义;后面落地到 `node.config.branchList` 和 `edge.sourceBranchId`。
132
+
133
+ ---
134
+
135
+ ## 4. 第二步:前置 CLI 查询
136
+
137
+ ### 4.1 查询 cluster definition schema
138
+
139
+ 调用:
140
+
141
+ ```bash
142
+ te-cli te_audience +get_cluster_definition_schema --cluster_type condition
143
+ ```
144
+
145
+ 作用:
146
+ - 为条件节点、分群节点、入口节点准备 QP 构造依据
147
+ - 帮助生成 `targetClusterQp`
148
+ - 帮助生成 `triggerRule.events`
149
+
150
+ 这一步不是直接返回最终节点,而是提供“怎样把条件表达成 QP / 事件条件”的规则基础。
151
+
152
+ ### 4.2 查询项目通道
153
+
154
+ 调用:
155
+
156
+ ```bash
157
+ te-cli te-engage +channel-list --project-id <projectId>
158
+ ```
159
+
160
+ 作用:
161
+ - 获取项目下可用通道
162
+ - 根据意图中的 `channel_name` 为触达节点匹配真实 `channelId`
163
+ - 根据通道类型判断是 `message_push`、`wechat_push` 还是 `webhook_push`
164
+
165
+ 如果 `channel_name` 没有精确匹配,应优先:
166
+
167
+ 1. 名称精确匹配
168
+ 2. 名称关键词匹配
169
+ 3. 按节点类型兜底匹配通道类型
170
+
171
+ ---
172
+
173
+ ## 5. 第三步:把意图映射成 `req`
174
+
175
+ ### 5.1 `req` 顶层结构
176
+
177
+ 最终传给 `--req` 的对象结构如下:
178
+
179
+ ```json
180
+ {
181
+ "flowName": "<string>",
182
+ "flowDesc": "<string>",
183
+ "groupId": 0,
184
+ "tzOffset": 8,
185
+ "flowUuid": "<string, optional>",
186
+ "parentFlowUuid": "<string, optional>",
187
+ "versionType": 1,
188
+ "nodeList": [],
189
+ "edgeList": []
190
+ }
191
+ ```
192
+
193
+ 说明:
194
+ - `projectId` 不需要手写进 `--req`,CLI 会从 `--project-id` 自动注入
195
+ - `flowUuid` 和 `parentFlowUuid` 互斥
196
+ - 创建新草稿时,这两个字段都不传
197
+
198
+ ### 5.2 顶层字段来源
199
+
200
+ | `req` 字段 | 来源 |
201
+ |---|---|
202
+ | `flowName` | 意图 `flow_name` |
203
+ | `flowDesc` | 意图 `flow_desc`,没有就给空串或简短描述 |
204
+ | `groupId` | 默认 `0`,除非业务要求指定分组 |
205
+ | `tzOffset` | 用户时区或项目默认时区,常见为 `8` |
206
+ | `nodeList` | 由意图 `entry` + `nodes` 映射生成 |
207
+ | `edgeList` | 由意图 `edges` 和分支结构生成 |
208
+
209
+ ---
210
+
211
+ ## 6. 第四步:意图节点到画布节点的映射
212
+
213
+ ### 6.1 入口节点映射
214
+
215
+ | 意图 `entry.type` | 画布节点 `type` |
216
+ |---|---|
217
+ | `single_trigger` | `single_trigger` |
218
+ | `repeat_trigger` | `repeat_trigger` |
219
+ | `event_trigger` | `event_trigger` |
220
+
221
+ 入口节点始终要成为 `nodeList` 中唯一的入口节点。
222
+
223
+ ### 6.2 业务节点映射
224
+
225
+ | 意图节点语义 | 画布节点 `type` |
226
+ |---|---|
227
+ | 行为分流 | `event_split_flow` |
228
+ | 特征分流 | `feature_split_flow` |
229
+ | A/B 分流 | `ab_split_flow` |
230
+ | 行为判断 | `event_judge` |
231
+ | 特征判断 | `feature_judge` |
232
+ | Push 触达 | `message_push` |
233
+ | 微信触达 | `wechat_push` |
234
+ | Webhook / 其他外部触达 | `webhook_push` |
235
+ | 等待 | `time_control` |
236
+ | 结束 | `exit_flow` |
237
+
238
+ ### 6.3 条件字段映射
239
+
240
+ 条件类语义不能直接原样放进 `req`,要按下面方式落地:
241
+
242
+ | 语义类型 | 目标字段 |
243
+ |---|---|
244
+ | 受众分群条件 | `targetClusterQp` |
245
+ | 特征判断条件 | `targetClusterQp` |
246
+ | 特征分流分支条件 | `targetClusterQp` |
247
+ | 事件触发条件 | `triggerRule[].events[]` |
248
+ | 行为判断条件 | `triggerRule[].events[]` |
249
+ | 行为分流分支条件 | `triggerRule[].events[]` |
250
+
251
+ 简单理解:
252
+ - “按人群 / 属性判断”的,多数落到 `targetClusterQp`
253
+ - “按事件是否发生 / 发生几次判断”的,多数落到 `triggerRule.events`
254
+
255
+ ### 6.4 触达节点映射
256
+
257
+ 动作语义节点里的这些字段:
258
+
259
+ - `channel_name`
260
+ - `content`
261
+ - `languages`
262
+
263
+ 需要落地到 push 节点 `config`:
264
+
265
+ - `channel_name` -> 匹配成真实 `channelId`
266
+ - `content` -> 放进 `contentList`
267
+ - `languages` -> 决定是否生成多语言 `contentList`
268
+
269
+ ---
270
+
271
+ ## 7. 第五步:`nodeList` 怎么写
272
+
273
+ `nodeList` 中每一项结构如下:
274
+
275
+ | 字段 | 类型 | 必填 | 说明 |
276
+ |---|---|---|---|
277
+ | `id` | string | 是 | 请求内唯一节点 ID |
278
+ | `name` | string | 是 | 节点显示名 |
279
+ | `type` | string | 是 | 节点类型 |
280
+ | `config` | string | 是 | **JSON 字符串**,顶层必须是 JSON 对象 |
281
+ | `desc` | string | 否 | 节点描述 |
282
+
283
+ ### 7.1 最关键的规则
284
+
285
+ 1. `config` 必须是字符串,不是对象。
286
+ 2. `node.id` 必须唯一。
287
+ 3. 分支节点、判断节点里会被 `edge.sourceBranchId` 用到的 branchId,必须先定义在 `config` 里。
288
+ 4. 所有路径最终都要落到 `exit_flow`。
289
+
290
+ ### 7.2 常见节点类型
291
+
292
+ - `single_trigger`
293
+ - `repeat_trigger`
294
+ - `event_trigger`
295
+ - `event_split_flow`
296
+ - `feature_split_flow`
297
+ - `ab_split_flow`
298
+ - `event_judge`
299
+ - `feature_judge`
300
+ - `message_push`
301
+ - `wechat_push`
302
+ - `webhook_push`
303
+ - `time_control`
304
+ - `exit_flow`
305
+
306
+ ### 7.3 示例:最简单节点
307
+
308
+ ```json
309
+ {
310
+ "id": "node_1",
311
+ "name": "定时单次进入",
312
+ "type": "single_trigger",
313
+ "config": {
314
+ "triggerTime": "2026-04-10 06:35",
315
+ "flowEndDate": "2026-04-11 06:35"
316
+ }
317
+ }
318
+ ```
319
+
320
+ ### 7.4 常用 `config` 模板
321
+
322
+ 下面这些模板是“直接拼 `req`”时最该优先参考的部分。使用时先按对象构造,再整体 `JSON.stringify` 放进 `nodeList[].config`。
323
+
324
+ #### `repeat_trigger`
325
+
326
+ ```json
327
+ {
328
+ "targetUserType": 1,
329
+ "startDate": "<YYYY-MM-DD>",
330
+ "endDate": "<YYYY-MM-DD>",
331
+ "flowEndDate": "<YYYY-MM-DD HH:mm>",
332
+ "crontab": "0 00 09 * * ?",
333
+ "entryControlLimits": {
334
+ "enableMultEntry": false,
335
+ "disableConcurrentEntry": false
336
+ },
337
+ "targetClusterName": null,
338
+ "clusterPredictCount": null,
339
+ "clusterPredictTime": "<YYYY-MM-DD HH:mm:ss>",
340
+ "targetClusterQp": "<JSON.stringify(qp)>"
341
+ }
342
+ ```
343
+
344
+ 规则:
345
+ - `entry.segment` -> `targetClusterQp`
346
+ - `entry.schedule` -> `crontab`
347
+ - 常见默认值可用 `0 00 09 * * ?`
348
+
349
+ #### `event_trigger`
350
+
351
+ ```json
352
+ {
353
+ "triggerType": 3,
354
+ "targetUserType": 1,
355
+ "realtime": 0,
356
+ "clusterRefresh": 12,
357
+ "clusterRefreshTime": null,
358
+ "startDate": "<YYYY-MM-DD HH:mm>",
359
+ "endDate": "<YYYY-MM-DD HH:mm>",
360
+ "flowEndDate": "<YYYY-MM-DD HH:mm>",
361
+ "clusterPredictCount": null,
362
+ "clusterPredictTime": "<YYYY-MM-DD HH:mm:ss>",
363
+ "triggerRule": [
364
+ {
365
+ "periodStart": "<startDate>",
366
+ "periodEnd": "<endDate>",
367
+ "periodTimeSymbol": "TS02",
368
+ "dayStartTime": null,
369
+ "startDay": null,
370
+ "eventTriggerType": 0,
371
+ "zoneoffset": 8,
372
+ "events": []
373
+ }
374
+ ],
375
+ "entryControlLimits": {
376
+ "enableMultEntry": false,
377
+ "disableConcurrentEntry": false
378
+ },
379
+ "targetClusterQp": "<JSON.stringify(qp) 或 null>"
380
+ }
381
+ ```
382
+
383
+ 规则:
384
+ - `entry.trigger_event` -> `triggerRule[0].events`
385
+ - `entry.segment` 存在时再生成 `targetClusterQp`
386
+ - 没有 `segment` 时,`targetClusterQp` 可为 `null`
387
+
388
+ #### `event_split_flow`
389
+
390
+ ```json
391
+ {
392
+ "splitFlowType": 1,
393
+ "branchList": [
394
+ {
395
+ "branchId": "<branchId>",
396
+ "branchName": "<label>",
397
+ "branchType": 1,
398
+ "triggerRule": [
399
+ {
400
+ "delayTimeSymbol": "<minute|hour|day>",
401
+ "delayTime": "<number>",
402
+ "eventTriggerType": "<0 或 -1>",
403
+ "zoneoffset": 8,
404
+ "events": []
405
+ }
406
+ ]
407
+ }
408
+ ]
409
+ }
410
+ ```
411
+
412
+ 规则:
413
+ - `branch.condition` 是行为条件时,落到 `triggerRule[].events[]`
414
+ - `time_limit` -> `delayTimeSymbol` + `delayTime`
415
+ - “发生”用 `0`,“未发生”用 `-1`
416
+ - 兜底分支只保留:
417
+
418
+ ```json
419
+ {
420
+ "branchId": "<branchId>",
421
+ "branchType": 2
422
+ }
423
+ ```
424
+
425
+ #### `feature_split_flow`
426
+
427
+ ```json
428
+ {
429
+ "splitFlowType": 1,
430
+ "branchList": [
431
+ {
432
+ "branchId": "<branchId>",
433
+ "branchName": "<label>",
434
+ "branchType": 1,
435
+ "realtime": 0,
436
+ "clusterRefresh": 12,
437
+ "clusterPredictCount": null,
438
+ "clusterPredictTime": "<YYYY-MM-DD HH:mm:ss>",
439
+ "targetClusterQp": "<JSON.stringify(qp)>"
440
+ }
441
+ ]
442
+ }
443
+ ```
444
+
445
+ 规则:
446
+ - 属性 / 标签条件 -> `targetClusterQp`
447
+ - 兜底分支同样只保留 `branchId` + `branchType: 2`
448
+
449
+ #### `ab_split_flow`
450
+
451
+ ```json
452
+ {
453
+ "branchList": [
454
+ {
455
+ "branchId": "<branchId>",
456
+ "branchName": "对照组",
457
+ "branchType": 1,
458
+ "order": 1,
459
+ "percentageInExperiment": 34
460
+ },
461
+ {
462
+ "branchId": "<branchId>",
463
+ "branchName": "实验组 A",
464
+ "branchType": 2,
465
+ "order": 2,
466
+ "percentageInExperiment": 33
467
+ }
468
+ ],
469
+ "indicatorsDef": [],
470
+ "activateIndicatorsDef": null
471
+ }
472
+ ```
473
+
474
+ 规则:
475
+ - 用户没给比例时可均分
476
+ - 3 组时可用 `34/33/33`
477
+
478
+ #### `event_judge`
479
+
480
+ ```json
481
+ {
482
+ "transferType": 1,
483
+ "meetBranchId": "<meetBranchId>",
484
+ "notMeetBranchId": "<notMeetBranchId>",
485
+ "triggerRule": [
486
+ {
487
+ "delayTimeSymbol": "<minute|hour|day>",
488
+ "delayTime": "<number>",
489
+ "eventTriggerType": 0,
490
+ "zoneoffset": 8,
491
+ "events": []
492
+ }
493
+ ]
494
+ }
495
+ ```
496
+
497
+ 规则:
498
+ - `node.event` -> `triggerRule[].events[]`
499
+ - `wait_time` -> `delayTimeSymbol` + `delayTime`
500
+ - 未指定等待时长时,可默认 `30 minute`
501
+
502
+ #### `feature_judge`
503
+
504
+ ```json
505
+ {
506
+ "transferType": 1,
507
+ "meetBranchId": "<meetBranchId>",
508
+ "notMeetBranchId": "<notMeetBranchId>",
509
+ "clusterPredictCount": null,
510
+ "clusterPredictTime": "",
511
+ "targetClusterQp": "<JSON.stringify(qp)>"
512
+ }
513
+ ```
514
+
515
+ #### `message_push` / `webhook_push`
516
+
517
+ ```json
518
+ {
519
+ "channelId": "<matched channelId>",
520
+ "channelType": "<matched channelType>",
521
+ "enableChannelTouchLimits": false,
522
+ "isOccasionUp": false,
523
+ "contentList": [
524
+ {
525
+ "pushLanguageCode": "default",
526
+ "content": []
527
+ }
528
+ ],
529
+ "processType": 1
530
+ }
531
+ ```
532
+
533
+ 规则:
534
+ - `channel_name` -> 匹配真实 `channelId`
535
+ - `content` -> 优先填入最像“正文 / 内容 / 消息”的参数
536
+ - 当参数 `type = TEXT` 时,额外补:
537
+
538
+ ```json
539
+ {
540
+ "config": "[{\"type\":\"paragraph\",\"children\":[{\"text\":\"<与 value 相同>\"}]}]"
541
+ }
542
+ ```
543
+
544
+ 多语言规则:
545
+ - 第一条始终是 `"pushLanguageCode": "default"`
546
+ - 后续按 `languages` 生成其他语言版本
547
+ - 每种语言的 `content[]` 结构相同,只替换 `value`
548
+
549
+ #### `wechat_push`
550
+
551
+ ```json
552
+ {
553
+ "channelId": "<matched channelId>",
554
+ "enableChannelTouchLimits": false,
555
+ "isOccasionUp": false,
556
+ "contentList": [
557
+ {
558
+ "pushLanguageCode": "default",
559
+ "content": [
560
+ {
561
+ "key": "lang",
562
+ "type": "STRING",
563
+ "required": true,
564
+ "paramType": 2,
565
+ "name": "语言",
566
+ "value": "default"
567
+ },
568
+ {
569
+ "key": "page",
570
+ "type": "STRING",
571
+ "required": true,
572
+ "paramType": 2,
573
+ "name": "跳转页面",
574
+ "value": ""
575
+ },
576
+ {
577
+ "key": "miniprogramState",
578
+ "type": "STRING",
579
+ "required": true,
580
+ "paramType": 2,
581
+ "name": "版本",
582
+ "value": ""
583
+ }
584
+ ]
585
+ }
586
+ ],
587
+ "processType": 1
588
+ }
589
+ ```
590
+
591
+ #### `time_control`
592
+
593
+ ```json
594
+ {
595
+ "controlType": 1,
596
+ "timeUnit": "<minute|hour|day>",
597
+ "timeUnitNum": "<number>"
598
+ }
599
+ ```
600
+
601
+ 常见解析:
602
+ - `30分钟` -> `minute` + `30`
603
+ - `2小时` -> `hour` + `2`
604
+ - `1天` -> `day` + `1`
605
+
606
+ #### `exit_flow`
607
+
608
+ 最小可用 `config`:
609
+
610
+ ```json
611
+ {}
612
+ ```
613
+
614
+ ---
615
+
616
+ ## 8. 第六步:`edgeList` 怎么写
617
+
618
+ `edgeList` 中每一项结构如下:
619
+
620
+ | 字段 | 类型 | 必填 | 说明 |
621
+ |---|---|---|---|
622
+ | `source` | string | 是 | 上游节点 ID |
623
+ | `target` | string | 是 | 下游节点 ID |
624
+ | `edgeId` | string | 否 | 连线 ID |
625
+ | `sourceBranchId` | string | 否 | 分支/判断节点出边时使用 |
626
+ | `config` | string | 否 | JSON 字符串 |
627
+
628
+ ### 8.1 普通连线
629
+
630
+ ```json
631
+ {
632
+ "source": "node_1",
633
+ "target": "node_2"
634
+ }
635
+ ```
636
+
637
+ ### 8.2 分支连线
638
+
639
+ ```json
640
+ {
641
+ "source": "node_split",
642
+ "target": "node_a",
643
+ "sourceBranchId": "branch_a"
644
+ }
645
+ ```
646
+
647
+ ### 8.3 最关键的规则
648
+
649
+ 1. `source` 和 `target` 必须引用真实存在的 `node.id`
650
+ 2. 只有分支节点 / 判断节点的出边才需要 `sourceBranchId`
651
+ 3. 图必须是 DAG,不能有环
652
+ 4. 分支节点的 `sourceBranchId` 必须来自对应节点 `config` 里已经声明过的 branchId
653
+
654
+ ### 8.4 标准出边规则
655
+
656
+ | 节点类型 | 出边数 | `sourceBranchId` 规则 |
657
+ |---|---|---|
658
+ | `single_trigger` / `repeat_trigger` / `event_trigger` | 1 | 不传 |
659
+ | `event_split_flow` / `feature_split_flow` / `ab_split_flow` | 每分支 1 条 | 对应 `branchList[].branchId` |
660
+ | `event_judge` / `feature_judge` | 2 | 分别使用 `meetBranchId` / `notMeetBranchId` |
661
+ | `message_push` / `wechat_push` / `webhook_push` / `time_control` | 1 | 不传 |
662
+ | `exit_flow` | 0 | 不传 |
663
+
664
+ ---
665
+
666
+ ## 9. 第七步:图约束检查
667
+
668
+ 在提交前必须自检:
669
+
670
+ 1. `nodeList` 非空
671
+ 2. 入口节点必须且只能有一个
672
+ 3. 至少有一个 `exit_flow`
673
+ 4. 每个 `exit_flow` 恰好一条入边,且没有出边
674
+ 5. 每个 `node.id` 唯一
675
+ 6. 每条边引用的节点都存在
676
+ 7. 整张图无环
677
+
678
+ 如果分流节点使用 `splitFlowType = 2`,还要额外保证:
679
+ - 不同分支后续路径不要再次汇合到同一个节点
680
+ - 每条分支应独立走到自己的 `exit_flow`
681
+
682
+ ---
683
+
684
+ ## 10. 第八步:CLI 提交
685
+
686
+ ### 10.1 顶层 flags
687
+
688
+ | Flag | 类型 | 必填 | 说明 |
689
+ |---|---|---|---|
690
+ | `--project-id` / `-p` | number | 是 | 项目 ID |
691
+ | `--req` | json | 是 | 最终请求体对象 |
692
+
693
+ ### 10.2 CLI 实际提交结构
694
+
695
+ CLI 会把输入整理成:
696
+
697
+ ```json
698
+ {
699
+ "projectId": 1,
700
+ "req": {
701
+ "projectId": 1,
702
+ "...": "..."
703
+ }
704
+ }
705
+ ```
706
+
707
+ 也就是说:
708
+ - 顶层 `projectId` 来自 `--project-id`
709
+ - `req.projectId` 也会由 CLI 自动注入
710
+
711
+ ### 10.3 最小可用示例
712
+
713
+ ```bash
714
+ te-cli te-engage +save-flow \
715
+ --project-id 1 \
716
+ --req '{
717
+ "flowName": "Welcome Flow",
718
+ "flowDesc": "New user welcome flow",
719
+ "groupId": 0,
720
+ "tzOffset": 8,
721
+ "nodeList": [
722
+ {
723
+ "id": "node_1",
724
+ "name": "进入流程",
725
+ "type": "single_trigger",
726
+ "config": "{}"
727
+ },
728
+ {
729
+ "id": "node_2",
730
+ "name": "结束",
731
+ "type": "exit_flow",
732
+ "config": "{}"
733
+ }
734
+ ],
735
+ "edgeList": [
736
+ {
737
+ "source": "node_1",
738
+ "target": "node_2"
739
+ }
740
+ ]
741
+ }'
742
+ ```
743
+
744
+ ### 10.4 创建成功后的输出要求
745
+
746
+ 前置条件:
747
+ - 创建流程画布成功,返回了新创建的流程画布 `flowUuid`
748
+
749
+ 成功时必须:
750
+ - 向用户展示创建结果,至少包含画布名称等关键信息
751
+ - 必须输出一个**可点击的 Markdown 链接**
752
+
753
+ 链接生成规则:
754
+ - 使用标准 Markdown 链接语法,禁止放在代码块中
755
+ - URL 必须以 `/#/` 开头,禁止添加域名或任何域名占位符
756
+ - 将 `save_flow` 返回的 `flowUuid` 和本次创建使用的 `projectId` 替换到 URL 中
757
+
758
+ 输出模板:
759
+
760
+ [点击查看画布](/#/hermes/flow/detail?flowUuid=<替换为实际flowUuid>&currentProjectId=<替换为实际projectId>)
761
+
762
+ 正确示例:
763
+
764
+ [点击查看画布](/#/hermes/flow/detail?flowUuid=0006_831135755&currentProjectId=1)
765
+
766
+ 常见错误:
767
+ - `❌ {域名}/#/hermes/flow/...`:不要加域名占位符
768
+ - `❌` 把链接放在代码块 ````` 中:代码块内的链接不可点击
769
+ - `❌ /#/hermes/flow/detail?flowUuid=...`:不要输出纯文本 URL,必须使用 `[文字](URL)` 格式
770
+
771
+ ### 10.5 创建失败后的输出要求
772
+
773
+ 失败时必须:
774
+ - 输出完整请求体 JSON,供用户调试
775
+ - 明确说明失败原因
776
+
777
+ 建议输出结构:
778
+
779
+ ```json
780
+ {
781
+ "projectId": "<实际 projectId>",
782
+ "req": {
783
+ "...": "完整 save_flow 请求体"
784
+ }
785
+ }
786
+ ```
787
+
788
+ ---
789
+
790
+ ## 11. 最容易写错的地方
791
+
792
+ ### 11.1 `--req` 是对象,但 `node.config` / `edge.config` 是字符串
793
+
794
+ 正确:
795
+
796
+ ```json
797
+ {
798
+ "id": "node_1",
799
+ "name": "entry",
800
+ "type": "single_trigger",
801
+ "config": "{}"
802
+ }
803
+ ```
804
+
805
+ 错误:
806
+
807
+ ```json
808
+ {
809
+ "id": "node_1",
810
+ "name": "entry",
811
+ "type": "single_trigger",
812
+ "config": {}
813
+ }
814
+ ```
815
+
816
+ ### 11.2 时间单位必须小写
817
+
818
+ 像 `time_control` 里,应使用:
819
+
820
+ - `day`
821
+ - `hour`
822
+ - `minute`
823
+ - `week`
824
+ - `month`
825
+
826
+ 不要写成 `DAY`、`HOUR`、`MINUTE`。
827
+
828
+ ### 11.3 不要凭空写 `channelId`
829
+
830
+ `message_push`、`wechat_push`、`webhook_push` 这类节点的 `channelId`,必须来自:
831
+
832
+ ```bash
833
+ te-cli te-engage +channel-list --project-id <projectId>
834
+ ```
835
+
836
+ ### 11.4 分支 ID 必须先定义再引用
837
+
838
+ 如果某条边用了:
839
+
840
+ ```json
841
+ { "sourceBranchId": "branch_a" }
842
+ ```
843
+
844
+ 那么 `"branch_a"` 必须已经存在于对应上游节点的 `config` 中。
845
+
846
+ ### 11.5 `targetClusterQp` 本身通常也是字符串
847
+
848
+ 虽然 `targetClusterQp` 出现在节点 `config` 的 JSON 对象里,但它的值通常也不是原始对象,而是 QP 对象再做一次 `JSON.stringify` 后的字符串。
849
+
850
+ 示意:
851
+
852
+ ```json
853
+ { "targetClusterQp": "{\"totalCFilter\":{\"relation\":\"1\",\"filts\":[]}}" }
854
+ ```
855
+
856
+ ### 11.6 `TEXT` 参数的富文本 `config` 也必须是字符串
857
+
858
+ push 参数如果是 `TEXT`,它内部那个富文本 `config` 不是对象,而是字符串化 JSON。这个点很容易漏。
859
+
860
+ ### 11.7 `splitFlowType = 2` 时不要让分支重新汇合
861
+
862
+ “满足条件即进入”表示用户可能同时进入多个分支,这时后续路径不要共用同一个节点,否则语义容易冲突。
863
+
864
+ ---
865
+
866
+ ## 12. 一句话总结
867
+
868
+ 要稳定构建 `+save-flow` 的入参,不能直接从自然语言跳到 `req`,而应该遵循这条链路:
869
+
870
+ **用户需求 -> 意图 JSON -> schema / 通道补全 -> `nodeList` / `edgeList` -> `te-cli te-engage +save-flow`。**