@aglyn/plugins-ai 1.0.0-beta.143

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 (717) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +25 -0
  3. package/package.json +60 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +22 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/activity/ai-activity-actions.d.ts +106 -0
  8. package/src/lib/activity/ai-activity-actions.js +209 -0
  9. package/src/lib/activity/ai-activity-actions.js.map +1 -0
  10. package/src/lib/activity/ai-activity.d.ts +219 -0
  11. package/src/lib/activity/ai-activity.js +251 -0
  12. package/src/lib/activity/ai-activity.js.map +1 -0
  13. package/src/lib/billing/ai-overage-charge.d.ts +102 -0
  14. package/src/lib/billing/ai-overage-charge.js +258 -0
  15. package/src/lib/billing/ai-overage-charge.js.map +1 -0
  16. package/src/lib/billing/ai-overage-close.d.ts +62 -0
  17. package/src/lib/billing/ai-overage-close.js +129 -0
  18. package/src/lib/billing/ai-overage-close.js.map +1 -0
  19. package/src/lib/billing/ai-overage-cutover.d.ts +63 -0
  20. package/src/lib/billing/ai-overage-cutover.js +114 -0
  21. package/src/lib/billing/ai-overage-cutover.js.map +1 -0
  22. package/src/lib/billing/ai-overage-events.d.ts +77 -0
  23. package/src/lib/billing/ai-overage-events.js +174 -0
  24. package/src/lib/billing/ai-overage-events.js.map +1 -0
  25. package/src/lib/billing/ai-overage-gate.d.ts +147 -0
  26. package/src/lib/billing/ai-overage-gate.js +177 -0
  27. package/src/lib/billing/ai-overage-gate.js.map +1 -0
  28. package/src/lib/billing/ai-overage-ledger.d.ts +135 -0
  29. package/src/lib/billing/ai-overage-ledger.js +278 -0
  30. package/src/lib/billing/ai-overage-ledger.js.map +1 -0
  31. package/src/lib/billing/ai-overage-standing-writes.d.ts +110 -0
  32. package/src/lib/billing/ai-overage-standing-writes.js +205 -0
  33. package/src/lib/billing/ai-overage-standing-writes.js.map +1 -0
  34. package/src/lib/billing/ai-overage-standing.d.ts +168 -0
  35. package/src/lib/billing/ai-overage-standing.js +215 -0
  36. package/src/lib/billing/ai-overage-standing.js.map +1 -0
  37. package/src/lib/billing/ai-overage-trigger.d.ts +30 -0
  38. package/src/lib/billing/ai-overage-trigger.js +76 -0
  39. package/src/lib/billing/ai-overage-trigger.js.map +1 -0
  40. package/src/lib/components/ai-allotment-editor.component.d.ts +40 -0
  41. package/src/lib/components/ai-allotment-editor.component.js +213 -0
  42. package/src/lib/components/ai-allotment-editor.component.js.map +1 -0
  43. package/src/lib/components/ai-assist-actions-context.d.ts +13 -0
  44. package/src/lib/components/ai-assist-actions-context.js +21 -0
  45. package/src/lib/components/ai-assist-actions-context.js.map +1 -0
  46. package/src/lib/components/ai-assist-provider.component.d.ts +51 -0
  47. package/src/lib/components/ai-assist-provider.component.js +519 -0
  48. package/src/lib/components/ai-assist-provider.component.js.map +1 -0
  49. package/src/lib/components/ai-brief-dialog.component.d.ts +56 -0
  50. package/src/lib/components/ai-brief-dialog.component.js +319 -0
  51. package/src/lib/components/ai-brief-dialog.component.js.map +1 -0
  52. package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +32 -0
  53. package/src/lib/components/ai-collaborator-permissions-column.component.js +132 -0
  54. package/src/lib/components/ai-collaborator-permissions-column.component.js.map +1 -0
  55. package/src/lib/components/ai-credits-card.component.d.ts +34 -0
  56. package/src/lib/components/ai-credits-card.component.js +131 -0
  57. package/src/lib/components/ai-credits-card.component.js.map +1 -0
  58. package/src/lib/components/ai-credits-columns.component.d.ts +56 -0
  59. package/src/lib/components/ai-credits-columns.component.js +118 -0
  60. package/src/lib/components/ai-credits-columns.component.js.map +1 -0
  61. package/src/lib/components/ai-crm-email-draft.component.d.ts +17 -0
  62. package/src/lib/components/ai-crm-email-draft.component.js +159 -0
  63. package/src/lib/components/ai-crm-email-draft.component.js.map +1 -0
  64. package/src/lib/components/ai-crm-import-mapping.component.d.ts +20 -0
  65. package/src/lib/components/ai-crm-import-mapping.component.js +167 -0
  66. package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -0
  67. package/src/lib/components/ai-crm-record-card.component.d.ts +27 -0
  68. package/src/lib/components/ai-crm-record-card.component.js +263 -0
  69. package/src/lib/components/ai-crm-record-card.component.js.map +1 -0
  70. package/src/lib/components/ai-describe-automation.component.d.ts +31 -0
  71. package/src/lib/components/ai-describe-automation.component.js +226 -0
  72. package/src/lib/components/ai-describe-automation.component.js.map +1 -0
  73. package/src/lib/components/ai-describe-button.component.d.ts +39 -0
  74. package/src/lib/components/ai-describe-button.component.js +87 -0
  75. package/src/lib/components/ai-describe-button.component.js.map +1 -0
  76. package/src/lib/components/ai-describe-page.component.d.ts +26 -0
  77. package/src/lib/components/ai-describe-page.component.js +18 -0
  78. package/src/lib/components/ai-describe-page.component.js.map +1 -0
  79. package/src/lib/components/ai-experiment-cards.component.d.ts +75 -0
  80. package/src/lib/components/ai-experiment-cards.component.js +573 -0
  81. package/src/lib/components/ai-experiment-cards.component.js.map +1 -0
  82. package/src/lib/components/ai-explain-automation.component.d.ts +31 -0
  83. package/src/lib/components/ai-explain-automation.component.js +265 -0
  84. package/src/lib/components/ai-explain-automation.component.js.map +1 -0
  85. package/src/lib/components/ai-insight-dialog.component.d.ts +37 -0
  86. package/src/lib/components/ai-insight-dialog.component.js +441 -0
  87. package/src/lib/components/ai-insight-dialog.component.js.map +1 -0
  88. package/src/lib/components/ai-job-plan.component.d.ts +46 -0
  89. package/src/lib/components/ai-job-plan.component.js +192 -0
  90. package/src/lib/components/ai-job-plan.component.js.map +1 -0
  91. package/src/lib/components/ai-model-selector.component.d.ts +21 -0
  92. package/src/lib/components/ai-model-selector.component.js +109 -0
  93. package/src/lib/components/ai-model-selector.component.js.map +1 -0
  94. package/src/lib/components/ai-page-brief-dialog.component.d.ts +29 -0
  95. package/src/lib/components/ai-page-brief-dialog.component.js +27 -0
  96. package/src/lib/components/ai-page-brief-dialog.component.js.map +1 -0
  97. package/src/lib/components/ai-permissions-on-host.component.d.ts +55 -0
  98. package/src/lib/components/ai-permissions-on-host.component.js +91 -0
  99. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -0
  100. package/src/lib/components/ai-product-copy-card.component.d.ts +25 -0
  101. package/src/lib/components/ai-product-copy-card.component.js +328 -0
  102. package/src/lib/components/ai-product-copy-card.component.js.map +1 -0
  103. package/src/lib/components/ai-product-import-option.component.d.ts +14 -0
  104. package/src/lib/components/ai-product-import-option.component.js +58 -0
  105. package/src/lib/components/ai-product-import-option.component.js.map +1 -0
  106. package/src/lib/components/ai-products-hub-card.component.d.ts +15 -0
  107. package/src/lib/components/ai-products-hub-card.component.js +418 -0
  108. package/src/lib/components/ai-products-hub-card.component.js.map +1 -0
  109. package/src/lib/components/ai-products-proposals.component.d.ts +19 -0
  110. package/src/lib/components/ai-products-proposals.component.js +547 -0
  111. package/src/lib/components/ai-products-proposals.component.js.map +1 -0
  112. package/src/lib/components/ai-save-as-component.component.d.ts +38 -0
  113. package/src/lib/components/ai-save-as-component.component.js +231 -0
  114. package/src/lib/components/ai-save-as-component.component.js.map +1 -0
  115. package/src/lib/components/ai-seo-audit-card.component.d.ts +9 -0
  116. package/src/lib/components/ai-seo-audit-card.component.js +620 -0
  117. package/src/lib/components/ai-seo-audit-card.component.js.map +1 -0
  118. package/src/lib/components/ai-seo-fields-card.component.d.ts +10 -0
  119. package/src/lib/components/ai-seo-fields-card.component.js +453 -0
  120. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -0
  121. package/src/lib/components/ai-site-batch-card.component.d.ts +32 -0
  122. package/src/lib/components/ai-site-batch-card.component.js +531 -0
  123. package/src/lib/components/ai-site-batch-card.component.js.map +1 -0
  124. package/src/lib/components/ai-site-seo-start-card.component.d.ts +26 -0
  125. package/src/lib/components/ai-site-seo-start-card.component.js +178 -0
  126. package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -0
  127. package/src/lib/components/ai-site-start-card.component.d.ts +19 -0
  128. package/src/lib/components/ai-site-start-card.component.js +348 -0
  129. package/src/lib/components/ai-site-start-card.component.js.map +1 -0
  130. package/src/lib/components/ai-template-collection-field.component.d.ts +32 -0
  131. package/src/lib/components/ai-template-collection-field.component.js +63 -0
  132. package/src/lib/components/ai-template-collection-field.component.js.map +1 -0
  133. package/src/lib/components/ai-theme-proposal-card.component.d.ts +6 -0
  134. package/src/lib/components/ai-theme-proposal-card.component.js +619 -0
  135. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -0
  136. package/src/lib/components/ai-usage-strip.component.d.ts +27 -0
  137. package/src/lib/components/ai-usage-strip.component.js +145 -0
  138. package/src/lib/components/ai-usage-strip.component.js.map +1 -0
  139. package/src/lib/components/assist-edit-canvas.d.ts +169 -0
  140. package/src/lib/components/assist-edit-canvas.js +636 -0
  141. package/src/lib/components/assist-edit-canvas.js.map +1 -0
  142. package/src/lib/components/assist-edit-card.component.d.ts +16 -0
  143. package/src/lib/components/assist-edit-card.component.js +181 -0
  144. package/src/lib/components/assist-edit-card.component.js.map +1 -0
  145. package/src/lib/components/assist-jobs-drawer.component.d.ts +72 -0
  146. package/src/lib/components/assist-jobs-drawer.component.js +626 -0
  147. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -0
  148. package/src/lib/components/assist-panel.component.d.ts +136 -0
  149. package/src/lib/components/assist-panel.component.js +1099 -0
  150. package/src/lib/components/assist-panel.component.js.map +1 -0
  151. package/src/lib/components/assist-signals-page.component.d.ts +3 -0
  152. package/src/lib/components/assist-signals-page.component.js +1017 -0
  153. package/src/lib/components/assist-signals-page.component.js.map +1 -0
  154. package/src/lib/components/besigner-ai-controls.component.d.ts +29 -0
  155. package/src/lib/components/besigner-ai-controls.component.js +81 -0
  156. package/src/lib/components/besigner-ai-controls.component.js.map +1 -0
  157. package/src/lib/components/billing-ai-allotments.component.d.ts +36 -0
  158. package/src/lib/components/billing-ai-allotments.component.js +486 -0
  159. package/src/lib/components/billing-ai-allotments.component.js.map +1 -0
  160. package/src/lib/components/billing-ai-top-users.component.d.ts +44 -0
  161. package/src/lib/components/billing-ai-top-users.component.js +304 -0
  162. package/src/lib/components/billing-ai-top-users.component.js.map +1 -0
  163. package/src/lib/components/billing-assist-overage-card.component.d.ts +69 -0
  164. package/src/lib/components/billing-assist-overage-card.component.js +437 -0
  165. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -0
  166. package/src/lib/components/host-ai-allotments.component.d.ts +40 -0
  167. package/src/lib/components/host-ai-allotments.component.js +239 -0
  168. package/src/lib/components/host-ai-allotments.component.js.map +1 -0
  169. package/src/lib/components/member-ai-allotment-card.component.d.ts +28 -0
  170. package/src/lib/components/member-ai-allotment-card.component.js +172 -0
  171. package/src/lib/components/member-ai-allotment-card.component.js.map +1 -0
  172. package/src/lib/components/member-ai-usage-card.component.d.ts +28 -0
  173. package/src/lib/components/member-ai-usage-card.component.js +240 -0
  174. package/src/lib/components/member-ai-usage-card.component.js.map +1 -0
  175. package/src/lib/components/staff-org-ai-card.component.d.ts +17 -0
  176. package/src/lib/components/staff-org-ai-card.component.js +739 -0
  177. package/src/lib/components/staff-org-ai-card.component.js.map +1 -0
  178. package/src/lib/components/staff-org-usage-ai-columns.component.d.ts +41 -0
  179. package/src/lib/components/staff-org-usage-ai-columns.component.js +65 -0
  180. package/src/lib/components/staff-org-usage-ai-columns.component.js.map +1 -0
  181. package/src/lib/components/staff-orgs-ai-spend-column.component.d.ts +28 -0
  182. package/src/lib/components/staff-orgs-ai-spend-column.component.js +89 -0
  183. package/src/lib/components/staff-orgs-ai-spend-column.component.js.map +1 -0
  184. package/src/lib/components/staff-user-ai-usage-card.component.d.ts +27 -0
  185. package/src/lib/components/staff-user-ai-usage-card.component.js +183 -0
  186. package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -0
  187. package/src/lib/components/use-ai-allotments.d.ts +49 -0
  188. package/src/lib/components/use-ai-allotments.js +171 -0
  189. package/src/lib/components/use-ai-allotments.js.map +1 -0
  190. package/src/lib/components/use-ai-crm-answer.d.ts +50 -0
  191. package/src/lib/components/use-ai-crm-answer.js +220 -0
  192. package/src/lib/components/use-ai-crm-answer.js.map +1 -0
  193. package/src/lib/components/use-ai-job-run.d.ts +51 -0
  194. package/src/lib/components/use-ai-job-run.js +176 -0
  195. package/src/lib/components/use-ai-job-run.js.map +1 -0
  196. package/src/lib/components/use-ai-model-choice.d.ts +47 -0
  197. package/src/lib/components/use-ai-model-choice.js +150 -0
  198. package/src/lib/components/use-ai-model-choice.js.map +1 -0
  199. package/src/lib/components/use-ai-products-jobs.d.ts +36 -0
  200. package/src/lib/components/use-ai-products-jobs.js +190 -0
  201. package/src/lib/components/use-ai-products-jobs.js.map +1 -0
  202. package/src/lib/components/use-ai-usage-meter.d.ts +11 -0
  203. package/src/lib/components/use-ai-usage-meter.js +96 -0
  204. package/src/lib/components/use-ai-usage-meter.js.map +1 -0
  205. package/src/lib/components/use-org-ai-usage.d.ts +42 -0
  206. package/src/lib/components/use-org-ai-usage.js +181 -0
  207. package/src/lib/components/use-org-ai-usage.js.map +1 -0
  208. package/src/lib/components/use-staff-orgs-ai-spend.d.ts +18 -0
  209. package/src/lib/components/use-staff-orgs-ai-spend.js +127 -0
  210. package/src/lib/components/use-staff-orgs-ai-spend.js.map +1 -0
  211. package/src/lib/constants.d.ts +24 -0
  212. package/src/lib/constants.js +23 -0
  213. package/src/lib/constants.js.map +1 -0
  214. package/src/lib/declarations.d.ts +48 -0
  215. package/src/lib/declarations.js +129 -0
  216. package/src/lib/declarations.js.map +1 -0
  217. package/src/lib/declarations.server.d.ts +35 -0
  218. package/src/lib/declarations.server.js +138 -0
  219. package/src/lib/declarations.server.js.map +1 -0
  220. package/src/lib/insights/ai-figure-readers.d.ts +90 -0
  221. package/src/lib/insights/ai-figure-readers.js +863 -0
  222. package/src/lib/insights/ai-figure-readers.js.map +1 -0
  223. package/src/lib/insights/ai-insight-digest.d.ts +165 -0
  224. package/src/lib/insights/ai-insight-digest.js +363 -0
  225. package/src/lib/insights/ai-insight-digest.js.map +1 -0
  226. package/src/lib/insights/ai-insight-readers.d.ts +71 -0
  227. package/src/lib/insights/ai-insight-readers.js +141 -0
  228. package/src/lib/insights/ai-insight-readers.js.map +1 -0
  229. package/src/lib/jobs/ai-crm-access.d.ts +61 -0
  230. package/src/lib/jobs/ai-crm-access.js +94 -0
  231. package/src/lib/jobs/ai-crm-access.js.map +1 -0
  232. package/src/lib/jobs/ai-email-bindings.d.ts +97 -0
  233. package/src/lib/jobs/ai-email-bindings.js +147 -0
  234. package/src/lib/jobs/ai-email-bindings.js.map +1 -0
  235. package/src/lib/jobs/ai-job-admission.d.ts +82 -0
  236. package/src/lib/jobs/ai-job-admission.js +45 -0
  237. package/src/lib/jobs/ai-job-admission.js.map +1 -0
  238. package/src/lib/jobs/ai-job-budget.d.ts +167 -0
  239. package/src/lib/jobs/ai-job-budget.js +161 -0
  240. package/src/lib/jobs/ai-job-budget.js.map +1 -0
  241. package/src/lib/jobs/ai-job-campaign-step.d.ts +108 -0
  242. package/src/lib/jobs/ai-job-campaign-step.js +340 -0
  243. package/src/lib/jobs/ai-job-campaign-step.js.map +1 -0
  244. package/src/lib/jobs/ai-job-component-checks.d.ts +74 -0
  245. package/src/lib/jobs/ai-job-component-checks.js +442 -0
  246. package/src/lib/jobs/ai-job-component-checks.js.map +1 -0
  247. package/src/lib/jobs/ai-job-component-step.d.ts +75 -0
  248. package/src/lib/jobs/ai-job-component-step.js +262 -0
  249. package/src/lib/jobs/ai-job-component-step.js.map +1 -0
  250. package/src/lib/jobs/ai-job-crm-step.d.ts +192 -0
  251. package/src/lib/jobs/ai-job-crm-step.js +734 -0
  252. package/src/lib/jobs/ai-job-crm-step.js.map +1 -0
  253. package/src/lib/jobs/ai-job-draft-ids.d.ts +62 -0
  254. package/src/lib/jobs/ai-job-draft-ids.js +132 -0
  255. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -0
  256. package/src/lib/jobs/ai-job-drafts.d.ts +304 -0
  257. package/src/lib/jobs/ai-job-drafts.js +557 -0
  258. package/src/lib/jobs/ai-job-drafts.js.map +1 -0
  259. package/src/lib/jobs/ai-job-email-step.d.ts +195 -0
  260. package/src/lib/jobs/ai-job-email-step.js +547 -0
  261. package/src/lib/jobs/ai-job-email-step.js.map +1 -0
  262. package/src/lib/jobs/ai-job-experiment-step.d.ts +105 -0
  263. package/src/lib/jobs/ai-job-experiment-step.js +445 -0
  264. package/src/lib/jobs/ai-job-experiment-step.js.map +1 -0
  265. package/src/lib/jobs/ai-job-form-step.d.ts +250 -0
  266. package/src/lib/jobs/ai-job-form-step.js +634 -0
  267. package/src/lib/jobs/ai-job-form-step.js.map +1 -0
  268. package/src/lib/jobs/ai-job-generation.d.ts +114 -0
  269. package/src/lib/jobs/ai-job-generation.js +384 -0
  270. package/src/lib/jobs/ai-job-generation.js.map +1 -0
  271. package/src/lib/jobs/ai-job-insight-budget.d.ts +41 -0
  272. package/src/lib/jobs/ai-job-insight-budget.js +46 -0
  273. package/src/lib/jobs/ai-job-insight-budget.js.map +1 -0
  274. package/src/lib/jobs/ai-job-insight-step.d.ts +58 -0
  275. package/src/lib/jobs/ai-job-insight-step.js +350 -0
  276. package/src/lib/jobs/ai-job-insight-step.js.map +1 -0
  277. package/src/lib/jobs/ai-job-layout-step.d.ts +103 -0
  278. package/src/lib/jobs/ai-job-layout-step.js +340 -0
  279. package/src/lib/jobs/ai-job-layout-step.js.map +1 -0
  280. package/src/lib/jobs/ai-job-page-budget.d.ts +57 -0
  281. package/src/lib/jobs/ai-job-page-budget.js +60 -0
  282. package/src/lib/jobs/ai-job-page-budget.js.map +1 -0
  283. package/src/lib/jobs/ai-job-page-sections.d.ts +150 -0
  284. package/src/lib/jobs/ai-job-page-sections.js +450 -0
  285. package/src/lib/jobs/ai-job-page-sections.js.map +1 -0
  286. package/src/lib/jobs/ai-job-page-step.d.ts +198 -0
  287. package/src/lib/jobs/ai-job-page-step.js +667 -0
  288. package/src/lib/jobs/ai-job-page-step.js.map +1 -0
  289. package/src/lib/jobs/ai-job-plan-conformance.d.ts +107 -0
  290. package/src/lib/jobs/ai-job-plan-conformance.js +164 -0
  291. package/src/lib/jobs/ai-job-plan-conformance.js.map +1 -0
  292. package/src/lib/jobs/ai-job-plan-step.d.ts +196 -0
  293. package/src/lib/jobs/ai-job-plan-step.js +458 -0
  294. package/src/lib/jobs/ai-job-plan-step.js.map +1 -0
  295. package/src/lib/jobs/ai-job-plugin-drafts.d.ts +76 -0
  296. package/src/lib/jobs/ai-job-plugin-drafts.js +91 -0
  297. package/src/lib/jobs/ai-job-plugin-drafts.js.map +1 -0
  298. package/src/lib/jobs/ai-job-products-step.d.ts +106 -0
  299. package/src/lib/jobs/ai-job-products-step.js +436 -0
  300. package/src/lib/jobs/ai-job-products-step.js.map +1 -0
  301. package/src/lib/jobs/ai-job-seo-budget.d.ts +52 -0
  302. package/src/lib/jobs/ai-job-seo-budget.js +63 -0
  303. package/src/lib/jobs/ai-job-seo-budget.js.map +1 -0
  304. package/src/lib/jobs/ai-job-seo-step.d.ts +145 -0
  305. package/src/lib/jobs/ai-job-seo-step.js +809 -0
  306. package/src/lib/jobs/ai-job-seo-step.js.map +1 -0
  307. package/src/lib/jobs/ai-job-site-step.d.ts +252 -0
  308. package/src/lib/jobs/ai-job-site-step.js +538 -0
  309. package/src/lib/jobs/ai-job-site-step.js.map +1 -0
  310. package/src/lib/jobs/ai-job-template-step.d.ts +105 -0
  311. package/src/lib/jobs/ai-job-template-step.js +391 -0
  312. package/src/lib/jobs/ai-job-template-step.js.map +1 -0
  313. package/src/lib/jobs/ai-job-text-step.d.ts +125 -0
  314. package/src/lib/jobs/ai-job-text-step.js +128 -0
  315. package/src/lib/jobs/ai-job-text-step.js.map +1 -0
  316. package/src/lib/jobs/ai-job-theme-budget.d.ts +38 -0
  317. package/src/lib/jobs/ai-job-theme-budget.js +43 -0
  318. package/src/lib/jobs/ai-job-theme-budget.js.map +1 -0
  319. package/src/lib/jobs/ai-job-theme-step.d.ts +115 -0
  320. package/src/lib/jobs/ai-job-theme-step.js +337 -0
  321. package/src/lib/jobs/ai-job-theme-step.js.map +1 -0
  322. package/src/lib/jobs/ai-job-workflow-step.d.ts +139 -0
  323. package/src/lib/jobs/ai-job-workflow-step.js +530 -0
  324. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -0
  325. package/src/lib/jobs/ai-jobs-beat.d.ts +78 -0
  326. package/src/lib/jobs/ai-jobs-beat.js +93 -0
  327. package/src/lib/jobs/ai-jobs-beat.js.map +1 -0
  328. package/src/lib/jobs/ai-jobs-pause.d.ts +38 -0
  329. package/src/lib/jobs/ai-jobs-pause.js +45 -0
  330. package/src/lib/jobs/ai-jobs-pause.js.map +1 -0
  331. package/src/lib/jobs/ai-jobs.d.ts +558 -0
  332. package/src/lib/jobs/ai-jobs.js +1410 -0
  333. package/src/lib/jobs/ai-jobs.js.map +1 -0
  334. package/src/lib/jobs/ai-media-asset-server.d.ts +34 -0
  335. package/src/lib/jobs/ai-media-asset-server.js +34 -0
  336. package/src/lib/jobs/ai-media-asset-server.js.map +1 -0
  337. package/src/lib/jobs/ai-media-asset.d.ts +59 -0
  338. package/src/lib/jobs/ai-media-asset.js +86 -0
  339. package/src/lib/jobs/ai-media-asset.js.map +1 -0
  340. package/src/lib/jobs/ai-product-image.d.ts +78 -0
  341. package/src/lib/jobs/ai-product-image.js +113 -0
  342. package/src/lib/jobs/ai-product-image.js.map +1 -0
  343. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +125 -0
  344. package/src/lib/jobs/ai-theme-brand-inputs.js +378 -0
  345. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -0
  346. package/src/lib/jobs/ai-theme-brand-server.d.ts +33 -0
  347. package/src/lib/jobs/ai-theme-brand-server.js +33 -0
  348. package/src/lib/jobs/ai-theme-brand-server.js.map +1 -0
  349. package/src/lib/jobs/ai-workflow-records.d.ts +84 -0
  350. package/src/lib/jobs/ai-workflow-records.js +158 -0
  351. package/src/lib/jobs/ai-workflow-records.js.map +1 -0
  352. package/src/lib/jobs/fixtures/ai-free-page-built-recording.d.ts +31 -0
  353. package/src/lib/jobs/fixtures/ai-free-page-built-recording.js +367 -0
  354. package/src/lib/jobs/fixtures/ai-free-page-built-recording.js.map +1 -0
  355. package/src/lib/jobs/fixtures/ai-free-page-recording.d.ts +69 -0
  356. package/src/lib/jobs/fixtures/ai-free-page-recording.js +442 -0
  357. package/src/lib/jobs/fixtures/ai-free-page-recording.js.map +1 -0
  358. package/src/lib/jobs/fixtures/ai-page-briefs.d.ts +146 -0
  359. package/src/lib/jobs/fixtures/ai-page-briefs.js +1850 -0
  360. package/src/lib/jobs/fixtures/ai-page-briefs.js.map +1 -0
  361. package/src/lib/model/ai-allotments.d.ts +208 -0
  362. package/src/lib/model/ai-allotments.js +269 -0
  363. package/src/lib/model/ai-allotments.js.map +1 -0
  364. package/src/lib/model/ai-automation-draft.d.ts +74 -0
  365. package/src/lib/model/ai-automation-draft.js +310 -0
  366. package/src/lib/model/ai-automation-draft.js.map +1 -0
  367. package/src/lib/model/ai-automation-outline.d.ts +50 -0
  368. package/src/lib/model/ai-automation-outline.js +262 -0
  369. package/src/lib/model/ai-automation-outline.js.map +1 -0
  370. package/src/lib/model/ai-build-plan.d.ts +197 -0
  371. package/src/lib/model/ai-build-plan.js +438 -0
  372. package/src/lib/model/ai-build-plan.js.map +1 -0
  373. package/src/lib/model/ai-crm.d.ts +237 -0
  374. package/src/lib/model/ai-crm.js +225 -0
  375. package/src/lib/model/ai-crm.js.map +1 -0
  376. package/src/lib/model/ai-experiment-proposal.d.ts +68 -0
  377. package/src/lib/model/ai-experiment-proposal.js +146 -0
  378. package/src/lib/model/ai-experiment-proposal.js.map +1 -0
  379. package/src/lib/model/ai-experiment.d.ts +309 -0
  380. package/src/lib/model/ai-experiment.js +395 -0
  381. package/src/lib/model/ai-experiment.js.map +1 -0
  382. package/src/lib/model/ai-insight.d.ts +178 -0
  383. package/src/lib/model/ai-insight.js +201 -0
  384. package/src/lib/model/ai-insight.js.map +1 -0
  385. package/src/lib/model/ai-jobs.types.d.ts +412 -0
  386. package/src/lib/model/ai-jobs.types.js +42 -0
  387. package/src/lib/model/ai-jobs.types.js.map +1 -0
  388. package/src/lib/model/ai-page-job.d.ts +92 -0
  389. package/src/lib/model/ai-page-job.js +159 -0
  390. package/src/lib/model/ai-page-job.js.map +1 -0
  391. package/src/lib/model/ai-permissions.d.ts +49 -0
  392. package/src/lib/model/ai-permissions.js +97 -0
  393. package/src/lib/model/ai-permissions.js.map +1 -0
  394. package/src/lib/model/ai-plan-capabilities.d.ts +139 -0
  395. package/src/lib/model/ai-plan-capabilities.js +149 -0
  396. package/src/lib/model/ai-plan-capabilities.js.map +1 -0
  397. package/src/lib/model/ai-products.d.ts +251 -0
  398. package/src/lib/model/ai-products.js +253 -0
  399. package/src/lib/model/ai-products.js.map +1 -0
  400. package/src/lib/model/ai-seo.d.ts +208 -0
  401. package/src/lib/model/ai-seo.js +150 -0
  402. package/src/lib/model/ai-seo.js.map +1 -0
  403. package/src/lib/model/ai-site-inventory.d.ts +164 -0
  404. package/src/lib/model/ai-site-inventory.js +145 -0
  405. package/src/lib/model/ai-site-inventory.js.map +1 -0
  406. package/src/lib/model/ai-site-job.d.ts +247 -0
  407. package/src/lib/model/ai-site-job.js +314 -0
  408. package/src/lib/model/ai-site-job.js.map +1 -0
  409. package/src/lib/model/ai-site-start-seo.d.ts +103 -0
  410. package/src/lib/model/ai-site-start-seo.js +154 -0
  411. package/src/lib/model/ai-site-start-seo.js.map +1 -0
  412. package/src/lib/model/ai-site-start.d.ts +122 -0
  413. package/src/lib/model/ai-site-start.js +159 -0
  414. package/src/lib/model/ai-site-start.js.map +1 -0
  415. package/src/lib/model/ai-site-switch.d.ts +56 -0
  416. package/src/lib/model/ai-site-switch.js +73 -0
  417. package/src/lib/model/ai-site-switch.js.map +1 -0
  418. package/src/lib/model/ai-storefront-claims.d.ts +70 -0
  419. package/src/lib/model/ai-storefront-claims.js +130 -0
  420. package/src/lib/model/ai-storefront-claims.js.map +1 -0
  421. package/src/lib/model/ai-template-subjects.d.ts +82 -0
  422. package/src/lib/model/ai-template-subjects.js +136 -0
  423. package/src/lib/model/ai-template-subjects.js.map +1 -0
  424. package/src/lib/model/ai-theme-proposal.d.ts +210 -0
  425. package/src/lib/model/ai-theme-proposal.js +506 -0
  426. package/src/lib/model/ai-theme-proposal.js.map +1 -0
  427. package/src/lib/model/ai-tokens.d.ts +96 -0
  428. package/src/lib/model/ai-tokens.js +117 -0
  429. package/src/lib/model/ai-tokens.js.map +1 -0
  430. package/src/lib/model/ai-usage-by-user.d.ts +120 -0
  431. package/src/lib/model/ai-usage-by-user.js +139 -0
  432. package/src/lib/model/ai-usage-by-user.js.map +1 -0
  433. package/src/lib/model/ai-workflow-job.d.ts +111 -0
  434. package/src/lib/model/ai-workflow-job.js +183 -0
  435. package/src/lib/model/ai-workflow-job.js.map +1 -0
  436. package/src/lib/model/assist-edit.d.ts +261 -0
  437. package/src/lib/model/assist-edit.js +175 -0
  438. package/src/lib/model/assist-edit.js.map +1 -0
  439. package/src/lib/plugin-config.d.ts +33 -0
  440. package/src/lib/plugin-config.js +118 -0
  441. package/src/lib/plugin-config.js.map +1 -0
  442. package/src/lib/plugin.d.ts +30 -0
  443. package/src/lib/plugin.js +525 -0
  444. package/src/lib/plugin.js.map +1 -0
  445. package/src/lib/providers/anthropic.d.ts +84 -0
  446. package/src/lib/providers/anthropic.js +432 -0
  447. package/src/lib/providers/anthropic.js.map +1 -0
  448. package/src/lib/providers/catalog.d.ts +197 -0
  449. package/src/lib/providers/catalog.js +312 -0
  450. package/src/lib/providers/catalog.js.map +1 -0
  451. package/src/lib/providers/contract.d.ts +464 -0
  452. package/src/lib/providers/contract.js +274 -0
  453. package/src/lib/providers/contract.js.map +1 -0
  454. package/src/lib/providers/model-choice.d.ts +119 -0
  455. package/src/lib/providers/model-choice.js +416 -0
  456. package/src/lib/providers/model-choice.js.map +1 -0
  457. package/src/lib/providers/openai-compatible.d.ts +58 -0
  458. package/src/lib/providers/openai-compatible.js +361 -0
  459. package/src/lib/providers/openai-compatible.js.map +1 -0
  460. package/src/lib/providers/registry.d.ts +49 -0
  461. package/src/lib/providers/registry.js +71 -0
  462. package/src/lib/providers/registry.js.map +1 -0
  463. package/src/lib/providers/routing.d.ts +98 -0
  464. package/src/lib/providers/routing.js +450 -0
  465. package/src/lib/providers/routing.js.map +1 -0
  466. package/src/lib/runtime/ai-abuse-guards.d.ts +113 -0
  467. package/src/lib/runtime/ai-abuse-guards.js +148 -0
  468. package/src/lib/runtime/ai-abuse-guards.js.map +1 -0
  469. package/src/lib/runtime/ai-component-bindings.d.ts +67 -0
  470. package/src/lib/runtime/ai-component-bindings.js +106 -0
  471. package/src/lib/runtime/ai-component-bindings.js.map +1 -0
  472. package/src/lib/runtime/ai-device-audit.d.ts +109 -0
  473. package/src/lib/runtime/ai-device-audit.js +97 -0
  474. package/src/lib/runtime/ai-device-audit.js.map +1 -0
  475. package/src/lib/runtime/ai-doctrine-validators.d.ts +720 -0
  476. package/src/lib/runtime/ai-doctrine-validators.js +3133 -0
  477. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -0
  478. package/src/lib/runtime/ai-doctrine.d.ts +372 -0
  479. package/src/lib/runtime/ai-doctrine.js +944 -0
  480. package/src/lib/runtime/ai-doctrine.js.map +1 -0
  481. package/src/lib/runtime/ai-eval-live.d.ts +321 -0
  482. package/src/lib/runtime/ai-eval-live.js +1257 -0
  483. package/src/lib/runtime/ai-eval-live.js.map +1 -0
  484. package/src/lib/runtime/ai-eval-memory-firestore.d.ts +51 -0
  485. package/src/lib/runtime/ai-eval-memory-firestore.js +183 -0
  486. package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -0
  487. package/src/lib/runtime/ai-eval.d.ts +441 -0
  488. package/src/lib/runtime/ai-eval.js +1151 -0
  489. package/src/lib/runtime/ai-eval.js.map +1 -0
  490. package/src/lib/runtime/ai-gate.d.ts +130 -0
  491. package/src/lib/runtime/ai-gate.js +272 -0
  492. package/src/lib/runtime/ai-gate.js.map +1 -0
  493. package/src/lib/runtime/ai-generation-bounds.d.ts +24 -0
  494. package/src/lib/runtime/ai-generation-bounds.js +23 -0
  495. package/src/lib/runtime/ai-generation-bounds.js.map +1 -0
  496. package/src/lib/runtime/ai-insight-check.d.ts +76 -0
  497. package/src/lib/runtime/ai-insight-check.js +281 -0
  498. package/src/lib/runtime/ai-insight-check.js.map +1 -0
  499. package/src/lib/runtime/ai-node-tree.d.ts +181 -0
  500. package/src/lib/runtime/ai-node-tree.js +931 -0
  501. package/src/lib/runtime/ai-node-tree.js.map +1 -0
  502. package/src/lib/runtime/ai-page-links.d.ts +79 -0
  503. package/src/lib/runtime/ai-page-links.js +135 -0
  504. package/src/lib/runtime/ai-page-links.js.map +1 -0
  505. package/src/lib/runtime/ai-palette.d.ts +252 -0
  506. package/src/lib/runtime/ai-palette.generated.d.ts +34 -0
  507. package/src/lib/runtime/ai-palette.generated.js +5263 -0
  508. package/src/lib/runtime/ai-palette.generated.js.map +1 -0
  509. package/src/lib/runtime/ai-palette.js +187 -0
  510. package/src/lib/runtime/ai-palette.js.map +1 -0
  511. package/src/lib/runtime/ai-products-generation.d.ts +107 -0
  512. package/src/lib/runtime/ai-products-generation.js +250 -0
  513. package/src/lib/runtime/ai-products-generation.js.map +1 -0
  514. package/src/lib/runtime/ai-repeated-items.d.ts +95 -0
  515. package/src/lib/runtime/ai-repeated-items.js +397 -0
  516. package/src/lib/runtime/ai-repeated-items.js.map +1 -0
  517. package/src/lib/runtime/ai-runtime.d.ts +148 -0
  518. package/src/lib/runtime/ai-runtime.js +237 -0
  519. package/src/lib/runtime/ai-runtime.js.map +1 -0
  520. package/src/lib/runtime/ai-template-examples.d.ts +71 -0
  521. package/src/lib/runtime/ai-template-examples.js +135 -0
  522. package/src/lib/runtime/ai-template-examples.js.map +1 -0
  523. package/src/lib/runtime/assist-answer-cache.d.ts +80 -0
  524. package/src/lib/runtime/assist-answer-cache.js +184 -0
  525. package/src/lib/runtime/assist-answer-cache.js.map +1 -0
  526. package/src/lib/runtime/seo-audit.d.ts +93 -0
  527. package/src/lib/runtime/seo-audit.js +260 -0
  528. package/src/lib/runtime/seo-audit.js.map +1 -0
  529. package/src/lib/runtime/seo-content-fixes.d.ts +41 -0
  530. package/src/lib/runtime/seo-content-fixes.js +168 -0
  531. package/src/lib/runtime/seo-content-fixes.js.map +1 -0
  532. package/src/lib/runtime/seo-fields.d.ts +152 -0
  533. package/src/lib/runtime/seo-fields.js +215 -0
  534. package/src/lib/runtime/seo-fields.js.map +1 -0
  535. package/src/lib/runtime/seo-page-facts.d.ts +61 -0
  536. package/src/lib/runtime/seo-page-facts.js +150 -0
  537. package/src/lib/runtime/seo-page-facts.js.map +1 -0
  538. package/src/lib/runtime/site-inventory.d.ts +63 -0
  539. package/src/lib/runtime/site-inventory.js +230 -0
  540. package/src/lib/runtime/site-inventory.js.map +1 -0
  541. package/src/lib/server/ai-admin-org.d.ts +33 -0
  542. package/src/lib/server/ai-admin-org.js +381 -0
  543. package/src/lib/server/ai-admin-org.js.map +1 -0
  544. package/src/lib/server/ai-admin-orgs-spend.d.ts +40 -0
  545. package/src/lib/server/ai-admin-orgs-spend.js +129 -0
  546. package/src/lib/server/ai-admin-orgs-spend.js.map +1 -0
  547. package/src/lib/server/ai-admin-overage.d.ts +19 -0
  548. package/src/lib/server/ai-admin-overage.js +246 -0
  549. package/src/lib/server/ai-admin-overage.js.map +1 -0
  550. package/src/lib/server/ai-admin-signals.d.ts +34 -0
  551. package/src/lib/server/ai-admin-signals.js +330 -0
  552. package/src/lib/server/ai-admin-signals.js.map +1 -0
  553. package/src/lib/server/ai-admin-user.d.ts +27 -0
  554. package/src/lib/server/ai-admin-user.js +128 -0
  555. package/src/lib/server/ai-admin-user.js.map +1 -0
  556. package/src/lib/server/ai-allotments.d.ts +27 -0
  557. package/src/lib/server/ai-allotments.js +544 -0
  558. package/src/lib/server/ai-allotments.js.map +1 -0
  559. package/src/lib/server/ai-assist-prompts.d.ts +102 -0
  560. package/src/lib/server/ai-assist-prompts.js +207 -0
  561. package/src/lib/server/ai-assist-prompts.js.map +1 -0
  562. package/src/lib/server/ai-assist.d.ts +119 -0
  563. package/src/lib/server/ai-assist.js +517 -0
  564. package/src/lib/server/ai-assist.js.map +1 -0
  565. package/src/lib/server/ai-crm-answer.d.ts +30 -0
  566. package/src/lib/server/ai-crm-answer.js +98 -0
  567. package/src/lib/server/ai-crm-answer.js.map +1 -0
  568. package/src/lib/server/ai-generate-component.d.ts +111 -0
  569. package/src/lib/server/ai-generate-component.js +643 -0
  570. package/src/lib/server/ai-generate-component.js.map +1 -0
  571. package/src/lib/server/ai-host-permissions.d.ts +46 -0
  572. package/src/lib/server/ai-host-permissions.js +204 -0
  573. package/src/lib/server/ai-host-permissions.js.map +1 -0
  574. package/src/lib/server/ai-insight-answer.d.ts +30 -0
  575. package/src/lib/server/ai-insight-answer.js +83 -0
  576. package/src/lib/server/ai-insight-answer.js.map +1 -0
  577. package/src/lib/server/ai-insight-digest-route.d.ts +30 -0
  578. package/src/lib/server/ai-insight-digest-route.js +156 -0
  579. package/src/lib/server/ai-insight-digest-route.js.map +1 -0
  580. package/src/lib/server/ai-jobs-batch.d.ts +48 -0
  581. package/src/lib/server/ai-jobs-batch.js +306 -0
  582. package/src/lib/server/ai-jobs-batch.js.map +1 -0
  583. package/src/lib/server/ai-jobs-beat-route.d.ts +36 -0
  584. package/src/lib/server/ai-jobs-beat-route.js +86 -0
  585. package/src/lib/server/ai-jobs-beat-route.js.map +1 -0
  586. package/src/lib/server/ai-jobs-cancel.d.ts +30 -0
  587. package/src/lib/server/ai-jobs-cancel.js +74 -0
  588. package/src/lib/server/ai-jobs-cancel.js.map +1 -0
  589. package/src/lib/server/ai-jobs-events-route.d.ts +31 -0
  590. package/src/lib/server/ai-jobs-events-route.js +51 -0
  591. package/src/lib/server/ai-jobs-events-route.js.map +1 -0
  592. package/src/lib/server/ai-jobs-events.d.ts +55 -0
  593. package/src/lib/server/ai-jobs-events.js +144 -0
  594. package/src/lib/server/ai-jobs-events.js.map +1 -0
  595. package/src/lib/server/ai-jobs-gate.d.ts +47 -0
  596. package/src/lib/server/ai-jobs-gate.js +106 -0
  597. package/src/lib/server/ai-jobs-gate.js.map +1 -0
  598. package/src/lib/server/ai-jobs-resume.d.ts +23 -0
  599. package/src/lib/server/ai-jobs-resume.js +209 -0
  600. package/src/lib/server/ai-jobs-resume.js.map +1 -0
  601. package/src/lib/server/ai-jobs-route.d.ts +32 -0
  602. package/src/lib/server/ai-jobs-route.js +307 -0
  603. package/src/lib/server/ai-jobs-route.js.map +1 -0
  604. package/src/lib/server/ai-models.d.ts +18 -0
  605. package/src/lib/server/ai-models.js +134 -0
  606. package/src/lib/server/ai-models.js.map +1 -0
  607. package/src/lib/server/ai-seo-apply.d.ts +53 -0
  608. package/src/lib/server/ai-seo-apply.js +294 -0
  609. package/src/lib/server/ai-seo-apply.js.map +1 -0
  610. package/src/lib/server/ai-usage.d.ts +18 -0
  611. package/src/lib/server/ai-usage.js +220 -0
  612. package/src/lib/server/ai-usage.js.map +1 -0
  613. package/src/lib/server/assist-chat.d.ts +234 -0
  614. package/src/lib/server/assist-chat.js +1446 -0
  615. package/src/lib/server/assist-chat.js.map +1 -0
  616. package/src/lib/server/assist-edit-applied.d.ts +22 -0
  617. package/src/lib/server/assist-edit-applied.js +239 -0
  618. package/src/lib/server/assist-edit-applied.js.map +1 -0
  619. package/src/lib/server/assist-edit.d.ts +124 -0
  620. package/src/lib/server/assist-edit.js +1000 -0
  621. package/src/lib/server/assist-edit.js.map +1 -0
  622. package/src/lib/server/assist-feedback.d.ts +31 -0
  623. package/src/lib/server/assist-feedback.js +115 -0
  624. package/src/lib/server/assist-feedback.js.map +1 -0
  625. package/src/lib/server/assist-view-context.d.ts +343 -0
  626. package/src/lib/server/assist-view-context.js +690 -0
  627. package/src/lib/server/assist-view-context.js.map +1 -0
  628. package/src/lib/server/billing-credits.d.ts +59 -0
  629. package/src/lib/server/billing-credits.js +146 -0
  630. package/src/lib/server/billing-credits.js.map +1 -0
  631. package/src/lib/server/billing-overage.d.ts +19 -0
  632. package/src/lib/server/billing-overage.js +337 -0
  633. package/src/lib/server/billing-overage.js.map +1 -0
  634. package/src/lib/server.d.ts +32 -0
  635. package/src/lib/server.js +265 -0
  636. package/src/lib/server.js.map +1 -0
  637. package/src/lib/subprocessors.d.ts +18 -0
  638. package/src/lib/subprocessors.js +52 -0
  639. package/src/lib/subprocessors.js.map +1 -0
  640. package/src/lib/tools/ai-component-tool.d.ts +99 -0
  641. package/src/lib/tools/ai-component-tool.js +369 -0
  642. package/src/lib/tools/ai-component-tool.js.map +1 -0
  643. package/src/lib/tools/ai-crm-tool.d.ts +106 -0
  644. package/src/lib/tools/ai-crm-tool.js +488 -0
  645. package/src/lib/tools/ai-crm-tool.js.map +1 -0
  646. package/src/lib/tools/ai-duplicate-resource-tool.d.ts +71 -0
  647. package/src/lib/tools/ai-duplicate-resource-tool.js +164 -0
  648. package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -0
  649. package/src/lib/tools/ai-experiment-tool.d.ts +40 -0
  650. package/src/lib/tools/ai-experiment-tool.js +155 -0
  651. package/src/lib/tools/ai-experiment-tool.js.map +1 -0
  652. package/src/lib/tools/ai-insight-tool.d.ts +46 -0
  653. package/src/lib/tools/ai-insight-tool.js +200 -0
  654. package/src/lib/tools/ai-insight-tool.js.map +1 -0
  655. package/src/lib/tools/ai-inventory-lookup-tool.d.ts +86 -0
  656. package/src/lib/tools/ai-inventory-lookup-tool.js +164 -0
  657. package/src/lib/tools/ai-inventory-lookup-tool.js.map +1 -0
  658. package/src/lib/tools/ai-products-tool.d.ts +65 -0
  659. package/src/lib/tools/ai-products-tool.js +644 -0
  660. package/src/lib/tools/ai-products-tool.js.map +1 -0
  661. package/src/lib/tools/ai-seo-tool.d.ts +162 -0
  662. package/src/lib/tools/ai-seo-tool.js +546 -0
  663. package/src/lib/tools/ai-seo-tool.js.map +1 -0
  664. package/src/lib/tools/ai-theme-tool.d.ts +101 -0
  665. package/src/lib/tools/ai-theme-tool.js +562 -0
  666. package/src/lib/tools/ai-theme-tool.js.map +1 -0
  667. package/src/lib/tools/ai-workflow-tool.d.ts +166 -0
  668. package/src/lib/tools/ai-workflow-tool.js +860 -0
  669. package/src/lib/tools/ai-workflow-tool.js.map +1 -0
  670. package/src/lib/usage/ai-allotment-alerts.d.ts +72 -0
  671. package/src/lib/usage/ai-allotment-alerts.js +157 -0
  672. package/src/lib/usage/ai-allotment-alerts.js.map +1 -0
  673. package/src/lib/usage/ai-allotments.d.ts +125 -0
  674. package/src/lib/usage/ai-allotments.js +239 -0
  675. package/src/lib/usage/ai-allotments.js.map +1 -0
  676. package/src/lib/usage/ai-model-sample.d.ts +36 -0
  677. package/src/lib/usage/ai-model-sample.js +68 -0
  678. package/src/lib/usage/ai-model-sample.js.map +1 -0
  679. package/src/lib/usage/ai-usage-alerts.d.ts +55 -0
  680. package/src/lib/usage/ai-usage-alerts.js +114 -0
  681. package/src/lib/usage/ai-usage-alerts.js.map +1 -0
  682. package/src/lib/usage/ai-usage-by-user.d.ts +161 -0
  683. package/src/lib/usage/ai-usage-by-user.js +211 -0
  684. package/src/lib/usage/ai-usage-by-user.js.map +1 -0
  685. package/src/lib/usage/ai-usage-eraser.d.ts +29 -0
  686. package/src/lib/usage/ai-usage-eraser.js +40 -0
  687. package/src/lib/usage/ai-usage-eraser.js.map +1 -0
  688. package/src/lib/usage/ai-usage-meter.d.ts +39 -0
  689. package/src/lib/usage/ai-usage-meter.js +85 -0
  690. package/src/lib/usage/ai-usage-meter.js.map +1 -0
  691. package/src/lib/usage/ai-usage-wire.d.ts +184 -0
  692. package/src/lib/usage/ai-usage-wire.js +98 -0
  693. package/src/lib/usage/ai-usage-wire.js.map +1 -0
  694. package/src/lib/usage/assist-ceiling.d.ts +87 -0
  695. package/src/lib/usage/assist-ceiling.js +110 -0
  696. package/src/lib/usage/assist-ceiling.js.map +1 -0
  697. package/src/lib/usage/assist-free-taste.d.ts +225 -0
  698. package/src/lib/usage/assist-free-taste.js +308 -0
  699. package/src/lib/usage/assist-free-taste.js.map +1 -0
  700. package/src/lib/usage/assist-refusals.d.ts +69 -0
  701. package/src/lib/usage/assist-refusals.js +79 -0
  702. package/src/lib/usage/assist-refusals.js.map +1 -0
  703. package/src/lib/usage/assist-signal-mining.d.ts +375 -0
  704. package/src/lib/usage/assist-signal-mining.js +344 -0
  705. package/src/lib/usage/assist-signal-mining.js.map +1 -0
  706. package/src/lib/usage/assist-usage.d.ts +571 -0
  707. package/src/lib/usage/assist-usage.js +978 -0
  708. package/src/lib/usage/assist-usage.js.map +1 -0
  709. package/src/lib/usage/staff-org-ai.d.ts +242 -0
  710. package/src/lib/usage/staff-org-ai.js +173 -0
  711. package/src/lib/usage/staff-org-ai.js.map +1 -0
  712. package/src/lib/usage/staff-org-usage-ai.d.ts +83 -0
  713. package/src/lib/usage/staff-org-usage-ai.js +59 -0
  714. package/src/lib/usage/staff-org-usage-ai.js.map +1 -0
  715. package/src/lib/usage/staff-orgs-ai-spend.d.ts +83 -0
  716. package/src/lib/usage/staff-orgs-ai-spend.js +114 -0
  717. package/src/lib/usage/staff-orgs-ai-spend.js.map +1 -0
@@ -0,0 +1,1410 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ /**
18
+ * `FieldValue` straight from the SDK rather than through `./firebase-admin`,
19
+ * for the reason `assist-usage.ts` gives: the default-app initialization
20
+ * would ride into every unit test that touches a job, and the statics need
21
+ * no app at all.
22
+ */ import { FieldValue } from "firebase-admin/firestore";
23
+ import { createResourceUid } from "@aglyn/aglyn/app-utils/create-resource-uid";
24
+ import { checkEntitlement } from "@aglyn/aglyn/server";
25
+ import { assistCreditsFromUsd, assistFreeTasteRefusalText, assistHardCapRefusalText, assistRefusedByHardCap } from "@aglyn/aglyn/app-utils/assist-credits";
26
+ import { AI_JOB_TERMINAL_STATUSES } from "../model/ai-jobs.types.js";
27
+ import { resolveEffectivePlan } from "@aglyn/aglyn/app-utils/plan-entitlements";
28
+ import { aiOverageReservationRefusal } from "../billing/ai-overage-gate.js";
29
+ import { aiAllotmentRefusalText } from "../model/ai-allotments.js";
30
+ import { aiJobPlanCreditEstimate } from "../model/ai-site-job.js";
31
+ import { AI_OFF_FOR_SITE_COPY, isAiOffForSite } from "../model/ai-site-switch.js";
32
+ import { resolveAiModelChoice } from "../providers/model-choice.js";
33
+ import { aiOutputTargetType } from "../activity/ai-activity-actions.js";
34
+ import { logAiJobCanceled, logAiJobCreated, logAiJobNeedsInput, logAiJobOutput } from "../activity/ai-activity.js";
35
+ import { AI_UPSTREAM_FAILURE_COPY, AiUpstreamError } from "../runtime/ai-runtime.js";
36
+ import { recordUserAiRefusal } from "../usage/ai-usage-by-user.js";
37
+ import { AI_JOB_INLINE_BUDGET_MS, AI_JOB_SWEEP_BUDGET_MS } from "./ai-job-budget.js";
38
+ import { aiMintJobDraftIds } from "./ai-job-draft-ids.js";
39
+ import { AI_JOB_TEXT_STEP_MINIMUM_MS, runAiJobTextStep } from "./ai-job-text-step.js";
40
+ import { AI_JOB_SEO_STEP_MINIMUM_MS } from "./ai-job-seo-budget.js";
41
+ import { AI_JOB_THEME_STEP_MINIMUM_MS } from "./ai-job-theme-budget.js";
42
+ import { assistExchangeExpiry, recordAssistCost, releaseAssistMessage, reserveAssistMessage } from "../usage/assist-usage.js";
43
+ /**
44
+ * AI generation jobs — the Firestore state machine (AGL-2904).
45
+ *
46
+ * One document per job under the org, written only by this module through
47
+ * the Admin SDK; the rules let a member READ their org's jobs and nobody
48
+ * write them. The console route creates a job and runs its first step
49
+ * inline when it can; the AI jobs beat, a console route of its own, claims
50
+ * and runs whatever is queued, across every org, inside a wall-clock budget
51
+ * (`ai-jobs-beat.ts`). Both go through
52
+ * `runAiJobStep`, so there is exactly one place a step is claimed, metered,
53
+ * run and recorded.
54
+ *
55
+ * ── Credits, per step ────────────────────────────────────────────────────
56
+ *
57
+ * Every step is an assist message to the meter: `reserveAssistMessage`
58
+ * BEFORE the provider is called — the same read-and-increment transaction
59
+ * the chat route takes, so a job cannot slip past the org's monthly ceiling
60
+ * by being asynchronous — and `recordAssistCost` after, at the serving
61
+ * model's rates, so the usage rollup and the invoice see a job's tokens
62
+ * exactly as they see a chat turn's. The credit figure on the job is that
63
+ * cost at the plan's credit rate, rounded up like every other credit.
64
+ *
65
+ * A refused reservation is NOT a failure. The org is out of credits, over
66
+ * its cap, or has switched overage off — all things a member can change —
67
+ * so the job parks as `needs_input` with the refusal in customer-safe words
68
+ * and the beat tries it again once it has rested. `failed` is reserved for
69
+ * a step that cannot succeed by waiting.
70
+ *
71
+ * ── What a step may not do ───────────────────────────────────────────────
72
+ *
73
+ * A step runner writes drafts and returns. It does not touch the job
74
+ * document, the meter or the lease: the machine owns those, so a runner
75
+ * written next month cannot forget the reservation or record itself done
76
+ * while the provider is still generating.
77
+ */ export const AI_JOBS_COLLECTION = 'aiJobs';
78
+ /**
79
+ * How long a claim holds the step: longer than the longest any holder can
80
+ * still be running it, which is the beat route's 300 s function ceiling
81
+ * (AGL-3026). A lease that ran out under a live holder would let the next
82
+ * beat claim the same step and call the provider for it a second time, and
83
+ * the beat fires every minute while a sweep may run for most of five, so
84
+ * this is what keeps overlapping beats apart. A step abandoned by a process
85
+ * that died is recovered once it runs out, by the first beat after that.
86
+ */ export const AI_JOB_LEASE_MS = 330000;
87
+ /** A step handed back by a retryable provider failure this many times fails. */ export const AI_JOB_STEP_MAX_ATTEMPTS = 3;
88
+ /**
89
+ * The most passes one step may take by asking to continue (AGL-2910), for a
90
+ * kind that registers no bound of its own. A site audit's passes are its
91
+ * units of generated work; this bounds a runner that never finishes, not a
92
+ * real site.
93
+ */ export const AI_JOB_STEP_MAX_PASSES = 40;
94
+ /**
95
+ * The nominal credit figure shown as held per outstanding step. Not a
96
+ * bound — the reservation and the monthly ceiling are — but the console
97
+ * must show a running job as costing something before its bill is known.
98
+ *
99
+ * NOMINAL, and nothing reads it as more (AGL-3030): the band, the Free
100
+ * taste's account allowance and every refusal are measured on recorded
101
+ * spend, and the one real reservation a step takes is a message, counted
102
+ * when the step is claimed and settled — metered or handed back — before the
103
+ * step is recorded. So a job holds nothing real between steps, and a job
104
+ * parked for a person shows nothing held either: `recordStep` releases the
105
+ * figure when a step parks for review, and `resumeAiJob` holds it again for
106
+ * the steps a person's resume queues.
107
+ */ export const AI_JOB_STEP_RESERVE_CREDITS = 50;
108
+ /**
109
+ * The inline doors' budget and the beat's, declared beside the time a step is
110
+ * planned against (`ai-job-budget.ts`, AGL-3036) so a step's least time and
111
+ * the budgets it has to fit are read in one place.
112
+ */ export { AI_JOB_INLINE_BUDGET_MS, AI_JOB_SWEEP_BUDGET_MS };
113
+ /** Jobs one beat reads as candidates; the budget usually stops it first. */ export const AI_JOB_SWEEP_MAX_JOBS = 25;
114
+ /** Parked jobs one beat re-queues, on top of the active candidates. */ export const AI_JOB_SWEEP_MAX_PARKED = 5;
115
+ /** How long a `needs_input` job rests before the beat tries its reservation again. */ export const AI_JOB_NEEDS_INPUT_RETRY_MS = 60 * 60000;
116
+ export const AI_JOB_NOT_AVAILABLE_COPY = 'This kind of AI job is not available yet.';
117
+ export const AI_JOB_REFUSED_COPY = 'The model declined this brief. Try rephrasing it.';
118
+ function toMillis(value) {
119
+ if (value == null) return null;
120
+ if (value instanceof Date) return value.getTime();
121
+ if (typeof value === 'number') return value;
122
+ if (typeof value === 'string') {
123
+ const parsed = Date.parse(value);
124
+ return Number.isFinite(parsed) ? parsed : null;
125
+ }
126
+ return typeof value.toMillis === 'function' ? value.toMillis() : null;
127
+ }
128
+ function toIso(value) {
129
+ const millis = toMillis(value);
130
+ return millis === null ? null : new Date(millis).toISOString();
131
+ }
132
+ export function isAiJobTerminal(status) {
133
+ return AI_JOB_TERMINAL_STATUSES.includes(status);
134
+ }
135
+ // ── The step runner registry ──────────────────────────────────────────────
136
+ /** The step a planned kind runs first (AGL-2935). */ export const AI_JOB_PLAN_STEP = 'plan';
137
+ /**
138
+ * The kinds that build site structure, and so plan before they generate
139
+ * (AGL-2935): the plan their first step proposes is what their generation
140
+ * step executes, once a person has confirmed it.
141
+ */ export const AI_PLANNED_JOB_KINDS = [
142
+ 'page',
143
+ 'site',
144
+ 'component',
145
+ 'layout',
146
+ 'template',
147
+ 'form',
148
+ 'email'
149
+ ];
150
+ const stepRunners = new Map();
151
+ const stepMinimums = new Map();
152
+ const stepRunMinimums = new Map();
153
+ let planStepRunner = null;
154
+ /** The plan step's least time: one step every planned kind shares, so kept by the step, not by a kind. */ let planStepMinimumMs = 0;
155
+ const stepPassCaps = new Map();
156
+ /** Idempotent per kind; last registration wins. */ export function registerAiJobStep(kind, runner, registration = {}) {
157
+ stepRunners.set(kind, runner);
158
+ if (registration.minimumMs && registration.minimumMs > 0) {
159
+ stepMinimums.set(kind, registration.minimumMs);
160
+ } else {
161
+ stepMinimums.delete(kind);
162
+ }
163
+ if (registration.minimumMsFor) {
164
+ stepRunMinimums.set(kind, registration.minimumMsFor);
165
+ } else {
166
+ stepRunMinimums.delete(kind);
167
+ }
168
+ }
169
+ /**
170
+ * The least time a step needs before it starts: the plan step's own minimum
171
+ * for the plan step of any kind (AGL-3026), and the kind's registered
172
+ * minimum for the kind's own step — the least any run of it needs.
173
+ */ export function aiJobStepMinimumMs(kind, stepName) {
174
+ var _stepMinimums_get;
175
+ return stepName === AI_JOB_PLAN_STEP ? planStepMinimumMs : (_stepMinimums_get = stepMinimums.get(kind)) != null ? _stepMinimums_get : 0;
176
+ }
177
+ /**
178
+ * The least time the next run of a job's own step needs (AGL-3035): what the
179
+ * kind registered, or more where the kind says this job's next run needs
180
+ * more. A step that delegates a unit to another kind — a page job's creation,
181
+ * a scaffold's page — asks this of the job it derives for the unit.
182
+ */ export function aiJobStepRunMinimumMs(job) {
183
+ var _stepMinimums_get;
184
+ const least = (_stepMinimums_get = stepMinimums.get(job.kind)) != null ? _stepMinimums_get : 0;
185
+ const forRun = stepRunMinimums.get(job.kind);
186
+ return forRun ? Math.max(least, forRun(job)) : least;
187
+ }
188
+ /** The least time the job's next step needs; 0 when no step is left to run. */ export function aiJobNextStepMinimumMs(job) {
189
+ const index = nextStepIndex(job);
190
+ if (index === -1) return 0;
191
+ return job.steps[index].name === AI_JOB_PLAN_STEP ? planStepMinimumMs : aiJobStepRunMinimumMs(job);
192
+ }
193
+ export function aiJobStepRunnerFor(kind) {
194
+ var _stepRunners_get;
195
+ return (_stepRunners_get = stepRunners.get(kind)) != null ? _stepRunners_get : null;
196
+ }
197
+ /**
198
+ * A kind whose step works through more units than the default bounds
199
+ * (AGL-2911). A scaffold's unit is a whole page and its site is eight of
200
+ * them, where an audit's is one page's listing, so the runaway bound the
201
+ * default gives an audit would cut a real site short. The kind registers its
202
+ * own beside its runner, so the machine keeps no list of kinds and the bound
203
+ * sits with the plan that explains it.
204
+ */ export function registerAiJobStepPasses(kind, maxPasses) {
205
+ stepPassCaps.set(kind, Math.max(1, Math.floor(maxPasses)));
206
+ }
207
+ /** The passes a kind's step may take; the default where it registered none. */ export function aiJobStepMaxPasses(kind) {
208
+ var _stepPassCaps_get;
209
+ return (_stepPassCaps_get = stepPassCaps.get(kind)) != null ? _stepPassCaps_get : AI_JOB_STEP_MAX_PASSES;
210
+ }
211
+ /**
212
+ * The plan step every planned kind runs first. Registered by its own module
213
+ * (`ai-job-plan-step.ts`), which the plugin's server surface loads, so this
214
+ * machine — and every spec that drives it — never loads the inventory
215
+ * reader and the Admin SDK behind it. `null` unregisters it, minimum and all.
216
+ *
217
+ * `minimumMs` means for the plan step what it means for a kind's step
218
+ * (AGL-3026): a plan answered at its ceiling takes longer than an inline
219
+ * door's budget, so the step says so, and both doors leave it for the beat.
220
+ */ export function registerAiJobPlanStep(runner, registration = {}) {
221
+ planStepRunner = runner;
222
+ planStepMinimumMs = runner && registration.minimumMs && registration.minimumMs > 0 ? registration.minimumMs : 0;
223
+ }
224
+ let pauseReader = null;
225
+ /**
226
+ * The reader `runAiJobStep` asks before it claims a step. Registered by its
227
+ * own module (`ai-jobs-pause.ts`), which the plugin's console surface calls,
228
+ * so this machine — and every spec that drives it — never loads the Admin SDK
229
+ * the lockdown reads run on. `null` unregisters it; a machine with no reader
230
+ * runs every job, as a process with no lockdown carrier would.
231
+ */ export function registerAiJobPauseReader(reader) {
232
+ pauseReader = reader;
233
+ }
234
+ /** Whether a pause reader is registered: what a surface that runs jobs must have. */ export function aiJobPauseReaderRegistered() {
235
+ return pauseReader !== null;
236
+ }
237
+ /**
238
+ * The registered reader's answer. A read that throws is not a pause: the
239
+ * lockdown carriers fail open on an unreachable Firestore, and so does this.
240
+ */ async function aiJobPausedFor(orgId, jobId, staff) {
241
+ if (!pauseReader) return false;
242
+ try {
243
+ return await pauseReader({
244
+ orgId,
245
+ staff
246
+ });
247
+ } catch (error) {
248
+ console.error('ai job pause read failed', {
249
+ orgId,
250
+ jobId,
251
+ error
252
+ });
253
+ return false;
254
+ }
255
+ }
256
+ /** The runner for one step of one job: the plan step by its name, else the kind's own. */ export function aiJobRunnerForStep(kind, stepName) {
257
+ return stepName === AI_JOB_PLAN_STEP ? planStepRunner : aiJobStepRunnerFor(kind);
258
+ }
259
+ /**
260
+ * The step names a job of this kind carries, in order. A planned kind plans
261
+ * only once something can build the plan: until its generation runner is
262
+ * registered, its job fails fast and free, rather than spending on a plan
263
+ * nothing will execute.
264
+ */ export function aiJobStepNames(kind) {
265
+ if (kind === 'text') return [
266
+ 'draft'
267
+ ];
268
+ return AI_PLANNED_JOB_KINDS.includes(kind) && planStepRunner && stepRunners.has(kind) ? [
269
+ AI_JOB_PLAN_STEP,
270
+ 'generate'
271
+ ] : [
272
+ 'generate'
273
+ ];
274
+ }
275
+ /**
276
+ * The text step (AGL-2904). Every kind with no runner refuses until its issue
277
+ * lands. Its least time fits an inline door's budget (AGL-3035), so the doors
278
+ * run a text job where it is asked for.
279
+ */ registerAiJobStep('text', runAiJobTextStep, {
280
+ minimumMs: AI_JOB_TEXT_STEP_MINIMUM_MS
281
+ });
282
+ /**
283
+ * The theme step (AGL-2938), loaded the first time a theme job runs rather
284
+ * than when this module does: it builds the brand themes it measures
285
+ * contrast against and may read a site's logo, and a process that never runs
286
+ * a theme job should pay for neither. Its least time is declared apart from
287
+ * the step (`ai-job-theme-budget.ts`, AGL-3035) for the same reason.
288
+ */ registerAiJobStep('theme', async (context)=>{
289
+ const { runAiJobThemeStep } = await import("./ai-job-theme-step.js");
290
+ return runAiJobThemeStep(context);
291
+ }, {
292
+ minimumMs: AI_JOB_THEME_STEP_MINIMUM_MS
293
+ });
294
+ /**
295
+ * The SEO step (AGL-2910), loaded the first time an SEO job runs rather than
296
+ * when this module does: it reads pages, versions and layouts, and a process
297
+ * that never runs one should load none of that. Its least time is declared
298
+ * apart from the step (`ai-job-seo-budget.ts`, AGL-3035) for the same reason.
299
+ */ registerAiJobStep('seo', async (context)=>{
300
+ const { runAiJobSeoStep } = await import("./ai-job-seo-step.js");
301
+ return runAiJobSeoStep(context);
302
+ }, {
303
+ minimumMs: AI_JOB_SEO_STEP_MINIMUM_MS
304
+ });
305
+ // ── Documents ─────────────────────────────────────────────────────────────
306
+ function jobsCollection(firestore, orgId) {
307
+ return firestore.collection('orgs').doc(orgId).collection(AI_JOBS_COLLECTION);
308
+ }
309
+ function jobFrom(snapshot) {
310
+ if (!snapshot.exists) return null;
311
+ const data = snapshot.data();
312
+ return _extends({}, data, {
313
+ $id: snapshot.id
314
+ });
315
+ }
316
+ /**
317
+ * A new job, `queued`, with its step plan laid out and nothing run.
318
+ *
319
+ * The activity row is written once the document is, so the feed never names
320
+ * a job that does not exist. The brief's length stands in for the brief,
321
+ * which is the customer's own text and is not logged (AGL-2929).
322
+ */ export async function createAiJob(firestore, input, now = new Date()) {
323
+ var _input_hostId, _input_inputs, _input_model, _input_createdByEmail, _input_hostId1;
324
+ const brief = input.brief.trim();
325
+ if (!brief) throw new Error('an AI job needs a brief');
326
+ // The drafts the kind always writes are named before any step runs, on the
327
+ // step that writes them, so a run repeated after its write finds them.
328
+ const draftIds = aiMintJobDraftIds(input.kind);
329
+ const steps = aiJobStepNames(input.kind).map((name)=>_extends({
330
+ name,
331
+ status: 'pending',
332
+ startedAt: null,
333
+ endedAt: null,
334
+ creditsSpent: 0,
335
+ error: null,
336
+ attempts: 0
337
+ }, draftIds && name !== AI_JOB_PLAN_STEP ? {
338
+ draftIds
339
+ } : {}));
340
+ // A job is a resource the console lists and routes to, named as one.
341
+ const ref = jobsCollection(firestore, input.orgId).doc(createResourceUid());
342
+ const data = {
343
+ orgId: input.orgId,
344
+ hostId: (_input_hostId = input.hostId) != null ? _input_hostId : null,
345
+ kind: input.kind,
346
+ status: 'queued',
347
+ brief,
348
+ inputs: (_input_inputs = input.inputs) != null ? _input_inputs : {},
349
+ model: (_input_model = input.model) != null ? _input_model : null,
350
+ steps,
351
+ outputs: [],
352
+ creditsReserved: steps.length * AI_JOB_STEP_RESERVE_CREDITS,
353
+ creditsSpent: 0,
354
+ createdBy: input.createdBy,
355
+ createdAt: now,
356
+ updatedAt: now,
357
+ // The brief is verbatim customer text, so it expires on the same clock
358
+ // as an assist exchange; the TTL policy keys on this field.
359
+ expiresAt: assistExchangeExpiry(now),
360
+ error: null,
361
+ lease: null
362
+ };
363
+ await ref.set(data);
364
+ await logAiJobCreated(input.orgId, {
365
+ uid: input.createdBy,
366
+ email: (_input_createdByEmail = input.createdByEmail) != null ? _input_createdByEmail : null
367
+ }, {
368
+ jobId: ref.id,
369
+ kind: input.kind,
370
+ briefLength: brief.length,
371
+ hostId: (_input_hostId1 = input.hostId) != null ? _input_hostId1 : null
372
+ });
373
+ return _extends({}, data, {
374
+ $id: ref.id
375
+ });
376
+ }
377
+ export async function getAiJob(firestore, orgId, jobId) {
378
+ return jobFrom(await jobsCollection(firestore, orgId).doc(jobId).get());
379
+ }
380
+ /** Newest first. Needs the (status, createdAt) index when filtered. */ export async function listAiJobs(firestore, orgId, options = {}) {
381
+ var _options_limit;
382
+ const limit = Math.min(Math.max(1, Math.floor((_options_limit = options.limit) != null ? _options_limit : 20)), 100);
383
+ let query = jobsCollection(firestore, orgId);
384
+ if (options.status) query = query.where('status', '==', options.status);
385
+ const snapshot = await query.orderBy('createdAt', 'desc').limit(limit).get();
386
+ return snapshot.docs.map((doc)=>jobFrom(doc)).filter((job)=>job !== null);
387
+ }
388
+ /** The wire form. `running` is the lease, read against `now`. */ export function aiJobSummary(job, now = new Date()) {
389
+ var _job_hostId, _job_steps, _job_outputs, _job_creditsReserved, _job_creditsSpent, _toIso, _toIso1, _job_error, _job_plan_labels, _job_plan_confirmedBy, _job_review, _job_applied_versions, _job_applied_staged;
390
+ var _job_lease, _job_inputs;
391
+ const leaseUntil = toMillis((_job_lease = job.lease) == null ? void 0 : _job_lease.until);
392
+ return {
393
+ id: job.$id,
394
+ orgId: job.orgId,
395
+ hostId: (_job_hostId = job.hostId) != null ? _job_hostId : null,
396
+ kind: job.kind,
397
+ status: job.status,
398
+ brief: job.brief,
399
+ batch: typeof ((_job_inputs = job.inputs) == null ? void 0 : _job_inputs['batchId']) === 'string' ? job.inputs['batchId'] : null,
400
+ steps: ((_job_steps = job.steps) != null ? _job_steps : []).map((step)=>{
401
+ var _step_creditsSpent, _step_error;
402
+ return {
403
+ name: step.name,
404
+ status: step.status,
405
+ startedAt: toIso(step.startedAt),
406
+ endedAt: toIso(step.endedAt),
407
+ creditsSpent: (_step_creditsSpent = step.creditsSpent) != null ? _step_creditsSpent : 0,
408
+ error: (_step_error = step.error) != null ? _step_error : null
409
+ };
410
+ }),
411
+ outputs: (_job_outputs = job.outputs) != null ? _job_outputs : [],
412
+ creditsReserved: (_job_creditsReserved = job.creditsReserved) != null ? _job_creditsReserved : 0,
413
+ creditsSpent: (_job_creditsSpent = job.creditsSpent) != null ? _job_creditsSpent : 0,
414
+ createdBy: job.createdBy,
415
+ createdAt: (_toIso = toIso(job.createdAt)) != null ? _toIso : new Date(0).toISOString(),
416
+ updatedAt: (_toIso1 = toIso(job.updatedAt)) != null ? _toIso1 : new Date(0).toISOString(),
417
+ error: (_job_error = job.error) != null ? _job_error : null,
418
+ running: job.status === 'running' && leaseUntil !== null && leaseUntil > now.getTime(),
419
+ plan: job.plan ? _extends({}, job.plan, {
420
+ labels: (_job_plan_labels = job.plan.labels) != null ? _job_plan_labels : {},
421
+ proposedAt: toIso(job.plan.proposedAt),
422
+ confirmedAt: toIso(job.plan.confirmedAt),
423
+ confirmedBy: (_job_plan_confirmedBy = job.plan.confirmedBy) != null ? _job_plan_confirmedBy : null
424
+ }) : null,
425
+ review: (_job_review = job.review) != null ? _job_review : null,
426
+ applied: job.applied ? {
427
+ at: toIso(job.applied.at),
428
+ by: job.applied.by,
429
+ versions: (_job_applied_versions = job.applied.versions) != null ? _job_applied_versions : {},
430
+ staged: (_job_applied_staged = job.applied.staged) != null ? _job_applied_staged : []
431
+ } : null
432
+ };
433
+ }
434
+ function leaseIsLive(job, owner, nowMs) {
435
+ const lease = job.lease;
436
+ if (!lease) return false;
437
+ if (lease.owner === owner) return false;
438
+ const until = toMillis(lease.until);
439
+ return until !== null && until > nowMs;
440
+ }
441
+ function nextStepIndex(job) {
442
+ var _job_steps;
443
+ return ((_job_steps = job.steps) != null ? _job_steps : []).findIndex((step)=>step.status === 'pending' || step.status === 'running');
444
+ }
445
+ /**
446
+ * The step a claim by `owner` would take, or -1 when there is none to take:
447
+ * the job is terminal or parked, has no step left, or ANOTHER owner's lease
448
+ * has not yet expired.
449
+ */ function claimableStepIndex(job, owner, nowMs) {
450
+ if (job.status !== 'queued' && job.status !== 'running') return -1;
451
+ if (leaseIsLive(job, owner, nowMs)) return -1;
452
+ return nextStepIndex(job);
453
+ }
454
+ /**
455
+ * Take the lease on the job's next step, in one transaction.
456
+ *
457
+ * Refuses — `null` — when the job is terminal or parked, when it has no
458
+ * step left, or when ANOTHER owner's lease has not yet expired. That last
459
+ * clause is the whole point: the console route and two overlapping beats
460
+ * can all look at one job inside the same minute, and only one of them may
461
+ * spend the reservation for its step. An expired lease is claimable, which
462
+ * is how a step abandoned mid-flight by a frozen process is recovered — the
463
+ * stale lease is released by being taken, not by a sweep of its own.
464
+ */ export async function claimNextStep(firestore, orgId, jobId, owner, now = new Date()) {
465
+ const ref = jobsCollection(firestore, orgId).doc(jobId);
466
+ return firestore.runTransaction(async (tx)=>{
467
+ const job = jobFrom(await tx.get(ref));
468
+ if (!job) return null;
469
+ const stepIndex = claimableStepIndex(job, owner, now.getTime());
470
+ if (stepIndex === -1) return null;
471
+ const steps = job.steps.map((step, index)=>{
472
+ var _step_startedAt, _step_attempts;
473
+ return index === stepIndex ? _extends({}, step, {
474
+ status: 'running',
475
+ startedAt: (_step_startedAt = step.startedAt) != null ? _step_startedAt : now,
476
+ attempts: ((_step_attempts = step.attempts) != null ? _step_attempts : 0) + 1
477
+ }) : step;
478
+ });
479
+ const lease = {
480
+ owner,
481
+ until: new Date(now.getTime() + AI_JOB_LEASE_MS)
482
+ };
483
+ tx.set(ref, {
484
+ status: 'running',
485
+ steps,
486
+ lease,
487
+ updatedAt: now
488
+ }, {
489
+ merge: true
490
+ });
491
+ return {
492
+ job: _extends({}, job, {
493
+ status: 'running',
494
+ steps: steps,
495
+ lease: lease,
496
+ updatedAt: now
497
+ }),
498
+ stepIndex
499
+ };
500
+ });
501
+ }
502
+ /**
503
+ * Extend the lease while a long step is still running. `false` when the
504
+ * caller no longer holds it — the step was recovered by someone else, and
505
+ * the caller's result must not overwrite theirs.
506
+ */ export async function heartbeatStep(firestore, orgId, jobId, owner, now = new Date()) {
507
+ const ref = jobsCollection(firestore, orgId).doc(jobId);
508
+ return firestore.runTransaction(async (tx)=>{
509
+ var _job_lease;
510
+ const job = jobFrom(await tx.get(ref));
511
+ if (!job || job.status !== 'running' || ((_job_lease = job.lease) == null ? void 0 : _job_lease.owner) !== owner) {
512
+ return false;
513
+ }
514
+ tx.set(ref, {
515
+ lease: {
516
+ owner,
517
+ until: new Date(now.getTime() + AI_JOB_LEASE_MS)
518
+ },
519
+ updatedAt: now
520
+ }, {
521
+ merge: true
522
+ });
523
+ return true;
524
+ });
525
+ }
526
+ /**
527
+ * Leave a job whose workspace's AI is paused where it is (AGL-3037), moved to
528
+ * the back of the beat's queue. Nothing is claimed: its steps, their attempts
529
+ * and its lease stay exactly as they were, so resuming AI runs the job from
530
+ * where it stopped. Only `updatedAt` moves — the beat's queue is ordered by it,
531
+ * and a paused workspace's jobs left at the front would fill every beat's
532
+ * candidates and starve every other workspace's.
533
+ *
534
+ * `null`, writing nothing, for a job a claim would not take either: terminal,
535
+ * parked, no step left, or another owner's live lease.
536
+ */ export async function holdPausedAiJob(firestore, orgId, jobId, owner, now = new Date()) {
537
+ const ref = jobsCollection(firestore, orgId).doc(jobId);
538
+ return firestore.runTransaction(async (tx)=>{
539
+ const job = jobFrom(await tx.get(ref));
540
+ if (!job || claimableStepIndex(job, owner, now.getTime()) === -1) return null;
541
+ tx.set(ref, {
542
+ updatedAt: now
543
+ }, {
544
+ merge: true
545
+ });
546
+ return _extends({}, job, {
547
+ updatedAt: now
548
+ });
549
+ });
550
+ }
551
+ /**
552
+ * The runs whose stop reasons a step's record keeps (AGL-3042), newest last.
553
+ * A page job that builds a layout, a form and a component, then five sections
554
+ * and its last pass, runs its generation step nine times: twelve keep such a
555
+ * page whole with room for three retries.
556
+ *
557
+ * What it costs the document: an entry is at most 67 bytes as Firestore sizes
558
+ * it (the two field names, 11 and 7; a stop reason, a provider's ASCII word of
559
+ * at most `AI_JOB_STEP_STOP_REASON_MAX_CHARS` characters, 41; an integer, 8),
560
+ * so a step's list is at most 813 bytes with its field name, and a job's two
561
+ * steps at most 1,626 of the 1,048,576 bytes a document may hold.
562
+ */ export const AI_JOB_STEP_LAST_RUNS = 12;
563
+ /** The longest stop reason a run's entry keeps; every one a provider names today is shorter. */ export const AI_JOB_STEP_STOP_REASON_MAX_CHARS = 40;
564
+ /**
565
+ * A step's measure with one more run added: the four counts and the time
566
+ * summed, the model and effort taken from the run, and why it stopped
567
+ * appended to the latest runs (AGL-3042).
568
+ */ export function addAiJobStepTokens(current, run) {
569
+ var _run_effort;
570
+ const count = (value)=>{
571
+ const parsed = Number(value != null ? value : 0);
572
+ return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0;
573
+ };
574
+ const kept = Array.isArray(current == null ? void 0 : current.lastRuns) ? current.lastRuns : [];
575
+ const stopReason = typeof run.stopReason === 'string' && run.stopReason ? run.stopReason.slice(0, AI_JOB_STEP_STOP_REASON_MAX_CHARS) : null;
576
+ return {
577
+ input: count(current == null ? void 0 : current.input) + count(run.usage.inputTokens),
578
+ cachedRead: count(current == null ? void 0 : current.cachedRead) + count(run.usage.cacheReadTokens),
579
+ cacheWrite: count(current == null ? void 0 : current.cacheWrite) + count(run.usage.cacheWriteTokens),
580
+ output: count(current == null ? void 0 : current.output) + count(run.usage.outputTokens),
581
+ model: run.model || (current == null ? void 0 : current.model) || null,
582
+ effort: (_run_effort = run.effort) != null ? _run_effort : null,
583
+ latencyMs: count(current == null ? void 0 : current.latencyMs) + count(run.latencyMs),
584
+ runs: count(current == null ? void 0 : current.runs) + 1,
585
+ lastRuns: [
586
+ ...kept,
587
+ {
588
+ stopReason,
589
+ output: count(run.usage.outputTokens)
590
+ }
591
+ ].slice(-AI_JOB_STEP_LAST_RUNS)
592
+ };
593
+ }
594
+ /**
595
+ * Record what a step cost and produced, and hand the lease back.
596
+ *
597
+ * Credits and outputs are recorded whatever the job's status is by now —
598
+ * a job canceled while its provider call was in flight still spent the
599
+ * tokens, and hiding that would make the bill disagree with the document.
600
+ * The status transition is the caller's next call (`completeAiJob`,
601
+ * `failAiJob`), except that a step handed back or a step with more steps
602
+ * behind it re-queues here, so the beat sees it without another write —
603
+ * and a step that stopped for a person parks the job `needs_review` here,
604
+ * in the same transaction, so no beat can claim the next step in between.
605
+ */ export async function recordStep(firestore, orgId, jobId, owner, stepIndex, input, now = new Date()) {
606
+ const ref = jobsCollection(firestore, orgId).doc(jobId);
607
+ return firestore.runTransaction(async (tx)=>{
608
+ var _job_outputs, _input_outputs, _job_creditsSpent, _job_creditsReserved, _job_creditsReserved1;
609
+ var _job_lease;
610
+ const job = jobFrom(await tx.get(ref));
611
+ if (!job) throw new Error(`ai job ${orgId}/${jobId} vanished`);
612
+ const steps = job.steps.map((step, index)=>{
613
+ var _step_creditsSpent, _input_error, _step_passes;
614
+ return index === stepIndex ? _extends({}, step, {
615
+ status: input.status,
616
+ endedAt: input.status === 'pending' ? null : now,
617
+ creditsSpent: ((_step_creditsSpent = step.creditsSpent) != null ? _step_creditsSpent : 0) + input.creditsSpent,
618
+ error: (_input_error = input.error) != null ? _input_error : null
619
+ }, input.continued && input.status === 'pending' ? {
620
+ attempts: 0,
621
+ passes: ((_step_passes = step.passes) != null ? _step_passes : 0) + 1
622
+ } : {}, input.tokens ? {
623
+ tokens: addAiJobStepTokens(step.tokens, input.tokens)
624
+ } : {}) : step;
625
+ });
626
+ const remaining = steps.filter((step)=>step.status === 'pending' || step.status === 'running').length;
627
+ const settled = input.status !== 'pending';
628
+ const ownsLease = ((_job_lease = job.lease) == null ? void 0 : _job_lease.owner) === owner;
629
+ const parksForReview = Boolean(input.review) && !isAiJobTerminal(job.status);
630
+ const status = isAiJobTerminal(job.status) ? job.status : job.status === 'needs_input' ? job.status : parksForReview ? 'needs_review' : input.status === 'failed' ? 'running' : remaining > 0 ? 'queued' : 'running';
631
+ const patch = _extends({
632
+ status,
633
+ steps,
634
+ outputs: [
635
+ ...(_job_outputs = job.outputs) != null ? _job_outputs : [],
636
+ ...(_input_outputs = input.outputs) != null ? _input_outputs : []
637
+ ],
638
+ creditsSpent: ((_job_creditsSpent = job.creditsSpent) != null ? _job_creditsSpent : 0) + input.creditsSpent,
639
+ // A job parked for a person holds nothing: no step of it can run until
640
+ // someone resumes it, and the resume holds the figure again (AGL-3030).
641
+ creditsReserved: parksForReview ? 0 : settled ? Math.max(0, ((_job_creditsReserved = job.creditsReserved) != null ? _job_creditsReserved : 0) - AI_JOB_STEP_RESERVE_CREDITS) : (_job_creditsReserved1 = job.creditsReserved) != null ? _job_creditsReserved1 : 0,
642
+ updatedAt: now
643
+ }, ownsLease ? {
644
+ lease: null
645
+ } : {}, input.plan ? {
646
+ plan: input.plan
647
+ } : {}, parksForReview && input.review ? {
648
+ review: input.review,
649
+ error: input.review.reason === 'plan' ? null : input.review.message
650
+ } : {});
651
+ tx.set(ref, patch, {
652
+ merge: true
653
+ });
654
+ return {
655
+ job: _extends({}, job, patch),
656
+ remaining
657
+ };
658
+ });
659
+ }
660
+ async function transition(firestore, orgId, jobId, apply) {
661
+ const ref = jobsCollection(firestore, orgId).doc(jobId);
662
+ return firestore.runTransaction(async (tx)=>{
663
+ const job = jobFrom(await tx.get(ref));
664
+ if (!job) throw new Error(`ai job ${orgId}/${jobId} vanished`);
665
+ const patch = apply(job);
666
+ if (!patch) return {
667
+ job,
668
+ changed: false
669
+ };
670
+ tx.set(ref, patch, {
671
+ merge: true
672
+ });
673
+ return {
674
+ job: _extends({}, job, patch),
675
+ changed: true
676
+ };
677
+ });
678
+ }
679
+ /** Every step done: the job is `done` and holds nothing. */ export async function completeAiJob(firestore, orgId, jobId, now = new Date()) {
680
+ const { job } = await transition(firestore, orgId, jobId, (current)=>isAiJobTerminal(current.status) ? null : {
681
+ status: 'done',
682
+ creditsReserved: 0,
683
+ lease: null,
684
+ error: null,
685
+ updatedAt: now
686
+ });
687
+ return job;
688
+ }
689
+ /**
690
+ * Terminal failure. `message` is the only thing a customer reads, so it is
691
+ * a fixed sentence; whatever the provider or the runner actually said goes
692
+ * to the log beside the ids an operator would search for.
693
+ */ export async function failAiJob(firestore, orgId, jobId, message, detail, now = new Date()) {
694
+ var _ref, _ref1;
695
+ console.error('ai job failed', {
696
+ orgId,
697
+ jobId,
698
+ stepIndex: (_ref = detail == null ? void 0 : detail.stepIndex) != null ? _ref : null,
699
+ error: (detail == null ? void 0 : detail.error) instanceof Error ? detail.error.message : (_ref1 = detail == null ? void 0 : detail.error) != null ? _ref1 : null
700
+ });
701
+ const { job } = await transition(firestore, orgId, jobId, (current)=>isAiJobTerminal(current.status) ? null : {
702
+ status: 'failed',
703
+ error: message,
704
+ creditsReserved: 0,
705
+ lease: null,
706
+ steps: current.steps.map((step)=>step.status === 'running' ? _extends({}, step, {
707
+ status: 'failed',
708
+ endedAt: now,
709
+ error: message
710
+ }) : step),
711
+ updatedAt: now
712
+ });
713
+ return job;
714
+ }
715
+ /**
716
+ * Park the job for something only the workspace can change. The running
717
+ * step goes back to `pending` so the same step is what runs when the beat
718
+ * tries again; its attempt is not counted, because nothing was attempted.
719
+ */ export async function markAiJobNeedsInput(firestore, orgId, jobId, reason, now = new Date()) {
720
+ const { job } = await transition(firestore, orgId, jobId, (current)=>isAiJobTerminal(current.status) ? null : {
721
+ status: 'needs_input',
722
+ error: reason,
723
+ lease: null,
724
+ steps: current.steps.map((step)=>{
725
+ var _step_attempts;
726
+ return step.status === 'running' ? _extends({}, step, {
727
+ status: 'pending',
728
+ attempts: Math.max(0, ((_step_attempts = step.attempts) != null ? _step_attempts : 0) - 1)
729
+ }) : step;
730
+ }),
731
+ updatedAt: now
732
+ });
733
+ return job;
734
+ }
735
+ /**
736
+ * Cancel. Idempotent — a terminal job is returned unchanged — and it does
737
+ * not wait for a step in flight: the runner holding the lease finishes its
738
+ * provider call, records what it cost, and finds the job canceled when it
739
+ * goes to complete it.
740
+ *
741
+ * The activity row is written only when the cancel changed something: a
742
+ * second cancel of the same job is not a second act. `actor` is the member
743
+ * who canceled; a cancel with nobody named is recorded as nobody's rather
744
+ * than as the creator's.
745
+ */ export async function cancelAiJob(firestore, orgId, jobId, now = new Date(), actor = null) {
746
+ const result = await transition(firestore, orgId, jobId, (current)=>isAiJobTerminal(current.status) ? null : {
747
+ status: 'canceled',
748
+ creditsReserved: 0,
749
+ lease: null,
750
+ updatedAt: now
751
+ });
752
+ if (result.changed) {
753
+ await logAiJobCanceled(orgId, actor != null ? actor : {
754
+ uid: null
755
+ }, {
756
+ jobId,
757
+ kind: result.job.kind
758
+ });
759
+ }
760
+ return result;
761
+ }
762
+ /**
763
+ * Resume a job that stopped for a person (AGL-2935): confirm its plan, or
764
+ * try again the step whose answer broke a building rule. One transaction,
765
+ * so two confirmations land once; anything but a `needs_review` job comes
766
+ * back unchanged. The pending step's attempts start over — a person asking
767
+ * again is not a provider failing again — and a confirmed plan with no step
768
+ * left behind it completes the job rather than queueing nothing. The steps
769
+ * it queues are held at the nominal figure again, which the park released —
770
+ * and a confirmed plan is held at what the whole job is estimated to cost
771
+ * (AGL-3031), creations included, where that is more.
772
+ */ export async function resumeAiJob(firestore, orgId, jobId, actor, now = new Date()) {
773
+ return transition(firestore, orgId, jobId, (current)=>{
774
+ var _current_review;
775
+ if (current.status !== 'needs_review') return null;
776
+ const steps = current.steps.map((step)=>step.status === 'pending' ? _extends({}, step, {
777
+ attempts: 0
778
+ }) : step);
779
+ const outstanding = steps.filter((step)=>step.status === 'pending').length;
780
+ const pending = outstanding > 0;
781
+ const confirming = ((_current_review = current.review) == null ? void 0 : _current_review.reason) === 'plan' && current.plan ? current.plan : null;
782
+ const confirmed = confirming ? {
783
+ plan: _extends({}, confirming, {
784
+ status: 'confirmed',
785
+ confirmedAt: now,
786
+ confirmedBy: actor.uid
787
+ })
788
+ } : {};
789
+ return _extends({
790
+ status: pending ? 'queued' : 'done',
791
+ steps,
792
+ review: null,
793
+ error: null
794
+ }, confirmed, {
795
+ creditsReserved: pending ? Math.max(outstanding * AI_JOB_STEP_RESERVE_CREDITS, confirming ? aiJobPlanCreditEstimate(current.kind, confirming) : 0) : 0,
796
+ updatedAt: now
797
+ });
798
+ });
799
+ }
800
+ /**
801
+ * Record what a person applied from a finished job's outputs (AGL-2910): the
802
+ * versions an apply opened and the listings it staged. The apply door calls
803
+ * this after its own writes, so the record names only what exists. It never
804
+ * changes the job's status, its steps or its spend.
805
+ */ export async function recordAiJobApplied(firestore, orgId, jobId, applied, now = new Date()) {
806
+ const { job } = await transition(firestore, orgId, jobId, ()=>({
807
+ applied,
808
+ updatedAt: now
809
+ }));
810
+ return job;
811
+ }
812
+ /**
813
+ * One `adminAudit` row, the same writer shape the billing routes use. Never
814
+ * throws: an audit row that fails to land is logged, not turned into a
815
+ * failed job the customer paid for.
816
+ */ export async function writeAiJobAudit(firestore, entry) {
817
+ try {
818
+ var _entry_actorEmail;
819
+ await firestore.collection('adminAudit').add({
820
+ actorUid: entry.actorUid,
821
+ actorEmail: (_entry_actorEmail = entry.actorEmail) != null ? _entry_actorEmail : null,
822
+ action: entry.action,
823
+ target: `orgs/${entry.orgId}/${AI_JOBS_COLLECTION}/${entry.jobId}`,
824
+ after: entry.after,
825
+ at: FieldValue.serverTimestamp()
826
+ });
827
+ } catch (error) {
828
+ console.error('ai job audit write failed', {
829
+ orgId: entry.orgId,
830
+ jobId: entry.jobId,
831
+ action: entry.action,
832
+ error
833
+ });
834
+ }
835
+ }
836
+ // ── Running a step ────────────────────────────────────────────────────────
837
+ /**
838
+ * The refusal in customer-safe words. The org's own wall names the switch
839
+ * (AGL-2653); a cap, a band and a budget are told apart because one is a
840
+ * figure the org set, one is what its plan sold, and one is the operator's
841
+ * backstop; the message cap resets on a clock the others do not.
842
+ */ export function aiJobRefusalText(org, reservation) {
843
+ const refusedBy = reservation.refusedBy;
844
+ // AGLYN'S OWN OVERAGE GUARDS (AGL-3011). First, because a `cap` refusal
845
+ // that carries a reason knows exactly which limit stopped the job, where
846
+ // the `case 'cap'` below can only name the workspace's own.
847
+ const overage = aiOverageReservationRefusal(reservation);
848
+ if (overage) return overage.text;
849
+ // A hard allotment (AGL-2942) — the creator's, theirs on the job's site,
850
+ // or the site's — in the sentence every door gives, naming who can raise
851
+ // it. A member can change that, so the job parks rather than fails.
852
+ if (refusedBy === 'allotment') {
853
+ var _reservation_allotment_refusal, _reservation_allotment;
854
+ return aiAllotmentRefusalText((_reservation_allotment = reservation.allotment) == null ? void 0 : (_reservation_allotment_refusal = _reservation_allotment.refusal) == null ? void 0 : _reservation_allotment_refusal.scope);
855
+ }
856
+ if (assistRefusedByHardCap(org, refusedBy)) {
857
+ return assistHardCapRefusalText(org);
858
+ }
859
+ // The Free taste's own precautions (AGL-2925), in the sentences every
860
+ // other door uses — each names a clock or an upgrade.
861
+ const taste = assistFreeTasteRefusalText(refusedBy);
862
+ if (taste) return taste;
863
+ switch(refusedBy){
864
+ case 'cap':
865
+ return 'This workspace reached the AI spending cap it set for the month';
866
+ case 'band':
867
+ return 'This workspace used its AI credits for the month';
868
+ case 'budget':
869
+ return reservation.budgetUsd === null ? 'This workspace reached its AI spending limit for the month' : 'This workspace used its AI credits for the month';
870
+ default:
871
+ return 'This workspace reached its AI limit for the month';
872
+ }
873
+ }
874
+ /**
875
+ * A budget that ended before the provider answered. `fetch` rejects with
876
+ * the signal's reason, which is an `AbortError` for a manual abort and a
877
+ * `TimeoutError` for `AbortSignal.timeout` — the one the route and the
878
+ * sweep actually hand in.
879
+ */ function isAbort(error) {
880
+ const name = error == null ? void 0 : error.name;
881
+ return name === 'AbortError' || name === 'TimeoutError';
882
+ }
883
+ /** A step outcome that carries no tokens and no cost: the provider was never reached. */ export function aiJobStepSpentNothing(outcome) {
884
+ const { usage } = outcome;
885
+ return outcome.estCostUsd === 0 && usage.inputTokens === 0 && usage.outputTokens === 0 && usage.cacheReadTokens === 0 && usage.cacheWriteTokens === 0;
886
+ }
887
+ /**
888
+ * Pause, claim, reserve, run, meter, record — one step of one job.
889
+ *
890
+ * The order is the invariant. The workspace's AI pause is asked BEFORE the
891
+ * claim, so a paused workspace's job is neither claimed nor reserved for.
892
+ * The reservation is taken AFTER the claim so a refused claim costs nothing,
893
+ * and BEFORE the runner so the org's ceiling binds before a token is spent.
894
+ * The cost is recorded before the step is, so a process cut off between the
895
+ * two leaves the bill right and the step recoverable, never the other way
896
+ * round.
897
+ */ export async function runAiJobStep(firestore, orgId, jobId, options) {
898
+ var _options_now, _step_attempts, _options_org, _data, _ref, _ref1, _outcome_effort, _step_passes, _options_actor;
899
+ var _reservation_allotment, _reservation_allotment1;
900
+ const now = (_options_now = options.now) != null ? _options_now : new Date();
901
+ // A reservation the caller took before the job existed is a message
902
+ // counted against the org; a step that fails before the provider is
903
+ // reached spends nothing, so the message goes back rather than standing
904
+ // as capacity the org paid for and never used.
905
+ const releaseHeld = async ()=>{
906
+ if (!options.reservation) return;
907
+ await releaseAssistMessage(firestore, orgId, options.reservation).catch((releaseError)=>console.error('ai job release failed', {
908
+ orgId,
909
+ jobId,
910
+ releaseError
911
+ }));
912
+ };
913
+ // A WORKSPACE WHOSE AI STAFF HAVE PAUSED runs none of its jobs (AGL-3037),
914
+ // queued before the pause or not: the pause is a spend stop, and a job the
915
+ // beat kept running would spend through it. The pause is lifted by staff
916
+ // or by its own expiry and leaves the plan, the add-on and every
917
+ // entitlement as they were, so a paused job is held, not failed: nothing is
918
+ // claimed, reserved or run, and resuming AI runs it from where it stopped.
919
+ // Read through the same verdict the jobs doors climb, before the claim.
920
+ if (await aiJobPausedFor(orgId, jobId, options.staff === true)) {
921
+ const held = await holdPausedAiJob(firestore, orgId, jobId, options.owner, now);
922
+ if (!held) return {
923
+ outcome: 'not-claimable'
924
+ };
925
+ await releaseHeld();
926
+ return {
927
+ outcome: 'paused',
928
+ job: held
929
+ };
930
+ }
931
+ const claimed = await claimNextStep(firestore, orgId, jobId, options.owner, now);
932
+ if (!claimed) return {
933
+ outcome: 'not-claimable'
934
+ };
935
+ const { job, stepIndex } = claimed;
936
+ const step = job.steps[stepIndex];
937
+ const runner = aiJobRunnerForStep(job.kind, step.name);
938
+ if (!runner) {
939
+ await releaseHeld();
940
+ return {
941
+ outcome: 'failed',
942
+ job: await failAiJob(firestore, orgId, jobId, AI_JOB_NOT_AVAILABLE_COPY, {
943
+ stepIndex,
944
+ error: `no runner registered for kind ${job.kind}`
945
+ }, now)
946
+ };
947
+ }
948
+ if (((_step_attempts = step.attempts) != null ? _step_attempts : 0) > AI_JOB_STEP_MAX_ATTEMPTS) {
949
+ await releaseHeld();
950
+ return {
951
+ outcome: 'failed',
952
+ job: await failAiJob(firestore, orgId, jobId, AI_UPSTREAM_FAILURE_COPY, {
953
+ stepIndex,
954
+ error: `step ${step.name} exhausted ${AI_JOB_STEP_MAX_ATTEMPTS} attempts`
955
+ }, now)
956
+ };
957
+ }
958
+ const org = (_options_org = options.org) != null ? _options_org : (_data = (await firestore.collection('orgs').doc(orgId).get()).data()) != null ? _data : {};
959
+ // A site that switched AI off runs none of its jobs (AGL-3028), queued
960
+ // before the switch or not. Asked before the reservation, so the job fails
961
+ // in words a member can act on and nothing is reserved, run or metered.
962
+ if (await isAiOffForSite(firestore, org, job.hostId)) {
963
+ await releaseHeld();
964
+ return {
965
+ outcome: 'failed',
966
+ job: await failAiJob(firestore, orgId, jobId, AI_OFF_FOR_SITE_COPY, {
967
+ stepIndex,
968
+ error: `ai is switched off for site ${job.hostId}`
969
+ }, now)
970
+ };
971
+ }
972
+ const entitled = checkEntitlement(org, 'aiAssist') || checkEntitlement(org, 'aiGenerative');
973
+ let reservation;
974
+ if (options.reservation) {
975
+ reservation = options.reservation;
976
+ } else {
977
+ try {
978
+ var _job_hostId;
979
+ // The creator's allotments on the job's site (AGL-2942): the step is
980
+ // their spend, as the meter below attributes it.
981
+ reservation = await reserveAssistMessage(firestore, orgId, entitled, now, org, {
982
+ uid: job.createdBy,
983
+ hostId: (_job_hostId = job.hostId) != null ? _job_hostId : null
984
+ });
985
+ } catch (error) {
986
+ // The meter is unreachable, not refusing. Hand the step back; the
987
+ // next beat asks again.
988
+ console.error('ai job reservation failed', {
989
+ orgId,
990
+ jobId,
991
+ error
992
+ });
993
+ const { job: requeued } = await recordStep(firestore, orgId, jobId, options.owner, stepIndex, {
994
+ status: 'pending',
995
+ creditsSpent: 0
996
+ }, now);
997
+ return {
998
+ outcome: 'requeued',
999
+ job: requeued
1000
+ };
1001
+ }
1002
+ }
1003
+ // A refused step is the creator's refusal (AGL-2928), on their month,
1004
+ // beside the org counter the reservation moved; an admitted one records
1005
+ // nothing.
1006
+ recordUserAiRefusal(firestore, orgId, job.createdBy, reservation);
1007
+ if (!reservation.allowed) {
1008
+ const refusal = aiJobRefusalText(org, reservation);
1009
+ const parked = await markAiJobNeedsInput(firestore, orgId, jobId, refusal, now);
1010
+ // Nobody parked the job — the meter did — so the row carries no actor
1011
+ // rather than the creator's name on an act they did not perform. Only
1012
+ // when the job was not already parked for this: the reason the last
1013
+ // park stored survives the beat's re-queue, so a job the meter refuses
1014
+ // again on its hourly retry is one row, not one an hour; a different
1015
+ // ceiling is a new row. The meter names a ceiling on every refusal; the
1016
+ // guard narrows the type.
1017
+ if (reservation.refusedBy && job.error !== refusal) {
1018
+ await logAiJobNeedsInput(orgId, {
1019
+ uid: null
1020
+ }, {
1021
+ jobId,
1022
+ kind: job.kind,
1023
+ reason: reservation.refusedBy
1024
+ });
1025
+ }
1026
+ return {
1027
+ outcome: 'needs_input',
1028
+ job: parked
1029
+ };
1030
+ }
1031
+ // The model each step runs on (AGL-2942): the creator's pick where the
1032
+ // plan and the allotment allowlists the reservation read allow it, the
1033
+ // routing table otherwise. Handed to the runner as a function of the step
1034
+ // kind, because the runner — not the machine — knows what kind it runs.
1035
+ const bounds = {
1036
+ plan: resolveEffectivePlan(org),
1037
+ allotmentModels: (_ref = (_reservation_allotment = reservation.allotment) == null ? void 0 : _reservation_allotment.models) != null ? _ref : null,
1038
+ orgModels: (_ref1 = (_reservation_allotment1 = reservation.allotment) == null ? void 0 : _reservation_allotment1.orgModels) != null ? _ref1 : null
1039
+ };
1040
+ const modelFor = (kind)=>{
1041
+ var _job_model;
1042
+ var _resolveAiModelChoice;
1043
+ return (_resolveAiModelChoice = resolveAiModelChoice(kind, (_job_model = job.model) != null ? _job_model : null, bounds)) == null ? void 0 : _resolveAiModelChoice.model;
1044
+ };
1045
+ let outcome;
1046
+ // The runner's wall-clock time, recorded on the step beside its tokens
1047
+ // (AGL-2937): measured here, around the call, rather than asked of it.
1048
+ const runStarted = Date.now();
1049
+ try {
1050
+ outcome = await runner({
1051
+ job,
1052
+ stepIndex,
1053
+ now,
1054
+ signal: options.signal,
1055
+ firestore,
1056
+ org,
1057
+ modelFor
1058
+ });
1059
+ } catch (error) {
1060
+ // The provider refused the request or the budget ended before it
1061
+ // answered: no usage came back, so nothing is metered and the message
1062
+ // goes back to the org. The provider's own words are already in the
1063
+ // log under the request id (AGL-2815).
1064
+ await releaseAssistMessage(firestore, orgId, reservation).catch((releaseError)=>console.error('ai job release failed', {
1065
+ orgId,
1066
+ jobId,
1067
+ releaseError
1068
+ }));
1069
+ const retryable = error instanceof AiUpstreamError && error.retryable || isAbort(error);
1070
+ if (retryable) {
1071
+ const { job: requeued } = await recordStep(firestore, orgId, jobId, options.owner, stepIndex, {
1072
+ status: 'pending',
1073
+ creditsSpent: 0
1074
+ }, now);
1075
+ return {
1076
+ outcome: 'requeued',
1077
+ job: requeued
1078
+ };
1079
+ }
1080
+ return {
1081
+ outcome: 'failed',
1082
+ job: await failAiJob(firestore, orgId, jobId, AI_UPSTREAM_FAILURE_COPY, {
1083
+ stepIndex,
1084
+ error
1085
+ }, now)
1086
+ };
1087
+ }
1088
+ const latencyMs = Math.max(0, Date.now() - runStarted);
1089
+ // A step that failed before it reached the provider — the site it builds
1090
+ // from could not be read, say (AGL-2938) — spent nothing: its message goes
1091
+ // back and nothing is metered, exactly as for a request the provider
1092
+ // refused.
1093
+ if (outcome.failure && aiJobStepSpentNothing(outcome)) {
1094
+ await releaseAssistMessage(firestore, orgId, reservation).catch((releaseError)=>console.error('ai job release failed', {
1095
+ orgId,
1096
+ jobId,
1097
+ releaseError
1098
+ }));
1099
+ await recordStep(firestore, orgId, jobId, options.owner, stepIndex, {
1100
+ status: 'failed',
1101
+ creditsSpent: 0,
1102
+ error: outcome.failure
1103
+ }, now);
1104
+ return {
1105
+ outcome: 'failed',
1106
+ job: await failAiJob(firestore, orgId, jobId, outcome.failure, {
1107
+ stepIndex,
1108
+ error: `step failure before the provider: ${outcome.failure}`
1109
+ }, now)
1110
+ };
1111
+ }
1112
+ const tokens = {
1113
+ usage: outcome.usage,
1114
+ model: outcome.model,
1115
+ effort: (_outcome_effort = outcome.effort) != null ? _outcome_effort : null,
1116
+ latencyMs,
1117
+ stopReason: outcome.stopReason
1118
+ };
1119
+ // A step that stopped before the provider without failing — a site with no
1120
+ // room for the draft (AGL-2909), say — spent nothing too: its message goes
1121
+ // back and there is nothing to meter. What it returns is still recorded
1122
+ // below, as any step's is.
1123
+ const spentNothing = aiJobStepSpentNothing(outcome);
1124
+ if (spentNothing) {
1125
+ await releaseAssistMessage(firestore, orgId, reservation).catch((releaseError)=>console.error('ai job release failed', {
1126
+ orgId,
1127
+ jobId,
1128
+ releaseError
1129
+ }));
1130
+ } else {
1131
+ // Tokens were spent, so the bill is written first and its failure is a
1132
+ // log line, never a failed job — the same rule the chat route keeps.
1133
+ try {
1134
+ var _job_hostId1, _reservation_free;
1135
+ await recordAssistCost(firestore, orgId, {
1136
+ route: 'ai/jobs',
1137
+ hostId: (_job_hostId1 = job.hostId) != null ? _job_hostId1 : null,
1138
+ model: outcome.model,
1139
+ tier: entitled ? 'entitled' : 'free',
1140
+ usage: outcome.usage,
1141
+ docsPaths: [],
1142
+ stopReason: outcome.stopReason,
1143
+ deflected: false,
1144
+ // The account this job drew on, as the reservation decided it
1145
+ // (AGL-2925): a Free job lands on the owner's allowance and the
1146
+ // platform's day; a paid one on neither.
1147
+ free: (_reservation_free = reservation.free) != null ? _reservation_free : null,
1148
+ // The step is the creator's spend, under the job's kind (AGL-2928).
1149
+ uid: job.createdBy,
1150
+ kind: job.kind
1151
+ }, now);
1152
+ } catch (error) {
1153
+ console.error('ai job cost record failed', {
1154
+ orgId,
1155
+ jobId,
1156
+ error
1157
+ });
1158
+ }
1159
+ }
1160
+ const credits = assistCreditsFromUsd(outcome.estCostUsd);
1161
+ // A model that declined, or a step that got nothing usable out of the
1162
+ // model's answer (AGL-2938), fails the job with its own sentence. The
1163
+ // tokens are already on the bill above.
1164
+ if (outcome.refused || outcome.failure) {
1165
+ const message = outcome.refused ? AI_JOB_REFUSED_COPY : outcome.failure;
1166
+ await recordStep(firestore, orgId, jobId, options.owner, stepIndex, {
1167
+ status: 'failed',
1168
+ creditsSpent: credits,
1169
+ error: message,
1170
+ tokens
1171
+ }, now);
1172
+ return {
1173
+ outcome: 'failed',
1174
+ job: await failAiJob(firestore, orgId, jobId, message, {
1175
+ stepIndex,
1176
+ error: outcome.refused ? 'stop_reason refusal' : `step failure: ${message}`
1177
+ }, now)
1178
+ };
1179
+ }
1180
+ // A step that stopped for a person parks the job in the same write that
1181
+ // records it (AGL-2935): a plan review completes the step, so confirming
1182
+ // runs the next one; a doctrine or limit review hands it back, so trying
1183
+ // again runs the same one.
1184
+ //
1185
+ // A step that asks to continue (AGL-2910) is recorded as this pass — its
1186
+ // cost, its credits, its outputs, its audit rows — and handed back as
1187
+ // `pending`, so the next claim runs the same step again. A step that stopped
1188
+ // for a person never continues: the review is what it waits on. The pass
1189
+ // cap is what stops a runner that never finishes: past it the pass is
1190
+ // recorded as the step's last, and what it produced stands.
1191
+ const review = outcome.review;
1192
+ const continuing = !review && Boolean(outcome.continue) && ((_step_passes = step.passes) != null ? _step_passes : 0) + 1 < aiJobStepMaxPasses(job.kind);
1193
+ if (!review && outcome.continue && !continuing) {
1194
+ console.warn('ai job step reached its pass cap', {
1195
+ orgId,
1196
+ jobId,
1197
+ stepIndex
1198
+ });
1199
+ }
1200
+ const recorded = await recordStep(firestore, orgId, jobId, options.owner, stepIndex, _extends({
1201
+ status: continuing || review && review.reason !== 'plan' ? 'pending' : 'done'
1202
+ }, continuing ? {
1203
+ continued: true
1204
+ } : {}, {
1205
+ creditsSpent: credits
1206
+ }, spentNothing ? {} : {
1207
+ tokens
1208
+ }, {
1209
+ outputs: outcome.outputs
1210
+ }, outcome.plan ? {
1211
+ plan: outcome.plan
1212
+ } : {}, review ? {
1213
+ review
1214
+ } : {}), now);
1215
+ const actor = (_options_actor = options.actor) != null ? _options_actor : {
1216
+ uid: job.createdBy
1217
+ };
1218
+ for (const output of outcome.outputs){
1219
+ var _output_versionId, _output_versionId1;
1220
+ await writeAiJobAudit(firestore, {
1221
+ action: 'ai.job.output',
1222
+ actorUid: job.createdBy,
1223
+ orgId,
1224
+ jobId,
1225
+ after: {
1226
+ resource: output.resource,
1227
+ id: output.id,
1228
+ versionId: (_output_versionId = output.versionId) != null ? _output_versionId : null,
1229
+ hostId: output.hostId,
1230
+ label: output.label,
1231
+ credits
1232
+ }
1233
+ });
1234
+ // The customer-visible row, one per output: the label names the thing,
1235
+ // never its text, which is the site's content.
1236
+ await logAiJobOutput(orgId, actor, {
1237
+ jobId,
1238
+ hostId: output.hostId,
1239
+ resource: {
1240
+ type: aiOutputTargetType(output.resource),
1241
+ id: output.id,
1242
+ name: output.label,
1243
+ versionId: (_output_versionId1 = output.versionId) != null ? _output_versionId1 : null
1244
+ }
1245
+ });
1246
+ }
1247
+ if (review && recorded.job.status === 'needs_review') {
1248
+ // Nobody parked the job but its own step, so the row names no actor, as
1249
+ // the meter's park does.
1250
+ await logAiJobNeedsInput(orgId, {
1251
+ uid: null
1252
+ }, {
1253
+ jobId,
1254
+ kind: job.kind,
1255
+ reason: review.reason
1256
+ });
1257
+ return {
1258
+ outcome: 'needs_review',
1259
+ job: recorded.job
1260
+ };
1261
+ }
1262
+ if (recorded.remaining > 0 || isAiJobTerminal(recorded.job.status)) {
1263
+ return {
1264
+ outcome: 'done',
1265
+ job: recorded.job
1266
+ };
1267
+ }
1268
+ return {
1269
+ outcome: 'done',
1270
+ job: await completeAiJob(firestore, orgId, jobId, now)
1271
+ };
1272
+ }
1273
+ /**
1274
+ * Every job the beat should look at, oldest first: queued and running
1275
+ * across every org, then `needs_input` jobs that have rested long enough
1276
+ * for the org's standing to have changed. Two queries rather than one, so
1277
+ * a workspace with many parked jobs cannot fill the candidate list and
1278
+ * starve the queue behind it. Both use the collection-group index on
1279
+ * (status, updatedAt).
1280
+ *
1281
+ * The ordering is the cursor. A job this sweep touches has its `updatedAt`
1282
+ * moved and goes to the back of the next query; one it did not reach keeps
1283
+ * its place at the front. So there is no stored position to fall behind
1284
+ * or skip past — the same shape `media-move.ts` gives its budgeted loop,
1285
+ * where what was not done is simply what is asked for next.
1286
+ */ export async function listDueAiJobs(firestore, nowMs, maxJobs = AI_JOB_SWEEP_MAX_JOBS, maxParked = AI_JOB_SWEEP_MAX_PARKED) {
1287
+ const group = firestore.collectionGroup(AI_JOBS_COLLECTION);
1288
+ const [active, parked] = await Promise.all([
1289
+ group.where('status', 'in', [
1290
+ 'queued',
1291
+ 'running'
1292
+ ]).orderBy('updatedAt', 'asc').limit(maxJobs).get(),
1293
+ group.where('status', '==', 'needs_input').where('updatedAt', '<=', new Date(nowMs - AI_JOB_NEEDS_INPUT_RETRY_MS)).orderBy('updatedAt', 'asc').limit(maxParked).get()
1294
+ ]);
1295
+ return [
1296
+ ...active.docs,
1297
+ ...parked.docs
1298
+ ].map((doc)=>{
1299
+ var _doc_get;
1300
+ return {
1301
+ orgId: String((_doc_get = doc.get('orgId')) != null ? _doc_get : ''),
1302
+ jobId: doc.id
1303
+ };
1304
+ }).filter((due)=>due.orgId !== '');
1305
+ }
1306
+ /**
1307
+ * Run due steps until the budget is spent, and account for every candidate.
1308
+ *
1309
+ * The bound is wall clock, not a count, for the reason `media-move.ts`
1310
+ * gives: one step is one provider round trip of unknown length, so any
1311
+ * fixed number would be wrong for some brief. The budget is checked BETWEEN
1312
+ * jobs, and the step in flight gets the time that is left as its abort
1313
+ * signal, so the sweep still finishes whichever step it has started. At
1314
+ * least one candidate is always attempted, so a beat that yields having
1315
+ * done nothing cannot starve a queue behind a slow clock.
1316
+ *
1317
+ * A `needs_input` job is re-queued before its step is claimed, because the
1318
+ * claim admits only queued and running jobs; the reservation inside the
1319
+ * step is what decides whether the org's standing has changed.
1320
+ */ export async function sweepAiJobs(options) {
1321
+ var _options_now, _options_budgetMs, _options_listDue, _options_runStep;
1322
+ const now = (_options_now = options.now) != null ? _options_now : Date.now;
1323
+ const budgetMs = (_options_budgetMs = options.budgetMs) != null ? _options_budgetMs : AI_JOB_SWEEP_BUDGET_MS;
1324
+ const startedAt = now();
1325
+ const listDue = (_options_listDue = options.listDue) != null ? _options_listDue : ()=>listDueAiJobs(options.firestore, now(), options.maxJobs);
1326
+ const runStep = (_options_runStep = options.runStep) != null ? _options_runStep : (orgId, jobId, stepOptions)=>runAiJobStep(options.firestore, orgId, jobId, stepOptions);
1327
+ const due = await listDue();
1328
+ const result = {
1329
+ due: due.length,
1330
+ ran: 0,
1331
+ skipped: 0,
1332
+ paused: 0,
1333
+ remaining: 0,
1334
+ budgetExhausted: false
1335
+ };
1336
+ // Jobs a run left with more of a timed step to do, in the order they ran.
1337
+ const again = [];
1338
+ const attempt = async (candidate, left, first)=>{
1339
+ const { orgId, jobId } = candidate;
1340
+ try {
1341
+ const current = await getAiJob(options.firestore, orgId, jobId);
1342
+ // A step that needs more time than is left is not started (AGL-2907): a
1343
+ // provider call the abort cuts off is billed upstream and metered
1344
+ // nowhere. The job is left as it is, so it keeps its place at the front
1345
+ // of the next beat's queue.
1346
+ const minimumMs = current ? aiJobNextStepMinimumMs(current) : 0;
1347
+ if (minimumMs > left) {
1348
+ if (first) result.remaining += 1;
1349
+ return;
1350
+ }
1351
+ if ((current == null ? void 0 : current.status) === 'needs_input') {
1352
+ await transition(options.firestore, orgId, jobId, (job)=>job.status === 'needs_input' ? {
1353
+ status: 'queued',
1354
+ updatedAt: new Date(now())
1355
+ } : null);
1356
+ }
1357
+ const run = await runStep(orgId, jobId, {
1358
+ owner: options.owner,
1359
+ now: new Date(now()),
1360
+ signal: AbortSignal.timeout(left)
1361
+ });
1362
+ if (run.outcome === 'not-claimable') {
1363
+ if (first) result.skipped += 1;
1364
+ return;
1365
+ }
1366
+ if (run.outcome === 'paused') {
1367
+ if (first) result.paused += 1;
1368
+ return;
1369
+ }
1370
+ result.ran += 1;
1371
+ // Only a step that says how long it needs is run again in this sweep:
1372
+ // one that does not could start with too little time left.
1373
+ if (run.outcome === 'done' && run.job.status === 'queued' && aiJobNextStepMinimumMs(run.job) > 0) {
1374
+ again.push(candidate);
1375
+ }
1376
+ } catch (error) {
1377
+ // One job's fault is isolated, as the runner isolates one job's.
1378
+ console.error('ai job sweep step failed', {
1379
+ orgId,
1380
+ jobId,
1381
+ error
1382
+ });
1383
+ if (first) result.skipped += 1;
1384
+ }
1385
+ };
1386
+ for(let index = 0; index < due.length; index += 1){
1387
+ const elapsed = now() - startedAt;
1388
+ if (index > 0 && elapsed >= budgetMs) {
1389
+ result.budgetExhausted = true;
1390
+ result.remaining += due.length - index;
1391
+ return result;
1392
+ }
1393
+ await attempt(due[index], Math.max(1000, budgetMs - elapsed), true);
1394
+ }
1395
+ // Once every due job has had its turn, a job whose timed step has more to
1396
+ // do runs again while the time it needs is left (AGL-2907): a page built a
1397
+ // section a pass otherwise waits a beat between sections. Bounded by the
1398
+ // budget, and by the sweep's candidate count so no clock is trusted alone.
1399
+ for(let round = 0; again.length && round < AI_JOB_SWEEP_MAX_JOBS; round += 1){
1400
+ const elapsed = now() - startedAt;
1401
+ if (elapsed >= budgetMs) {
1402
+ result.budgetExhausted = true;
1403
+ break;
1404
+ }
1405
+ await attempt(again.shift(), budgetMs - elapsed, false);
1406
+ }
1407
+ return result;
1408
+ }
1409
+
1410
+ //# sourceMappingURL=ai-jobs.js.map