@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 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-jobs.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `FieldValue` straight from the SDK rather than through `./firebase-admin`,\n * for the reason `assist-usage.ts` gives: the default-app initialization\n * would ride into every unit test that touches a job, and the statics need\n * no app at all.\n */\nimport { FieldValue } from 'firebase-admin/firestore'\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { checkEntitlement } from '@aglyn/aglyn/server'\nimport {\n assistCreditsFromUsd,\n assistFreeTasteRefusalText,\n assistHardCapRefusalText,\n assistRefusedByHardCap,\n} from '@aglyn/aglyn/app-utils/assist-credits'\nimport {\n AI_JOB_TERMINAL_STATUSES,\n type AiJob,\n type AiJobApplied,\n type AiJobKind,\n type AiJobOutput,\n type AiJobPlan,\n type AiJobReview,\n type AiJobStatus,\n type AiJobStep,\n type AiJobStepTokens,\n type AiJobSummary,\n} from '../model/ai-jobs.types'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { aiOverageReservationRefusal } from '../billing/ai-overage-gate'\nimport { aiAllotmentRefusalText } from '../model/ai-allotments'\nimport { aiJobPlanCreditEstimate } from '../model/ai-site-job'\nimport { AI_OFF_FOR_SITE_COPY, isAiOffForSite } from '../model/ai-site-switch'\nimport { resolveAiModelChoice } from '../providers/model-choice'\nimport { aiOutputTargetType } from '../activity/ai-activity-actions'\nimport {\n logAiJobCanceled,\n logAiJobCreated,\n logAiJobNeedsInput,\n logAiJobOutput,\n type AiActivityActor,\n} from '../activity/ai-activity'\nimport {\n AI_UPSTREAM_FAILURE_COPY,\n AiUpstreamError,\n type AiEffort,\n type AiUsage,\n} from '../runtime/ai-runtime'\nimport { recordUserAiRefusal } from '../usage/ai-usage-by-user'\nimport { AI_JOB_INLINE_BUDGET_MS, AI_JOB_SWEEP_BUDGET_MS } from './ai-job-budget'\nimport { aiMintJobDraftIds } from './ai-job-draft-ids'\nimport {\n AI_JOB_TEXT_STEP_MINIMUM_MS,\n runAiJobTextStep,\n type AiJobStepOutcome,\n type AiJobStepRunner,\n} from './ai-job-text-step'\nimport { AI_JOB_SEO_STEP_MINIMUM_MS } from './ai-job-seo-budget'\nimport { AI_JOB_THEME_STEP_MINIMUM_MS } from './ai-job-theme-budget'\nimport {\n assistExchangeExpiry,\n recordAssistCost,\n releaseAssistMessage,\n reserveAssistMessage,\n type AssistReservation,\n} from '../usage/assist-usage'\n\n/**\n * AI generation jobs — the Firestore state machine (AGL-2904).\n *\n * One document per job under the org, written only by this module through\n * the Admin SDK; the rules let a member READ their org's jobs and nobody\n * write them. The console route creates a job and runs its first step\n * inline when it can; the AI jobs beat, a console route of its own, claims\n * and runs whatever is queued, across every org, inside a wall-clock budget\n * (`ai-jobs-beat.ts`). Both go through\n * `runAiJobStep`, so there is exactly one place a step is claimed, metered,\n * run and recorded.\n *\n * ── Credits, per step ────────────────────────────────────────────────────\n *\n * Every step is an assist message to the meter: `reserveAssistMessage`\n * BEFORE the provider is called — the same read-and-increment transaction\n * the chat route takes, so a job cannot slip past the org's monthly ceiling\n * by being asynchronous — and `recordAssistCost` after, at the serving\n * model's rates, so the usage rollup and the invoice see a job's tokens\n * exactly as they see a chat turn's. The credit figure on the job is that\n * cost at the plan's credit rate, rounded up like every other credit.\n *\n * A refused reservation is NOT a failure. The org is out of credits, over\n * its cap, or has switched overage off — all things a member can change —\n * so the job parks as `needs_input` with the refusal in customer-safe words\n * and the beat tries it again once it has rested. `failed` is reserved for\n * a step that cannot succeed by waiting.\n *\n * ── What a step may not do ───────────────────────────────────────────────\n *\n * A step runner writes drafts and returns. It does not touch the job\n * document, the meter or the lease: the machine owns those, so a runner\n * written next month cannot forget the reservation or record itself done\n * while the provider is still generating.\n */\n\nexport const AI_JOBS_COLLECTION = 'aiJobs'\n\n/**\n * How long a claim holds the step: longer than the longest any holder can\n * still be running it, which is the beat route's 300 s function ceiling\n * (AGL-3026). A lease that ran out under a live holder would let the next\n * beat claim the same step and call the provider for it a second time, and\n * the beat fires every minute while a sweep may run for most of five, so\n * this is what keeps overlapping beats apart. A step abandoned by a process\n * that died is recovered once it runs out, by the first beat after that.\n */\nexport const AI_JOB_LEASE_MS = 330_000\n\n/** A step handed back by a retryable provider failure this many times fails. */\nexport const AI_JOB_STEP_MAX_ATTEMPTS = 3\n\n/**\n * The most passes one step may take by asking to continue (AGL-2910), for a\n * kind that registers no bound of its own. A site audit's passes are its\n * units of generated work; this bounds a runner that never finishes, not a\n * real site.\n */\nexport const AI_JOB_STEP_MAX_PASSES = 40\n\n/**\n * The nominal credit figure shown as held per outstanding step. Not a\n * bound — the reservation and the monthly ceiling are — but the console\n * must show a running job as costing something before its bill is known.\n *\n * NOMINAL, and nothing reads it as more (AGL-3030): the band, the Free\n * taste's account allowance and every refusal are measured on recorded\n * spend, and the one real reservation a step takes is a message, counted\n * when the step is claimed and settled — metered or handed back — before the\n * step is recorded. So a job holds nothing real between steps, and a job\n * parked for a person shows nothing held either: `recordStep` releases the\n * figure when a step parks for review, and `resumeAiJob` holds it again for\n * the steps a person's resume queues.\n */\nexport const AI_JOB_STEP_RESERVE_CREDITS = 50\n\n/**\n * The inline doors' budget and the beat's, declared beside the time a step is\n * planned against (`ai-job-budget.ts`, AGL-3036) so a step's least time and\n * the budgets it has to fit are read in one place.\n */\nexport { AI_JOB_INLINE_BUDGET_MS, AI_JOB_SWEEP_BUDGET_MS }\n\n/** Jobs one beat reads as candidates; the budget usually stops it first. */\nexport const AI_JOB_SWEEP_MAX_JOBS = 25\n\n/** Parked jobs one beat re-queues, on top of the active candidates. */\nexport const AI_JOB_SWEEP_MAX_PARKED = 5\n\n/** How long a `needs_input` job rests before the beat tries its reservation again. */\nexport const AI_JOB_NEEDS_INPUT_RETRY_MS = 60 * 60_000\n\nexport const AI_JOB_NOT_AVAILABLE_COPY =\n 'This kind of AI job is not available yet.'\nexport const AI_JOB_REFUSED_COPY =\n 'The model declined this brief. Try rephrasing it.'\n\ntype Firestore = FirebaseFirestore.Firestore\ntype Transaction = FirebaseFirestore.Transaction\n\n/** A stored instant as the SDK returns it, or as this module wrote it. */\ntype Instant = Date | { toMillis(): number } | number | string | null | undefined\n\nfunction toMillis(value: Instant): number | null {\n if (value == null) return null\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'number') return value\n if (typeof value === 'string') {\n const parsed = Date.parse(value)\n return Number.isFinite(parsed) ? parsed : null\n }\n return typeof value.toMillis === 'function' ? value.toMillis() : null\n}\n\nfunction toIso(value: Instant): string | null {\n const millis = toMillis(value)\n return millis === null ? null : new Date(millis).toISOString()\n}\n\nexport function isAiJobTerminal(status: AiJobStatus): boolean {\n return AI_JOB_TERMINAL_STATUSES.includes(status)\n}\n\n// ── The step runner registry ──────────────────────────────────────────────\n\n/** The step a planned kind runs first (AGL-2935). */\nexport const AI_JOB_PLAN_STEP = 'plan'\n\n/**\n * The kinds that build site structure, and so plan before they generate\n * (AGL-2935): the plan their first step proposes is what their generation\n * step executes, once a person has confirmed it.\n */\nexport const AI_PLANNED_JOB_KINDS: readonly AiJobKind[] = [\n 'page',\n 'site',\n 'component',\n 'layout',\n 'template',\n 'form',\n 'email',\n]\n\nconst stepRunners = new Map<AiJobKind, AiJobStepRunner>()\nconst stepMinimums = new Map<AiJobKind, number>()\nconst stepRunMinimums = new Map<AiJobKind, (job: AiJob) => number>()\nlet planStepRunner: AiJobStepRunner | null = null\n/** The plan step's least time: one step every planned kind shares, so kept by the step, not by a kind. */\nlet planStepMinimumMs = 0\nconst stepPassCaps = new Map<AiJobKind, number>()\n\nexport interface AiJobStepRegistration {\n /**\n * The least time, in milliseconds, one run of the kind's step needs before\n * it starts (AGL-2907): its generation's worst case at the rates\n * `ai-job-budget.ts` assumes — every model call it may make, with the step's\n * own reads and writes (AGL-3036). The beat leaves the step queued rather\n * than start it with less time left, and an inline door leaves it for the\n * beat, because a provider call the caller's budget cuts off is still\n * generated and billed upstream while the meter records nothing.\n *\n * Every generation step the plugin registers declares one (AGL-3035), and a\n * spec over the console surface's registrations fails on a step that does\n * not. Absent, the step starts whenever it is claimed.\n */\n minimumMs?: number\n /**\n * For a step whose runs need different times, the least time the run this\n * job would make next needs (AGL-3035): a page job's pass that builds a\n * layout needs a layout's time, where its section passes need a section's,\n * and a scaffold's pass needs what the unit it hands on needs. Never read as\n * less than `minimumMs`, which is then the least any run of the step needs.\n */\n minimumMsFor?: (job: AiJob) => number\n}\n\n/** Idempotent per kind; last registration wins. */\nexport function registerAiJobStep(\n kind: AiJobKind,\n runner: AiJobStepRunner,\n registration: AiJobStepRegistration = {},\n): void {\n stepRunners.set(kind, runner)\n if (registration.minimumMs && registration.minimumMs > 0) {\n stepMinimums.set(kind, registration.minimumMs)\n } else {\n stepMinimums.delete(kind)\n }\n if (registration.minimumMsFor) {\n stepRunMinimums.set(kind, registration.minimumMsFor)\n } else {\n stepRunMinimums.delete(kind)\n }\n}\n\n/**\n * The least time a step needs before it starts: the plan step's own minimum\n * for the plan step of any kind (AGL-3026), and the kind's registered\n * minimum for the kind's own step — the least any run of it needs.\n */\nexport function aiJobStepMinimumMs(kind: AiJobKind, stepName: string): number {\n return stepName === AI_JOB_PLAN_STEP ? planStepMinimumMs : (stepMinimums.get(kind) ?? 0)\n}\n\n/**\n * The least time the next run of a job's own step needs (AGL-3035): what the\n * kind registered, or more where the kind says this job's next run needs\n * more. A step that delegates a unit to another kind — a page job's creation,\n * a scaffold's page — asks this of the job it derives for the unit.\n */\nexport function aiJobStepRunMinimumMs(job: AiJob): number {\n const least = stepMinimums.get(job.kind) ?? 0\n const forRun = stepRunMinimums.get(job.kind)\n return forRun ? Math.max(least, forRun(job)) : least\n}\n\n/** The least time the job's next step needs; 0 when no step is left to run. */\nexport function aiJobNextStepMinimumMs(job: AiJob): number {\n const index = nextStepIndex(job)\n if (index === -1) return 0\n return job.steps[index].name === AI_JOB_PLAN_STEP ? planStepMinimumMs : aiJobStepRunMinimumMs(job)\n}\n\nexport function aiJobStepRunnerFor(kind: AiJobKind): AiJobStepRunner | null {\n return stepRunners.get(kind) ?? null\n}\n\n/**\n * A kind whose step works through more units than the default bounds\n * (AGL-2911). A scaffold's unit is a whole page and its site is eight of\n * them, where an audit's is one page's listing, so the runaway bound the\n * default gives an audit would cut a real site short. The kind registers its\n * own beside its runner, so the machine keeps no list of kinds and the bound\n * sits with the plan that explains it.\n */\nexport function registerAiJobStepPasses(kind: AiJobKind, maxPasses: number): void {\n stepPassCaps.set(kind, Math.max(1, Math.floor(maxPasses)))\n}\n\n/** The passes a kind's step may take; the default where it registered none. */\nexport function aiJobStepMaxPasses(kind: AiJobKind): number {\n return stepPassCaps.get(kind) ?? AI_JOB_STEP_MAX_PASSES\n}\n\n/**\n * The plan step every planned kind runs first. Registered by its own module\n * (`ai-job-plan-step.ts`), which the plugin's server surface loads, so this\n * machine — and every spec that drives it — never loads the inventory\n * reader and the Admin SDK behind it. `null` unregisters it, minimum and all.\n *\n * `minimumMs` means for the plan step what it means for a kind's step\n * (AGL-3026): a plan answered at its ceiling takes longer than an inline\n * door's budget, so the step says so, and both doors leave it for the beat.\n */\nexport function registerAiJobPlanStep(\n runner: AiJobStepRunner | null,\n registration: AiJobStepRegistration = {},\n): void {\n planStepRunner = runner\n planStepMinimumMs =\n runner && registration.minimumMs && registration.minimumMs > 0 ? registration.minimumMs : 0\n}\n\n/**\n * Whether AI generation is paused for a workspace, as the jobs doors read it\n * (AGL-3037). `staff` is a verified staff caller on an inline door; the beat\n * has none.\n */\nexport type AiJobPauseReader = (input: { orgId: string; staff: boolean }) => Promise<boolean>\n\nlet pauseReader: AiJobPauseReader | null = null\n\n/**\n * The reader `runAiJobStep` asks before it claims a step. Registered by its\n * own module (`ai-jobs-pause.ts`), which the plugin's console surface calls,\n * so this machine — and every spec that drives it — never loads the Admin SDK\n * the lockdown reads run on. `null` unregisters it; a machine with no reader\n * runs every job, as a process with no lockdown carrier would.\n */\nexport function registerAiJobPauseReader(reader: AiJobPauseReader | null): void {\n pauseReader = reader\n}\n\n/** Whether a pause reader is registered: what a surface that runs jobs must have. */\nexport function aiJobPauseReaderRegistered(): boolean {\n return pauseReader !== null\n}\n\n/**\n * The registered reader's answer. A read that throws is not a pause: the\n * lockdown carriers fail open on an unreachable Firestore, and so does this.\n */\nasync function aiJobPausedFor(orgId: string, jobId: string, staff: boolean): Promise<boolean> {\n if (!pauseReader) return false\n try {\n return await pauseReader({ orgId, staff })\n } catch (error) {\n console.error('ai job pause read failed', { orgId, jobId, error })\n return false\n }\n}\n\n/** The runner for one step of one job: the plan step by its name, else the kind's own. */\nexport function aiJobRunnerForStep(kind: AiJobKind, stepName: string): AiJobStepRunner | null {\n return stepName === AI_JOB_PLAN_STEP ? planStepRunner : aiJobStepRunnerFor(kind)\n}\n\n/**\n * The step names a job of this kind carries, in order. A planned kind plans\n * only once something can build the plan: until its generation runner is\n * registered, its job fails fast and free, rather than spending on a plan\n * nothing will execute.\n */\nexport function aiJobStepNames(kind: AiJobKind): string[] {\n if (kind === 'text') return ['draft']\n return AI_PLANNED_JOB_KINDS.includes(kind) && planStepRunner && stepRunners.has(kind)\n ? [AI_JOB_PLAN_STEP, 'generate']\n : ['generate']\n}\n\n/**\n * The text step (AGL-2904). Every kind with no runner refuses until its issue\n * lands. Its least time fits an inline door's budget (AGL-3035), so the doors\n * run a text job where it is asked for.\n */\nregisterAiJobStep('text', runAiJobTextStep, { minimumMs: AI_JOB_TEXT_STEP_MINIMUM_MS })\n\n/**\n * The theme step (AGL-2938), loaded the first time a theme job runs rather\n * than when this module does: it builds the brand themes it measures\n * contrast against and may read a site's logo, and a process that never runs\n * a theme job should pay for neither. Its least time is declared apart from\n * the step (`ai-job-theme-budget.ts`, AGL-3035) for the same reason.\n */\nregisterAiJobStep(\n 'theme',\n async (context) => {\n const { runAiJobThemeStep } = await import('./ai-job-theme-step')\n return runAiJobThemeStep(context)\n },\n { minimumMs: AI_JOB_THEME_STEP_MINIMUM_MS },\n)\n\n/**\n * The SEO step (AGL-2910), loaded the first time an SEO job runs rather than\n * when this module does: it reads pages, versions and layouts, and a process\n * that never runs one should load none of that. Its least time is declared\n * apart from the step (`ai-job-seo-budget.ts`, AGL-3035) for the same reason.\n */\nregisterAiJobStep(\n 'seo',\n async (context) => {\n const { runAiJobSeoStep } = await import('./ai-job-seo-step')\n return runAiJobSeoStep(context)\n },\n { minimumMs: AI_JOB_SEO_STEP_MINIMUM_MS },\n)\n\n// ── Documents ─────────────────────────────────────────────────────────────\n\nfunction jobsCollection(firestore: Firestore, orgId: string) {\n return firestore.collection('orgs').doc(orgId).collection(AI_JOBS_COLLECTION)\n}\n\nfunction jobFrom(\n snapshot: FirebaseFirestore.DocumentSnapshot,\n): AiJob | null {\n if (!snapshot.exists) return null\n const data = snapshot.data() as Omit<AiJob, '$id'>\n return { ...data, $id: snapshot.id }\n}\n\nexport interface CreateAiJobInput {\n orgId: string\n hostId?: string | null\n kind: AiJobKind\n brief: string\n inputs?: Record<string, unknown>\n /** The model the creator picked (AGL-2942); absent or `null` for Auto. */\n model?: string | null\n createdBy: string\n /** The creator's address, for the activity row; the document stores the uid only. */\n createdByEmail?: string | null\n}\n\n/**\n * A new job, `queued`, with its step plan laid out and nothing run.\n *\n * The activity row is written once the document is, so the feed never names\n * a job that does not exist. The brief's length stands in for the brief,\n * which is the customer's own text and is not logged (AGL-2929).\n */\nexport async function createAiJob(\n firestore: Firestore,\n input: CreateAiJobInput,\n now = new Date(),\n): Promise<AiJob> {\n const brief = input.brief.trim()\n if (!brief) throw new Error('an AI job needs a brief')\n // The drafts the kind always writes are named before any step runs, on the\n // step that writes them, so a run repeated after its write finds them.\n const draftIds = aiMintJobDraftIds(input.kind)\n const steps: AiJobStep[] = aiJobStepNames(input.kind).map((name) => ({\n name,\n status: 'pending',\n startedAt: null,\n endedAt: null,\n creditsSpent: 0,\n error: null,\n attempts: 0,\n ...(draftIds && name !== AI_JOB_PLAN_STEP ? { draftIds } : {}),\n }))\n // A job is a resource the console lists and routes to, named as one.\n const ref = jobsCollection(firestore, input.orgId).doc(createResourceUid())\n const data = {\n orgId: input.orgId,\n hostId: input.hostId ?? null,\n kind: input.kind,\n status: 'queued' as AiJobStatus,\n brief,\n inputs: input.inputs ?? {},\n model: input.model ?? null,\n steps,\n outputs: [] as AiJobOutput[],\n creditsReserved: steps.length * AI_JOB_STEP_RESERVE_CREDITS,\n creditsSpent: 0,\n createdBy: input.createdBy,\n createdAt: now,\n updatedAt: now,\n // The brief is verbatim customer text, so it expires on the same clock\n // as an assist exchange; the TTL policy keys on this field.\n expiresAt: assistExchangeExpiry(now),\n error: null,\n lease: null,\n }\n await ref.set(data)\n await logAiJobCreated(\n input.orgId,\n { uid: input.createdBy, email: input.createdByEmail ?? null },\n {\n jobId: ref.id,\n kind: input.kind,\n briefLength: brief.length,\n hostId: input.hostId ?? null,\n },\n )\n return { ...(data as unknown as Omit<AiJob, '$id'>), $id: ref.id }\n}\n\nexport async function getAiJob(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n): Promise<AiJob | null> {\n return jobFrom(await jobsCollection(firestore, orgId).doc(jobId).get())\n}\n\nexport interface ListAiJobsOptions {\n status?: AiJobStatus\n limit?: number\n}\n\n/** Newest first. Needs the (status, createdAt) index when filtered. */\nexport async function listAiJobs(\n firestore: Firestore,\n orgId: string,\n options: ListAiJobsOptions = {},\n): Promise<AiJob[]> {\n const limit = Math.min(Math.max(1, Math.floor(options.limit ?? 20)), 100)\n let query: FirebaseFirestore.Query = jobsCollection(firestore, orgId)\n if (options.status) query = query.where('status', '==', options.status)\n const snapshot = await query.orderBy('createdAt', 'desc').limit(limit).get()\n return snapshot.docs\n .map((doc) => jobFrom(doc))\n .filter((job): job is AiJob => job !== null)\n}\n\n/** The wire form. `running` is the lease, read against `now`. */\nexport function aiJobSummary(job: AiJob, now = new Date()): AiJobSummary {\n const leaseUntil = toMillis(job.lease?.until as Instant)\n return {\n id: job.$id,\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n kind: job.kind,\n status: job.status,\n brief: job.brief,\n batch: typeof job.inputs?.['batchId'] === 'string' ? job.inputs['batchId'] : null,\n steps: (job.steps ?? []).map((step) => ({\n name: step.name,\n status: step.status,\n startedAt: toIso(step.startedAt as Instant),\n endedAt: toIso(step.endedAt as Instant),\n creditsSpent: step.creditsSpent ?? 0,\n error: step.error ?? null,\n })),\n outputs: job.outputs ?? [],\n creditsReserved: job.creditsReserved ?? 0,\n creditsSpent: job.creditsSpent ?? 0,\n createdBy: job.createdBy,\n createdAt: toIso(job.createdAt as Instant) ?? new Date(0).toISOString(),\n updatedAt: toIso(job.updatedAt as Instant) ?? new Date(0).toISOString(),\n error: job.error ?? null,\n running:\n job.status === 'running' &&\n leaseUntil !== null &&\n leaseUntil > now.getTime(),\n plan: job.plan\n ? {\n ...job.plan,\n labels: job.plan.labels ?? {},\n proposedAt: toIso(job.plan.proposedAt as Instant),\n confirmedAt: toIso(job.plan.confirmedAt as Instant),\n confirmedBy: job.plan.confirmedBy ?? null,\n }\n : null,\n review: job.review ?? null,\n applied: job.applied\n ? {\n at: toIso(job.applied.at as Instant),\n by: job.applied.by,\n versions: job.applied.versions ?? {},\n staged: job.applied.staged ?? [],\n }\n : null,\n }\n}\n\n// ── The lease ─────────────────────────────────────────────────────────────\n\nexport interface ClaimedAiJobStep {\n job: AiJob\n stepIndex: number\n}\n\nfunction leaseIsLive(job: AiJob, owner: string, nowMs: number): boolean {\n const lease = job.lease\n if (!lease) return false\n if (lease.owner === owner) return false\n const until = toMillis(lease.until as Instant)\n return until !== null && until > nowMs\n}\n\nfunction nextStepIndex(job: AiJob): number {\n return (job.steps ?? []).findIndex(\n (step) => step.status === 'pending' || step.status === 'running',\n )\n}\n\n/**\n * The step a claim by `owner` would take, or -1 when there is none to take:\n * the job is terminal or parked, has no step left, or ANOTHER owner's lease\n * has not yet expired.\n */\nfunction claimableStepIndex(job: AiJob, owner: string, nowMs: number): number {\n if (job.status !== 'queued' && job.status !== 'running') return -1\n if (leaseIsLive(job, owner, nowMs)) return -1\n return nextStepIndex(job)\n}\n\n/**\n * Take the lease on the job's next step, in one transaction.\n *\n * Refuses — `null` — when the job is terminal or parked, when it has no\n * step left, or when ANOTHER owner's lease has not yet expired. That last\n * clause is the whole point: the console route and two overlapping beats\n * can all look at one job inside the same minute, and only one of them may\n * spend the reservation for its step. An expired lease is claimable, which\n * is how a step abandoned mid-flight by a frozen process is recovered — the\n * stale lease is released by being taken, not by a sweep of its own.\n */\nexport async function claimNextStep(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n owner: string,\n now = new Date(),\n): Promise<ClaimedAiJobStep | null> {\n const ref = jobsCollection(firestore, orgId).doc(jobId)\n return firestore.runTransaction(async (tx: Transaction) => {\n const job = jobFrom(await tx.get(ref))\n if (!job) return null\n const stepIndex = claimableStepIndex(job, owner, now.getTime())\n if (stepIndex === -1) return null\n const steps = job.steps.map((step, index) =>\n index === stepIndex\n ? {\n ...step,\n status: 'running' as const,\n startedAt: step.startedAt ?? now,\n attempts: (step.attempts ?? 0) + 1,\n }\n : step,\n )\n const lease = { owner, until: new Date(now.getTime() + AI_JOB_LEASE_MS) }\n tx.set(\n ref,\n { status: 'running', steps, lease, updatedAt: now },\n { merge: true },\n )\n return {\n job: {\n ...job,\n status: 'running',\n steps: steps as AiJob['steps'],\n lease: lease as unknown as AiJob['lease'],\n updatedAt: now as unknown as AiJob['updatedAt'],\n },\n stepIndex,\n }\n })\n}\n\n/**\n * Extend the lease while a long step is still running. `false` when the\n * caller no longer holds it — the step was recovered by someone else, and\n * the caller's result must not overwrite theirs.\n */\nexport async function heartbeatStep(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n owner: string,\n now = new Date(),\n): Promise<boolean> {\n const ref = jobsCollection(firestore, orgId).doc(jobId)\n return firestore.runTransaction(async (tx: Transaction) => {\n const job = jobFrom(await tx.get(ref))\n if (!job || job.status !== 'running' || job.lease?.owner !== owner) {\n return false\n }\n tx.set(\n ref,\n {\n lease: { owner, until: new Date(now.getTime() + AI_JOB_LEASE_MS) },\n updatedAt: now,\n },\n { merge: true },\n )\n return true\n })\n}\n\n/**\n * Leave a job whose workspace's AI is paused where it is (AGL-3037), moved to\n * the back of the beat's queue. Nothing is claimed: its steps, their attempts\n * and its lease stay exactly as they were, so resuming AI runs the job from\n * where it stopped. Only `updatedAt` moves — the beat's queue is ordered by it,\n * and a paused workspace's jobs left at the front would fill every beat's\n * candidates and starve every other workspace's.\n *\n * `null`, writing nothing, for a job a claim would not take either: terminal,\n * parked, no step left, or another owner's live lease.\n */\nexport async function holdPausedAiJob(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n owner: string,\n now = new Date(),\n): Promise<AiJob | null> {\n const ref = jobsCollection(firestore, orgId).doc(jobId)\n return firestore.runTransaction(async (tx: Transaction) => {\n const job = jobFrom(await tx.get(ref))\n if (!job || claimableStepIndex(job, owner, now.getTime()) === -1) return null\n tx.set(ref, { updatedAt: now }, { merge: true })\n return { ...job, updatedAt: now as unknown as AiJob['updatedAt'] }\n })\n}\n\nexport interface RecordStepInput {\n /** `pending` hands the step back for another attempt. */\n status: 'done' | 'failed' | 'pending'\n creditsSpent: number\n error?: string | null\n outputs?: AiJobOutput[]\n /** The plan the step proposed, kept on the job (AGL-2935). */\n plan?: AiJobPlan\n /** The step stopped for a person: the job parks `needs_review` in this same write. */\n review?: AiJobReview\n /**\n * With `pending`: the step is handed back because it made progress and\n * asked to continue (AGL-2910), not because an attempt failed. Its\n * attempts count again from zero and its passes by one.\n */\n continued?: boolean\n /** What the run cost in tokens and time (AGL-2937), added to the step's totals. */\n tokens?: AiJobStepTokenRun\n}\n\n/** One run of a step's runner, as the machine measured it (AGL-2937). */\nexport interface AiJobStepTokenRun {\n usage: AiUsage\n model: string\n effort: AiEffort | null\n latencyMs: number\n /** Why the run's last model call stopped (AGL-3042). */\n stopReason: string | null\n}\n\n/**\n * The runs whose stop reasons a step's record keeps (AGL-3042), newest last.\n * A page job that builds a layout, a form and a component, then five sections\n * and its last pass, runs its generation step nine times: twelve keep such a\n * page whole with room for three retries.\n *\n * What it costs the document: an entry is at most 67 bytes as Firestore sizes\n * it (the two field names, 11 and 7; a stop reason, a provider's ASCII word of\n * at most `AI_JOB_STEP_STOP_REASON_MAX_CHARS` characters, 41; an integer, 8),\n * so a step's list is at most 813 bytes with its field name, and a job's two\n * steps at most 1,626 of the 1,048,576 bytes a document may hold.\n */\nexport const AI_JOB_STEP_LAST_RUNS = 12\n\n/** The longest stop reason a run's entry keeps; every one a provider names today is shorter. */\nexport const AI_JOB_STEP_STOP_REASON_MAX_CHARS = 40\n\n/**\n * A step's measure with one more run added: the four counts and the time\n * summed, the model and effort taken from the run, and why it stopped\n * appended to the latest runs (AGL-3042).\n */\nexport function addAiJobStepTokens(\n current: AiJobStepTokens | null | undefined,\n run: AiJobStepTokenRun,\n): AiJobStepTokens {\n const count = (value: unknown): number => {\n const parsed = Number(value ?? 0)\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0\n }\n const kept = Array.isArray(current?.lastRuns) ? current.lastRuns : []\n const stopReason =\n typeof run.stopReason === 'string' && run.stopReason\n ? run.stopReason.slice(0, AI_JOB_STEP_STOP_REASON_MAX_CHARS)\n : null\n return {\n input: count(current?.input) + count(run.usage.inputTokens),\n cachedRead: count(current?.cachedRead) + count(run.usage.cacheReadTokens),\n cacheWrite: count(current?.cacheWrite) + count(run.usage.cacheWriteTokens),\n output: count(current?.output) + count(run.usage.outputTokens),\n model: run.model || current?.model || null,\n effort: run.effort ?? null,\n latencyMs: count(current?.latencyMs) + count(run.latencyMs),\n runs: count(current?.runs) + 1,\n lastRuns: [...kept, { stopReason, output: count(run.usage.outputTokens) }].slice(-AI_JOB_STEP_LAST_RUNS),\n }\n}\n\nexport interface RecordedStep {\n job: AiJob\n /** Steps still to run after this one. */\n remaining: number\n}\n\n/**\n * Record what a step cost and produced, and hand the lease back.\n *\n * Credits and outputs are recorded whatever the job's status is by now —\n * a job canceled while its provider call was in flight still spent the\n * tokens, and hiding that would make the bill disagree with the document.\n * The status transition is the caller's next call (`completeAiJob`,\n * `failAiJob`), except that a step handed back or a step with more steps\n * behind it re-queues here, so the beat sees it without another write —\n * and a step that stopped for a person parks the job `needs_review` here,\n * in the same transaction, so no beat can claim the next step in between.\n */\nexport async function recordStep(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n owner: string,\n stepIndex: number,\n input: RecordStepInput,\n now = new Date(),\n): Promise<RecordedStep> {\n const ref = jobsCollection(firestore, orgId).doc(jobId)\n return firestore.runTransaction(async (tx: Transaction) => {\n const job = jobFrom(await tx.get(ref))\n if (!job) throw new Error(`ai job ${orgId}/${jobId} vanished`)\n const steps = job.steps.map((step, index) =>\n index === stepIndex\n ? {\n ...step,\n status: input.status,\n endedAt: input.status === 'pending' ? null : now,\n creditsSpent: (step.creditsSpent ?? 0) + input.creditsSpent,\n error: input.error ?? null,\n ...(input.continued && input.status === 'pending'\n ? { attempts: 0, passes: (step.passes ?? 0) + 1 }\n : {}),\n ...(input.tokens ? { tokens: addAiJobStepTokens(step.tokens, input.tokens) } : {}),\n }\n : step,\n )\n const remaining = steps.filter(\n (step) => step.status === 'pending' || step.status === 'running',\n ).length\n const settled = input.status !== 'pending'\n const ownsLease = job.lease?.owner === owner\n const parksForReview = Boolean(input.review) && !isAiJobTerminal(job.status)\n const status: AiJobStatus = isAiJobTerminal(job.status)\n ? job.status\n : job.status === 'needs_input'\n ? job.status\n : parksForReview\n ? 'needs_review'\n : input.status === 'failed'\n ? 'running'\n : remaining > 0\n ? 'queued'\n : 'running'\n const patch = {\n status,\n steps,\n outputs: [...(job.outputs ?? []), ...(input.outputs ?? [])],\n creditsSpent: (job.creditsSpent ?? 0) + input.creditsSpent,\n // A job parked for a person holds nothing: no step of it can run until\n // someone resumes it, and the resume holds the figure again (AGL-3030).\n creditsReserved: parksForReview\n ? 0\n : settled\n ? Math.max(0, (job.creditsReserved ?? 0) - AI_JOB_STEP_RESERVE_CREDITS)\n : (job.creditsReserved ?? 0),\n updatedAt: now,\n ...(ownsLease ? { lease: null } : {}),\n // A plan the step produced is kept whatever the job's status is by\n // now, for the reason its credits are.\n ...(input.plan ? { plan: input.plan } : {}),\n // A doctrine or limit review's sentence is the job's customer-safe\n // error, as a meter park's is; a plan waiting to be confirmed is not an\n // error.\n ...(parksForReview && input.review\n ? {\n review: input.review,\n error: input.review.reason === 'plan' ? null : input.review.message,\n }\n : {}),\n }\n tx.set(ref, patch, { merge: true })\n return {\n job: { ...job, ...(patch as unknown as Partial<AiJob>) } as AiJob,\n remaining,\n }\n })\n}\n\nasync function transition(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n apply: (job: AiJob) => Record<string, unknown> | null,\n): Promise<{ job: AiJob; changed: boolean }> {\n const ref = jobsCollection(firestore, orgId).doc(jobId)\n return firestore.runTransaction(async (tx: Transaction) => {\n const job = jobFrom(await tx.get(ref))\n if (!job) throw new Error(`ai job ${orgId}/${jobId} vanished`)\n const patch = apply(job)\n if (!patch) return { job, changed: false }\n tx.set(ref, patch, { merge: true })\n return {\n job: { ...job, ...(patch as unknown as Partial<AiJob>) } as AiJob,\n changed: true,\n }\n })\n}\n\n/** Every step done: the job is `done` and holds nothing. */\nexport async function completeAiJob(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n now = new Date(),\n): Promise<AiJob> {\n const { job } = await transition(firestore, orgId, jobId, (current) =>\n isAiJobTerminal(current.status)\n ? null\n : {\n status: 'done',\n creditsReserved: 0,\n lease: null,\n error: null,\n updatedAt: now,\n },\n )\n return job\n}\n\n/**\n * Terminal failure. `message` is the only thing a customer reads, so it is\n * a fixed sentence; whatever the provider or the runner actually said goes\n * to the log beside the ids an operator would search for.\n */\nexport async function failAiJob(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n message: string,\n detail?: { stepIndex?: number; error?: unknown },\n now = new Date(),\n): Promise<AiJob> {\n console.error('ai job failed', {\n orgId,\n jobId,\n stepIndex: detail?.stepIndex ?? null,\n error: detail?.error instanceof Error ? detail.error.message : detail?.error ?? null,\n })\n const { job } = await transition(firestore, orgId, jobId, (current) =>\n isAiJobTerminal(current.status)\n ? null\n : {\n status: 'failed',\n error: message,\n creditsReserved: 0,\n lease: null,\n steps: current.steps.map((step) =>\n step.status === 'running'\n ? { ...step, status: 'failed', endedAt: now, error: message }\n : step,\n ),\n updatedAt: now,\n },\n )\n return job\n}\n\n/**\n * Park the job for something only the workspace can change. The running\n * step goes back to `pending` so the same step is what runs when the beat\n * tries again; its attempt is not counted, because nothing was attempted.\n */\nexport async function markAiJobNeedsInput(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n reason: string,\n now = new Date(),\n): Promise<AiJob> {\n const { job } = await transition(firestore, orgId, jobId, (current) =>\n isAiJobTerminal(current.status)\n ? null\n : {\n status: 'needs_input',\n error: reason,\n lease: null,\n steps: current.steps.map((step) =>\n step.status === 'running'\n ? {\n ...step,\n status: 'pending',\n attempts: Math.max(0, (step.attempts ?? 0) - 1),\n }\n : step,\n ),\n updatedAt: now,\n },\n )\n return job\n}\n\n/**\n * Cancel. Idempotent — a terminal job is returned unchanged — and it does\n * not wait for a step in flight: the runner holding the lease finishes its\n * provider call, records what it cost, and finds the job canceled when it\n * goes to complete it.\n *\n * The activity row is written only when the cancel changed something: a\n * second cancel of the same job is not a second act. `actor` is the member\n * who canceled; a cancel with nobody named is recorded as nobody's rather\n * than as the creator's.\n */\nexport async function cancelAiJob(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n now = new Date(),\n actor: AiActivityActor | null = null,\n): Promise<{ job: AiJob; changed: boolean }> {\n const result = await transition(firestore, orgId, jobId, (current) =>\n isAiJobTerminal(current.status)\n ? null\n : {\n status: 'canceled',\n creditsReserved: 0,\n lease: null,\n updatedAt: now,\n },\n )\n if (result.changed) {\n await logAiJobCanceled(orgId, actor ?? { uid: null }, {\n jobId,\n kind: result.job.kind,\n })\n }\n return result\n}\n\n/**\n * Resume a job that stopped for a person (AGL-2935): confirm its plan, or\n * try again the step whose answer broke a building rule. One transaction,\n * so two confirmations land once; anything but a `needs_review` job comes\n * back unchanged. The pending step's attempts start over — a person asking\n * again is not a provider failing again — and a confirmed plan with no step\n * left behind it completes the job rather than queueing nothing. The steps\n * it queues are held at the nominal figure again, which the park released —\n * and a confirmed plan is held at what the whole job is estimated to cost\n * (AGL-3031), creations included, where that is more.\n */\nexport async function resumeAiJob(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n actor: { uid: string },\n now = new Date(),\n): Promise<{ job: AiJob; changed: boolean }> {\n return transition(firestore, orgId, jobId, (current) => {\n if (current.status !== 'needs_review') return null\n const steps = current.steps.map((step) =>\n step.status === 'pending' ? { ...step, attempts: 0 } : step,\n )\n const outstanding = steps.filter((step) => step.status === 'pending').length\n const pending = outstanding > 0\n const confirming = current.review?.reason === 'plan' && current.plan ? current.plan : null\n const confirmed = confirming\n ? {\n plan: {\n ...confirming,\n status: 'confirmed',\n confirmedAt: now,\n confirmedBy: actor.uid,\n },\n }\n : {}\n return {\n status: pending ? 'queued' : 'done',\n steps,\n review: null,\n error: null,\n ...confirmed,\n creditsReserved: pending\n ? Math.max(\n outstanding * AI_JOB_STEP_RESERVE_CREDITS,\n confirming ? aiJobPlanCreditEstimate(current.kind, confirming) : 0,\n )\n : 0,\n updatedAt: now,\n }\n })\n}\n\n/**\n * Record what a person applied from a finished job's outputs (AGL-2910): the\n * versions an apply opened and the listings it staged. The apply door calls\n * this after its own writes, so the record names only what exists. It never\n * changes the job's status, its steps or its spend.\n */\nexport async function recordAiJobApplied(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n applied: AiJobApplied,\n now = new Date(),\n): Promise<AiJob> {\n const { job } = await transition(firestore, orgId, jobId, () => ({\n applied,\n updatedAt: now,\n }))\n return job\n}\n\n// ── Audit ─────────────────────────────────────────────────────────────────\n\nexport type AiJobAuditAction = 'ai.job.output' | 'ai.job.cancel' | 'ai.job.resume' | 'ai.job.apply'\n\nexport interface AiJobAuditEntry {\n action: AiJobAuditAction\n actorUid: string\n actorEmail?: string | null\n orgId: string\n jobId: string\n after: Record<string, unknown>\n}\n\n/**\n * One `adminAudit` row, the same writer shape the billing routes use. Never\n * throws: an audit row that fails to land is logged, not turned into a\n * failed job the customer paid for.\n */\nexport async function writeAiJobAudit(\n firestore: Firestore,\n entry: AiJobAuditEntry,\n): Promise<void> {\n try {\n await firestore.collection('adminAudit').add({\n actorUid: entry.actorUid,\n actorEmail: entry.actorEmail ?? null,\n action: entry.action,\n target: `orgs/${entry.orgId}/${AI_JOBS_COLLECTION}/${entry.jobId}`,\n after: entry.after,\n at: FieldValue.serverTimestamp(),\n })\n } catch (error) {\n console.error('ai job audit write failed', {\n orgId: entry.orgId,\n jobId: entry.jobId,\n action: entry.action,\n error,\n })\n }\n}\n\n// ── Running a step ────────────────────────────────────────────────────────\n\n/**\n * The refusal in customer-safe words. The org's own wall names the switch\n * (AGL-2653); a cap, a band and a budget are told apart because one is a\n * figure the org set, one is what its plan sold, and one is the operator's\n * backstop; the message cap resets on a clock the others do not.\n */\nexport function aiJobRefusalText(\n org: Partial<AglynOrgBilling> | null,\n reservation: Pick<\n AssistReservation,\n | 'refusedBy'\n | 'budgetUsd'\n | 'allotment'\n | 'capReason'\n | 'overageLimitUsd'\n | 'overageUnpaidUsd'\n >,\n): string {\n const refusedBy = reservation.refusedBy\n // AGLYN'S OWN OVERAGE GUARDS (AGL-3011). First, because a `cap` refusal\n // that carries a reason knows exactly which limit stopped the job, where\n // the `case 'cap'` below can only name the workspace's own.\n const overage = aiOverageReservationRefusal(reservation)\n if (overage) return overage.text\n // A hard allotment (AGL-2942) — the creator's, theirs on the job's site,\n // or the site's — in the sentence every door gives, naming who can raise\n // it. A member can change that, so the job parks rather than fails.\n if (refusedBy === 'allotment') {\n return aiAllotmentRefusalText(reservation.allotment?.refusal?.scope)\n }\n if (assistRefusedByHardCap(org, refusedBy)) {\n return assistHardCapRefusalText(org)\n }\n // The Free taste's own precautions (AGL-2925), in the sentences every\n // other door uses — each names a clock or an upgrade.\n const taste = assistFreeTasteRefusalText(refusedBy)\n if (taste) return taste\n switch (refusedBy) {\n case 'cap':\n return 'This workspace reached the AI spending cap it set for the month'\n case 'band':\n return 'This workspace used its AI credits for the month'\n case 'budget':\n return reservation.budgetUsd === null\n ? 'This workspace reached its AI spending limit for the month'\n : 'This workspace used its AI credits for the month'\n default:\n return 'This workspace reached its AI limit for the month'\n }\n}\n\nexport interface RunAiJobStepOptions {\n /** Who is claiming: a request id or a beat id. */\n owner: string\n now?: Date\n /**\n * A reservation the caller already holds for THIS step — the console\n * route's gate ladder takes one before the job exists. Every later step\n * reserves for itself.\n */\n reservation?: AssistReservation\n /** The org billing document when the caller has it; read otherwise. */\n org?: Partial<AglynOrgBilling> | null\n /** Ends the provider call when the caller's budget does. */\n signal?: AbortSignal\n /**\n * The person on the request when a route runs the step inline. The beat\n * has none: what a step produces is then credited to the job's creator,\n * whose brief it is, never to nobody (AGL-2929).\n */\n actor?: AiActivityActor\n /**\n * A verified staff claim on the request when a route runs the step inline.\n * The workspace's AI pause lets staff through here as the gate ladder does,\n * so staff can verify a pause with one generation (AGL-3037). The beat has\n * no caller and never passes it.\n */\n staff?: boolean\n}\n\nexport type AiJobStepRun =\n /** Nothing to do: terminal, parked, no step left, or another owner's lease. */\n | { outcome: 'not-claimable' }\n /** The reservation was refused; the job is parked with the reason. */\n | { outcome: 'needs_input'; job: AiJob }\n /** The step stopped for a person (AGL-2935): its plan waits, or its answer broke a rule twice. */\n | { outcome: 'needs_review'; job: AiJob }\n /** The step ran and was recorded; `job.status` says whether more remain. */\n | { outcome: 'done'; job: AiJob }\n | { outcome: 'failed'; job: AiJob }\n /** A retryable provider failure; the step is pending again. */\n | { outcome: 'requeued'; job: AiJob }\n /**\n * AI is paused for the job's workspace (AGL-3037): nothing was claimed,\n * reserved or run, and the job waits where it stopped, at the back of the\n * beat's queue, until staff resume AI.\n */\n | { outcome: 'paused'; job: AiJob }\n\n/**\n * A budget that ended before the provider answered. `fetch` rejects with\n * the signal's reason, which is an `AbortError` for a manual abort and a\n * `TimeoutError` for `AbortSignal.timeout` — the one the route and the\n * sweep actually hand in.\n */\nfunction isAbort(error: unknown): boolean {\n const name = (error as { name?: string } | null)?.name\n return name === 'AbortError' || name === 'TimeoutError'\n}\n\n/** A step outcome that carries no tokens and no cost: the provider was never reached. */\nexport function aiJobStepSpentNothing(\n outcome: Pick<AiJobStepOutcome, 'usage' | 'estCostUsd'>,\n): boolean {\n const { usage } = outcome\n return (\n outcome.estCostUsd === 0 &&\n usage.inputTokens === 0 &&\n usage.outputTokens === 0 &&\n usage.cacheReadTokens === 0 &&\n usage.cacheWriteTokens === 0\n )\n}\n\n/**\n * Pause, claim, reserve, run, meter, record — one step of one job.\n *\n * The order is the invariant. The workspace's AI pause is asked BEFORE the\n * claim, so a paused workspace's job is neither claimed nor reserved for.\n * The reservation is taken AFTER the claim so a refused claim costs nothing,\n * and BEFORE the runner so the org's ceiling binds before a token is spent.\n * The cost is recorded before the step is, so a process cut off between the\n * two leaves the bill right and the step recoverable, never the other way\n * round.\n */\nexport async function runAiJobStep(\n firestore: Firestore,\n orgId: string,\n jobId: string,\n options: RunAiJobStepOptions,\n): Promise<AiJobStepRun> {\n const now = options.now ?? new Date()\n\n // A reservation the caller took before the job existed is a message\n // counted against the org; a step that fails before the provider is\n // reached spends nothing, so the message goes back rather than standing\n // as capacity the org paid for and never used.\n const releaseHeld = async () => {\n if (!options.reservation) return\n await releaseAssistMessage(firestore, orgId, options.reservation).catch(\n (releaseError) =>\n console.error('ai job release failed', { orgId, jobId, releaseError }),\n )\n }\n\n // A WORKSPACE WHOSE AI STAFF HAVE PAUSED runs none of its jobs (AGL-3037),\n // queued before the pause or not: the pause is a spend stop, and a job the\n // beat kept running would spend through it. The pause is lifted by staff\n // or by its own expiry and leaves the plan, the add-on and every\n // entitlement as they were, so a paused job is held, not failed: nothing is\n // claimed, reserved or run, and resuming AI runs it from where it stopped.\n // Read through the same verdict the jobs doors climb, before the claim.\n if (await aiJobPausedFor(orgId, jobId, options.staff === true)) {\n const held = await holdPausedAiJob(firestore, orgId, jobId, options.owner, now)\n if (!held) return { outcome: 'not-claimable' }\n await releaseHeld()\n return { outcome: 'paused', job: held }\n }\n\n const claimed = await claimNextStep(firestore, orgId, jobId, options.owner, now)\n if (!claimed) return { outcome: 'not-claimable' }\n const { job, stepIndex } = claimed\n const step = job.steps[stepIndex]\n\n const runner = aiJobRunnerForStep(job.kind, step.name)\n if (!runner) {\n await releaseHeld()\n return {\n outcome: 'failed',\n job: await failAiJob(firestore, orgId, jobId, AI_JOB_NOT_AVAILABLE_COPY, {\n stepIndex,\n error: `no runner registered for kind ${job.kind}`,\n }, now),\n }\n }\n if ((step.attempts ?? 0) > AI_JOB_STEP_MAX_ATTEMPTS) {\n await releaseHeld()\n return {\n outcome: 'failed',\n job: await failAiJob(firestore, orgId, jobId, AI_UPSTREAM_FAILURE_COPY, {\n stepIndex,\n error: `step ${step.name} exhausted ${AI_JOB_STEP_MAX_ATTEMPTS} attempts`,\n }, now),\n }\n }\n\n const org =\n options.org ??\n (((await firestore.collection('orgs').doc(orgId).get()).data() ??\n {}) as Partial<AglynOrgBilling>)\n\n // A site that switched AI off runs none of its jobs (AGL-3028), queued\n // before the switch or not. Asked before the reservation, so the job fails\n // in words a member can act on and nothing is reserved, run or metered.\n if (await isAiOffForSite(firestore, org, job.hostId)) {\n await releaseHeld()\n return {\n outcome: 'failed',\n job: await failAiJob(firestore, orgId, jobId, AI_OFF_FOR_SITE_COPY, {\n stepIndex,\n error: `ai is switched off for site ${job.hostId}`,\n }, now),\n }\n }\n\n const entitled =\n checkEntitlement(org, 'aiAssist') || checkEntitlement(org, 'aiGenerative')\n\n let reservation: AssistReservation\n if (options.reservation) {\n reservation = options.reservation\n } else {\n try {\n // The creator's allotments on the job's site (AGL-2942): the step is\n // their spend, as the meter below attributes it.\n reservation = await reserveAssistMessage(firestore, orgId, entitled, now, org, {\n uid: job.createdBy,\n hostId: job.hostId ?? null,\n })\n } catch (error) {\n // The meter is unreachable, not refusing. Hand the step back; the\n // next beat asks again.\n console.error('ai job reservation failed', { orgId, jobId, error })\n const { job: requeued } = await recordStep(\n firestore, orgId, jobId, options.owner, stepIndex,\n { status: 'pending', creditsSpent: 0 },\n now,\n )\n return { outcome: 'requeued', job: requeued }\n }\n }\n // A refused step is the creator's refusal (AGL-2928), on their month,\n // beside the org counter the reservation moved; an admitted one records\n // nothing.\n recordUserAiRefusal(firestore, orgId, job.createdBy, reservation)\n if (!reservation.allowed) {\n const refusal = aiJobRefusalText(org, reservation)\n const parked = await markAiJobNeedsInput(firestore, orgId, jobId, refusal, now)\n // Nobody parked the job — the meter did — so the row carries no actor\n // rather than the creator's name on an act they did not perform. Only\n // when the job was not already parked for this: the reason the last\n // park stored survives the beat's re-queue, so a job the meter refuses\n // again on its hourly retry is one row, not one an hour; a different\n // ceiling is a new row. The meter names a ceiling on every refusal; the\n // guard narrows the type.\n if (reservation.refusedBy && job.error !== refusal) {\n await logAiJobNeedsInput(orgId, { uid: null }, {\n jobId,\n kind: job.kind,\n reason: reservation.refusedBy,\n })\n }\n return { outcome: 'needs_input', job: parked }\n }\n\n // The model each step runs on (AGL-2942): the creator's pick where the\n // plan and the allotment allowlists the reservation read allow it, the\n // routing table otherwise. Handed to the runner as a function of the step\n // kind, because the runner — not the machine — knows what kind it runs.\n const bounds = {\n plan: resolveEffectivePlan(org),\n allotmentModels: reservation.allotment?.models ?? null,\n orgModels: reservation.allotment?.orgModels ?? null,\n }\n const modelFor = (kind: Parameters<typeof resolveAiModelChoice>[0]) =>\n resolveAiModelChoice(kind, job.model ?? null, bounds)?.model\n\n let outcome: AiJobStepOutcome\n // The runner's wall-clock time, recorded on the step beside its tokens\n // (AGL-2937): measured here, around the call, rather than asked of it.\n const runStarted = Date.now()\n try {\n outcome = await runner({\n job, stepIndex, now, signal: options.signal, firestore, org, modelFor,\n })\n } catch (error) {\n // The provider refused the request or the budget ended before it\n // answered: no usage came back, so nothing is metered and the message\n // goes back to the org. The provider's own words are already in the\n // log under the request id (AGL-2815).\n await releaseAssistMessage(firestore, orgId, reservation).catch((releaseError) =>\n console.error('ai job release failed', { orgId, jobId, releaseError }),\n )\n const retryable =\n (error instanceof AiUpstreamError && error.retryable) || isAbort(error)\n if (retryable) {\n const { job: requeued } = await recordStep(\n firestore, orgId, jobId, options.owner, stepIndex,\n { status: 'pending', creditsSpent: 0 },\n now,\n )\n return { outcome: 'requeued', job: requeued }\n }\n return {\n outcome: 'failed',\n job: await failAiJob(firestore, orgId, jobId, AI_UPSTREAM_FAILURE_COPY, {\n stepIndex,\n error,\n }, now),\n }\n }\n\n const latencyMs = Math.max(0, Date.now() - runStarted)\n\n // A step that failed before it reached the provider — the site it builds\n // from could not be read, say (AGL-2938) — spent nothing: its message goes\n // back and nothing is metered, exactly as for a request the provider\n // refused.\n if (outcome.failure && aiJobStepSpentNothing(outcome)) {\n await releaseAssistMessage(firestore, orgId, reservation).catch((releaseError) =>\n console.error('ai job release failed', { orgId, jobId, releaseError }),\n )\n await recordStep(\n firestore, orgId, jobId, options.owner, stepIndex,\n { status: 'failed', creditsSpent: 0, error: outcome.failure },\n now,\n )\n return {\n outcome: 'failed',\n job: await failAiJob(firestore, orgId, jobId, outcome.failure, {\n stepIndex,\n error: `step failure before the provider: ${outcome.failure}`,\n }, now),\n }\n }\n\n const tokens: AiJobStepTokenRun = {\n usage: outcome.usage,\n model: outcome.model,\n effort: outcome.effort ?? null,\n latencyMs,\n stopReason: outcome.stopReason,\n }\n\n // A step that stopped before the provider without failing — a site with no\n // room for the draft (AGL-2909), say — spent nothing too: its message goes\n // back and there is nothing to meter. What it returns is still recorded\n // below, as any step's is.\n const spentNothing = aiJobStepSpentNothing(outcome)\n if (spentNothing) {\n await releaseAssistMessage(firestore, orgId, reservation).catch((releaseError) =>\n console.error('ai job release failed', { orgId, jobId, releaseError }),\n )\n } else {\n // Tokens were spent, so the bill is written first and its failure is a\n // log line, never a failed job — the same rule the chat route keeps.\n try {\n await recordAssistCost(\n firestore,\n orgId,\n {\n route: 'ai/jobs',\n hostId: job.hostId ?? null,\n model: outcome.model,\n tier: entitled ? 'entitled' : 'free',\n usage: outcome.usage,\n docsPaths: [],\n stopReason: outcome.stopReason,\n deflected: false,\n // The account this job drew on, as the reservation decided it\n // (AGL-2925): a Free job lands on the owner's allowance and the\n // platform's day; a paid one on neither.\n free: reservation.free ?? null,\n // The step is the creator's spend, under the job's kind (AGL-2928).\n uid: job.createdBy,\n kind: job.kind,\n },\n now,\n )\n } catch (error) {\n console.error('ai job cost record failed', { orgId, jobId, error })\n }\n }\n const credits = assistCreditsFromUsd(outcome.estCostUsd)\n\n // A model that declined, or a step that got nothing usable out of the\n // model's answer (AGL-2938), fails the job with its own sentence. The\n // tokens are already on the bill above.\n if (outcome.refused || outcome.failure) {\n const message = outcome.refused ? AI_JOB_REFUSED_COPY : (outcome.failure as string)\n await recordStep(\n firestore, orgId, jobId, options.owner, stepIndex,\n { status: 'failed', creditsSpent: credits, error: message, tokens },\n now,\n )\n return {\n outcome: 'failed',\n job: await failAiJob(firestore, orgId, jobId, message, {\n stepIndex,\n error: outcome.refused ? 'stop_reason refusal' : `step failure: ${message}`,\n }, now),\n }\n }\n\n // A step that stopped for a person parks the job in the same write that\n // records it (AGL-2935): a plan review completes the step, so confirming\n // runs the next one; a doctrine or limit review hands it back, so trying\n // again runs the same one.\n //\n // A step that asks to continue (AGL-2910) is recorded as this pass — its\n // cost, its credits, its outputs, its audit rows — and handed back as\n // `pending`, so the next claim runs the same step again. A step that stopped\n // for a person never continues: the review is what it waits on. The pass\n // cap is what stops a runner that never finishes: past it the pass is\n // recorded as the step's last, and what it produced stands.\n const review = outcome.review\n const continuing =\n !review &&\n Boolean(outcome.continue) &&\n (step.passes ?? 0) + 1 < aiJobStepMaxPasses(job.kind)\n if (!review && outcome.continue && !continuing) {\n console.warn('ai job step reached its pass cap', { orgId, jobId, stepIndex })\n }\n const recorded = await recordStep(\n firestore, orgId, jobId, options.owner, stepIndex,\n {\n status: continuing || (review && review.reason !== 'plan') ? 'pending' : 'done',\n ...(continuing ? { continued: true } : {}),\n creditsSpent: credits,\n // A step that spent nothing ran no model, so it adds no run to the measure.\n ...(spentNothing ? {} : { tokens }),\n outputs: outcome.outputs,\n ...(outcome.plan ? { plan: outcome.plan } : {}),\n ...(review ? { review } : {}),\n },\n now,\n )\n const actor: AiActivityActor = options.actor ?? { uid: job.createdBy }\n for (const output of outcome.outputs) {\n await writeAiJobAudit(firestore, {\n action: 'ai.job.output',\n actorUid: job.createdBy,\n orgId,\n jobId,\n after: {\n resource: output.resource,\n id: output.id,\n versionId: output.versionId ?? null,\n hostId: output.hostId,\n label: output.label,\n credits,\n },\n })\n // The customer-visible row, one per output: the label names the thing,\n // never its text, which is the site's content.\n await logAiJobOutput(orgId, actor, {\n jobId,\n hostId: output.hostId,\n resource: {\n type: aiOutputTargetType(output.resource),\n id: output.id,\n name: output.label,\n versionId: output.versionId ?? null,\n },\n })\n }\n if (review && recorded.job.status === 'needs_review') {\n // Nobody parked the job but its own step, so the row names no actor, as\n // the meter's park does.\n await logAiJobNeedsInput(orgId, { uid: null }, {\n jobId,\n kind: job.kind,\n reason: review.reason,\n })\n return { outcome: 'needs_review', job: recorded.job }\n }\n if (recorded.remaining > 0 || isAiJobTerminal(recorded.job.status)) {\n return { outcome: 'done', job: recorded.job }\n }\n return {\n outcome: 'done',\n job: await completeAiJob(firestore, orgId, jobId, now),\n }\n}\n\n// ── The beat's sweep ──────────────────────────────────────────────────────\n\nexport interface DueAiJob {\n orgId: string\n jobId: string\n}\n\nexport interface SweepAiJobsOptions {\n firestore: Firestore\n /** The beat's identity for its leases. */\n owner: string\n now?: () => number\n budgetMs?: number\n maxJobs?: number\n /** Test seams; the defaults query Firestore and run the real step. */\n listDue?: () => Promise<DueAiJob[]>\n runStep?: (\n orgId: string,\n jobId: string,\n options: RunAiJobStepOptions,\n ) => Promise<AiJobStepRun>\n}\n\nexport interface SweepAiJobsResult {\n /** Candidates the queries returned. */\n due: number\n /** Steps this sweep actually ran to a recorded result. */\n ran: number\n /** Claims another owner held, or jobs with nothing left. */\n skipped: number\n /**\n * Jobs whose workspace's AI staff have paused (AGL-3037): held where they\n * stopped and moved to the back of the queue, to run once AI is resumed.\n */\n paused: number\n /** Candidates left untouched because the wall clock ran out. */\n remaining: number\n budgetExhausted: boolean\n}\n\n/**\n * Every job the beat should look at, oldest first: queued and running\n * across every org, then `needs_input` jobs that have rested long enough\n * for the org's standing to have changed. Two queries rather than one, so\n * a workspace with many parked jobs cannot fill the candidate list and\n * starve the queue behind it. Both use the collection-group index on\n * (status, updatedAt).\n *\n * The ordering is the cursor. A job this sweep touches has its `updatedAt`\n * moved and goes to the back of the next query; one it did not reach keeps\n * its place at the front. So there is no stored position to fall behind\n * or skip past — the same shape `media-move.ts` gives its budgeted loop,\n * where what was not done is simply what is asked for next.\n */\nexport async function listDueAiJobs(\n firestore: Firestore,\n nowMs: number,\n maxJobs = AI_JOB_SWEEP_MAX_JOBS,\n maxParked = AI_JOB_SWEEP_MAX_PARKED,\n): Promise<DueAiJob[]> {\n const group = firestore.collectionGroup(AI_JOBS_COLLECTION)\n const [active, parked] = await Promise.all([\n group\n .where('status', 'in', ['queued', 'running'])\n .orderBy('updatedAt', 'asc')\n .limit(maxJobs)\n .get(),\n group\n .where('status', '==', 'needs_input')\n .where('updatedAt', '<=', new Date(nowMs - AI_JOB_NEEDS_INPUT_RETRY_MS))\n .orderBy('updatedAt', 'asc')\n .limit(maxParked)\n .get(),\n ])\n return [...active.docs, ...parked.docs]\n .map((doc) => ({ orgId: String(doc.get('orgId') ?? ''), jobId: doc.id }))\n .filter((due) => due.orgId !== '')\n}\n\n/**\n * Run due steps until the budget is spent, and account for every candidate.\n *\n * The bound is wall clock, not a count, for the reason `media-move.ts`\n * gives: one step is one provider round trip of unknown length, so any\n * fixed number would be wrong for some brief. The budget is checked BETWEEN\n * jobs, and the step in flight gets the time that is left as its abort\n * signal, so the sweep still finishes whichever step it has started. At\n * least one candidate is always attempted, so a beat that yields having\n * done nothing cannot starve a queue behind a slow clock.\n *\n * A `needs_input` job is re-queued before its step is claimed, because the\n * claim admits only queued and running jobs; the reservation inside the\n * step is what decides whether the org's standing has changed.\n */\nexport async function sweepAiJobs(\n options: SweepAiJobsOptions,\n): Promise<SweepAiJobsResult> {\n const now = options.now ?? Date.now\n const budgetMs = options.budgetMs ?? AI_JOB_SWEEP_BUDGET_MS\n const startedAt = now()\n const listDue =\n options.listDue ??\n (() => listDueAiJobs(options.firestore, now(), options.maxJobs))\n const runStep =\n options.runStep ??\n ((orgId: string, jobId: string, stepOptions: RunAiJobStepOptions) =>\n runAiJobStep(options.firestore, orgId, jobId, stepOptions))\n\n const due = await listDue()\n const result: SweepAiJobsResult = {\n due: due.length,\n ran: 0,\n skipped: 0,\n paused: 0,\n remaining: 0,\n budgetExhausted: false,\n }\n // Jobs a run left with more of a timed step to do, in the order they ran.\n const again: DueAiJob[] = []\n const attempt = async (candidate: DueAiJob, left: number, first: boolean): Promise<void> => {\n const { orgId, jobId } = candidate\n try {\n const current = await getAiJob(options.firestore, orgId, jobId)\n // A step that needs more time than is left is not started (AGL-2907): a\n // provider call the abort cuts off is billed upstream and metered\n // nowhere. The job is left as it is, so it keeps its place at the front\n // of the next beat's queue.\n const minimumMs = current ? aiJobNextStepMinimumMs(current) : 0\n if (minimumMs > left) {\n if (first) result.remaining += 1\n return\n }\n if (current?.status === 'needs_input') {\n await transition(options.firestore, orgId, jobId, (job) =>\n job.status === 'needs_input' ? { status: 'queued', updatedAt: new Date(now()) } : null,\n )\n }\n const run = await runStep(orgId, jobId, {\n owner: options.owner,\n now: new Date(now()),\n signal: AbortSignal.timeout(left),\n })\n if (run.outcome === 'not-claimable') {\n if (first) result.skipped += 1\n return\n }\n if (run.outcome === 'paused') {\n if (first) result.paused += 1\n return\n }\n result.ran += 1\n // Only a step that says how long it needs is run again in this sweep:\n // one that does not could start with too little time left.\n if (\n run.outcome === 'done' &&\n run.job.status === 'queued' &&\n aiJobNextStepMinimumMs(run.job) > 0\n ) {\n again.push(candidate)\n }\n } catch (error) {\n // One job's fault is isolated, as the runner isolates one job's.\n console.error('ai job sweep step failed', { orgId, jobId, error })\n if (first) result.skipped += 1\n }\n }\n\n for (let index = 0; index < due.length; index += 1) {\n const elapsed = now() - startedAt\n if (index > 0 && elapsed >= budgetMs) {\n result.budgetExhausted = true\n result.remaining += due.length - index\n return result\n }\n await attempt(due[index], Math.max(1_000, budgetMs - elapsed), true)\n }\n // Once every due job has had its turn, a job whose timed step has more to\n // do runs again while the time it needs is left (AGL-2907): a page built a\n // section a pass otherwise waits a beat between sections. Bounded by the\n // budget, and by the sweep's candidate count so no clock is trusted alone.\n for (let round = 0; again.length && round < AI_JOB_SWEEP_MAX_JOBS; round += 1) {\n const elapsed = now() - startedAt\n if (elapsed >= budgetMs) {\n result.budgetExhausted = true\n break\n }\n await attempt(again.shift() as DueAiJob, budgetMs - elapsed, false)\n }\n return result\n}\n"],"names":["FieldValue","createResourceUid","checkEntitlement","assistCreditsFromUsd","assistFreeTasteRefusalText","assistHardCapRefusalText","assistRefusedByHardCap","AI_JOB_TERMINAL_STATUSES","resolveEffectivePlan","aiOverageReservationRefusal","aiAllotmentRefusalText","aiJobPlanCreditEstimate","AI_OFF_FOR_SITE_COPY","isAiOffForSite","resolveAiModelChoice","aiOutputTargetType","logAiJobCanceled","logAiJobCreated","logAiJobNeedsInput","logAiJobOutput","AI_UPSTREAM_FAILURE_COPY","AiUpstreamError","recordUserAiRefusal","AI_JOB_INLINE_BUDGET_MS","AI_JOB_SWEEP_BUDGET_MS","aiMintJobDraftIds","AI_JOB_TEXT_STEP_MINIMUM_MS","runAiJobTextStep","AI_JOB_SEO_STEP_MINIMUM_MS","AI_JOB_THEME_STEP_MINIMUM_MS","assistExchangeExpiry","recordAssistCost","releaseAssistMessage","reserveAssistMessage","AI_JOBS_COLLECTION","AI_JOB_LEASE_MS","AI_JOB_STEP_MAX_ATTEMPTS","AI_JOB_STEP_MAX_PASSES","AI_JOB_STEP_RESERVE_CREDITS","AI_JOB_SWEEP_MAX_JOBS","AI_JOB_SWEEP_MAX_PARKED","AI_JOB_NEEDS_INPUT_RETRY_MS","AI_JOB_NOT_AVAILABLE_COPY","AI_JOB_REFUSED_COPY","toMillis","value","Date","getTime","parsed","parse","Number","isFinite","toIso","millis","toISOString","isAiJobTerminal","status","includes","AI_JOB_PLAN_STEP","AI_PLANNED_JOB_KINDS","stepRunners","Map","stepMinimums","stepRunMinimums","planStepRunner","planStepMinimumMs","stepPassCaps","registerAiJobStep","kind","runner","registration","set","minimumMs","delete","minimumMsFor","aiJobStepMinimumMs","stepName","get","aiJobStepRunMinimumMs","job","least","forRun","Math","max","aiJobNextStepMinimumMs","index","nextStepIndex","steps","name","aiJobStepRunnerFor","registerAiJobStepPasses","maxPasses","floor","aiJobStepMaxPasses","registerAiJobPlanStep","pauseReader","registerAiJobPauseReader","reader","aiJobPauseReaderRegistered","aiJobPausedFor","orgId","jobId","staff","error","console","aiJobRunnerForStep","aiJobStepNames","has","context","runAiJobThemeStep","runAiJobSeoStep","jobsCollection","firestore","collection","doc","jobFrom","snapshot","exists","data","$id","id","createAiJob","input","now","brief","trim","Error","draftIds","map","startedAt","endedAt","creditsSpent","attempts","ref","hostId","inputs","model","outputs","creditsReserved","length","createdBy","createdAt","updatedAt","expiresAt","lease","uid","email","createdByEmail","briefLength","getAiJob","listAiJobs","options","limit","min","query","where","orderBy","docs","filter","aiJobSummary","leaseUntil","until","batch","step","running","plan","labels","proposedAt","confirmedAt","confirmedBy","review","applied","at","by","versions","staged","leaseIsLive","owner","nowMs","findIndex","claimableStepIndex","claimNextStep","runTransaction","tx","stepIndex","merge","heartbeatStep","holdPausedAiJob","AI_JOB_STEP_LAST_RUNS","AI_JOB_STEP_STOP_REASON_MAX_CHARS","addAiJobStepTokens","current","run","count","kept","Array","isArray","lastRuns","stopReason","slice","usage","inputTokens","cachedRead","cacheReadTokens","cacheWrite","cacheWriteTokens","output","outputTokens","effort","latencyMs","runs","recordStep","continued","passes","tokens","remaining","settled","ownsLease","parksForReview","Boolean","patch","reason","message","transition","apply","changed","completeAiJob","failAiJob","detail","markAiJobNeedsInput","cancelAiJob","actor","result","resumeAiJob","outstanding","pending","confirming","confirmed","recordAiJobApplied","writeAiJobAudit","entry","add","actorUid","actorEmail","action","target","after","serverTimestamp","aiJobRefusalText","org","reservation","refusedBy","overage","text","allotment","refusal","scope","taste","budgetUsd","isAbort","aiJobStepSpentNothing","outcome","estCostUsd","runAiJobStep","releaseHeld","catch","releaseError","held","claimed","entitled","requeued","allowed","parked","bounds","allotmentModels","models","orgModels","modelFor","runStarted","signal","retryable","failure","spentNothing","route","tier","docsPaths","deflected","free","credits","refused","continuing","continue","warn","recorded","resource","versionId","label","type","listDueAiJobs","maxJobs","maxParked","group","collectionGroup","active","Promise","all","String","due","sweepAiJobs","budgetMs","listDue","runStep","stepOptions","ran","skipped","paused","budgetExhausted","again","attempt","candidate","left","first","AbortSignal","timeout","push","elapsed","round","shift"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * The server helpers a media library read defers (AGL-2916): storage, the
19
+ * media CDN's block and sharp, loaded only when a job actually reads an
20
+ * asset's bytes.
21
+ *
22
+ * The deferral targets THIS module by relative path, for the reason
23
+ * `ai-theme-brand-server.ts` gives: a workspace lib ever `import()`ed by its
24
+ * package specifier is lazy-loaded everywhere as far as nx is concerned, and
25
+ * the module boundary rule then forbids every static import of
26
+ * `@aglyn/tenant-data-admin` across the plugin and both apps. A relative
27
+ * specifier crosses no project boundary.
28
+ *
29
+ * Import this module dynamically, and only from `ai-media-asset.ts`.
30
+ */
31
+ export { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin';
32
+ export { mediaStoragePathInScope } from '@aglyn/tenant-data-admin/server/media-storage-path';
33
+ export { loadSharp } from '@aglyn/tenant-data-admin/server/media-variants';
34
+ export { mediaCdnServeBlock } from '@aglyn/tenant-data-admin/server/serve-media-cdn';
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * The server helpers a media library read defers (AGL-2916): storage, the
18
+ * media CDN's block and sharp, loaded only when a job actually reads an
19
+ * asset's bytes.
20
+ *
21
+ * The deferral targets THIS module by relative path, for the reason
22
+ * `ai-theme-brand-server.ts` gives: a workspace lib ever `import()`ed by its
23
+ * package specifier is lazy-loaded everywhere as far as nx is concerned, and
24
+ * the module boundary rule then forbids every static import of
25
+ * `@aglyn/tenant-data-admin` across the plugin and both apps. A relative
26
+ * specifier crosses no project boundary.
27
+ *
28
+ * Import this module dynamically, and only from `ai-media-asset.ts`.
29
+ */ export { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
30
+ export { mediaStoragePathInScope } from "@aglyn/tenant-data-admin/server/media-storage-path";
31
+ export { loadSharp } from "@aglyn/tenant-data-admin/server/media-variants";
32
+ export { mediaCdnServeBlock } from "@aglyn/tenant-data-admin/server/serve-media-cdn";
33
+
34
+ //# sourceMappingURL=ai-media-asset-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-media-asset-server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The server helpers a media library read defers (AGL-2916): storage, the\n * media CDN's block and sharp, loaded only when a job actually reads an\n * asset's bytes.\n *\n * The deferral targets THIS module by relative path, for the reason\n * `ai-theme-brand-server.ts` gives: a workspace lib ever `import()`ed by its\n * package specifier is lazy-loaded everywhere as far as nx is concerned, and\n * the module boundary rule then forbids every static import of\n * `@aglyn/tenant-data-admin` across the plugin and both apps. A relative\n * specifier crosses no project boundary.\n *\n * Import this module dynamically, and only from `ai-media-asset.ts`.\n */\nexport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nexport { mediaStoragePathInScope } from '@aglyn/tenant-data-admin/server/media-storage-path'\nexport { loadSharp } from '@aglyn/tenant-data-admin/server/media-variants'\nexport { mediaCdnServeBlock } from '@aglyn/tenant-data-admin/server/serve-media-cdn'\n"],"names":["firebaseAdmin","mediaStoragePathInScope","loadSharp","mediaCdnServeBlock"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;CAaC,GACD,SAASA,aAAa,QAAQ,iDAAgD;AAC9E,SAASC,uBAAuB,QAAQ,qDAAoD;AAC5F,SAASC,SAAS,QAAQ,iDAAgD;AAC1E,SAASC,kBAAkB,QAAQ,kDAAiD"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type MediaCdnScope } from '@aglyn/aglyn/app-utils/media-cdn-scope';
18
+ /**
19
+ * One asset of a site's media library, read the way the media CDN would serve
20
+ * it (AGL-2938, AGL-2916): what a job reads when it looks at a
21
+ * picture a customer already keeps, a theme's logo or a product's photo.
22
+ *
23
+ * A job never fetches a URL for this. It reads the asset from storage, and
24
+ * only when the reference names this site's own library or its org's, the
25
+ * document is live and not private, an org asset is visible to the site, the
26
+ * scope is not locked and the asset not quarantined, and the object path sits
27
+ * inside the scope's own media prefix. Anything else is no asset at all.
28
+ */
29
+ export interface AiMediaAssetLocation {
30
+ scope: MediaCdnScope;
31
+ /** The CDN scope segment, which is also a quarantine key. */
32
+ scopeSegment: string;
33
+ mediaId: string;
34
+ }
35
+ /**
36
+ * Where a stored media value lives in a media library: a media reference or
37
+ * a CDN path naming this site's library, or its org's. An external URL, a raw
38
+ * storage URL, or an asset of some other site or org has no location.
39
+ */
40
+ export declare function aiMediaAssetLocation(value: unknown, hostId: string, orgId: string): AiMediaAssetLocation | null;
41
+ export interface AiMediaAssetBytes {
42
+ buffer: Buffer;
43
+ /** The content type the media document records. */
44
+ contentType: string;
45
+ }
46
+ export interface AiMediaAssetReadOptions {
47
+ /** The largest asset read, by the size its document records and by what storage returns. */
48
+ maxBytes: number;
49
+ /** The content types read; any other asset is not read at all. */
50
+ types: RegExp;
51
+ }
52
+ /**
53
+ * An asset's bytes, or `null` when any condition in the module note does not
54
+ * hold. The storage read and the CDN's block are loaded only when a document
55
+ * passes every check that needs no network.
56
+ */
57
+ export declare function readAiMediaAssetBytes(firestore: FirebaseFirestore.Firestore, location: AiMediaAssetLocation, hostId: string, options: AiMediaAssetReadOptions): Promise<AiMediaAssetBytes | null>;
58
+ /** `sharp`, as far as a job that decodes an asset uses it. */
59
+ export declare function loadAiMediaSharp(): Promise<unknown>;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { parseMediaCdnScope } from "@aglyn/aglyn/app-utils/media-cdn-scope";
17
+ import { isMediaCdnPath, MEDIA_CDN_ROUTE, parseMediaRef } from "@aglyn/aglyn/app-utils/media-ref";
18
+ import { visibleToHost } from "@aglyn/aglyn/app-utils/scope-tokens";
19
+ /**
20
+ * Where a stored media value lives in a media library: a media reference or
21
+ * a CDN path naming this site's library, or its org's. An external URL, a raw
22
+ * storage URL, or an asset of some other site or org has no location.
23
+ */ export function aiMediaAssetLocation(value, hostId, orgId) {
24
+ let scopeSegment;
25
+ let mediaId;
26
+ const ref = parseMediaRef(value);
27
+ if (ref) {
28
+ scopeSegment = ref.scope;
29
+ mediaId = ref.mediaId;
30
+ } else if (isMediaCdnPath(value)) {
31
+ const rest = value.slice(`${MEDIA_CDN_ROUTE}/`.length);
32
+ const slash = rest.indexOf('/');
33
+ scopeSegment = rest.slice(0, slash);
34
+ mediaId = rest.slice(slash + 1);
35
+ } else {
36
+ return null;
37
+ }
38
+ const scope = parseMediaCdnScope(scopeSegment);
39
+ if (!scope) return null;
40
+ const owned = scope.isOrg ? scope.scopeId === orgId : scope.scopeId === hostId;
41
+ return owned ? {
42
+ scope,
43
+ scopeSegment,
44
+ mediaId
45
+ } : null;
46
+ }
47
+ /**
48
+ * An asset's bytes, or `null` when any condition in the module note does not
49
+ * hold. The storage read and the CDN's block are loaded only when a document
50
+ * passes every check that needs no network.
51
+ */ export async function readAiMediaAssetBytes(firestore, location, hostId, options) {
52
+ var _media_contentType;
53
+ const { scope, mediaId } = location;
54
+ const snapshot = await firestore.collection(scope.isOrg ? 'orgs' : 'hosts').doc(scope.scopeId).collection('media').doc(mediaId).get();
55
+ const media = snapshot.exists ? snapshot.data() : null;
56
+ if (!media || media['deletedAt'] || media['private']) return null;
57
+ if (scope.isOrg && !visibleToHost(media['visibleTo'], hostId)) return null;
58
+ const contentType = String((_media_contentType = media['contentType']) != null ? _media_contentType : '');
59
+ if (!options.types.test(contentType)) return null;
60
+ if (typeof media['sizeBytes'] === 'number' && media['sizeBytes'] > options.maxBytes) return null;
61
+ const { mediaCdnServeBlock, mediaStoragePathInScope, firebaseAdmin } = await import("./ai-media-asset-server.js");
62
+ const blocked = await mediaCdnServeBlock(scope, {
63
+ contentSha256: typeof media['contentSha256'] === 'string' ? media['contentSha256'] : undefined,
64
+ contentHash: typeof media['contentHash'] === 'string' ? media['contentHash'] : undefined,
65
+ scopeSegment: location.scopeSegment,
66
+ mediaId
67
+ });
68
+ if (blocked) return null;
69
+ const objectPath = mediaStoragePathInScope({
70
+ storagePath: media['storagePath'],
71
+ base: `${scope.isOrg ? 'orgs' : 'hosts'}/${scope.scopeId}`,
72
+ mediaId
73
+ });
74
+ const [buffer] = await firebaseAdmin.app().storage().bucket(process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET || undefined).file(objectPath).download();
75
+ if (buffer.length > options.maxBytes) return null;
76
+ return {
77
+ buffer,
78
+ contentType
79
+ };
80
+ }
81
+ /** `sharp`, as far as a job that decodes an asset uses it. */ export async function loadAiMediaSharp() {
82
+ const { loadSharp } = await import("./ai-media-asset-server.js");
83
+ return loadSharp();
84
+ }
85
+
86
+ //# sourceMappingURL=ai-media-asset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-media-asset.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseMediaCdnScope, type MediaCdnScope } from '@aglyn/aglyn/app-utils/media-cdn-scope'\nimport { isMediaCdnPath, MEDIA_CDN_ROUTE, parseMediaRef } from '@aglyn/aglyn/app-utils/media-ref'\nimport { visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\n\n/**\n * One asset of a site's media library, read the way the media CDN would serve\n * it (AGL-2938, AGL-2916): what a job reads when it looks at a\n * picture a customer already keeps, a theme's logo or a product's photo.\n *\n * A job never fetches a URL for this. It reads the asset from storage, and\n * only when the reference names this site's own library or its org's, the\n * document is live and not private, an org asset is visible to the site, the\n * scope is not locked and the asset not quarantined, and the object path sits\n * inside the scope's own media prefix. Anything else is no asset at all.\n */\n\nexport interface AiMediaAssetLocation {\n scope: MediaCdnScope\n /** The CDN scope segment, which is also a quarantine key. */\n scopeSegment: string\n mediaId: string\n}\n\n/**\n * Where a stored media value lives in a media library: a media reference or\n * a CDN path naming this site's library, or its org's. An external URL, a raw\n * storage URL, or an asset of some other site or org has no location.\n */\nexport function aiMediaAssetLocation(\n value: unknown,\n hostId: string,\n orgId: string,\n): AiMediaAssetLocation | null {\n let scopeSegment: string\n let mediaId: string\n const ref = parseMediaRef(value)\n if (ref) {\n scopeSegment = ref.scope\n mediaId = ref.mediaId\n } else if (isMediaCdnPath(value)) {\n const rest = value.slice(`${MEDIA_CDN_ROUTE}/`.length)\n const slash = rest.indexOf('/')\n scopeSegment = rest.slice(0, slash)\n mediaId = rest.slice(slash + 1)\n } else {\n return null\n }\n const scope = parseMediaCdnScope(scopeSegment)\n if (!scope) return null\n const owned = scope.isOrg ? scope.scopeId === orgId : scope.scopeId === hostId\n return owned ? { scope, scopeSegment, mediaId } : null\n}\n\nexport interface AiMediaAssetBytes {\n buffer: Buffer\n /** The content type the media document records. */\n contentType: string\n}\n\nexport interface AiMediaAssetReadOptions {\n /** The largest asset read, by the size its document records and by what storage returns. */\n maxBytes: number\n /** The content types read; any other asset is not read at all. */\n types: RegExp\n}\n\n/**\n * An asset's bytes, or `null` when any condition in the module note does not\n * hold. The storage read and the CDN's block are loaded only when a document\n * passes every check that needs no network.\n */\nexport async function readAiMediaAssetBytes(\n firestore: FirebaseFirestore.Firestore,\n location: AiMediaAssetLocation,\n hostId: string,\n options: AiMediaAssetReadOptions,\n): Promise<AiMediaAssetBytes | null> {\n const { scope, mediaId } = location\n const snapshot = await firestore\n .collection(scope.isOrg ? 'orgs' : 'hosts')\n .doc(scope.scopeId)\n .collection('media')\n .doc(mediaId)\n .get()\n const media = (snapshot.exists ? snapshot.data() : null) as Record<string, unknown> | null\n if (!media || media['deletedAt'] || media['private']) return null\n if (scope.isOrg && !visibleToHost(media['visibleTo'] as string[] | undefined, hostId)) return null\n const contentType = String(media['contentType'] ?? '')\n if (!options.types.test(contentType)) return null\n if (typeof media['sizeBytes'] === 'number' && media['sizeBytes'] > options.maxBytes) return null\n const { mediaCdnServeBlock, mediaStoragePathInScope, firebaseAdmin } = await import(\n './ai-media-asset-server'\n )\n const blocked = await mediaCdnServeBlock(scope, {\n contentSha256: typeof media['contentSha256'] === 'string' ? media['contentSha256'] : undefined,\n contentHash: typeof media['contentHash'] === 'string' ? media['contentHash'] : undefined,\n scopeSegment: location.scopeSegment,\n mediaId,\n })\n if (blocked) return null\n const objectPath = mediaStoragePathInScope({\n storagePath: media['storagePath'],\n base: `${scope.isOrg ? 'orgs' : 'hosts'}/${scope.scopeId}`,\n mediaId,\n })\n const [buffer] = (await firebaseAdmin\n .app()\n .storage()\n .bucket(process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET || undefined)\n .file(objectPath)\n .download()) as [Buffer]\n if (buffer.length > options.maxBytes) return null\n return { buffer, contentType }\n}\n\n/** `sharp`, as far as a job that decodes an asset uses it. */\nexport async function loadAiMediaSharp(): Promise<unknown> {\n const { loadSharp } = await import('./ai-media-asset-server')\n return loadSharp()\n}\n"],"names":["parseMediaCdnScope","isMediaCdnPath","MEDIA_CDN_ROUTE","parseMediaRef","visibleToHost","aiMediaAssetLocation","value","hostId","orgId","scopeSegment","mediaId","ref","scope","rest","slice","length","slash","indexOf","owned","isOrg","scopeId","readAiMediaAssetBytes","firestore","location","options","media","snapshot","collection","doc","get","exists","data","contentType","String","types","test","maxBytes","mediaCdnServeBlock","mediaStoragePathInScope","firebaseAdmin","blocked","contentSha256","undefined","contentHash","objectPath","storagePath","base","buffer","app","storage","bucket","process","env","NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET","file","download","loadAiMediaSharp","loadSharp"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { AiProductPhotoRead } from '../model/ai-products';
18
+ import type { AiImagePart } from '../providers/contract';
19
+ import { type AiMediaAssetBytes, type AiMediaAssetLocation } from './ai-media-asset';
20
+ /**
21
+ * A PRODUCT'S PHOTO, as a `products` job shows it to the model (AGL-2916).
22
+ *
23
+ * Exactly one picture is read for a product: its FIRST media item, the photo
24
+ * the storefront leads with. Nothing else of the media library is read or
25
+ * sent — no other photo of the product, no other asset, no folder, no file
26
+ * name and no alt text.
27
+ *
28
+ * The photo is read the way the media CDN would serve it
29
+ * (`readAiMediaAssetBytes`): only an asset of this site's own library or its
30
+ * org's, live, not private, visible to the site, not locked or quarantined.
31
+ * A photo that is a link to somewhere else, or a raw storage URL, is not an
32
+ * asset of the library and is not read at all; nothing is ever fetched from a
33
+ * URL.
34
+ *
35
+ * What is sent is a new JPEG made from it: turned upright by its own
36
+ * orientation, shrunk to fit inside `AI_PRODUCT_IMAGE_MAX_EDGE_PX` on its
37
+ * longer edge (never enlarged), laid on white where it was transparent, and
38
+ * encoded at `AI_PRODUCT_IMAGE_JPEG_QUALITY`. Encoding a new image carries none
39
+ * of the original's metadata, so no camera, date or location embedded in the
40
+ * file leaves with it. An animated image sends its first frame.
41
+ */
42
+ /** The longer edge of the picture sent, in pixels. */
43
+ export declare const AI_PRODUCT_IMAGE_MAX_EDGE_PX = 768;
44
+ /** The JPEG quality the picture is sent at. */
45
+ export declare const AI_PRODUCT_IMAGE_JPEG_QUALITY = 80;
46
+ /** The largest original read, in bytes. */
47
+ export declare const AI_PRODUCT_IMAGE_MAX_SOURCE_BYTES: number;
48
+ /** The formats read; a vector drawing is not a product photo, and is not decoded. */
49
+ export declare const AI_PRODUCT_IMAGE_TYPES: RegExp;
50
+ /**
51
+ * ASSUMED: how long the photo read takes — the media document, the CDN's
52
+ * block, the storage download and the resize — which a pass's least time
53
+ * counts (AGL-3035).
54
+ */
55
+ export declare const AI_PRODUCT_IMAGE_READ_MS = 6000;
56
+ /** The reads that leave the process, replaceable where a spec needs to. */
57
+ export interface AiProductImageSeams {
58
+ readBytes?: (firestore: FirebaseFirestore.Firestore, location: AiMediaAssetLocation, hostId: string) => Promise<AiMediaAssetBytes | null>;
59
+ encode?: (bytes: Buffer) => Promise<Buffer>;
60
+ }
61
+ export type AiProductImage = {
62
+ status: 'read';
63
+ image: AiImagePart;
64
+ } | {
65
+ status: Exclude<AiProductPhotoRead, 'read' | 'model'>;
66
+ };
67
+ /** The JPEG the model is shown, made from the original's bytes. */
68
+ export declare function encodeAiProductImage(bytes: Buffer): Promise<Buffer>;
69
+ /**
70
+ * The product's first photo as a picture part, or what kept it from being
71
+ * one. Never throws: a photo that cannot be read leaves the copy to be written
72
+ * from the product's words, and says so.
73
+ */
74
+ export declare function readAiProductImage(firestore: FirebaseFirestore.Firestore, input: {
75
+ value: string | null | undefined;
76
+ hostId: string;
77
+ orgId: string;
78
+ }, seams?: AiProductImageSeams): Promise<AiProductImage>;