@aglyn/plugins-ai 1.0.0-beta.229 → 1.0.0-beta.230

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 (248) hide show
  1. package/README.md +3 -3
  2. package/package.json +17 -17
  3. package/src/lib/activity/ai-activity-actions.js +7 -1
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-automation-zones.d.ts +38 -0
  6. package/src/lib/components/ai-automation-zones.js +5 -1
  7. package/src/lib/components/ai-automation-zones.js.map +1 -1
  8. package/src/lib/components/ai-brief-dialog.component.d.ts +20 -2
  9. package/src/lib/components/ai-brief-dialog.component.js +87 -8
  10. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  11. package/src/lib/components/ai-campaign-create.component.d.ts +54 -0
  12. package/src/lib/components/ai-campaign-create.component.js +270 -0
  13. package/src/lib/components/ai-campaign-create.component.js.map +1 -0
  14. package/src/lib/components/ai-describe-automation.component.d.ts +8 -3
  15. package/src/lib/components/ai-describe-automation.component.js +15 -6
  16. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  17. package/src/lib/components/ai-describe-button.component.d.ts +20 -8
  18. package/src/lib/components/ai-describe-button.component.js +19 -36
  19. package/src/lib/components/ai-describe-button.component.js.map +1 -1
  20. package/src/lib/components/ai-describe-email.component.d.ts +31 -0
  21. package/src/lib/components/ai-describe-email.component.js +22 -0
  22. package/src/lib/components/ai-describe-email.component.js.map +1 -0
  23. package/src/lib/components/ai-describe-org-automation.component.d.ts +36 -0
  24. package/src/lib/components/ai-describe-org-automation.component.js +238 -0
  25. package/src/lib/components/ai-describe-org-automation.component.js.map +1 -0
  26. package/src/lib/components/ai-experiment-cards.component.d.ts +9 -1
  27. package/src/lib/components/ai-experiment-cards.component.js +104 -18
  28. package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
  29. package/src/lib/components/ai-explain-automation.component.js +1 -5
  30. package/src/lib/components/ai-explain-automation.component.js.map +1 -1
  31. package/src/lib/components/ai-funnel-zones.component.d.ts +61 -0
  32. package/src/lib/components/ai-funnel-zones.component.js +178 -0
  33. package/src/lib/components/ai-funnel-zones.component.js.map +1 -0
  34. package/src/lib/components/ai-insight-card.component.d.ts +42 -0
  35. package/src/lib/components/ai-insight-card.component.js +137 -0
  36. package/src/lib/components/ai-insight-card.component.js.map +1 -0
  37. package/src/lib/components/ai-insight-dialog.component.d.ts +6 -0
  38. package/src/lib/components/ai-insight-dialog.component.js +9 -3
  39. package/src/lib/components/ai-insight-dialog.component.js.map +1 -1
  40. package/src/lib/components/ai-job-plan.component.d.ts +7 -2
  41. package/src/lib/components/ai-job-plan.component.js +35 -5
  42. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  43. package/src/lib/components/ai-job-requests.d.ts +17 -1
  44. package/src/lib/components/ai-job-requests.js +39 -3
  45. package/src/lib/components/ai-job-requests.js.map +1 -1
  46. package/src/lib/components/ai-logic-zones.d.ts +64 -0
  47. package/src/lib/components/ai-logic-zones.js +18 -0
  48. package/src/lib/components/ai-logic-zones.js.map +1 -0
  49. package/src/lib/components/ai-logic.component.d.ts +77 -0
  50. package/src/lib/components/ai-logic.component.js +553 -0
  51. package/src/lib/components/ai-logic.component.js.map +1 -0
  52. package/src/lib/components/ai-marketing-insight.component.d.ts +30 -0
  53. package/src/lib/components/ai-marketing-insight.component.js +80 -0
  54. package/src/lib/components/ai-marketing-insight.component.js.map +1 -0
  55. package/src/lib/components/ai-media-create.component.d.ts +55 -0
  56. package/src/lib/components/ai-media-create.component.js +433 -0
  57. package/src/lib/components/ai-media-create.component.js.map +1 -0
  58. package/src/lib/components/ai-overlay-cards.component.d.ts +83 -0
  59. package/src/lib/components/ai-overlay-cards.component.js +505 -0
  60. package/src/lib/components/ai-overlay-cards.component.js.map +1 -0
  61. package/src/lib/components/ai-product-zones.d.ts +5 -0
  62. package/src/lib/components/ai-product-zones.js +1 -1
  63. package/src/lib/components/ai-product-zones.js.map +1 -1
  64. package/src/lib/components/ai-products-create-button.component.d.ts +42 -0
  65. package/src/lib/components/ai-products-create-button.component.js +67 -0
  66. package/src/lib/components/ai-products-create-button.component.js.map +1 -0
  67. package/src/lib/components/ai-products-hub-card.component.js +100 -81
  68. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  69. package/src/lib/components/ai-revise-automation.component.d.ts +16 -0
  70. package/src/lib/components/ai-revise-automation.component.js +207 -0
  71. package/src/lib/components/ai-revise-automation.component.js.map +1 -0
  72. package/src/lib/components/ai-site-build-page.component.js +140 -16
  73. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  74. package/src/lib/components/ai-upsell-dialog.component.d.ts +53 -0
  75. package/src/lib/components/ai-upsell-dialog.component.js +177 -0
  76. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -0
  77. package/src/lib/components/assist-build-card.component.d.ts +42 -0
  78. package/src/lib/components/assist-build-card.component.js +183 -0
  79. package/src/lib/components/assist-build-card.component.js.map +1 -0
  80. package/src/lib/components/assist-edit-canvas.d.ts +2 -0
  81. package/src/lib/components/assist-edit-canvas.js +56 -1
  82. package/src/lib/components/assist-edit-canvas.js.map +1 -1
  83. package/src/lib/components/assist-jobs-drawer.component.js +48 -3
  84. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  85. package/src/lib/components/assist-panel.component.js +51 -2
  86. package/src/lib/components/assist-panel.component.js.map +1 -1
  87. package/src/lib/components/use-ai-job-run.d.ts +3 -14
  88. package/src/lib/components/use-ai-job-run.js +0 -50
  89. package/src/lib/components/use-ai-job-run.js.map +1 -1
  90. package/src/lib/jobs/ai-build-capabilities.d.ts +58 -0
  91. package/src/lib/jobs/ai-build-capabilities.js +256 -0
  92. package/src/lib/jobs/ai-build-capabilities.js.map +1 -0
  93. package/src/lib/jobs/ai-build-unit-outcome.d.ts +52 -0
  94. package/src/lib/jobs/ai-build-unit-outcome.js +138 -0
  95. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -0
  96. package/src/lib/jobs/ai-job-build-step.d.ts +144 -0
  97. package/src/lib/jobs/ai-job-build-step.js +657 -0
  98. package/src/lib/jobs/ai-job-build-step.js.map +1 -0
  99. package/src/lib/jobs/ai-job-draft-ids.js +9 -1
  100. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
  101. package/src/lib/jobs/ai-job-drafts.d.ts +14 -4
  102. package/src/lib/jobs/ai-job-drafts.js +25 -4
  103. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  104. package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
  105. package/src/lib/jobs/ai-job-logic-step.js +395 -0
  106. package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
  107. package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
  108. package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
  109. package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
  110. package/src/lib/jobs/ai-job-page-step.js +6 -6
  111. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  112. package/src/lib/jobs/ai-job-plan-step.d.ts +26 -1
  113. package/src/lib/jobs/ai-job-plan-step.js +79 -11
  114. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  115. package/src/lib/jobs/ai-job-site-step.d.ts +15 -1
  116. package/src/lib/jobs/ai-job-site-step.js +200 -58
  117. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  118. package/src/lib/jobs/ai-job-text-step.d.ts +22 -1
  119. package/src/lib/jobs/ai-job-text-step.js +12 -0
  120. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  121. package/src/lib/jobs/ai-job-workflow-step.d.ts +54 -4
  122. package/src/lib/jobs/ai-job-workflow-step.js +318 -13
  123. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
  124. package/src/lib/jobs/ai-jobs.d.ts +80 -2
  125. package/src/lib/jobs/ai-jobs.js +377 -13
  126. package/src/lib/jobs/ai-jobs.js.map +1 -1
  127. package/src/lib/jobs/ai-logic-records.d.ts +40 -0
  128. package/src/lib/jobs/ai-logic-records.js +55 -0
  129. package/src/lib/jobs/ai-logic-records.js.map +1 -0
  130. package/src/lib/jobs/ai-site-publish.d.ts +7 -0
  131. package/src/lib/jobs/ai-site-publish.js +9 -0
  132. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  133. package/src/lib/jobs/ai-workflow-records.d.ts +4 -0
  134. package/src/lib/jobs/ai-workflow-records.js +40 -1
  135. package/src/lib/jobs/ai-workflow-records.js.map +1 -1
  136. package/src/lib/model/ai-automation-draft.d.ts +18 -0
  137. package/src/lib/model/ai-automation-draft.js +86 -0
  138. package/src/lib/model/ai-automation-draft.js.map +1 -1
  139. package/src/lib/model/ai-build-job.d.ts +201 -0
  140. package/src/lib/model/ai-build-job.js +471 -0
  141. package/src/lib/model/ai-build-job.js.map +1 -0
  142. package/src/lib/model/ai-build-plan.d.ts +61 -0
  143. package/src/lib/model/ai-build-plan.js +154 -9
  144. package/src/lib/model/ai-build-plan.js.map +1 -1
  145. package/src/lib/model/ai-build-progress.d.ts +56 -0
  146. package/src/lib/model/ai-build-progress.js +128 -0
  147. package/src/lib/model/ai-build-progress.js.map +1 -0
  148. package/src/lib/model/ai-insight.d.ts +20 -10
  149. package/src/lib/model/ai-insight.js +72 -9
  150. package/src/lib/model/ai-insight.js.map +1 -1
  151. package/src/lib/model/ai-job-activity.js +3 -1
  152. package/src/lib/model/ai-job-activity.js.map +1 -1
  153. package/src/lib/model/ai-jobs.types.d.ts +80 -2
  154. package/src/lib/model/ai-jobs.types.js +3 -1
  155. package/src/lib/model/ai-jobs.types.js.map +1 -1
  156. package/src/lib/model/ai-logic-job.d.ts +108 -0
  157. package/src/lib/model/ai-logic-job.js +327 -0
  158. package/src/lib/model/ai-logic-job.js.map +1 -0
  159. package/src/lib/model/ai-media-credits.d.ts +52 -0
  160. package/src/lib/model/ai-media-credits.js +61 -0
  161. package/src/lib/model/ai-media-credits.js.map +1 -0
  162. package/src/lib/model/ai-overlay-copy.d.ts +114 -0
  163. package/src/lib/model/ai-overlay-copy.js +175 -0
  164. package/src/lib/model/ai-overlay-copy.js.map +1 -0
  165. package/src/lib/model/ai-site-build-progress.d.ts +20 -3
  166. package/src/lib/model/ai-site-build-progress.js +170 -10
  167. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  168. package/src/lib/model/ai-svg.d.ts +69 -0
  169. package/src/lib/model/ai-svg.js +265 -0
  170. package/src/lib/model/ai-svg.js.map +1 -0
  171. package/src/lib/model/ai-usage-by-user.d.ts +3 -2
  172. package/src/lib/model/ai-usage-by-user.js.map +1 -1
  173. package/src/lib/model/ai-workflow-job.d.ts +92 -4
  174. package/src/lib/model/ai-workflow-job.js +124 -7
  175. package/src/lib/model/ai-workflow-job.js.map +1 -1
  176. package/src/lib/model/assist-build.d.ts +58 -0
  177. package/src/lib/model/assist-build.js +52 -0
  178. package/src/lib/model/assist-build.js.map +1 -0
  179. package/src/lib/model/assist-edit.d.ts +48 -3
  180. package/src/lib/model/assist-edit.js +48 -4
  181. package/src/lib/model/assist-edit.js.map +1 -1
  182. package/src/lib/plugin-config.js +2 -0
  183. package/src/lib/plugin-config.js.map +1 -1
  184. package/src/lib/plugin.js +240 -11
  185. package/src/lib/plugin.js.map +1 -1
  186. package/src/lib/providers/catalog.d.ts +81 -4
  187. package/src/lib/providers/catalog.js +80 -9
  188. package/src/lib/providers/catalog.js.map +1 -1
  189. package/src/lib/providers/image-contract.d.ts +116 -0
  190. package/src/lib/providers/image-contract.js +74 -0
  191. package/src/lib/providers/image-contract.js.map +1 -0
  192. package/src/lib/providers/model-choice.js +11 -0
  193. package/src/lib/providers/model-choice.js.map +1 -1
  194. package/src/lib/providers/routing.js +18 -0
  195. package/src/lib/providers/routing.js.map +1 -1
  196. package/src/lib/providers/vertex-image.d.ts +121 -0
  197. package/src/lib/providers/vertex-image.js +312 -0
  198. package/src/lib/providers/vertex-image.js.map +1 -0
  199. package/src/lib/runtime/ai-doctrine-validators.d.ts +19 -0
  200. package/src/lib/runtime/ai-doctrine-validators.js +89 -0
  201. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  202. package/src/lib/runtime/ai-doctrine.js +11 -5
  203. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  204. package/src/lib/runtime/ai-eval-live.js +4 -0
  205. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  206. package/src/lib/runtime/ai-eval.d.ts +15 -1
  207. package/src/lib/runtime/ai-eval.js +52 -1
  208. package/src/lib/runtime/ai-eval.js.map +1 -1
  209. package/src/lib/runtime/experiment-variant-copy.d.ts +34 -0
  210. package/src/lib/runtime/experiment-variant-copy.js +102 -0
  211. package/src/lib/runtime/experiment-variant-copy.js.map +1 -0
  212. package/src/lib/server/ai-experiment-versions.d.ts +51 -0
  213. package/src/lib/server/ai-experiment-versions.js +270 -0
  214. package/src/lib/server/ai-experiment-versions.js.map +1 -0
  215. package/src/lib/server/ai-jobs-resume.js +74 -4
  216. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  217. package/src/lib/server/ai-media-image.d.ts +66 -0
  218. package/src/lib/server/ai-media-image.js +521 -0
  219. package/src/lib/server/ai-media-image.js.map +1 -0
  220. package/src/lib/server/ai-media-svg.d.ts +91 -0
  221. package/src/lib/server/ai-media-svg.js +186 -0
  222. package/src/lib/server/ai-media-svg.js.map +1 -0
  223. package/src/lib/server/assist-build.d.ts +54 -0
  224. package/src/lib/server/assist-build.js +121 -0
  225. package/src/lib/server/assist-build.js.map +1 -0
  226. package/src/lib/server/assist-chat.js +108 -12
  227. package/src/lib/server/assist-chat.js.map +1 -1
  228. package/src/lib/server/assist-edit.js +213 -3
  229. package/src/lib/server/assist-edit.js.map +1 -1
  230. package/src/lib/server/assist-view-context.js +242 -4
  231. package/src/lib/server/assist-view-context.js.map +1 -1
  232. package/src/lib/server.js +26 -0
  233. package/src/lib/server.js.map +1 -1
  234. package/src/lib/tools/ai-logic-tool.d.ts +27 -0
  235. package/src/lib/tools/ai-logic-tool.js +207 -0
  236. package/src/lib/tools/ai-logic-tool.js.map +1 -0
  237. package/src/lib/tools/ai-overlay-tool.d.ts +35 -0
  238. package/src/lib/tools/ai-overlay-tool.js +107 -0
  239. package/src/lib/tools/ai-overlay-tool.js.map +1 -0
  240. package/src/lib/tools/ai-workflow-tool.d.ts +11 -0
  241. package/src/lib/tools/ai-workflow-tool.js +31 -0
  242. package/src/lib/tools/ai-workflow-tool.js.map +1 -1
  243. package/src/lib/usage/assist-job-refund.d.ts +28 -1
  244. package/src/lib/usage/assist-job-refund.js +44 -9
  245. package/src/lib/usage/assist-job-refund.js.map +1 -1
  246. package/src/lib/usage/assist-usage.d.ts +5 -0
  247. package/src/lib/usage/assist-usage.js +2 -0
  248. package/src/lib/usage/assist-usage.js.map +1 -1
@@ -17,17 +17,18 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
17
17
  */ import { ACTION_MAX_CONDITIONS, ACTION_MAX_STEPS } from "@aglyn/aglyn/app-utils/site-interactions";
18
18
  import { CONTACT_LIFECYCLE_STAGES, CONTACT_TAG_MAX_LENGTH, CRM_TASK_MAX_DUE_DAYS } from "@aglyn/aglyn/app-utils/crm";
19
19
  import { HOST_EVENT_PAYLOAD_KEYS } from "@aglyn/aglyn/app-utils/host-events";
20
- import { isHostPluginEnabled } from "@aglyn/aglyn/plugin-manager/enabled-plugins";
20
+ import { checkEntitlement } from "@aglyn/aglyn/app-utils/plan-entitlements";
21
+ import { isHostPluginEnabled, isPluginEnabled } from "@aglyn/aglyn/plugin-manager/enabled-plugins";
21
22
  import { filterEnabledPluginsByReleaseFlags } from "@aglyn/tenant-data-admin/server/release-flags";
22
23
  import { resolveOrgIdForHost } from "@aglyn/tenant-data-admin/server/organizations";
23
- import { aiAutomationDraft, aiAutomationDraftNote } from "../model/ai-automation-draft.js";
24
+ import { aiAutomationDraft, aiAutomationDraftNote, aiAutomationRevisionChanges, aiAutomationRevisionNote } from "../model/ai-automation-draft.js";
24
25
  import { AI_AUTOMATION_TIMED_OUT_FIELD, AI_AUTOMATION_WAIT_MINUTES, aiStepLabel } from "../model/ai-automation-format.js";
25
26
  import { aiActionOutline, aiActionRecordKinds, aiRunOutline, aiWorkflowExplanationText, aiWorkflowOutline } from "../model/ai-automation-outline.js";
26
- import { AI_AUTOMATION_NEED_LABELS, AI_AUTOMATION_RESOURCE, AI_AUTOMATION_STEP_NEEDS, AI_AUTOMATION_STEP_TYPES, AI_AUTOMATION_TRIGGER_NEEDS, AI_AUTOMATION_TRIGGERS, AI_AUTOMATION_UNSUPPORTED_COPY, AI_WORKFLOW_GONE_COPY, AI_WORKFLOW_NO_DRAFT_COPY, AI_WORKFLOW_NO_EXPLANATION_COPY, AI_WORKFLOW_NO_SITE_COPY, AI_WORKFLOW_RUN_GONE_COPY, AI_WORKFLOW_RUN_NOT_FAILED_COPY, AI_WORKFLOW_SAVE_FAILURE_COPY, AI_WORKFLOW_UNAVAILABLE_COPY, aiAutomationCapabilities, aiAutomationTriggerLabel, parseAiWorkflowJobInputs } from "../model/ai-workflow-job.js";
27
+ import { AI_AUTOMATION_NEED_LABELS, AI_AUTOMATION_RESOURCE, AI_AUTOMATION_STEP_NEEDS, AI_AUTOMATION_STEP_TYPES, AI_AUTOMATION_TRIGGER_NEEDS, AI_AUTOMATION_TRIGGERS, AI_AUTOMATION_UNSUPPORTED_COPY, AI_WORKFLOW_GONE_COPY, AI_WORKFLOW_NO_DRAFT_COPY, AI_WORKFLOW_NO_EXPLANATION_COPY, AI_WORKFLOW_NO_SITE_COPY, AI_WORKFLOW_RUN_GONE_COPY, AI_WORKFLOW_RUN_NOT_FAILED_COPY, AI_WORKFLOW_SAVE_FAILURE_COPY, AI_WORKFLOW_REVISE_BLOCKER_COPY, AI_WORKFLOW_REVISE_WORKFLOW_COPY, AI_WORKFLOW_UNAVAILABLE_COPY, AI_ORG_AUTOMATION_PLAN_COPY, AI_ORG_AUTOMATION_RESOURCE, AI_ORG_AUTOMATION_UNAVAILABLE_COPY, aiActionReviseBlocker, aiAutomationCapabilities, aiAutomationTriggerLabel, parseAiWorkflowJobInputs } from "../model/ai-workflow-job.js";
27
28
  import { AI_STEP_TIERS } from "../providers/catalog.js";
28
29
  import { AI_ROUTING_TABLE, aiModelForStep } from "../providers/routing.js";
29
30
  import { runValidatedGeneration } from "../runtime/ai-doctrine.js";
30
- import { AI_AUTOMATION_TOOL_NAME, AI_WORKFLOW_EXPLANATION_TOOL_NAME, aiAutomationTool, aiWorkflowExplanationTool, readAiAutomationAnswer, readAiWorkflowExplanation } from "../tools/ai-workflow-tool.js";
31
+ import { AI_AUTOMATION_TOOL_NAME, AI_WORKFLOW_EXPLANATION_TOOL_NAME, aiAutomationTool, aiWorkflowExplanationTool, holdAiAutomationAnswerToVocabulary, readAiAutomationAnswer, readAiWorkflowExplanation } from "../tools/ai-workflow-tool.js";
31
32
  import { registerAiJobAdmission } from "./ai-job-admission.js";
32
33
  import { aiJobStepBudget } from "./ai-job-budget.js";
33
34
  import { aiJobDraftId } from "./ai-job-draft-ids.js";
@@ -35,7 +36,7 @@ import { aiDoctrineReview, aiGenerationSpent, aiLimitReview, aiUnspentOutcome }
35
36
  import { aiPluginDraftAdmissionRefusal, aiPluginDraftOwner, aiPluginDraftUnavailable, aiPluginDraftWriter } from "./ai-job-plugin-drafts.js";
36
37
  import { AI_JOB_BRIEF_MAX_CHARS } from "./ai-job-text-step.js";
37
38
  import { registerAiJobStep } from "./ai-jobs.js";
38
- import { readAiAutomationRecords, readAiWorkflowFunctions, readAiWorkflowRun, readAiWorkflowTarget } from "./ai-workflow-records.js";
39
+ import { readAiAutomationRecords, readAiOrgAutomationRecords, readAiWorkflowFunctions, readAiWorkflowRun, readAiWorkflowTarget } from "./ai-workflow-records.js";
39
40
  /**
40
41
  * The `workflow` step (AGL-2919): an automation drafted from a description,
41
42
  * or a saved automation explained.
@@ -68,6 +69,29 @@ import { readAiAutomationRecords, readAiWorkflowFunctions, readAiWorkflowRun, re
68
69
  * never the stored documents, never an email address, never a run's event
69
70
  * payload. It answers through `submit_explanation`, which becomes a `text`
70
71
  * output. Nothing is changed.
72
+ *
73
+ * ## Revising (AGL-3603)
74
+ *
75
+ * A saved ACTION and a change asked of it. The model is sent the drafting
76
+ * request — the same cached vocabulary, the same tool, the same reach, forms
77
+ * and datasets — with the action's outline in the user turn and the change as
78
+ * the brief, and answers the whole action as it would be after the change.
79
+ * That answer is held to the vocabulary and matched to the site's records as
80
+ * a draft is, and written as a NEW draft, OFF, under the job's draft id: the
81
+ * saved action is read and never written. What changed is worked out in code
82
+ * from the two stored shapes. An action holding what the vocabulary cannot
83
+ * write is refused before the model is asked, so a revision never drops an
84
+ * on-page step the person did not ask to lose.
85
+ *
86
+ * ## A workspace's automation (AGL-3603)
87
+ *
88
+ * A draft with `scope: 'org'` names no site. It is asked as a draft is — the
89
+ * same cached vocabulary, the same tool — with the org automation's narrower
90
+ * vocabulary stated in the user turn and held by the check, and matched
91
+ * against the workspace's lists, campaigns, datasets and stages. Nothing is
92
+ * written: the automation rides on an `orgAutomation` output, which the Org
93
+ * automations editor opens unsaved, where its sites are picked and its save
94
+ * route — the workflows plugin's — holds it to that plugin's rules.
71
95
  */ /** The longest an explanation or a draft's generation may take reading the site first. */ export const AI_WORKFLOW_RECORDS_READ_MS = 4000;
72
96
  /**
73
97
  * The step's time (AGL-3035): its answer and its re-ask at the routing
@@ -174,21 +198,41 @@ function stepLine(type) {
174
198
  function yesNo(value) {
175
199
  return value ? 'yes' : 'no';
176
200
  }
177
- /** What a draft is asked from: the workspace's reach, the site's forms and datasets, and the brief. */ export function aiJobWorkflowDraftPrompt(input) {
201
+ /**
202
+ * What a draft is asked from: the workspace's reach, the site's forms and
203
+ * datasets, and the brief. A revision adds the saved action's outline, and its
204
+ * brief is the change asked for.
205
+ */ export function aiJobWorkflowDraftPrompt(input) {
178
206
  const { crm, webhooks, bookings } = input.capabilities;
179
207
  const forms = input.records.forms.slice(0, AI_WORKFLOW_FORMS_LISTED);
180
208
  const datasets = input.records.datasets.slice(0, AI_WORKFLOW_DATASETS_LISTED);
181
209
  return [
210
+ ...input.org ? [
211
+ 'This automation belongs to the workspace: it runs on each site it is placed on, as that site. It may start only on these triggers, and use only these steps; anything else, even if listed above, is never used.',
212
+ `Triggers: ${input.org.triggers.join(', ')}.`,
213
+ `Steps: ${input.org.steps.join(', ')}.`
214
+ ] : [],
182
215
  `This workspace can use: the CRM — ${yesNo(crm)}; webhooks — ${yesNo(webhooks)}; bookings — ${yesNo(bookings)}.`,
183
- 'Forms on this site (id · name · fields):',
184
- ...forms.length ? forms.map((form)=>`- ${form.id} · ${form.name} · ${form.fields.slice(0, AI_WORKFLOW_FORM_FIELDS_LISTED).join(', ') || 'no fields'}`) : [
185
- '- none'
216
+ ...input.org ? [
217
+ 'Forms: an automation of the workspace runs on several sites, so none is listed; a form is named in the description’s words.'
218
+ ] : [
219
+ 'Forms on this site (id · name · fields):',
220
+ ...forms.length ? forms.map((form)=>`- ${form.id} · ${form.name} · ${form.fields.slice(0, AI_WORKFLOW_FORM_FIELDS_LISTED).join(', ') || 'no fields'}`) : [
221
+ '- none'
222
+ ]
186
223
  ],
187
- 'Datasets on this site (name):',
224
+ input.org ? 'Datasets in this workspace (name):' : 'Datasets on this site (name):',
188
225
  ...datasets.length ? datasets.map((dataset)=>`- ${dataset.name}`) : [
189
226
  '- none'
190
227
  ],
191
- `Brief: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`
228
+ ...input.revising ? [
229
+ 'The automation to change, as it is set up now:',
230
+ input.revising.outline,
231
+ 'Answer with the whole automation as it should be after the change below. Keep every condition and step the change does not touch as it is, with the same records named in the same words, and keep its name unless the change asks for another. A detail shown as [email address] or a named teammate is written as a placeholder in square brackets.',
232
+ `Change: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`
233
+ ] : [
234
+ `Brief: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`
235
+ ]
192
236
  ].join('\n');
193
237
  }
194
238
  /** What an explanation is asked from: the mode, the outlines, and the member's question. */ export function aiJobWorkflowExplainPrompt(input) {
@@ -210,7 +254,8 @@ function yesNo(value) {
210
254
  } : {});
211
255
  }
212
256
  /** The draft generation as the doctrine's loop runs it; the eval harness records one through this same call. */ export function aiJobWorkflowDraftGeneration(request) {
213
- const check = (answer)=>readAiAutomationAnswer(answer, request.capabilities);
257
+ const org = request.org;
258
+ const check = (answer)=>org ? holdAiAutomationAnswerToVocabulary(readAiAutomationAnswer(answer, request.capabilities), org) : readAiAutomationAnswer(answer, request.capabilities);
214
259
  return _extends({
215
260
  step: 'job.workflow',
216
261
  model: request.model,
@@ -253,9 +298,10 @@ function yesNo(value) {
253
298
  return `“${clean.length > 60 ? `${clean.slice(0, 60)}…` : clean}”`;
254
299
  }
255
300
  export function createAiJobWorkflowStep(deps = {}) {
256
- var _deps_writerFor, _deps_readRecords, _deps_readTarget, _deps_readRun, _deps_readFunctions;
301
+ var _deps_writerFor, _deps_readRecords, _deps_readOrgRecords, _deps_readTarget, _deps_readRun, _deps_readFunctions;
257
302
  const writerFor = (_deps_writerFor = deps.writerFor) != null ? _deps_writerFor : aiPluginDraftWriter;
258
303
  const readRecords = (_deps_readRecords = deps.readRecords) != null ? _deps_readRecords : readAiAutomationRecords;
304
+ const readOrgRecords = (_deps_readOrgRecords = deps.readOrgRecords) != null ? _deps_readOrgRecords : readAiOrgAutomationRecords;
259
305
  const readTarget = (_deps_readTarget = deps.readTarget) != null ? _deps_readTarget : readAiWorkflowTarget;
260
306
  const readRun = (_deps_readRun = deps.readRun) != null ? _deps_readRun : readAiWorkflowRun;
261
307
  const readFunctions = (_deps_readFunctions = deps.readFunctions) != null ? _deps_readFunctions : readAiWorkflowFunctions;
@@ -268,6 +314,58 @@ export function createAiJobWorkflowStep(deps = {}) {
268
314
  });
269
315
  const inputs = parseAiWorkflowJobInputs(job.inputs);
270
316
  if (typeof inputs === 'string') return unspent(inputs);
317
+ if (inputs.mode === 'draft' && inputs.scope === 'org') {
318
+ var _ref2;
319
+ // A workspace's automation (AGL-3603): no site, and nothing written.
320
+ const orgData = (_ref2 = org != null ? org : (await firestore.collection('orgs').doc(job.orgId).get()).data()) != null ? _ref2 : null;
321
+ if (!checkEntitlement(orgData, 'actions')) {
322
+ return aiUnspentOutcome(model, {
323
+ review: aiLimitReview(AI_ORG_AUTOMATION_PLAN_COPY)
324
+ });
325
+ }
326
+ const capabilities = aiAutomationCapabilities(orgData);
327
+ const vocabulary = {
328
+ triggers: inputs.triggers,
329
+ steps: inputs.steps
330
+ };
331
+ const records = await readOrgRecords(firestore, {
332
+ orgId: job.orgId,
333
+ crm: capabilities.crm
334
+ });
335
+ const generation = await runValidatedGeneration('workflow', aiJobWorkflowDraftGeneration(_extends({
336
+ brief: job.brief,
337
+ capabilities,
338
+ records,
339
+ org: vocabulary,
340
+ model
341
+ }, signal ? {
342
+ signal
343
+ } : {})));
344
+ const spent = _extends({}, aiGenerationSpent(generation), generation.effort ? {
345
+ effort: generation.effort
346
+ } : {});
347
+ if (generation.status === 'refused') return _extends({}, spent, {
348
+ refused: true
349
+ });
350
+ if (generation.status === 'needs_input') return _extends({}, spent, {
351
+ review: aiDoctrineReview(generation)
352
+ });
353
+ const answer = generation.value;
354
+ if (answer.unsupported) {
355
+ return _extends({}, spent, {
356
+ failure: answer.unsupported === 'no-trigger' || answer.unsupported === 'no-step' ? AI_ORG_AUTOMATION_UNSUPPORTED_COPY : AI_AUTOMATION_UNSUPPORTED_COPY[answer.unsupported]
357
+ });
358
+ }
359
+ if (!answer.steps.length) return _extends({}, spent, {
360
+ failure: AI_WORKFLOW_NO_DRAFT_COPY
361
+ });
362
+ const draft = aiAutomationDraft(answer, records);
363
+ return _extends({}, spent, {
364
+ outputs: [
365
+ orgProposalOutput(draft, answer.notes)
366
+ ]
367
+ });
368
+ }
271
369
  const hostId = job.hostId;
272
370
  if (!hostId) return unspent(AI_WORKFLOW_NO_SITE_COPY);
273
371
  // The door checks the caller's membership of the org the job is metered
@@ -362,6 +460,111 @@ export function createAiJobWorkflowStep(deps = {}) {
362
460
  ]
363
461
  });
364
462
  }
463
+ if (inputs.mode === 'revise') {
464
+ const writer = writerFor(AI_AUTOMATION_RESOURCE);
465
+ if (!writer) return unspent(AI_WORKFLOW_UNAVAILABLE_COPY);
466
+ const place = {
467
+ hostId,
468
+ hostSubdomain
469
+ };
470
+ const draftId = aiJobDraftId(job, 'workflow');
471
+ const written = await writer.read({
472
+ hostId,
473
+ id: draftId
474
+ });
475
+ if (written) {
476
+ return aiUnspentOutcome(model, {
477
+ outputs: [
478
+ draftOutput(written.id, written.name, place, 'It is off until you switch it on.')
479
+ ]
480
+ });
481
+ }
482
+ const saved = await readTarget({
483
+ hostId,
484
+ type: 'action',
485
+ id: inputs.targetId
486
+ });
487
+ if (!saved) return unspent(AI_WORKFLOW_GONE_COPY);
488
+ if (saved.type !== 'action') return unspent(AI_WORKFLOW_REVISE_WORKFLOW_COPY);
489
+ const blocker = aiActionReviseBlocker(saved.action);
490
+ if (blocker) return unspent(AI_WORKFLOW_REVISE_BLOCKER_COPY[blocker]);
491
+ const context = {
492
+ orgId: job.orgId,
493
+ hostId,
494
+ uid: job.createdBy,
495
+ org: orgData,
496
+ now
497
+ };
498
+ const refusal = await writer.refusal(context);
499
+ if (refusal) {
500
+ return refusal.status === 403 ? aiUnspentOutcome(model, {
501
+ review: aiLimitReview(refusal.error)
502
+ }) : unspent(refusal.error);
503
+ }
504
+ const records = await readRecords(firestore, {
505
+ orgId: job.orgId,
506
+ hostId,
507
+ crm: capabilities.crm
508
+ });
509
+ const generation = await runValidatedGeneration('workflow', aiJobWorkflowDraftGeneration(_extends({
510
+ brief: job.brief,
511
+ capabilities,
512
+ records,
513
+ revising: {
514
+ outline: aiActionOutline(saved.action, records)
515
+ },
516
+ model
517
+ }, signal ? {
518
+ signal
519
+ } : {})));
520
+ const spent = _extends({}, aiGenerationSpent(generation), generation.effort ? {
521
+ effort: generation.effort
522
+ } : {});
523
+ if (generation.status === 'refused') return _extends({}, spent, {
524
+ refused: true
525
+ });
526
+ if (generation.status === 'needs_input') return _extends({}, spent, {
527
+ review: aiDoctrineReview(generation)
528
+ });
529
+ const answer = generation.value;
530
+ if (answer.unsupported) return _extends({}, spent, {
531
+ failure: AI_AUTOMATION_UNSUPPORTED_COPY[answer.unsupported]
532
+ });
533
+ if (!answer.steps.length) return _extends({}, spent, {
534
+ failure: AI_WORKFLOW_NO_DRAFT_COPY
535
+ });
536
+ const draft = aiAutomationDraft(answer, records);
537
+ // The copy never takes the saved action's name: two rows by one name
538
+ // in the list are two rows nobody can tell apart.
539
+ const name = draft.action.name.trim() && draft.action.name.trim() !== saved.name.trim() ? draft.action.name : aiRevisedName(saved.name);
540
+ const write = await writer.write(_extends({}, context, {
541
+ id: draftId,
542
+ name,
543
+ content: {
544
+ action: _extends({}, draft.action, {
545
+ name
546
+ })
547
+ }
548
+ }));
549
+ if (write.ok === false) {
550
+ return write.status === 403 ? _extends({}, spent, {
551
+ review: aiLimitReview(write.error)
552
+ }) : _extends({}, spent, {
553
+ failure: AI_WORKFLOW_SAVE_FAILURE_COPY
554
+ });
555
+ }
556
+ const changes = aiAutomationRevisionChanges(saved.action, draft.action, aiStepLabel);
557
+ return _extends({}, spent, {
558
+ outputs: [
559
+ draftOutput(write.id, write.name, place, aiAutomationRevisionNote({
560
+ fromName: saved.name,
561
+ changes,
562
+ draft,
563
+ notes: answer.notes
564
+ }))
565
+ ]
566
+ });
567
+ }
365
568
  const target = await readTarget({
366
569
  hostId,
367
570
  type: inputs.targetType,
@@ -423,6 +626,41 @@ export function createAiJobWorkflowStep(deps = {}) {
423
626
  });
424
627
  };
425
628
  }
629
+ /** What a person is told when a workspace's automation would need what only one site runs. */ export const AI_ORG_AUTOMATION_UNSUPPORTED_COPY = 'An org automation cannot do what this description asks — it starts only on what the server sees and uses only the steps every site runs the same way — so nothing was drafted. Build it as an action on the site instead.';
630
+ /**
631
+ * A workspace's drafted automation as the output that proposes it
632
+ * (AGL-3603): the stored shape the Org automations editor opens — its name,
633
+ * trigger and steps, never a placement, which the person picks — and what
634
+ * to fill in before switching it on.
635
+ */ export function orgProposalOutput(draft, notes) {
636
+ const { name, trigger, steps } = draft.action;
637
+ return {
638
+ resource: AI_ORG_AUTOMATION_RESOURCE,
639
+ // A proposal has no document; the id names what it is within the job.
640
+ id: 'proposal',
641
+ hostId: null,
642
+ hostSubdomain: null,
643
+ label: name,
644
+ note: [
645
+ 'Nothing is saved yet: it opens in the org automation editor, switched off, where you choose the sites it runs on and save it.',
646
+ ...draft.placeholders.length ? [
647
+ `Fill in ${draft.placeholders.length === 1 ? 'its placeholder' : `its ${draft.placeholders.length} placeholders`} before switching it on.`
648
+ ] : [],
649
+ ...notes
650
+ ].join(' '),
651
+ proposal: {
652
+ automation: {
653
+ name,
654
+ trigger,
655
+ steps
656
+ }
657
+ }
658
+ };
659
+ }
660
+ /** The name a revised copy is saved under when the change asked for no other. */ export function aiRevisedName(name) {
661
+ const clean = name.replace(/\s+/g, ' ').trim() || 'Automation';
662
+ return `${clean.length > 80 ? clean.slice(0, 80) : clean} (revised)`;
663
+ }
426
664
  function draftOutput(id, name, place, note) {
427
665
  return {
428
666
  resource: 'workflow',
@@ -460,6 +698,40 @@ export const runAiJobWorkflowStep = createAiJobWorkflowStep();
460
698
  error: aiPluginDraftUnavailable('Automation')
461
699
  };
462
700
  }
701
+ /**
702
+ * Whether a workspace's automation may be drafted (AGL-3603): no site is
703
+ * named, the plugin that keeps automations runs for the workspace and is
704
+ * past its release flag, and the plan includes the actions builder that
705
+ * section is sold under. Nothing is written, so no allowance is asked: the
706
+ * section's save route counts its cap when the person saves.
707
+ */ async function orgAutomationRefusal(context) {
708
+ if (context.hostId) return {
709
+ status: 400,
710
+ error: 'An org automation belongs to no one site'
711
+ };
712
+ const owner = aiPluginDraftOwner(AI_AUTOMATION_RESOURCE);
713
+ if (!owner) return {
714
+ status: 403,
715
+ error: AI_ORG_AUTOMATION_UNAVAILABLE_COPY
716
+ };
717
+ const org = context.org;
718
+ const released = await filterEnabledPluginsByReleaseFlags([
719
+ owner
720
+ ], {
721
+ orgId: context.orgId,
722
+ authorization: null
723
+ });
724
+ if (!released.includes(owner) || !isPluginEnabled(org, owner)) {
725
+ return {
726
+ status: 403,
727
+ error: AI_ORG_AUTOMATION_UNAVAILABLE_COPY
728
+ };
729
+ }
730
+ return checkEntitlement(org, 'actions') ? null : {
731
+ status: 403,
732
+ error: AI_ORG_AUTOMATION_PLAN_COPY
733
+ };
734
+ }
463
735
  /**
464
736
  * A workflow job is admitted for a site of its org with the Automation plugin
465
737
  * on. A draft also needs the draft writer and the member's room and role in
@@ -475,6 +747,7 @@ export const runAiJobWorkflowStep = createAiJobWorkflowStep();
475
747
  status: 400,
476
748
  error: inputs
477
749
  };
750
+ if (inputs.mode === 'draft' && inputs.scope === 'org') return orgAutomationRefusal(context);
478
751
  if (inputs.mode === 'draft') {
479
752
  return aiPluginDraftAdmissionRefusal(context, _extends({
480
753
  kind: 'workflow',
@@ -488,6 +761,38 @@ export const runAiJobWorkflowStep = createAiJobWorkflowStep();
488
761
  writerFor: deps.writerFor
489
762
  } : {}));
490
763
  }
764
+ if (inputs.mode === 'revise') {
765
+ // A revision writes a draft as a description does, and also needs the
766
+ // action it starts from to exist and to hold only what AI writes.
767
+ return aiPluginDraftAdmissionRefusal(context, _extends({
768
+ kind: 'workflow',
769
+ drafts: [
770
+ {
771
+ resource: AI_AUTOMATION_RESOURCE,
772
+ label: 'Automation'
773
+ }
774
+ ]
775
+ }, deps.writerFor ? {
776
+ writerFor: deps.writerFor
777
+ } : {}, {
778
+ ownCheck: async (hostId)=>{
779
+ const saved = await readTarget({
780
+ hostId,
781
+ type: 'action',
782
+ id: inputs.targetId
783
+ });
784
+ if (!saved || saved.type !== 'action') return {
785
+ status: 404,
786
+ error: AI_WORKFLOW_GONE_COPY
787
+ };
788
+ const blocker = aiActionReviseBlocker(saved.action);
789
+ return blocker ? {
790
+ status: 400,
791
+ error: AI_WORKFLOW_REVISE_BLOCKER_COPY[blocker]
792
+ } : null;
793
+ }
794
+ }));
795
+ }
491
796
  const hostId = context.hostId;
492
797
  if (!hostId) return {
493
798
  status: 400,