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

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 (340) hide show
  1. package/README.md +3 -3
  2. package/package.json +17 -17
  3. package/src/lib/activity/ai-activity-actions.js +7 -1
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-assist-provider-on-host.component.d.ts +66 -0
  6. package/src/lib/components/ai-assist-provider-on-host.component.js +78 -0
  7. package/src/lib/components/ai-assist-provider-on-host.component.js.map +1 -0
  8. package/src/lib/components/ai-assist-provider.component.js +9 -10
  9. package/src/lib/components/ai-assist-provider.component.js.map +1 -1
  10. package/src/lib/components/ai-automation-zones.d.ts +38 -0
  11. package/src/lib/components/ai-automation-zones.js +5 -1
  12. package/src/lib/components/ai-automation-zones.js.map +1 -1
  13. package/src/lib/components/ai-brief-dialog.component.d.ts +20 -2
  14. package/src/lib/components/ai-brief-dialog.component.js +87 -8
  15. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  16. package/src/lib/components/ai-campaign-create.component.d.ts +54 -0
  17. package/src/lib/components/ai-campaign-create.component.js +270 -0
  18. package/src/lib/components/ai-campaign-create.component.js.map +1 -0
  19. package/src/lib/components/ai-describe-automation.component.d.ts +8 -3
  20. package/src/lib/components/ai-describe-automation.component.js +15 -6
  21. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  22. package/src/lib/components/ai-describe-button.component.d.ts +20 -8
  23. package/src/lib/components/ai-describe-button.component.js +19 -36
  24. package/src/lib/components/ai-describe-button.component.js.map +1 -1
  25. package/src/lib/components/ai-describe-email.component.d.ts +31 -0
  26. package/src/lib/components/ai-describe-email.component.js +22 -0
  27. package/src/lib/components/ai-describe-email.component.js.map +1 -0
  28. package/src/lib/components/ai-describe-org-automation.component.d.ts +36 -0
  29. package/src/lib/components/ai-describe-org-automation.component.js +238 -0
  30. package/src/lib/components/ai-describe-org-automation.component.js.map +1 -0
  31. package/src/lib/components/ai-experiment-cards.component.d.ts +9 -1
  32. package/src/lib/components/ai-experiment-cards.component.js +104 -18
  33. package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
  34. package/src/lib/components/ai-explain-automation.component.js +1 -5
  35. package/src/lib/components/ai-explain-automation.component.js.map +1 -1
  36. package/src/lib/components/ai-funnel-zones.component.d.ts +61 -0
  37. package/src/lib/components/ai-funnel-zones.component.js +178 -0
  38. package/src/lib/components/ai-funnel-zones.component.js.map +1 -0
  39. package/src/lib/components/ai-insight-card.component.d.ts +42 -0
  40. package/src/lib/components/ai-insight-card.component.js +137 -0
  41. package/src/lib/components/ai-insight-card.component.js.map +1 -0
  42. package/src/lib/components/ai-insight-dialog.component.d.ts +6 -0
  43. package/src/lib/components/ai-insight-dialog.component.js +9 -3
  44. package/src/lib/components/ai-insight-dialog.component.js.map +1 -1
  45. package/src/lib/components/ai-job-plan.component.d.ts +7 -2
  46. package/src/lib/components/ai-job-plan.component.js +38 -6
  47. package/src/lib/components/ai-job-plan.component.js.map +1 -1
  48. package/src/lib/components/ai-job-requests.d.ts +17 -1
  49. package/src/lib/components/ai-job-requests.js +39 -3
  50. package/src/lib/components/ai-job-requests.js.map +1 -1
  51. package/src/lib/components/ai-logic-zones.d.ts +64 -0
  52. package/src/lib/components/ai-logic-zones.js +18 -0
  53. package/src/lib/components/ai-logic-zones.js.map +1 -0
  54. package/src/lib/components/ai-logic.component.d.ts +77 -0
  55. package/src/lib/components/ai-logic.component.js +553 -0
  56. package/src/lib/components/ai-logic.component.js.map +1 -0
  57. package/src/lib/components/ai-marketing-insight.component.d.ts +30 -0
  58. package/src/lib/components/ai-marketing-insight.component.js +80 -0
  59. package/src/lib/components/ai-marketing-insight.component.js.map +1 -0
  60. package/src/lib/components/ai-media-create.component.d.ts +55 -0
  61. package/src/lib/components/ai-media-create.component.js +433 -0
  62. package/src/lib/components/ai-media-create.component.js.map +1 -0
  63. package/src/lib/components/ai-overlay-cards.component.d.ts +83 -0
  64. package/src/lib/components/ai-overlay-cards.component.js +505 -0
  65. package/src/lib/components/ai-overlay-cards.component.js.map +1 -0
  66. package/src/lib/components/ai-permissions-on-host.component.d.ts +3 -46
  67. package/src/lib/components/ai-permissions-on-host.component.js +5 -53
  68. package/src/lib/components/ai-permissions-on-host.component.js.map +1 -1
  69. package/src/lib/components/ai-product-zones.d.ts +5 -0
  70. package/src/lib/components/ai-product-zones.js +1 -1
  71. package/src/lib/components/ai-product-zones.js.map +1 -1
  72. package/src/lib/components/ai-products-create-button.component.d.ts +42 -0
  73. package/src/lib/components/ai-products-create-button.component.js +67 -0
  74. package/src/lib/components/ai-products-create-button.component.js.map +1 -0
  75. package/src/lib/components/ai-products-hub-card.component.js +100 -81
  76. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  77. package/src/lib/components/ai-revise-automation.component.d.ts +16 -0
  78. package/src/lib/components/ai-revise-automation.component.js +207 -0
  79. package/src/lib/components/ai-revise-automation.component.js.map +1 -0
  80. package/src/lib/components/ai-site-build-page.component.js +160 -24
  81. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  82. package/src/lib/components/ai-upsell-dialog.component.d.ts +53 -0
  83. package/src/lib/components/ai-upsell-dialog.component.js +177 -0
  84. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -0
  85. package/src/lib/components/assist-build-card.component.d.ts +42 -0
  86. package/src/lib/components/assist-build-card.component.js +183 -0
  87. package/src/lib/components/assist-build-card.component.js.map +1 -0
  88. package/src/lib/components/assist-edit-canvas.d.ts +2 -0
  89. package/src/lib/components/assist-edit-canvas.js +56 -1
  90. package/src/lib/components/assist-edit-canvas.js.map +1 -1
  91. package/src/lib/components/assist-jobs-drawer.component.js +48 -3
  92. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  93. package/src/lib/components/assist-panel.component.js +51 -2
  94. package/src/lib/components/assist-panel.component.js.map +1 -1
  95. package/src/lib/components/use-ai-job-run.d.ts +3 -14
  96. package/src/lib/components/use-ai-job-run.js +0 -50
  97. package/src/lib/components/use-ai-job-run.js.map +1 -1
  98. package/src/lib/jobs/ai-build-capabilities.d.ts +58 -0
  99. package/src/lib/jobs/ai-build-capabilities.js +256 -0
  100. package/src/lib/jobs/ai-build-capabilities.js.map +1 -0
  101. package/src/lib/jobs/ai-build-unit-outcome.d.ts +52 -0
  102. package/src/lib/jobs/ai-build-unit-outcome.js +140 -0
  103. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -0
  104. package/src/lib/jobs/ai-job-auto-confirm.d.ts +8 -0
  105. package/src/lib/jobs/ai-job-auto-confirm.js +30 -6
  106. package/src/lib/jobs/ai-job-auto-confirm.js.map +1 -1
  107. package/src/lib/jobs/ai-job-build-step.d.ts +144 -0
  108. package/src/lib/jobs/ai-job-build-step.js +668 -0
  109. package/src/lib/jobs/ai-job-build-step.js.map +1 -0
  110. package/src/lib/jobs/ai-job-draft-ids.js +9 -1
  111. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
  112. package/src/lib/jobs/ai-job-drafts.d.ts +14 -4
  113. package/src/lib/jobs/ai-job-drafts.js +25 -4
  114. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  115. package/src/lib/jobs/ai-job-generation.d.ts +8 -0
  116. package/src/lib/jobs/ai-job-generation.js +13 -2
  117. package/src/lib/jobs/ai-job-generation.js.map +1 -1
  118. package/src/lib/jobs/ai-job-insight-step.js +8 -1
  119. package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
  120. package/src/lib/jobs/ai-job-layout-language.d.ts +73 -0
  121. package/src/lib/jobs/ai-job-layout-language.js +194 -0
  122. package/src/lib/jobs/ai-job-layout-language.js.map +1 -0
  123. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +13 -2
  124. package/src/lib/jobs/ai-job-layout-site-pages.js +18 -2
  125. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
  126. package/src/lib/jobs/ai-job-layout-step.d.ts +5 -0
  127. package/src/lib/jobs/ai-job-layout-step.js +105 -5
  128. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  129. package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
  130. package/src/lib/jobs/ai-job-logic-step.js +395 -0
  131. package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
  132. package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
  133. package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
  134. package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
  135. package/src/lib/jobs/ai-job-page-language.d.ts +149 -0
  136. package/src/lib/jobs/ai-job-page-language.js +355 -0
  137. package/src/lib/jobs/ai-job-page-language.js.map +1 -0
  138. package/src/lib/jobs/ai-job-page-sections.d.ts +37 -1
  139. package/src/lib/jobs/ai-job-page-sections.js +93 -11
  140. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  141. package/src/lib/jobs/ai-job-page-step.d.ts +4 -4
  142. package/src/lib/jobs/ai-job-page-step.js +111 -20
  143. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  144. package/src/lib/jobs/ai-job-plan-step.d.ts +27 -2
  145. package/src/lib/jobs/ai-job-plan-step.js +87 -13
  146. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  147. package/src/lib/jobs/ai-job-site-step.d.ts +19 -1
  148. package/src/lib/jobs/ai-job-site-step.js +220 -61
  149. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  150. package/src/lib/jobs/ai-job-text-step.d.ts +22 -1
  151. package/src/lib/jobs/ai-job-text-step.js +12 -0
  152. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  153. package/src/lib/jobs/ai-job-workflow-step.d.ts +54 -4
  154. package/src/lib/jobs/ai-job-workflow-step.js +320 -15
  155. package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
  156. package/src/lib/jobs/ai-jobs.d.ts +80 -2
  157. package/src/lib/jobs/ai-jobs.js +391 -18
  158. package/src/lib/jobs/ai-jobs.js.map +1 -1
  159. package/src/lib/jobs/ai-layout-full-height.d.ts +40 -0
  160. package/src/lib/jobs/ai-layout-full-height.js +82 -0
  161. package/src/lib/jobs/ai-layout-full-height.js.map +1 -0
  162. package/src/lib/jobs/ai-layout-site-facts.d.ts +54 -0
  163. package/src/lib/jobs/ai-layout-site-facts.js +153 -0
  164. package/src/lib/jobs/ai-layout-site-facts.js.map +1 -0
  165. package/src/lib/jobs/ai-logic-records.d.ts +40 -0
  166. package/src/lib/jobs/ai-logic-records.js +55 -0
  167. package/src/lib/jobs/ai-logic-records.js.map +1 -0
  168. package/src/lib/jobs/ai-site-publish.d.ts +7 -0
  169. package/src/lib/jobs/ai-site-publish.js +9 -0
  170. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  171. package/src/lib/jobs/ai-workflow-records.d.ts +4 -0
  172. package/src/lib/jobs/ai-workflow-records.js +40 -1
  173. package/src/lib/jobs/ai-workflow-records.js.map +1 -1
  174. package/src/lib/layout-language/ai-layout-compiler.d.ts +145 -0
  175. package/src/lib/layout-language/ai-layout-compiler.js +1148 -0
  176. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -0
  177. package/src/lib/layout-language/ai-layout-copy.d.ts +73 -0
  178. package/src/lib/layout-language/ai-layout-copy.js +137 -0
  179. package/src/lib/layout-language/ai-layout-copy.js.map +1 -0
  180. package/src/lib/layout-language/ai-layout-frame.d.ts +52 -0
  181. package/src/lib/layout-language/ai-layout-frame.js +457 -0
  182. package/src/lib/layout-language/ai-layout-frame.js.map +1 -0
  183. package/src/lib/layout-language/ai-layout-gaps.d.ts +63 -0
  184. package/src/lib/layout-language/ai-layout-gaps.js +345 -0
  185. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -0
  186. package/src/lib/layout-language/ai-layout-language.d.ts +161 -0
  187. package/src/lib/layout-language/ai-layout-language.js +446 -0
  188. package/src/lib/layout-language/ai-layout-language.js.map +1 -0
  189. package/src/lib/layout-language/ai-layout-links.d.ts +80 -0
  190. package/src/lib/layout-language/ai-layout-links.js +109 -0
  191. package/src/lib/layout-language/ai-layout-links.js.map +1 -0
  192. package/src/lib/layout-language/ai-layout-store.d.ts +39 -0
  193. package/src/lib/layout-language/ai-layout-store.js +69 -0
  194. package/src/lib/layout-language/ai-layout-store.js.map +1 -0
  195. package/src/lib/layout-language/ai-layout-tree.d.ts +59 -0
  196. package/src/lib/layout-language/ai-layout-tree.js +84 -0
  197. package/src/lib/layout-language/ai-layout-tree.js.map +1 -0
  198. package/src/lib/lazy-widget.d.ts +45 -0
  199. package/src/lib/lazy-widget.js +53 -0
  200. package/src/lib/lazy-widget.js.map +1 -0
  201. package/src/lib/model/ai-automation-draft.d.ts +18 -0
  202. package/src/lib/model/ai-automation-draft.js +86 -0
  203. package/src/lib/model/ai-automation-draft.js.map +1 -1
  204. package/src/lib/model/ai-build-job.d.ts +201 -0
  205. package/src/lib/model/ai-build-job.js +472 -0
  206. package/src/lib/model/ai-build-job.js.map +1 -0
  207. package/src/lib/model/ai-build-plan.d.ts +61 -0
  208. package/src/lib/model/ai-build-plan.js +154 -9
  209. package/src/lib/model/ai-build-plan.js.map +1 -1
  210. package/src/lib/model/ai-build-progress.d.ts +73 -0
  211. package/src/lib/model/ai-build-progress.js +170 -0
  212. package/src/lib/model/ai-build-progress.js.map +1 -0
  213. package/src/lib/model/ai-host-publish-context.d.ts +51 -0
  214. package/src/lib/model/ai-host-publish-context.js +104 -0
  215. package/src/lib/model/ai-host-publish-context.js.map +1 -0
  216. package/src/lib/model/ai-insight.d.ts +20 -10
  217. package/src/lib/model/ai-insight.js +72 -9
  218. package/src/lib/model/ai-insight.js.map +1 -1
  219. package/src/lib/model/ai-job-activity.d.ts +22 -0
  220. package/src/lib/model/ai-job-activity.js +25 -2
  221. package/src/lib/model/ai-job-activity.js.map +1 -1
  222. package/src/lib/model/ai-job-failure-copy.d.ts +38 -1
  223. package/src/lib/model/ai-job-failure-copy.js +56 -1
  224. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  225. package/src/lib/model/ai-job-notice.d.ts +3 -1
  226. package/src/lib/model/ai-job-notice.js +31 -9
  227. package/src/lib/model/ai-job-notice.js.map +1 -1
  228. package/src/lib/model/ai-jobs.types.d.ts +99 -2
  229. package/src/lib/model/ai-jobs.types.js +3 -1
  230. package/src/lib/model/ai-jobs.types.js.map +1 -1
  231. package/src/lib/model/ai-logic-job.d.ts +108 -0
  232. package/src/lib/model/ai-logic-job.js +327 -0
  233. package/src/lib/model/ai-logic-job.js.map +1 -0
  234. package/src/lib/model/ai-media-credits.d.ts +52 -0
  235. package/src/lib/model/ai-media-credits.js +61 -0
  236. package/src/lib/model/ai-media-credits.js.map +1 -0
  237. package/src/lib/model/ai-overlay-copy.d.ts +114 -0
  238. package/src/lib/model/ai-overlay-copy.js +175 -0
  239. package/src/lib/model/ai-overlay-copy.js.map +1 -0
  240. package/src/lib/model/ai-site-build-progress.d.ts +25 -4
  241. package/src/lib/model/ai-site-build-progress.js +194 -11
  242. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  243. package/src/lib/model/ai-site-job.d.ts +8 -0
  244. package/src/lib/model/ai-site-job.js +9 -0
  245. package/src/lib/model/ai-site-job.js.map +1 -1
  246. package/src/lib/model/ai-site-start-seo.d.ts +1 -1
  247. package/src/lib/model/ai-site-start.d.ts +5 -2
  248. package/src/lib/model/ai-site-start.js +5 -2
  249. package/src/lib/model/ai-site-start.js.map +1 -1
  250. package/src/lib/model/ai-svg.d.ts +69 -0
  251. package/src/lib/model/ai-svg.js +265 -0
  252. package/src/lib/model/ai-svg.js.map +1 -0
  253. package/src/lib/model/ai-usage-by-user.d.ts +3 -2
  254. package/src/lib/model/ai-usage-by-user.js.map +1 -1
  255. package/src/lib/model/ai-workflow-job.d.ts +92 -4
  256. package/src/lib/model/ai-workflow-job.js +124 -7
  257. package/src/lib/model/ai-workflow-job.js.map +1 -1
  258. package/src/lib/model/assist-build.d.ts +58 -0
  259. package/src/lib/model/assist-build.js +52 -0
  260. package/src/lib/model/assist-build.js.map +1 -0
  261. package/src/lib/model/assist-edit.d.ts +48 -3
  262. package/src/lib/model/assist-edit.js +48 -4
  263. package/src/lib/model/assist-edit.js.map +1 -1
  264. package/src/lib/plugin-config.js +2 -0
  265. package/src/lib/plugin-config.js.map +1 -1
  266. package/src/lib/plugin.js +308 -47
  267. package/src/lib/plugin.js.map +1 -1
  268. package/src/lib/providers/catalog.d.ts +82 -5
  269. package/src/lib/providers/catalog.js +83 -12
  270. package/src/lib/providers/catalog.js.map +1 -1
  271. package/src/lib/providers/image-contract.d.ts +116 -0
  272. package/src/lib/providers/image-contract.js +74 -0
  273. package/src/lib/providers/image-contract.js.map +1 -0
  274. package/src/lib/providers/model-choice.js +11 -0
  275. package/src/lib/providers/model-choice.js.map +1 -1
  276. package/src/lib/providers/routing.js +18 -0
  277. package/src/lib/providers/routing.js.map +1 -1
  278. package/src/lib/providers/vertex-image.d.ts +121 -0
  279. package/src/lib/providers/vertex-image.js +312 -0
  280. package/src/lib/providers/vertex-image.js.map +1 -0
  281. package/src/lib/runtime/ai-doctrine-validators.d.ts +101 -0
  282. package/src/lib/runtime/ai-doctrine-validators.js +525 -4
  283. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  284. package/src/lib/runtime/ai-doctrine.js +21 -6
  285. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  286. package/src/lib/runtime/ai-eval-live.js +4 -0
  287. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  288. package/src/lib/runtime/ai-eval.d.ts +15 -1
  289. package/src/lib/runtime/ai-eval.js +52 -1
  290. package/src/lib/runtime/ai-eval.js.map +1 -1
  291. package/src/lib/runtime/ai-icon-library.d.ts +257 -0
  292. package/src/lib/runtime/ai-icon-library.js +254 -0
  293. package/src/lib/runtime/ai-icon-library.js.map +1 -0
  294. package/src/lib/runtime/ai-node-tree.d.ts +9 -0
  295. package/src/lib/runtime/ai-node-tree.js +30 -4
  296. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  297. package/src/lib/runtime/ai-palette.d.ts +6 -0
  298. package/src/lib/runtime/ai-palette.generated.js +70 -0
  299. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  300. package/src/lib/runtime/ai-palette.js.map +1 -1
  301. package/src/lib/runtime/experiment-variant-copy.d.ts +34 -0
  302. package/src/lib/runtime/experiment-variant-copy.js +102 -0
  303. package/src/lib/runtime/experiment-variant-copy.js.map +1 -0
  304. package/src/lib/server/ai-experiment-versions.d.ts +51 -0
  305. package/src/lib/server/ai-experiment-versions.js +270 -0
  306. package/src/lib/server/ai-experiment-versions.js.map +1 -0
  307. package/src/lib/server/ai-jobs-resume.js +74 -4
  308. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  309. package/src/lib/server/ai-media-image.d.ts +66 -0
  310. package/src/lib/server/ai-media-image.js +521 -0
  311. package/src/lib/server/ai-media-image.js.map +1 -0
  312. package/src/lib/server/ai-media-svg.d.ts +91 -0
  313. package/src/lib/server/ai-media-svg.js +186 -0
  314. package/src/lib/server/ai-media-svg.js.map +1 -0
  315. package/src/lib/server/assist-build.d.ts +54 -0
  316. package/src/lib/server/assist-build.js +121 -0
  317. package/src/lib/server/assist-build.js.map +1 -0
  318. package/src/lib/server/assist-chat.js +108 -12
  319. package/src/lib/server/assist-chat.js.map +1 -1
  320. package/src/lib/server/assist-edit.js +213 -3
  321. package/src/lib/server/assist-edit.js.map +1 -1
  322. package/src/lib/server/assist-view-context.js +242 -4
  323. package/src/lib/server/assist-view-context.js.map +1 -1
  324. package/src/lib/server.js +26 -0
  325. package/src/lib/server.js.map +1 -1
  326. package/src/lib/tools/ai-logic-tool.d.ts +27 -0
  327. package/src/lib/tools/ai-logic-tool.js +207 -0
  328. package/src/lib/tools/ai-logic-tool.js.map +1 -0
  329. package/src/lib/tools/ai-overlay-tool.d.ts +35 -0
  330. package/src/lib/tools/ai-overlay-tool.js +107 -0
  331. package/src/lib/tools/ai-overlay-tool.js.map +1 -0
  332. package/src/lib/tools/ai-workflow-tool.d.ts +17 -2
  333. package/src/lib/tools/ai-workflow-tool.js +47 -14
  334. package/src/lib/tools/ai-workflow-tool.js.map +1 -1
  335. package/src/lib/usage/assist-job-refund.d.ts +28 -1
  336. package/src/lib/usage/assist-job-refund.js +44 -9
  337. package/src/lib/usage/assist-job-refund.js.map +1 -1
  338. package/src/lib/usage/assist-usage.d.ts +5 -0
  339. package/src/lib/usage/assist-usage.js +2 -0
  340. package/src/lib/usage/assist-usage.js.map +1 -1
@@ -0,0 +1,355 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { CANVAS_ROOT_ELEMENT_ID } from "@aglyn/aglyn/foundation/constants/canvas";
18
+ import { isAiPlanNewRef } from "../model/ai-build-plan.js";
19
+ import { aiHomeScreenIds } from "../model/ai-site-inventory.js";
20
+ import { aiCompileLayoutPage } from "../layout-language/ai-layout-compiler.js";
21
+ import { AI_LAYOUT_LANGUAGE_TEXT, AI_LAYOUT_PAGE_TOOL, aiReadLayoutPage } from "../layout-language/ai-layout-language.js";
22
+ import { aiLayoutCopyCheck } from "../layout-language/ai-layout-gaps.js";
23
+ import { aiLayoutStoredTree } from "../layout-language/ai-layout-store.js";
24
+ import { AI_GENERATION_MAX_ATTEMPTS } from "../runtime/ai-generation-bounds.js";
25
+ import { AI_STEP_TIERS } from "../providers/catalog.js";
26
+ import { runValidatedGeneration } from "../runtime/ai-doctrine.js";
27
+ import { validateAiDoctrineTree } from "../runtime/ai-doctrine-validators.js";
28
+ import { aiGenerationWorstCaseOnTierMs, aiJobStepBudget } from "./ai-job-budget.js";
29
+ import { aiJobBriefLine, aiPlanReferenceLines } from "./ai-job-generation.js";
30
+ import { aiLayoutSitePages } from "./ai-job-layout-site-pages.js";
31
+ import { aiLayoutInventedContactViolations } from "./ai-layout-site-facts.js";
32
+ /**
33
+ * A page built in the compact layout language (AGL-3660): the page step's
34
+ * pass for a site's page units — a guided start's and a build's — in place of
35
+ * the raw-tree section passes.
36
+ *
37
+ * ONE answer a page: every planned section, in the language, through
38
+ * `submit_page`. The compiler writes the tree, the palette validator stores
39
+ * it as it stores any generated tree, and the doctrine checks the whole page.
40
+ * A section the answer left out or left empty is the one thing a re-ask asks
41
+ * for: the sections that read are kept, and the second answer fills only
42
+ * what is still missing. Then the page step's last pass runs as it always
43
+ * has — the whole page held to the doctrine again, its listing written, the
44
+ * draft reported — so the item ledger, the credits and Try again work exactly
45
+ * as they did.
46
+ */ /** The unit input that says a page or a layout is built in the layout language. */ export const AI_LAYOUT_LANGUAGE_INPUT = 'layoutLanguage';
47
+ /** The unit input naming the page of the site that places its form, where it is another page. */ export const AI_LAYOUT_FORM_PAGE_INPUT = 'layoutFormPage';
48
+ /** Whether this job builds its page or its layout in the layout language. */ export function aiJobUsesLayoutLanguage(job) {
49
+ var _job_inputs;
50
+ return ((_job_inputs = job.inputs) == null ? void 0 : _job_inputs[AI_LAYOUT_LANGUAGE_INPUT]) === true;
51
+ }
52
+ /**
53
+ * The most one page's answer asks for. A section in the language is about
54
+ * 120 to 250 tokens with its copy, so the largest page a plan admits — eight
55
+ * sections — fits with room; the compiler, not the ceiling, keeps a page small.
56
+ */ export const AI_JOB_PAGE_LANGUAGE_TOKENS = 3000;
57
+ /**
58
+ * The time a language page pass needs: its lookup rounds, its answer and its
59
+ * re-ask at `AI_JOB_PAGE_LANGUAGE_TOKENS` on the tier the page step is served
60
+ * from, with the step's reads and writes.
61
+ */ /** The most the follow-up asking only for the sections an answer left out may run to. */ export const AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS = 1500;
62
+ export const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({
63
+ tier: AI_STEP_TIERS['job.page'],
64
+ maxTokens: AI_JOB_PAGE_LANGUAGE_TOKENS,
65
+ // The follow-up for sections an answer left out is one more generation.
66
+ ownReadsMs: aiGenerationWorstCaseOnTierMs({
67
+ tier: AI_STEP_TIERS['job.page'],
68
+ maxTokens: AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS
69
+ })
70
+ });
71
+ /** The doctrine scope the language doors are told: values the compiler checks itself. */ export const AI_LAYOUT_PAGE_KIND = 'layout-page';
72
+ /** The language, as the page door's cached instructions. */ export const AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS = [
73
+ {
74
+ text: [
75
+ AI_LAYOUT_LANGUAGE_TEXT,
76
+ '',
77
+ 'Answer with submit_page: the whole page, one entry in sections for each planned section, in order.'
78
+ ].join('\n'),
79
+ cacheBreakpoint: true
80
+ }
81
+ ];
82
+ /** The page of a site plan that places its form: the form the plan creates, or one the site has. */ export function aiLayoutFormPageOfPlan(plan, formIds = []) {
83
+ const created = new Set(plan.create.filter((entry)=>entry.kind === 'form').map((entry)=>`new:${entry.name}`.toLowerCase()));
84
+ const forms = new Set(formIds);
85
+ const screen = plan.screens.find((entry)=>entry.sections.some((section)=>section.uses.some((ref)=>isAiPlanNewRef(ref) ? created.has(ref.toLowerCase()) : forms.has(ref))));
86
+ return typeof (screen == null ? void 0 : screen.id) === 'string' ? screen.id : null;
87
+ }
88
+ /** Every word the job was given, which a page's contact details are held to. */ export function aiLayoutFacts(job) {
89
+ var _job_inputs;
90
+ const values = Object.values((_job_inputs = job.inputs) != null ? _job_inputs : {}).filter((value)=>typeof value === 'string');
91
+ return [
92
+ job.brief,
93
+ ...values
94
+ ].join('\n');
95
+ }
96
+ /** What a page's links resolve against: the site's pages, built and planned, its forms and components. */ export function aiLayoutPageTargets(input) {
97
+ var _ref, _own_, _ref1, _ref2;
98
+ var _job_inputs;
99
+ const { job, inventory } = input;
100
+ const own = input.own.filter((id)=>!!id);
101
+ const planned = aiLayoutSitePages(job.inputs);
102
+ const pages = [
103
+ ...planned,
104
+ ...((_ref = inventory == null ? void 0 : inventory.screens) != null ? _ref : []).filter((row)=>!row.template && !planned.some((page)=>page.id === row.id)).map((row)=>({
105
+ id: row.id,
106
+ label: row.name,
107
+ slug: row.slug
108
+ }))
109
+ ];
110
+ const formPage = (_job_inputs = job.inputs) == null ? void 0 : _job_inputs[AI_LAYOUT_FORM_PAGE_INPUT];
111
+ return {
112
+ pageId: (_own_ = own[0]) != null ? _own_ : null,
113
+ pages: pages.filter((page)=>!own.includes(page.id)),
114
+ homeIds: aiHomeScreenIds(inventory),
115
+ forms: ((_ref1 = inventory == null ? void 0 : inventory.forms) != null ? _ref1 : []).map((form)=>({
116
+ id: form.id,
117
+ name: form.name
118
+ })),
119
+ formPageId: typeof formPage === 'string' && !own.includes(formPage) ? formPage : null,
120
+ components: ((_ref2 = inventory == null ? void 0 : inventory.components) != null ? _ref2 : []).map((component)=>({
121
+ id: component.id,
122
+ name: component.name,
123
+ props: component.props
124
+ })),
125
+ facts: aiLayoutFacts(job)
126
+ };
127
+ }
128
+ /** The page's user turn: the page, the brief, the plan, its sections and where its links may go. */ export function aiLayoutPagePrompt(input) {
129
+ const { job, plan, screen, targets } = input;
130
+ const sections = screen.sections.map((section, index)=>{
131
+ const places = section.uses.length ? `; places ${section.uses.join(', ')}` : '';
132
+ const items = section.items ? `; shows ${section.items} items` : '';
133
+ return `${index + 1}. "${section.name}"${places}${items}`;
134
+ });
135
+ const pages = targets.pages.map((page)=>`${page.label} (page:${page.id})`);
136
+ const components = targets.components.map((component)=>`${component.name} (${component.id}; props ${Object.keys(component.props).join(', ') || 'none'})`);
137
+ return [
138
+ `Page: "${screen.title}" at ${screen.slug}`,
139
+ aiJobBriefLine(job),
140
+ ...aiPlanReferenceLines(plan),
141
+ `Sections to design, in order:`,
142
+ ...sections,
143
+ pages.length ? `Other pages of this site: ${pages.join(', ')}.` : 'This site has no other page to link.',
144
+ targets.forms.length ? `The site's form: ${targets.forms.map((form)=>`${form.name} (${form.id})`).join(', ')}.` : 'The site has no saved form: place none.',
145
+ ...components.length ? [
146
+ `Components this page may place: ${components.join('; ')}.`
147
+ ] : [],
148
+ input.reusableComponents ? 'Where a section repeats an item, place the component its plan line names with cards whose to is that component.' : 'This site keeps no reusable components: draw repeated items as cards, steps, stats or a list.',
149
+ // A per-job word, so two identical briefs are designed apart.
150
+ `Design seed: ${job.$id.slice(-6)}.`
151
+ ].join('\n');
152
+ }
153
+ /**
154
+ * The follow-up turn for the sections a page's answer left out (AGL-3660):
155
+ * the page as before, told which sections it already has, and asked for only
156
+ * the missing ones, in order — the one part of a page asked for again.
157
+ */ export function aiLayoutMissingSectionsPrompt(input) {
158
+ const names = input.missing.map((index)=>`${index + 1}. "${input.screen.sections[index].name}"`);
159
+ return [
160
+ input.base,
161
+ '',
162
+ `The other sections of this page are already designed. Design ONLY these, in this order, one entry in sections each: ${names.join('; ')}. Give each at least one block.`
163
+ ].join('\n');
164
+ }
165
+ /** The plan indices a page still lacks, after the answers so far. */ export function aiLayoutMissingSections(kept) {
166
+ return kept.flatMap((section, index)=>section ? [] : [
167
+ index
168
+ ]);
169
+ }
170
+ /** The violation a planned section the answer gave nothing usable for is named by. */ export const AI_LAYOUT_SECTION_MISSING_CODE = 'layout-section-missing';
171
+ /**
172
+ * The check a language page answer is held to: each planned section read,
173
+ * the page compiled, stored and checked whole. Sections that read are kept
174
+ * across the re-ask, so the second answer is asked only for what was missing,
175
+ * and a section it sends again that already read is not taken twice.
176
+ */ export function aiLayoutPageCheck(input) {
177
+ var _input_kept, _input_only;
178
+ const kept = (_input_kept = input.kept) != null ? _input_kept : input.screen.sections.map(()=>null);
179
+ const fills = (_input_only = input.only) != null ? _input_only : input.screen.sections.map((_, index)=>index);
180
+ let answers = 0;
181
+ return (answer)=>{
182
+ // The last answer a generation takes has its gaps taken out rather than asked about again.
183
+ answers += 1;
184
+ const last = answers >= AI_GENERATION_MAX_ATTEMPTS;
185
+ const reading = aiReadLayoutPage(answer, fills.length);
186
+ reading.sections.forEach((section, position)=>{
187
+ // A section the answer gives is taken as given; one it leaves out keeps
188
+ // what an earlier answer gave, so a re-ask may send only what was missing.
189
+ if (section) kept[fills[position]] = section;
190
+ });
191
+ const missing = kept.flatMap((section, index)=>section ? [] : [
192
+ index
193
+ ]);
194
+ if (missing.length) {
195
+ const names = missing.map((index)=>`${index + 1} ("${input.screen.sections[index].name}")`);
196
+ return {
197
+ value: null,
198
+ violations: [
199
+ {
200
+ rule: null,
201
+ code: AI_LAYOUT_SECTION_MISSING_CODE,
202
+ message: `The page left out section ${names.join(', ')}.`,
203
+ detail: `Answer again with every section in order; the sections you already designed are kept, so only ${names.join(', ')} ${missing.length === 1 ? 'needs' : 'need'} its design. Give each at least one block.`
204
+ }
205
+ ]
206
+ };
207
+ }
208
+ const compiled = aiCompileLayoutPage(kept, {
209
+ title: input.screen.title,
210
+ sections: input.screen.sections
211
+ }, input.targets, {
212
+ reusableComponents: input.reusableComponents,
213
+ sectionIds: input.sectionIds
214
+ });
215
+ const stored = aiLayoutStoredTree(compiled.tree, 'screen', input.context, input.sectionIds);
216
+ if (stored.ok === false) {
217
+ // The compiler writes only palette trees, which the property spec holds;
218
+ // a refusal here is the platform's, and is reported as one.
219
+ console.error('ai layout page: a compiled page did not store', {
220
+ error: stored.error
221
+ });
222
+ return {
223
+ value: null,
224
+ violations: [
225
+ {
226
+ rule: null,
227
+ code: 'layout-compile',
228
+ message: 'This page could not be built. Try again.',
229
+ detail: stored.error
230
+ }
231
+ ]
232
+ };
233
+ }
234
+ // No gap and no internal reference in the words of a page that is published as built.
235
+ const copy = aiLayoutCopyCheck(stored.nodes, CANVAS_ROOT_ELEMENT_ID, {
236
+ pages: input.targets.pages,
237
+ ids: [
238
+ ...input.targets.pages.map((page)=>page.id),
239
+ ...input.targets.forms.map((form)=>form.id),
240
+ ...input.targets.components.map((component)=>component.id),
241
+ ...input.sectionIds,
242
+ ...input.targets.pageId ? [
243
+ input.targets.pageId
244
+ ] : []
245
+ ]
246
+ }, last);
247
+ const { nodes, dropped } = copy;
248
+ const report = validateAiDoctrineTree({
249
+ rootId: CANVAS_ROOT_ELEMENT_ID,
250
+ nodes
251
+ }, 'page', _extends({}, input.context, {
252
+ scrollTargetIds: input.sectionIds
253
+ }));
254
+ // A street address or opening hours the job was never given is invented
255
+ // (rule 14, AGL-3596), the same check a layout is held to; a phone number
256
+ // or an email the compiler already writes as its gap.
257
+ const violations = [
258
+ ...report.violations,
259
+ ...copy.violations,
260
+ ...aiLayoutInventedContactViolations({
261
+ rootId: CANVAS_ROOT_ELEMENT_ID,
262
+ nodes: nodes
263
+ }, input.targets.facts)
264
+ ];
265
+ return {
266
+ value: violations.length ? null : {
267
+ nodes,
268
+ load: report.load,
269
+ settled: [
270
+ ...reading.settled,
271
+ ...compiled.settled
272
+ ],
273
+ dropped
274
+ },
275
+ violations
276
+ };
277
+ };
278
+ }
279
+ /** Two generations' spend as one: every call is billed. */ function spentTogether(first, second) {
280
+ const usage = {
281
+ inputTokens: first.usage.inputTokens + second.usage.inputTokens,
282
+ outputTokens: first.usage.outputTokens + second.usage.outputTokens,
283
+ cacheReadTokens: first.usage.cacheReadTokens + second.usage.cacheReadTokens,
284
+ cacheWriteTokens: first.usage.cacheWriteTokens + second.usage.cacheWriteTokens
285
+ };
286
+ return {
287
+ attempts: first.attempts + second.attempts,
288
+ usage,
289
+ estCostUsd: Math.round((first.estCostUsd + second.estCostUsd) * 1000000) / 1000000,
290
+ model: second.model,
291
+ stopReason: second.stopReason,
292
+ effort: second.effort
293
+ };
294
+ }
295
+ /**
296
+ * A whole page in the layout language: one answer for every section, and,
297
+ * where that answer and its re-ask still left a section out, one follow-up
298
+ * asking for only those (AGL-3660). The sections that read are kept between
299
+ * them, so the page is compiled whole once every section is designed.
300
+ */ export async function aiRunLayoutPage(input) {
301
+ var _input_observe;
302
+ const kept = input.screen.sections.map(()=>null);
303
+ const observe = (_input_observe = input.observe) != null ? _input_observe : (check)=>check;
304
+ const base = aiLayoutPagePrompt({
305
+ job: input.job,
306
+ plan: input.plan,
307
+ screen: input.screen,
308
+ targets: input.targets,
309
+ reusableComponents: input.reusableComponents
310
+ });
311
+ const ask = (content, maxTokens, only)=>runValidatedGeneration(AI_LAYOUT_PAGE_KIND, _extends({
312
+ step: 'job.page',
313
+ model: input.model,
314
+ instructions: AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS,
315
+ inventory: input.inventory,
316
+ messages: [
317
+ {
318
+ role: 'user',
319
+ content
320
+ }
321
+ ],
322
+ tool: AI_LAYOUT_PAGE_TOOL,
323
+ maxTokens,
324
+ cutOff: {
325
+ noun: 'page',
326
+ smaller: 'Write shorter copy, and fewer items in each group.'
327
+ },
328
+ thinking: 'off',
329
+ check: observe(aiLayoutPageCheck(_extends({
330
+ screen: input.screen,
331
+ sectionIds: input.sectionIds,
332
+ targets: input.targets,
333
+ context: input.context,
334
+ reusableComponents: input.reusableComponents,
335
+ kept
336
+ }, only ? {
337
+ only
338
+ } : {})))
339
+ }, input.signal ? {
340
+ signal: input.signal
341
+ } : {}));
342
+ const first = await ask(base, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model));
343
+ const missing = aiLayoutMissingSections(kept);
344
+ if (first.status !== 'needs_input' || !missing.length || !first.violations.every((violation)=>violation.code === AI_LAYOUT_SECTION_MISSING_CODE)) {
345
+ return first;
346
+ }
347
+ const second = await ask(aiLayoutMissingSectionsPrompt({
348
+ base,
349
+ screen: input.screen,
350
+ missing
351
+ }), Math.min(AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model)), missing);
352
+ return _extends({}, second, spentTogether(first, second));
353
+ }
354
+
355
+ //# sourceMappingURL=ai-job-page-language.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-page-language.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 { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport type { NodesMap } from '@aglyn/aglyn/types/nodes'\nimport { isAiPlanNewRef, type AiBuildPlanScreen } from '../model/ai-build-plan'\nimport type { AiJob, AiJobPlan } from '../model/ai-jobs.types'\nimport {\n aiHomeScreenIds,\n type AiSiteInventory,\n} from '../model/ai-site-inventory'\nimport { aiCompileLayoutPage } from '../layout-language/ai-layout-compiler'\nimport {\n AI_LAYOUT_LANGUAGE_TEXT,\n AI_LAYOUT_PAGE_TOOL,\n aiReadLayoutPage,\n type AiLayoutSection,\n type AiLayoutSettlement,\n} from '../layout-language/ai-layout-language'\nimport type {\n AiLayoutPage,\n AiLayoutTargets,\n} from '../layout-language/ai-layout-links'\nimport { aiLayoutCopyCheck } from '../layout-language/ai-layout-gaps'\nimport { aiLayoutStoredTree } from '../layout-language/ai-layout-store'\nimport { AI_GENERATION_MAX_ATTEMPTS } from '../runtime/ai-generation-bounds'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport {\n runValidatedGeneration,\n type AiGenerationCheck,\n type AiGenerationSpend,\n type AiValidatedGeneration,\n} from '../runtime/ai-doctrine'\nimport type { AiUsage } from '../providers/contract'\nimport {\n validateAiDoctrineTree,\n type AiDoctrineNode,\n type AiDoctrineTreeContext,\n type AiDoctrineViolation,\n} from '../runtime/ai-doctrine-validators'\nimport type { AiLoadEstimate } from '../runtime/ai-palette'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport { aiGenerationWorstCaseOnTierMs, aiJobStepBudget } from './ai-job-budget'\nimport { aiJobBriefLine, aiPlanReferenceLines } from './ai-job-generation'\nimport { aiLayoutSitePages } from './ai-job-layout-site-pages'\nimport { aiLayoutInventedContactViolations } from './ai-layout-site-facts'\n\n/**\n * A page built in the compact layout language (AGL-3660): the page step's\n * pass for a site's page units — a guided start's and a build's — in place of\n * the raw-tree section passes.\n *\n * ONE answer a page: every planned section, in the language, through\n * `submit_page`. The compiler writes the tree, the palette validator stores\n * it as it stores any generated tree, and the doctrine checks the whole page.\n * A section the answer left out or left empty is the one thing a re-ask asks\n * for: the sections that read are kept, and the second answer fills only\n * what is still missing. Then the page step's last pass runs as it always\n * has — the whole page held to the doctrine again, its listing written, the\n * draft reported — so the item ledger, the credits and Try again work exactly\n * as they did.\n */\n\n/** The unit input that says a page or a layout is built in the layout language. */\nexport const AI_LAYOUT_LANGUAGE_INPUT = 'layoutLanguage'\n\n/** The unit input naming the page of the site that places its form, where it is another page. */\nexport const AI_LAYOUT_FORM_PAGE_INPUT = 'layoutFormPage'\n\n/** Whether this job builds its page or its layout in the layout language. */\nexport function aiJobUsesLayoutLanguage(job: Pick<AiJob, 'inputs'>): boolean {\n return job.inputs?.[AI_LAYOUT_LANGUAGE_INPUT] === true\n}\n\n/**\n * The most one page's answer asks for. A section in the language is about\n * 120 to 250 tokens with its copy, so the largest page a plan admits — eight\n * sections — fits with room; the compiler, not the ceiling, keeps a page small.\n */\nexport const AI_JOB_PAGE_LANGUAGE_TOKENS = 3_000\n\n/**\n * The time a language page pass needs: its lookup rounds, its answer and its\n * re-ask at `AI_JOB_PAGE_LANGUAGE_TOKENS` on the tier the page step is served\n * from, with the step's reads and writes.\n */\n/** The most the follow-up asking only for the sections an answer left out may run to. */\nexport const AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS = 1_500\n\nexport const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.page'],\n maxTokens: AI_JOB_PAGE_LANGUAGE_TOKENS,\n // The follow-up for sections an answer left out is one more generation.\n ownReadsMs: aiGenerationWorstCaseOnTierMs({\n tier: AI_STEP_TIERS['job.page'],\n maxTokens: AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS,\n }),\n})\n\n/** The doctrine scope the language doors are told: values the compiler checks itself. */\nexport const AI_LAYOUT_PAGE_KIND = 'layout-page'\n\n/** The language, as the page door's cached instructions. */\nexport const AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n AI_LAYOUT_LANGUAGE_TEXT,\n '',\n 'Answer with submit_page: the whole page, one entry in sections for each planned section, in order.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n/** The page of a site plan that places its form: the form the plan creates, or one the site has. */\nexport function aiLayoutFormPageOfPlan(\n plan: Pick<AiJobPlan, 'create' | 'screens'>,\n formIds: readonly string[] = [],\n): string | null {\n const created = new Set(\n plan.create\n .filter((entry) => entry.kind === 'form')\n .map((entry) => `new:${entry.name}`.toLowerCase()),\n )\n const forms = new Set(formIds)\n const screen = plan.screens.find((entry) =>\n entry.sections.some((section) =>\n section.uses.some((ref) =>\n isAiPlanNewRef(ref) ? created.has(ref.toLowerCase()) : forms.has(ref),\n ),\n ),\n )\n return typeof screen?.id === 'string' ? screen.id : null\n}\n\n/** Every word the job was given, which a page's contact details are held to. */\nexport function aiLayoutFacts(job: Pick<AiJob, 'brief' | 'inputs'>): string {\n const values = Object.values(job.inputs ?? {}).filter(\n (value): value is string => typeof value === 'string',\n )\n return [job.brief, ...values].join('\\n')\n}\n\n/** What a page's links resolve against: the site's pages, built and planned, its forms and components. */\nexport function aiLayoutPageTargets(input: {\n job: Pick<AiJob, 'brief' | 'inputs'>\n inventory: AiSiteInventory | null\n own: ReadonlyArray<string | null | undefined>\n}): AiLayoutTargets {\n const { job, inventory } = input\n const own = input.own.filter((id): id is string => !!id)\n const planned = aiLayoutSitePages(job.inputs)\n const pages: AiLayoutPage[] = [\n ...planned,\n ...(inventory?.screens ?? [])\n .filter(\n (row) => !row.template && !planned.some((page) => page.id === row.id),\n )\n .map((row) => ({ id: row.id, label: row.name, slug: row.slug })),\n ]\n const formPage = job.inputs?.[AI_LAYOUT_FORM_PAGE_INPUT]\n return {\n pageId: own[0] ?? null,\n pages: pages.filter((page) => !own.includes(page.id)),\n homeIds: aiHomeScreenIds(inventory),\n forms: (inventory?.forms ?? []).map((form) => ({\n id: form.id,\n name: form.name,\n })),\n formPageId:\n typeof formPage === 'string' && !own.includes(formPage) ? formPage : null,\n components: (inventory?.components ?? []).map((component) => ({\n id: component.id,\n name: component.name,\n props: component.props,\n })),\n facts: aiLayoutFacts(job),\n }\n}\n\n/** The page's user turn: the page, the brief, the plan, its sections and where its links may go. */\nexport function aiLayoutPagePrompt(input: {\n job: Pick<AiJob, 'brief' | 'inputs' | '$id'>\n plan: AiJobPlan\n screen: AiBuildPlanScreen\n targets: AiLayoutTargets\n reusableComponents: boolean\n /** The sections a re-ask still needs, by plan index; absent on the first ask. */\n missing?: readonly number[]\n}): string {\n const { job, plan, screen, targets } = input\n const sections = screen.sections.map((section, index) => {\n const places = section.uses.length\n ? `; places ${section.uses.join(', ')}`\n : ''\n const items = section.items ? `; shows ${section.items} items` : ''\n return `${index + 1}. \"${section.name}\"${places}${items}`\n })\n const pages = targets.pages.map((page) => `${page.label} (page:${page.id})`)\n const components = targets.components.map(\n (component) =>\n `${component.name} (${component.id}; props ${Object.keys(component.props).join(', ') || 'none'})`,\n )\n return [\n `Page: \"${screen.title}\" at ${screen.slug}`,\n aiJobBriefLine(job),\n ...aiPlanReferenceLines(plan),\n `Sections to design, in order:`,\n ...sections,\n pages.length\n ? `Other pages of this site: ${pages.join(', ')}.`\n : 'This site has no other page to link.',\n targets.forms.length\n ? `The site's form: ${targets.forms.map((form) => `${form.name} (${form.id})`).join(', ')}.`\n : 'The site has no saved form: place none.',\n ...(components.length\n ? [`Components this page may place: ${components.join('; ')}.`]\n : []),\n input.reusableComponents\n ? 'Where a section repeats an item, place the component its plan line names with cards whose to is that component.'\n : 'This site keeps no reusable components: draw repeated items as cards, steps, stats or a list.',\n // A per-job word, so two identical briefs are designed apart.\n `Design seed: ${job.$id.slice(-6)}.`,\n ].join('\\n')\n}\n\n/** A validated language page, stored as the page keeps it. */\nexport interface AiLayoutPageBuilt {\n nodes: NodesMap\n load: AiLoadEstimate | null\n settled: AiLayoutSettlement[]\n /** What the last answer's gaps took out of the page (`ai-layout-gaps.ts`). */\n dropped: string[]\n}\n\nexport interface AiLayoutPageCheckInput {\n screen: AiBuildPlanScreen\n sectionIds: readonly string[]\n targets: AiLayoutTargets\n context: AiDoctrineTreeContext\n reusableComponents: boolean\n /**\n * What earlier answers gave, by plan index, shared between the page's\n * generations: a follow-up asking only for missing sections fills the rest.\n */\n kept?: Array<AiLayoutSection | null>\n /** The plan indices this answer's sections fill, in order; absent, every section. */\n only?: readonly number[]\n}\n\n/**\n * The follow-up turn for the sections a page's answer left out (AGL-3660):\n * the page as before, told which sections it already has, and asked for only\n * the missing ones, in order — the one part of a page asked for again.\n */\nexport function aiLayoutMissingSectionsPrompt(input: {\n base: string\n screen: AiBuildPlanScreen\n missing: readonly number[]\n}): string {\n const names = input.missing.map((index) => `${index + 1}. \"${input.screen.sections[index].name}\"`)\n return [\n input.base,\n '',\n `The other sections of this page are already designed. Design ONLY these, in this order, one entry in sections each: ${names.join('; ')}. Give each at least one block.`,\n ].join('\\n')\n}\n\n/** The plan indices a page still lacks, after the answers so far. */\nexport function aiLayoutMissingSections(kept: ReadonlyArray<AiLayoutSection | null>): number[] {\n return kept.flatMap((section, index) => (section ? [] : [index]))\n}\n\n/** The violation a planned section the answer gave nothing usable for is named by. */\nexport const AI_LAYOUT_SECTION_MISSING_CODE = 'layout-section-missing'\n\n/**\n * The check a language page answer is held to: each planned section read,\n * the page compiled, stored and checked whole. Sections that read are kept\n * across the re-ask, so the second answer is asked only for what was missing,\n * and a section it sends again that already read is not taken twice.\n */\nexport function aiLayoutPageCheck(\n input: AiLayoutPageCheckInput,\n): AiGenerationCheck<AiLayoutPageBuilt> {\n const kept: Array<AiLayoutSection | null> = input.kept ?? input.screen.sections.map(() => null)\n const fills = input.only ?? input.screen.sections.map((_, index) => index)\n let answers = 0\n return (answer) => {\n // The last answer a generation takes has its gaps taken out rather than asked about again.\n answers += 1\n const last = answers >= AI_GENERATION_MAX_ATTEMPTS\n const reading = aiReadLayoutPage(answer, fills.length)\n reading.sections.forEach((section, position) => {\n // A section the answer gives is taken as given; one it leaves out keeps\n // what an earlier answer gave, so a re-ask may send only what was missing.\n if (section) kept[fills[position]] = section\n })\n const missing = kept.flatMap((section, index) => (section ? [] : [index]))\n if (missing.length) {\n const names = missing.map(\n (index) => `${index + 1} (\"${input.screen.sections[index].name}\")`,\n )\n return {\n value: null,\n violations: [\n {\n rule: null,\n code: AI_LAYOUT_SECTION_MISSING_CODE,\n message: `The page left out section ${names.join(', ')}.`,\n detail: `Answer again with every section in order; the sections you already designed are kept, so only ${names.join(', ')} ${missing.length === 1 ? 'needs' : 'need'} its design. Give each at least one block.`,\n },\n ],\n }\n }\n const compiled = aiCompileLayoutPage(\n kept as AiLayoutSection[],\n { title: input.screen.title, sections: input.screen.sections },\n input.targets,\n {\n reusableComponents: input.reusableComponents,\n sectionIds: input.sectionIds,\n },\n )\n const stored = aiLayoutStoredTree(\n compiled.tree,\n 'screen',\n input.context,\n input.sectionIds,\n )\n if (stored.ok === false) {\n // The compiler writes only palette trees, which the property spec holds;\n // a refusal here is the platform's, and is reported as one.\n console.error('ai layout page: a compiled page did not store', {\n error: stored.error,\n })\n return {\n value: null,\n violations: [\n {\n rule: null,\n code: 'layout-compile',\n message: 'This page could not be built. Try again.',\n detail: stored.error,\n },\n ],\n }\n }\n // No gap and no internal reference in the words of a page that is published as built.\n const copy = aiLayoutCopyCheck(\n stored.nodes,\n CANVAS_ROOT_ELEMENT_ID,\n {\n pages: input.targets.pages,\n ids: [\n ...input.targets.pages.map((page) => page.id),\n ...input.targets.forms.map((form) => form.id),\n ...input.targets.components.map((component) => component.id),\n ...input.sectionIds,\n ...(input.targets.pageId ? [input.targets.pageId] : []),\n ],\n },\n last,\n )\n const { nodes, dropped } = copy\n const report = validateAiDoctrineTree(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes },\n 'page',\n {\n ...input.context,\n scrollTargetIds: input.sectionIds,\n },\n )\n // A street address or opening hours the job was never given is invented\n // (rule 14, AGL-3596), the same check a layout is held to; a phone number\n // or an email the compiler already writes as its gap.\n const violations: AiDoctrineViolation[] = [\n ...report.violations,\n ...copy.violations,\n ...aiLayoutInventedContactViolations(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes: nodes as unknown as Record<string, AiDoctrineNode> },\n input.targets.facts,\n ),\n ]\n return {\n value: violations.length\n ? null\n : {\n nodes,\n load: report.load,\n settled: [...reading.settled, ...compiled.settled],\n dropped,\n },\n violations,\n }\n }\n}\n\nexport interface AiLayoutPageRunInput {\n job: Pick<AiJob, 'brief' | 'inputs' | '$id'>\n plan: AiJobPlan\n screen: AiBuildPlanScreen\n sectionIds: readonly string[]\n targets: AiLayoutTargets\n context: AiDoctrineTreeContext\n reusableComponents: boolean\n inventory: AiSiteInventory | null\n model: string\n signal?: AbortSignal\n /** Wraps the check, for an eval that records each answer it reads. */\n observe?: (check: AiGenerationCheck<AiLayoutPageBuilt>) => AiGenerationCheck<AiLayoutPageBuilt>\n}\n\n/** Two generations' spend as one: every call is billed. */\nfunction spentTogether(first: AiGenerationSpend, second: AiGenerationSpend): AiGenerationSpend {\n const usage: AiUsage = {\n inputTokens: first.usage.inputTokens + second.usage.inputTokens,\n outputTokens: first.usage.outputTokens + second.usage.outputTokens,\n cacheReadTokens: first.usage.cacheReadTokens + second.usage.cacheReadTokens,\n cacheWriteTokens: first.usage.cacheWriteTokens + second.usage.cacheWriteTokens,\n }\n return {\n attempts: first.attempts + second.attempts,\n usage,\n estCostUsd: Math.round((first.estCostUsd + second.estCostUsd) * 1_000_000) / 1_000_000,\n model: second.model,\n stopReason: second.stopReason,\n effort: second.effort,\n }\n}\n\n/**\n * A whole page in the layout language: one answer for every section, and,\n * where that answer and its re-ask still left a section out, one follow-up\n * asking for only those (AGL-3660). The sections that read are kept between\n * them, so the page is compiled whole once every section is designed.\n */\nexport async function aiRunLayoutPage(input: AiLayoutPageRunInput): Promise<AiValidatedGeneration<AiLayoutPageBuilt>> {\n const kept: Array<AiLayoutSection | null> = input.screen.sections.map(() => null)\n const observe = input.observe ?? ((check) => check)\n const base = aiLayoutPagePrompt({\n job: input.job,\n plan: input.plan,\n screen: input.screen,\n targets: input.targets,\n reusableComponents: input.reusableComponents,\n })\n const ask = (content: string, maxTokens: number, only?: readonly number[]) =>\n runValidatedGeneration<AiLayoutPageBuilt>(AI_LAYOUT_PAGE_KIND, {\n step: 'job.page',\n model: input.model,\n instructions: AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS,\n inventory: input.inventory,\n messages: [{ role: 'user', content }],\n tool: AI_LAYOUT_PAGE_TOOL,\n maxTokens,\n cutOff: { noun: 'page', smaller: 'Write shorter copy, and fewer items in each group.' },\n thinking: 'off',\n check: observe(\n aiLayoutPageCheck({\n screen: input.screen,\n sectionIds: input.sectionIds,\n targets: input.targets,\n context: input.context,\n reusableComponents: input.reusableComponents,\n kept,\n ...(only ? { only } : {}),\n }),\n ),\n ...(input.signal ? { signal: input.signal } : {}),\n })\n const first = await ask(base, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model))\n const missing = aiLayoutMissingSections(kept)\n if (\n first.status !== 'needs_input' ||\n !missing.length ||\n !first.violations.every((violation) => violation.code === AI_LAYOUT_SECTION_MISSING_CODE)\n ) {\n return first\n }\n const second = await ask(\n aiLayoutMissingSectionsPrompt({ base, screen: input.screen, missing }),\n Math.min(AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model)),\n missing,\n )\n return { ...second, ...spentTogether(first, second) }\n}\n"],"names":["CANVAS_ROOT_ELEMENT_ID","isAiPlanNewRef","aiHomeScreenIds","aiCompileLayoutPage","AI_LAYOUT_LANGUAGE_TEXT","AI_LAYOUT_PAGE_TOOL","aiReadLayoutPage","aiLayoutCopyCheck","aiLayoutStoredTree","AI_GENERATION_MAX_ATTEMPTS","AI_STEP_TIERS","runValidatedGeneration","validateAiDoctrineTree","aiGenerationWorstCaseOnTierMs","aiJobStepBudget","aiJobBriefLine","aiPlanReferenceLines","aiLayoutSitePages","aiLayoutInventedContactViolations","AI_LAYOUT_LANGUAGE_INPUT","AI_LAYOUT_FORM_PAGE_INPUT","aiJobUsesLayoutLanguage","job","inputs","AI_JOB_PAGE_LANGUAGE_TOKENS","AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS","AI_JOB_PAGE_LANGUAGE_BUDGET","tier","maxTokens","ownReadsMs","AI_LAYOUT_PAGE_KIND","AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS","text","join","cacheBreakpoint","aiLayoutFormPageOfPlan","plan","formIds","created","Set","create","filter","entry","kind","map","name","toLowerCase","forms","screen","screens","find","sections","some","section","uses","ref","has","id","aiLayoutFacts","values","Object","value","brief","aiLayoutPageTargets","input","own","inventory","planned","pages","row","template","page","label","slug","formPage","pageId","includes","homeIds","form","formPageId","components","component","props","facts","aiLayoutPagePrompt","targets","index","places","length","items","keys","title","reusableComponents","$id","slice","aiLayoutMissingSectionsPrompt","names","missing","base","aiLayoutMissingSections","kept","flatMap","AI_LAYOUT_SECTION_MISSING_CODE","aiLayoutPageCheck","fills","only","_","answers","answer","last","reading","forEach","position","violations","rule","code","message","detail","compiled","sectionIds","stored","tree","context","ok","console","error","copy","nodes","ids","dropped","report","rootId","scrollTargetIds","load","settled","spentTogether","first","second","usage","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","attempts","estCostUsd","Math","round","model","stopReason","effort","aiRunLayoutPage","observe","check","ask","content","step","instructions","messages","role","tool","cutOff","noun","smaller","thinking","signal","status","every","violation","min"],"mappings":"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"}
@@ -103,7 +103,34 @@ export interface AiPageSectionPromptInput {
103
103
  reusableComponents?: boolean;
104
104
  /** The dataset this page is the record template of; absent for a page that is one page. */
105
105
  record?: AiPageRecordTemplate | null;
106
+ /**
107
+ * The site's other pages a link may go to by id (AGL-3596): a guided
108
+ * start's pages are minted on its plan before any is built, so the Home
109
+ * page is built before the Contact page its buttons go to exists.
110
+ */
111
+ linkablePages?: readonly AiLinkablePage[];
106
112
  }
113
+ /** A page of the site a section may link by its id, built or still to come. */
114
+ export interface AiLinkablePage {
115
+ id: string;
116
+ label: string;
117
+ slug: string;
118
+ }
119
+ /**
120
+ * The pages a section may link by id beyond the ones the site has built, and
121
+ * the one page a link that names no destination can only mean (AGL-3596).
122
+ * `planned` are a guided start's pages, minted on its plan (the input the
123
+ * layout reads them from); `own` are this page's ids, which neither counts.
124
+ * The link target is the site's one page that is neither its home nor this
125
+ * page, where it has exactly one, built or planned: a two-page guided start's
126
+ * Contact page, which its Home hero's "Book an appointment" goes to.
127
+ */
128
+ export declare function aiPageLinkablePages(inventory: AiSiteInventory | null, planned: readonly AiLinkablePage[], own: ReadonlyArray<string | null | undefined>): {
129
+ linkablePages: AiLinkablePage[];
130
+ linkTarget: string | null;
131
+ };
132
+ /** The line a section request names the site's other pages in. */
133
+ export declare function aiPageSectionLinkablePagesLine(pages: readonly AiLinkablePage[]): string | null;
107
134
  /** What a section request says where the workspace keeps no reusable components. */
108
135
  export declare const AI_PAGE_SECTION_INLINE_LINE = "This site keeps no reusable components: write a repeated item once.";
109
136
  /**
@@ -207,6 +234,8 @@ export declare function aiPageCheckContext(inventory: AiSiteInventory | null, op
207
234
  embeds?: AiDoctrineTreeContext['plannedEmbeds'];
208
235
  /** A record template's tokens, which its links and images may name (AGL-3475). */
209
236
  recordTokens?: readonly string[];
237
+ /** The site's pages still to be built that a link may go to by id (AGL-3596). */
238
+ linkablePages?: readonly AiLinkablePage[];
210
239
  }): AiDoctrineTreeContext;
211
240
  export interface AiPageSectionCheckInput {
212
241
  /** The page as stored so far; an empty page on the first pass. */
@@ -221,11 +250,18 @@ export interface AiPageSectionCheckInput {
221
250
  */
222
251
  section: Pick<AiBuildPlanSection, 'name' | 'uses' | 'items'>;
223
252
  inventory: AiSiteInventory | null;
253
+ /**
254
+ * The one page a link that goes nowhere can only mean, where the site has
255
+ * exactly one page besides its home and this one (AGL-3596): a guided
256
+ * start's Contact page. Absent or `null`, such a link is re-asked.
257
+ */
258
+ linkTarget?: string | null;
224
259
  }
225
260
  /**
226
261
  * The check a section's answer is held to: a repeated item written once drawn
227
262
  * into its copies (AGL-3053), then the palette validator on the section, with
228
- * any line it cut at its ceiling refused (AGL-3076), the doctrine's page check
263
+ * any line it cut at its ceiling refused (AGL-3076), a Grid container's items
264
+ * sized where rule 12 has one answer (AGL-3596), the doctrine's page check
229
265
  * on the page with the section added, and the plan line — every component it
230
266
  * names placed as an instance, every form bound by its id (rule 7), and as
231
267
  * many items as it promised (AGL-3024). Violations