@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,978 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ /**
|
|
18
|
+
* `FieldValue` comes straight from the SDK rather than through the admin
|
|
19
|
+
* barrel (AGL-2073). This module serves every metered AI door — the chat
|
|
20
|
+
* door, the besigner copy assistant and the generation jobs — and importing
|
|
21
|
+
* the admin lib's `firebase-admin` module would drag the default-app
|
|
22
|
+
* initialization (cert credential, RTDB, AppCheck) into every unit test that
|
|
23
|
+
* touches a counter; `FieldValue`'s statics need no app at all.
|
|
24
|
+
*/ import { FieldValue } from "firebase-admin/firestore";
|
|
25
|
+
import { ASSIST_PROVIDER_COST_FIELD, assistBandRefuses, assistCreditsFromUsd, assistMonthOverage, assistOverageCapReached, publicAssistCredits, resolveAssistBudgetUsd, resolveAssistOverageCapUsd, resolveAssistOverageRateUsdPer1k } from "@aglyn/aglyn/app-utils/assist-credits";
|
|
26
|
+
import { aiOverageRefusal } from "../billing/ai-overage-gate.js";
|
|
27
|
+
import { aiOverageBillsByInvoice, aiOverageGuardsApply } from "../billing/ai-overage-cutover.js";
|
|
28
|
+
import { AI_BILLING_STANDING_DOC, AI_BILLING_SUBCOLLECTION, readAiOverageMonthLedger } from "../billing/ai-overage-ledger.js";
|
|
29
|
+
import { readAiOverageStanding } from "../billing/ai-overage-standing.js";
|
|
30
|
+
import { AI_HOST_CREDITS_FIELD, readAiAllotmentGate } from "./ai-allotments.js";
|
|
31
|
+
import { isUncappedPlanComp } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
32
|
+
import { assistMonthlyCeilingUsd } from "./assist-ceiling.js";
|
|
33
|
+
import { estimateAiBilledUsd, estimateAiProviderCostUsd } from "../providers/catalog.js";
|
|
34
|
+
import { recordAssistRefusal } from "./assist-refusals.js";
|
|
35
|
+
import { announcePlatformFreeSpend, freeAccountReservationWrite, freeAccountUsageRef, freeAssistAccount, freeTasteMeterWrites, freeTasteReadsFrom, freeTasteRefusal, platformFreeSpendRef } from "./assist-free-taste.js";
|
|
36
|
+
import { aiTokenIncrements, recordUserAiUsage } from "./ai-usage-by-user.js";
|
|
37
|
+
import { AI_USAGE_MONTH_KINDS_FIELD, AI_USAGE_TOKENS_FIELD } from "../model/ai-tokens.js";
|
|
38
|
+
import { aiUsageKindFromRoute } from "../model/ai-usage-by-user.js";
|
|
39
|
+
// The ceiling composition lives beside the one other reader it has, the staff
|
|
40
|
+
// refusal alert, in a module that writes nothing; the reservation's importers
|
|
41
|
+
// keep reaching it here.
|
|
42
|
+
export { assistMonthlyCeilingUsd } from "./assist-ceiling.js";
|
|
43
|
+
/**
|
|
44
|
+
* Aglyn Assist metering + the data loop (AGL-1860, phase 1).
|
|
45
|
+
*
|
|
46
|
+
* Collections (org-scoped, ABSENT from firebase-firestore.rules on purpose —
|
|
47
|
+
* default-deny, the forumThreads precedent: every read/write passes the
|
|
48
|
+
* assist API route via the Admin SDK):
|
|
49
|
+
*
|
|
50
|
+
* orgs/{orgId}/assistUsage/{YYYY-MM} per-org monthly cost telemetry:
|
|
51
|
+
* { month, messages, inputTokens, outputTokens, cacheReadTokens,
|
|
52
|
+
* cacheWriteTokens, estCostUsd, byHost: { hostId: credits },
|
|
53
|
+
* kinds: { kind: { requests, estCostUsd, tokens } }, updatedAt }
|
|
54
|
+
* (`byHost` is each site's credits, which a site's AI allotment is
|
|
55
|
+
* measured against — AGL-2942; `kinds` splits the tokens and the
|
|
56
|
+
* measured spend by what each model request was for — AGL-2937)
|
|
57
|
+
* orgs/{orgId}/counters/assistMessagesDaily
|
|
58
|
+
* fields keyed YYYY-MM-DD → integer (the free-tier daily cap counter;
|
|
59
|
+
* same field-per-period shape as the other `counters/*` docs)
|
|
60
|
+
* orgs/{orgId}/assistExchanges/{id} the VERBATIM half of one exchange:
|
|
61
|
+
* { uid, question, answer, hostId, createdAt, expiresAt }
|
|
62
|
+
* orgs/{orgId}/assistSignals/{id} the DERIVED half, same id:
|
|
63
|
+
* { route, hostId, model, tier, kind, inputTokens, outputTokens,
|
|
64
|
+
* cacheReadTokens, cacheWriteTokens, estCostUsd, docsPaths,
|
|
65
|
+
* stopReason, feedback: 'up'|'down'|null, createdAt }
|
|
66
|
+
*
|
|
67
|
+
* The Free taste (AGL-2925) adds two more, one under the workspace OWNER's
|
|
68
|
+
* user document and one platform-wide, both documented and both closed to
|
|
69
|
+
* clients in `assist-free-taste.ts`.
|
|
70
|
+
*
|
|
71
|
+
* Costs are OUR cost estimates at list rates (pricing-tunable telemetry),
|
|
72
|
+
* mirrored after ORG_COGS_UNIT_RATES_USD's posture: cost visibility per org
|
|
73
|
+
* from day one so the paid gate and caps can be tuned with data — the * "must not eat margins" constraint.
|
|
74
|
+
*
|
|
75
|
+
* ── Why the exchange is split in two (AGL-1972) ────────────────────────────
|
|
76
|
+
*
|
|
77
|
+
* One document carrying both halves forces one retention period onto two
|
|
78
|
+
* kinds of data with opposite needs. The prose is what a person typed; the
|
|
79
|
+
* data loop is what it cited and what it cost. Keeping them together means
|
|
80
|
+
* either the prose is retained forever so the loop keeps its corpus, or the
|
|
81
|
+
* loop's corpus is destroyed so the prose can expire. Neither is the answer,
|
|
82
|
+
* and picking one number for both is how that false choice gets made.
|
|
83
|
+
*
|
|
84
|
+
* So: `assistExchanges` holds the question, the answer and the asking `uid`,
|
|
85
|
+
* and carries `expiresAt` — a TTL policy reaps it after
|
|
86
|
+
* ASSIST_EXCHANGE_RETENTION_DAYS. `assistSignals` holds no prose and NO uid,
|
|
87
|
+
* carries no expiry, and is what the docs-gap view, the thumbs loop and the
|
|
88
|
+
* cost meters actually read. The corpus the loop needs outlives the words
|
|
89
|
+
* that produced it, because the corpus was never the words.
|
|
90
|
+
*
|
|
91
|
+
* Both subcollections sit under the org, so `recursiveDelete(orgRef)` still
|
|
92
|
+
* takes them and an erasure still clears everything with no extra sweep. And
|
|
93
|
+
* both are ABSENT from firebase-firestore.rules deliberately: the org block
|
|
94
|
+
* matches its subcollections BY NAME and has no wildcard, so an unmatched
|
|
95
|
+
* name is default-deny for every client (verified against the live ruleset —
|
|
96
|
+
* the `{subcollection}/{document=**}` catch-all is under `hosts/{hostId}`,
|
|
97
|
+
* not here).
|
|
98
|
+
*
|
|
99
|
+
* ⚠️ The TTL policy is MANUAL gcloud configuration, not repo state. It is
|
|
100
|
+
* documented in `docs/FIRESTORE_MANUAL_CONFIG.md` and declared as a
|
|
101
|
+
* `fieldOverrides` entry in `cloud/firebase-firestore.indexes.json` — the
|
|
102
|
+
* declaration is not decoration, it is what stops the next unrelated index
|
|
103
|
+
* deploy from DELETING the policy. `apps/console/specs/retention-ttl-config.spec.ts`
|
|
104
|
+
* fails the build if either half goes missing.
|
|
105
|
+
*/ /** Current billing month key, `YYYY-MM`, matching the usage rollup. */ export function assistUsageMonth(now = new Date()) {
|
|
106
|
+
return now.toISOString().slice(0, 7);
|
|
107
|
+
}
|
|
108
|
+
/** Current day key, `YYYY-MM-DD` (UTC — same clock as the month key). */ export function assistUsageDay(now = new Date()) {
|
|
109
|
+
return now.toISOString().slice(0, 10);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* How long the VERBATIM half of an exchange is kept — the question, the
|
|
113
|
+
* answer and the asking uid (AGL-1972).
|
|
114
|
+
*
|
|
115
|
+
* 180 days, and the number is chosen against what actually reads this data
|
|
116
|
+
* rather than against a round figure:
|
|
117
|
+
*
|
|
118
|
+
* - The docs-gap loop mines `docsPaths` and the thumbs rating. Both live on
|
|
119
|
+
* the signal document, which has no expiry, so shortening this period
|
|
120
|
+
* costs the loop nothing. That separation is what makes 180 affordable;
|
|
121
|
+
* without it the honest answer would have been "forever".
|
|
122
|
+
* - Two full quarters is long enough to read a quarter's questions LATE, and
|
|
123
|
+
* long enough to diff what people asked before and after a docs rewrite —
|
|
124
|
+
* the one analysis that genuinely needs the prose and not the citations.
|
|
125
|
+
* - It is short enough that a workspace open for years is not an indefinite
|
|
126
|
+
* archive of what its people typed into a text box.
|
|
127
|
+
*
|
|
128
|
+
* ⚠️ TTL deletion is best-effort within ~72h of expiry, so nothing may treat
|
|
129
|
+
* an exchange's absence OR its presence as exact at the boundary. Nothing
|
|
130
|
+
* does: the only reader addresses an exchange by id and tolerates a miss.
|
|
131
|
+
*/ export const ASSIST_EXCHANGE_RETENTION_DAYS = 180;
|
|
132
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
133
|
+
/**
|
|
134
|
+
* When an exchange written at `now` expires. A `Date` rather than a number:
|
|
135
|
+
* a TTL policy keys on a Firestore **Timestamp** and silently governs
|
|
136
|
+
* nothing when the field is a number (`bookings.expiresAtMs` is the
|
|
137
|
+
* documented non-target for exactly this reason). The Admin SDK converts a
|
|
138
|
+
* JS `Date` to a Timestamp on write, which is how `cspViolationDaily` does
|
|
139
|
+
* it and is why this module needs no firebase-admin type here.
|
|
140
|
+
*/ export function assistExchangeExpiry(now = new Date()) {
|
|
141
|
+
return new Date(now.getTime() + ASSIST_EXCHANGE_RETENTION_DAYS * DAY_MS);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Free-tier daily message cap (level-1 answers only). Env-tunable without a
|
|
145
|
+
* deploy of new code paths.
|
|
146
|
+
*
|
|
147
|
+
* What ten messages actually cost: about **$0.28 a day** at Sonnet list
|
|
148
|
+
* rates, taking the worst case the clamps allow (see
|
|
149
|
+
* `ASSIST_ORG_MONTHLY_COGS_LIMIT_DEFAULT_USD` for the same arithmetic
|
|
150
|
+
* carried to the monthly ceiling). A typical question costs a fraction of
|
|
151
|
+
* that, because the worst case assumes a full 8,000-character history and a
|
|
152
|
+
* 4,000-character question on every one of the ten.
|
|
153
|
+
*
|
|
154
|
+
* This docstring used to claim "well under a cent a day", which was the
|
|
155
|
+
* pre-AGL-2441 figure and wrong by ~28x once the history clamp was measured
|
|
156
|
+
* rather than assumed. It is restated here because it is the stated
|
|
157
|
+
* justification for the size of this cap, and a justification that is off by
|
|
158
|
+
* that much is how a cap ends up set by a number nobody re-derived.
|
|
159
|
+
*/ export function assistFreeDailyLimit() {
|
|
160
|
+
const raw = process.env.ASSIST_FREE_DAILY_LIMIT;
|
|
161
|
+
// `Number('')` is 0, so an unset/empty var must fall through to the
|
|
162
|
+
// default rather than silently zeroing the free tier.
|
|
163
|
+
const parsed = raw ? Number(raw) : Number.NaN;
|
|
164
|
+
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 10;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Entitled (Pro+/aiAssist) monthly message cap — a runaway guard, not a
|
|
168
|
+
* product limit: high enough that no real user hits it, low enough that a
|
|
169
|
+
* scripted client cannot turn one subscription into unbounded token spend.
|
|
170
|
+
*/ export function assistEntitledMonthlyLimit() {
|
|
171
|
+
const raw = process.env.ASSIST_ENTITLED_MONTHLY_LIMIT;
|
|
172
|
+
const parsed = raw ? Number(raw) : Number.NaN;
|
|
173
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 1000;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* What one exchange DRAWS FROM THE CUSTOMER, at the serving model's billed
|
|
177
|
+
* rates, rounded to 6dp — the figure `assistCreditsFromUsd` turns into
|
|
178
|
+
* credits and the one the band, the cap and the invoice are measured in.
|
|
179
|
+
*
|
|
180
|
+
* The rates are the model catalog's (AGL-2939), keyed by model rather than
|
|
181
|
+
* fixed at one model's because `ASSIST_MODEL` is an env override: a
|
|
182
|
+
* one-line incident swap to a dearer model would otherwise keep reporting
|
|
183
|
+
* the cheaper money, and per-org cost would read as roughly right — the
|
|
184
|
+
* failure mode this whole meter exists to prevent. An unknown id is priced
|
|
185
|
+
* at the dearest known tier on purpose, because an estimate that errs low is
|
|
186
|
+
* worse than one that errs high, and a docs-only answer is metered under a
|
|
187
|
+
* zero-priced sentinel (`AI_METER_SENTINELS`) so it lands in the same rollup
|
|
188
|
+
* as a served one.
|
|
189
|
+
*
|
|
190
|
+
* NOT A COST (AGL-3015). A model may be billed above what its provider
|
|
191
|
+
* charges, so this overstates what the exchange cost us by exactly that
|
|
192
|
+
* markup. `estimateAssistProviderCostUsd` is the figure a margin or a spend
|
|
193
|
+
* meter takes.
|
|
194
|
+
*/ export function estimateAssistCostUsd(usage, model) {
|
|
195
|
+
return estimateAiBilledUsd(usage, model);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* What one exchange COST US, at the serving model's provider rates, rounded
|
|
199
|
+
* to 6dp — real money, recorded beside the billed figure so a margin is
|
|
200
|
+
* taken against a bill we actually pay rather than against a price we
|
|
201
|
+
* charge.
|
|
202
|
+
*
|
|
203
|
+
* At or below `estimateAssistCostUsd` for the same tokens, and equal to it
|
|
204
|
+
* on every model billed at its provider's list.
|
|
205
|
+
*/ export function estimateAssistProviderCostUsd(usage, model) {
|
|
206
|
+
return estimateAiProviderCostUsd(usage, model);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Reserve one assist message BEFORE the model is called (AGL-2057).
|
|
210
|
+
*
|
|
211
|
+
* This replaces `checkAssistQuota` on the request path, and the difference is
|
|
212
|
+
* the whole point. `checkAssistQuota` READ the counter and let the request
|
|
213
|
+
* through; the counter only moved in `recordAssistExchange`, at stream
|
|
214
|
+
* COMPLETION. Two ways out of the cap followed, both of which spend real
|
|
215
|
+
* provider tokens for an org that has no invoice to put them on:
|
|
216
|
+
*
|
|
217
|
+
* 1. **Concurrency.** N in-flight requests each read `used < limit` before any
|
|
218
|
+
* of them recorded. The per-uid rate limiter (20/min) was the only bound.
|
|
219
|
+
* 2. **Abandoned streams.** Recording ran in the stream's completion handler,
|
|
220
|
+
* so a client that opened a request and dropped it never counted at all.
|
|
221
|
+
* Looped, that is UNBOUNDED spend on a free workspace — the cap simply
|
|
222
|
+
* never advanced. This is the fail-open that costs money silently.
|
|
223
|
+
*
|
|
224
|
+
* So the count moves to the front, inside a transaction: read and increment
|
|
225
|
+
* are one atomic step, and a refused request never reaches the provider. The
|
|
226
|
+
* lesson is AGL's own — fix WHEN the quota is evaluated, not how the counting
|
|
227
|
+
* is done.
|
|
228
|
+
*
|
|
229
|
+
* Both counters move here (the daily one AND monthly `messages`) so message
|
|
230
|
+
* counting has exactly one home. `recordAssistExchange` therefore records the
|
|
231
|
+
* exchange, its tokens and its cost, and counts NO messages; calling it after
|
|
232
|
+
* a reservation must not double-count.
|
|
233
|
+
*
|
|
234
|
+
* A plan-less org resolves as free upstream, so an unknown org gets the
|
|
235
|
+
* SMALLER cap. That direction is deliberate.
|
|
236
|
+
*
|
|
237
|
+
* ## The spend gate is the one that matters now
|
|
238
|
+
*
|
|
239
|
+
* The message caps above are a runaway guard. The gate that decides what a
|
|
240
|
+
* paying workspace gets is the SPEND ceiling, because assist actions differ
|
|
241
|
+
* in cost by up to two orders of magnitude: a question is a few thousand
|
|
242
|
+
* tokens and generating a screen carries a node tree, a component catalog and
|
|
243
|
+
* theme tokens in and structured markup out. Counting both as one message
|
|
244
|
+
* would let ten screen builds outspend a thousand questions while both read
|
|
245
|
+
* as being within allowance.
|
|
246
|
+
*
|
|
247
|
+
* `org` is the billing document the caller already resolved `entitled` from.
|
|
248
|
+
* It is optional and defaults to no org, which resolves as free — a band of
|
|
249
|
+
* none, and therefore exactly the operator-backstop behaviour that predates
|
|
250
|
+
* plan bands. Passing it is what makes a plan's own band bind.
|
|
251
|
+
*
|
|
252
|
+
* ## Refusal is legitimate here, unlike the transactional email carve-out
|
|
253
|
+
*
|
|
254
|
+
* A campaign send is refusable at its band and transactional mail is not,
|
|
255
|
+
* because a blocked password reset locks somebody out of their own account.
|
|
256
|
+
* Nothing assist does is that. It is help, not a person's data and not their
|
|
257
|
+
* access: a refused question means the answer is not given, and a refused
|
|
258
|
+
* build means the screen is built by hand in a besigner that still works. So
|
|
259
|
+
* assist refuses at the band with no carve-out.
|
|
260
|
+
*
|
|
261
|
+
* What is never refused is what costs nothing. A docs-deflected answer and a
|
|
262
|
+
* cache hit spend no tokens and take NO RESERVATION AT ALL — they return
|
|
263
|
+
* before this function is reached — so a workspace at its band keeps getting
|
|
264
|
+
* every answer the docs index can give it. That is not a carve-out inside
|
|
265
|
+
* this gate; it is the reason those paths are ahead of it.
|
|
266
|
+
*
|
|
267
|
+
* ## The band is sold past by default (AGL-2653)
|
|
268
|
+
*
|
|
269
|
+
* Refusing at the band is legitimate; it is no longer the default. A plan
|
|
270
|
+
* with an `extraAssistCreditsUsdPer1k` keeps reserving past its band and
|
|
271
|
+
* `report-usage` bills the excess at that rate, unless the org's own
|
|
272
|
+
* `assistOverage.hardCap` asks for the wall — `assistBandRefuses` is the one
|
|
273
|
+
* place that rule lives. The ceiling below is composed from that answer, and
|
|
274
|
+
* `refusedBy: 'band'` is how a refusal the switch caused is told apart from
|
|
275
|
+
* one the operator's figure caused.
|
|
276
|
+
*
|
|
277
|
+
* ## The Free taste is metered twice (AGL-2925)
|
|
278
|
+
*
|
|
279
|
+
* A Free workspace's band is a wall, and a wall per workspace is not a
|
|
280
|
+
* bound per person. So when `org` resolves to the Free plan the SAME
|
|
281
|
+
* transaction also reads the workspace owner's account document and the
|
|
282
|
+
* platform's day of free spend, and refuses on the account's daily request
|
|
283
|
+
* cap, its refusal pause, its monthly allowance and the platform ceiling —
|
|
284
|
+
* see `assist-free-taste.ts` for each. An admitted free reservation counts
|
|
285
|
+
* the request on the account beside the org's own counters, so the release
|
|
286
|
+
* path hands both back together.
|
|
287
|
+
*
|
|
288
|
+
* ## Allotments sit inside the band (AGL-2942)
|
|
289
|
+
*
|
|
290
|
+
* `subject` names the person asking and the site the request named. Once
|
|
291
|
+
* the workspace's own ceilings — the message cap, the band or budget, the
|
|
292
|
+
* overage cap — have admitted the request, the SAME transaction reads the
|
|
293
|
+
* allotments that apply to that person and site and refuses as `allotment`
|
|
294
|
+
* when a hard one is spent. After the workspace's rungs, so a workspace at
|
|
295
|
+
* its band hears about its band and an allotment can never admit what the
|
|
296
|
+
* band refused; before the Free taste's, which are precautions about the
|
|
297
|
+
* account rather than decisions a manager made. Refusing moves no counter,
|
|
298
|
+
* like every refusal above it. A soft allotment at 80% or 100% admits the
|
|
299
|
+
* request and is announced once the transaction has committed.
|
|
300
|
+
*/ export async function reserveAssistMessage(firestore, orgId, entitled, now = new Date(), org = null, subject = null) {
|
|
301
|
+
var _reservation_allotment;
|
|
302
|
+
const reservation = await reserveInTransaction(firestore, orgId, entitled, now, org, subject);
|
|
303
|
+
if ((_reservation_allotment = reservation.allotment) == null ? void 0 : _reservation_allotment.alerts.length) {
|
|
304
|
+
announceAllotmentAlerts(firestore, orgId, org, reservation);
|
|
305
|
+
}
|
|
306
|
+
return reservation;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* A soft allotment's crossing, told through the alert pipeline — off the
|
|
310
|
+
* reservation's await path and never failing it: the request was admitted,
|
|
311
|
+
* and a notification is not a reason to take that back. Loaded when the
|
|
312
|
+
* first crossing arrives, so the modules that write notifications and send
|
|
313
|
+
* mail are not part of every metered request.
|
|
314
|
+
*/ function announceAllotmentAlerts(firestore, orgId, org, reservation) {
|
|
315
|
+
var _ref;
|
|
316
|
+
var _reservation_allotment;
|
|
317
|
+
const alerts = (_ref = (_reservation_allotment = reservation.allotment) == null ? void 0 : _reservation_allotment.alerts) != null ? _ref : [];
|
|
318
|
+
void import("./ai-allotment-alerts.js").then(({ announceAiAllotmentAlerts })=>announceAiAllotmentAlerts(firestore, {
|
|
319
|
+
orgId,
|
|
320
|
+
orgSlug: typeof (org == null ? void 0 : org.slug) === 'string' ? String(org.slug) : null,
|
|
321
|
+
month: reservation.monthKey,
|
|
322
|
+
alerts
|
|
323
|
+
})).catch((error)=>console.error('[ai-allotments] alert failed', orgId, error));
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* The charge this turn may have earned (AGL-3011).
|
|
327
|
+
*
|
|
328
|
+
* Off the await path and never able to fail the turn: the tokens are already
|
|
329
|
+
* spent, and making the answer wait on a Stripe round trip — or losing it to
|
|
330
|
+
* one — would turn a billing problem into a product one. Loaded when the
|
|
331
|
+
* first chargeable turn arrives, so the modules that read org billing and
|
|
332
|
+
* call Stripe are not part of every metered request.
|
|
333
|
+
*
|
|
334
|
+
* Returns before loading anything at all while `AI_OVERAGE_INVOICED_FROM`
|
|
335
|
+
* names no month, which is how this ships: AI overage bills through the
|
|
336
|
+
* monthly meter exactly as it does today, and this costs one string compare.
|
|
337
|
+
*
|
|
338
|
+
* A turn whose process ends before this finishes is covered three ways: the
|
|
339
|
+
* next turn tries again, the reconcile sweep finishes a half-made charge,
|
|
340
|
+
* and the gate refuses at the unpaid limit regardless.
|
|
341
|
+
*/ function chargeAccruedOverage(firestore, orgId, month, now) {
|
|
342
|
+
if (!aiOverageBillsByInvoice(month)) return;
|
|
343
|
+
void import("../billing/ai-overage-trigger.js").then(({ chargeAccruedAiOverage })=>chargeAccruedAiOverage(firestore, orgId, month, now)).catch((error)=>console.error('[ai-overage] charge failed', orgId, error));
|
|
344
|
+
}
|
|
345
|
+
async function reserveInTransaction(firestore, orgId, entitled, now, org, subject) {
|
|
346
|
+
const increment = FieldValue.increment;
|
|
347
|
+
const serverTimestamp = FieldValue.serverTimestamp;
|
|
348
|
+
const orgRef = firestore.collection('orgs').doc(orgId);
|
|
349
|
+
const day = assistUsageDay(now);
|
|
350
|
+
const month = assistUsageMonth(now);
|
|
351
|
+
const dailyRef = orgRef.collection('counters').doc('assistMessagesDaily');
|
|
352
|
+
const monthlyRef = orgRef.collection('assistUsage').doc(month);
|
|
353
|
+
const limit = entitled ? assistEntitledMonthlyLimit() : assistFreeDailyLimit();
|
|
354
|
+
const period = entitled ? 'month' : 'day';
|
|
355
|
+
const gateRef = entitled ? monthlyRef : dailyRef;
|
|
356
|
+
const gateField = entitled ? 'messages' : day;
|
|
357
|
+
// The Free taste's attribution, resolved once and carried on every
|
|
358
|
+
// answer below: `null` for any paid plan, and for the paths that never
|
|
359
|
+
// consult it.
|
|
360
|
+
const free = freeAssistAccount(org);
|
|
361
|
+
const accountRef = (free == null ? void 0 : free.accountUid) ? freeAccountUsageRef(firestore, free.accountUid, month) : null;
|
|
362
|
+
// The plan's band first, then whether it refuses at all, then whatever the
|
|
363
|
+
// operator did about it. Resolved OUTSIDE the transaction: it is pure
|
|
364
|
+
// arithmetic over a document the caller already holds, and a transaction
|
|
365
|
+
// that retries must not re-derive a ceiling that could have moved between
|
|
366
|
+
// attempts.
|
|
367
|
+
const budgetUsd = resolveAssistBudgetUsd(org);
|
|
368
|
+
const bandRefuses = assistBandRefuses(org);
|
|
369
|
+
// An uncapped staff comp has no band and no backstop default (AGL-3049).
|
|
370
|
+
const costLimitUsd = assistMonthlyCeilingUsd(budgetUsd, bandRefuses, isUncappedPlanComp(org));
|
|
371
|
+
// The ceiling IS the band when the band refuses and nothing lower undercut
|
|
372
|
+
// it. That is the refusal the surface has to attribute to the org's own
|
|
373
|
+
// switch (or to a plan that sells no overage); a lower operator figure is
|
|
374
|
+
// the operator's decision and keeps the operator's word.
|
|
375
|
+
const ceilingIsBand = bandRefuses && budgetUsd !== null && costLimitUsd === budgetUsd;
|
|
376
|
+
// The org's own ceiling on the overage it buys (AGL-2898). Only a band
|
|
377
|
+
// that is SOLD past has an overage to cap, so a band that refuses leaves
|
|
378
|
+
// no ceiling to consult: past a wall there is nothing to be over.
|
|
379
|
+
const overageCapUsd = bandRefuses ? null : resolveAssistOverageCapUsd(org);
|
|
380
|
+
// AGLYN'S OWN GUARDS ON THE OVERAGE IT EXTENDS (AGL-3011), resolved here
|
|
381
|
+
// for the same reason the ceilings above are: pure arithmetic over a
|
|
382
|
+
// document the caller already holds, and a transaction that retries must
|
|
383
|
+
// not re-derive them.
|
|
384
|
+
//
|
|
385
|
+
// They apply only where there IS overage to guard — a band that is sold
|
|
386
|
+
// past, at a rate — and only from the month the platform bills that
|
|
387
|
+
// overage by invoice. Before that month nothing charges, so nothing is
|
|
388
|
+
// ever paid for, so an unpaid-balance guard would refuse every workspace
|
|
389
|
+
// with no invoice to pay. See `ai-overage-cutover.ts`.
|
|
390
|
+
const guardsOverage = !bandRefuses && budgetUsd !== null && resolveAssistOverageRateUsdPer1k(org) !== null && aiOverageGuardsApply(month);
|
|
391
|
+
return firestore.runTransaction(async (tx)=>{
|
|
392
|
+
var _snapshot_get, _monthlySnapshot_get, _ref, _standingSnapshot_data;
|
|
393
|
+
// Every read before any write — Firestore requires that ordering, and it
|
|
394
|
+
// is also what makes check-and-increment a single atomic step.
|
|
395
|
+
const snapshot = await tx.get(gateRef);
|
|
396
|
+
// The spend ceiling reads the SAME monthly document the entitled gate
|
|
397
|
+
// already read, so an entitled reservation costs no extra read at all
|
|
398
|
+
// and a free one costs a second read only when a ceiling is configured.
|
|
399
|
+
const monthlySnapshot = entitled ? snapshot : costLimitUsd === null ? null : await tx.get(monthlyRef);
|
|
400
|
+
// The taste's two extra reads, only for a Free workspace: the owner's
|
|
401
|
+
// account month (when the org names an owner) and the platform's day.
|
|
402
|
+
// Inside the transaction with everything else, so the rungs they feed
|
|
403
|
+
// are decided against the same snapshot the counters move under.
|
|
404
|
+
// The workspace's overage standing (AGL-3011): one document, read only
|
|
405
|
+
// where the guards apply, beside the reads the gate already makes. The
|
|
406
|
+
// allotment gate reads a plugin document in this transaction the same
|
|
407
|
+
// way, and for the same reason — a guard decided against a snapshot the
|
|
408
|
+
// transaction did not take is a guard a concurrent burst walks past.
|
|
409
|
+
const standingSnapshot = guardsOverage ? await tx.get(orgRef.collection(AI_BILLING_SUBCOLLECTION).doc(AI_BILLING_STANDING_DOC)) : null;
|
|
410
|
+
const accountSnapshot = accountRef ? await tx.get(accountRef) : null;
|
|
411
|
+
const platformSnapshot = free ? await tx.get(platformFreeSpendRef(firestore, day)) : null;
|
|
412
|
+
const used = Number((_snapshot_get = snapshot.get(gateField)) != null ? _snapshot_get : 0);
|
|
413
|
+
const costUsd = monthlySnapshot ? Number((_monthlySnapshot_get = monthlySnapshot.get('estCostUsd')) != null ? _monthlySnapshot_get : 0) : null;
|
|
414
|
+
if (!(used < limit)) {
|
|
415
|
+
recordAssistRefusal(firestore, orgId, month, 'messages');
|
|
416
|
+
return {
|
|
417
|
+
allowed: false,
|
|
418
|
+
refusedBy: 'messages',
|
|
419
|
+
period,
|
|
420
|
+
dayKey: day,
|
|
421
|
+
monthKey: month,
|
|
422
|
+
used,
|
|
423
|
+
limit,
|
|
424
|
+
remaining: 0,
|
|
425
|
+
costUsd,
|
|
426
|
+
costLimitUsd,
|
|
427
|
+
budgetUsd,
|
|
428
|
+
free
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
// The dollar ceiling, checked AFTER the message cap so the cheaper and
|
|
432
|
+
// more explicable refusal wins when both apply. Refusing here leaves both
|
|
433
|
+
// counters untouched, exactly like the message refusal above: the point
|
|
434
|
+
// of a spend ceiling is that the org above it spends nothing more.
|
|
435
|
+
if (costLimitUsd !== null && costUsd !== null && !(costUsd < costLimitUsd)) {
|
|
436
|
+
recordAssistRefusal(firestore, orgId, month, ceilingIsBand ? 'band' : 'budget');
|
|
437
|
+
return {
|
|
438
|
+
allowed: false,
|
|
439
|
+
refusedBy: ceilingIsBand ? 'band' : 'budget',
|
|
440
|
+
period,
|
|
441
|
+
dayKey: day,
|
|
442
|
+
monthKey: month,
|
|
443
|
+
used,
|
|
444
|
+
limit,
|
|
445
|
+
remaining: Math.max(0, limit - used),
|
|
446
|
+
costUsd,
|
|
447
|
+
costLimitUsd,
|
|
448
|
+
budgetUsd,
|
|
449
|
+
free
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
// The org's ceiling on its OVERAGE (AGL-2898), checked after the band
|
|
453
|
+
// because it only exists on a band that is sold past. Same shape as the
|
|
454
|
+
// refusals above — inside the transaction, against the spend the
|
|
455
|
+
// transaction read, moving no counter — so a burst of concurrent
|
|
456
|
+
// requests at the ceiling cannot each read "under" and all proceed.
|
|
457
|
+
// `assistOverageCapReached` prices the month's overage the way the
|
|
458
|
+
// invoice will, so the figure that stops here is the figure that would
|
|
459
|
+
// have been billed.
|
|
460
|
+
if (overageCapUsd !== null && costUsd !== null && assistOverageCapReached(org, costUsd)) {
|
|
461
|
+
recordAssistRefusal(firestore, orgId, month, 'cap');
|
|
462
|
+
return {
|
|
463
|
+
allowed: false,
|
|
464
|
+
refusedBy: 'cap',
|
|
465
|
+
// Whose ceiling, for the doors (AGL-3011). This one is the
|
|
466
|
+
// workspace's own, and it keeps the sentence and the 402 it has had
|
|
467
|
+
// since AGL-2898 — the four below are Aglyn's and have their own.
|
|
468
|
+
capReason: 'customer',
|
|
469
|
+
period,
|
|
470
|
+
dayKey: day,
|
|
471
|
+
monthKey: month,
|
|
472
|
+
used,
|
|
473
|
+
limit,
|
|
474
|
+
remaining: Math.max(0, limit - used),
|
|
475
|
+
costUsd,
|
|
476
|
+
costLimitUsd,
|
|
477
|
+
budgetUsd,
|
|
478
|
+
free
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
// AGLYN'S OWN OVERAGE GUARDS (AGL-3011), after the workspace's own
|
|
482
|
+
// ceiling so a workspace that set a limit is told about ITS limit.
|
|
483
|
+
//
|
|
484
|
+
// Four refusals, all `refusedBy: 'cap'` with a `capReason`: no card on
|
|
485
|
+
// file, accrual paused, this month's ceiling reached, and the unpaid
|
|
486
|
+
// balance at its limit. The last is the one that makes the bound a
|
|
487
|
+
// bound — it compares what the month accrued against what it PAID, so
|
|
488
|
+
// overage stops at the unpaid limit whether or not any charge ever ran.
|
|
489
|
+
//
|
|
490
|
+
// Inside the transaction, against the figures the transaction read,
|
|
491
|
+
// moving no counter: a burst of concurrent requests at the limit cannot
|
|
492
|
+
// each read "under" and all proceed.
|
|
493
|
+
const overageGuard = guardsOverage && costUsd !== null && budgetUsd !== null && costUsd >= budgetUsd ? aiOverageRefusal({
|
|
494
|
+
// Priced the way the invoice prices it, so the figure that
|
|
495
|
+
// stops here is the figure that would have been charged.
|
|
496
|
+
overageUsd: assistMonthOverage(org, costUsd).overageMonthlyUsd,
|
|
497
|
+
paidUsd: readAiOverageMonthLedger((_ref = monthlySnapshot == null ? void 0 : monthlySnapshot.data()) != null ? _ref : null).paidUsd,
|
|
498
|
+
standing: readAiOverageStanding((standingSnapshot == null ? void 0 : standingSnapshot.exists) ? (_standingSnapshot_data = standingSnapshot.data()) != null ? _standingSnapshot_data : null : null),
|
|
499
|
+
now
|
|
500
|
+
}) : null;
|
|
501
|
+
if (overageGuard) {
|
|
502
|
+
recordAssistRefusal(firestore, orgId, month, 'cap');
|
|
503
|
+
return {
|
|
504
|
+
allowed: false,
|
|
505
|
+
refusedBy: 'cap',
|
|
506
|
+
capReason: overageGuard.capReason,
|
|
507
|
+
overageLimitUsd: overageGuard.limitUsd,
|
|
508
|
+
overageUnpaidUsd: overageGuard.unpaidUsd,
|
|
509
|
+
period,
|
|
510
|
+
dayKey: day,
|
|
511
|
+
monthKey: month,
|
|
512
|
+
used,
|
|
513
|
+
limit,
|
|
514
|
+
remaining: Math.max(0, limit - used),
|
|
515
|
+
costUsd,
|
|
516
|
+
costLimitUsd,
|
|
517
|
+
budgetUsd,
|
|
518
|
+
free
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
// The allotments that apply to the person asking (AGL-2942): read only
|
|
522
|
+
// now that the workspace's own ceilings admitted the request, so an
|
|
523
|
+
// allotment is decided inside the band and a refusal at the band costs
|
|
524
|
+
// no allotment read. Reads, still — every write waits below.
|
|
525
|
+
const allotment = subject ? await readAiAllotmentGate((ref)=>tx.get(ref), orgRef, subject, month, monthlySnapshot) : null;
|
|
526
|
+
if (allotment == null ? void 0 : allotment.refusal) {
|
|
527
|
+
recordAssistRefusal(firestore, orgId, month, 'allotment');
|
|
528
|
+
return {
|
|
529
|
+
allowed: false,
|
|
530
|
+
refusedBy: 'allotment',
|
|
531
|
+
period,
|
|
532
|
+
dayKey: day,
|
|
533
|
+
monthKey: month,
|
|
534
|
+
used,
|
|
535
|
+
limit,
|
|
536
|
+
remaining: Math.max(0, limit - used),
|
|
537
|
+
costUsd,
|
|
538
|
+
costLimitUsd,
|
|
539
|
+
budgetUsd,
|
|
540
|
+
free,
|
|
541
|
+
allotment
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
// The Free taste's own rungs (AGL-2925), AFTER the workspace's, so a
|
|
545
|
+
// workspace at its own band is told about its own band. Same shape:
|
|
546
|
+
// decided inside the transaction, against what it read, moving nothing.
|
|
547
|
+
const tasteRefusal = free ? freeTasteRefusal(freeTasteReadsFrom(accountSnapshot, platformSnapshot, day)) : null;
|
|
548
|
+
if (tasteRefusal) {
|
|
549
|
+
recordAssistRefusal(firestore, orgId, month, tasteRefusal);
|
|
550
|
+
return {
|
|
551
|
+
allowed: false,
|
|
552
|
+
refusedBy: tasteRefusal,
|
|
553
|
+
period,
|
|
554
|
+
dayKey: day,
|
|
555
|
+
monthKey: month,
|
|
556
|
+
used,
|
|
557
|
+
limit,
|
|
558
|
+
remaining: Math.max(0, limit - used),
|
|
559
|
+
costUsd,
|
|
560
|
+
costLimitUsd,
|
|
561
|
+
budgetUsd,
|
|
562
|
+
free,
|
|
563
|
+
allotment
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
// `set(…, { merge: true })` and never `update()`: the counter document
|
|
567
|
+
// does not exist before an org's first message, and `update()` throws
|
|
568
|
+
// NOT_FOUND on a missing doc where a merging set conjures it.
|
|
569
|
+
tx.set(dailyRef, {
|
|
570
|
+
[day]: increment(1)
|
|
571
|
+
}, {
|
|
572
|
+
merge: true
|
|
573
|
+
});
|
|
574
|
+
tx.set(monthlyRef, {
|
|
575
|
+
month,
|
|
576
|
+
messages: increment(1),
|
|
577
|
+
updatedAt: serverTimestamp()
|
|
578
|
+
}, {
|
|
579
|
+
merge: true
|
|
580
|
+
});
|
|
581
|
+
// The account's request, counted in the same commit as the org's
|
|
582
|
+
// message — one atomic step, or the daily request cap has the same
|
|
583
|
+
// read-then-write hole the message cap was moved here to close.
|
|
584
|
+
if (accountRef) {
|
|
585
|
+
tx.set(accountRef, freeAccountReservationWrite(month, day), {
|
|
586
|
+
merge: true
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
return {
|
|
590
|
+
allowed: true,
|
|
591
|
+
refusedBy: null,
|
|
592
|
+
period,
|
|
593
|
+
dayKey: day,
|
|
594
|
+
monthKey: month,
|
|
595
|
+
used: used + 1,
|
|
596
|
+
limit,
|
|
597
|
+
remaining: Math.max(0, limit - (used + 1)),
|
|
598
|
+
costUsd,
|
|
599
|
+
costLimitUsd,
|
|
600
|
+
budgetUsd,
|
|
601
|
+
free,
|
|
602
|
+
allotment
|
|
603
|
+
};
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* The reservation as a CUSTOMER may see it.
|
|
608
|
+
*
|
|
609
|
+
* `AssistReservation` carries `costUsd`, `costLimitUsd` and `budgetUsd`, and
|
|
610
|
+
* all three are our provider bill at the serving model's list rates. Handing
|
|
611
|
+
* the reservation itself to a browser publishes our model costs, and they
|
|
612
|
+
* would move under customers on every model swap. Assist is surfaced in
|
|
613
|
+
* CREDITS, whose meaning is fixed, and this is the one function that crosses
|
|
614
|
+
* that boundary — every route returning quota to a client returns this.
|
|
615
|
+
*
|
|
616
|
+
* `limit` and `remaining` stay MESSAGES, unchanged: the free tier's daily
|
|
617
|
+
* message cap is a real, separately-worded limit that the panel already
|
|
618
|
+
* renders, and folding it into credits would make "10 messages a day"
|
|
619
|
+
* unsayable.
|
|
620
|
+
*
|
|
621
|
+
* The credit view reads against the LOWER of the plan band and the effective
|
|
622
|
+
* ceiling. The band, because it is the quantity the org was sold and the line
|
|
623
|
+
* `report-usage` bills past — an org buying overage (AGL-2653) has no ceiling
|
|
624
|
+
* at all, and reading against `null` would blank its standing at "used 900 of
|
|
625
|
+
* nothing". The ceiling, because an org whose band was undercut by an
|
|
626
|
+
* operator's figure must not be told it has credits left while being refused.
|
|
627
|
+
* `remaining` clamps at zero, so a workspace past its band reads as spent
|
|
628
|
+
* rather than as owed.
|
|
629
|
+
*/ export function publicAssistQuota(reservation) {
|
|
630
|
+
const { budgetUsd, costLimitUsd, costUsd } = reservation;
|
|
631
|
+
const ceilingUsd = budgetUsd === null ? null : costLimitUsd === null ? budgetUsd : Math.min(budgetUsd, costLimitUsd);
|
|
632
|
+
return {
|
|
633
|
+
allowed: reservation.allowed,
|
|
634
|
+
period: reservation.period,
|
|
635
|
+
used: reservation.used,
|
|
636
|
+
limit: reservation.limit,
|
|
637
|
+
remaining: reservation.remaining,
|
|
638
|
+
refusedBy: reservation.refusedBy,
|
|
639
|
+
credits: ceilingUsd === null ? null : publicAssistCredits(costUsd, ceilingUsd)
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Hand a reservation back when the provider was never reached (AGL-2057): an
|
|
644
|
+
* upstream 502 spent no tokens, so it must not spend one of a free
|
|
645
|
+
* workspace's ten messages a day either.
|
|
646
|
+
*
|
|
647
|
+
* Released against the keys the RESERVATION recorded — see
|
|
648
|
+
* `AssistReservation`. Each counter is read first so neither can be driven
|
|
649
|
+
* below zero, even if the same reservation were released twice: a negative
|
|
650
|
+
* counter is extra capacity, and the release path must not become the
|
|
651
|
+
* laundering route the reservation was added to close.
|
|
652
|
+
*/ export async function releaseAssistMessage(firestore, orgId, reservation) {
|
|
653
|
+
var _reservation_free;
|
|
654
|
+
if (!reservation.allowed) return;
|
|
655
|
+
const increment = FieldValue.increment;
|
|
656
|
+
const orgRef = firestore.collection('orgs').doc(orgId);
|
|
657
|
+
const dailyRef = orgRef.collection('counters').doc('assistMessagesDaily');
|
|
658
|
+
const monthlyRef = orgRef.collection('assistUsage').doc(reservation.monthKey);
|
|
659
|
+
// The account's request goes back with the org's message (AGL-2925) —
|
|
660
|
+
// against the same keys, read first for the same reason.
|
|
661
|
+
const accountRef = ((_reservation_free = reservation.free) == null ? void 0 : _reservation_free.accountUid) ? freeAccountUsageRef(firestore, reservation.free.accountUid, reservation.monthKey) : null;
|
|
662
|
+
await firestore.runTransaction(async (tx)=>{
|
|
663
|
+
var _dailySnapshot_get, _monthlySnapshot_get;
|
|
664
|
+
const dailySnapshot = await tx.get(dailyRef);
|
|
665
|
+
const monthlySnapshot = await tx.get(monthlyRef);
|
|
666
|
+
const accountSnapshot = accountRef ? await tx.get(accountRef) : null;
|
|
667
|
+
if (Number((_dailySnapshot_get = dailySnapshot.get(reservation.dayKey)) != null ? _dailySnapshot_get : 0) > 0) {
|
|
668
|
+
tx.set(dailyRef, {
|
|
669
|
+
[reservation.dayKey]: increment(-1)
|
|
670
|
+
}, {
|
|
671
|
+
merge: true
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
if (Number((_monthlySnapshot_get = monthlySnapshot.get('messages')) != null ? _monthlySnapshot_get : 0) > 0) {
|
|
675
|
+
tx.set(monthlyRef, {
|
|
676
|
+
messages: increment(-1)
|
|
677
|
+
}, {
|
|
678
|
+
merge: true
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
if (accountRef && accountSnapshot) {
|
|
682
|
+
var _accountSnapshot_get, _ref, _accountSnapshot_get1;
|
|
683
|
+
var _days_reservation_dayKey;
|
|
684
|
+
const days = (_accountSnapshot_get = accountSnapshot.get('days')) != null ? _accountSnapshot_get : {};
|
|
685
|
+
const today = Number((_ref = (_days_reservation_dayKey = days[reservation.dayKey]) == null ? void 0 : _days_reservation_dayKey.requests) != null ? _ref : 0);
|
|
686
|
+
const month = Number((_accountSnapshot_get1 = accountSnapshot.get('requests')) != null ? _accountSnapshot_get1 : 0);
|
|
687
|
+
if (today > 0 || month > 0) {
|
|
688
|
+
tx.set(accountRef, _extends({}, month > 0 ? {
|
|
689
|
+
requests: increment(-1)
|
|
690
|
+
} : {}, today > 0 ? {
|
|
691
|
+
days: {
|
|
692
|
+
[reservation.dayKey]: {
|
|
693
|
+
requests: increment(-1)
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
} : {}), {
|
|
697
|
+
merge: true
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* READ-ONLY view of where an org stands against its cap.
|
|
705
|
+
*
|
|
706
|
+
* ⚠️ NOT the enforcement path any more (AGL-2057) — `reserveAssistMessage` is.
|
|
707
|
+
* A read that is followed by a separate write is exactly the shape that let
|
|
708
|
+
* concurrent requests and abandoned streams past the cap; this function is
|
|
709
|
+
* kept for reporting and for tests that want the standing without consuming a
|
|
710
|
+
* message. **Anything that decides whether to call the model must reserve.**
|
|
711
|
+
*
|
|
712
|
+
* Free orgs meter per UTC day; entitled orgs carry the monthly runaway guard.
|
|
713
|
+
*/ export async function checkAssistQuota(firestore, orgId, entitled, now = new Date()) {
|
|
714
|
+
var _snapshot_get;
|
|
715
|
+
if (entitled) {
|
|
716
|
+
var _snapshot_get1;
|
|
717
|
+
const limit = assistEntitledMonthlyLimit();
|
|
718
|
+
const month = assistUsageMonth(now);
|
|
719
|
+
const snapshot = await firestore.collection('orgs').doc(orgId).collection('assistUsage').doc(month).get();
|
|
720
|
+
const used = Number((_snapshot_get1 = snapshot.get('messages')) != null ? _snapshot_get1 : 0);
|
|
721
|
+
return {
|
|
722
|
+
allowed: used < limit,
|
|
723
|
+
period: 'month',
|
|
724
|
+
used,
|
|
725
|
+
limit,
|
|
726
|
+
remaining: Math.max(0, limit - used)
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
const limit = assistFreeDailyLimit();
|
|
730
|
+
const day = assistUsageDay(now);
|
|
731
|
+
const snapshot = await firestore.collection('orgs').doc(orgId).collection('counters').doc('assistMessagesDaily').get();
|
|
732
|
+
const used = Number((_snapshot_get = snapshot.get(day)) != null ? _snapshot_get : 0);
|
|
733
|
+
return {
|
|
734
|
+
allowed: used < limit,
|
|
735
|
+
period: 'day',
|
|
736
|
+
used,
|
|
737
|
+
limit,
|
|
738
|
+
remaining: Math.max(0, limit - used)
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* The signal document and the monthly cost rollup — the two writes every
|
|
743
|
+
* assist turn owes regardless of whether its prose is kept. Shared by
|
|
744
|
+
* `recordAssistExchange` and `recordAssistCost` so the meter has exactly one
|
|
745
|
+
* writer and the two entrypoints can never drift into reporting different
|
|
746
|
+
* money for the same tokens.
|
|
747
|
+
*/ function writeSignalAndRollup(firestore, batch, orgRef, signalRef, record, now, /** What the request was for, as the caller's own rollup names it. */ kind) {
|
|
748
|
+
var _record_free, _record_hostId;
|
|
749
|
+
const increment = FieldValue.increment;
|
|
750
|
+
const serverTimestamp = FieldValue.serverTimestamp;
|
|
751
|
+
const estCostUsd = estimateAssistCostUsd(record.usage, record.model);
|
|
752
|
+
// What the same tokens COST US (AGL-3015). Recorded beside the billed
|
|
753
|
+
// figure rather than derived from it later: a month is a sum over models
|
|
754
|
+
// and a markup lives on the model, so once the exchanges are added up the
|
|
755
|
+
// mix is gone and the two can no longer be told apart.
|
|
756
|
+
const providerCostUsd = estimateAssistProviderCostUsd(record.usage, record.model);
|
|
757
|
+
const deflected = record.deflected === true;
|
|
758
|
+
const free = (_record_free = record.free) != null ? _record_free : null;
|
|
759
|
+
// On the Free taste a `refusal` stop draws no credits (AGL-2925): the
|
|
760
|
+
// org's band and the account's allowance stay where they were, and the
|
|
761
|
+
// cost goes to the platform's day instead, where it is still our money.
|
|
762
|
+
// Everywhere else the tokens are metered as they always were.
|
|
763
|
+
const refusedFree = free !== null && record.stopReason === 'refusal';
|
|
764
|
+
// The site's credits for its allotment (AGL-2942), rounded as the person's
|
|
765
|
+
// own `byHost` rounds them, so a site's month equals the sum of its
|
|
766
|
+
// people's months on it. Not zeroed for a declined Free turn, for the same
|
|
767
|
+
// reason the person's month is not: the site did spend it.
|
|
768
|
+
const hostId = String((_record_hostId = record.hostId) != null ? _record_hostId : '').trim();
|
|
769
|
+
const hostCredits = hostId ? assistCreditsFromUsd(estCostUsd) : 0;
|
|
770
|
+
// The analytic half. No prose and NO uid — deliberately, because a signal
|
|
771
|
+
// row that names the asker is just the exchange with the words removed,
|
|
772
|
+
// and would re-create as an access-request obligation exactly what the
|
|
773
|
+
// expiry was meant to retire. What survives answers "which docs gaps, at
|
|
774
|
+
// what cost, rated how", which is the whole of the data loop.
|
|
775
|
+
batch.set(signalRef, _extends({
|
|
776
|
+
route: record.route,
|
|
777
|
+
hostId: record.hostId,
|
|
778
|
+
model: record.model,
|
|
779
|
+
tier: record.tier,
|
|
780
|
+
kind,
|
|
781
|
+
inputTokens: record.usage.inputTokens,
|
|
782
|
+
outputTokens: record.usage.outputTokens,
|
|
783
|
+
cacheReadTokens: record.usage.cacheReadTokens,
|
|
784
|
+
cacheWriteTokens: record.usage.cacheWriteTokens,
|
|
785
|
+
estCostUsd,
|
|
786
|
+
[ASSIST_PROVIDER_COST_FIELD]: providerCostUsd,
|
|
787
|
+
docsPaths: record.docsPaths,
|
|
788
|
+
stopReason: record.stopReason,
|
|
789
|
+
deflected,
|
|
790
|
+
feedback: null
|
|
791
|
+
}, record.editOps && record.editOps > 0 ? {
|
|
792
|
+
editOps: Math.floor(record.editOps)
|
|
793
|
+
} : {}, {
|
|
794
|
+
createdAt: serverTimestamp()
|
|
795
|
+
}));
|
|
796
|
+
// NO message counting here (AGL-2057). Both message counters are moved by
|
|
797
|
+
// `reserveAssistMessage`, BEFORE the provider is called — which is what
|
|
798
|
+
// makes the cap a cap. Counting again here would double every message, and
|
|
799
|
+
// more importantly would restore the belief that this is where the cap
|
|
800
|
+
// advances: it is not, and an exchange that never reaches this function
|
|
801
|
+
// (an abandoned stream) has already been counted.
|
|
802
|
+
batch.set(orgRef.collection('assistUsage').doc(assistUsageMonth(now)), _extends({
|
|
803
|
+
month: assistUsageMonth(now),
|
|
804
|
+
// The free half of the month, counted where the paid half already is
|
|
805
|
+
// (AGL-2486). `messages` counts what the RESERVATION moved — model
|
|
806
|
+
// turns — and a deflected turn takes no reservation because it spends
|
|
807
|
+
// nothing, so without this counter the questions Assist answered for
|
|
808
|
+
// free are invisible and the deflection rate can only be guessed at.
|
|
809
|
+
// Total questions asked is `messages + deflected`; neither field alone
|
|
810
|
+
// is that number, and reading `messages` as it would understate usage
|
|
811
|
+
// by exactly the amount this work was done to create.
|
|
812
|
+
deflected: increment(deflected ? 1 : 0),
|
|
813
|
+
inputTokens: increment(record.usage.inputTokens),
|
|
814
|
+
outputTokens: increment(record.usage.outputTokens),
|
|
815
|
+
cacheReadTokens: increment(record.usage.cacheReadTokens),
|
|
816
|
+
cacheWriteTokens: increment(record.usage.cacheWriteTokens),
|
|
817
|
+
estCostUsd: increment(refusedFree ? 0 : estCostUsd),
|
|
818
|
+
// Our bill for the same turns, credited and refused alike on the same
|
|
819
|
+
// rule as `estCostUsd` above, so the month's two dollar figures always
|
|
820
|
+
// describe the same set of exchanges and a margin taken across them is
|
|
821
|
+
// a margin over one period.
|
|
822
|
+
[ASSIST_PROVIDER_COST_FIELD]: increment(refusedFree ? 0 : providerCostUsd),
|
|
823
|
+
// The refused half of a Free month, kept beside the credited half so
|
|
824
|
+
// the rollup still says what the month cost us in total. Its own field
|
|
825
|
+
// name (AGL-2986): `refusals` on this document is the gate's map of
|
|
826
|
+
// refusal counts by reason (`recordAssistRefusal`), and an increment
|
|
827
|
+
// over a map replaces the map with the operand.
|
|
828
|
+
refusedTurns: increment(refusedFree ? 1 : 0),
|
|
829
|
+
refusedCostUsd: increment(refusedFree ? estCostUsd : 0)
|
|
830
|
+
}, deflected ? {} : {
|
|
831
|
+
[AI_USAGE_MONTH_KINDS_FIELD]: {
|
|
832
|
+
[kind]: {
|
|
833
|
+
requests: increment(1),
|
|
834
|
+
estCostUsd: increment(estCostUsd),
|
|
835
|
+
[ASSIST_PROVIDER_COST_FIELD]: increment(providerCostUsd),
|
|
836
|
+
[AI_USAGE_TOKENS_FIELD]: aiTokenIncrements(record.usage)
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}, hostCredits > 0 ? {
|
|
840
|
+
[AI_HOST_CREDITS_FIELD]: {
|
|
841
|
+
[hostId]: increment(hostCredits)
|
|
842
|
+
}
|
|
843
|
+
} : {}, {
|
|
844
|
+
updatedAt: serverTimestamp()
|
|
845
|
+
}), {
|
|
846
|
+
merge: true
|
|
847
|
+
});
|
|
848
|
+
if (free) {
|
|
849
|
+
const day = assistUsageDay(now);
|
|
850
|
+
const writes = freeTasteMeterWrites({
|
|
851
|
+
estCostUsd,
|
|
852
|
+
refused: refusedFree,
|
|
853
|
+
day,
|
|
854
|
+
month: assistUsageMonth(now)
|
|
855
|
+
});
|
|
856
|
+
batch.set(platformFreeSpendRef(firestore, day), writes.platform, {
|
|
857
|
+
merge: true
|
|
858
|
+
});
|
|
859
|
+
if (free.accountUid) {
|
|
860
|
+
batch.set(freeAccountUsageRef(firestore, free.accountUid, assistUsageMonth(now)), writes.account, {
|
|
861
|
+
merge: true
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* After a Free turn's batch commits: the ceiling's announcements, which
|
|
868
|
+
* need the figure the batch just moved and must never fail the turn.
|
|
869
|
+
*/ async function announceFreeTurn(firestore, record, now) {
|
|
870
|
+
if (!record.free) return;
|
|
871
|
+
await announcePlatformFreeSpend(firestore, assistUsageDay(now)).catch((error)=>console.error('[ai-free-spend] announcement failed', error));
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Meter one assist turn that keeps NO verbatim record (AGL-2073) — the
|
|
875
|
+
* besigner copy assistant at `/api/ai/assist`.
|
|
876
|
+
*
|
|
877
|
+
* Writes the signal and folds tokens/cost into the monthly rollup, and writes
|
|
878
|
+
* nothing to `assistExchanges`. Same reason the console route splits the two:
|
|
879
|
+
* the loop's corpus was never the words. Here there is no loop to feed and no
|
|
880
|
+
* thumbs to collect, so the words are simply not taken.
|
|
881
|
+
*
|
|
882
|
+
* Like `recordAssistExchange` it counts NO message — the reservation did that
|
|
883
|
+
* before the tokens were spent. Callers should not let a metering failure fail
|
|
884
|
+
* the request: the tokens are already spent either way, and refusing the
|
|
885
|
+
* answer the customer paid for would make an accounting problem a product one.
|
|
886
|
+
*/ export async function recordAssistCost(firestore, orgId, record, now = new Date()) {
|
|
887
|
+
var _record_kind;
|
|
888
|
+
const orgRef = firestore.collection('orgs').doc(orgId);
|
|
889
|
+
const signalRef = orgRef.collection('assistSignals').doc();
|
|
890
|
+
const batch = firestore.batch();
|
|
891
|
+
const kind = (_record_kind = record.kind) != null ? _record_kind : aiUsageKindFromRoute(record.route);
|
|
892
|
+
writeSignalAndRollup(firestore, batch, orgRef, signalRef, record, now, kind);
|
|
893
|
+
// The person's month, on the SAME batch as the org's (AGL-2928), so the
|
|
894
|
+
// two rollups commit together or not at all.
|
|
895
|
+
recordUserAiUsage(batch, orgRef, {
|
|
896
|
+
uid: record.uid,
|
|
897
|
+
month: assistUsageMonth(now),
|
|
898
|
+
estCostUsd: estimateAssistCostUsd(record.usage, record.model),
|
|
899
|
+
hostId: record.hostId,
|
|
900
|
+
kind,
|
|
901
|
+
usage: record.usage
|
|
902
|
+
});
|
|
903
|
+
await batch.commit();
|
|
904
|
+
chargeAccruedOverage(firestore, orgId, assistUsageMonth(now), now);
|
|
905
|
+
await announceFreeTurn(firestore, record, now);
|
|
906
|
+
return signalRef.id;
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* The data loop + meters, one batch: writes the two halves of the exchange
|
|
910
|
+
* and folds tokens/cost into the monthly usage doc. It does NOT count the
|
|
911
|
+
* message — `reserveAssistMessage` already did, before the tokens were spent.
|
|
912
|
+
* Returns the shared id (the feedback route addresses it later). Callers
|
|
913
|
+
* `await` this — an exchange that fails to record should surface in logs,
|
|
914
|
+
* but the batch is one round trip so it does not add meaningful latency.
|
|
915
|
+
*
|
|
916
|
+
* The two halves share one id ON PURPOSE. It is what lets the feedback route
|
|
917
|
+
* keep its single-id signature, and it is what makes an exchange and its
|
|
918
|
+
* signal joinable for as long as both exist — without storing a second
|
|
919
|
+
* pointer that could rot.
|
|
920
|
+
*/ export async function recordAssistExchange(firestore, orgId, record, now = new Date()) {
|
|
921
|
+
var _record_kind;
|
|
922
|
+
const serverTimestamp = FieldValue.serverTimestamp;
|
|
923
|
+
const orgRef = firestore.collection('orgs').doc(orgId);
|
|
924
|
+
const exchangeRef = orgRef.collection('assistExchanges').doc();
|
|
925
|
+
const signalRef = orgRef.collection('assistSignals').doc(exchangeRef.id);
|
|
926
|
+
const batch = firestore.batch();
|
|
927
|
+
// The personal half. Everything a person typed, everything we said back,
|
|
928
|
+
// and who asked — and nothing else. Expires.
|
|
929
|
+
batch.set(exchangeRef, {
|
|
930
|
+
uid: record.uid,
|
|
931
|
+
question: record.question,
|
|
932
|
+
answer: record.answer,
|
|
933
|
+
hostId: record.hostId,
|
|
934
|
+
createdAt: serverTimestamp(),
|
|
935
|
+
expiresAt: assistExchangeExpiry(now)
|
|
936
|
+
});
|
|
937
|
+
// A chat turn is an `assist` request whatever console route it was asked
|
|
938
|
+
// from — on the signal, the org's month and the asker's month alike.
|
|
939
|
+
const kind = (_record_kind = record.kind) != null ? _record_kind : 'assist';
|
|
940
|
+
// The analytic half plus the meters — the same writer `recordAssistCost`
|
|
941
|
+
// uses, so the two assist entrypoints can never report different money for
|
|
942
|
+
// the same tokens.
|
|
943
|
+
writeSignalAndRollup(firestore, batch, orgRef, signalRef, record, now, kind);
|
|
944
|
+
// And the asker's month, on the same batch (AGL-2928).
|
|
945
|
+
recordUserAiUsage(batch, orgRef, {
|
|
946
|
+
uid: record.uid,
|
|
947
|
+
month: assistUsageMonth(now),
|
|
948
|
+
estCostUsd: estimateAssistCostUsd(record.usage, record.model),
|
|
949
|
+
hostId: record.hostId,
|
|
950
|
+
kind,
|
|
951
|
+
usage: record.usage
|
|
952
|
+
});
|
|
953
|
+
await batch.commit();
|
|
954
|
+
chargeAccruedOverage(firestore, orgId, assistUsageMonth(now), now);
|
|
955
|
+
await announceFreeTurn(firestore, record, now);
|
|
956
|
+
return exchangeRef.id;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Record explicit thumbs feedback on an exchange. Only the exchange's own
|
|
960
|
+
* org path is addressable, and only the two literal values are accepted —
|
|
961
|
+
* the route validates membership before calling this.
|
|
962
|
+
*
|
|
963
|
+
* The rating lands on the SIGNAL document, not the exchange (AGL-1972). A
|
|
964
|
+
* thumbs-down is the single most valuable row in the data loop and it is not
|
|
965
|
+
* personal content, so it must not be reaped along with the prose that
|
|
966
|
+
* earned it. Existence is checked on the signal too: it is the document
|
|
967
|
+
* being written, and after the exchange expires it is the only one left.
|
|
968
|
+
*/ export async function recordAssistFeedback(firestore, orgId, exchangeId, feedback) {
|
|
969
|
+
const ref = firestore.collection('orgs').doc(orgId).collection('assistSignals').doc(exchangeId);
|
|
970
|
+
const snapshot = await ref.get();
|
|
971
|
+
if (!snapshot.exists) return false;
|
|
972
|
+
await ref.update({
|
|
973
|
+
feedback
|
|
974
|
+
});
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
//# sourceMappingURL=assist-usage.js.map
|