@aglyn/plugins-ai 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +25 -0
- package/package.json +60 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +22 -0
- package/src/index.js.map +1 -0
- package/src/lib/activity/ai-activity-actions.d.ts +106 -0
- package/src/lib/activity/ai-activity-actions.js +209 -0
- package/src/lib/activity/ai-activity-actions.js.map +1 -0
- package/src/lib/activity/ai-activity.d.ts +219 -0
- package/src/lib/activity/ai-activity.js +251 -0
- package/src/lib/activity/ai-activity.js.map +1 -0
- package/src/lib/billing/ai-overage-charge.d.ts +102 -0
- package/src/lib/billing/ai-overage-charge.js +258 -0
- package/src/lib/billing/ai-overage-charge.js.map +1 -0
- package/src/lib/billing/ai-overage-close.d.ts +62 -0
- package/src/lib/billing/ai-overage-close.js +129 -0
- package/src/lib/billing/ai-overage-close.js.map +1 -0
- package/src/lib/billing/ai-overage-cutover.d.ts +63 -0
- package/src/lib/billing/ai-overage-cutover.js +114 -0
- package/src/lib/billing/ai-overage-cutover.js.map +1 -0
- package/src/lib/billing/ai-overage-events.d.ts +77 -0
- package/src/lib/billing/ai-overage-events.js +174 -0
- package/src/lib/billing/ai-overage-events.js.map +1 -0
- package/src/lib/billing/ai-overage-gate.d.ts +147 -0
- package/src/lib/billing/ai-overage-gate.js +177 -0
- package/src/lib/billing/ai-overage-gate.js.map +1 -0
- package/src/lib/billing/ai-overage-ledger.d.ts +135 -0
- package/src/lib/billing/ai-overage-ledger.js +278 -0
- package/src/lib/billing/ai-overage-ledger.js.map +1 -0
- package/src/lib/billing/ai-overage-standing-writes.d.ts +110 -0
- package/src/lib/billing/ai-overage-standing-writes.js +205 -0
- package/src/lib/billing/ai-overage-standing-writes.js.map +1 -0
- package/src/lib/billing/ai-overage-standing.d.ts +168 -0
- package/src/lib/billing/ai-overage-standing.js +215 -0
- package/src/lib/billing/ai-overage-standing.js.map +1 -0
- package/src/lib/billing/ai-overage-trigger.d.ts +30 -0
- package/src/lib/billing/ai-overage-trigger.js +76 -0
- package/src/lib/billing/ai-overage-trigger.js.map +1 -0
- package/src/lib/components/ai-allotment-editor.component.d.ts +40 -0
- package/src/lib/components/ai-allotment-editor.component.js +213 -0
- package/src/lib/components/ai-allotment-editor.component.js.map +1 -0
- package/src/lib/components/ai-assist-actions-context.d.ts +13 -0
- package/src/lib/components/ai-assist-actions-context.js +21 -0
- package/src/lib/components/ai-assist-actions-context.js.map +1 -0
- package/src/lib/components/ai-assist-provider.component.d.ts +51 -0
- package/src/lib/components/ai-assist-provider.component.js +519 -0
- package/src/lib/components/ai-assist-provider.component.js.map +1 -0
- package/src/lib/components/ai-brief-dialog.component.d.ts +56 -0
- package/src/lib/components/ai-brief-dialog.component.js +319 -0
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -0
- package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +32 -0
- package/src/lib/components/ai-collaborator-permissions-column.component.js +132 -0
- package/src/lib/components/ai-collaborator-permissions-column.component.js.map +1 -0
- package/src/lib/components/ai-credits-card.component.d.ts +34 -0
- package/src/lib/components/ai-credits-card.component.js +131 -0
- package/src/lib/components/ai-credits-card.component.js.map +1 -0
- package/src/lib/components/ai-credits-columns.component.d.ts +56 -0
- package/src/lib/components/ai-credits-columns.component.js +118 -0
- package/src/lib/components/ai-credits-columns.component.js.map +1 -0
- package/src/lib/components/ai-crm-email-draft.component.d.ts +17 -0
- package/src/lib/components/ai-crm-email-draft.component.js +159 -0
- package/src/lib/components/ai-crm-email-draft.component.js.map +1 -0
- package/src/lib/components/ai-crm-import-mapping.component.d.ts +20 -0
- package/src/lib/components/ai-crm-import-mapping.component.js +167 -0
- package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -0
- package/src/lib/components/ai-crm-record-card.component.d.ts +27 -0
- package/src/lib/components/ai-crm-record-card.component.js +263 -0
- package/src/lib/components/ai-crm-record-card.component.js.map +1 -0
- package/src/lib/components/ai-describe-automation.component.d.ts +31 -0
- package/src/lib/components/ai-describe-automation.component.js +226 -0
- package/src/lib/components/ai-describe-automation.component.js.map +1 -0
- package/src/lib/components/ai-describe-button.component.d.ts +39 -0
- package/src/lib/components/ai-describe-button.component.js +87 -0
- package/src/lib/components/ai-describe-button.component.js.map +1 -0
- package/src/lib/components/ai-describe-page.component.d.ts +26 -0
- package/src/lib/components/ai-describe-page.component.js +18 -0
- package/src/lib/components/ai-describe-page.component.js.map +1 -0
- package/src/lib/components/ai-experiment-cards.component.d.ts +75 -0
- package/src/lib/components/ai-experiment-cards.component.js +573 -0
- package/src/lib/components/ai-experiment-cards.component.js.map +1 -0
- package/src/lib/components/ai-explain-automation.component.d.ts +31 -0
- package/src/lib/components/ai-explain-automation.component.js +265 -0
- package/src/lib/components/ai-explain-automation.component.js.map +1 -0
- package/src/lib/components/ai-insight-dialog.component.d.ts +37 -0
- package/src/lib/components/ai-insight-dialog.component.js +441 -0
- package/src/lib/components/ai-insight-dialog.component.js.map +1 -0
- package/src/lib/components/ai-job-plan.component.d.ts +46 -0
- package/src/lib/components/ai-job-plan.component.js +192 -0
- package/src/lib/components/ai-job-plan.component.js.map +1 -0
- package/src/lib/components/ai-model-selector.component.d.ts +21 -0
- package/src/lib/components/ai-model-selector.component.js +109 -0
- package/src/lib/components/ai-model-selector.component.js.map +1 -0
- package/src/lib/components/ai-page-brief-dialog.component.d.ts +29 -0
- package/src/lib/components/ai-page-brief-dialog.component.js +27 -0
- package/src/lib/components/ai-page-brief-dialog.component.js.map +1 -0
- package/src/lib/components/ai-permissions-on-host.component.d.ts +55 -0
- package/src/lib/components/ai-permissions-on-host.component.js +91 -0
- package/src/lib/components/ai-permissions-on-host.component.js.map +1 -0
- package/src/lib/components/ai-product-copy-card.component.d.ts +25 -0
- package/src/lib/components/ai-product-copy-card.component.js +328 -0
- package/src/lib/components/ai-product-copy-card.component.js.map +1 -0
- package/src/lib/components/ai-product-import-option.component.d.ts +14 -0
- package/src/lib/components/ai-product-import-option.component.js +58 -0
- package/src/lib/components/ai-product-import-option.component.js.map +1 -0
- package/src/lib/components/ai-products-hub-card.component.d.ts +15 -0
- package/src/lib/components/ai-products-hub-card.component.js +418 -0
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -0
- package/src/lib/components/ai-products-proposals.component.d.ts +19 -0
- package/src/lib/components/ai-products-proposals.component.js +547 -0
- package/src/lib/components/ai-products-proposals.component.js.map +1 -0
- package/src/lib/components/ai-save-as-component.component.d.ts +38 -0
- package/src/lib/components/ai-save-as-component.component.js +231 -0
- package/src/lib/components/ai-save-as-component.component.js.map +1 -0
- package/src/lib/components/ai-seo-audit-card.component.d.ts +9 -0
- package/src/lib/components/ai-seo-audit-card.component.js +620 -0
- package/src/lib/components/ai-seo-audit-card.component.js.map +1 -0
- package/src/lib/components/ai-seo-fields-card.component.d.ts +10 -0
- package/src/lib/components/ai-seo-fields-card.component.js +453 -0
- package/src/lib/components/ai-seo-fields-card.component.js.map +1 -0
- package/src/lib/components/ai-site-batch-card.component.d.ts +32 -0
- package/src/lib/components/ai-site-batch-card.component.js +531 -0
- package/src/lib/components/ai-site-batch-card.component.js.map +1 -0
- package/src/lib/components/ai-site-seo-start-card.component.d.ts +26 -0
- package/src/lib/components/ai-site-seo-start-card.component.js +178 -0
- package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -0
- package/src/lib/components/ai-site-start-card.component.d.ts +19 -0
- package/src/lib/components/ai-site-start-card.component.js +348 -0
- package/src/lib/components/ai-site-start-card.component.js.map +1 -0
- package/src/lib/components/ai-template-collection-field.component.d.ts +32 -0
- package/src/lib/components/ai-template-collection-field.component.js +63 -0
- package/src/lib/components/ai-template-collection-field.component.js.map +1 -0
- package/src/lib/components/ai-theme-proposal-card.component.d.ts +6 -0
- package/src/lib/components/ai-theme-proposal-card.component.js +619 -0
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -0
- package/src/lib/components/ai-usage-strip.component.d.ts +27 -0
- package/src/lib/components/ai-usage-strip.component.js +145 -0
- package/src/lib/components/ai-usage-strip.component.js.map +1 -0
- package/src/lib/components/assist-edit-canvas.d.ts +169 -0
- package/src/lib/components/assist-edit-canvas.js +636 -0
- package/src/lib/components/assist-edit-canvas.js.map +1 -0
- package/src/lib/components/assist-edit-card.component.d.ts +16 -0
- package/src/lib/components/assist-edit-card.component.js +181 -0
- package/src/lib/components/assist-edit-card.component.js.map +1 -0
- package/src/lib/components/assist-jobs-drawer.component.d.ts +72 -0
- package/src/lib/components/assist-jobs-drawer.component.js +626 -0
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -0
- package/src/lib/components/assist-panel.component.d.ts +136 -0
- package/src/lib/components/assist-panel.component.js +1099 -0
- package/src/lib/components/assist-panel.component.js.map +1 -0
- package/src/lib/components/assist-signals-page.component.d.ts +3 -0
- package/src/lib/components/assist-signals-page.component.js +1017 -0
- package/src/lib/components/assist-signals-page.component.js.map +1 -0
- package/src/lib/components/besigner-ai-controls.component.d.ts +29 -0
- package/src/lib/components/besigner-ai-controls.component.js +81 -0
- package/src/lib/components/besigner-ai-controls.component.js.map +1 -0
- package/src/lib/components/billing-ai-allotments.component.d.ts +36 -0
- package/src/lib/components/billing-ai-allotments.component.js +486 -0
- package/src/lib/components/billing-ai-allotments.component.js.map +1 -0
- package/src/lib/components/billing-ai-top-users.component.d.ts +44 -0
- package/src/lib/components/billing-ai-top-users.component.js +304 -0
- package/src/lib/components/billing-ai-top-users.component.js.map +1 -0
- package/src/lib/components/billing-assist-overage-card.component.d.ts +69 -0
- package/src/lib/components/billing-assist-overage-card.component.js +437 -0
- package/src/lib/components/billing-assist-overage-card.component.js.map +1 -0
- package/src/lib/components/host-ai-allotments.component.d.ts +40 -0
- package/src/lib/components/host-ai-allotments.component.js +239 -0
- package/src/lib/components/host-ai-allotments.component.js.map +1 -0
- package/src/lib/components/member-ai-allotment-card.component.d.ts +28 -0
- package/src/lib/components/member-ai-allotment-card.component.js +172 -0
- package/src/lib/components/member-ai-allotment-card.component.js.map +1 -0
- package/src/lib/components/member-ai-usage-card.component.d.ts +28 -0
- package/src/lib/components/member-ai-usage-card.component.js +240 -0
- package/src/lib/components/member-ai-usage-card.component.js.map +1 -0
- package/src/lib/components/staff-org-ai-card.component.d.ts +17 -0
- package/src/lib/components/staff-org-ai-card.component.js +739 -0
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -0
- package/src/lib/components/staff-org-usage-ai-columns.component.d.ts +41 -0
- package/src/lib/components/staff-org-usage-ai-columns.component.js +65 -0
- package/src/lib/components/staff-org-usage-ai-columns.component.js.map +1 -0
- package/src/lib/components/staff-orgs-ai-spend-column.component.d.ts +28 -0
- package/src/lib/components/staff-orgs-ai-spend-column.component.js +89 -0
- package/src/lib/components/staff-orgs-ai-spend-column.component.js.map +1 -0
- package/src/lib/components/staff-user-ai-usage-card.component.d.ts +27 -0
- package/src/lib/components/staff-user-ai-usage-card.component.js +183 -0
- package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -0
- package/src/lib/components/use-ai-allotments.d.ts +49 -0
- package/src/lib/components/use-ai-allotments.js +171 -0
- package/src/lib/components/use-ai-allotments.js.map +1 -0
- package/src/lib/components/use-ai-crm-answer.d.ts +50 -0
- package/src/lib/components/use-ai-crm-answer.js +220 -0
- package/src/lib/components/use-ai-crm-answer.js.map +1 -0
- package/src/lib/components/use-ai-job-run.d.ts +51 -0
- package/src/lib/components/use-ai-job-run.js +176 -0
- package/src/lib/components/use-ai-job-run.js.map +1 -0
- package/src/lib/components/use-ai-model-choice.d.ts +47 -0
- package/src/lib/components/use-ai-model-choice.js +150 -0
- package/src/lib/components/use-ai-model-choice.js.map +1 -0
- package/src/lib/components/use-ai-products-jobs.d.ts +36 -0
- package/src/lib/components/use-ai-products-jobs.js +190 -0
- package/src/lib/components/use-ai-products-jobs.js.map +1 -0
- package/src/lib/components/use-ai-usage-meter.d.ts +11 -0
- package/src/lib/components/use-ai-usage-meter.js +96 -0
- package/src/lib/components/use-ai-usage-meter.js.map +1 -0
- package/src/lib/components/use-org-ai-usage.d.ts +42 -0
- package/src/lib/components/use-org-ai-usage.js +181 -0
- package/src/lib/components/use-org-ai-usage.js.map +1 -0
- package/src/lib/components/use-staff-orgs-ai-spend.d.ts +18 -0
- package/src/lib/components/use-staff-orgs-ai-spend.js +127 -0
- package/src/lib/components/use-staff-orgs-ai-spend.js.map +1 -0
- package/src/lib/constants.d.ts +24 -0
- package/src/lib/constants.js +23 -0
- package/src/lib/constants.js.map +1 -0
- package/src/lib/declarations.d.ts +48 -0
- package/src/lib/declarations.js +129 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.d.ts +35 -0
- package/src/lib/declarations.server.js +138 -0
- package/src/lib/declarations.server.js.map +1 -0
- package/src/lib/insights/ai-figure-readers.d.ts +90 -0
- package/src/lib/insights/ai-figure-readers.js +863 -0
- package/src/lib/insights/ai-figure-readers.js.map +1 -0
- package/src/lib/insights/ai-insight-digest.d.ts +165 -0
- package/src/lib/insights/ai-insight-digest.js +363 -0
- package/src/lib/insights/ai-insight-digest.js.map +1 -0
- package/src/lib/insights/ai-insight-readers.d.ts +71 -0
- package/src/lib/insights/ai-insight-readers.js +141 -0
- package/src/lib/insights/ai-insight-readers.js.map +1 -0
- package/src/lib/jobs/ai-crm-access.d.ts +61 -0
- package/src/lib/jobs/ai-crm-access.js +94 -0
- package/src/lib/jobs/ai-crm-access.js.map +1 -0
- package/src/lib/jobs/ai-email-bindings.d.ts +97 -0
- package/src/lib/jobs/ai-email-bindings.js +147 -0
- package/src/lib/jobs/ai-email-bindings.js.map +1 -0
- package/src/lib/jobs/ai-job-admission.d.ts +82 -0
- package/src/lib/jobs/ai-job-admission.js +45 -0
- package/src/lib/jobs/ai-job-admission.js.map +1 -0
- package/src/lib/jobs/ai-job-budget.d.ts +167 -0
- package/src/lib/jobs/ai-job-budget.js +161 -0
- package/src/lib/jobs/ai-job-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-campaign-step.d.ts +108 -0
- package/src/lib/jobs/ai-job-campaign-step.js +340 -0
- package/src/lib/jobs/ai-job-campaign-step.js.map +1 -0
- package/src/lib/jobs/ai-job-component-checks.d.ts +74 -0
- package/src/lib/jobs/ai-job-component-checks.js +442 -0
- package/src/lib/jobs/ai-job-component-checks.js.map +1 -0
- package/src/lib/jobs/ai-job-component-step.d.ts +75 -0
- package/src/lib/jobs/ai-job-component-step.js +262 -0
- package/src/lib/jobs/ai-job-component-step.js.map +1 -0
- package/src/lib/jobs/ai-job-crm-step.d.ts +192 -0
- package/src/lib/jobs/ai-job-crm-step.js +734 -0
- package/src/lib/jobs/ai-job-crm-step.js.map +1 -0
- package/src/lib/jobs/ai-job-draft-ids.d.ts +62 -0
- package/src/lib/jobs/ai-job-draft-ids.js +132 -0
- package/src/lib/jobs/ai-job-draft-ids.js.map +1 -0
- package/src/lib/jobs/ai-job-drafts.d.ts +304 -0
- package/src/lib/jobs/ai-job-drafts.js +557 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -0
- package/src/lib/jobs/ai-job-email-step.d.ts +195 -0
- package/src/lib/jobs/ai-job-email-step.js +547 -0
- package/src/lib/jobs/ai-job-email-step.js.map +1 -0
- package/src/lib/jobs/ai-job-experiment-step.d.ts +105 -0
- package/src/lib/jobs/ai-job-experiment-step.js +445 -0
- package/src/lib/jobs/ai-job-experiment-step.js.map +1 -0
- package/src/lib/jobs/ai-job-form-step.d.ts +250 -0
- package/src/lib/jobs/ai-job-form-step.js +634 -0
- package/src/lib/jobs/ai-job-form-step.js.map +1 -0
- package/src/lib/jobs/ai-job-generation.d.ts +114 -0
- package/src/lib/jobs/ai-job-generation.js +384 -0
- package/src/lib/jobs/ai-job-generation.js.map +1 -0
- package/src/lib/jobs/ai-job-insight-budget.d.ts +41 -0
- package/src/lib/jobs/ai-job-insight-budget.js +46 -0
- package/src/lib/jobs/ai-job-insight-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-insight-step.d.ts +58 -0
- package/src/lib/jobs/ai-job-insight-step.js +350 -0
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -0
- package/src/lib/jobs/ai-job-layout-step.d.ts +103 -0
- package/src/lib/jobs/ai-job-layout-step.js +340 -0
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -0
- package/src/lib/jobs/ai-job-page-budget.d.ts +57 -0
- package/src/lib/jobs/ai-job-page-budget.js +60 -0
- package/src/lib/jobs/ai-job-page-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-page-sections.d.ts +150 -0
- package/src/lib/jobs/ai-job-page-sections.js +450 -0
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -0
- package/src/lib/jobs/ai-job-page-step.d.ts +198 -0
- package/src/lib/jobs/ai-job-page-step.js +667 -0
- package/src/lib/jobs/ai-job-page-step.js.map +1 -0
- package/src/lib/jobs/ai-job-plan-conformance.d.ts +107 -0
- package/src/lib/jobs/ai-job-plan-conformance.js +164 -0
- package/src/lib/jobs/ai-job-plan-conformance.js.map +1 -0
- package/src/lib/jobs/ai-job-plan-step.d.ts +196 -0
- package/src/lib/jobs/ai-job-plan-step.js +458 -0
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -0
- package/src/lib/jobs/ai-job-plugin-drafts.d.ts +76 -0
- package/src/lib/jobs/ai-job-plugin-drafts.js +91 -0
- package/src/lib/jobs/ai-job-plugin-drafts.js.map +1 -0
- package/src/lib/jobs/ai-job-products-step.d.ts +106 -0
- package/src/lib/jobs/ai-job-products-step.js +436 -0
- package/src/lib/jobs/ai-job-products-step.js.map +1 -0
- package/src/lib/jobs/ai-job-seo-budget.d.ts +52 -0
- package/src/lib/jobs/ai-job-seo-budget.js +63 -0
- package/src/lib/jobs/ai-job-seo-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-seo-step.d.ts +145 -0
- package/src/lib/jobs/ai-job-seo-step.js +809 -0
- package/src/lib/jobs/ai-job-seo-step.js.map +1 -0
- package/src/lib/jobs/ai-job-site-step.d.ts +252 -0
- package/src/lib/jobs/ai-job-site-step.js +538 -0
- package/src/lib/jobs/ai-job-site-step.js.map +1 -0
- package/src/lib/jobs/ai-job-template-step.d.ts +105 -0
- package/src/lib/jobs/ai-job-template-step.js +391 -0
- package/src/lib/jobs/ai-job-template-step.js.map +1 -0
- package/src/lib/jobs/ai-job-text-step.d.ts +125 -0
- package/src/lib/jobs/ai-job-text-step.js +128 -0
- package/src/lib/jobs/ai-job-text-step.js.map +1 -0
- package/src/lib/jobs/ai-job-theme-budget.d.ts +38 -0
- package/src/lib/jobs/ai-job-theme-budget.js +43 -0
- package/src/lib/jobs/ai-job-theme-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-theme-step.d.ts +115 -0
- package/src/lib/jobs/ai-job-theme-step.js +337 -0
- package/src/lib/jobs/ai-job-theme-step.js.map +1 -0
- package/src/lib/jobs/ai-job-workflow-step.d.ts +139 -0
- package/src/lib/jobs/ai-job-workflow-step.js +530 -0
- package/src/lib/jobs/ai-job-workflow-step.js.map +1 -0
- package/src/lib/jobs/ai-jobs-beat.d.ts +78 -0
- package/src/lib/jobs/ai-jobs-beat.js +93 -0
- package/src/lib/jobs/ai-jobs-beat.js.map +1 -0
- package/src/lib/jobs/ai-jobs-pause.d.ts +38 -0
- package/src/lib/jobs/ai-jobs-pause.js +45 -0
- package/src/lib/jobs/ai-jobs-pause.js.map +1 -0
- package/src/lib/jobs/ai-jobs.d.ts +558 -0
- package/src/lib/jobs/ai-jobs.js +1410 -0
- package/src/lib/jobs/ai-jobs.js.map +1 -0
- package/src/lib/jobs/ai-media-asset-server.d.ts +34 -0
- package/src/lib/jobs/ai-media-asset-server.js +34 -0
- package/src/lib/jobs/ai-media-asset-server.js.map +1 -0
- package/src/lib/jobs/ai-media-asset.d.ts +59 -0
- package/src/lib/jobs/ai-media-asset.js +86 -0
- package/src/lib/jobs/ai-media-asset.js.map +1 -0
- package/src/lib/jobs/ai-product-image.d.ts +78 -0
- package/src/lib/jobs/ai-product-image.js +113 -0
- package/src/lib/jobs/ai-product-image.js.map +1 -0
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +125 -0
- package/src/lib/jobs/ai-theme-brand-inputs.js +378 -0
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -0
- package/src/lib/jobs/ai-theme-brand-server.d.ts +33 -0
- package/src/lib/jobs/ai-theme-brand-server.js +33 -0
- package/src/lib/jobs/ai-theme-brand-server.js.map +1 -0
- package/src/lib/jobs/ai-workflow-records.d.ts +84 -0
- package/src/lib/jobs/ai-workflow-records.js +158 -0
- package/src/lib/jobs/ai-workflow-records.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-free-page-built-recording.d.ts +31 -0
- package/src/lib/jobs/fixtures/ai-free-page-built-recording.js +367 -0
- package/src/lib/jobs/fixtures/ai-free-page-built-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-free-page-recording.d.ts +69 -0
- package/src/lib/jobs/fixtures/ai-free-page-recording.js +442 -0
- package/src/lib/jobs/fixtures/ai-free-page-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-page-briefs.d.ts +146 -0
- package/src/lib/jobs/fixtures/ai-page-briefs.js +1850 -0
- package/src/lib/jobs/fixtures/ai-page-briefs.js.map +1 -0
- package/src/lib/model/ai-allotments.d.ts +208 -0
- package/src/lib/model/ai-allotments.js +269 -0
- package/src/lib/model/ai-allotments.js.map +1 -0
- package/src/lib/model/ai-automation-draft.d.ts +74 -0
- package/src/lib/model/ai-automation-draft.js +310 -0
- package/src/lib/model/ai-automation-draft.js.map +1 -0
- package/src/lib/model/ai-automation-outline.d.ts +50 -0
- package/src/lib/model/ai-automation-outline.js +262 -0
- package/src/lib/model/ai-automation-outline.js.map +1 -0
- package/src/lib/model/ai-build-plan.d.ts +197 -0
- package/src/lib/model/ai-build-plan.js +438 -0
- package/src/lib/model/ai-build-plan.js.map +1 -0
- package/src/lib/model/ai-crm.d.ts +237 -0
- package/src/lib/model/ai-crm.js +225 -0
- package/src/lib/model/ai-crm.js.map +1 -0
- package/src/lib/model/ai-experiment-proposal.d.ts +68 -0
- package/src/lib/model/ai-experiment-proposal.js +146 -0
- package/src/lib/model/ai-experiment-proposal.js.map +1 -0
- package/src/lib/model/ai-experiment.d.ts +309 -0
- package/src/lib/model/ai-experiment.js +395 -0
- package/src/lib/model/ai-experiment.js.map +1 -0
- package/src/lib/model/ai-insight.d.ts +178 -0
- package/src/lib/model/ai-insight.js +201 -0
- package/src/lib/model/ai-insight.js.map +1 -0
- package/src/lib/model/ai-jobs.types.d.ts +412 -0
- package/src/lib/model/ai-jobs.types.js +42 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -0
- package/src/lib/model/ai-page-job.d.ts +92 -0
- package/src/lib/model/ai-page-job.js +159 -0
- package/src/lib/model/ai-page-job.js.map +1 -0
- package/src/lib/model/ai-permissions.d.ts +49 -0
- package/src/lib/model/ai-permissions.js +97 -0
- package/src/lib/model/ai-permissions.js.map +1 -0
- package/src/lib/model/ai-plan-capabilities.d.ts +139 -0
- package/src/lib/model/ai-plan-capabilities.js +149 -0
- package/src/lib/model/ai-plan-capabilities.js.map +1 -0
- package/src/lib/model/ai-products.d.ts +251 -0
- package/src/lib/model/ai-products.js +253 -0
- package/src/lib/model/ai-products.js.map +1 -0
- package/src/lib/model/ai-seo.d.ts +208 -0
- package/src/lib/model/ai-seo.js +150 -0
- package/src/lib/model/ai-seo.js.map +1 -0
- package/src/lib/model/ai-site-inventory.d.ts +164 -0
- package/src/lib/model/ai-site-inventory.js +145 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +247 -0
- package/src/lib/model/ai-site-job.js +314 -0
- package/src/lib/model/ai-site-job.js.map +1 -0
- package/src/lib/model/ai-site-start-seo.d.ts +103 -0
- package/src/lib/model/ai-site-start-seo.js +154 -0
- package/src/lib/model/ai-site-start-seo.js.map +1 -0
- package/src/lib/model/ai-site-start.d.ts +122 -0
- package/src/lib/model/ai-site-start.js +159 -0
- package/src/lib/model/ai-site-start.js.map +1 -0
- package/src/lib/model/ai-site-switch.d.ts +56 -0
- package/src/lib/model/ai-site-switch.js +73 -0
- package/src/lib/model/ai-site-switch.js.map +1 -0
- package/src/lib/model/ai-storefront-claims.d.ts +70 -0
- package/src/lib/model/ai-storefront-claims.js +130 -0
- package/src/lib/model/ai-storefront-claims.js.map +1 -0
- package/src/lib/model/ai-template-subjects.d.ts +82 -0
- package/src/lib/model/ai-template-subjects.js +136 -0
- package/src/lib/model/ai-template-subjects.js.map +1 -0
- package/src/lib/model/ai-theme-proposal.d.ts +210 -0
- package/src/lib/model/ai-theme-proposal.js +506 -0
- package/src/lib/model/ai-theme-proposal.js.map +1 -0
- package/src/lib/model/ai-tokens.d.ts +96 -0
- package/src/lib/model/ai-tokens.js +117 -0
- package/src/lib/model/ai-tokens.js.map +1 -0
- package/src/lib/model/ai-usage-by-user.d.ts +120 -0
- package/src/lib/model/ai-usage-by-user.js +139 -0
- package/src/lib/model/ai-usage-by-user.js.map +1 -0
- package/src/lib/model/ai-workflow-job.d.ts +111 -0
- package/src/lib/model/ai-workflow-job.js +183 -0
- package/src/lib/model/ai-workflow-job.js.map +1 -0
- package/src/lib/model/assist-edit.d.ts +261 -0
- package/src/lib/model/assist-edit.js +175 -0
- package/src/lib/model/assist-edit.js.map +1 -0
- package/src/lib/plugin-config.d.ts +33 -0
- package/src/lib/plugin-config.js +118 -0
- package/src/lib/plugin-config.js.map +1 -0
- package/src/lib/plugin.d.ts +30 -0
- package/src/lib/plugin.js +525 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/providers/anthropic.d.ts +84 -0
- package/src/lib/providers/anthropic.js +432 -0
- package/src/lib/providers/anthropic.js.map +1 -0
- package/src/lib/providers/catalog.d.ts +197 -0
- package/src/lib/providers/catalog.js +312 -0
- package/src/lib/providers/catalog.js.map +1 -0
- package/src/lib/providers/contract.d.ts +464 -0
- package/src/lib/providers/contract.js +274 -0
- package/src/lib/providers/contract.js.map +1 -0
- package/src/lib/providers/model-choice.d.ts +119 -0
- package/src/lib/providers/model-choice.js +416 -0
- package/src/lib/providers/model-choice.js.map +1 -0
- package/src/lib/providers/openai-compatible.d.ts +58 -0
- package/src/lib/providers/openai-compatible.js +361 -0
- package/src/lib/providers/openai-compatible.js.map +1 -0
- package/src/lib/providers/registry.d.ts +49 -0
- package/src/lib/providers/registry.js +71 -0
- package/src/lib/providers/registry.js.map +1 -0
- package/src/lib/providers/routing.d.ts +98 -0
- package/src/lib/providers/routing.js +450 -0
- package/src/lib/providers/routing.js.map +1 -0
- package/src/lib/runtime/ai-abuse-guards.d.ts +113 -0
- package/src/lib/runtime/ai-abuse-guards.js +148 -0
- package/src/lib/runtime/ai-abuse-guards.js.map +1 -0
- package/src/lib/runtime/ai-component-bindings.d.ts +67 -0
- package/src/lib/runtime/ai-component-bindings.js +106 -0
- package/src/lib/runtime/ai-component-bindings.js.map +1 -0
- package/src/lib/runtime/ai-device-audit.d.ts +109 -0
- package/src/lib/runtime/ai-device-audit.js +97 -0
- package/src/lib/runtime/ai-device-audit.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +720 -0
- package/src/lib/runtime/ai-doctrine-validators.js +3133 -0
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -0
- package/src/lib/runtime/ai-doctrine.d.ts +372 -0
- package/src/lib/runtime/ai-doctrine.js +944 -0
- package/src/lib/runtime/ai-doctrine.js.map +1 -0
- package/src/lib/runtime/ai-eval-live.d.ts +321 -0
- package/src/lib/runtime/ai-eval-live.js +1257 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -0
- package/src/lib/runtime/ai-eval-memory-firestore.d.ts +51 -0
- package/src/lib/runtime/ai-eval-memory-firestore.js +183 -0
- package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -0
- package/src/lib/runtime/ai-eval.d.ts +441 -0
- package/src/lib/runtime/ai-eval.js +1151 -0
- package/src/lib/runtime/ai-eval.js.map +1 -0
- package/src/lib/runtime/ai-gate.d.ts +130 -0
- package/src/lib/runtime/ai-gate.js +272 -0
- package/src/lib/runtime/ai-gate.js.map +1 -0
- package/src/lib/runtime/ai-generation-bounds.d.ts +24 -0
- package/src/lib/runtime/ai-generation-bounds.js +23 -0
- package/src/lib/runtime/ai-generation-bounds.js.map +1 -0
- package/src/lib/runtime/ai-insight-check.d.ts +76 -0
- package/src/lib/runtime/ai-insight-check.js +281 -0
- package/src/lib/runtime/ai-insight-check.js.map +1 -0
- package/src/lib/runtime/ai-node-tree.d.ts +181 -0
- package/src/lib/runtime/ai-node-tree.js +931 -0
- package/src/lib/runtime/ai-node-tree.js.map +1 -0
- package/src/lib/runtime/ai-page-links.d.ts +79 -0
- package/src/lib/runtime/ai-page-links.js +135 -0
- package/src/lib/runtime/ai-page-links.js.map +1 -0
- package/src/lib/runtime/ai-palette.d.ts +252 -0
- package/src/lib/runtime/ai-palette.generated.d.ts +34 -0
- package/src/lib/runtime/ai-palette.generated.js +5263 -0
- package/src/lib/runtime/ai-palette.generated.js.map +1 -0
- package/src/lib/runtime/ai-palette.js +187 -0
- package/src/lib/runtime/ai-palette.js.map +1 -0
- package/src/lib/runtime/ai-products-generation.d.ts +107 -0
- package/src/lib/runtime/ai-products-generation.js +250 -0
- package/src/lib/runtime/ai-products-generation.js.map +1 -0
- package/src/lib/runtime/ai-repeated-items.d.ts +95 -0
- package/src/lib/runtime/ai-repeated-items.js +397 -0
- package/src/lib/runtime/ai-repeated-items.js.map +1 -0
- package/src/lib/runtime/ai-runtime.d.ts +148 -0
- package/src/lib/runtime/ai-runtime.js +237 -0
- package/src/lib/runtime/ai-runtime.js.map +1 -0
- package/src/lib/runtime/ai-template-examples.d.ts +71 -0
- package/src/lib/runtime/ai-template-examples.js +135 -0
- package/src/lib/runtime/ai-template-examples.js.map +1 -0
- package/src/lib/runtime/assist-answer-cache.d.ts +80 -0
- package/src/lib/runtime/assist-answer-cache.js +184 -0
- package/src/lib/runtime/assist-answer-cache.js.map +1 -0
- package/src/lib/runtime/seo-audit.d.ts +93 -0
- package/src/lib/runtime/seo-audit.js +260 -0
- package/src/lib/runtime/seo-audit.js.map +1 -0
- package/src/lib/runtime/seo-content-fixes.d.ts +41 -0
- package/src/lib/runtime/seo-content-fixes.js +168 -0
- package/src/lib/runtime/seo-content-fixes.js.map +1 -0
- package/src/lib/runtime/seo-fields.d.ts +152 -0
- package/src/lib/runtime/seo-fields.js +215 -0
- package/src/lib/runtime/seo-fields.js.map +1 -0
- package/src/lib/runtime/seo-page-facts.d.ts +61 -0
- package/src/lib/runtime/seo-page-facts.js +150 -0
- package/src/lib/runtime/seo-page-facts.js.map +1 -0
- package/src/lib/runtime/site-inventory.d.ts +63 -0
- package/src/lib/runtime/site-inventory.js +230 -0
- package/src/lib/runtime/site-inventory.js.map +1 -0
- package/src/lib/server/ai-admin-org.d.ts +33 -0
- package/src/lib/server/ai-admin-org.js +381 -0
- package/src/lib/server/ai-admin-org.js.map +1 -0
- package/src/lib/server/ai-admin-orgs-spend.d.ts +40 -0
- package/src/lib/server/ai-admin-orgs-spend.js +129 -0
- package/src/lib/server/ai-admin-orgs-spend.js.map +1 -0
- package/src/lib/server/ai-admin-overage.d.ts +19 -0
- package/src/lib/server/ai-admin-overage.js +246 -0
- package/src/lib/server/ai-admin-overage.js.map +1 -0
- package/src/lib/server/ai-admin-signals.d.ts +34 -0
- package/src/lib/server/ai-admin-signals.js +330 -0
- package/src/lib/server/ai-admin-signals.js.map +1 -0
- package/src/lib/server/ai-admin-user.d.ts +27 -0
- package/src/lib/server/ai-admin-user.js +128 -0
- package/src/lib/server/ai-admin-user.js.map +1 -0
- package/src/lib/server/ai-allotments.d.ts +27 -0
- package/src/lib/server/ai-allotments.js +544 -0
- package/src/lib/server/ai-allotments.js.map +1 -0
- package/src/lib/server/ai-assist-prompts.d.ts +102 -0
- package/src/lib/server/ai-assist-prompts.js +207 -0
- package/src/lib/server/ai-assist-prompts.js.map +1 -0
- package/src/lib/server/ai-assist.d.ts +119 -0
- package/src/lib/server/ai-assist.js +517 -0
- package/src/lib/server/ai-assist.js.map +1 -0
- package/src/lib/server/ai-crm-answer.d.ts +30 -0
- package/src/lib/server/ai-crm-answer.js +98 -0
- package/src/lib/server/ai-crm-answer.js.map +1 -0
- package/src/lib/server/ai-generate-component.d.ts +111 -0
- package/src/lib/server/ai-generate-component.js +643 -0
- package/src/lib/server/ai-generate-component.js.map +1 -0
- package/src/lib/server/ai-host-permissions.d.ts +46 -0
- package/src/lib/server/ai-host-permissions.js +204 -0
- package/src/lib/server/ai-host-permissions.js.map +1 -0
- package/src/lib/server/ai-insight-answer.d.ts +30 -0
- package/src/lib/server/ai-insight-answer.js +83 -0
- package/src/lib/server/ai-insight-answer.js.map +1 -0
- package/src/lib/server/ai-insight-digest-route.d.ts +30 -0
- package/src/lib/server/ai-insight-digest-route.js +156 -0
- package/src/lib/server/ai-insight-digest-route.js.map +1 -0
- package/src/lib/server/ai-jobs-batch.d.ts +48 -0
- package/src/lib/server/ai-jobs-batch.js +306 -0
- package/src/lib/server/ai-jobs-batch.js.map +1 -0
- package/src/lib/server/ai-jobs-beat-route.d.ts +36 -0
- package/src/lib/server/ai-jobs-beat-route.js +86 -0
- package/src/lib/server/ai-jobs-beat-route.js.map +1 -0
- package/src/lib/server/ai-jobs-cancel.d.ts +30 -0
- package/src/lib/server/ai-jobs-cancel.js +74 -0
- package/src/lib/server/ai-jobs-cancel.js.map +1 -0
- package/src/lib/server/ai-jobs-events-route.d.ts +31 -0
- package/src/lib/server/ai-jobs-events-route.js +51 -0
- package/src/lib/server/ai-jobs-events-route.js.map +1 -0
- package/src/lib/server/ai-jobs-events.d.ts +55 -0
- package/src/lib/server/ai-jobs-events.js +144 -0
- package/src/lib/server/ai-jobs-events.js.map +1 -0
- package/src/lib/server/ai-jobs-gate.d.ts +47 -0
- package/src/lib/server/ai-jobs-gate.js +106 -0
- package/src/lib/server/ai-jobs-gate.js.map +1 -0
- package/src/lib/server/ai-jobs-resume.d.ts +23 -0
- package/src/lib/server/ai-jobs-resume.js +209 -0
- package/src/lib/server/ai-jobs-resume.js.map +1 -0
- package/src/lib/server/ai-jobs-route.d.ts +32 -0
- package/src/lib/server/ai-jobs-route.js +307 -0
- package/src/lib/server/ai-jobs-route.js.map +1 -0
- package/src/lib/server/ai-models.d.ts +18 -0
- package/src/lib/server/ai-models.js +134 -0
- package/src/lib/server/ai-models.js.map +1 -0
- package/src/lib/server/ai-seo-apply.d.ts +53 -0
- package/src/lib/server/ai-seo-apply.js +294 -0
- package/src/lib/server/ai-seo-apply.js.map +1 -0
- package/src/lib/server/ai-usage.d.ts +18 -0
- package/src/lib/server/ai-usage.js +220 -0
- package/src/lib/server/ai-usage.js.map +1 -0
- package/src/lib/server/assist-chat.d.ts +234 -0
- package/src/lib/server/assist-chat.js +1446 -0
- package/src/lib/server/assist-chat.js.map +1 -0
- package/src/lib/server/assist-edit-applied.d.ts +22 -0
- package/src/lib/server/assist-edit-applied.js +239 -0
- package/src/lib/server/assist-edit-applied.js.map +1 -0
- package/src/lib/server/assist-edit.d.ts +124 -0
- package/src/lib/server/assist-edit.js +1000 -0
- package/src/lib/server/assist-edit.js.map +1 -0
- package/src/lib/server/assist-feedback.d.ts +31 -0
- package/src/lib/server/assist-feedback.js +115 -0
- package/src/lib/server/assist-feedback.js.map +1 -0
- package/src/lib/server/assist-view-context.d.ts +343 -0
- package/src/lib/server/assist-view-context.js +690 -0
- package/src/lib/server/assist-view-context.js.map +1 -0
- package/src/lib/server/billing-credits.d.ts +59 -0
- package/src/lib/server/billing-credits.js +146 -0
- package/src/lib/server/billing-credits.js.map +1 -0
- package/src/lib/server/billing-overage.d.ts +19 -0
- package/src/lib/server/billing-overage.js +337 -0
- package/src/lib/server/billing-overage.js.map +1 -0
- package/src/lib/server.d.ts +32 -0
- package/src/lib/server.js +265 -0
- package/src/lib/server.js.map +1 -0
- package/src/lib/subprocessors.d.ts +18 -0
- package/src/lib/subprocessors.js +52 -0
- package/src/lib/subprocessors.js.map +1 -0
- package/src/lib/tools/ai-component-tool.d.ts +99 -0
- package/src/lib/tools/ai-component-tool.js +369 -0
- package/src/lib/tools/ai-component-tool.js.map +1 -0
- package/src/lib/tools/ai-crm-tool.d.ts +106 -0
- package/src/lib/tools/ai-crm-tool.js +488 -0
- package/src/lib/tools/ai-crm-tool.js.map +1 -0
- package/src/lib/tools/ai-duplicate-resource-tool.d.ts +71 -0
- package/src/lib/tools/ai-duplicate-resource-tool.js +164 -0
- package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -0
- package/src/lib/tools/ai-experiment-tool.d.ts +40 -0
- package/src/lib/tools/ai-experiment-tool.js +155 -0
- package/src/lib/tools/ai-experiment-tool.js.map +1 -0
- package/src/lib/tools/ai-insight-tool.d.ts +46 -0
- package/src/lib/tools/ai-insight-tool.js +200 -0
- package/src/lib/tools/ai-insight-tool.js.map +1 -0
- package/src/lib/tools/ai-inventory-lookup-tool.d.ts +86 -0
- package/src/lib/tools/ai-inventory-lookup-tool.js +164 -0
- package/src/lib/tools/ai-inventory-lookup-tool.js.map +1 -0
- package/src/lib/tools/ai-products-tool.d.ts +65 -0
- package/src/lib/tools/ai-products-tool.js +644 -0
- package/src/lib/tools/ai-products-tool.js.map +1 -0
- package/src/lib/tools/ai-seo-tool.d.ts +162 -0
- package/src/lib/tools/ai-seo-tool.js +546 -0
- package/src/lib/tools/ai-seo-tool.js.map +1 -0
- package/src/lib/tools/ai-theme-tool.d.ts +101 -0
- package/src/lib/tools/ai-theme-tool.js +562 -0
- package/src/lib/tools/ai-theme-tool.js.map +1 -0
- package/src/lib/tools/ai-workflow-tool.d.ts +166 -0
- package/src/lib/tools/ai-workflow-tool.js +860 -0
- package/src/lib/tools/ai-workflow-tool.js.map +1 -0
- package/src/lib/usage/ai-allotment-alerts.d.ts +72 -0
- package/src/lib/usage/ai-allotment-alerts.js +157 -0
- package/src/lib/usage/ai-allotment-alerts.js.map +1 -0
- package/src/lib/usage/ai-allotments.d.ts +125 -0
- package/src/lib/usage/ai-allotments.js +239 -0
- package/src/lib/usage/ai-allotments.js.map +1 -0
- package/src/lib/usage/ai-model-sample.d.ts +36 -0
- package/src/lib/usage/ai-model-sample.js +68 -0
- package/src/lib/usage/ai-model-sample.js.map +1 -0
- package/src/lib/usage/ai-usage-alerts.d.ts +55 -0
- package/src/lib/usage/ai-usage-alerts.js +114 -0
- package/src/lib/usage/ai-usage-alerts.js.map +1 -0
- package/src/lib/usage/ai-usage-by-user.d.ts +161 -0
- package/src/lib/usage/ai-usage-by-user.js +211 -0
- package/src/lib/usage/ai-usage-by-user.js.map +1 -0
- package/src/lib/usage/ai-usage-eraser.d.ts +29 -0
- package/src/lib/usage/ai-usage-eraser.js +40 -0
- package/src/lib/usage/ai-usage-eraser.js.map +1 -0
- package/src/lib/usage/ai-usage-meter.d.ts +39 -0
- package/src/lib/usage/ai-usage-meter.js +85 -0
- package/src/lib/usage/ai-usage-meter.js.map +1 -0
- package/src/lib/usage/ai-usage-wire.d.ts +184 -0
- package/src/lib/usage/ai-usage-wire.js +98 -0
- package/src/lib/usage/ai-usage-wire.js.map +1 -0
- package/src/lib/usage/assist-ceiling.d.ts +87 -0
- package/src/lib/usage/assist-ceiling.js +110 -0
- package/src/lib/usage/assist-ceiling.js.map +1 -0
- package/src/lib/usage/assist-free-taste.d.ts +225 -0
- package/src/lib/usage/assist-free-taste.js +308 -0
- package/src/lib/usage/assist-free-taste.js.map +1 -0
- package/src/lib/usage/assist-refusals.d.ts +69 -0
- package/src/lib/usage/assist-refusals.js +79 -0
- package/src/lib/usage/assist-refusals.js.map +1 -0
- package/src/lib/usage/assist-signal-mining.d.ts +375 -0
- package/src/lib/usage/assist-signal-mining.js +344 -0
- package/src/lib/usage/assist-signal-mining.js.map +1 -0
- package/src/lib/usage/assist-usage.d.ts +571 -0
- package/src/lib/usage/assist-usage.js +978 -0
- package/src/lib/usage/assist-usage.js.map +1 -0
- package/src/lib/usage/staff-org-ai.d.ts +242 -0
- package/src/lib/usage/staff-org-ai.js +173 -0
- package/src/lib/usage/staff-org-ai.js.map +1 -0
- package/src/lib/usage/staff-org-usage-ai.d.ts +83 -0
- package/src/lib/usage/staff-org-usage-ai.js +59 -0
- package/src/lib/usage/staff-org-usage-ai.js.map +1 -0
- package/src/lib/usage/staff-orgs-ai-spend.d.ts +83 -0
- package/src/lib/usage/staff-orgs-ai-spend.js +114 -0
- package/src/lib/usage/staff-orgs-ai-spend.js.map +1 -0
|
@@ -0,0 +1,517 @@
|
|
|
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 { checkEntitlement } from "@aglyn/aglyn/server";
|
|
18
|
+
import { assistCreditsFromUsd, assistFreeTasteRefusalText, assistOwnControlRefusalText } from "@aglyn/aglyn/app-utils/assist-credits";
|
|
19
|
+
import { resolveEffectivePlan } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
20
|
+
import { aiAllotmentRefusalText } from "../model/ai-allotments.js";
|
|
21
|
+
import { resolveAiModelChoice } from "../providers/model-choice.js";
|
|
22
|
+
import { aiUsageMeter } from "../usage/ai-usage-meter.js";
|
|
23
|
+
import { permissionRefusal, checkRateLimit, featureLockdownRefusal, firebaseAdmin, getOrgForUser, lockdownRefusal, memberHasPermissionOnHost, rateLimitHeaders } from "@aglyn/tenant-data-admin";
|
|
24
|
+
import { aiOverageReservationRefusal } from "../billing/ai-overage-gate.js";
|
|
25
|
+
import { recordUserAiRefusal } from "../usage/ai-usage-by-user.js";
|
|
26
|
+
import { estimateAssistCostUsd, publicAssistQuota, recordAssistCost, releaseAssistMessage, reserveAssistMessage } from "../usage/assist-usage.js";
|
|
27
|
+
import { logAiAssistSection } from "../activity/ai-activity.js";
|
|
28
|
+
// By its own entry point rather than the barrel (AGL-2903): this handler's
|
|
29
|
+
// spec replaces the barrel with a closed-world factory, and nothing replaces
|
|
30
|
+
// the entry point, so the spec exercises the real request shape and the real
|
|
31
|
+
// error boundary rather than a stub that agrees with the handler.
|
|
32
|
+
import { AI_ROUTING_TABLE, aiModelForStep } from "../providers/routing.js";
|
|
33
|
+
import { AiUpstreamError, aiProviderReady, runAiRequest } from "../runtime/ai-runtime.js";
|
|
34
|
+
import { assistModeSystemBlocks, assistSectionTool, readAssistSection } from "./ai-assist-prompts.js";
|
|
35
|
+
// By its own entry point for the same reason (AGL-2925): the per-address
|
|
36
|
+
// rung is real in the spec, keyed on whatever address the harness sends.
|
|
37
|
+
import { checkAiClientIpRateLimit } from "../runtime/ai-abuse-guards.js";
|
|
38
|
+
/**
|
|
39
|
+
* The model each mode is served by, through the routing table — tiered by
|
|
40
|
+
* what the mode actually asks for (AGL-2486), not one model for all three.
|
|
41
|
+
*
|
|
42
|
+
* - **element** → the fast tier (`copy.element`). Rewriting one button label
|
|
43
|
+
* or one heading to an instruction is a short, bounded transformation with
|
|
44
|
+
* the source text supplied: the least model-shaped work on this route and
|
|
45
|
+
* the highest-volume (a user clicking "improve this" runs it repeatedly on
|
|
46
|
+
* the same element).
|
|
47
|
+
* - **blog** → the balanced tier (`copy.blog`). A post body is real long-form
|
|
48
|
+
* writing, and the difference between tiers is legible to the reader.
|
|
49
|
+
* - **section** → the balanced tier (`copy.section`). A constrained-JSON node
|
|
50
|
+
* subtree over the published-component allowlist is a structured-generation
|
|
51
|
+
* task with a schema the sanitizer will reject if it is got wrong, and a
|
|
52
|
+
* rejected generation costs the whole request rather than part of it.
|
|
53
|
+
*
|
|
54
|
+
* ⚠️ NO PROMPT CACHING IS LOST BY THE FAST RUNG. Each mode's static text now
|
|
55
|
+
* carries a breakpoint (`assistModeSystemBlocks`), but none of the three is
|
|
56
|
+
* long enough for its model to cache: the catalog states each model's
|
|
57
|
+
* minimum and `runtime/ai-prompt-cache.spec.ts` measures every door against
|
|
58
|
+
* it. That is why the tier drop is free here and NOT free on
|
|
59
|
+
* `/api/assist/chat`, whose ~1,030-token prefix clears the balanced tier's
|
|
60
|
+
* minimum and would stop caching entirely on the fast tier's — cheaper per
|
|
61
|
+
* token, dearer per request, and invisible either way without that
|
|
62
|
+
* measurement. See the header of `assist-chat.ts`.
|
|
63
|
+
*
|
|
64
|
+
* The cost meter prices by model id, so the value returned here MUST be the
|
|
65
|
+
* one passed to `recordAssistCost` — same call, same variable. A tiering
|
|
66
|
+
* change that updates the request and not the meter reports one tier's money
|
|
67
|
+
* for another tier's tokens, which is the failure the by-model rate table
|
|
68
|
+
* exists to stop.
|
|
69
|
+
*/ export function assistModelForMode(mode) {
|
|
70
|
+
return aiModelForStep(assistStepKindForMode(mode));
|
|
71
|
+
}
|
|
72
|
+
/** The routing table's step kind for each mode. */ export function assistStepKindForMode(mode) {
|
|
73
|
+
return mode === 'element' ? 'copy.element' : mode === 'blog' ? 'copy.blog' : 'copy.section';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Per-uid burst limit, matched to `/api/assist/chat`'s 20/min so a client
|
|
77
|
+
* cannot arbitrage the two assist doors against each other.
|
|
78
|
+
*/ const ASSIST_RATE_LIMIT = 20;
|
|
79
|
+
const ASSIST_RATE_WINDOW_MS = 60000;
|
|
80
|
+
const SECTION_MAX_TOKENS = AI_ROUTING_TABLE['copy.section'].maxTokens;
|
|
81
|
+
const BLOG_MAX_TOKENS = AI_ROUTING_TABLE['copy.blog'].maxTokens;
|
|
82
|
+
const ELEMENT_MAX_TOKENS = AI_ROUTING_TABLE['copy.element'].maxTokens;
|
|
83
|
+
/**
|
|
84
|
+
* What a `refusal` stop is answered with. The model declined the brief —
|
|
85
|
+
* a policy verdict on the instruction, not a fault — so the sentence asks
|
|
86
|
+
* for a different one rather than a retry. The tokens were spent and are
|
|
87
|
+
* metered before this is sent.
|
|
88
|
+
*/ const REFUSED = {
|
|
89
|
+
error: 'The AI declined that instruction — try a different one.'
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* AI assist (AGL-89/130/169), the besigner copy assistant's door — the
|
|
93
|
+
* section mode composes over the published-component allowlist and every
|
|
94
|
+
* generated subtree passes the node-definition sanitizer a marketplace
|
|
95
|
+
* install passes, before it reaches a canvas. `/api/ai/assist` is served by
|
|
96
|
+
* the plugin API dispatcher under the `ai` prefix. Gated on a ready provider,
|
|
97
|
+
* one registered with its key set (501 without, the same degrade pattern as
|
|
98
|
+
* Stripe); auth via Firebase ID token.
|
|
99
|
+
*
|
|
100
|
+
* The provider call is `runAiRequest`, the runtime every AI door shares
|
|
101
|
+
* (AGL-2903). This handler owns the ladder below and the response shapes;
|
|
102
|
+
* `ai-assist-prompts.ts` owns the three prompts and the section tool; the
|
|
103
|
+
* runtime owns the wire, the usage arithmetic and the error boundary. The
|
|
104
|
+
* request keeps the model per mode, the `max_tokens` and the absent
|
|
105
|
+
* `thinking` field it has always had — a fast-tier model rejects an explicit
|
|
106
|
+
* one, and the balanced modes keep the model default.
|
|
107
|
+
*
|
|
108
|
+
* A section arrives through a strict tool (AGL-2937). It used to be asked
|
|
109
|
+
* for as bare JSON and parsed: a parse that failed answered 502 with the
|
|
110
|
+
* tokens already spent, so the whole request bought nothing and the member's
|
|
111
|
+
* next move was to spend it again. The text parse is kept behind the tool,
|
|
112
|
+
* for a provider whose adapter has none.
|
|
113
|
+
*
|
|
114
|
+
* ── The spend ladder (AGL-2073) ────────────────────────────────────────────
|
|
115
|
+
*
|
|
116
|
+
* This route reached the provider behind nothing but an entitlement check. Free
|
|
117
|
+
* orgs could not get in, so the free tier was safe — but for any Pro org it
|
|
118
|
+
* had no rate limit, no quota, no per-org cost telemetry, and it resolved the
|
|
119
|
+
* org from the USER rather than the request, so someone with one paid org got
|
|
120
|
+
* assist charged against whichever org `getOrgForUser` happened to return. One
|
|
121
|
+
* subscription, unbounded and unmeasured provider spend.
|
|
122
|
+
*
|
|
123
|
+
* The ladder now, in order, each rung able to go red on its own:
|
|
124
|
+
* 405 → 501 no ready provider → 401 no token → 400 bad body (the request
|
|
125
|
+
* must NAME the org it is metered against) → 403 not a member of that org →
|
|
126
|
+
* 423 the workspace's AI pause → 403 the member's role lacks `ai.use`, or
|
|
127
|
+
* `ai.generate` for a section (AGL-2927; staff pass) → 403 no `aiAssist`
|
|
128
|
+
* entitlement → 423 org lockdown → 429 rate limit → 429 quota → the model
|
|
129
|
+
* call → meter.
|
|
130
|
+
*
|
|
131
|
+
* Two deliberate choices about which way each rung fails:
|
|
132
|
+
*
|
|
133
|
+
* - **The rate limiter fails SOFT and is not the spend bound.** It is a
|
|
134
|
+
* per-instance in-memory window, so N serverless instances admit N × 20/min;
|
|
135
|
+
* it smooths bursts and nothing more. Treating it as the cap would be the
|
|
136
|
+
* fail-open this issue is about.
|
|
137
|
+
* - **The reservation fails CLOSED.** It is the only global, atomic bound on
|
|
138
|
+
* provider spend, so a reservation that cannot be taken — a Firestore
|
|
139
|
+
* outage, a contended transaction — refuses the request with 503 rather than
|
|
140
|
+
* calling the provider uncapped. An unavailable meter must stop the spending,
|
|
141
|
+
* not wave it through.
|
|
142
|
+
*
|
|
143
|
+
* The reservation is `reserveAssistMessage` — the same shared counter the
|
|
144
|
+
* console chat route moves (AGL-2057), not a second mechanism. That is what
|
|
145
|
+
* closes the "uncapped for paid" hole the earlier audit named: an entitled org
|
|
146
|
+
* carries the monthly runaway guard, and because both doors move the SAME
|
|
147
|
+
* counter, an org's monthly assist budget is shared across them rather than
|
|
148
|
+
* doubled by having two.
|
|
149
|
+
*
|
|
150
|
+
* Metering is `recordAssistCost`, the signal + rollup half of the assist
|
|
151
|
+
* meters WITHOUT the verbatim half: what a customer types here is their own
|
|
152
|
+
* site copy and blog bodies, and retaining that for 180 days is a data flow
|
|
153
|
+
* the published privacy disclosure does not describe. The margin question is
|
|
154
|
+
* answered by the signal alone.
|
|
155
|
+
*/ export const aiAssistHandler = async (req, res)=>{
|
|
156
|
+
var _headers_authorization, _req_body, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
|
157
|
+
if (req.method !== 'POST') {
|
|
158
|
+
return res.status(405).json({
|
|
159
|
+
error: 'Method not allowed'
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (!aiProviderReady()) {
|
|
163
|
+
return res.status(501).json({
|
|
164
|
+
error: 'AI assist is not configured (no AI provider key).'
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const headers = req.headers;
|
|
168
|
+
const authorization = (_headers_authorization = headers.authorization) != null ? _headers_authorization : '';
|
|
169
|
+
const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
|
|
170
|
+
if (!idToken) return res.status(401).json({
|
|
171
|
+
error: 'Unauthenticated'
|
|
172
|
+
});
|
|
173
|
+
const body = (_req_body = req.body) != null ? _req_body : {};
|
|
174
|
+
const text = String((_ref = body == null ? void 0 : body.text) != null ? _ref : '').slice(0, 12000);
|
|
175
|
+
const instruction = String((_ref1 = body == null ? void 0 : body.instruction) != null ? _ref1 : '').slice(0, 500);
|
|
176
|
+
// Modes (AGL-130): 'element' rewrites short copy; 'blog' writes or
|
|
177
|
+
// improves markdown-lite entry bodies with title/excerpt context.
|
|
178
|
+
const mode = (body == null ? void 0 : body.mode) === 'blog' ? 'blog' : (body == null ? void 0 : body.mode) === 'section' ? 'section' : 'element';
|
|
179
|
+
const title = String((_ref2 = body == null ? void 0 : body.title) != null ? _ref2 : '').slice(0, 200);
|
|
180
|
+
const excerpt = String((_ref3 = body == null ? void 0 : body.excerpt) != null ? _ref3 : '').slice(0, 500);
|
|
181
|
+
// The request must NAME the org it is about to be metered against
|
|
182
|
+
// (AGL-2073, the AGL-1934 rule applied to this door). Resolving the org
|
|
183
|
+
// from the user alone charged a multi-org user's assist to whichever org
|
|
184
|
+
// came back first — and handed their free workspaces a paid feature.
|
|
185
|
+
const orgId = String((_ref4 = body == null ? void 0 : body.orgId) != null ? _ref4 : '').trim();
|
|
186
|
+
const hostId = String((_ref5 = body == null ? void 0 : body.hostId) != null ? _ref5 : '').trim().slice(0, 128);
|
|
187
|
+
if (!instruction) {
|
|
188
|
+
return res.status(400).json({
|
|
189
|
+
error: 'Missing instruction'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (!orgId) {
|
|
193
|
+
return res.status(400).json({
|
|
194
|
+
error: 'Open a workspace before using AI assist'
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
let reservation = null;
|
|
198
|
+
let providerAnswered = false;
|
|
199
|
+
let firestore = null;
|
|
200
|
+
try {
|
|
201
|
+
var _resolved_org, _ref6, _ref7, _ref8, _ref9;
|
|
202
|
+
var _held_allotment, _held_allotment1;
|
|
203
|
+
const app = firebaseAdmin.app();
|
|
204
|
+
firestore = app.firestore();
|
|
205
|
+
const decoded = await app.auth().verifyIdToken(idToken);
|
|
206
|
+
// Plan gate (AGL-469): AI assist is a Pro+ entitlement with real token
|
|
207
|
+
// cost — resolve the caller's org and check it server-side; a plan-less
|
|
208
|
+
// org resolves as `free` and is denied. Scoped to the NAMED org, so
|
|
209
|
+
// membership of some other paid org is not a key to this one.
|
|
210
|
+
const resolved = await getOrgForUser(decoded.uid, orgId);
|
|
211
|
+
if (!resolved || resolved.orgId !== orgId) {
|
|
212
|
+
return res.status(403).json({
|
|
213
|
+
error: 'You are not a member of that organization'
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const org = (_resolved_org = resolved.org) != null ? _resolved_org : {};
|
|
217
|
+
// Permission (AGL-2927), directly after membership. The element and
|
|
218
|
+
// blog modes are assistance and sell under `ai.use`; a generated
|
|
219
|
+
// section is a generation and sells under `ai.generate`. Decided on the
|
|
220
|
+
// caller's own axis — the org catalog for an org-wide member, the site
|
|
221
|
+
// the body named for a collaborator, who is refused when it named none.
|
|
222
|
+
// A fact about the caller, so it is answered before the plan is. Staff
|
|
223
|
+
// pass, as at every other org route. Beside it, the workspace-scoped
|
|
224
|
+
// pause on `ai-assist`: the dispatcher already applied the platform-wide
|
|
225
|
+
// switch by path, before it knew which org the body would name.
|
|
226
|
+
const staff = decoded['staff'] === true;
|
|
227
|
+
const aiPaused = await featureLockdownRefusal({
|
|
228
|
+
feature: 'ai-assist',
|
|
229
|
+
staff,
|
|
230
|
+
orgId
|
|
231
|
+
});
|
|
232
|
+
if (aiPaused) return forwardRefusal(res, aiPaused);
|
|
233
|
+
const permission = mode === 'section' ? 'ai.generate' : 'ai.use';
|
|
234
|
+
if (!staff && !await memberHasPermissionOnHost(orgId, hostId, resolved.member, permission)) {
|
|
235
|
+
return forwardRefusal(res, permissionRefusal(permission));
|
|
236
|
+
}
|
|
237
|
+
const entitled = checkEntitlement(org, 'aiAssist');
|
|
238
|
+
if (!entitled) {
|
|
239
|
+
return res.status(403).json({
|
|
240
|
+
error: 'AI assist requires a Pro plan'
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// Org-scoped lockdown. The dispatcher already evaluates platform and user
|
|
244
|
+
// scope plus the `ai-assist` feature kill switch, but its org scope needs
|
|
245
|
+
// a `hostId` this route's callers do not send — so a suspended workspace
|
|
246
|
+
// kept spending. The org doc is already in hand, so the verdict is free.
|
|
247
|
+
const locked = await lockdownRefusal({
|
|
248
|
+
request: {
|
|
249
|
+
method: req.method
|
|
250
|
+
},
|
|
251
|
+
staff,
|
|
252
|
+
uid: decoded.uid,
|
|
253
|
+
org: org
|
|
254
|
+
});
|
|
255
|
+
if (locked) return forwardRefusal(res, locked);
|
|
256
|
+
const rate = checkRateLimit(`ai-assist:${decoded.uid}`, {
|
|
257
|
+
limit: ASSIST_RATE_LIMIT,
|
|
258
|
+
windowMs: ASSIST_RATE_WINDOW_MS
|
|
259
|
+
});
|
|
260
|
+
if (!rate.allowed) {
|
|
261
|
+
for (const [name, value] of Object.entries(rateLimitHeaders(rate))){
|
|
262
|
+
res.setHeader(name, value);
|
|
263
|
+
}
|
|
264
|
+
return res.status(429).json({
|
|
265
|
+
error: 'Too many AI requests — slow down a moment'
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
// The same window keyed on the trusted-hop client address (AGL-2925):
|
|
269
|
+
// accounts rotated behind one address share one budget.
|
|
270
|
+
const ipRate = checkAiClientIpRateLimit(headers);
|
|
271
|
+
if (ipRate && !ipRate.allowed) {
|
|
272
|
+
for (const [name, value] of Object.entries(rateLimitHeaders(ipRate))){
|
|
273
|
+
res.setHeader(name, value);
|
|
274
|
+
}
|
|
275
|
+
return res.status(429).json({
|
|
276
|
+
error: 'Too many AI requests — slow down a moment'
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
// RESERVED, not merely checked (AGL-2057/2073). Read-and-increment in one
|
|
280
|
+
// transaction, BEFORE a single token is spent, so N concurrent requests
|
|
281
|
+
// cannot all read the same "under the cap" and a client that drops the
|
|
282
|
+
// connection has already been counted.
|
|
283
|
+
try {
|
|
284
|
+
// `org` is the document `entitled` came from, and it is what makes
|
|
285
|
+
// the plan's own assist band bind rather than the operator backstop
|
|
286
|
+
// alone. Generative building is the dearest thing this route serves,
|
|
287
|
+
// so the band it spends against has to be the one that was sold.
|
|
288
|
+
reservation = await reserveAssistMessage(firestore, orgId, entitled, new Date(), org, // The allotments that apply (AGL-2942): the asker's own, theirs on
|
|
289
|
+
// the canvas's site, and the site's.
|
|
290
|
+
{
|
|
291
|
+
uid: decoded.uid,
|
|
292
|
+
hostId: hostId || null
|
|
293
|
+
});
|
|
294
|
+
} catch (error) {
|
|
295
|
+
// FAIL CLOSED. The reservation is the only global bound on what this
|
|
296
|
+
// route can spend at the provider; if it cannot be taken there is no cap,
|
|
297
|
+
// and no cap is worse than no answer.
|
|
298
|
+
console.error('assist reservation failed', error);
|
|
299
|
+
return res.status(503).json({
|
|
300
|
+
error: 'AI assist is temporarily unavailable'
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
// A refusal is the asker's as well as the workspace's (AGL-2928): their
|
|
304
|
+
// month counts it beside the org counter the reservation moved.
|
|
305
|
+
recordUserAiRefusal(firestore, orgId, decoded.uid, reservation);
|
|
306
|
+
if (!reservation.allowed) {
|
|
307
|
+
var _ref10;
|
|
308
|
+
const refusedBy = reservation.refusedBy;
|
|
309
|
+
// A hard allotment (AGL-2942): the monthly line a manager drew for
|
|
310
|
+
// the asker or the site, with the sentence naming who can raise it.
|
|
311
|
+
if (refusedBy === 'allotment') {
|
|
312
|
+
var _reservation_allotment_refusal, _reservation_allotment;
|
|
313
|
+
return res.status(429).json({
|
|
314
|
+
error: aiAllotmentRefusalText((_reservation_allotment = reservation.allotment) == null ? void 0 : (_reservation_allotment_refusal = _reservation_allotment.refusal) == null ? void 0 : _reservation_allotment_refusal.scope),
|
|
315
|
+
reason: 'quota',
|
|
316
|
+
quota: publicAssistQuota(reservation),
|
|
317
|
+
meter: aiUsageMeter(reservation)
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
// The org's own controls are a 402, not a 429: credits past the band
|
|
321
|
+
// are for sale and this workspace either switched the sale off
|
|
322
|
+
// (AGL-2653) or capped what it would buy (AGL-2898), so the sentence
|
|
323
|
+
// names the control that refused — the same sentence the console
|
|
324
|
+
// assistant gives, from the same helper. Every other refusal keeps
|
|
325
|
+
// the 429.
|
|
326
|
+
// AGLYN'S OWN OVERAGE GUARDS (AGL-3011): a card, a pause, this
|
|
327
|
+
// month's ceiling or a settling balance, each with the status that
|
|
328
|
+
// says whether the workspace can act on it. Before the workspace's
|
|
329
|
+
// own controls, which answer only for the controls it set itself.
|
|
330
|
+
const overage = aiOverageReservationRefusal(reservation);
|
|
331
|
+
if (overage) {
|
|
332
|
+
return res.status(overage.status).json({
|
|
333
|
+
error: overage.text,
|
|
334
|
+
reason: 'quota',
|
|
335
|
+
quota: publicAssistQuota(reservation),
|
|
336
|
+
meter: aiUsageMeter(reservation)
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
const ownControl = assistOwnControlRefusalText(org, refusedBy);
|
|
340
|
+
return res.status(ownControl ? 402 : 429).json({
|
|
341
|
+
error: (_ref10 = ownControl != null ? ownControl : // The Free taste's own precautions (AGL-2925), in the sentences
|
|
342
|
+
// the console assistant uses.
|
|
343
|
+
assistFreeTasteRefusalText(refusedBy)) != null ? _ref10 : 'This workspace reached its AI assist limit for the month — contact support if you need a higher cap',
|
|
344
|
+
// CREDITS, never the reservation itself — see `publicAssistQuota`.
|
|
345
|
+
quota: publicAssistQuota(reservation),
|
|
346
|
+
meter: aiUsageMeter(reservation)
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
const tier = entitled ? 'entitled' : 'free';
|
|
350
|
+
// ONE resolution, read by both the request and the meter — see
|
|
351
|
+
// `assistModelForMode`. Two call sites would let them drift. A model the
|
|
352
|
+
// asker picked (AGL-2942) replaces the routing table's answer only when
|
|
353
|
+
// the plan, the org's restriction and the allotment allowlists all allow
|
|
354
|
+
// it; anything else runs on Auto.
|
|
355
|
+
const held = reservation;
|
|
356
|
+
const choice = resolveAiModelChoice(assistStepKindForMode(mode), body == null ? void 0 : body.model, {
|
|
357
|
+
plan: resolveEffectivePlan(org),
|
|
358
|
+
allotmentModels: (_ref6 = (_held_allotment = held.allotment) == null ? void 0 : _held_allotment.models) != null ? _ref6 : null,
|
|
359
|
+
orgModels: (_ref7 = (_held_allotment1 = held.allotment) == null ? void 0 : _held_allotment1.orgModels) != null ? _ref7 : null
|
|
360
|
+
});
|
|
361
|
+
const model = (_ref8 = choice == null ? void 0 : choice.model) != null ? _ref8 : assistModelForMode(mode);
|
|
362
|
+
/** The usage strip's envelope for an answered request (AGL-2942). */ const meterFor = (result)=>{
|
|
363
|
+
var _ref;
|
|
364
|
+
return aiUsageMeter(held, {
|
|
365
|
+
lastCredits: assistCreditsFromUsd(estimateAssistCostUsd(result.usage, model)),
|
|
366
|
+
model: {
|
|
367
|
+
id: model,
|
|
368
|
+
auto: (_ref = choice == null ? void 0 : choice.auto) != null ? _ref : true
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
/** Meter what the provider actually charged us for, per org. */ // The account the reservation drew on (AGL-2925), read once here: the
|
|
373
|
+
// closure below runs after `reservation` may have been cleared by a
|
|
374
|
+
// refund, and a refund never reaches the meter.
|
|
375
|
+
const free = (_ref9 = reservation == null ? void 0 : reservation.free) != null ? _ref9 : null;
|
|
376
|
+
const meter = (result)=>recordAssistCost(firestore, orgId, {
|
|
377
|
+
route: `/api/ai/assist/${mode}`,
|
|
378
|
+
hostId: hostId || null,
|
|
379
|
+
model,
|
|
380
|
+
tier,
|
|
381
|
+
usage: result.usage,
|
|
382
|
+
docsPaths: [],
|
|
383
|
+
stopReason: result.stopReason,
|
|
384
|
+
free
|
|
385
|
+
}).catch((error)=>console.error('assist cost metering failed', error));
|
|
386
|
+
/**
|
|
387
|
+
* One provider call, with the refund decided at the boundary: a refused
|
|
388
|
+
* request (a non-2xx answer) spent nothing, so the reservation goes back
|
|
389
|
+
* — against the keys it RECORDED, never against "now" — and the caller
|
|
390
|
+
* gets the runtime's fixed sentence, never the provider's (AGL-2815).
|
|
391
|
+
* A result, even a refusal, means the tokens ARE spent: every exit after
|
|
392
|
+
* it meters and none refunds. Anything else thrown never reached the
|
|
393
|
+
* provider and is left to the outer catch, which refunds too.
|
|
394
|
+
*/ const ask = async (content, maxTokens, tools)=>{
|
|
395
|
+
try {
|
|
396
|
+
const result = await runAiRequest(_extends({
|
|
397
|
+
model,
|
|
398
|
+
maxTokens,
|
|
399
|
+
stream: false,
|
|
400
|
+
// The mode's prompt with the acceptable-use rules ahead of it
|
|
401
|
+
// (AGL-2925), from `ai-assist-prompts.ts` so a spec can read what
|
|
402
|
+
// this route sends without standing up the route.
|
|
403
|
+
system: assistModeSystemBlocks(mode),
|
|
404
|
+
messages: [
|
|
405
|
+
{
|
|
406
|
+
role: 'user',
|
|
407
|
+
content
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
}, tools ? {
|
|
411
|
+
tools
|
|
412
|
+
} : {}));
|
|
413
|
+
providerAnswered = true;
|
|
414
|
+
await meter(result);
|
|
415
|
+
return result;
|
|
416
|
+
} catch (error) {
|
|
417
|
+
if (!(error instanceof AiUpstreamError)) throw error;
|
|
418
|
+
providerAnswered = true;
|
|
419
|
+
await releaseReservation(firestore, orgId, reservation);
|
|
420
|
+
reservation = null;
|
|
421
|
+
res.status(502).json({
|
|
422
|
+
error: error.message
|
|
423
|
+
});
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
// Generate section (AGL-169): a constrained-JSON node subtree over the
|
|
428
|
+
// marketplace component allowlist; the response passes the same
|
|
429
|
+
// sanitizer as marketplace installs before it ever reaches a canvas.
|
|
430
|
+
if (mode === 'section') {
|
|
431
|
+
var _decoded_email;
|
|
432
|
+
const result = await ask(`Section to design: ${instruction}`, SECTION_MAX_TOKENS, [
|
|
433
|
+
assistSectionTool()
|
|
434
|
+
]);
|
|
435
|
+
if (!result) return;
|
|
436
|
+
if (result.kind === 'refusal') {
|
|
437
|
+
return res.status(502).json(_extends({}, REFUSED, {
|
|
438
|
+
meter: meterFor(result)
|
|
439
|
+
}));
|
|
440
|
+
}
|
|
441
|
+
const read = readAssistSection(result);
|
|
442
|
+
if (read.status !== 'ok') {
|
|
443
|
+
// Unreadable is the provider's fault and rejected is the answer's,
|
|
444
|
+
// the two statuses this route has always drawn that line between.
|
|
445
|
+
return res.status(read.status === 'unreadable' ? 502 : 422).json({
|
|
446
|
+
error: read.error
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
// A subtree is going back (AGL-2929): the act, its size and its site in
|
|
450
|
+
// the customer's feed — never the instruction or the copy generated.
|
|
451
|
+
await logAiAssistSection({
|
|
452
|
+
uid: decoded.uid,
|
|
453
|
+
email: (_decoded_email = decoded.email) != null ? _decoded_email : null
|
|
454
|
+
}, {
|
|
455
|
+
orgId,
|
|
456
|
+
hostId: hostId || null,
|
|
457
|
+
nodeCount: Object.keys(read.section.nodes).length
|
|
458
|
+
});
|
|
459
|
+
return res.status(200).json({
|
|
460
|
+
section: read.section,
|
|
461
|
+
meter: meterFor(result)
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
const result = await ask(mode === 'blog' ? [
|
|
465
|
+
title && `Title: ${title}`,
|
|
466
|
+
excerpt && `Excerpt: ${excerpt}`,
|
|
467
|
+
text && `Current body:\n${text}`,
|
|
468
|
+
`Instruction: ${instruction}`
|
|
469
|
+
].filter(Boolean).join('\n\n') : text ? `Current element text:\n${text}\n\nInstruction: ${instruction}` : `Write website element text. Instruction: ${instruction}`, mode === 'blog' ? BLOG_MAX_TOKENS : ELEMENT_MAX_TOKENS);
|
|
470
|
+
if (!result) return;
|
|
471
|
+
if (result.kind === 'refusal') {
|
|
472
|
+
return res.status(502).json(_extends({}, REFUSED, {
|
|
473
|
+
meter: meterFor(result)
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
476
|
+
const output = result.text.trim();
|
|
477
|
+
if (!output) {
|
|
478
|
+
return res.status(502).json({
|
|
479
|
+
error: 'Empty AI response',
|
|
480
|
+
meter: meterFor(result)
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
return res.status(200).json({
|
|
484
|
+
text: output,
|
|
485
|
+
meter: meterFor(result)
|
|
486
|
+
});
|
|
487
|
+
} catch (error) {
|
|
488
|
+
console.error(error);
|
|
489
|
+
// The provider was never reached — a token verification failure, a DNS
|
|
490
|
+
// error, a socket reset before any response. Nothing was spent, so the
|
|
491
|
+
// reservation must not be. If the provider DID answer, the tokens are
|
|
492
|
+
// real and the reservation stays consumed however the request ends.
|
|
493
|
+
if (firestore && reservation && !providerAnswered) {
|
|
494
|
+
await releaseReservation(firestore, orgId, reservation);
|
|
495
|
+
}
|
|
496
|
+
return res.status(500).json({
|
|
497
|
+
error: 'Assist failed'
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* Hand a reservation back, never letting the refund itself fail the request.
|
|
503
|
+
* Released against the keys the RESERVATION recorded — a reservation taken at
|
|
504
|
+
* 23:59:59 and released at 00:00:01 must not credit the next day.
|
|
505
|
+
*/ async function releaseReservation(firestore, orgId, reservation) {
|
|
506
|
+
await releaseAssistMessage(firestore, orgId, reservation).catch((error)=>console.error('assist reservation release failed', error));
|
|
507
|
+
}
|
|
508
|
+
/** Re-emit a lockdown `Response` through the plugin API's res object. */ async function forwardRefusal(res, refusal) {
|
|
509
|
+
const retryAfter = refusal.headers.get('Retry-After');
|
|
510
|
+
if (retryAfter) res.setHeader('Retry-After', retryAfter);
|
|
511
|
+
const body = await refusal.json().catch(()=>({
|
|
512
|
+
error: 'locked'
|
|
513
|
+
}));
|
|
514
|
+
res.status(refusal.status).json(body);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
//# sourceMappingURL=ai-assist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/ai-assist.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 {\n checkEntitlement,\n type PluginApiHandler,\n type PluginApiResponse,\n} from '@aglyn/aglyn/server'\nimport {\n assistCreditsFromUsd,\n assistFreeTasteRefusalText,\n assistOwnControlRefusalText,\n} from '@aglyn/aglyn/app-utils/assist-credits'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { aiAllotmentRefusalText } from '../model/ai-allotments'\nimport { resolveAiModelChoice } from '../providers/model-choice'\nimport { aiUsageMeter } from '../usage/ai-usage-meter'\nimport {\n permissionRefusal,\n checkRateLimit,\n featureLockdownRefusal,\n firebaseAdmin,\n getOrgForUser,\n lockdownRefusal,\n memberHasPermissionOnHost,\n rateLimitHeaders,\n} from '@aglyn/tenant-data-admin'\nimport { aiOverageReservationRefusal } from '../billing/ai-overage-gate'\nimport { recordUserAiRefusal } from '../usage/ai-usage-by-user'\nimport {\n estimateAssistCostUsd,\n publicAssistQuota,\n recordAssistCost,\n releaseAssistMessage,\n reserveAssistMessage,\n type AssistReservation,\n} from '../usage/assist-usage'\nimport { logAiAssistSection } from '../activity/ai-activity'\n// By its own entry point rather than the barrel (AGL-2903): this handler's\n// spec replaces the barrel with a closed-world factory, and nothing replaces\n// the entry point, so the spec exercises the real request shape and the real\n// error boundary rather than a stub that agrees with the handler.\nimport { AI_ROUTING_TABLE, aiModelForStep } from '../providers/routing'\nimport {\n AiUpstreamError,\n aiProviderReady,\n runAiRequest,\n type AiResult,\n type AiTool,\n} from '../runtime/ai-runtime'\nimport {\n ASSIST_SECTION_TOOL_NAME,\n assistModeSystemBlocks,\n assistSectionTool,\n readAssistSection,\n type AiAssistMode,\n} from './ai-assist-prompts'\n// By its own entry point for the same reason (AGL-2925): the per-address\n// rung is real in the spec, keyed on whatever address the harness sends.\nimport { checkAiClientIpRateLimit } from '../runtime/ai-abuse-guards'\n\n/**\n * The model each mode is served by, through the routing table — tiered by\n * what the mode actually asks for (AGL-2486), not one model for all three.\n *\n * - **element** → the fast tier (`copy.element`). Rewriting one button label\n * or one heading to an instruction is a short, bounded transformation with\n * the source text supplied: the least model-shaped work on this route and\n * the highest-volume (a user clicking \"improve this\" runs it repeatedly on\n * the same element).\n * - **blog** → the balanced tier (`copy.blog`). A post body is real long-form\n * writing, and the difference between tiers is legible to the reader.\n * - **section** → the balanced tier (`copy.section`). A constrained-JSON node\n * subtree over the published-component allowlist is a structured-generation\n * task with a schema the sanitizer will reject if it is got wrong, and a\n * rejected generation costs the whole request rather than part of it.\n *\n * ⚠️ NO PROMPT CACHING IS LOST BY THE FAST RUNG. Each mode's static text now\n * carries a breakpoint (`assistModeSystemBlocks`), but none of the three is\n * long enough for its model to cache: the catalog states each model's\n * minimum and `runtime/ai-prompt-cache.spec.ts` measures every door against\n * it. That is why the tier drop is free here and NOT free on\n * `/api/assist/chat`, whose ~1,030-token prefix clears the balanced tier's\n * minimum and would stop caching entirely on the fast tier's — cheaper per\n * token, dearer per request, and invisible either way without that\n * measurement. See the header of `assist-chat.ts`.\n *\n * The cost meter prices by model id, so the value returned here MUST be the\n * one passed to `recordAssistCost` — same call, same variable. A tiering\n * change that updates the request and not the meter reports one tier's money\n * for another tier's tokens, which is the failure the by-model rate table\n * exists to stop.\n */\nexport function assistModelForMode(mode: AiAssistMode): string {\n return aiModelForStep(assistStepKindForMode(mode))\n}\n\n/** The routing table's step kind for each mode. */\nexport function assistStepKindForMode(\n mode: AiAssistMode,\n): 'copy.element' | 'copy.blog' | 'copy.section' {\n return mode === 'element' ? 'copy.element' : mode === 'blog' ? 'copy.blog' : 'copy.section'\n}\n\n/**\n * Per-uid burst limit, matched to `/api/assist/chat`'s 20/min so a client\n * cannot arbitrage the two assist doors against each other.\n */\nconst ASSIST_RATE_LIMIT = 20\nconst ASSIST_RATE_WINDOW_MS = 60_000\n\nconst SECTION_MAX_TOKENS = AI_ROUTING_TABLE['copy.section'].maxTokens\nconst BLOG_MAX_TOKENS = AI_ROUTING_TABLE['copy.blog'].maxTokens\nconst ELEMENT_MAX_TOKENS = AI_ROUTING_TABLE['copy.element'].maxTokens\n\n/**\n * What a `refusal` stop is answered with. The model declined the brief —\n * a policy verdict on the instruction, not a fault — so the sentence asks\n * for a different one rather than a retry. The tokens were spent and are\n * metered before this is sent.\n */\nconst REFUSED = {\n error: 'The AI declined that instruction — try a different one.',\n}\n\n/**\n * AI assist (AGL-89/130/169), the besigner copy assistant's door — the\n * section mode composes over the published-component allowlist and every\n * generated subtree passes the node-definition sanitizer a marketplace\n * install passes, before it reaches a canvas. `/api/ai/assist` is served by\n * the plugin API dispatcher under the `ai` prefix. Gated on a ready provider,\n * one registered with its key set (501 without, the same degrade pattern as\n * Stripe); auth via Firebase ID token.\n *\n * The provider call is `runAiRequest`, the runtime every AI door shares\n * (AGL-2903). This handler owns the ladder below and the response shapes;\n * `ai-assist-prompts.ts` owns the three prompts and the section tool; the\n * runtime owns the wire, the usage arithmetic and the error boundary. The\n * request keeps the model per mode, the `max_tokens` and the absent\n * `thinking` field it has always had — a fast-tier model rejects an explicit\n * one, and the balanced modes keep the model default.\n *\n * A section arrives through a strict tool (AGL-2937). It used to be asked\n * for as bare JSON and parsed: a parse that failed answered 502 with the\n * tokens already spent, so the whole request bought nothing and the member's\n * next move was to spend it again. The text parse is kept behind the tool,\n * for a provider whose adapter has none.\n *\n * ── The spend ladder (AGL-2073) ────────────────────────────────────────────\n *\n * This route reached the provider behind nothing but an entitlement check. Free\n * orgs could not get in, so the free tier was safe — but for any Pro org it\n * had no rate limit, no quota, no per-org cost telemetry, and it resolved the\n * org from the USER rather than the request, so someone with one paid org got\n * assist charged against whichever org `getOrgForUser` happened to return. One\n * subscription, unbounded and unmeasured provider spend.\n *\n * The ladder now, in order, each rung able to go red on its own:\n * 405 → 501 no ready provider → 401 no token → 400 bad body (the request\n * must NAME the org it is metered against) → 403 not a member of that org →\n * 423 the workspace's AI pause → 403 the member's role lacks `ai.use`, or\n * `ai.generate` for a section (AGL-2927; staff pass) → 403 no `aiAssist`\n * entitlement → 423 org lockdown → 429 rate limit → 429 quota → the model\n * call → meter.\n *\n * Two deliberate choices about which way each rung fails:\n *\n * - **The rate limiter fails SOFT and is not the spend bound.** It is a\n * per-instance in-memory window, so N serverless instances admit N × 20/min;\n * it smooths bursts and nothing more. Treating it as the cap would be the\n * fail-open this issue is about.\n * - **The reservation fails CLOSED.** It is the only global, atomic bound on\n * provider spend, so a reservation that cannot be taken — a Firestore\n * outage, a contended transaction — refuses the request with 503 rather than\n * calling the provider uncapped. An unavailable meter must stop the spending,\n * not wave it through.\n *\n * The reservation is `reserveAssistMessage` — the same shared counter the\n * console chat route moves (AGL-2057), not a second mechanism. That is what\n * closes the \"uncapped for paid\" hole the earlier audit named: an entitled org\n * carries the monthly runaway guard, and because both doors move the SAME\n * counter, an org's monthly assist budget is shared across them rather than\n * doubled by having two.\n *\n * Metering is `recordAssistCost`, the signal + rollup half of the assist\n * meters WITHOUT the verbatim half: what a customer types here is their own\n * site copy and blog bodies, and retaining that for 180 days is a data flow\n * the published privacy disclosure does not describe. The margin question is\n * answered by the signal alone.\n */\nexport const aiAssistHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n if (!aiProviderReady()) {\n return res\n .status(501)\n .json({ error: 'AI assist is not configured (no AI provider key).' })\n }\n\n const headers = req.headers as Partial<Record<string, string>>\n const authorization = headers.authorization ?? ''\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n\n const body = req.body ?? {}\n const text = String(body?.text ?? '').slice(0, 12000)\n const instruction = String(body?.instruction ?? '').slice(0, 500)\n // Modes (AGL-130): 'element' rewrites short copy; 'blog' writes or\n // improves markdown-lite entry bodies with title/excerpt context.\n const mode =\n body?.mode === 'blog'\n ? 'blog'\n : body?.mode === 'section'\n ? 'section'\n : 'element'\n const title = String(body?.title ?? '').slice(0, 200)\n const excerpt = String(body?.excerpt ?? '').slice(0, 500)\n // The request must NAME the org it is about to be metered against\n // (AGL-2073, the AGL-1934 rule applied to this door). Resolving the org\n // from the user alone charged a multi-org user's assist to whichever org\n // came back first — and handed their free workspaces a paid feature.\n const orgId = String(body?.orgId ?? '').trim()\n const hostId = String(body?.hostId ?? '')\n .trim()\n .slice(0, 128)\n if (!instruction) {\n return res.status(400).json({ error: 'Missing instruction' })\n }\n if (!orgId) {\n return res\n .status(400)\n .json({ error: 'Open a workspace before using AI assist' })\n }\n\n let reservation: AssistReservation | null = null\n let providerAnswered = false\n let firestore: FirebaseFirestore.Firestore | null = null\n\n try {\n const app = firebaseAdmin.app()\n firestore = app.firestore()\n const decoded = await app.auth().verifyIdToken(idToken)\n\n // Plan gate (AGL-469): AI assist is a Pro+ entitlement with real token\n // cost — resolve the caller's org and check it server-side; a plan-less\n // org resolves as `free` and is denied. Scoped to the NAMED org, so\n // membership of some other paid org is not a key to this one.\n const resolved = await getOrgForUser(decoded.uid, orgId)\n if (!resolved || resolved.orgId !== orgId) {\n return res\n .status(403)\n .json({ error: 'You are not a member of that organization' })\n }\n const org = resolved.org ?? {}\n\n // Permission (AGL-2927), directly after membership. The element and\n // blog modes are assistance and sell under `ai.use`; a generated\n // section is a generation and sells under `ai.generate`. Decided on the\n // caller's own axis — the org catalog for an org-wide member, the site\n // the body named for a collaborator, who is refused when it named none.\n // A fact about the caller, so it is answered before the plan is. Staff\n // pass, as at every other org route. Beside it, the workspace-scoped\n // pause on `ai-assist`: the dispatcher already applied the platform-wide\n // switch by path, before it knew which org the body would name.\n const staff = decoded['staff'] === true\n const aiPaused = await featureLockdownRefusal({\n feature: 'ai-assist',\n staff,\n orgId,\n })\n if (aiPaused) return forwardRefusal(res, aiPaused)\n const permission = mode === 'section' ? 'ai.generate' : 'ai.use'\n if (\n !staff &&\n !(await memberHasPermissionOnHost(orgId, hostId, resolved.member, permission))\n ) {\n return forwardRefusal(res, permissionRefusal(permission))\n }\n\n const entitled = checkEntitlement(org, 'aiAssist')\n if (!entitled) {\n return res.status(403).json({ error: 'AI assist requires a Pro plan' })\n }\n\n // Org-scoped lockdown. The dispatcher already evaluates platform and user\n // scope plus the `ai-assist` feature kill switch, but its org scope needs\n // a `hostId` this route's callers do not send — so a suspended workspace\n // kept spending. The org doc is already in hand, so the verdict is free.\n const locked = await lockdownRefusal({\n request: { method: req.method },\n staff,\n uid: decoded.uid,\n org: org as Record<string, unknown>,\n })\n if (locked) return forwardRefusal(res, locked)\n\n const rate = checkRateLimit(`ai-assist:${decoded.uid}`, {\n limit: ASSIST_RATE_LIMIT,\n windowMs: ASSIST_RATE_WINDOW_MS,\n })\n if (!rate.allowed) {\n for (const [name, value] of Object.entries(rateLimitHeaders(rate))) {\n res.setHeader(name, value)\n }\n return res\n .status(429)\n .json({ error: 'Too many AI requests — slow down a moment' })\n }\n // The same window keyed on the trusted-hop client address (AGL-2925):\n // accounts rotated behind one address share one budget.\n const ipRate = checkAiClientIpRateLimit(headers)\n if (ipRate && !ipRate.allowed) {\n for (const [name, value] of Object.entries(rateLimitHeaders(ipRate))) {\n res.setHeader(name, value)\n }\n return res\n .status(429)\n .json({ error: 'Too many AI requests — slow down a moment' })\n }\n\n // RESERVED, not merely checked (AGL-2057/2073). Read-and-increment in one\n // transaction, BEFORE a single token is spent, so N concurrent requests\n // cannot all read the same \"under the cap\" and a client that drops the\n // connection has already been counted.\n try {\n // `org` is the document `entitled` came from, and it is what makes\n // the plan's own assist band bind rather than the operator backstop\n // alone. Generative building is the dearest thing this route serves,\n // so the band it spends against has to be the one that was sold.\n reservation = await reserveAssistMessage(\n firestore,\n orgId,\n entitled,\n new Date(),\n org,\n // The allotments that apply (AGL-2942): the asker's own, theirs on\n // the canvas's site, and the site's.\n { uid: decoded.uid, hostId: hostId || null },\n )\n } catch (error) {\n // FAIL CLOSED. The reservation is the only global bound on what this\n // route can spend at the provider; if it cannot be taken there is no cap,\n // and no cap is worse than no answer.\n console.error('assist reservation failed', error)\n return res\n .status(503)\n .json({ error: 'AI assist is temporarily unavailable' })\n }\n // A refusal is the asker's as well as the workspace's (AGL-2928): their\n // month counts it beside the org counter the reservation moved.\n recordUserAiRefusal(firestore, orgId, decoded.uid, reservation)\n if (!reservation.allowed) {\n const refusedBy = reservation.refusedBy\n // A hard allotment (AGL-2942): the monthly line a manager drew for\n // the asker or the site, with the sentence naming who can raise it.\n if (refusedBy === 'allotment') {\n return res.status(429).json({\n error: aiAllotmentRefusalText(reservation.allotment?.refusal?.scope),\n reason: 'quota',\n quota: publicAssistQuota(reservation),\n meter: aiUsageMeter(reservation),\n })\n }\n // The org's own controls are a 402, not a 429: credits past the band\n // are for sale and this workspace either switched the sale off\n // (AGL-2653) or capped what it would buy (AGL-2898), so the sentence\n // names the control that refused — the same sentence the console\n // assistant gives, from the same helper. Every other refusal keeps\n // the 429.\n // AGLYN'S OWN OVERAGE GUARDS (AGL-3011): a card, a pause, this\n // month's ceiling or a settling balance, each with the status that\n // says whether the workspace can act on it. Before the workspace's\n // own controls, which answer only for the controls it set itself.\n const overage = aiOverageReservationRefusal(reservation)\n if (overage) {\n return res.status(overage.status).json({\n error: overage.text,\n reason: 'quota',\n quota: publicAssistQuota(reservation),\n meter: aiUsageMeter(reservation),\n })\n }\n const ownControl = assistOwnControlRefusalText(org, refusedBy)\n return res.status(ownControl ? 402 : 429).json({\n error:\n ownControl ??\n // The Free taste's own precautions (AGL-2925), in the sentences\n // the console assistant uses.\n assistFreeTasteRefusalText(refusedBy) ??\n 'This workspace reached its AI assist limit for the month — contact support if you need a higher cap',\n // CREDITS, never the reservation itself — see `publicAssistQuota`.\n quota: publicAssistQuota(reservation),\n meter: aiUsageMeter(reservation),\n })\n }\n\n const tier: 'free' | 'entitled' = entitled ? 'entitled' : 'free'\n // ONE resolution, read by both the request and the meter — see\n // `assistModelForMode`. Two call sites would let them drift. A model the\n // asker picked (AGL-2942) replaces the routing table's answer only when\n // the plan, the org's restriction and the allotment allowlists all allow\n // it; anything else runs on Auto.\n const held = reservation\n const choice = resolveAiModelChoice(assistStepKindForMode(mode), body?.model, {\n plan: resolveEffectivePlan(org),\n allotmentModels: held.allotment?.models ?? null,\n orgModels: held.allotment?.orgModels ?? null,\n })\n const model = choice?.model ?? assistModelForMode(mode)\n /** The usage strip's envelope for an answered request (AGL-2942). */\n const meterFor = (result: AiResult) =>\n aiUsageMeter(held, {\n lastCredits: assistCreditsFromUsd(estimateAssistCostUsd(result.usage, model)),\n model: { id: model, auto: choice?.auto ?? true },\n })\n /** Meter what the provider actually charged us for, per org. */\n // The account the reservation drew on (AGL-2925), read once here: the\n // closure below runs after `reservation` may have been cleared by a\n // refund, and a refund never reaches the meter.\n const free = reservation?.free ?? null\n const meter = (result: AiResult): Promise<unknown> =>\n recordAssistCost(firestore, orgId, {\n route: `/api/ai/assist/${mode}`,\n hostId: hostId || null,\n model,\n tier,\n usage: result.usage,\n docsPaths: [],\n stopReason: result.stopReason,\n free,\n }).catch((error) => console.error('assist cost metering failed', error))\n\n /**\n * One provider call, with the refund decided at the boundary: a refused\n * request (a non-2xx answer) spent nothing, so the reservation goes back\n * — against the keys it RECORDED, never against \"now\" — and the caller\n * gets the runtime's fixed sentence, never the provider's (AGL-2815).\n * A result, even a refusal, means the tokens ARE spent: every exit after\n * it meters and none refunds. Anything else thrown never reached the\n * provider and is left to the outer catch, which refunds too.\n */\n const ask = async (\n content: string,\n maxTokens: number,\n tools?: AiTool[],\n ): Promise<AiResult | null> => {\n try {\n const result = await runAiRequest({\n model,\n maxTokens,\n stream: false,\n // The mode's prompt with the acceptable-use rules ahead of it\n // (AGL-2925), from `ai-assist-prompts.ts` so a spec can read what\n // this route sends without standing up the route.\n system: assistModeSystemBlocks(mode),\n messages: [{ role: 'user', content }],\n ...(tools ? { tools } : {}),\n })\n providerAnswered = true\n await meter(result)\n return result\n } catch (error) {\n if (!(error instanceof AiUpstreamError)) throw error\n providerAnswered = true\n await releaseReservation(firestore, orgId, reservation as AssistReservation)\n reservation = null\n res.status(502).json({ error: error.message })\n return null\n }\n }\n\n // Generate section (AGL-169): a constrained-JSON node subtree over the\n // marketplace component allowlist; the response passes the same\n // sanitizer as marketplace installs before it ever reaches a canvas.\n if (mode === 'section') {\n const result = await ask(\n `Section to design: ${instruction}`,\n SECTION_MAX_TOKENS,\n [assistSectionTool()],\n )\n if (!result) return\n if (result.kind === 'refusal') {\n return res.status(502).json({ ...REFUSED, meter: meterFor(result) })\n }\n const read = readAssistSection(result)\n if (read.status !== 'ok') {\n // Unreadable is the provider's fault and rejected is the answer's,\n // the two statuses this route has always drawn that line between.\n return res.status(read.status === 'unreadable' ? 502 : 422).json({ error: read.error })\n }\n // A subtree is going back (AGL-2929): the act, its size and its site in\n // the customer's feed — never the instruction or the copy generated.\n await logAiAssistSection(\n { uid: decoded.uid, email: decoded.email ?? null },\n {\n orgId,\n hostId: hostId || null,\n nodeCount: Object.keys(read.section.nodes).length,\n },\n )\n return res.status(200).json({ section: read.section, meter: meterFor(result) })\n }\n\n const result = await ask(\n mode === 'blog'\n ? [\n title && `Title: ${title}`,\n excerpt && `Excerpt: ${excerpt}`,\n text && `Current body:\\n${text}`,\n `Instruction: ${instruction}`,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n : text\n ? `Current element text:\\n${text}\\n\\nInstruction: ${instruction}`\n : `Write website element text. Instruction: ${instruction}`,\n mode === 'blog' ? BLOG_MAX_TOKENS : ELEMENT_MAX_TOKENS,\n )\n if (!result) return\n if (result.kind === 'refusal') {\n return res.status(502).json({ ...REFUSED, meter: meterFor(result) })\n }\n const output = result.text.trim()\n if (!output) {\n return res.status(502).json({ error: 'Empty AI response', meter: meterFor(result) })\n }\n return res.status(200).json({ text: output, meter: meterFor(result) })\n } catch (error) {\n console.error(error)\n // The provider was never reached — a token verification failure, a DNS\n // error, a socket reset before any response. Nothing was spent, so the\n // reservation must not be. If the provider DID answer, the tokens are\n // real and the reservation stays consumed however the request ends.\n if (firestore && reservation && !providerAnswered) {\n await releaseReservation(firestore, orgId, reservation)\n }\n return res.status(500).json({ error: 'Assist failed' })\n }\n}\n\n/**\n * Hand a reservation back, never letting the refund itself fail the request.\n * Released against the keys the RESERVATION recorded — a reservation taken at\n * 23:59:59 and released at 00:00:01 must not credit the next day.\n */\nasync function releaseReservation(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n reservation: AssistReservation,\n): Promise<void> {\n await releaseAssistMessage(firestore, orgId, reservation).catch((error) =>\n console.error('assist reservation release failed', error),\n )\n}\n\n/** Re-emit a lockdown `Response` through the plugin API's res object. */\nasync function forwardRefusal(\n res: PluginApiResponse,\n refusal: Response,\n): Promise<void> {\n const retryAfter = refusal.headers.get('Retry-After')\n if (retryAfter) res.setHeader('Retry-After', retryAfter)\n const body = await refusal.json().catch(() => ({ error: 'locked' }))\n res.status(refusal.status).json(body)\n}\n"],"names":["checkEntitlement","assistCreditsFromUsd","assistFreeTasteRefusalText","assistOwnControlRefusalText","resolveEffectivePlan","aiAllotmentRefusalText","resolveAiModelChoice","aiUsageMeter","permissionRefusal","checkRateLimit","featureLockdownRefusal","firebaseAdmin","getOrgForUser","lockdownRefusal","memberHasPermissionOnHost","rateLimitHeaders","aiOverageReservationRefusal","recordUserAiRefusal","estimateAssistCostUsd","publicAssistQuota","recordAssistCost","releaseAssistMessage","reserveAssistMessage","logAiAssistSection","AI_ROUTING_TABLE","aiModelForStep","AiUpstreamError","aiProviderReady","runAiRequest","assistModeSystemBlocks","assistSectionTool","readAssistSection","checkAiClientIpRateLimit","assistModelForMode","mode","assistStepKindForMode","ASSIST_RATE_LIMIT","ASSIST_RATE_WINDOW_MS","SECTION_MAX_TOKENS","maxTokens","BLOG_MAX_TOKENS","ELEMENT_MAX_TOKENS","REFUSED","error","aiAssistHandler","req","res","headers","method","status","json","authorization","idToken","startsWith","slice","length","undefined","body","text","String","instruction","title","excerpt","orgId","trim","hostId","reservation","providerAnswered","firestore","resolved","held","app","decoded","auth","verifyIdToken","uid","org","staff","aiPaused","feature","forwardRefusal","permission","member","entitled","locked","request","rate","limit","windowMs","allowed","name","value","Object","entries","setHeader","ipRate","Date","console","ownControl","refusedBy","allotment","refusal","scope","reason","quota","meter","overage","tier","choice","model","plan","allotmentModels","models","orgModels","meterFor","result","lastCredits","usage","id","auto","free","route","docsPaths","stopReason","catch","ask","content","tools","stream","system","messages","role","releaseReservation","message","kind","read","email","nodeCount","keys","section","nodes","filter","Boolean","join","output","retryAfter","get"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,gBAAgB,QAGX,sBAAqB;AAC5B,SACEC,oBAAoB,EACpBC,0BAA0B,EAC1BC,2BAA2B,QACtB,wCAAuC;AAC9C,SAASC,oBAAoB,QAAQ,2CAA0C;AAC/E,SAASC,sBAAsB,QAAQ,4BAAwB;AAC/D,SAASC,oBAAoB,QAAQ,+BAA2B;AAChE,SAASC,YAAY,QAAQ,6BAAyB;AACtD,SACEC,iBAAiB,EACjBC,cAAc,EACdC,sBAAsB,EACtBC,aAAa,EACbC,aAAa,EACbC,eAAe,EACfC,yBAAyB,EACzBC,gBAAgB,QACX,2BAA0B;AACjC,SAASC,2BAA2B,QAAQ,gCAA4B;AACxE,SAASC,mBAAmB,QAAQ,+BAA2B;AAC/D,SACEC,qBAAqB,EACrBC,iBAAiB,EACjBC,gBAAgB,EAChBC,oBAAoB,EACpBC,oBAAoB,QAEf,2BAAuB;AAC9B,SAASC,kBAAkB,QAAQ,6BAAyB;AAC5D,2EAA2E;AAC3E,6EAA6E;AAC7E,6EAA6E;AAC7E,kEAAkE;AAClE,SAASC,gBAAgB,EAAEC,cAAc,QAAQ,0BAAsB;AACvE,SACEC,eAAe,EACfC,eAAe,EACfC,YAAY,QAGP,2BAAuB;AAC9B,SAEEC,sBAAsB,EACtBC,iBAAiB,EACjBC,iBAAiB,QAEZ,yBAAqB;AAC5B,yEAAyE;AACzE,yEAAyE;AACzE,SAASC,wBAAwB,QAAQ,gCAA4B;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BC,GACD,OAAO,SAASC,mBAAmBC,IAAkB;IACnD,OAAOT,eAAeU,sBAAsBD;AAC9C;AAEA,iDAAiD,GACjD,OAAO,SAASC,sBACdD,IAAkB;IAElB,OAAOA,SAAS,YAAY,iBAAiBA,SAAS,SAAS,cAAc;AAC/E;AAEA;;;CAGC,GACD,MAAME,oBAAoB;AAC1B,MAAMC,wBAAwB;AAE9B,MAAMC,qBAAqBd,gBAAgB,CAAC,eAAe,CAACe,SAAS;AACrE,MAAMC,kBAAkBhB,gBAAgB,CAAC,YAAY,CAACe,SAAS;AAC/D,MAAME,qBAAqBjB,gBAAgB,CAAC,eAAe,CAACe,SAAS;AAErE;;;;;CAKC,GACD,MAAMG,UAAU;IACdC,OAAO;AACT;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgEC,GACD,OAAO,MAAMC,kBAAoC,OAAOC,KAAKC;QAWrCC,wBAMTF;IAhBb,IAAIA,IAAIG,MAAM,KAAK,QAAQ;QACzB,OAAOF,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEP,OAAO;QAAqB;IAC5D;IACA,IAAI,CAAChB,mBAAmB;QACtB,OAAOmB,IACJG,MAAM,CAAC,KACPC,IAAI,CAAC;YAAEP,OAAO;QAAoD;IACvE;IAEA,MAAMI,UAAUF,IAAIE,OAAO;IAC3B,MAAMI,iBAAgBJ,yBAAAA,QAAQI,aAAa,YAArBJ,yBAAyB;IAC/C,MAAMK,UAAUD,cAAcE,UAAU,CAAC,aACrCF,cAAcG,KAAK,CAAC,UAAUC,MAAM,IACpCC;IACJ,IAAI,CAACJ,SAAS,OAAON,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;QAAEP,OAAO;IAAkB;IAErE,MAAMc,QAAOZ,YAAAA,IAAIY,IAAI,YAARZ,YAAY,CAAC;IAC1B,MAAMa,OAAOC,eAAOF,wBAAAA,KAAMC,IAAI,mBAAI,IAAIJ,KAAK,CAAC,GAAG;IAC/C,MAAMM,cAAcD,gBAAOF,wBAAAA,KAAMG,WAAW,oBAAI,IAAIN,KAAK,CAAC,GAAG;IAC7D,mEAAmE;IACnE,kEAAkE;IAClE,MAAMpB,OACJuB,CAAAA,wBAAAA,KAAMvB,IAAI,MAAK,SACX,SACAuB,CAAAA,wBAAAA,KAAMvB,IAAI,MAAK,YACb,YACA;IACR,MAAM2B,QAAQF,gBAAOF,wBAAAA,KAAMI,KAAK,oBAAI,IAAIP,KAAK,CAAC,GAAG;IACjD,MAAMQ,UAAUH,gBAAOF,wBAAAA,KAAMK,OAAO,oBAAI,IAAIR,KAAK,CAAC,GAAG;IACrD,kEAAkE;IAClE,wEAAwE;IACxE,yEAAyE;IACzE,qEAAqE;IACrE,MAAMS,QAAQJ,gBAAOF,wBAAAA,KAAMM,KAAK,oBAAI,IAAIC,IAAI;IAC5C,MAAMC,SAASN,gBAAOF,wBAAAA,KAAMQ,MAAM,oBAAI,IACnCD,IAAI,GACJV,KAAK,CAAC,GAAG;IACZ,IAAI,CAACM,aAAa;QAChB,OAAOd,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEP,OAAO;QAAsB;IAC7D;IACA,IAAI,CAACoB,OAAO;QACV,OAAOjB,IACJG,MAAM,CAAC,KACPC,IAAI,CAAC;YAAEP,OAAO;QAA0C;IAC7D;IAEA,IAAIuB,cAAwC;IAC5C,IAAIC,mBAAmB;IACvB,IAAIC,YAAgD;IAEpD,IAAI;YAeUC;YAwJOC,iBACNA;QAvKb,MAAMC,MAAM5D,cAAc4D,GAAG;QAC7BH,YAAYG,IAAIH,SAAS;QACzB,MAAMI,UAAU,MAAMD,IAAIE,IAAI,GAAGC,aAAa,CAACtB;QAE/C,uEAAuE;QACvE,wEAAwE;QACxE,oEAAoE;QACpE,8DAA8D;QAC9D,MAAMiB,WAAW,MAAMzD,cAAc4D,QAAQG,GAAG,EAAEZ;QAClD,IAAI,CAACM,YAAYA,SAASN,KAAK,KAAKA,OAAO;YACzC,OAAOjB,IACJG,MAAM,CAAC,KACPC,IAAI,CAAC;gBAAEP,OAAO;YAA4C;QAC/D;QACA,MAAMiC,OAAMP,gBAAAA,SAASO,GAAG,YAAZP,gBAAgB,CAAC;QAE7B,oEAAoE;QACpE,iEAAiE;QACjE,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,uEAAuE;QACvE,qEAAqE;QACrE,yEAAyE;QACzE,gEAAgE;QAChE,MAAMQ,QAAQL,OAAO,CAAC,QAAQ,KAAK;QACnC,MAAMM,WAAW,MAAMpE,uBAAuB;YAC5CqE,SAAS;YACTF;YACAd;QACF;QACA,IAAIe,UAAU,OAAOE,eAAelC,KAAKgC;QACzC,MAAMG,aAAa/C,SAAS,YAAY,gBAAgB;QACxD,IACE,CAAC2C,SACD,CAAE,MAAM/D,0BAA0BiD,OAAOE,QAAQI,SAASa,MAAM,EAAED,aAClE;YACA,OAAOD,eAAelC,KAAKtC,kBAAkByE;QAC/C;QAEA,MAAME,WAAWnF,iBAAiB4E,KAAK;QACvC,IAAI,CAACO,UAAU;YACb,OAAOrC,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;gBAAEP,OAAO;YAAgC;QACvE;QAEA,0EAA0E;QAC1E,0EAA0E;QAC1E,yEAAyE;QACzE,yEAAyE;QACzE,MAAMyC,SAAS,MAAMvE,gBAAgB;YACnCwE,SAAS;gBAAErC,QAAQH,IAAIG,MAAM;YAAC;YAC9B6B;YACAF,KAAKH,QAAQG,GAAG;YAChBC,KAAKA;QACP;QACA,IAAIQ,QAAQ,OAAOJ,eAAelC,KAAKsC;QAEvC,MAAME,OAAO7E,eAAe,CAAC,UAAU,EAAE+D,QAAQG,GAAG,EAAE,EAAE;YACtDY,OAAOnD;YACPoD,UAAUnD;QACZ;QACA,IAAI,CAACiD,KAAKG,OAAO,EAAE;YACjB,KAAK,MAAM,CAACC,MAAMC,MAAM,IAAIC,OAAOC,OAAO,CAAC9E,iBAAiBuE,OAAQ;gBAClExC,IAAIgD,SAAS,CAACJ,MAAMC;YACtB;YACA,OAAO7C,IACJG,MAAM,CAAC,KACPC,IAAI,CAAC;gBAAEP,OAAO;YAA4C;QAC/D;QACA,sEAAsE;QACtE,wDAAwD;QACxD,MAAMoD,SAAS/D,yBAAyBe;QACxC,IAAIgD,UAAU,CAACA,OAAON,OAAO,EAAE;YAC7B,KAAK,MAAM,CAACC,MAAMC,MAAM,IAAIC,OAAOC,OAAO,CAAC9E,iBAAiBgF,SAAU;gBACpEjD,IAAIgD,SAAS,CAACJ,MAAMC;YACtB;YACA,OAAO7C,IACJG,MAAM,CAAC,KACPC,IAAI,CAAC;gBAAEP,OAAO;YAA4C;QAC/D;QAEA,0EAA0E;QAC1E,wEAAwE;QACxE,uEAAuE;QACvE,uCAAuC;QACvC,IAAI;YACF,mEAAmE;YACnE,oEAAoE;YACpE,qEAAqE;YACrE,iEAAiE;YACjEuB,cAAc,MAAM5C,qBAClB8C,WACAL,OACAoB,UACA,IAAIa,QACJpB,KACA,mEAAmE;YACnE,qCAAqC;YACrC;gBAAED,KAAKH,QAAQG,GAAG;gBAAEV,QAAQA,UAAU;YAAK;QAE/C,EAAE,OAAOtB,OAAO;YACd,qEAAqE;YACrE,0EAA0E;YAC1E,sCAAsC;YACtCsD,QAAQtD,KAAK,CAAC,6BAA6BA;YAC3C,OAAOG,IACJG,MAAM,CAAC,KACPC,IAAI,CAAC;gBAAEP,OAAO;YAAuC;QAC1D;QACA,wEAAwE;QACxE,gEAAgE;QAChE1B,oBAAoBmD,WAAWL,OAAOS,QAAQG,GAAG,EAAET;QACnD,IAAI,CAACA,YAAYuB,OAAO,EAAE;gBAkCpBS;YAjCJ,MAAMC,YAAYjC,YAAYiC,SAAS;YACvC,mEAAmE;YACnE,oEAAoE;YACpE,IAAIA,cAAc,aAAa;oBAEGjC,gCAAAA;gBADhC,OAAOpB,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;oBAC1BP,OAAOtC,wBAAuB6D,yBAAAA,YAAYkC,SAAS,sBAArBlC,iCAAAA,uBAAuBmC,OAAO,qBAA9BnC,+BAAgCoC,KAAK;oBACnEC,QAAQ;oBACRC,OAAOrF,kBAAkB+C;oBACzBuC,OAAOlG,aAAa2D;gBACtB;YACF;YACA,qEAAqE;YACrE,+DAA+D;YAC/D,qEAAqE;YACrE,iEAAiE;YACjE,mEAAmE;YACnE,WAAW;YACX,+DAA+D;YAC/D,mEAAmE;YACnE,mEAAmE;YACnE,kEAAkE;YAClE,MAAMwC,UAAU1F,4BAA4BkD;YAC5C,IAAIwC,SAAS;gBACX,OAAO5D,IAAIG,MAAM,CAACyD,QAAQzD,MAAM,EAAEC,IAAI,CAAC;oBACrCP,OAAO+D,QAAQhD,IAAI;oBACnB6C,QAAQ;oBACRC,OAAOrF,kBAAkB+C;oBACzBuC,OAAOlG,aAAa2D;gBACtB;YACF;YACA,MAAMgC,aAAa/F,4BAA4ByE,KAAKuB;YACpD,OAAOrD,IAAIG,MAAM,CAACiD,aAAa,MAAM,KAAKhD,IAAI,CAAC;gBAC7CP,KAAK,GACHuD,SAAAA,qBAAAA,aACA,gEAAgE;gBAChE,8BAA8B;gBAC9BhG,2BAA2BiG,sBAH3BD,SAIA;gBACF,mEAAmE;gBACnEM,OAAOrF,kBAAkB+C;gBACzBuC,OAAOlG,aAAa2D;YACtB;QACF;QAEA,MAAMyC,OAA4BxB,WAAW,aAAa;QAC1D,+DAA+D;QAC/D,yEAAyE;QACzE,wEAAwE;QACxE,yEAAyE;QACzE,kCAAkC;QAClC,MAAMb,OAAOJ;QACb,MAAM0C,SAAStG,qBAAqB6B,sBAAsBD,OAAOuB,wBAAAA,KAAMoD,KAAK,EAAE;YAC5EC,MAAM1G,qBAAqBwE;YAC3BmC,eAAe,YAAEzC,kBAAAA,KAAK8B,SAAS,qBAAd9B,gBAAgB0C,MAAM,oBAAI;YAC3CC,SAAS,YAAE3C,mBAAAA,KAAK8B,SAAS,qBAAd9B,iBAAgB2C,SAAS,oBAAI;QAC1C;QACA,MAAMJ,iBAAQD,0BAAAA,OAAQC,KAAK,oBAAI5E,mBAAmBC;QAClD,mEAAmE,GACnE,MAAMgF,WAAW,CAACC;;mBAChB5G,aAAa+D,MAAM;gBACjB8C,aAAanH,qBAAqBiB,sBAAsBiG,OAAOE,KAAK,EAAER;gBACtEA,OAAO;oBAAES,IAAIT;oBAAOU,IAAI,UAAEX,0BAAAA,OAAQW,IAAI,mBAAI;gBAAK;YACjD;;QACF,8DAA8D,GAC9D,sEAAsE;QACtE,oEAAoE;QACpE,gDAAgD;QAChD,MAAMC,gBAAOtD,+BAAAA,YAAasD,IAAI,oBAAI;QAClC,MAAMf,QAAQ,CAACU,SACb/F,iBAAiBgD,WAAWL,OAAO;gBACjC0D,OAAO,CAAC,eAAe,EAAEvF,MAAM;gBAC/B+B,QAAQA,UAAU;gBAClB4C;gBACAF;gBACAU,OAAOF,OAAOE,KAAK;gBACnBK,WAAW,EAAE;gBACbC,YAAYR,OAAOQ,UAAU;gBAC7BH;YACF,GAAGI,KAAK,CAAC,CAACjF,QAAUsD,QAAQtD,KAAK,CAAC,+BAA+BA;QAEnE;;;;;;;;KAQC,GACD,MAAMkF,MAAM,OACVC,SACAvF,WACAwF;YAEA,IAAI;gBACF,MAAMZ,SAAS,MAAMvF,aAAa;oBAChCiF;oBACAtE;oBACAyF,QAAQ;oBACR,8DAA8D;oBAC9D,kEAAkE;oBAClE,kDAAkD;oBAClDC,QAAQpG,uBAAuBK;oBAC/BgG,UAAU;wBAAC;4BAAEC,MAAM;4BAAQL;wBAAQ;qBAAE;mBACjCC,QAAQ;oBAAEA;gBAAM,IAAI,CAAC;gBAE3B5D,mBAAmB;gBACnB,MAAMsC,MAAMU;gBACZ,OAAOA;YACT,EAAE,OAAOxE,OAAO;gBACd,IAAI,CAAEA,CAAAA,iBAAiBjB,eAAc,GAAI,MAAMiB;gBAC/CwB,mBAAmB;gBACnB,MAAMiE,mBAAmBhE,WAAWL,OAAOG;gBAC3CA,cAAc;gBACdpB,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;oBAAEP,OAAOA,MAAM0F,OAAO;gBAAC;gBAC5C,OAAO;YACT;QACF;QAEA,uEAAuE;QACvE,gEAAgE;QAChE,qEAAqE;QACrE,IAAInG,SAAS,WAAW;gBAmBOsC;YAlB7B,MAAM2C,SAAS,MAAMU,IACnB,CAAC,mBAAmB,EAAEjE,aAAa,EACnCtB,oBACA;gBAACR;aAAoB;YAEvB,IAAI,CAACqF,QAAQ;YACb,IAAIA,OAAOmB,IAAI,KAAK,WAAW;gBAC7B,OAAOxF,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC,aAAKR;oBAAS+D,OAAOS,SAASC;;YAC5D;YACA,MAAMoB,OAAOxG,kBAAkBoF;YAC/B,IAAIoB,KAAKtF,MAAM,KAAK,MAAM;gBACxB,mEAAmE;gBACnE,kEAAkE;gBAClE,OAAOH,IAAIG,MAAM,CAACsF,KAAKtF,MAAM,KAAK,eAAe,MAAM,KAAKC,IAAI,CAAC;oBAAEP,OAAO4F,KAAK5F,KAAK;gBAAC;YACvF;YACA,wEAAwE;YACxE,qEAAqE;YACrE,MAAMpB,mBACJ;gBAAEoD,KAAKH,QAAQG,GAAG;gBAAE6D,KAAK,GAAEhE,iBAAAA,QAAQgE,KAAK,YAAbhE,iBAAiB;YAAK,GACjD;gBACET;gBACAE,QAAQA,UAAU;gBAClBwE,WAAW7C,OAAO8C,IAAI,CAACH,KAAKI,OAAO,CAACC,KAAK,EAAErF,MAAM;YACnD;YAEF,OAAOT,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;gBAAEyF,SAASJ,KAAKI,OAAO;gBAAElC,OAAOS,SAASC;YAAQ;QAC/E;QAEA,MAAMA,SAAS,MAAMU,IACnB3F,SAAS,SACL;YACE2B,SAAS,CAAC,OAAO,EAAEA,OAAO;YAC1BC,WAAW,CAAC,SAAS,EAAEA,SAAS;YAChCJ,QAAQ,CAAC,eAAe,EAAEA,MAAM;YAChC,CAAC,aAAa,EAAEE,aAAa;SAC9B,CACEiF,MAAM,CAACC,SACPC,IAAI,CAAC,UACRrF,OACE,CAAC,uBAAuB,EAAEA,KAAK,iBAAiB,EAAEE,aAAa,GAC/D,CAAC,yCAAyC,EAAEA,aAAa,EAC/D1B,SAAS,SAASM,kBAAkBC;QAEtC,IAAI,CAAC0E,QAAQ;QACb,IAAIA,OAAOmB,IAAI,KAAK,WAAW;YAC7B,OAAOxF,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC,aAAKR;gBAAS+D,OAAOS,SAASC;;QAC5D;QACA,MAAM6B,SAAS7B,OAAOzD,IAAI,CAACM,IAAI;QAC/B,IAAI,CAACgF,QAAQ;YACX,OAAOlG,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;gBAAEP,OAAO;gBAAqB8D,OAAOS,SAASC;YAAQ;QACpF;QACA,OAAOrE,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEQ,MAAMsF;YAAQvC,OAAOS,SAASC;QAAQ;IACtE,EAAE,OAAOxE,OAAO;QACdsD,QAAQtD,KAAK,CAACA;QACd,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,oEAAoE;QACpE,IAAIyB,aAAaF,eAAe,CAACC,kBAAkB;YACjD,MAAMiE,mBAAmBhE,WAAWL,OAAOG;QAC7C;QACA,OAAOpB,IAAIG,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEP,OAAO;QAAgB;IACvD;AACF,EAAC;AAED;;;;CAIC,GACD,eAAeyF,mBACbhE,SAAsC,EACtCL,KAAa,EACbG,WAA8B;IAE9B,MAAM7C,qBAAqB+C,WAAWL,OAAOG,aAAa0D,KAAK,CAAC,CAACjF,QAC/DsD,QAAQtD,KAAK,CAAC,qCAAqCA;AAEvD;AAEA,uEAAuE,GACvE,eAAeqC,eACblC,GAAsB,EACtBuD,OAAiB;IAEjB,MAAM4C,aAAa5C,QAAQtD,OAAO,CAACmG,GAAG,CAAC;IACvC,IAAID,YAAYnG,IAAIgD,SAAS,CAAC,eAAemD;IAC7C,MAAMxF,OAAO,MAAM4C,QAAQnD,IAAI,GAAG0E,KAAK,CAAC,IAAO,CAAA;YAAEjF,OAAO;QAAS,CAAA;IACjEG,IAAIG,MAAM,CAACoD,QAAQpD,MAAM,EAAEC,IAAI,CAACO;AAClC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
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 AiCrmProposal } from '../model/ai-crm';
|
|
18
|
+
/** The CRM resource and record an answer was written from, by what it answers. */
|
|
19
|
+
export declare function aiCrmAnswerSubject(proposal: AiCrmProposal): {
|
|
20
|
+
resource: string;
|
|
21
|
+
id: string;
|
|
22
|
+
};
|
|
23
|
+
/** Whether an answer of this kind may be read by anyone other than the member who asked. */
|
|
24
|
+
export declare function aiCrmAnswerShared(proposal: AiCrmProposal): boolean;
|
|
25
|
+
export declare function GET(request: Request, context: {
|
|
26
|
+
params: Promise<{
|
|
27
|
+
jobId: string;
|
|
28
|
+
}>;
|
|
29
|
+
}): Promise<Response>;
|
|
30
|
+
export declare const dynamic = "force-dynamic";
|