@oomol-lab/open-flow 0.1.0-beta.72 → 0.1.0-beta.74

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 (432) hide show
  1. package/LICENSE +36 -0
  2. package/NOTICE +7 -0
  3. package/README.md +40 -0
  4. package/dist/browser/{createResourceDialog-BWJkjiOO.js → createResourceDialog-DI9pL-Yr.js} +2 -2
  5. package/dist/browser/{dialog-CUy_fwx9.js → dialog-BYJGvItc.js} +54 -19
  6. package/dist/browser/{flowChanges-CgSnSqqP.js → flowChanges-RL-H4CjD.js} +306 -48
  7. package/dist/browser/{flowWorkspace-Bf7H-r0t.js → flowWorkspace-BkDsETj0.js} +20745 -20186
  8. package/dist/browser/preview.css +73 -3
  9. package/dist/browser/preview.js +21410 -20607
  10. package/dist/browser/{typeScriptSession-B0hC-C8y.js → typeScriptSession-CSRwWmZm.js} +1 -1
  11. package/dist/browser/ui.css +72 -2
  12. package/dist/browser/workbench.css +73 -3
  13. package/dist/browser/workbench.js +14 -76
  14. package/dist/browser/{workbenchSelect-C3e4J93X.js → workbenchSelect-BcWPWGzw.js} +1 -1
  15. package/dist/command/index.js +34 -34
  16. package/dist/common/authoring.d.ts +1 -1
  17. package/dist/common/authoringFields.d.ts +1 -1
  18. package/dist/common/authoringSchema.d.ts +28 -4
  19. package/dist/common/connector-proxy.d.ts +1 -1
  20. package/dist/common/control-api-conformance.d.ts +1 -1
  21. package/dist/common/control-api-conformance.js +61 -24
  22. package/dist/common/control-api.d.ts +4 -3
  23. package/dist/common/control-api.js +90 -42
  24. package/dist/common/control-requests.d.ts +2 -1
  25. package/dist/common/control-requests.js +204 -42
  26. package/dist/common/cron-trigger.d.ts +1 -1
  27. package/dist/common/decision.d.ts +1 -1
  28. package/dist/common/draftOperations.d.ts +1 -1
  29. package/dist/common/engine-contract.d.ts +3 -2
  30. package/dist/common/event-source-definition.d.ts +1 -1
  31. package/dist/common/flow-agent.d.ts +1 -1
  32. package/dist/{browser → common}/flow-authoring-node.d.ts +3 -3
  33. package/dist/{browser → common}/flow-authoring.js +75 -23
  34. package/dist/{browser → common}/flow-change-schema.d.ts +177 -6
  35. package/dist/{browser → common}/flow-change.d.ts +35 -15
  36. package/dist/{browser → common}/flow-change.js +77 -25
  37. package/dist/common/flow-connectionUsage.d.ts +1 -1
  38. package/dist/common/flow-encoding.d.ts +1 -1
  39. package/dist/common/flow-encoding.js +34 -16
  40. package/dist/common/flow-errorHandling.d.ts +1 -1
  41. package/dist/common/flow-graph.d.ts +1 -1
  42. package/dist/common/flow-modules.d.ts +1 -1
  43. package/dist/common/flow-promptTemplate.d.ts +1 -1
  44. package/dist/common/flow-retry.d.ts +1 -1
  45. package/dist/common/flow-semantics.d.ts +1 -1
  46. package/dist/common/flow-semantics.js +151 -32
  47. package/dist/common/flow-workflowFile.d.ts +1 -1
  48. package/dist/common/flowInspection.d.ts +3 -3
  49. package/dist/common/integration-trigger.d.ts +1 -1
  50. package/dist/common/licenses.md +118 -1
  51. package/dist/common/liveDetails.d.ts +1 -1
  52. package/dist/common/mcp.d.ts +2 -1
  53. package/dist/common/mcp.js +59 -22
  54. package/dist/common/openapi.d.ts +1 -1
  55. package/dist/common/poll-trigger.d.ts +1 -1
  56. package/dist/common/run-results.d.ts +8 -1
  57. package/dist/common/runtime-contract.d.ts +8 -2
  58. package/dist/common/runtime-contract.js +22 -5
  59. package/dist/common/scheduler-checkpoint.d.ts +1 -1
  60. package/dist/common/scheduler-dependencies.d.ts +1 -1
  61. package/dist/common/scheduler-node-execution.d.ts +1 -1
  62. package/dist/common/scheduler.d.ts +2 -2
  63. package/dist/common/scheduler.js +31 -12
  64. package/dist/common/trigger-catalog.d.ts +1 -1
  65. package/dist/common/trigger-config-options.d.ts +1 -1
  66. package/dist/common/trigger-config.d.ts +1 -1
  67. package/dist/common/trigger-contract.d.ts +2 -2
  68. package/dist/common/trigger-localization.d.ts +1 -1
  69. package/dist/common/webhook-response.d.ts +1 -1
  70. package/dist/common/webhook-trigger.d.ts +1 -1
  71. package/dist/common/workflow.d.ts +17 -1
  72. package/dist/common/workflow.js +68 -22
  73. package/dist/index.d.ts +6 -3
  74. package/package.json +7 -6
  75. package/src/base/common/json.ts +90 -0
  76. package/src/canvas/common/commands.ts +15 -0
  77. package/src/connector/common/actionSchema.ts +168 -0
  78. package/src/connector/common/proxy.ts +44 -0
  79. package/src/control/common/api.ts +1505 -0
  80. package/src/control/common/authoring.ts +912 -0
  81. package/src/control/common/authoringCondition.ts +110 -0
  82. package/src/control/common/authoringDiagnosticFields.ts +136 -0
  83. package/src/control/common/authoringExamples.ts +192 -0
  84. package/src/control/common/authoringFields.ts +53 -0
  85. package/src/control/common/authoringLlm.ts +70 -0
  86. package/src/control/common/authoringOpenApi.ts +129 -0
  87. package/src/control/common/authoringSchema.ts +404 -0
  88. package/src/control/common/authoringTools.ts +123 -0
  89. package/src/control/common/authoringTriggers.ts +26 -0
  90. package/src/control/common/checkDecoders.ts +65 -0
  91. package/src/control/common/conformance.ts +1989 -0
  92. package/src/control/common/connectorDecoders.ts +370 -0
  93. package/src/control/common/connectorQueries.ts +61 -0
  94. package/src/control/common/decoding.ts +60 -0
  95. package/src/control/common/draftOperations.ts +61 -0
  96. package/src/control/common/errors.ts +114 -0
  97. package/src/control/common/eventSourceSchemas.ts +13 -0
  98. package/src/control/common/eventSources.ts +186 -0
  99. package/src/control/common/flowDecoders.ts +153 -0
  100. package/src/control/common/flowInspection.ts +181 -0
  101. package/src/control/common/flowNotifications.ts +37 -0
  102. package/src/control/common/liveDetails.ts +124 -0
  103. package/src/control/common/mcp.ts +241 -0
  104. package/src/control/common/mcpConformance.ts +142 -0
  105. package/src/control/common/providerAccess.ts +28 -0
  106. package/src/control/common/providerIconSprite.ts +42 -0
  107. package/src/control/common/publicationDecoders.ts +98 -0
  108. package/src/control/common/random.ts +16 -0
  109. package/src/control/common/requests.ts +112 -0
  110. package/src/control/common/resultQuery.ts +8 -0
  111. package/src/control/common/results.ts +176 -0
  112. package/src/control/common/revisionDecoders.ts +52 -0
  113. package/src/control/common/runDecoders.ts +240 -0
  114. package/src/control/common/triggerCatalog.ts +89 -0
  115. package/src/control/common/triggerDecoders.ts +175 -0
  116. package/src/decision/common/decision.ts +168 -0
  117. package/src/event-source/common/catalog.generated.json +65 -0
  118. package/src/event-source/common/definition.ts +66 -0
  119. package/src/event-source/common/index.ts +99 -0
  120. package/src/execution/common/checkpoint.ts +311 -0
  121. package/src/execution/common/dependencies.ts +440 -0
  122. package/src/execution/common/engineContract.ts +80 -0
  123. package/src/execution/common/events.ts +328 -0
  124. package/src/execution/common/node-execution.ts +467 -0
  125. package/src/execution/common/runLifecycle.ts +250 -0
  126. package/src/execution/common/runtime.ts +563 -0
  127. package/src/execution/common/scheduler.ts +696 -0
  128. package/src/execution/common/wait.ts +36 -0
  129. package/src/flow/common/agent.ts +305 -0
  130. package/src/flow/common/authoring.ts +30 -0
  131. package/src/flow/common/change.ts +1036 -0
  132. package/src/flow/common/changeSchema.ts +783 -0
  133. package/src/flow/common/codePermissions.ts +2 -0
  134. package/src/flow/common/condition.ts +265 -0
  135. package/src/flow/common/connectionUsage.ts +131 -0
  136. package/src/flow/common/edgeChanges.ts +35 -0
  137. package/src/flow/common/encoding.ts +437 -0
  138. package/src/flow/common/errorHandling.ts +34 -0
  139. package/src/flow/common/graph.ts +892 -0
  140. package/src/flow/common/inputValue.ts +16 -0
  141. package/src/flow/common/json.ts +8 -0
  142. package/src/flow/common/moduleChanges.ts +31 -0
  143. package/src/flow/common/modules.ts +292 -0
  144. package/src/flow/common/nodeChanges.ts +762 -0
  145. package/src/flow/common/portChanges.ts +36 -0
  146. package/src/flow/common/promptTemplate.ts +15 -0
  147. package/src/flow/common/retry.ts +20 -0
  148. package/src/flow/common/schema.ts +162 -0
  149. package/src/flow/common/schemaCompare.ts +176 -0
  150. package/src/flow/common/schemaComparer.ts +178 -0
  151. package/src/flow/common/schemaKeywords.ts +53 -0
  152. package/src/flow/common/semantics.ts +474 -0
  153. package/src/flow/common/sourceField.ts +35 -0
  154. package/src/flow/common/triggerScheduleSchema.ts +8 -0
  155. package/src/flow/common/wait.ts +30 -0
  156. package/src/flow/common/webhookMethod.ts +7 -0
  157. package/src/flow/common/webhookResponse.ts +75 -0
  158. package/src/flow/common/workflowFile.ts +97 -0
  159. package/src/json-schema-subset/checker/array.ts +142 -0
  160. package/src/json-schema-subset/checker/cache.ts +57 -0
  161. package/src/json-schema-subset/checker/checker.ts +230 -0
  162. package/src/json-schema-subset/checker/enumAndConst.ts +113 -0
  163. package/src/json-schema-subset/checker/equals.ts +93 -0
  164. package/src/json-schema-subset/checker/numeric/checker.ts +50 -0
  165. package/src/json-schema-subset/checker/numeric/float.ts +121 -0
  166. package/src/json-schema-subset/checker/numeric/index.ts +1 -0
  167. package/src/json-schema-subset/checker/numeric/integer.ts +119 -0
  168. package/src/json-schema-subset/checker/numeric/integerNormalizer.ts +72 -0
  169. package/src/json-schema-subset/checker/object.ts +354 -0
  170. package/src/json-schema-subset/checker/range.ts +91 -0
  171. package/src/json-schema-subset/checker/string.ts +60 -0
  172. package/src/json-schema-subset/checker/tools/index.ts +3 -0
  173. package/src/json-schema-subset/checker/tools/mark.ts +82 -0
  174. package/src/json-schema-subset/checker/tools/quantum.ts +106 -0
  175. package/src/json-schema-subset/checker/tools/range.ts +210 -0
  176. package/src/json-schema-subset/checker/validator.ts +23 -0
  177. package/src/json-schema-subset/compiler/array.ts +163 -0
  178. package/src/json-schema-subset/compiler/combination.ts +109 -0
  179. package/src/json-schema-subset/compiler/common.ts +99 -0
  180. package/src/json-schema-subset/compiler/compiler.ts +188 -0
  181. package/src/json-schema-subset/compiler/enumAndConst.ts +75 -0
  182. package/src/json-schema-subset/compiler/index.ts +11 -0
  183. package/src/json-schema-subset/compiler/object.ts +411 -0
  184. package/src/json-schema-subset/compiler/primitive.ts +144 -0
  185. package/src/json-schema-subset/compiler/utils.ts +24 -0
  186. package/src/json-schema-subset/compiler/wrapper.ts +192 -0
  187. package/src/json-schema-subset/error.ts +55 -0
  188. package/src/json-schema-subset/expression/calculator.ts +442 -0
  189. package/src/json-schema-subset/expression/combination.ts +49 -0
  190. package/src/json-schema-subset/expression/expression.ts +191 -0
  191. package/src/json-schema-subset/expression/index.ts +25 -0
  192. package/src/json-schema-subset/expression/result.ts +88 -0
  193. package/src/json-schema-subset/expression/types.ts +36 -0
  194. package/src/json-schema-subset/extends/extendsContext.ts +89 -0
  195. package/src/json-schema-subset/extends/index.ts +2 -0
  196. package/src/json-schema-subset/extends/types.ts +12 -0
  197. package/src/json-schema-subset/global.ts +60 -0
  198. package/src/json-schema-subset/index.ts +8 -0
  199. package/src/json-schema-subset/preprocessing.ts +74 -0
  200. package/src/json-schema-subset/types.ts +8 -0
  201. package/src/json-schema-subset/utils.ts +95 -0
  202. package/src/localization/common/languages.ts +118 -0
  203. package/src/localization/common/timeZone.ts +25 -0
  204. package/src/openapi/common/authBindings.ts +12 -0
  205. package/src/openapi/common/openapi.ts +459 -0
  206. package/src/trigger/common/config.ts +56 -0
  207. package/src/trigger/common/configOptions.ts +15 -0
  208. package/src/trigger/common/configSchema.ts +8 -0
  209. package/src/trigger/common/contract.ts +132 -0
  210. package/src/trigger/common/cron.ts +151 -0
  211. package/src/trigger/common/integration.ts +498 -0
  212. package/src/trigger/common/poll.ts +187 -0
  213. package/src/trigger/common/webhook.ts +412 -0
  214. package/src/trigger/providers/airtable/locales/fr.json +18 -0
  215. package/src/trigger/providers/airtable/locales/ja.json +18 -0
  216. package/src/trigger/providers/airtable/locales/ko.json +18 -0
  217. package/src/trigger/providers/airtable/locales/ru.json +18 -0
  218. package/src/trigger/providers/airtable/locales/zh-CN.json +18 -0
  219. package/src/trigger/providers/airtable/locales/zh-TW.json +18 -0
  220. package/src/trigger/providers/asana/locales/fr.json +15 -0
  221. package/src/trigger/providers/asana/locales/ja.json +15 -0
  222. package/src/trigger/providers/asana/locales/ko.json +15 -0
  223. package/src/trigger/providers/asana/locales/ru.json +15 -0
  224. package/src/trigger/providers/asana/locales/zh-CN.json +15 -0
  225. package/src/trigger/providers/asana/locales/zh-TW.json +15 -0
  226. package/src/trigger/providers/calendly/locales/fr.json +16 -0
  227. package/src/trigger/providers/calendly/locales/ja.json +16 -0
  228. package/src/trigger/providers/calendly/locales/ko.json +16 -0
  229. package/src/trigger/providers/calendly/locales/ru.json +16 -0
  230. package/src/trigger/providers/calendly/locales/zh-CN.json +16 -0
  231. package/src/trigger/providers/calendly/locales/zh-TW.json +16 -0
  232. package/src/trigger/providers/catalog.generated.json +4996 -0
  233. package/src/trigger/providers/clickup/locales/fr.json +16 -0
  234. package/src/trigger/providers/clickup/locales/ja.json +16 -0
  235. package/src/trigger/providers/clickup/locales/ko.json +16 -0
  236. package/src/trigger/providers/clickup/locales/ru.json +16 -0
  237. package/src/trigger/providers/clickup/locales/zh-CN.json +16 -0
  238. package/src/trigger/providers/clickup/locales/zh-TW.json +16 -0
  239. package/src/trigger/providers/definitions.ts +19 -0
  240. package/src/trigger/providers/feishu/locales/fr.json +20 -0
  241. package/src/trigger/providers/feishu/locales/ja.json +20 -0
  242. package/src/trigger/providers/feishu/locales/ko.json +20 -0
  243. package/src/trigger/providers/feishu/locales/ru.json +20 -0
  244. package/src/trigger/providers/feishu/locales/zh-CN.json +20 -0
  245. package/src/trigger/providers/feishu/locales/zh-TW.json +20 -0
  246. package/src/trigger/providers/fieldDescriptions.ts +392 -0
  247. package/src/trigger/providers/fieldLabels.ts +256 -0
  248. package/src/trigger/providers/fireflies/locales/fr.json +17 -0
  249. package/src/trigger/providers/fireflies/locales/ja.json +17 -0
  250. package/src/trigger/providers/fireflies/locales/ko.json +17 -0
  251. package/src/trigger/providers/fireflies/locales/ru.json +17 -0
  252. package/src/trigger/providers/fireflies/locales/zh-CN.json +17 -0
  253. package/src/trigger/providers/fireflies/locales/zh-TW.json +17 -0
  254. package/src/trigger/providers/github/locales/fr.json +30 -0
  255. package/src/trigger/providers/github/locales/ja.json +30 -0
  256. package/src/trigger/providers/github/locales/ko.json +30 -0
  257. package/src/trigger/providers/github/locales/ru.json +30 -0
  258. package/src/trigger/providers/github/locales/zh-CN.json +30 -0
  259. package/src/trigger/providers/github/locales/zh-TW.json +30 -0
  260. package/src/trigger/providers/gitlab/locales/fr.json +18 -0
  261. package/src/trigger/providers/gitlab/locales/ja.json +18 -0
  262. package/src/trigger/providers/gitlab/locales/ko.json +18 -0
  263. package/src/trigger/providers/gitlab/locales/ru.json +18 -0
  264. package/src/trigger/providers/gitlab/locales/zh-CN.json +18 -0
  265. package/src/trigger/providers/gitlab/locales/zh-TW.json +18 -0
  266. package/src/trigger/providers/gmail/locales/fr.json +18 -0
  267. package/src/trigger/providers/gmail/locales/ja.json +18 -0
  268. package/src/trigger/providers/gmail/locales/ko.json +18 -0
  269. package/src/trigger/providers/gmail/locales/ru.json +18 -0
  270. package/src/trigger/providers/gmail/locales/zh-CN.json +18 -0
  271. package/src/trigger/providers/gmail/locales/zh-TW.json +18 -0
  272. package/src/trigger/providers/google-calendar/locales/fr.json +15 -0
  273. package/src/trigger/providers/google-calendar/locales/ja.json +15 -0
  274. package/src/trigger/providers/google-calendar/locales/ko.json +15 -0
  275. package/src/trigger/providers/google-calendar/locales/ru.json +15 -0
  276. package/src/trigger/providers/google-calendar/locales/zh-CN.json +15 -0
  277. package/src/trigger/providers/google-calendar/locales/zh-TW.json +15 -0
  278. package/src/trigger/providers/google-drive/locales/fr.json +48 -0
  279. package/src/trigger/providers/google-drive/locales/ja.json +48 -0
  280. package/src/trigger/providers/google-drive/locales/ko.json +48 -0
  281. package/src/trigger/providers/google-drive/locales/ru.json +48 -0
  282. package/src/trigger/providers/google-drive/locales/zh-CN.json +48 -0
  283. package/src/trigger/providers/google-drive/locales/zh-TW.json +48 -0
  284. package/src/trigger/providers/google-sheets/locales/fr.json +19 -0
  285. package/src/trigger/providers/google-sheets/locales/ja.json +19 -0
  286. package/src/trigger/providers/google-sheets/locales/ko.json +19 -0
  287. package/src/trigger/providers/google-sheets/locales/ru.json +19 -0
  288. package/src/trigger/providers/google-sheets/locales/zh-CN.json +19 -0
  289. package/src/trigger/providers/google-sheets/locales/zh-TW.json +19 -0
  290. package/src/trigger/providers/intercom/locales/fr.json +17 -0
  291. package/src/trigger/providers/intercom/locales/ja.json +17 -0
  292. package/src/trigger/providers/intercom/locales/ko.json +17 -0
  293. package/src/trigger/providers/intercom/locales/ru.json +17 -0
  294. package/src/trigger/providers/intercom/locales/zh-CN.json +17 -0
  295. package/src/trigger/providers/intercom/locales/zh-TW.json +17 -0
  296. package/src/trigger/providers/jira/locales/fr.json +17 -0
  297. package/src/trigger/providers/jira/locales/ja.json +17 -0
  298. package/src/trigger/providers/jira/locales/ko.json +17 -0
  299. package/src/trigger/providers/jira/locales/ru.json +17 -0
  300. package/src/trigger/providers/jira/locales/zh-CN.json +17 -0
  301. package/src/trigger/providers/jira/locales/zh-TW.json +17 -0
  302. package/src/trigger/providers/linear/locales/fr.json +13 -0
  303. package/src/trigger/providers/linear/locales/ja.json +13 -0
  304. package/src/trigger/providers/linear/locales/ko.json +13 -0
  305. package/src/trigger/providers/linear/locales/ru.json +13 -0
  306. package/src/trigger/providers/linear/locales/zh-CN.json +13 -0
  307. package/src/trigger/providers/linear/locales/zh-TW.json +13 -0
  308. package/src/trigger/providers/locales/fr.ts +71 -0
  309. package/src/trigger/providers/locales/ja.ts +71 -0
  310. package/src/trigger/providers/locales/ko.ts +71 -0
  311. package/src/trigger/providers/locales/ru.ts +71 -0
  312. package/src/trigger/providers/locales/zh-CN.ts +71 -0
  313. package/src/trigger/providers/locales/zh-TW.ts +71 -0
  314. package/src/trigger/providers/localization.ts +59 -0
  315. package/src/trigger/providers/notion/locales/fr.json +16 -0
  316. package/src/trigger/providers/notion/locales/ja.json +16 -0
  317. package/src/trigger/providers/notion/locales/ko.json +16 -0
  318. package/src/trigger/providers/notion/locales/ru.json +16 -0
  319. package/src/trigger/providers/notion/locales/zh-CN.json +16 -0
  320. package/src/trigger/providers/notion/locales/zh-TW.json +16 -0
  321. package/src/trigger/providers/one-drive/locales/fr.json +16 -0
  322. package/src/trigger/providers/one-drive/locales/ja.json +16 -0
  323. package/src/trigger/providers/one-drive/locales/ko.json +16 -0
  324. package/src/trigger/providers/one-drive/locales/ru.json +16 -0
  325. package/src/trigger/providers/one-drive/locales/zh-CN.json +16 -0
  326. package/src/trigger/providers/one-drive/locales/zh-TW.json +16 -0
  327. package/src/trigger/providers/outlook/locales/fr.json +18 -0
  328. package/src/trigger/providers/outlook/locales/ja.json +18 -0
  329. package/src/trigger/providers/outlook/locales/ko.json +18 -0
  330. package/src/trigger/providers/outlook/locales/ru.json +18 -0
  331. package/src/trigger/providers/outlook/locales/zh-CN.json +18 -0
  332. package/src/trigger/providers/outlook/locales/zh-TW.json +18 -0
  333. package/src/trigger/providers/pandadoc/locales/fr.json +12 -0
  334. package/src/trigger/providers/pandadoc/locales/ja.json +12 -0
  335. package/src/trigger/providers/pandadoc/locales/ko.json +12 -0
  336. package/src/trigger/providers/pandadoc/locales/ru.json +12 -0
  337. package/src/trigger/providers/pandadoc/locales/zh-CN.json +12 -0
  338. package/src/trigger/providers/pandadoc/locales/zh-TW.json +12 -0
  339. package/src/trigger/providers/pipedrive/locales/fr.json +15 -0
  340. package/src/trigger/providers/pipedrive/locales/ja.json +15 -0
  341. package/src/trigger/providers/pipedrive/locales/ko.json +15 -0
  342. package/src/trigger/providers/pipedrive/locales/ru.json +15 -0
  343. package/src/trigger/providers/pipedrive/locales/zh-CN.json +15 -0
  344. package/src/trigger/providers/pipedrive/locales/zh-TW.json +15 -0
  345. package/src/trigger/providers/remote.ts +163 -0
  346. package/src/trigger/providers/resend/locales/fr.json +16 -0
  347. package/src/trigger/providers/resend/locales/ja.json +16 -0
  348. package/src/trigger/providers/resend/locales/ko.json +16 -0
  349. package/src/trigger/providers/resend/locales/ru.json +16 -0
  350. package/src/trigger/providers/resend/locales/zh-CN.json +16 -0
  351. package/src/trigger/providers/resend/locales/zh-TW.json +16 -0
  352. package/src/trigger/providers/sentry/locales/fr.json +19 -0
  353. package/src/trigger/providers/sentry/locales/ja.json +19 -0
  354. package/src/trigger/providers/sentry/locales/ko.json +19 -0
  355. package/src/trigger/providers/sentry/locales/ru.json +19 -0
  356. package/src/trigger/providers/sentry/locales/zh-CN.json +19 -0
  357. package/src/trigger/providers/sentry/locales/zh-TW.json +19 -0
  358. package/src/trigger/providers/shopify/locales/fr.json +18 -0
  359. package/src/trigger/providers/shopify/locales/ja.json +18 -0
  360. package/src/trigger/providers/shopify/locales/ko.json +18 -0
  361. package/src/trigger/providers/shopify/locales/ru.json +18 -0
  362. package/src/trigger/providers/shopify/locales/zh-CN.json +18 -0
  363. package/src/trigger/providers/shopify/locales/zh-TW.json +18 -0
  364. package/src/trigger/providers/slack/locales/fr.json +18 -0
  365. package/src/trigger/providers/slack/locales/ja.json +18 -0
  366. package/src/trigger/providers/slack/locales/ko.json +18 -0
  367. package/src/trigger/providers/slack/locales/ru.json +18 -0
  368. package/src/trigger/providers/slack/locales/zh-CN.json +18 -0
  369. package/src/trigger/providers/slack/locales/zh-TW.json +18 -0
  370. package/src/trigger/providers/slackbot/locales/fr.json +23 -0
  371. package/src/trigger/providers/slackbot/locales/ja.json +23 -0
  372. package/src/trigger/providers/slackbot/locales/ko.json +23 -0
  373. package/src/trigger/providers/slackbot/locales/ru.json +23 -0
  374. package/src/trigger/providers/slackbot/locales/zh-CN.json +23 -0
  375. package/src/trigger/providers/slackbot/locales/zh-TW.json +23 -0
  376. package/src/trigger/providers/source-events.ts +25 -0
  377. package/src/trigger/providers/stripe/locales/fr.json +17 -0
  378. package/src/trigger/providers/stripe/locales/ja.json +17 -0
  379. package/src/trigger/providers/stripe/locales/ko.json +17 -0
  380. package/src/trigger/providers/stripe/locales/ru.json +17 -0
  381. package/src/trigger/providers/stripe/locales/zh-CN.json +17 -0
  382. package/src/trigger/providers/stripe/locales/zh-TW.json +17 -0
  383. package/src/trigger/providers/tally/locales/fr.json +12 -0
  384. package/src/trigger/providers/tally/locales/ja.json +12 -0
  385. package/src/trigger/providers/tally/locales/ko.json +12 -0
  386. package/src/trigger/providers/tally/locales/ru.json +12 -0
  387. package/src/trigger/providers/tally/locales/zh-CN.json +12 -0
  388. package/src/trigger/providers/tally/locales/zh-TW.json +12 -0
  389. package/src/trigger/providers/telegram/locales/fr.json +17 -0
  390. package/src/trigger/providers/telegram/locales/ja.json +17 -0
  391. package/src/trigger/providers/telegram/locales/ko.json +17 -0
  392. package/src/trigger/providers/telegram/locales/ru.json +17 -0
  393. package/src/trigger/providers/telegram/locales/zh-CN.json +17 -0
  394. package/src/trigger/providers/telegram/locales/zh-TW.json +17 -0
  395. package/src/trigger/providers/typeform/locales/fr.json +12 -0
  396. package/src/trigger/providers/typeform/locales/ja.json +12 -0
  397. package/src/trigger/providers/typeform/locales/ko.json +12 -0
  398. package/src/trigger/providers/typeform/locales/ru.json +12 -0
  399. package/src/trigger/providers/typeform/locales/zh-CN.json +12 -0
  400. package/src/trigger/providers/typeform/locales/zh-TW.json +12 -0
  401. package/src/trigger/providers/vercel/locales/fr.json +18 -0
  402. package/src/trigger/providers/vercel/locales/ja.json +18 -0
  403. package/src/trigger/providers/vercel/locales/ko.json +18 -0
  404. package/src/trigger/providers/vercel/locales/ru.json +18 -0
  405. package/src/trigger/providers/vercel/locales/zh-CN.json +18 -0
  406. package/src/trigger/providers/vercel/locales/zh-TW.json +18 -0
  407. package/src/trigger/providers/woocommerce/locales/fr.json +19 -0
  408. package/src/trigger/providers/woocommerce/locales/ja.json +19 -0
  409. package/src/trigger/providers/woocommerce/locales/ko.json +19 -0
  410. package/src/trigger/providers/woocommerce/locales/ru.json +19 -0
  411. package/src/trigger/providers/woocommerce/locales/zh-CN.json +19 -0
  412. package/src/trigger/providers/woocommerce/locales/zh-TW.json +19 -0
  413. package/src/trigger/providers/zendesk/locales/fr.json +15 -0
  414. package/src/trigger/providers/zendesk/locales/ja.json +15 -0
  415. package/src/trigger/providers/zendesk/locales/ko.json +15 -0
  416. package/src/trigger/providers/zendesk/locales/ru.json +15 -0
  417. package/src/trigger/providers/zendesk/locales/zh-CN.json +15 -0
  418. package/src/trigger/providers/zendesk/locales/zh-TW.json +15 -0
  419. package/src/trigger/providers/zoom/locales/fr.json +17 -0
  420. package/src/trigger/providers/zoom/locales/ja.json +17 -0
  421. package/src/trigger/providers/zoom/locales/ko.json +17 -0
  422. package/src/trigger/providers/zoom/locales/ru.json +17 -0
  423. package/src/trigger/providers/zoom/locales/zh-CN.json +17 -0
  424. package/src/trigger/providers/zoom/locales/zh-TW.json +17 -0
  425. package/src/types/index.ts +112 -0
  426. package/src/workflow/common/workflow.ts +273 -0
  427. package/dist/browser/lib-DrKav3HG.js +0 -11403
  428. /package/dist/{browser → common}/flow-authoring-edge.d.ts +0 -0
  429. /package/dist/{browser → common}/flow-authoring-module.d.ts +0 -0
  430. /package/dist/{browser → common}/flow-authoring.d.ts +0 -0
  431. /package/dist/{browser → common}/flow-input-value.d.ts +0 -0
  432. /package/dist/{browser → common}/webhook-method.d.ts +0 -0
@@ -0,0 +1,912 @@
1
+ import type {
2
+ ChangeOperation,
3
+ GraphNode,
4
+ InputMapping,
5
+ InputPort,
6
+ JsonValue,
7
+ ManagedTaskDefinition,
8
+ RevisionContent,
9
+ TriggerKeySnapshot,
10
+ } from '../../flow/common/change.ts'
11
+ import type { WorkflowContract, WorkflowCandidate } from '../../workflow/common/workflow.ts'
12
+ import type { ConnectorAction, Diagnostic } from './api.ts'
13
+ import type { AuthoringConditionConfiguration, AuthoringConditionSource } from './authoringCondition.ts'
14
+ import type { AuthoringOpenApiConfig } from './authoringOpenApi.ts'
15
+ import type { AuthoringRead, AuthoringRequest, AuthoringSearch, AuthoringSource, AuthoringType } from './authoringSchema.ts'
16
+ import type { AuthoringAgentTool, AuthoringCapability } from './authoringTools.ts'
17
+
18
+ import { dequal } from 'dequal/lite'
19
+ import { connectorOutputMode } from '../../connector/common/actionSchema.ts'
20
+ import { decisionTask } from '../../decision/common/decision.ts'
21
+ import { supportsNodeRetry, isTriggerNode, applyFlowChanges, decodeChangeOperations, upgradeRevisionContent } from '../../flow/common/change.ts'
22
+ import { nodeInputMappings } from '../../flow/common/condition.ts'
23
+ import { connect, disconnect } from '../../flow/common/edgeChanges.ts'
24
+ import { nodeSystemOutputPorts, supportsNodeErrorHandling } from '../../flow/common/errorHandling.ts'
25
+ import { nodeInputPorts, nodeOutputPorts } from '../../flow/common/graph.ts'
26
+ import { imports as moduleImports } from '../../flow/common/moduleChanges.ts'
27
+ import {
28
+ createAgentTask,
29
+ createCodeTask,
30
+ defaultCodeTaskPorts,
31
+ createCondition,
32
+ createDecisionTask,
33
+ createLlmTask,
34
+ createManagedTask,
35
+ createProviderTrigger,
36
+ createValue,
37
+ createWait,
38
+ createApproval,
39
+ cleanVariableBindings,
40
+ updateStartInputDefs,
41
+ updateOutputsDefs,
42
+ renameFlowOutputSources,
43
+ } from '../../flow/common/nodeChanges.ts'
44
+ import { retryConfigurationSchema } from '../../flow/common/retry.ts'
45
+ import { withWorkflowTask, workflowTask, workflowSelectionTask, workflowCapability, workflowAgentTool } from '../../workflow/common/workflow.ts'
46
+ import { conditionConfigurationView, prepareConditionConfiguration } from './authoringCondition.ts'
47
+ import { authoringDiagnosticField } from './authoringDiagnosticFields.ts'
48
+ import { fieldsView, fieldsToPorts } from './authoringFields.ts'
49
+ import { llmConfigurationView, prepareLlmConfiguration, initialAuthoringLlmTask } from './authoringLlm.ts'
50
+ import { AuthoringOpenApiAuthenticationError, openApiConfigView, openApiAuthenticationChoices, prepareOpenApiTask } from './authoringOpenApi.ts'
51
+ import { authoringConfigurations, authoringReadSchema, authoringRequestSchema, authoringSearchSchema } from './authoringSchema.ts'
52
+ import { AuthoringToolInputError, outwardAgentTools, prepareAgentTools, outwardCapabilities, prepareCapabilities } from './authoringTools.ts'
53
+ import { triggerConfiguration } from './authoringTriggers.ts'
54
+ export * from './authoringSchema.ts'
55
+
56
+ const record = (value: unknown): Record<string, unknown> =>
57
+ value != null && typeof value == 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : {}
58
+ const json = (value: unknown): JsonValue => JSON.parse(JSON.stringify(value)) as JsonValue
59
+ export class AuthoringError extends Error {
60
+ readonly code: string
61
+ readonly details: Record<string, unknown>
62
+ constructor(code: string, message: string, details: Record<string, unknown> = {}) {
63
+ super(message)
64
+ this.code = code
65
+ this.details = details
66
+ this.name = 'AuthoringError'
67
+ }
68
+ }
69
+ function fail(code: string, message: string, details: Record<string, unknown> = {}): never {
70
+ throw new AuthoringError(code, message, details)
71
+ }
72
+ function nodeAt(content: RevisionContent, ref: string): GraphNode {
73
+ return (
74
+ (Object.hasOwn(content.document.graph.nodes, ref) ? content.document.graph.nodes[ref] : undefined) ??
75
+ fail('node.not-found', `Node ${JSON.stringify(ref)} does not exist.`, { node: ref })
76
+ )
77
+ }
78
+ function taskAt(node: GraphNode) {
79
+ return node.kind == 'task' ? node.task : undefined
80
+ }
81
+ const llmReservedInputs = ['model', 'template', 'messages']
82
+ function inputDefinitions(node: GraphNode) {
83
+ if (node.kind == 'condition') return {}
84
+ if (node.kind == 'poll' || node.kind == 'integration')
85
+ return Object.fromEntries(node.definition.configInputs.flatMap((port) => ('handle' in port ? [[port.handle, port]] : [])))
86
+ return nodeInputPorts(node)
87
+ }
88
+ function inputMappings(node: GraphNode) {
89
+ return node.kind == 'condition' ? {} : node.kind == 'poll' || node.kind == 'integration' ? node.config : nodeInputMappings(node)
90
+ }
91
+ function typeOf(node: GraphNode): AuthoringType {
92
+ const task = taskAt(node)
93
+ return node.kind == 'manual' ? 'start' : node.kind != 'task' ? node.kind : task != null && 'executor' in task ? task.executor.kind : 'code'
94
+ }
95
+ function outwardSource(content: RevisionContent, value: unknown): unknown {
96
+ if (Array.isArray(value)) return value.map((v) => outwardSource(content, v))
97
+ if (value == null || typeof value != 'object') return value
98
+ const v = record(value)
99
+ if (v.kind == 'node' && typeof v.nodeId == 'string' && typeof v.output == 'string')
100
+ return { kind: v.system === true ? 'system' : 'output', node: v.nodeId, port: v.output, ...(v.field == null ? {} : { field: v.field }) }
101
+ if (v.kind == 'binding' && typeof v.bindingId == 'string')
102
+ return { kind: 'variable', name: content.document.bindings[v.bindingId]?.target ?? '[missing variable]' }
103
+ // Literal JSON is user data, including objects that resemble references.
104
+ if (v.kind == 'value') return value
105
+ return Object.fromEntries(Object.entries(v).map(([k, item]) => [k, outwardSource(content, item)]))
106
+ }
107
+ function authoringEdges(edges: RevisionContent['document']['graph']['edges']) {
108
+ return edges.map((edge) =>
109
+ edge.sourceHandle == null ? { source: edge.source, target: edge.target } : { source: edge.source, target: edge.target, branch: edge.sourceHandle },
110
+ )
111
+ }
112
+ export function authoringNode(content: RevisionContent, ref: string) {
113
+ const node = nodeAt(content, ref),
114
+ type = typeOf(node),
115
+ task = taskAt(node)
116
+ let config: Record<string, unknown> = {}
117
+ const texts: Record<string, string> = {}
118
+ if (task != null && 'executor' in task) {
119
+ const { kind: _, ...executor } = task.executor
120
+ config = { ...executor }
121
+ if (task.executor.kind == 'agent') {
122
+ const { prompt, tools, notification, ...rest } = task.executor
123
+ const { kind: _agentKind, ...settings } = rest
124
+ config = {
125
+ ...settings,
126
+ inputs: fieldsView([...task.inputs, ...(node.kind == 'task' ? (node.additionalInputs ?? []) : [])]),
127
+ resultSchema: task.outputs.find((port) => 'handle' in port)?.jsonSchema ?? { type: 'string' },
128
+ tools: outwardAgentTools(tools),
129
+ }
130
+ texts.prompt = prompt
131
+ if (notification != null) {
132
+ const { inputDefinitions: _definitions, ...noticeSettings } = notification
133
+ config.notification = noticeSettings
134
+ }
135
+ } else if (task.executor.kind == 'connector') {
136
+ const { kind: _kind, outputMode: _outputMode, ...settings } = task.executor
137
+ config = settings
138
+ } else if (task.executor.kind == 'llm')
139
+ config = {
140
+ ...llmConfigurationView(task),
141
+ inputs: fieldsView(
142
+ [...task.inputs, ...(node.kind == 'task' ? (node.additionalInputs ?? []) : [])].filter(
143
+ (port) => !('handle' in port) || !llmReservedInputs.includes(port.handle),
144
+ ),
145
+ ),
146
+ }
147
+ else if (task.executor.kind == 'workflow') config = { flowId: task.executor.flowId }
148
+ else if (task.executor.kind == 'openapi') {
149
+ config = { ...openApiConfigView(task.executor) }
150
+ }
151
+ } else if (node.kind == 'task' && 'moduleId' in node.task) {
152
+ config = {
153
+ inputs: fieldsView([...node.task.inputs, ...(node.additionalInputs ?? [])]),
154
+ outputs: fieldsView(node.task.outputs),
155
+ ...(node.task.capabilities == null ? {} : { capabilities: outwardCapabilities(node.task.capabilities) }),
156
+ }
157
+ texts.code = content.modules[node.task.moduleId]?.source ?? ''
158
+ } else {
159
+ switch (node.kind) {
160
+ case 'outputs':
161
+ config = { outputDefs: fieldsView(node.outputDefs) }
162
+ break
163
+ case 'condition':
164
+ config = { ...conditionConfigurationView(node, (value) => outwardSource(content, value) as AuthoringConditionSource) }
165
+ break
166
+ case 'value':
167
+ config = {
168
+ values: Object.fromEntries(node.values.filter((port) => Object.hasOwn(port, 'value')).map((port) => [port.handle, port.value])),
169
+ outputs: fieldsView(node.values.map(({ value: _value, ...port }) => port)),
170
+ }
171
+ break
172
+ case 'wait':
173
+ case 'approval':
174
+ config = { inputs: fieldsView(node.inputDefinitions), ...(node.kind == 'wait' && node.autoContinue != null ? { autoContinue: node.autoContinue } : {}) }
175
+ texts.prompt = node.prompt
176
+ break
177
+ case 'webhook-response':
178
+ case 'manual':
179
+ config = {}
180
+ break
181
+ case 'start':
182
+ case 'webhook':
183
+ case 'cron':
184
+ case 'error':
185
+ case 'poll':
186
+ case 'integration':
187
+ config = triggerConfiguration(node)
188
+ break
189
+ }
190
+ }
191
+ const edges = authoringEdges(content.document.graph.edges)
192
+ return {
193
+ ref,
194
+ type,
195
+ name: node.name ?? ref,
196
+ readOnly: false,
197
+ ...(node.description == null ? {} : { description: node.description }),
198
+ ...(node.icon == null ? {} : { icon: node.icon }),
199
+ ...('timeoutMs' in node && node.timeoutMs != null ? { timeoutMs: node.timeoutMs } : {}),
200
+ ...('maxExecutions' in node && node.maxExecutions != null ? { maxExecutions: node.maxExecutions } : {}),
201
+ ...(node.onError == null ? {} : { onError: node.onError }),
202
+ ...('retry' in node && node.retry != null ? { retry: node.retry } : {}),
203
+ config: json(config),
204
+ texts: Object.fromEntries(Object.entries(texts).map(([field, text]) => [field, { lines: text.split('\n').length, characters: text.length }])),
205
+ inputs: outwardSource(content, inputMappings(node)),
206
+ inputPorts: fieldsView(Object.entries(inputDefinitions(node)).map(([handle, port]) => Object.assign({}, port, { handle }))),
207
+ ...(Object.keys(nodeSystemOutputPorts(node)).length == 0
208
+ ? {}
209
+ : { systemOutputs: fieldsView(Object.entries(nodeSystemOutputPorts(node)).map(([handle, port]) => Object.assign({ handle }, port))) }),
210
+ outputPorts: fieldsView(Object.entries(nodeOutputPorts(node)).map(([handle, port]) => Object.assign({}, port, { handle }))),
211
+ ...(task != null && 'executor' in task && task.executor.kind == 'openapi' ? { authenticationChoices: openApiAuthenticationChoices(task.executor) } : {}),
212
+ incoming: edges.filter((e) => e.target == ref),
213
+ outgoing: edges.filter((e) => e.source == ref),
214
+ }
215
+ }
216
+ function textAt(content: RevisionContent, node: GraphNode, field: 'code' | 'prompt'): string {
217
+ if (field == 'code' && node.kind == 'task' && 'moduleId' in node.task)
218
+ return content.modules[node.task.moduleId]?.source ?? fail('text.missing', 'Node source is missing.')
219
+ const task = taskAt(node)
220
+ if (field == 'prompt' && task != null && 'executor' in task && task.executor.kind == 'agent') return task.executor.prompt
221
+ if (field == 'prompt' && (node.kind == 'wait' || node.kind == 'approval')) return node.prompt
222
+ return fail('text.unsupported', `This node has no ${field} field.`)
223
+ }
224
+ export function readAuthoring(content: RevisionContent, query: AuthoringRead = {}) {
225
+ const q = authoringReadSchema.parse(query)
226
+ if (q.text != null) {
227
+ const node = nodeAt(content, q.text.node),
228
+ source = textAt(content, node, q.text.field),
229
+ lines = source.split('\n')
230
+ const selected = lines.slice(q.text.start - 1, q.text.start - 1 + q.text.lines)
231
+ // Bound by characters as well as lines; never present a partial line as complete.
232
+ let count = 0,
233
+ characters = 0
234
+ for (const line of selected) {
235
+ if (characters + line.length + 1 > 24000) break
236
+ characters += line.length + 1
237
+ count++
238
+ }
239
+ if (count == 0 && selected.length > 0)
240
+ fail('text.line-too-large', 'Selected line exceeds 24000 characters; use search to locate a smaller edit.', { node: q.text.node, field: q.text.field })
241
+ const end = q.text.start - 1 + count
242
+ return {
243
+ text: {
244
+ ...q.text,
245
+ content: selected.slice(0, count).join('\n'),
246
+ totalLines: lines.length,
247
+ ...(end < lines.length ? { nextStart: end + 1 } : {}),
248
+ truncated: end < lines.length,
249
+ },
250
+ }
251
+ }
252
+ if (q.nodes != null) return { nodes: q.nodes.map((ref) => authoringNode(content, ref)) }
253
+ return {
254
+ nodes: Object.keys(content.document.graph.nodes).map((ref) => {
255
+ const node = authoringNode(content, ref)
256
+ return {
257
+ ref,
258
+ type: node.type,
259
+ name: node.name,
260
+ readOnly: node.readOnly,
261
+ inputHandles: Object.keys(node.inputPorts),
262
+ outputHandles: Object.keys(node.outputPorts),
263
+ inputs: compactValue(node.inputs),
264
+ texts: node.texts,
265
+ }
266
+ }),
267
+ edges: authoringEdges(content.document.graph.edges),
268
+ }
269
+ }
270
+ function compactValue(value: unknown, depth = 0): unknown {
271
+ if (depth >= 4 && value != null && typeof value == 'object') return { truncated: true }
272
+ if (typeof value == 'string') return value.length > 160 ? { preview: value.slice(0, 160), truncated: true } : value
273
+ if (Array.isArray(value))
274
+ return value.length > 8
275
+ ? { preview: value.slice(0, 8).map((v) => compactValue(v, depth + 1)), truncated: true }
276
+ : value.map((v) => compactValue(v, depth + 1))
277
+ if (value != null && typeof value == 'object')
278
+ return Object.fromEntries([
279
+ ...Object.entries(value)
280
+ .slice(0, 8)
281
+ .map(([key, v]) => [key, compactValue(v, depth + 1)]),
282
+ ...(Object.keys(value).length > 8 ? [['truncated', true]] : []),
283
+ ])
284
+ return value
285
+ }
286
+ export function searchAuthoring(content: RevisionContent, query: AuthoringSearch) {
287
+ const q = authoringSearchSchema.parse(query),
288
+ needle = q.query.toLowerCase()
289
+ const matches: { node?: string; field: string; line?: number; excerpt: string }[] = []
290
+ for (const [ref, node] of Object.entries(content.document.graph.nodes)) {
291
+ const view = authoringNode(content, ref)
292
+ if (q.type != null && q.type != view.type) continue
293
+ const fields = {
294
+ name: view.name,
295
+ description: view.description ?? '',
296
+ onError: view.onError ?? '',
297
+ retry: JSON.stringify(view.retry ?? {}),
298
+ inputs: JSON.stringify(view.inputs),
299
+ config: JSON.stringify(view.config),
300
+ ...Object.fromEntries(Object.keys(view.texts).map((field) => [field, textAt(content, node, field as 'code' | 'prompt')])),
301
+ }
302
+ for (const [field, value] of Object.entries(fields)) {
303
+ for (const [index, line] of value.split('\n').entries()) {
304
+ const at = line.toLowerCase().indexOf(needle)
305
+ if (at >= 0) matches.push({ node: ref, field, line: index + 1, excerpt: line.slice(Math.max(0, at - 100), at + Math.max(needle.length, 100)) })
306
+ }
307
+ }
308
+ }
309
+ const end = q.offset + q.limit
310
+ return { matches: matches.slice(q.offset, end), total: matches.length, ...(end < matches.length ? { nextOffset: end } : {}) }
311
+ }
312
+
313
+ export interface AuthoringHost {
314
+ workflow?(flowId: string): Promise<WorkflowContract | WorkflowCandidate>
315
+ id(label: string): string
316
+ action(id: string): Promise<ConnectorAction>
317
+ trigger(key: string): TriggerKeySnapshot
318
+ openapi(url: string): Promise<JsonValue>
319
+ }
320
+ function merge(base: unknown, patch: unknown): unknown {
321
+ if (patch == null || typeof patch != 'object' || Array.isArray(patch)) return patch
322
+ const result = { ...record(base) }
323
+ for (const [key, value] of Object.entries(patch)) {
324
+ if (['__proto__', 'constructor', 'prototype'].includes(key)) fail('edit.invalid-field', `Invalid field ${key}.`)
325
+ Object.defineProperty(result, key, { value: merge(result[key], value), enumerable: true, writable: true, configurable: true })
326
+ }
327
+ return result
328
+ }
329
+ function clearPath(value: Record<string, unknown>, path: readonly string[]) {
330
+ let current = value
331
+ for (const part of path.slice(0, -1)) {
332
+ if (!Object.hasOwn(current, part) || Array.isArray(current[part]) || current[part] == null || typeof current[part] != 'object')
333
+ fail('edit.invalid-field', `Cannot clear ${path.join('.')}.`)
334
+ current = record(current[part])
335
+ }
336
+ const last = path.at(-1)!
337
+ if (!Object.hasOwn(current, last)) fail('edit.invalid-field', `Cannot clear absent field ${path.join('.')}.`)
338
+ delete current[last]
339
+ }
340
+ export async function compileAuthoring(base: RevisionContent, request: AuthoringRequest, host: AuthoringHost) {
341
+ const parsed = authoringRequestSchema.parse(request)
342
+ const upgraded = upgradeRevisionContent(base)
343
+ let content = upgraded,
344
+ index = 0,
345
+ sequence = 0
346
+ const operations: ChangeOperation[] = [],
347
+ aliases: Record<string, string> = {}
348
+ const touchedModules = new Set<string>()
349
+ const explicitMessages = new Set<string>()
350
+ function fresh(label: string) {
351
+ return host.id(`${index}:${label}:${sequence++}`)
352
+ }
353
+ function apply(changes: readonly ChangeOperation[]) {
354
+ const checked = decodeChangeOperations(changes)
355
+ content = applyFlowChanges(content, checked)
356
+ operations.push(...checked)
357
+ }
358
+ function resolve(ref: string) {
359
+ return ref.startsWith('$')
360
+ ? ((Object.hasOwn(aliases, ref.slice(1)) ? aliases[ref.slice(1)] : undefined) ?? fail('node.alias-missing', `Unknown alias ${ref}.`))
361
+ : ref
362
+ }
363
+ function source(
364
+ value: Exclude<AuthoringSource, { kind: 'value' | 'default' | 'unset' | 'sources' }>,
365
+ ): Extract<InputMapping, { kind: 'sources' }>['sources'][number] {
366
+ if (value.kind == 'output' || value.kind == 'system') {
367
+ const ref = resolve(value.node)
368
+ const choices = Object.keys(nodeOutputPorts(nodeAt(content, ref)))
369
+ const port = value.port ?? (choices.length == 1 ? choices[0] : undefined)
370
+ if (port == null) fail('source.port-required', 'Choose an output name; this node does not have exactly one output.', { node: ref, choices })
371
+ return {
372
+ kind: 'node',
373
+ ...(value.kind == 'system' ? { system: true as const } : {}),
374
+ nodeId: ref,
375
+ output: port,
376
+ ...(value.field == null ? {} : { field: value.field }),
377
+ }
378
+ }
379
+ const existing = Object.entries(content.document.bindings).find(([, binding]) => binding.target == value.name)
380
+ const bindingId = existing?.[0] ?? fresh('binding')
381
+ if (existing == null) apply([{ kind: 'binding.create', bindingId, binding: { kind: 'variable', target: value.name } }])
382
+ return { kind: 'binding', bindingId }
383
+ }
384
+ function replace(ref: string, node: GraphNode) {
385
+ const before = nodeAt(content, ref)
386
+ if (!dequal(before, node)) {
387
+ const previous = before.kind == 'task' ? before.task.outputs : before.kind == 'value' ? before.values : []
388
+ const next = node.kind == 'task' ? node.task.outputs : node.kind == 'value' ? node.values : []
389
+ apply([
390
+ { kind: 'graph.node.replace', nodeId: ref, before, node },
391
+ ...(node.kind == 'task' && 'executor' in node.task && node.task.executor.kind == 'workflow'
392
+ ? []
393
+ : renameFlowOutputSources(content, new Set([ref]), previous, next)),
394
+ ])
395
+ }
396
+ }
397
+ function taskNode(ref: string, task: ManagedTaskDefinition) {
398
+ const node = nodeAt(content, ref)
399
+ if (node.kind != 'task' || !('executor' in node.task)) fail('node.invalid-type', 'Expected a managed node.')
400
+ replace(ref, { ...node, task })
401
+ }
402
+
403
+ async function connectorTask(config: Record<string, unknown>, name: string): Promise<ManagedTaskDefinition> {
404
+ const action = await host.action(String(config.action))
405
+ return {
406
+ name,
407
+ executor: {
408
+ kind: 'connector',
409
+ action: action.actionId,
410
+ ...(config.connectionId == null ? {} : { connectionId: String(config.connectionId) }),
411
+ ...(action.outputSchema !== undefined && connectorOutputMode(action.outputSchema) == 'value' ? { outputMode: 'value' as const } : {}),
412
+ },
413
+ inputs: Object.entries(action.inputs).map(([handle, port]) => Object.assign({ handle }, port)),
414
+ outputs: Object.entries(action.outputs).map(([handle, port]) => Object.assign({ handle }, port)),
415
+ }
416
+ }
417
+ async function workflowTarget(flowId: string) {
418
+ if (host.workflow == null) fail('workflow.unavailable', 'Workflow calls are unavailable.')
419
+ return host.workflow(flowId)
420
+ }
421
+ async function resolveWorkflow(flowId: string, name: string, previous?: ManagedTaskDefinition) {
422
+ const target = await workflowTarget(flowId)
423
+ return 'inputs' in target ? workflowTask(target, name) : workflowSelectionTask({ ...target, name }, undefined, previous)
424
+ }
425
+ async function configure(ref: string, patch: Record<string, unknown> = {}, clear: readonly (readonly string[])[] = []) {
426
+ const node = nodeAt(content, ref),
427
+ view = authoringNode(content, ref),
428
+ type = view.type as AuthoringType
429
+ const original = {
430
+ name: view.name,
431
+ ...(view.description == null ? {} : { description: view.description }),
432
+ ...(view.icon == null ? {} : { icon: view.icon }),
433
+ ...(view.timeoutMs == null ? {} : { timeoutMs: view.timeoutMs }),
434
+ ...(view.maxExecutions == null ? {} : { maxExecutions: view.maxExecutions }),
435
+ ...(view.onError == null ? {} : { onError: view.onError }),
436
+ ...(view.retry == null ? {} : { retry: view.retry }),
437
+ config: view.config,
438
+ }
439
+ const update = record(merge(original, patch))
440
+ const explicit = (key: string) => Object.hasOwn(record(patch.config), key) || clear.some((path) => path[0] == 'config' && path[1] == key)
441
+ if (type == 'wait') {
442
+ const timing = record(record(patch.config).autoContinue)
443
+ if (Object.hasOwn(timing, 'kind') && timing.kind != record(record(view.config).autoContinue).kind) record(update.config).autoContinue = timing
444
+ }
445
+ if (type == 'openapi' && Object.hasOwn(record(patch.config), 'authentication')) record(update.config).authentication = record(patch.config).authentication
446
+ for (const path of clear) clearPath(update, path)
447
+ if (typeof update.name != 'string') fail('node.name-required', 'Node name cannot be cleared.')
448
+ const config = authoringConfigurations[type].parse(update.config) as Record<string, unknown>
449
+ if (Object.hasOwn(update, 'retry')) update.retry = retryConfigurationSchema.parse(update.retry)
450
+ const { config: _, ...metadata } = update
451
+ const { name: _name, description: _description, icon: _icon, ...rest } = node
452
+ let next = { ...rest, ...metadata } as GraphNode
453
+ if (!isTriggerNode(node)) {
454
+ const clean = { ...next } as Record<string, unknown>
455
+ if (!Object.hasOwn(update, 'onError')) delete clean.onError
456
+ if (!Object.hasOwn(update, 'retry')) delete clean.retry
457
+ if (!Object.hasOwn(update, 'timeoutMs')) delete clean.timeoutMs
458
+ if (!Object.hasOwn(update, 'maxExecutions')) delete clean.maxExecutions
459
+ next = clean as unknown as GraphNode
460
+ } else if (update.timeoutMs != null || update.maxExecutions != null) fail('node.invalid-field', 'Trigger nodes do not have execution limits.')
461
+ if (update.onError != null && (!supportsNodeErrorHandling(next) || !['stop', 'error'].includes(String(update.onError))))
462
+ fail('node.invalid-field', 'This node does not support this error handling setting.')
463
+ if (update.retry != null && !supportsNodeRetry(next)) fail('node.invalid-field', 'This node does not support retries.')
464
+ if (node.kind == 'start' || node.kind == 'outputs') {
465
+ replace(ref, next)
466
+ const fields = node.kind == 'start' ? config.inputDefs : config.outputDefs
467
+ const ports = fieldsToPorts(fields, node.kind == 'start' ? node.inputDefs : node.outputDefs).filter((port): port is InputPort => 'handle' in port)
468
+ const changes = node.kind == 'start' ? updateStartInputDefs(content, ref, ports) : updateOutputsDefs(content, ref, ports)
469
+ if (changes.length > 0) apply(changes)
470
+ return
471
+ }
472
+ function taskInputs(task: ManagedTaskDefinition | NonNullable<Extract<GraphNode, { kind: 'task' }>['task']>, reserved: readonly string[] = []) {
473
+ if (node.kind != 'task') throw new Error('Expected a task.')
474
+ const fields = record(config.inputs)
475
+ for (const key of reserved)
476
+ if (Object.hasOwn(fields, key)) fail('input.reserved', `Configure ${key} through config.${key} or input.set.`, { node: ref, input: key })
477
+ const extraNames = new Set(node.additionalInputs?.map((port) => port.handle) ?? [])
478
+ const main = Object.fromEntries(Object.entries(fields).filter(([key]) => !extraNames.has(key)))
479
+ for (const port of task.inputs)
480
+ if ('handle' in port && (reserved.includes(port.handle) || (extraNames.has(port.handle) && Object.hasOwn(fields, port.handle))))
481
+ main[port.handle] = fieldsView([port])[port.handle]
482
+ if (node.additionalInputs != null) {
483
+ const extra = Object.fromEntries(Object.entries(fields).filter(([key]) => extraNames.has(key)))
484
+ for (const port of node.additionalInputs) if (reserved.includes(port.handle)) extra[port.handle] = fieldsView([port])[port.handle]
485
+ next = { ...next, additionalInputs: fieldsToPorts(extra, node.additionalInputs) as readonly InputPort[] } as GraphNode
486
+ }
487
+ return fieldsToPorts(main, task.inputs)
488
+ }
489
+ if (node.kind == 'task' && 'moduleId' in node.task) {
490
+ const inputs = taskInputs(node.task)
491
+ next = {
492
+ ...next,
493
+ task: {
494
+ moduleId: node.task.moduleId,
495
+ name: String(update.name),
496
+ ...config,
497
+ ...(config.capabilities == null
498
+ ? {}
499
+ : { capabilities: await prepareCapabilities(config.capabilities as readonly AuthoringCapability[], node.task.capabilities ?? [], workflowTarget) }),
500
+ inputs,
501
+ outputs: fieldsToPorts(config.outputs, node.task.outputs),
502
+ },
503
+ } as GraphNode
504
+ } else if (node.kind == 'task' && 'executor' in node.task) {
505
+ const before = node.task
506
+ let task: ManagedTaskDefinition
507
+ if (type == 'workflow') {
508
+ task =
509
+ before.executor.kind == 'workflow' && before.executor.flowId == config.flowId
510
+ ? { ...before, name: String(update.name) }
511
+ : await resolveWorkflow(String(config.flowId), String(update.name))
512
+ next = withWorkflowTask({ ...node, ...metadata } as typeof node, task)
513
+ } else if (type == 'connector') {
514
+ if (before.executor.kind == 'connector' && config.action == before.executor.action) {
515
+ const { connectionId: _connectionId, ...executor } = before.executor
516
+ task = { ...before, name: String(update.name), executor: { ...executor, ...config } } as ManagedTaskDefinition
517
+ } else task = await connectorTask(config, String(update.name))
518
+ } else if (type == 'decision') task = decisionTask(config.questions as Parameters<typeof decisionTask>[0], String(update.name))
519
+ else if (type == 'openapi') {
520
+ task = await prepareOpenApiTask(config as AuthoringOpenApiConfig, before, (url) => host.openapi(url), String(update.name), {
521
+ authentication: explicit('authentication'),
522
+ serverUrl: explicit('serverUrl'),
523
+ })
524
+ } else if (type == 'llm') {
525
+ task = prepareLlmConfiguration(config, before, String(update.name))
526
+ task = { ...task, inputs: taskInputs(task, llmReservedInputs) }
527
+ } else {
528
+ const { inputs: _inputs, resultSchema, notification, tools, ...executor } = config
529
+ const prepared = { ...executor, kind: type, ...(before.executor.kind == 'agent' ? { prompt: before.executor.prompt } : {}) }
530
+ if (type == 'agent') {
531
+ const previous = before.executor.kind == 'agent' ? before.executor : undefined
532
+ Object.assign(prepared, {
533
+ tools: await prepareAgentTools(
534
+ tools as AuthoringAgentTool[],
535
+ previous?.tools ?? [],
536
+ (id) => host.action(id),
537
+ () => fresh('tool'),
538
+ workflowTarget,
539
+ ),
540
+ })
541
+ Reflect.deleteProperty(prepared, 'notification')
542
+ if (notification != null) {
543
+ if (dequal(record(view.config).notification, notification) && previous?.notification != null)
544
+ Object.assign(prepared, { notification: previous.notification })
545
+ else {
546
+ const settings = record(notification)
547
+ const definition = await connectorTask(settings, `${update.name} notification`)
548
+ Object.assign(prepared, {
549
+ notification: {
550
+ action: settings.action,
551
+ ...(settings.connectionId == null ? {} : { connectionId: settings.connectionId }),
552
+ inputDefinitions: definition.inputs,
553
+ messageHandle: settings.messageHandle,
554
+ inputs: settings.inputs,
555
+ },
556
+ })
557
+ }
558
+ }
559
+ }
560
+ const outputs = dequal(record(view.config).resultSchema, resultSchema)
561
+ ? before.outputs
562
+ : before.outputs.map((port) => ('handle' in port ? { ...port, jsonSchema: resultSchema as JsonValue } : port))
563
+ task = {
564
+ name: String(update.name),
565
+ inputs: type == 'agent' ? taskInputs(before) : before.inputs,
566
+ outputs,
567
+ executor: prepared,
568
+ } as ManagedTaskDefinition
569
+ }
570
+ next = { ...next, task } as GraphNode
571
+ } else
572
+ switch (node.kind) {
573
+ case 'condition':
574
+ next = { ...next, ...prepareConditionConfiguration(config as unknown as AuthoringConditionConfiguration, source) } as GraphNode
575
+ break
576
+ case 'value': {
577
+ const fields = { ...record(config.outputs) }
578
+ for (const key of Object.keys(record(config.values))) if (!Object.hasOwn(fields, key)) fields[key] = {}
579
+ const values = fieldsToPorts(
580
+ fields,
581
+ node.values.map(({ value: _value, ...port }) => port),
582
+ )
583
+ .filter((port): port is InputPort => 'handle' in port)
584
+ .map((port) => Object.assign({}, port, Object.hasOwn(record(config.values), port.handle) ? { value: record(config.values)[port.handle] } : {}))
585
+ next = { ...next, values } as GraphNode
586
+ break
587
+ }
588
+ case 'wait':
589
+ case 'approval':
590
+ next = { ...next, inputDefinitions: fieldsToPorts(config.inputs, node.inputDefinitions) } as GraphNode
591
+ if (node.kind == 'wait') {
592
+ Reflect.deleteProperty(next, 'autoContinue')
593
+ if (config.autoContinue != null) Object.assign(next, { autoContinue: config.autoContinue })
594
+ }
595
+ break
596
+ case 'webhook': {
597
+ const { body, ...settings } = config
598
+ const responseOptions = record(settings.options)
599
+ const responsePolicy = record(responseOptions.responseBody)
600
+ if (responsePolicy.kind === 'webhook-response' && typeof responsePolicy.nodeId === 'string')
601
+ settings.options = { ...responseOptions, responseBody: { ...responsePolicy, nodeId: resolve(responsePolicy.nodeId) } }
602
+ const { options: _options, ...withoutOptions } = next as Extract<GraphNode, { kind: 'webhook' }>
603
+ next = { ...withoutOptions, ...settings, bodyFields: fieldsToPorts(body, node.bodyFields) } as GraphNode
604
+ break
605
+ }
606
+ case 'cron':
607
+ next = { ...next, cronTimes: config.schedule } as GraphNode
608
+ break
609
+ case 'poll':
610
+ case 'integration': {
611
+ if (config.key != node.definition.key) fail('trigger.key-immutable', 'Create a new node to change its Trigger type.')
612
+ const { connectionId: _connection, ...withoutConnection } = next as Extract<GraphNode, { kind: 'poll' | 'integration' }>
613
+ next = {
614
+ ...withoutConnection,
615
+ ...(config.connectionId == null ? {} : { connectionId: config.connectionId }),
616
+ ...(node.kind == 'poll' ? { pollTimes: config.schedule } : {}),
617
+ } as GraphNode
618
+ break
619
+ }
620
+ default: {
621
+ const fields = { ...next } as Record<string, unknown>
622
+ for (const key of Object.keys(record(view.config))) delete fields[key]
623
+ next = { ...fields, ...config } as unknown as GraphNode
624
+ }
625
+ }
626
+ replace(ref, next)
627
+ }
628
+ async function setText(ref: string, field: 'code' | 'prompt', text: string) {
629
+ const node = nodeAt(content, ref),
630
+ before = textAt(content, node, field)
631
+ if (before == text) return
632
+ if (field == 'code' && node.kind == 'task' && 'moduleId' in node.task) {
633
+ const moduleId = node.task.moduleId,
634
+ module = content.modules[moduleId]!
635
+ const shared =
636
+ Object.values(content.document.graph.nodes).some((n) => n.kind == 'task' && 'moduleId' in n.task && n.task.moduleId == moduleId && n !== node) ||
637
+ Object.values(content.modules).some((m) => m.imports.includes(moduleId))
638
+ const imports = await moduleImports(text)
639
+ if (shared) {
640
+ const id = fresh('module')
641
+ apply([{ kind: 'module.create', moduleId: id, module: { ...module, source: text, imports } }])
642
+ replace(ref, { ...node, task: { ...node.task, moduleId: id } })
643
+ } else apply([{ kind: 'module.source.replace', moduleId, beforeSource: before, beforeImports: module.imports, source: text, imports }])
644
+ } else if (node.kind == 'task' && 'executor' in node.task) {
645
+ const task = node.task
646
+ taskNode(ref, { ...task, executor: { ...task.executor, prompt: text } } as ManagedTaskDefinition)
647
+ } else if (node.kind == 'wait' || node.kind == 'approval') replace(ref, { ...node, prompt: text })
648
+ }
649
+ async function setInput(ref: string, input: string, value: AuthoringSource) {
650
+ if (input == 'message') explicitMessages.add(ref)
651
+ const node = nodeAt(content, ref)
652
+ if (node.kind == 'condition')
653
+ fail('input.unsupported', 'Edit the branch condition operands through config.branches.', { node: ref, field: 'config.branches' })
654
+ if (node.kind == 'poll' || node.kind == 'integration') {
655
+ if (!Object.hasOwn(inputDefinitions(node), input))
656
+ fail('input.not-found', `Unknown input ${input}.`, { node: ref, input, choices: Object.keys(inputDefinitions(node)) })
657
+ if (value.kind != 'value' && value.kind != 'unset' && value.kind != 'default')
658
+ fail('input.source-unsupported', 'Trigger parameters accept only value, unset or default; they cannot depend on execution outputs or variables.', {
659
+ node: ref,
660
+ input,
661
+ allowed: ['value', 'unset', 'default'],
662
+ })
663
+ const config = { ...node.config }
664
+ if (value.kind == 'default') delete config[input]
665
+ else config[input] = value
666
+ replace(ref, { ...node, config })
667
+ return
668
+ }
669
+ if (!Object.hasOwn(inputDefinitions(node), input)) {
670
+ const type = typeOf(node)
671
+ if (!['agent', 'code', 'llm', 'wait', 'approval'].includes(type))
672
+ fail('input.not-found', `Unknown input ${input}.`, { node: ref, input, choices: Object.keys(inputDefinitions(node)) })
673
+ if (type == 'llm' && llmReservedInputs.includes(input))
674
+ fail('input.not-found', `Missing built-in LLM input ${input}.`, { node: ref, input, choices: Object.keys(inputDefinitions(node)) })
675
+ await configure(ref, { config: { inputs: { [input]: {} } } })
676
+ }
677
+ const mapping: InputMapping | undefined =
678
+ value.kind == 'default'
679
+ ? undefined
680
+ : value.kind == 'value' || value.kind == 'unset'
681
+ ? value
682
+ : { kind: 'sources', sources: (value.kind == 'sources' ? value.sources : [value]).map(source) }
683
+ const before = nodeInputMappings(nodeAt(content, ref))[input]
684
+ if (!dequal(before, mapping)) apply([{ kind: 'graph.node.input.set', nodeId: ref, handle: input, before, ...(mapping == null ? {} : { value: mapping }) }])
685
+ }
686
+ for (const edit of parsed.edits) {
687
+ try {
688
+ switch (edit.op) {
689
+ case 'node.refresh': {
690
+ const ref = resolve(edit.node)
691
+ const node = nodeAt(content, ref)
692
+ if (node.kind != 'task') fail('node.invalid-type', 'Only workflow nodes and tools support refresh.')
693
+ if (edit.tool != null) {
694
+ if ('moduleId' in node.task) {
695
+ const selected = node.task.capabilities?.find((item) => item.kind == 'workflow' && item.name == edit.tool)
696
+ if (selected?.kind != 'workflow') fail('tool.not-found', 'Workflow tool was not found.')
697
+ const target = await workflowTarget(selected.flowId)
698
+ if (!('inputs' in target)) fail('workflow.unavailable', 'The workflow interface is unavailable.')
699
+ replace(ref, {
700
+ ...node,
701
+ task: {
702
+ ...node.task,
703
+ capabilities: node.task.capabilities!.map((item) => (item === selected ? workflowCapability(selected.name, target) : item)),
704
+ },
705
+ })
706
+ } else if (node.task.executor.kind == 'agent') {
707
+ const selected = node.task.executor.tools.find((item) => item.kind == 'workflow' && item.name == edit.tool)
708
+ if (selected?.kind != 'workflow') fail('tool.not-found', 'Workflow tool was not found.')
709
+ const target = await workflowTarget(selected.flowId)
710
+ if (!('inputs' in target)) fail('workflow.unavailable', 'The workflow interface is unavailable.')
711
+ replace(ref, {
712
+ ...node,
713
+ task: {
714
+ ...node.task,
715
+ executor: {
716
+ ...node.task.executor,
717
+ tools: node.task.executor.tools.map((item) => (item === selected ? workflowAgentTool(selected.id, selected.name, target, selected) : item)),
718
+ },
719
+ },
720
+ })
721
+ } else fail('node.invalid-type', 'Only Agent and Code nodes have workflow tools.')
722
+ } else {
723
+ if (!('executor' in node.task) || node.task.executor.kind != 'workflow') fail('node.invalid-type', 'Specify a workflow tool name.')
724
+ const task = await resolveWorkflow(node.task.executor.flowId, node.name ?? node.task.name, node.task)
725
+ apply([{ kind: 'graph.node.replace', nodeId: ref, before: node, node: withWorkflowTask(node, task) }])
726
+ }
727
+ break
728
+ }
729
+ case 'node.add': {
730
+ if (Object.hasOwn(aliases, edit.as)) fail('node.alias-duplicate', `Duplicate alias ${edit.as}.`)
731
+ const nodeId = host.id(`node:${edit.as}`),
732
+ identity = { nodeId, moduleId: fresh('module') },
733
+ name = edit.name
734
+ aliases[edit.as] = nodeId
735
+ const config = edit.config ?? {}
736
+ let changes: readonly ChangeOperation[]
737
+ switch (edit.type) {
738
+ case 'workflow':
739
+ changes = createManagedTask(identity, await resolveWorkflow(String(authoringConfigurations.workflow.parse(config).flowId), name))
740
+ break
741
+ case 'webhook-response':
742
+ changes = [{ kind: 'graph.node.create', nodeId, node: { kind: 'webhook-response', name, inputs: {} } }]
743
+ break
744
+ case 'outputs':
745
+ changes = [{ kind: 'graph.node.create', nodeId, node: { outputDefs: [], outputMappings: {}, kind: 'outputs', name } }]
746
+ break
747
+ case 'code':
748
+ changes = createCodeTask(identity, name, undefined, {
749
+ inputs: [],
750
+ outputs: config.outputs == null ? defaultCodeTaskPorts.outputs : [],
751
+ })
752
+ break
753
+ case 'agent':
754
+ changes = createAgentTask(identity, name, { inputs: [], prompt: edit.prompt ?? '' })
755
+ break
756
+ case 'llm':
757
+ changes = createLlmTask(identity, name, 'chat', 'Generated response.').map((change) =>
758
+ change.kind == 'graph.node.create' && change.node.kind == 'task' && 'executor' in change.node.task
759
+ ? Object.assign({}, change, { node: Object.assign({}, change.node, { task: initialAuthoringLlmTask(change.node.task) }) })
760
+ : change,
761
+ )
762
+ break
763
+ case 'decision':
764
+ changes = createDecisionTask(identity, name)
765
+ break
766
+ case 'connector':
767
+ changes = createManagedTask(identity, await connectorTask(config, name))
768
+ break
769
+ case 'openapi':
770
+ changes = createManagedTask(
771
+ identity,
772
+ await prepareOpenApiTask(authoringConfigurations.openapi.parse(config), undefined, (url) => host.openapi(url), name),
773
+ )
774
+ break
775
+ case 'condition':
776
+ changes = createCondition(nodeId, name)
777
+ break
778
+ case 'value':
779
+ changes = createValue(nodeId, name, [])
780
+ break
781
+ case 'wait':
782
+ changes = createWait(nodeId, name)
783
+ break
784
+ case 'approval':
785
+ changes = createApproval(nodeId, name)
786
+ break
787
+ case 'poll':
788
+ case 'integration': {
789
+ const definition = host.trigger(String(config.key))
790
+ if (definition.type != edit.type) fail('trigger.type-mismatch', 'Trigger key has a different type.')
791
+ changes = createProviderTrigger(nodeId, definition, { name, config: {} })
792
+ break
793
+ }
794
+ default:
795
+ changes = [
796
+ {
797
+ kind: 'graph.node.create',
798
+ nodeId,
799
+ node: {
800
+ kind: edit.type,
801
+ name,
802
+ ...(edit.type == 'start' ? { inputDefs: [] } : {}),
803
+ ...(edit.type == 'cron' ? { cronTimes: [{ type: 'every', unit: 'hour', value: 1 }] } : {}),
804
+ ...(edit.type == 'webhook' ? { method: 'POST', bodyFields: [] } : {}),
805
+ } as GraphNode,
806
+ },
807
+ ]
808
+ }
809
+ apply(changes)
810
+ await configure(nodeId, { config, ...(edit.onError == null ? {} : { onError: edit.onError }), ...(edit.retry == null ? {} : { retry: edit.retry }) })
811
+ const added = nodeAt(content, nodeId)
812
+ if (added.kind == 'task') replace(nodeId, { ...added, inputs: {} })
813
+ if (edit.code != null) await setText(nodeId, 'code', edit.code)
814
+ if (edit.prompt != null) await setText(nodeId, 'prompt', edit.prompt)
815
+ for (const [input, binding] of Object.entries(edit.inputs ?? {})) await setInput(nodeId, input, binding)
816
+ break
817
+ }
818
+ case 'node.update':
819
+ await configure(resolve(edit.node), edit.set, edit.clear)
820
+ break
821
+ case 'node.remove': {
822
+ const ref = resolve(edit.node),
823
+ node = nodeAt(content, ref)
824
+ if (node.kind == 'task' && 'moduleId' in node.task) touchedModules.add(node.task.moduleId)
825
+ apply([{ kind: 'graph.node.delete', nodeId: ref }])
826
+ break
827
+ }
828
+ case 'input.set': {
829
+ await setInput(resolve(edit.node), edit.input, edit.source)
830
+ break
831
+ }
832
+ case 'edge.connect':
833
+ case 'edge.disconnect': {
834
+ const from = resolve(edit.source),
835
+ to = resolve(edit.target)
836
+ nodeAt(content, from)
837
+ nodeAt(content, to)
838
+ const edge = { source: from, target: to, ...(edit.branch == null ? {} : { sourceHandle: edit.branch }) }
839
+ const changes = edit.op == 'edge.connect' ? connect(content, edge) : disconnect(content, edge)
840
+ apply(explicitMessages.has(to) ? changes.filter((change) => change.kind != 'graph.node.input.set') : changes)
841
+ break
842
+ }
843
+ case 'text.set':
844
+ await setText(resolve(edit.node), edit.field, edit.text)
845
+ break
846
+ case 'text.edit': {
847
+ const ref = resolve(edit.node),
848
+ value = textAt(content, nodeAt(content, ref), edit.field),
849
+ count = value.split(edit.oldText).length - 1
850
+ if (count != 1)
851
+ fail('text.match-count', `Expected one exact match, found ${count}. Read the field and include more context.`, {
852
+ node: ref,
853
+ field: edit.field,
854
+ matches: count,
855
+ })
856
+ await setText(
857
+ ref,
858
+ edit.field,
859
+ value.replace(edit.oldText, () => edit.newText),
860
+ )
861
+ break
862
+ }
863
+ }
864
+ } catch (error) {
865
+ if (error instanceof AuthoringError || error instanceof AuthoringToolInputError || error instanceof AuthoringOpenApiAuthenticationError)
866
+ throw new AuthoringError(error.code, error.message, { ...error.details, editIndex: index })
867
+ throw new AuthoringError('edit.invalid', error instanceof Error ? error.message : String(error), { editIndex: index })
868
+ }
869
+ index++
870
+ }
871
+ for (const moduleId of touchedModules)
872
+ if (
873
+ !Object.values(content.document.graph.nodes).some((n) => n.kind == 'task' && 'moduleId' in n.task && n.task.moduleId == moduleId) &&
874
+ !Object.values(content.modules).some((m) => m.imports.includes(moduleId))
875
+ )
876
+ apply([{ kind: 'module.delete', moduleId }])
877
+ // Shared binding lifecycle remains owned by the existing authoring implementation.
878
+ const cleaned = cleanVariableBindings(upgraded, operations)
879
+ return { operations: cleaned, content: cleaned.length == 0 ? upgraded : applyFlowChanges(upgraded, cleaned), nodes: aliases }
880
+ }
881
+
882
+ const escapePointer = (value: string) => value.replaceAll('~', '~0').replaceAll('/', '~1')
883
+ export function authoringDiagnostics(content: RevisionContent, diagnostics: readonly Diagnostic[]) {
884
+ const nodes = Object.entries(content.document.graph.nodes)
885
+ return diagnostics.map((diagnostic) => {
886
+ const affected = nodes.filter(([id, node]) => {
887
+ const roots = [`/document/graph/nodes/${escapePointer(id)}`]
888
+ if (node.kind == 'task' && 'moduleId' in node.task) roots.push(`/modules/${escapePointer(node.task.moduleId)}`)
889
+ return roots.some((root) => diagnostic.path == root || diagnostic.path.startsWith(`${root}/`))
890
+ })
891
+ // Diagnostic wording comes from the shared validators; storage identities are replaced at this boundary.
892
+ const message = diagnostic.message
893
+ .replace(/(CodeModule|Managed Task|Task|Binding) "([^"\n]+)"/g, (_, kind: string, id: string) => {
894
+ if (kind == 'Binding') return `Variable "${content.document.bindings[id]?.target ?? 'unresolved'}"`
895
+ const owners = nodes.filter(([, n]) => n.kind == 'task' && kind == 'CodeModule' && 'moduleId' in n.task && n.task.moduleId == id)
896
+ return owners.length
897
+ ? `${kind == 'CodeModule' ? 'Code for' : 'Node'} ${owners.map(([ref, n]) => JSON.stringify(n.name ?? ref)).join(', ')}`
898
+ : kind == 'CodeModule'
899
+ ? 'Referenced code'
900
+ : 'Node configuration'
901
+ })
902
+ .replaceAll('CodeModule', 'Code')
903
+ const parts = diagnostic.path.split('/').map((part) => part.replaceAll('~1', '/').replaceAll('~0', '~'))
904
+ return {
905
+ code: diagnostic.code,
906
+ message,
907
+ nodes: affected.map(([id]) => id),
908
+ field: authoringDiagnosticField(affected[0]?.[1], parts),
909
+ ...(diagnostic.line ? { line: diagnostic.line, column: diagnostic.column } : {}),
910
+ }
911
+ })
912
+ }