@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.
- package/README.md +3 -3
- package/package.json +17 -17
- package/src/lib/activity/ai-activity-actions.js +7 -1
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-assist-provider-on-host.component.d.ts +66 -0
- package/src/lib/components/ai-assist-provider-on-host.component.js +78 -0
- package/src/lib/components/ai-assist-provider-on-host.component.js.map +1 -0
- package/src/lib/components/ai-assist-provider.component.js +9 -10
- package/src/lib/components/ai-assist-provider.component.js.map +1 -1
- package/src/lib/components/ai-automation-zones.d.ts +38 -0
- package/src/lib/components/ai-automation-zones.js +5 -1
- package/src/lib/components/ai-automation-zones.js.map +1 -1
- package/src/lib/components/ai-brief-dialog.component.d.ts +20 -2
- package/src/lib/components/ai-brief-dialog.component.js +87 -8
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
- package/src/lib/components/ai-campaign-create.component.d.ts +54 -0
- package/src/lib/components/ai-campaign-create.component.js +270 -0
- package/src/lib/components/ai-campaign-create.component.js.map +1 -0
- package/src/lib/components/ai-describe-automation.component.d.ts +8 -3
- package/src/lib/components/ai-describe-automation.component.js +15 -6
- package/src/lib/components/ai-describe-automation.component.js.map +1 -1
- package/src/lib/components/ai-describe-button.component.d.ts +20 -8
- package/src/lib/components/ai-describe-button.component.js +19 -36
- package/src/lib/components/ai-describe-button.component.js.map +1 -1
- package/src/lib/components/ai-describe-email.component.d.ts +31 -0
- package/src/lib/components/ai-describe-email.component.js +22 -0
- package/src/lib/components/ai-describe-email.component.js.map +1 -0
- package/src/lib/components/ai-describe-org-automation.component.d.ts +36 -0
- package/src/lib/components/ai-describe-org-automation.component.js +238 -0
- package/src/lib/components/ai-describe-org-automation.component.js.map +1 -0
- package/src/lib/components/ai-experiment-cards.component.d.ts +9 -1
- package/src/lib/components/ai-experiment-cards.component.js +104 -18
- package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
- package/src/lib/components/ai-explain-automation.component.js +1 -5
- package/src/lib/components/ai-explain-automation.component.js.map +1 -1
- package/src/lib/components/ai-funnel-zones.component.d.ts +61 -0
- package/src/lib/components/ai-funnel-zones.component.js +178 -0
- package/src/lib/components/ai-funnel-zones.component.js.map +1 -0
- package/src/lib/components/ai-insight-card.component.d.ts +42 -0
- package/src/lib/components/ai-insight-card.component.js +137 -0
- package/src/lib/components/ai-insight-card.component.js.map +1 -0
- package/src/lib/components/ai-insight-dialog.component.d.ts +6 -0
- package/src/lib/components/ai-insight-dialog.component.js +9 -3
- package/src/lib/components/ai-insight-dialog.component.js.map +1 -1
- package/src/lib/components/ai-job-plan.component.d.ts +7 -2
- package/src/lib/components/ai-job-plan.component.js +38 -6
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +17 -1
- package/src/lib/components/ai-job-requests.js +39 -3
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-logic-zones.d.ts +64 -0
- package/src/lib/components/ai-logic-zones.js +18 -0
- package/src/lib/components/ai-logic-zones.js.map +1 -0
- package/src/lib/components/ai-logic.component.d.ts +77 -0
- package/src/lib/components/ai-logic.component.js +553 -0
- package/src/lib/components/ai-logic.component.js.map +1 -0
- package/src/lib/components/ai-marketing-insight.component.d.ts +30 -0
- package/src/lib/components/ai-marketing-insight.component.js +80 -0
- package/src/lib/components/ai-marketing-insight.component.js.map +1 -0
- package/src/lib/components/ai-media-create.component.d.ts +55 -0
- package/src/lib/components/ai-media-create.component.js +433 -0
- package/src/lib/components/ai-media-create.component.js.map +1 -0
- package/src/lib/components/ai-overlay-cards.component.d.ts +83 -0
- package/src/lib/components/ai-overlay-cards.component.js +505 -0
- package/src/lib/components/ai-overlay-cards.component.js.map +1 -0
- package/src/lib/components/ai-permissions-on-host.component.d.ts +3 -46
- package/src/lib/components/ai-permissions-on-host.component.js +5 -53
- package/src/lib/components/ai-permissions-on-host.component.js.map +1 -1
- package/src/lib/components/ai-product-zones.d.ts +5 -0
- package/src/lib/components/ai-product-zones.js +1 -1
- package/src/lib/components/ai-product-zones.js.map +1 -1
- package/src/lib/components/ai-products-create-button.component.d.ts +42 -0
- package/src/lib/components/ai-products-create-button.component.js +67 -0
- package/src/lib/components/ai-products-create-button.component.js.map +1 -0
- package/src/lib/components/ai-products-hub-card.component.js +100 -81
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
- package/src/lib/components/ai-revise-automation.component.d.ts +16 -0
- package/src/lib/components/ai-revise-automation.component.js +207 -0
- package/src/lib/components/ai-revise-automation.component.js.map +1 -0
- package/src/lib/components/ai-site-build-page.component.js +160 -24
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.d.ts +53 -0
- package/src/lib/components/ai-upsell-dialog.component.js +177 -0
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -0
- package/src/lib/components/assist-build-card.component.d.ts +42 -0
- package/src/lib/components/assist-build-card.component.js +183 -0
- package/src/lib/components/assist-build-card.component.js.map +1 -0
- package/src/lib/components/assist-edit-canvas.d.ts +2 -0
- package/src/lib/components/assist-edit-canvas.js +56 -1
- package/src/lib/components/assist-edit-canvas.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +48 -3
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +51 -2
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/use-ai-job-run.d.ts +3 -14
- package/src/lib/components/use-ai-job-run.js +0 -50
- package/src/lib/components/use-ai-job-run.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.d.ts +58 -0
- package/src/lib/jobs/ai-build-capabilities.js +256 -0
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -0
- package/src/lib/jobs/ai-build-unit-outcome.d.ts +52 -0
- package/src/lib/jobs/ai-build-unit-outcome.js +140 -0
- package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -0
- package/src/lib/jobs/ai-job-auto-confirm.d.ts +8 -0
- package/src/lib/jobs/ai-job-auto-confirm.js +30 -6
- package/src/lib/jobs/ai-job-auto-confirm.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +144 -0
- package/src/lib/jobs/ai-job-build-step.js +668 -0
- package/src/lib/jobs/ai-job-build-step.js.map +1 -0
- package/src/lib/jobs/ai-job-draft-ids.js +9 -1
- package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.d.ts +14 -4
- package/src/lib/jobs/ai-job-drafts.js +25 -4
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-generation.d.ts +8 -0
- package/src/lib/jobs/ai-job-generation.js +13 -2
- package/src/lib/jobs/ai-job-generation.js.map +1 -1
- package/src/lib/jobs/ai-job-insight-step.js +8 -1
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +73 -0
- package/src/lib/jobs/ai-job-layout-language.js +194 -0
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -0
- package/src/lib/jobs/ai-job-layout-site-pages.d.ts +13 -2
- package/src/lib/jobs/ai-job-layout-site-pages.js +18 -2
- package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.d.ts +5 -0
- package/src/lib/jobs/ai-job-layout-step.js +105 -5
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
- package/src/lib/jobs/ai-job-logic-step.js +395 -0
- package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
- package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
- package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
- package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
- package/src/lib/jobs/ai-job-page-language.d.ts +149 -0
- package/src/lib/jobs/ai-job-page-language.js +355 -0
- package/src/lib/jobs/ai-job-page-language.js.map +1 -0
- package/src/lib/jobs/ai-job-page-sections.d.ts +37 -1
- package/src/lib/jobs/ai-job-page-sections.js +93 -11
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +4 -4
- package/src/lib/jobs/ai-job-page-step.js +111 -20
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +27 -2
- package/src/lib/jobs/ai-job-plan-step.js +87 -13
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +19 -1
- package/src/lib/jobs/ai-job-site-step.js +220 -61
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +22 -1
- package/src/lib/jobs/ai-job-text-step.js +12 -0
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-job-workflow-step.d.ts +54 -4
- package/src/lib/jobs/ai-job-workflow-step.js +320 -15
- package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +80 -2
- package/src/lib/jobs/ai-jobs.js +391 -18
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-full-height.d.ts +40 -0
- package/src/lib/jobs/ai-layout-full-height.js +82 -0
- package/src/lib/jobs/ai-layout-full-height.js.map +1 -0
- package/src/lib/jobs/ai-layout-site-facts.d.ts +54 -0
- package/src/lib/jobs/ai-layout-site-facts.js +153 -0
- package/src/lib/jobs/ai-layout-site-facts.js.map +1 -0
- package/src/lib/jobs/ai-logic-records.d.ts +40 -0
- package/src/lib/jobs/ai-logic-records.js +55 -0
- package/src/lib/jobs/ai-logic-records.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +7 -0
- package/src/lib/jobs/ai-site-publish.js +9 -0
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/ai-workflow-records.d.ts +4 -0
- package/src/lib/jobs/ai-workflow-records.js +40 -1
- package/src/lib/jobs/ai-workflow-records.js.map +1 -1
- package/src/lib/layout-language/ai-layout-compiler.d.ts +145 -0
- package/src/lib/layout-language/ai-layout-compiler.js +1148 -0
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -0
- package/src/lib/layout-language/ai-layout-copy.d.ts +73 -0
- package/src/lib/layout-language/ai-layout-copy.js +137 -0
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +52 -0
- package/src/lib/layout-language/ai-layout-frame.js +457 -0
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -0
- package/src/lib/layout-language/ai-layout-gaps.d.ts +63 -0
- package/src/lib/layout-language/ai-layout-gaps.js +345 -0
- package/src/lib/layout-language/ai-layout-gaps.js.map +1 -0
- package/src/lib/layout-language/ai-layout-language.d.ts +161 -0
- package/src/lib/layout-language/ai-layout-language.js +446 -0
- package/src/lib/layout-language/ai-layout-language.js.map +1 -0
- package/src/lib/layout-language/ai-layout-links.d.ts +80 -0
- package/src/lib/layout-language/ai-layout-links.js +109 -0
- package/src/lib/layout-language/ai-layout-links.js.map +1 -0
- package/src/lib/layout-language/ai-layout-store.d.ts +39 -0
- package/src/lib/layout-language/ai-layout-store.js +69 -0
- package/src/lib/layout-language/ai-layout-store.js.map +1 -0
- package/src/lib/layout-language/ai-layout-tree.d.ts +59 -0
- package/src/lib/layout-language/ai-layout-tree.js +84 -0
- package/src/lib/layout-language/ai-layout-tree.js.map +1 -0
- package/src/lib/lazy-widget.d.ts +45 -0
- package/src/lib/lazy-widget.js +53 -0
- package/src/lib/lazy-widget.js.map +1 -0
- package/src/lib/model/ai-automation-draft.d.ts +18 -0
- package/src/lib/model/ai-automation-draft.js +86 -0
- package/src/lib/model/ai-automation-draft.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +201 -0
- package/src/lib/model/ai-build-job.js +472 -0
- package/src/lib/model/ai-build-job.js.map +1 -0
- package/src/lib/model/ai-build-plan.d.ts +61 -0
- package/src/lib/model/ai-build-plan.js +154 -9
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-build-progress.d.ts +73 -0
- package/src/lib/model/ai-build-progress.js +170 -0
- package/src/lib/model/ai-build-progress.js.map +1 -0
- package/src/lib/model/ai-host-publish-context.d.ts +51 -0
- package/src/lib/model/ai-host-publish-context.js +104 -0
- package/src/lib/model/ai-host-publish-context.js.map +1 -0
- package/src/lib/model/ai-insight.d.ts +20 -10
- package/src/lib/model/ai-insight.js +72 -9
- package/src/lib/model/ai-insight.js.map +1 -1
- package/src/lib/model/ai-job-activity.d.ts +22 -0
- package/src/lib/model/ai-job-activity.js +25 -2
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-job-failure-copy.d.ts +38 -1
- package/src/lib/model/ai-job-failure-copy.js +56 -1
- package/src/lib/model/ai-job-failure-copy.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +3 -1
- package/src/lib/model/ai-job-notice.js +31 -9
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +99 -2
- package/src/lib/model/ai-jobs.types.js +3 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-logic-job.d.ts +108 -0
- package/src/lib/model/ai-logic-job.js +327 -0
- package/src/lib/model/ai-logic-job.js.map +1 -0
- package/src/lib/model/ai-media-credits.d.ts +52 -0
- package/src/lib/model/ai-media-credits.js +61 -0
- package/src/lib/model/ai-media-credits.js.map +1 -0
- package/src/lib/model/ai-overlay-copy.d.ts +114 -0
- package/src/lib/model/ai-overlay-copy.js +175 -0
- package/src/lib/model/ai-overlay-copy.js.map +1 -0
- package/src/lib/model/ai-site-build-progress.d.ts +25 -4
- package/src/lib/model/ai-site-build-progress.js +194 -11
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +8 -0
- package/src/lib/model/ai-site-job.js +9 -0
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-start-seo.d.ts +1 -1
- package/src/lib/model/ai-site-start.d.ts +5 -2
- package/src/lib/model/ai-site-start.js +5 -2
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/ai-svg.d.ts +69 -0
- package/src/lib/model/ai-svg.js +265 -0
- package/src/lib/model/ai-svg.js.map +1 -0
- package/src/lib/model/ai-usage-by-user.d.ts +3 -2
- package/src/lib/model/ai-usage-by-user.js.map +1 -1
- package/src/lib/model/ai-workflow-job.d.ts +92 -4
- package/src/lib/model/ai-workflow-job.js +124 -7
- package/src/lib/model/ai-workflow-job.js.map +1 -1
- package/src/lib/model/assist-build.d.ts +58 -0
- package/src/lib/model/assist-build.js +52 -0
- package/src/lib/model/assist-build.js.map +1 -0
- package/src/lib/model/assist-edit.d.ts +48 -3
- package/src/lib/model/assist-edit.js +48 -4
- package/src/lib/model/assist-edit.js.map +1 -1
- package/src/lib/plugin-config.js +2 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +308 -47
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/catalog.d.ts +82 -5
- package/src/lib/providers/catalog.js +83 -12
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/image-contract.d.ts +116 -0
- package/src/lib/providers/image-contract.js +74 -0
- package/src/lib/providers/image-contract.js.map +1 -0
- package/src/lib/providers/model-choice.js +11 -0
- package/src/lib/providers/model-choice.js.map +1 -1
- package/src/lib/providers/routing.js +18 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/providers/vertex-image.d.ts +121 -0
- package/src/lib/providers/vertex-image.js +312 -0
- package/src/lib/providers/vertex-image.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +101 -0
- package/src/lib/runtime/ai-doctrine-validators.js +525 -4
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +21 -6
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.js +4 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-eval.d.ts +15 -1
- package/src/lib/runtime/ai-eval.js +52 -1
- package/src/lib/runtime/ai-eval.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +257 -0
- package/src/lib/runtime/ai-icon-library.js +254 -0
- package/src/lib/runtime/ai-icon-library.js.map +1 -0
- package/src/lib/runtime/ai-node-tree.d.ts +9 -0
- package/src/lib/runtime/ai-node-tree.js +30 -4
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/runtime/ai-palette.d.ts +6 -0
- package/src/lib/runtime/ai-palette.generated.js +70 -0
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-palette.js.map +1 -1
- package/src/lib/runtime/experiment-variant-copy.d.ts +34 -0
- package/src/lib/runtime/experiment-variant-copy.js +102 -0
- package/src/lib/runtime/experiment-variant-copy.js.map +1 -0
- package/src/lib/server/ai-experiment-versions.d.ts +51 -0
- package/src/lib/server/ai-experiment-versions.js +270 -0
- package/src/lib/server/ai-experiment-versions.js.map +1 -0
- package/src/lib/server/ai-jobs-resume.js +74 -4
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-media-image.d.ts +66 -0
- package/src/lib/server/ai-media-image.js +521 -0
- package/src/lib/server/ai-media-image.js.map +1 -0
- package/src/lib/server/ai-media-svg.d.ts +91 -0
- package/src/lib/server/ai-media-svg.js +186 -0
- package/src/lib/server/ai-media-svg.js.map +1 -0
- package/src/lib/server/assist-build.d.ts +54 -0
- package/src/lib/server/assist-build.js +121 -0
- package/src/lib/server/assist-build.js.map +1 -0
- package/src/lib/server/assist-chat.js +108 -12
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit.js +213 -3
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/server/assist-view-context.js +242 -4
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +26 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tools/ai-logic-tool.d.ts +27 -0
- package/src/lib/tools/ai-logic-tool.js +207 -0
- package/src/lib/tools/ai-logic-tool.js.map +1 -0
- package/src/lib/tools/ai-overlay-tool.d.ts +35 -0
- package/src/lib/tools/ai-overlay-tool.js +107 -0
- package/src/lib/tools/ai-overlay-tool.js.map +1 -0
- package/src/lib/tools/ai-workflow-tool.d.ts +17 -2
- package/src/lib/tools/ai-workflow-tool.js +47 -14
- package/src/lib/tools/ai-workflow-tool.js.map +1 -1
- package/src/lib/usage/assist-job-refund.d.ts +28 -1
- package/src/lib/usage/assist-job-refund.js +44 -9
- package/src/lib/usage/assist-job-refund.js.map +1 -1
- package/src/lib/usage/assist-usage.d.ts +5 -0
- package/src/lib/usage/assist-usage.js +2 -0
- package/src/lib/usage/assist-usage.js.map +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
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 { AiSystemBlock, AiTool, AiUsage } from '../providers/contract';
|
|
18
|
+
import type { AiImageAspectRatio, AiSvgStyle } from '../providers/image-contract';
|
|
19
|
+
import { type AiGenerationCheckResult } from '../runtime/ai-doctrine';
|
|
20
|
+
/**
|
|
21
|
+
* Illustrations in Media (AGL-3602): an SVG drawn by the TEXT provider every
|
|
22
|
+
* other AI door uses — the same registry, the same meter, the same data flow
|
|
23
|
+
* the published subprocessor row for the text provider already describes —
|
|
24
|
+
* so this mode needs no new vendor and runs wherever text AI does.
|
|
25
|
+
*
|
|
26
|
+
* One generation per picture, through `runValidatedGeneration`: the answer
|
|
27
|
+
* arrives through a strict tool, `checkAiSvgMarkup` is its check, and an
|
|
28
|
+
* answer with a problem is sent back once with what to fix. A second answer
|
|
29
|
+
* with a problem is not stored and, being our failure, not charged.
|
|
30
|
+
*
|
|
31
|
+
* It runs on the provider's fast tier: an SVG is a few thousand tokens of
|
|
32
|
+
* markup and the door answers inside one request, so the model that writes
|
|
33
|
+
* them quickest is the one that fits.
|
|
34
|
+
*/
|
|
35
|
+
/** The doctrine kind the generation runs under; it reads no site tree. */
|
|
36
|
+
export declare const AI_MEDIA_SVG_KIND = "media-svg";
|
|
37
|
+
/** The name of the tool the picture arrives through. */
|
|
38
|
+
export declare const AI_MEDIA_SVG_TOOL_NAME = "submit_svg";
|
|
39
|
+
/** The answer ceiling: room for a compact picture and a re-ask's worth of care. */
|
|
40
|
+
export declare const AI_MEDIA_SVG_MAX_TOKENS = 6000;
|
|
41
|
+
export declare const AI_MEDIA_SVG_INSTRUCTIONS: AiSystemBlock[];
|
|
42
|
+
export declare function aiMediaSvgTool(): AiTool;
|
|
43
|
+
/** The question one picture is asked as. */
|
|
44
|
+
export declare function aiMediaSvgPrompt(input: {
|
|
45
|
+
prompt: string;
|
|
46
|
+
style: AiSvgStyle;
|
|
47
|
+
aspectRatio: AiImageAspectRatio;
|
|
48
|
+
palette: readonly string[];
|
|
49
|
+
variant: number;
|
|
50
|
+
count: number;
|
|
51
|
+
}): string;
|
|
52
|
+
/** What one picture's answer holds once it is read. */
|
|
53
|
+
export type AiMediaSvgAnswer = {
|
|
54
|
+
svg: string;
|
|
55
|
+
alt: string;
|
|
56
|
+
} | {
|
|
57
|
+
declined: string;
|
|
58
|
+
};
|
|
59
|
+
/** The check one answer is held to: the SVG gate, or a decline. */
|
|
60
|
+
export declare function checkAiMediaSvgAnswer(answer: Record<string, unknown>, aspectRatio: AiImageAspectRatio, style: AiSvgStyle): AiGenerationCheckResult<AiMediaSvgAnswer>;
|
|
61
|
+
/** The model an illustration runs on: the text provider's fast tier. */
|
|
62
|
+
export declare function aiMediaSvgModel(): string | undefined;
|
|
63
|
+
/** One picture's outcome. */
|
|
64
|
+
export type AiMediaSvgOutcome = {
|
|
65
|
+
kind: 'drawn';
|
|
66
|
+
svg: string;
|
|
67
|
+
alt: string;
|
|
68
|
+
usage: AiUsage;
|
|
69
|
+
model: string;
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'declined';
|
|
72
|
+
reason: string;
|
|
73
|
+
usage: AiUsage;
|
|
74
|
+
model: string;
|
|
75
|
+
}
|
|
76
|
+
/** The re-ask still failed the gate, or the model stopped: ours, never charged. */
|
|
77
|
+
| {
|
|
78
|
+
kind: 'failed';
|
|
79
|
+
usage: AiUsage;
|
|
80
|
+
model: string;
|
|
81
|
+
};
|
|
82
|
+
/** Draws one picture. A provider fault propagates for the door to answer. */
|
|
83
|
+
export declare function generateAiMediaSvg(input: {
|
|
84
|
+
model: string;
|
|
85
|
+
prompt: string;
|
|
86
|
+
style: AiSvgStyle;
|
|
87
|
+
aspectRatio: AiImageAspectRatio;
|
|
88
|
+
palette: readonly string[];
|
|
89
|
+
variant: number;
|
|
90
|
+
count: number;
|
|
91
|
+
}): Promise<AiMediaSvgOutcome>;
|
|
@@ -0,0 +1,186 @@
|
|
|
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 { aiDefaultModelFor } from "../providers/catalog.js";
|
|
18
|
+
import { resolveAiProvider } from "../providers/routing.js";
|
|
19
|
+
import { AI_SVG_MAX_BYTES, AI_SVG_VIEWBOX, checkAiSvgMarkup } from "../model/ai-svg.js";
|
|
20
|
+
import { runValidatedGeneration } from "../runtime/ai-doctrine.js";
|
|
21
|
+
/**
|
|
22
|
+
* Illustrations in Media (AGL-3602): an SVG drawn by the TEXT provider every
|
|
23
|
+
* other AI door uses — the same registry, the same meter, the same data flow
|
|
24
|
+
* the published subprocessor row for the text provider already describes —
|
|
25
|
+
* so this mode needs no new vendor and runs wherever text AI does.
|
|
26
|
+
*
|
|
27
|
+
* One generation per picture, through `runValidatedGeneration`: the answer
|
|
28
|
+
* arrives through a strict tool, `checkAiSvgMarkup` is its check, and an
|
|
29
|
+
* answer with a problem is sent back once with what to fix. A second answer
|
|
30
|
+
* with a problem is not stored and, being our failure, not charged.
|
|
31
|
+
*
|
|
32
|
+
* It runs on the provider's fast tier: an SVG is a few thousand tokens of
|
|
33
|
+
* markup and the door answers inside one request, so the model that writes
|
|
34
|
+
* them quickest is the one that fits.
|
|
35
|
+
*/ /** The doctrine kind the generation runs under; it reads no site tree. */ export const AI_MEDIA_SVG_KIND = 'media-svg';
|
|
36
|
+
/** The name of the tool the picture arrives through. */ export const AI_MEDIA_SVG_TOOL_NAME = 'submit_svg';
|
|
37
|
+
/** The answer ceiling: room for a compact picture and a re-ask's worth of care. */ export const AI_MEDIA_SVG_MAX_TOKENS = 6000;
|
|
38
|
+
/** What each kind of illustration is, in the words the model is given. */ const STYLE_BRIEF = {
|
|
39
|
+
illustration: 'A spot illustration or small scene: flat or lightly shaded vector shapes, clear silhouettes, no photographic detail.',
|
|
40
|
+
icon: 'A single icon: bold, simple geometry centered with even padding, in ONE color, or two tones of the palette at most. Readable at 24 pixels.',
|
|
41
|
+
pattern: 'A seamless, tileable background pattern: every shape that leaves one edge re-enters at the opposite edge, so tiles join without a seam. Low contrast, suitable behind text.',
|
|
42
|
+
logo: "A simple abstract logo MARK: a symbol made of a few shapes, with no lettering at all. Never a real company's logo, a trademark, a brand's symbol or anything imitating one."
|
|
43
|
+
};
|
|
44
|
+
const INSTRUCTIONS = [
|
|
45
|
+
'You draw SVG pictures for a website owner. You receive what to draw, which kind of picture it is, its shape and the colors to use, and you answer through the submit_svg tool.',
|
|
46
|
+
'',
|
|
47
|
+
'The SVG you write must:',
|
|
48
|
+
'- be exactly one <svg> element with xmlns="http://www.w3.org/2000/svg" and the viewBox you are given, and no width or height attributes;',
|
|
49
|
+
'- use only shapes, paths, groups, gradients, clipPaths and masks drawn in the document itself: never <image>, <foreignObject>, <script>, <a>, animation elements, event attributes, or a href or url(...) pointing anywhere but #ids in the same SVG;',
|
|
50
|
+
'- use no web fonts, @import or @font-face; prefer no text at all, and use only generic font families (sans-serif, serif) when text is essential;',
|
|
51
|
+
`- stay compact: well under ${Math.round(AI_SVG_MAX_BYTES / 1024 / 4)} KB, with few paths and coordinates rounded to at most one decimal place;`,
|
|
52
|
+
'- use the colors given, plus white, black and transparency, and no others.',
|
|
53
|
+
'',
|
|
54
|
+
'Write alt text: one plain sentence describing what the picture shows, for someone who cannot see it.',
|
|
55
|
+
'',
|
|
56
|
+
"Decline instead of drawing — set declined to one short sentence and leave svg and alt empty — when you are asked for a real company's or organization's logo, a trademark, a recognizable brand symbol or anything imitating one; for a real, named person; or for anything sexual, hateful, violent or otherwise unsafe. Otherwise set declined to an empty string."
|
|
57
|
+
].join('\n');
|
|
58
|
+
export const AI_MEDIA_SVG_INSTRUCTIONS = [
|
|
59
|
+
{
|
|
60
|
+
text: INSTRUCTIONS,
|
|
61
|
+
cacheBreakpoint: true
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
export function aiMediaSvgTool() {
|
|
65
|
+
return {
|
|
66
|
+
name: AI_MEDIA_SVG_TOOL_NAME,
|
|
67
|
+
description: 'Submit the SVG picture and its alt text, or decline.',
|
|
68
|
+
strict: true,
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
additionalProperties: false,
|
|
72
|
+
required: [
|
|
73
|
+
'svg',
|
|
74
|
+
'alt',
|
|
75
|
+
'declined'
|
|
76
|
+
],
|
|
77
|
+
properties: {
|
|
78
|
+
svg: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'The whole SVG document, starting with <svg and ending with </svg>.'
|
|
81
|
+
},
|
|
82
|
+
alt: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'One plain sentence describing the picture.'
|
|
85
|
+
},
|
|
86
|
+
declined: {
|
|
87
|
+
type: 'string',
|
|
88
|
+
description: 'Empty, or one short sentence saying why this picture is not drawn.'
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** The question one picture is asked as. */ export function aiMediaSvgPrompt(input) {
|
|
95
|
+
const colors = input.palette.length ? `Colors: ${input.palette.join(', ')}.` : 'Colors: a restrained palette of three to five colors of your choice.';
|
|
96
|
+
const lines = [
|
|
97
|
+
`Kind: ${input.style}. ${STYLE_BRIEF[input.style]}`,
|
|
98
|
+
`Shape: ${input.aspectRatio}, viewBox="${AI_SVG_VIEWBOX[input.aspectRatio]}".`,
|
|
99
|
+
colors
|
|
100
|
+
];
|
|
101
|
+
if (input.count > 1) {
|
|
102
|
+
lines.push(`This is version ${input.variant + 1} of ${input.count}: make it a distinct take on the same description.`);
|
|
103
|
+
}
|
|
104
|
+
lines.push('', 'Draw:', input.prompt);
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
/** The check one answer is held to: the SVG gate, or a decline. */ export function checkAiMediaSvgAnswer(answer, aspectRatio, style) {
|
|
108
|
+
const declined = typeof answer['declined'] === 'string' ? answer['declined'].trim() : '';
|
|
109
|
+
if (declined) return {
|
|
110
|
+
value: {
|
|
111
|
+
declined: declined.slice(0, 300)
|
|
112
|
+
},
|
|
113
|
+
violations: []
|
|
114
|
+
};
|
|
115
|
+
const result = checkAiSvgMarkup(answer['svg'], aspectRatio, style);
|
|
116
|
+
const alt = typeof answer['alt'] === 'string' ? answer['alt'].replace(/\s+/g, ' ').trim().slice(0, 300) : '';
|
|
117
|
+
if (result.svg) return {
|
|
118
|
+
value: {
|
|
119
|
+
svg: result.svg,
|
|
120
|
+
alt
|
|
121
|
+
},
|
|
122
|
+
violations: []
|
|
123
|
+
};
|
|
124
|
+
const violations = result.problems.map((problem)=>({
|
|
125
|
+
rule: null,
|
|
126
|
+
code: `svg-${problem.code}`,
|
|
127
|
+
message: 'The picture could not be drawn safely.',
|
|
128
|
+
detail: problem.detail
|
|
129
|
+
}));
|
|
130
|
+
return {
|
|
131
|
+
value: {
|
|
132
|
+
svg: '',
|
|
133
|
+
alt
|
|
134
|
+
},
|
|
135
|
+
violations,
|
|
136
|
+
offending: {
|
|
137
|
+
svg: '(see the problems listed)'
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** The model an illustration runs on: the text provider's fast tier. */ export function aiMediaSvgModel() {
|
|
142
|
+
const provider = resolveAiProvider();
|
|
143
|
+
return provider ? aiDefaultModelFor(provider.id, 'fast') : undefined;
|
|
144
|
+
}
|
|
145
|
+
/** Draws one picture. A provider fault propagates for the door to answer. */ export async function generateAiMediaSvg(input) {
|
|
146
|
+
const generation = {
|
|
147
|
+
model: input.model,
|
|
148
|
+
instructions: AI_MEDIA_SVG_INSTRUCTIONS,
|
|
149
|
+
inventory: undefined,
|
|
150
|
+
messages: [
|
|
151
|
+
{
|
|
152
|
+
role: 'user',
|
|
153
|
+
content: aiMediaSvgPrompt(input)
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
tool: aiMediaSvgTool(),
|
|
157
|
+
maxTokens: AI_MEDIA_SVG_MAX_TOKENS,
|
|
158
|
+
check: (answer)=>checkAiMediaSvgAnswer(answer, input.aspectRatio, input.style)
|
|
159
|
+
};
|
|
160
|
+
const result = await runValidatedGeneration(AI_MEDIA_SVG_KIND, generation);
|
|
161
|
+
const spent = {
|
|
162
|
+
usage: result.usage,
|
|
163
|
+
model: result.model
|
|
164
|
+
};
|
|
165
|
+
if (result.status === 'ok') {
|
|
166
|
+
return 'declined' in result.value ? _extends({
|
|
167
|
+
kind: 'declined',
|
|
168
|
+
reason: result.value.declined
|
|
169
|
+
}, spent) : _extends({
|
|
170
|
+
kind: 'drawn',
|
|
171
|
+
svg: result.value.svg,
|
|
172
|
+
alt: result.value.alt
|
|
173
|
+
}, spent);
|
|
174
|
+
}
|
|
175
|
+
if (result.status === 'refused') {
|
|
176
|
+
return _extends({
|
|
177
|
+
kind: 'declined',
|
|
178
|
+
reason: 'The assistant would not draw this.'
|
|
179
|
+
}, spent);
|
|
180
|
+
}
|
|
181
|
+
return _extends({
|
|
182
|
+
kind: 'failed'
|
|
183
|
+
}, spent);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//# sourceMappingURL=ai-media-svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/ai-media-svg.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 { aiDefaultModelFor } from '../providers/catalog'\nimport type { AiSystemBlock, AiTool, AiUsage } from '../providers/contract'\nimport type { AiImageAspectRatio, AiSvgStyle } from '../providers/image-contract'\nimport { resolveAiProvider } from '../providers/routing'\nimport { AI_SVG_MAX_BYTES, AI_SVG_VIEWBOX, checkAiSvgMarkup } from '../model/ai-svg'\nimport type { AiDoctrineViolation } from '../runtime/ai-doctrine-validators'\nimport {\n runValidatedGeneration,\n type AiCustomGenerationInput,\n type AiGenerationCheckResult,\n type AiValidatedGeneration,\n} from '../runtime/ai-doctrine'\n\n/**\n * Illustrations in Media (AGL-3602): an SVG drawn by the TEXT provider every\n * other AI door uses — the same registry, the same meter, the same data flow\n * the published subprocessor row for the text provider already describes —\n * so this mode needs no new vendor and runs wherever text AI does.\n *\n * One generation per picture, through `runValidatedGeneration`: the answer\n * arrives through a strict tool, `checkAiSvgMarkup` is its check, and an\n * answer with a problem is sent back once with what to fix. A second answer\n * with a problem is not stored and, being our failure, not charged.\n *\n * It runs on the provider's fast tier: an SVG is a few thousand tokens of\n * markup and the door answers inside one request, so the model that writes\n * them quickest is the one that fits.\n */\n\n/** The doctrine kind the generation runs under; it reads no site tree. */\nexport const AI_MEDIA_SVG_KIND = 'media-svg'\n\n/** The name of the tool the picture arrives through. */\nexport const AI_MEDIA_SVG_TOOL_NAME = 'submit_svg'\n\n/** The answer ceiling: room for a compact picture and a re-ask's worth of care. */\nexport const AI_MEDIA_SVG_MAX_TOKENS = 6_000\n\n/** What each kind of illustration is, in the words the model is given. */\nconst STYLE_BRIEF: Readonly<Record<AiSvgStyle, string>> = {\n illustration:\n 'A spot illustration or small scene: flat or lightly shaded vector shapes, clear silhouettes, no photographic detail.',\n icon: 'A single icon: bold, simple geometry centered with even padding, in ONE color, or two tones of the palette at most. Readable at 24 pixels.',\n pattern:\n 'A seamless, tileable background pattern: every shape that leaves one edge re-enters at the opposite edge, so tiles join without a seam. Low contrast, suitable behind text.',\n logo: \"A simple abstract logo MARK: a symbol made of a few shapes, with no lettering at all. Never a real company's logo, a trademark, a brand's symbol or anything imitating one.\",\n}\n\nconst INSTRUCTIONS = [\n 'You draw SVG pictures for a website owner. You receive what to draw, which kind of picture it is, its shape and the colors to use, and you answer through the submit_svg tool.',\n '',\n 'The SVG you write must:',\n '- be exactly one <svg> element with xmlns=\"http://www.w3.org/2000/svg\" and the viewBox you are given, and no width or height attributes;',\n '- use only shapes, paths, groups, gradients, clipPaths and masks drawn in the document itself: never <image>, <foreignObject>, <script>, <a>, animation elements, event attributes, or a href or url(...) pointing anywhere but #ids in the same SVG;',\n '- use no web fonts, @import or @font-face; prefer no text at all, and use only generic font families (sans-serif, serif) when text is essential;',\n `- stay compact: well under ${Math.round(AI_SVG_MAX_BYTES / 1024 / 4)} KB, with few paths and coordinates rounded to at most one decimal place;`,\n '- use the colors given, plus white, black and transparency, and no others.',\n '',\n 'Write alt text: one plain sentence describing what the picture shows, for someone who cannot see it.',\n '',\n \"Decline instead of drawing — set declined to one short sentence and leave svg and alt empty — when you are asked for a real company's or organization's logo, a trademark, a recognizable brand symbol or anything imitating one; for a real, named person; or for anything sexual, hateful, violent or otherwise unsafe. Otherwise set declined to an empty string.\",\n].join('\\n')\n\nexport const AI_MEDIA_SVG_INSTRUCTIONS: AiSystemBlock[] = [{ text: INSTRUCTIONS, cacheBreakpoint: true }]\n\nexport function aiMediaSvgTool(): AiTool {\n return {\n name: AI_MEDIA_SVG_TOOL_NAME,\n description: 'Submit the SVG picture and its alt text, or decline.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['svg', 'alt', 'declined'],\n properties: {\n svg: { type: 'string', description: 'The whole SVG document, starting with <svg and ending with </svg>.' },\n alt: { type: 'string', description: 'One plain sentence describing the picture.' },\n declined: {\n type: 'string',\n description: 'Empty, or one short sentence saying why this picture is not drawn.',\n },\n },\n },\n }\n}\n\n/** The question one picture is asked as. */\nexport function aiMediaSvgPrompt(input: {\n prompt: string\n style: AiSvgStyle\n aspectRatio: AiImageAspectRatio\n palette: readonly string[]\n variant: number\n count: number\n}): string {\n const colors = input.palette.length\n ? `Colors: ${input.palette.join(', ')}.`\n : 'Colors: a restrained palette of three to five colors of your choice.'\n const lines = [\n `Kind: ${input.style}. ${STYLE_BRIEF[input.style]}`,\n `Shape: ${input.aspectRatio}, viewBox=\"${AI_SVG_VIEWBOX[input.aspectRatio]}\".`,\n colors,\n ]\n if (input.count > 1) {\n lines.push(\n `This is version ${input.variant + 1} of ${input.count}: make it a distinct take on the same description.`,\n )\n }\n lines.push('', 'Draw:', input.prompt)\n return lines.join('\\n')\n}\n\n/** What one picture's answer holds once it is read. */\nexport type AiMediaSvgAnswer = { svg: string; alt: string } | { declined: string }\n\n/** The check one answer is held to: the SVG gate, or a decline. */\nexport function checkAiMediaSvgAnswer(\n answer: Record<string, unknown>,\n aspectRatio: AiImageAspectRatio,\n style: AiSvgStyle,\n): AiGenerationCheckResult<AiMediaSvgAnswer> {\n const declined = typeof answer['declined'] === 'string' ? answer['declined'].trim() : ''\n if (declined) return { value: { declined: declined.slice(0, 300) }, violations: [] }\n const result = checkAiSvgMarkup(answer['svg'], aspectRatio, style)\n const alt = typeof answer['alt'] === 'string' ? answer['alt'].replace(/\\s+/g, ' ').trim().slice(0, 300) : ''\n if (result.svg) return { value: { svg: result.svg, alt }, violations: [] }\n const violations: AiDoctrineViolation[] = result.problems.map((problem) => ({\n rule: null,\n code: `svg-${problem.code}`,\n message: 'The picture could not be drawn safely.',\n detail: problem.detail,\n }))\n return { value: { svg: '', alt }, violations, offending: { svg: '(see the problems listed)' } }\n}\n\n/** The model an illustration runs on: the text provider's fast tier. */\nexport function aiMediaSvgModel(): string | undefined {\n const provider = resolveAiProvider()\n return provider ? aiDefaultModelFor(provider.id, 'fast') : undefined\n}\n\n/** One picture's outcome. */\nexport type AiMediaSvgOutcome =\n | { kind: 'drawn'; svg: string; alt: string; usage: AiUsage; model: string }\n | { kind: 'declined'; reason: string; usage: AiUsage; model: string }\n /** The re-ask still failed the gate, or the model stopped: ours, never charged. */\n | { kind: 'failed'; usage: AiUsage; model: string }\n\n/** Draws one picture. A provider fault propagates for the door to answer. */\nexport async function generateAiMediaSvg(input: {\n model: string\n prompt: string\n style: AiSvgStyle\n aspectRatio: AiImageAspectRatio\n palette: readonly string[]\n variant: number\n count: number\n}): Promise<AiMediaSvgOutcome> {\n const generation: AiCustomGenerationInput<AiMediaSvgAnswer> = {\n model: input.model,\n instructions: AI_MEDIA_SVG_INSTRUCTIONS,\n inventory: undefined,\n messages: [{ role: 'user', content: aiMediaSvgPrompt(input) }],\n tool: aiMediaSvgTool(),\n maxTokens: AI_MEDIA_SVG_MAX_TOKENS,\n check: (answer) => checkAiMediaSvgAnswer(answer, input.aspectRatio, input.style),\n }\n const result = (await runValidatedGeneration(\n AI_MEDIA_SVG_KIND,\n generation,\n )) as AiValidatedGeneration<AiMediaSvgAnswer>\n const spent = { usage: result.usage, model: result.model }\n if (result.status === 'ok') {\n return 'declined' in result.value\n ? { kind: 'declined', reason: result.value.declined, ...spent }\n : { kind: 'drawn', svg: result.value.svg, alt: result.value.alt, ...spent }\n }\n if (result.status === 'refused') {\n return { kind: 'declined', reason: 'The assistant would not draw this.', ...spent }\n }\n return { kind: 'failed', ...spent }\n}\n"],"names":["aiDefaultModelFor","resolveAiProvider","AI_SVG_MAX_BYTES","AI_SVG_VIEWBOX","checkAiSvgMarkup","runValidatedGeneration","AI_MEDIA_SVG_KIND","AI_MEDIA_SVG_TOOL_NAME","AI_MEDIA_SVG_MAX_TOKENS","STYLE_BRIEF","illustration","icon","pattern","logo","INSTRUCTIONS","Math","round","join","AI_MEDIA_SVG_INSTRUCTIONS","text","cacheBreakpoint","aiMediaSvgTool","name","description","strict","inputSchema","type","additionalProperties","required","properties","svg","alt","declined","aiMediaSvgPrompt","input","colors","palette","length","lines","style","aspectRatio","count","push","variant","prompt","checkAiMediaSvgAnswer","answer","trim","value","slice","violations","result","replace","problems","map","problem","rule","code","message","detail","offending","aiMediaSvgModel","provider","id","undefined","generateAiMediaSvg","generation","model","instructions","inventory","messages","role","content","tool","maxTokens","check","spent","usage","status","kind","reason"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
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 AssistBuildProposal } from '../model/assist-build';
|
|
18
|
+
import type { AiTool } from '../providers/contract';
|
|
19
|
+
import { aiBuildOps } from '../jobs/ai-build-capabilities';
|
|
20
|
+
/** The strict tool the model proposes a build through. */
|
|
21
|
+
export declare function assistBuildTool(): AiTool;
|
|
22
|
+
/**
|
|
23
|
+
* The build protocol — the same for every site, so it sits inside the cached
|
|
24
|
+
* prefix. What a build can make on THIS site is per site and rides
|
|
25
|
+
* `assistBuildIntentsBlock`, after every breakpoint.
|
|
26
|
+
*/
|
|
27
|
+
export declare function assistBuildBlock(): string;
|
|
28
|
+
/** What a build can make on this site, in each owner's own words. Per site: volatile. */
|
|
29
|
+
export declare function assistBuildIntentsBlock(intents: readonly string[]): string;
|
|
30
|
+
/**
|
|
31
|
+
* The tool call held to what a build job accepts, or `null` when it is
|
|
32
|
+
* unusable. The site is the request's own, never the model's; the brief is
|
|
33
|
+
* clamped to the job door's limit, with a line naming the console page it
|
|
34
|
+
* was asked from so the plan step can read "this page" against it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveAssistBuild(input: Record<string, unknown> | null, scope: {
|
|
37
|
+
hostId: string;
|
|
38
|
+
screen: string | null;
|
|
39
|
+
}): AssistBuildProposal | null;
|
|
40
|
+
export interface AssistBuildIntentsDeps {
|
|
41
|
+
ops?: typeof aiBuildOps;
|
|
42
|
+
hasBuildRunner?: () => boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* What a build may make on this site, or `null` where none can be built: a
|
|
46
|
+
* deployment that has not loaded the build kind, or a site where no
|
|
47
|
+
* operation passes its owner's gates. The same operations the build's plan
|
|
48
|
+
* step offers, so the chat never offers what the plan cannot make.
|
|
49
|
+
*/
|
|
50
|
+
export declare function assistBuildIntents(firestore: FirebaseFirestore.Firestore, input: {
|
|
51
|
+
orgId: string;
|
|
52
|
+
hostId: string;
|
|
53
|
+
org: Record<string, unknown>;
|
|
54
|
+
}, deps?: AssistBuildIntentsDeps): Promise<string[] | null>;
|
|
@@ -0,0 +1,121 @@
|
|
|
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 { ASSIST_BUILD_ACTION_ID, ASSIST_BUILD_SUMMARY_MAX_CHARS, ASSIST_BUILD_TOOL_NAME } from "../model/assist-build.js";
|
|
17
|
+
import { aiBuildIntents, aiBuildOps } from "../jobs/ai-build-capabilities.js";
|
|
18
|
+
import { aiBuildFreeTaste } from "../jobs/ai-job-build-step.js";
|
|
19
|
+
import { AI_JOB_BRIEF_MAX_CHARS } from "../jobs/ai-job-text-step.js";
|
|
20
|
+
import { aiJobStepRunnerFor } from "../jobs/ai-jobs.js";
|
|
21
|
+
/**
|
|
22
|
+
* The chat's build rung (AGL-3616): on a site, a request that names things
|
|
23
|
+
* to make — "a few new pages, a booking form and a contact form, then an
|
|
24
|
+
* about page" — is proposed as ONE build through a strict tool. The tool
|
|
25
|
+
* carries the request, not a plan: planning is the build job's own plan
|
|
26
|
+
* step, against the site's real inventory, with its re-ask and its limits.
|
|
27
|
+
* The panel starts that job and shows its plan card with one price; nothing
|
|
28
|
+
* is built until the person confirms it, and what is built is a draft unless
|
|
29
|
+
* they asked to publish and tick the card's box.
|
|
30
|
+
*/ const STRING = {
|
|
31
|
+
type: 'string'
|
|
32
|
+
};
|
|
33
|
+
/** The strict tool the model proposes a build through. */ export function assistBuildTool() {
|
|
34
|
+
return {
|
|
35
|
+
name: ASSIST_BUILD_TOOL_NAME,
|
|
36
|
+
description: 'Propose building what the user asked for on this site: pages, a header ' + 'and footer, forms and the other things listed. The user sees a plan with ' + 'its price and confirms it before anything is made. Call at most once per ' + 'message, with the whole request.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
summary: STRING,
|
|
41
|
+
brief: STRING,
|
|
42
|
+
publish: {
|
|
43
|
+
type: 'boolean'
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
required: [
|
|
47
|
+
'summary',
|
|
48
|
+
'brief',
|
|
49
|
+
'publish'
|
|
50
|
+
],
|
|
51
|
+
additionalProperties: false
|
|
52
|
+
},
|
|
53
|
+
strict: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The build protocol — the same for every site, so it sits inside the cached
|
|
58
|
+
* prefix. What a build can make on THIS site is per site and rides
|
|
59
|
+
* `assistBuildIntentsBlock`, after every breakpoint.
|
|
60
|
+
*/ export function assistBuildBlock() {
|
|
61
|
+
return [
|
|
62
|
+
'Building on this site:',
|
|
63
|
+
`- When the user asks you to make or set up things on their site — pages, a header and footer, forms, or anything listed in the "A build here can make" block — write one or two sentences saying what you will plan, then call the ${ASSIST_BUILD_TOOL_NAME} tool once with the whole request. Write no JSON in your message.`,
|
|
64
|
+
'- brief: everything they asked for, in their words, with each page, form and other part named and what each is for. Include what the conversation already settled. Do not invent parts they did not ask for beyond what their request plainly needs (a page that shows a form needs that form).',
|
|
65
|
+
'- publish: true only when they asked for the new pages to go live or be published; otherwise false. New work is an unpublished draft by default.',
|
|
66
|
+
'- summary: one short sentence, such as "Plan three pages, a contact form and a booking service".',
|
|
67
|
+
'- Nothing is built when you call the tool: the user is shown a plan with its price and confirms it. Never say anything is made, and never quote a price.',
|
|
68
|
+
'- Only offer what the "A build here can make" block lists. If they ask for something it does not list, say plainly it cannot be built here from the chat and build the rest.',
|
|
69
|
+
'- A question, or a change to the canvas the user has open, is not a build: answer it, or use the canvas edit tool where it is offered.'
|
|
70
|
+
].join('\n');
|
|
71
|
+
}
|
|
72
|
+
/** What a build can make on this site, in each owner's own words. Per site: volatile. */ export function assistBuildIntentsBlock(intents) {
|
|
73
|
+
return [
|
|
74
|
+
'A build here can make:',
|
|
75
|
+
...intents.map((intent)=>`- ${intent}`)
|
|
76
|
+
].join('\n');
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The tool call held to what a build job accepts, or `null` when it is
|
|
80
|
+
* unusable. The site is the request's own, never the model's; the brief is
|
|
81
|
+
* clamped to the job door's limit, with a line naming the console page it
|
|
82
|
+
* was asked from so the plan step can read "this page" against it.
|
|
83
|
+
*/ export function resolveAssistBuild(input, scope) {
|
|
84
|
+
if (!input) return null;
|
|
85
|
+
const asked = typeof input['brief'] === 'string' ? input['brief'].trim() : '';
|
|
86
|
+
if (!asked) return null;
|
|
87
|
+
const where = scope.screen ? `\nAsked from the console page: ${scope.screen}` : '';
|
|
88
|
+
const brief = `${asked.slice(0, AI_JOB_BRIEF_MAX_CHARS - where.length)}${where}`.trim();
|
|
89
|
+
const summary = typeof input['summary'] === 'string' && input['summary'].trim() ? input['summary'].trim().slice(0, ASSIST_BUILD_SUMMARY_MAX_CHARS) : 'Plan what you asked for';
|
|
90
|
+
return {
|
|
91
|
+
id: ASSIST_BUILD_ACTION_ID,
|
|
92
|
+
hostId: scope.hostId,
|
|
93
|
+
brief,
|
|
94
|
+
publish: input['publish'] === true,
|
|
95
|
+
summary
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* What a build may make on this site, or `null` where none can be built: a
|
|
100
|
+
* deployment that has not loaded the build kind, or a site where no
|
|
101
|
+
* operation passes its owner's gates. The same operations the build's plan
|
|
102
|
+
* step offers, so the chat never offers what the plan cannot make.
|
|
103
|
+
*/ export async function assistBuildIntents(firestore, input, deps = {}) {
|
|
104
|
+
var _deps_hasBuildRunner, _data, _deps_ops;
|
|
105
|
+
const hasBuildRunner = (_deps_hasBuildRunner = deps.hasBuildRunner) != null ? _deps_hasBuildRunner : ()=>aiJobStepRunnerFor('build') !== null;
|
|
106
|
+
if (!hasBuildRunner()) return null;
|
|
107
|
+
const host = (_data = (await firestore.collection('hosts').doc(input.hostId).get()).data()) != null ? _data : null;
|
|
108
|
+
if (!host) return null;
|
|
109
|
+
const org = input.org;
|
|
110
|
+
const ops = await ((_deps_ops = deps.ops) != null ? _deps_ops : aiBuildOps)({
|
|
111
|
+
orgId: input.orgId,
|
|
112
|
+
hostId: input.hostId,
|
|
113
|
+
org,
|
|
114
|
+
host,
|
|
115
|
+
freeTaste: aiBuildFreeTaste(org)
|
|
116
|
+
});
|
|
117
|
+
const intents = aiBuildIntents(ops);
|
|
118
|
+
return intents.length ? intents : null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=assist-build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/assist-build.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 type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport {\n ASSIST_BUILD_ACTION_ID,\n ASSIST_BUILD_SUMMARY_MAX_CHARS,\n ASSIST_BUILD_TOOL_NAME,\n type AssistBuildProposal,\n} from '../model/assist-build'\nimport type { AiTool } from '../providers/contract'\nimport { aiBuildIntents, aiBuildOps } from '../jobs/ai-build-capabilities'\nimport { aiBuildFreeTaste } from '../jobs/ai-job-build-step'\nimport { AI_JOB_BRIEF_MAX_CHARS } from '../jobs/ai-job-text-step'\nimport { aiJobStepRunnerFor } from '../jobs/ai-jobs'\n\n/**\n * The chat's build rung (AGL-3616): on a site, a request that names things\n * to make — \"a few new pages, a booking form and a contact form, then an\n * about page\" — is proposed as ONE build through a strict tool. The tool\n * carries the request, not a plan: planning is the build job's own plan\n * step, against the site's real inventory, with its re-ask and its limits.\n * The panel starts that job and shows its plan card with one price; nothing\n * is built until the person confirms it, and what is built is a draft unless\n * they asked to publish and tick the card's box.\n */\n\nconst STRING = { type: 'string' } as const\n\n/** The strict tool the model proposes a build through. */\nexport function assistBuildTool(): AiTool {\n return {\n name: ASSIST_BUILD_TOOL_NAME,\n description:\n 'Propose building what the user asked for on this site: pages, a header ' +\n 'and footer, forms and the other things listed. The user sees a plan with ' +\n 'its price and confirms it before anything is made. Call at most once per ' +\n 'message, with the whole request.',\n inputSchema: {\n type: 'object',\n properties: {\n summary: STRING,\n brief: STRING,\n publish: { type: 'boolean' },\n },\n required: ['summary', 'brief', 'publish'],\n additionalProperties: false,\n },\n strict: true,\n }\n}\n\n/**\n * The build protocol — the same for every site, so it sits inside the cached\n * prefix. What a build can make on THIS site is per site and rides\n * `assistBuildIntentsBlock`, after every breakpoint.\n */\nexport function assistBuildBlock(): string {\n return [\n 'Building on this site:',\n `- When the user asks you to make or set up things on their site — pages, a header and footer, forms, or anything listed in the \"A build here can make\" block — write one or two sentences saying what you will plan, then call the ${ASSIST_BUILD_TOOL_NAME} tool once with the whole request. Write no JSON in your message.`,\n '- brief: everything they asked for, in their words, with each page, form and other part named and what each is for. Include what the conversation already settled. Do not invent parts they did not ask for beyond what their request plainly needs (a page that shows a form needs that form).',\n '- publish: true only when they asked for the new pages to go live or be published; otherwise false. New work is an unpublished draft by default.',\n '- summary: one short sentence, such as \"Plan three pages, a contact form and a booking service\".',\n '- Nothing is built when you call the tool: the user is shown a plan with its price and confirms it. Never say anything is made, and never quote a price.',\n '- Only offer what the \"A build here can make\" block lists. If they ask for something it does not list, say plainly it cannot be built here from the chat and build the rest.',\n '- A question, or a change to the canvas the user has open, is not a build: answer it, or use the canvas edit tool where it is offered.',\n ].join('\\n')\n}\n\n/** What a build can make on this site, in each owner's own words. Per site: volatile. */\nexport function assistBuildIntentsBlock(intents: readonly string[]): string {\n return ['A build here can make:', ...intents.map((intent) => `- ${intent}`)].join('\\n')\n}\n\n/**\n * The tool call held to what a build job accepts, or `null` when it is\n * unusable. The site is the request's own, never the model's; the brief is\n * clamped to the job door's limit, with a line naming the console page it\n * was asked from so the plan step can read \"this page\" against it.\n */\nexport function resolveAssistBuild(\n input: Record<string, unknown> | null,\n scope: { hostId: string; screen: string | null },\n): AssistBuildProposal | null {\n if (!input) return null\n const asked = typeof input['brief'] === 'string' ? input['brief'].trim() : ''\n if (!asked) return null\n const where = scope.screen ? `\\nAsked from the console page: ${scope.screen}` : ''\n const brief = `${asked.slice(0, AI_JOB_BRIEF_MAX_CHARS - where.length)}${where}`.trim()\n const summary =\n typeof input['summary'] === 'string' && input['summary'].trim()\n ? input['summary'].trim().slice(0, ASSIST_BUILD_SUMMARY_MAX_CHARS)\n : 'Plan what you asked for'\n return {\n id: ASSIST_BUILD_ACTION_ID,\n hostId: scope.hostId,\n brief,\n publish: input['publish'] === true,\n summary,\n }\n}\n\nexport interface AssistBuildIntentsDeps {\n ops?: typeof aiBuildOps\n hasBuildRunner?: () => boolean\n}\n\n/**\n * What a build may make on this site, or `null` where none can be built: a\n * deployment that has not loaded the build kind, or a site where no\n * operation passes its owner's gates. The same operations the build's plan\n * step offers, so the chat never offers what the plan cannot make.\n */\nexport async function assistBuildIntents(\n firestore: FirebaseFirestore.Firestore,\n input: { orgId: string; hostId: string; org: Record<string, unknown> },\n deps: AssistBuildIntentsDeps = {},\n): Promise<string[] | null> {\n const hasBuildRunner = deps.hasBuildRunner ?? (() => aiJobStepRunnerFor('build') !== null)\n if (!hasBuildRunner()) return null\n const host = ((await firestore.collection('hosts').doc(input.hostId).get()).data() ?? null) as Record<\n string,\n unknown\n > | null\n if (!host) return null\n const org = input.org as Partial<AglynOrgBilling>\n const ops = await (deps.ops ?? aiBuildOps)({\n orgId: input.orgId,\n hostId: input.hostId,\n org,\n host,\n freeTaste: aiBuildFreeTaste(org),\n })\n const intents = aiBuildIntents(ops)\n return intents.length ? intents : null\n}\n"],"names":["ASSIST_BUILD_ACTION_ID","ASSIST_BUILD_SUMMARY_MAX_CHARS","ASSIST_BUILD_TOOL_NAME","aiBuildIntents","aiBuildOps","aiBuildFreeTaste","AI_JOB_BRIEF_MAX_CHARS","aiJobStepRunnerFor","STRING","type","assistBuildTool","name","description","inputSchema","properties","summary","brief","publish","required","additionalProperties","strict","assistBuildBlock","join","assistBuildIntentsBlock","intents","map","intent","resolveAssistBuild","input","scope","asked","trim","where","screen","slice","length","id","hostId","assistBuildIntents","firestore","deps","hasBuildRunner","host","collection","doc","get","data","org","ops","orgId","freeTaste"],"mappings":"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"}
|