@aglyn/plugins-ai 1.0.0-beta.229 → 1.0.0-beta.230
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +17 -17
- package/src/lib/activity/ai-activity-actions.js +7 -1
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-automation-zones.d.ts +38 -0
- package/src/lib/components/ai-automation-zones.js +5 -1
- package/src/lib/components/ai-automation-zones.js.map +1 -1
- package/src/lib/components/ai-brief-dialog.component.d.ts +20 -2
- package/src/lib/components/ai-brief-dialog.component.js +87 -8
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
- package/src/lib/components/ai-campaign-create.component.d.ts +54 -0
- package/src/lib/components/ai-campaign-create.component.js +270 -0
- package/src/lib/components/ai-campaign-create.component.js.map +1 -0
- package/src/lib/components/ai-describe-automation.component.d.ts +8 -3
- package/src/lib/components/ai-describe-automation.component.js +15 -6
- package/src/lib/components/ai-describe-automation.component.js.map +1 -1
- package/src/lib/components/ai-describe-button.component.d.ts +20 -8
- package/src/lib/components/ai-describe-button.component.js +19 -36
- package/src/lib/components/ai-describe-button.component.js.map +1 -1
- package/src/lib/components/ai-describe-email.component.d.ts +31 -0
- package/src/lib/components/ai-describe-email.component.js +22 -0
- package/src/lib/components/ai-describe-email.component.js.map +1 -0
- package/src/lib/components/ai-describe-org-automation.component.d.ts +36 -0
- package/src/lib/components/ai-describe-org-automation.component.js +238 -0
- package/src/lib/components/ai-describe-org-automation.component.js.map +1 -0
- package/src/lib/components/ai-experiment-cards.component.d.ts +9 -1
- package/src/lib/components/ai-experiment-cards.component.js +104 -18
- package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
- package/src/lib/components/ai-explain-automation.component.js +1 -5
- package/src/lib/components/ai-explain-automation.component.js.map +1 -1
- package/src/lib/components/ai-funnel-zones.component.d.ts +61 -0
- package/src/lib/components/ai-funnel-zones.component.js +178 -0
- package/src/lib/components/ai-funnel-zones.component.js.map +1 -0
- package/src/lib/components/ai-insight-card.component.d.ts +42 -0
- package/src/lib/components/ai-insight-card.component.js +137 -0
- package/src/lib/components/ai-insight-card.component.js.map +1 -0
- package/src/lib/components/ai-insight-dialog.component.d.ts +6 -0
- package/src/lib/components/ai-insight-dialog.component.js +9 -3
- package/src/lib/components/ai-insight-dialog.component.js.map +1 -1
- package/src/lib/components/ai-job-plan.component.d.ts +7 -2
- package/src/lib/components/ai-job-plan.component.js +35 -5
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +17 -1
- package/src/lib/components/ai-job-requests.js +39 -3
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-logic-zones.d.ts +64 -0
- package/src/lib/components/ai-logic-zones.js +18 -0
- package/src/lib/components/ai-logic-zones.js.map +1 -0
- package/src/lib/components/ai-logic.component.d.ts +77 -0
- package/src/lib/components/ai-logic.component.js +553 -0
- package/src/lib/components/ai-logic.component.js.map +1 -0
- package/src/lib/components/ai-marketing-insight.component.d.ts +30 -0
- package/src/lib/components/ai-marketing-insight.component.js +80 -0
- package/src/lib/components/ai-marketing-insight.component.js.map +1 -0
- package/src/lib/components/ai-media-create.component.d.ts +55 -0
- package/src/lib/components/ai-media-create.component.js +433 -0
- package/src/lib/components/ai-media-create.component.js.map +1 -0
- package/src/lib/components/ai-overlay-cards.component.d.ts +83 -0
- package/src/lib/components/ai-overlay-cards.component.js +505 -0
- package/src/lib/components/ai-overlay-cards.component.js.map +1 -0
- package/src/lib/components/ai-product-zones.d.ts +5 -0
- package/src/lib/components/ai-product-zones.js +1 -1
- package/src/lib/components/ai-product-zones.js.map +1 -1
- package/src/lib/components/ai-products-create-button.component.d.ts +42 -0
- package/src/lib/components/ai-products-create-button.component.js +67 -0
- package/src/lib/components/ai-products-create-button.component.js.map +1 -0
- package/src/lib/components/ai-products-hub-card.component.js +100 -81
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
- package/src/lib/components/ai-revise-automation.component.d.ts +16 -0
- package/src/lib/components/ai-revise-automation.component.js +207 -0
- package/src/lib/components/ai-revise-automation.component.js.map +1 -0
- package/src/lib/components/ai-site-build-page.component.js +140 -16
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.d.ts +53 -0
- package/src/lib/components/ai-upsell-dialog.component.js +177 -0
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -0
- package/src/lib/components/assist-build-card.component.d.ts +42 -0
- package/src/lib/components/assist-build-card.component.js +183 -0
- package/src/lib/components/assist-build-card.component.js.map +1 -0
- package/src/lib/components/assist-edit-canvas.d.ts +2 -0
- package/src/lib/components/assist-edit-canvas.js +56 -1
- package/src/lib/components/assist-edit-canvas.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +48 -3
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +51 -2
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/use-ai-job-run.d.ts +3 -14
- package/src/lib/components/use-ai-job-run.js +0 -50
- package/src/lib/components/use-ai-job-run.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.d.ts +58 -0
- package/src/lib/jobs/ai-build-capabilities.js +256 -0
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -0
- package/src/lib/jobs/ai-build-unit-outcome.d.ts +52 -0
- package/src/lib/jobs/ai-build-unit-outcome.js +138 -0
- package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -0
- package/src/lib/jobs/ai-job-build-step.d.ts +144 -0
- package/src/lib/jobs/ai-job-build-step.js +657 -0
- package/src/lib/jobs/ai-job-build-step.js.map +1 -0
- package/src/lib/jobs/ai-job-draft-ids.js +9 -1
- package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.d.ts +14 -4
- package/src/lib/jobs/ai-job-drafts.js +25 -4
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
- package/src/lib/jobs/ai-job-logic-step.js +395 -0
- package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
- package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
- package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
- package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
- package/src/lib/jobs/ai-job-page-step.js +6 -6
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +26 -1
- package/src/lib/jobs/ai-job-plan-step.js +79 -11
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +15 -1
- package/src/lib/jobs/ai-job-site-step.js +200 -58
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +22 -1
- package/src/lib/jobs/ai-job-text-step.js +12 -0
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-job-workflow-step.d.ts +54 -4
- package/src/lib/jobs/ai-job-workflow-step.js +318 -13
- package/src/lib/jobs/ai-job-workflow-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +80 -2
- package/src/lib/jobs/ai-jobs.js +377 -13
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-logic-records.d.ts +40 -0
- package/src/lib/jobs/ai-logic-records.js +55 -0
- package/src/lib/jobs/ai-logic-records.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +7 -0
- package/src/lib/jobs/ai-site-publish.js +9 -0
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/ai-workflow-records.d.ts +4 -0
- package/src/lib/jobs/ai-workflow-records.js +40 -1
- package/src/lib/jobs/ai-workflow-records.js.map +1 -1
- package/src/lib/model/ai-automation-draft.d.ts +18 -0
- package/src/lib/model/ai-automation-draft.js +86 -0
- package/src/lib/model/ai-automation-draft.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +201 -0
- package/src/lib/model/ai-build-job.js +471 -0
- package/src/lib/model/ai-build-job.js.map +1 -0
- package/src/lib/model/ai-build-plan.d.ts +61 -0
- package/src/lib/model/ai-build-plan.js +154 -9
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-build-progress.d.ts +56 -0
- package/src/lib/model/ai-build-progress.js +128 -0
- package/src/lib/model/ai-build-progress.js.map +1 -0
- package/src/lib/model/ai-insight.d.ts +20 -10
- package/src/lib/model/ai-insight.js +72 -9
- package/src/lib/model/ai-insight.js.map +1 -1
- package/src/lib/model/ai-job-activity.js +3 -1
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +80 -2
- package/src/lib/model/ai-jobs.types.js +3 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-logic-job.d.ts +108 -0
- package/src/lib/model/ai-logic-job.js +327 -0
- package/src/lib/model/ai-logic-job.js.map +1 -0
- package/src/lib/model/ai-media-credits.d.ts +52 -0
- package/src/lib/model/ai-media-credits.js +61 -0
- package/src/lib/model/ai-media-credits.js.map +1 -0
- package/src/lib/model/ai-overlay-copy.d.ts +114 -0
- package/src/lib/model/ai-overlay-copy.js +175 -0
- package/src/lib/model/ai-overlay-copy.js.map +1 -0
- package/src/lib/model/ai-site-build-progress.d.ts +20 -3
- package/src/lib/model/ai-site-build-progress.js +170 -10
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-svg.d.ts +69 -0
- package/src/lib/model/ai-svg.js +265 -0
- package/src/lib/model/ai-svg.js.map +1 -0
- package/src/lib/model/ai-usage-by-user.d.ts +3 -2
- package/src/lib/model/ai-usage-by-user.js.map +1 -1
- package/src/lib/model/ai-workflow-job.d.ts +92 -4
- package/src/lib/model/ai-workflow-job.js +124 -7
- package/src/lib/model/ai-workflow-job.js.map +1 -1
- package/src/lib/model/assist-build.d.ts +58 -0
- package/src/lib/model/assist-build.js +52 -0
- package/src/lib/model/assist-build.js.map +1 -0
- package/src/lib/model/assist-edit.d.ts +48 -3
- package/src/lib/model/assist-edit.js +48 -4
- package/src/lib/model/assist-edit.js.map +1 -1
- package/src/lib/plugin-config.js +2 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +240 -11
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/catalog.d.ts +81 -4
- package/src/lib/providers/catalog.js +80 -9
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/image-contract.d.ts +116 -0
- package/src/lib/providers/image-contract.js +74 -0
- package/src/lib/providers/image-contract.js.map +1 -0
- package/src/lib/providers/model-choice.js +11 -0
- package/src/lib/providers/model-choice.js.map +1 -1
- package/src/lib/providers/routing.js +18 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/providers/vertex-image.d.ts +121 -0
- package/src/lib/providers/vertex-image.js +312 -0
- package/src/lib/providers/vertex-image.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +19 -0
- package/src/lib/runtime/ai-doctrine-validators.js +89 -0
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +11 -5
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.js +4 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-eval.d.ts +15 -1
- package/src/lib/runtime/ai-eval.js +52 -1
- package/src/lib/runtime/ai-eval.js.map +1 -1
- package/src/lib/runtime/experiment-variant-copy.d.ts +34 -0
- package/src/lib/runtime/experiment-variant-copy.js +102 -0
- package/src/lib/runtime/experiment-variant-copy.js.map +1 -0
- package/src/lib/server/ai-experiment-versions.d.ts +51 -0
- package/src/lib/server/ai-experiment-versions.js +270 -0
- package/src/lib/server/ai-experiment-versions.js.map +1 -0
- package/src/lib/server/ai-jobs-resume.js +74 -4
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-media-image.d.ts +66 -0
- package/src/lib/server/ai-media-image.js +521 -0
- package/src/lib/server/ai-media-image.js.map +1 -0
- package/src/lib/server/ai-media-svg.d.ts +91 -0
- package/src/lib/server/ai-media-svg.js +186 -0
- package/src/lib/server/ai-media-svg.js.map +1 -0
- package/src/lib/server/assist-build.d.ts +54 -0
- package/src/lib/server/assist-build.js +121 -0
- package/src/lib/server/assist-build.js.map +1 -0
- package/src/lib/server/assist-chat.js +108 -12
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit.js +213 -3
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/server/assist-view-context.js +242 -4
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +26 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tools/ai-logic-tool.d.ts +27 -0
- package/src/lib/tools/ai-logic-tool.js +207 -0
- package/src/lib/tools/ai-logic-tool.js.map +1 -0
- package/src/lib/tools/ai-overlay-tool.d.ts +35 -0
- package/src/lib/tools/ai-overlay-tool.js +107 -0
- package/src/lib/tools/ai-overlay-tool.js.map +1 -0
- package/src/lib/tools/ai-workflow-tool.d.ts +11 -0
- package/src/lib/tools/ai-workflow-tool.js +31 -0
- package/src/lib/tools/ai-workflow-tool.js.map +1 -1
- package/src/lib/usage/assist-job-refund.d.ts +28 -1
- package/src/lib/usage/assist-job-refund.js +44 -9
- package/src/lib/usage/assist-job-refund.js.map +1 -1
- package/src/lib/usage/assist-usage.d.ts +5 -0
- package/src/lib/usage/assist-usage.js +2 -0
- package/src/lib/usage/assist-usage.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-workflow-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ACTION_MAX_CONDITIONS, ACTION_MAX_STEPS } from '@aglyn/aglyn/app-utils/site-interactions'\nimport {\n CONTACT_LIFECYCLE_STAGES,\n CONTACT_TAG_MAX_LENGTH,\n CRM_TASK_MAX_DUE_DAYS,\n} from '@aglyn/aglyn/app-utils/crm'\nimport { HOST_EVENT_PAYLOAD_KEYS, type HostEventType } from '@aglyn/aglyn/app-utils/host-events'\nimport { isHostPluginEnabled } from '@aglyn/aglyn/plugin-manager/enabled-plugins'\nimport { filterEnabledPluginsByReleaseFlags } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport {\n aiAutomationDraft,\n aiAutomationDraftNote,\n type AiAutomationRecords,\n} from '../model/ai-automation-draft'\nimport {\n AI_AUTOMATION_TIMED_OUT_FIELD,\n AI_AUTOMATION_WAIT_MINUTES,\n aiStepLabel,\n} from '../model/ai-automation-format'\nimport {\n aiActionOutline,\n aiActionRecordKinds,\n aiRunOutline,\n aiWorkflowExplanationText,\n aiWorkflowOutline,\n type AiRunRecord,\n} from '../model/ai-automation-outline'\nimport type { AiJobOutput } from '../model/ai-jobs.types'\nimport {\n AI_AUTOMATION_NEED_LABELS,\n AI_AUTOMATION_RESOURCE,\n AI_AUTOMATION_STEP_NEEDS,\n AI_AUTOMATION_STEP_TYPES,\n AI_AUTOMATION_TRIGGER_NEEDS,\n AI_AUTOMATION_TRIGGERS,\n AI_AUTOMATION_UNSUPPORTED_COPY,\n AI_WORKFLOW_GONE_COPY,\n AI_WORKFLOW_NO_DRAFT_COPY,\n AI_WORKFLOW_NO_EXPLANATION_COPY,\n AI_WORKFLOW_NO_SITE_COPY,\n AI_WORKFLOW_RUN_GONE_COPY,\n AI_WORKFLOW_RUN_NOT_FAILED_COPY,\n AI_WORKFLOW_SAVE_FAILURE_COPY,\n AI_WORKFLOW_UNAVAILABLE_COPY,\n aiAutomationCapabilities,\n aiAutomationTriggerLabel,\n parseAiWorkflowJobInputs,\n type AiAutomationCapabilities,\n type AiAutomationStepType,\n} from '../model/ai-workflow-job'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { AI_ROUTING_TABLE, aiModelForStep } from '../providers/routing'\nimport {\n runValidatedGeneration,\n type AiCustomGenerationInput,\n type AiGenerationCheck,\n} from '../runtime/ai-doctrine'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport {\n AI_AUTOMATION_TOOL_NAME,\n AI_WORKFLOW_EXPLANATION_TOOL_NAME,\n aiAutomationTool,\n aiWorkflowExplanationTool,\n readAiAutomationAnswer,\n readAiWorkflowExplanation,\n type AiAutomationAnswer,\n type AiWorkflowExplanation,\n} from '../tools/ai-workflow-tool'\nimport { registerAiJobAdmission, type AiJobAdmission, type AiJobAdmissionRefusal } from './ai-job-admission'\nimport { aiJobStepBudget } from './ai-job-budget'\nimport { aiJobDraftId } from './ai-job-draft-ids'\nimport { aiDoctrineReview, aiGenerationSpent, aiLimitReview, aiUnspentOutcome } from './ai-job-generation'\nimport {\n aiPluginDraftAdmissionRefusal,\n aiPluginDraftOwner,\n aiPluginDraftUnavailable,\n aiPluginDraftWriter,\n type AiPluginDraftWriterLookup,\n} from './ai-job-plugin-drafts'\nimport { AI_JOB_BRIEF_MAX_CHARS, type AiJobStepOutcome, type AiJobStepRunner } from './ai-job-text-step'\nimport { registerAiJobStep } from './ai-jobs'\nimport {\n readAiAutomationRecords,\n readAiWorkflowFunctions,\n readAiWorkflowRun,\n readAiWorkflowTarget,\n} from './ai-workflow-records'\n\n/**\n * The `workflow` step (AGL-2919): an automation drafted from a description,\n * or a saved automation explained.\n *\n * ## Drafting\n *\n * The model is shown the platform's automation vocabulary — every trigger with\n * the fields it carries, every step with the fields it takes — in a cached\n * block, and in the user turn what this workspace can run, the site's forms\n * and datasets by name, and the description. It answers through\n * `submit_automation`, and the answer is held to the vocabulary and to what\n * the workspace can run before anything is written.\n *\n * A record the description names — a list, a campaign, a workflow, a webhook,\n * a dataset, a form, a deal stage — is answered in the description's WORDS,\n * and looked up among the site's records in code, after the answer\n * (`model/ai-automation-draft.ts`). The model is never shown the site's lists,\n * campaigns, workflows, webhooks or pipelines. Words that name no record, or\n * more than one, are kept as a placeholder the person fills in.\n *\n * The automation is written through the workflows plugin's draft writer —\n * that plugin's stored shape, validator, role, plan and cap — keyed by the\n * job's id, and it is written OFF. A run cut off after the write finds its\n * draft and spends nothing.\n *\n * ## Explaining\n *\n * The model is shown an outline of the saved automation, and for a failed run\n * what the run history recorded about it (`model/ai-automation-outline.ts`):\n * never the stored documents, never an email address, never a run's event\n * payload. It answers through `submit_explanation`, which becomes a `text`\n * output. Nothing is changed.\n */\n\n/** The longest an explanation or a draft's generation may take reading the site first. */\nexport const AI_WORKFLOW_RECORDS_READ_MS = 4_000\n\n/**\n * The step's time (AGL-3035): its answer and its re-ask at the routing\n * table's `job.workflow` ceiling on the tier the step is served from. It sends\n * no site inventory block, so it makes no lookup; its own reads — the records\n * a draft is matched against, or the automation and run an explanation\n * reads — are the declared `AI_WORKFLOW_RECORDS_READ_MS`.\n */\nexport const AI_JOB_WORKFLOW_STEP_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.workflow'],\n maxTokens: AI_ROUTING_TABLE['job.workflow'].maxTokens,\n lookups: 0,\n ownReadsMs: AI_WORKFLOW_RECORDS_READ_MS,\n})\n\n/** The least time one workflow step needs before it starts. */\nexport const AI_JOB_WORKFLOW_STEP_MINIMUM_MS = AI_JOB_WORKFLOW_STEP_BUDGET.minimumMs\n\n/** The routing table's answer for `job.workflow`. */\nexport function aiJobWorkflowModel(): string {\n return aiModelForStep('job.workflow')\n}\n\n/** How many forms and datasets the user turn lists, and how many fields a form. */\nexport const AI_WORKFLOW_FORMS_LISTED = 40\nexport const AI_WORKFLOW_FORM_FIELDS_LISTED = 20\nexport const AI_WORKFLOW_DATASETS_LISTED = 40\n\n// ── The vocabulary, for the model ─────────────────────────────────────────\n\nconst STEP_USES: Readonly<Record<AiAutomationStepType, string>> = {\n sendEmail: 'emails the person the event is about. Fields: subject, body (plain text), toField',\n notifyAdmins: 'notifies the site’s admins in the console. Fields: text (what the admins read)',\n enrollList: 'adds the person to an email list. Fields: reference (the list)',\n assignCampaign: 'files the person under a campaign. Fields: reference (the campaign)',\n runWorkflow: 'runs one of the site’s workflows. Fields: reference (the workflow)',\n datasetAppend: 'saves the event as a new record in a dataset. Fields: reference (the dataset)',\n updateDataset: 'updates the event’s record in a dataset. Fields: reference (the dataset)',\n webhookPost: 'sends the event to one of the site’s outbound webhooks. Fields: reference (the webhook)',\n siteAlert: 'shows the visitor who caused the event a short message. Fields: text (the message), severity',\n wait: 'waits before the next step. Fields: minutes',\n waitForEvent: 'waits until something else happens to the same person, or gives up. Fields: event, minutes',\n exitFlow: 'ends the automation here; with a when it is a branch. Fields: none',\n setContactStage: 'sets the person’s lifecycle stage. Fields: stage',\n addContactTag: 'tags the person. Fields: text (the tag)',\n assignContactOwner: 'gives the person an owner. Fields: text (the owner)',\n createCrmTask: 'creates a follow-up task. Fields: text (the task), taskKind, priority, dueInDays',\n logCrmActivity: 'logs what happened on the person’s record. Fields: activityKind, direction (a call’s or an email’s), text (what happened)',\n}\n\nfunction triggerLine(event: HostEventType): string {\n const fields =\n event === 'formSubmission'\n ? 'formName (the form’s name, as the request lists it), path, and every field the form collects, by its field name'\n : (HOST_EVENT_PAYLOAD_KEYS[event] ?? []).join(', ') || 'none'\n const need = AI_AUTOMATION_TRIGGER_NEEDS[event]\n return `- ${event} (${aiAutomationTriggerLabel(event)}). Fields: ${fields}.${\n need ? ` Needs ${AI_AUTOMATION_NEED_LABELS[need]}.` : ''\n }`\n}\n\nfunction stepLine(type: AiAutomationStepType): string {\n const need = AI_AUTOMATION_STEP_NEEDS[type]\n return `- ${type} (${aiStepLabel(type)}) ${STEP_USES[type]}.${\n need ? ` Needs ${AI_AUTOMATION_NEED_LABELS[need]}.` : ''\n }`\n}\n\n/**\n * The drafting instructions, byte-identical on every request so they cache.\n * Built from the platform's own trigger and step catalogs, so the vocabulary\n * the model is shown is the vocabulary the answer is held to.\n */\nexport const AI_JOB_WORKFLOW_DRAFT_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n `You turn a description into one automation for the Actions page of a website builder: something that happens on the site (the trigger), the conditions it must meet, and the steps that run, in order. Answer by calling ${AI_AUTOMATION_TOOL_NAME} exactly once. A reply in prose cannot be used.`,\n '',\n 'A step is written as when it runs and what it does: a when beside an action that carries its type and only that type’s fields. Use only these triggers and steps; each step lists the fields its action takes, and it carries only those.',\n '',\n 'Triggers, with the fields their conditions can read:',\n ...AI_AUTOMATION_TRIGGERS.map(triggerLine),\n '',\n 'Steps:',\n ...AI_AUTOMATION_STEP_TYPES.map(stepLine),\n '',\n 'Rules:',\n '- A step that names a list, campaign, workflow, webhook or dataset writes it as reference, in the description’s own words, such as \"newsletter\". The platform finds the site’s record by those words. Never write an id for one.',\n '- A form is named by the id or the name the request lists: formId on contactCreated, formName on formSubmission. A form the description names that the request does not list is written in the description’s words.',\n '- A deal stage in a condition on stageId or previousStageId is written as the stage’s name.',\n `- A lifecycle stage is one of: ${CONTACT_LIFECYCLE_STAGES.join(', ')}. A new lead is the stage lead.`,\n `- The trigger holds at most ${ACTION_MAX_CONDITIONS} conditions; combinator is and unless the description means any of them. A step's when holds one condition of its own at most, over the same fields. After waitForEvent, when on the field \"${AI_AUTOMATION_TIMED_OUT_FIELD}\" with notEmpty means the wait ran out of time.`,\n `- At most ${ACTION_MAX_STEPS} steps. minutes are whole minutes, at most ${AI_AUTOMATION_WAIT_MINUTES.max}; dueInDays is from 0 to ${CRM_TASK_MAX_DUE_DAYS}; addContactTag’s text is at most ${CONTACT_TAG_MAX_LENGTH} characters.`,\n '- assignContactOwner’s text is \"round robin\", or the teammate’s email address when the description gives one. A teammate named without an address goes in notes.',\n '- Write an email’s subject and body, and any text a person reads, in the site’s voice and the language of the description. Where the description lacks a fact such as a phone number, an address or a price, write a short description of it in square brackets instead of inventing it.',\n '- A trigger or a step the request says this workspace cannot use is never used. When the description needs one, or needs something no trigger or step here does, answer with unsupported set to the reason, no steps, and trigger event formSubmission with no conditions. unsupported is empty on every automation that is built.',\n '- notes holds what the person must decide that the automation cannot hold, in at most three short sentences; empty when there is nothing.',\n '- The automation is drafted switched off, and a person reviews it and switches it on. Never ask to turn it on or to run it.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n/** The explaining instructions, byte-identical on every request so they cache. */\nexport const AI_JOB_WORKFLOW_EXPLAIN_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n `You explain an automation on a website builder to the person who owns the site, in plain words for someone who does not write code. You are shown the automation as it is set up — what starts it, its conditions and its steps in order — and, when you are asked why a run failed, what the run history recorded about that run. Answer by calling ${AI_WORKFLOW_EXPLANATION_TOOL_NAME} exactly once.`,\n '',\n '- summary: in one or two sentences, what the automation does; or, for a failed run, the most likely reason it failed.',\n '- points: what happens, step by step, in the order it happens; or, for a failed run, what the run did and where it went wrong. One sentence each.',\n '- suggestions: what the person can check or change — a list, campaign or workflow the site no longer has, a condition that can never match, a placeholder nobody has filled in, a step the plan does not include. For a failed run, how to fix it. Empty when there is nothing to suggest.',\n '',\n 'Rules:',\n '- Explain only what you are shown. Never guess at settings, records or history you were not given, and never say you changed anything: you change nothing.',\n '- Name triggers and steps the way you are shown them, not by internal names.',\n '- A value in square brackets is a placeholder nobody has filled in yet.',\n '- Personal details were removed from what you are shown, and are written as [email address] or a named teammate. Never ask for them.',\n '- Write plain text, with no markdown and no HTML.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n// ── The user turns ────────────────────────────────────────────────────────\n\nfunction yesNo(value: boolean): string {\n return value ? 'yes' : 'no'\n}\n\n/** What a draft is asked from: the workspace's reach, the site's forms and datasets, and the brief. */\nexport function aiJobWorkflowDraftPrompt(input: {\n brief: string\n capabilities: AiAutomationCapabilities\n records: Pick<AiAutomationRecords, 'forms' | 'datasets'>\n}): string {\n const { crm, webhooks, bookings } = input.capabilities\n const forms = input.records.forms.slice(0, AI_WORKFLOW_FORMS_LISTED)\n const datasets = input.records.datasets.slice(0, AI_WORKFLOW_DATASETS_LISTED)\n return [\n `This workspace can use: the CRM — ${yesNo(crm)}; webhooks — ${yesNo(webhooks)}; bookings — ${yesNo(bookings)}.`,\n 'Forms on this site (id · name · fields):',\n ...(forms.length\n ? forms.map(\n (form) =>\n `- ${form.id} · ${form.name} · ${form.fields.slice(0, AI_WORKFLOW_FORM_FIELDS_LISTED).join(', ') || 'no fields'}`,\n )\n : ['- none']),\n 'Datasets on this site (name):',\n ...(datasets.length ? datasets.map((dataset) => `- ${dataset.name}`) : ['- none']),\n `Brief: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`,\n ].join('\\n')\n}\n\n/** What an explanation is asked from: the mode, the outlines, and the member's question. */\nexport function aiJobWorkflowExplainPrompt(input: {\n brief: string\n mode: 'explain' | 'diagnose'\n outline: string\n run: string | null\n}): string {\n return [\n input.mode === 'diagnose'\n ? 'Asked: why a run of this automation failed.'\n : 'Asked: what this automation does.',\n input.outline,\n ...(input.run ? [input.run] : []),\n `Question: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`,\n ].join('\\n\\n')\n}\n\n/** The routing row's thinking and effort, as a generation input spells them. */\nfunction routedEffort(): Pick<AiCustomGenerationInput<unknown>, 'thinking' | 'effort'> {\n const row = AI_ROUTING_TABLE['job.workflow']\n return {\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n }\n}\n\n/** The draft generation as the doctrine's loop runs it; the eval harness records one through this same call. */\nexport function aiJobWorkflowDraftGeneration(request: {\n brief: string\n capabilities: AiAutomationCapabilities\n records: Pick<AiAutomationRecords, 'forms' | 'datasets'>\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<AiAutomationAnswer> {\n const check: AiGenerationCheck<AiAutomationAnswer> = (answer) =>\n readAiAutomationAnswer(answer, request.capabilities)\n return {\n step: 'job.workflow',\n model: request.model,\n instructions: AI_JOB_WORKFLOW_DRAFT_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobWorkflowDraftPrompt(request) }],\n tool: aiAutomationTool(),\n maxTokens: AI_JOB_WORKFLOW_STEP_BUDGET.maxTokens(request.model),\n ...routedEffort(),\n ...(request.signal ? { signal: request.signal } : {}),\n check,\n }\n}\n\n/** The explanation generation as the doctrine's loop runs it. */\nexport function aiJobWorkflowExplainGeneration(request: {\n brief: string\n mode: 'explain' | 'diagnose'\n outline: string\n run: string | null\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<AiWorkflowExplanation> {\n return {\n step: 'job.workflow',\n model: request.model,\n instructions: AI_JOB_WORKFLOW_EXPLAIN_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobWorkflowExplainPrompt(request) }],\n tool: aiWorkflowExplanationTool(),\n maxTokens: AI_JOB_WORKFLOW_STEP_BUDGET.maxTokens(request.model),\n ...routedEffort(),\n ...(request.signal ? { signal: request.signal } : {}),\n check: readAiWorkflowExplanation,\n }\n}\n\n// ── The runner ────────────────────────────────────────────────────────────\n\nexport interface AiJobWorkflowStepDeps {\n /** How the automation draft writer is found; the core's registry otherwise. */\n writerFor?: AiPluginDraftWriterLookup\n readRecords?: typeof readAiAutomationRecords\n readTarget?: typeof readAiWorkflowTarget\n readRun?: typeof readAiWorkflowRun\n readFunctions?: typeof readAiWorkflowFunctions\n}\n\n/** A job label: the automation's name in quotes, cut to a line. */\nfunction quotedName(name: string): string {\n const clean = name.replace(/\\s+/g, ' ').trim()\n return `“${clean.length > 60 ? `${clean.slice(0, 60)}…` : clean}”`\n}\n\nexport function createAiJobWorkflowStep(deps: AiJobWorkflowStepDeps = {}): AiJobStepRunner {\n const writerFor = deps.writerFor ?? aiPluginDraftWriter\n const readRecords = deps.readRecords ?? readAiAutomationRecords\n const readTarget = deps.readTarget ?? readAiWorkflowTarget\n const readRun = deps.readRun ?? readAiWorkflowRun\n const readFunctions = deps.readFunctions ?? readAiWorkflowFunctions\n return async ({ job, now, signal, firestore, org, modelFor }): Promise<AiJobStepOutcome> => {\n // The switch's answer for this job, else the routing table's (AGL-2942).\n const model = modelFor?.('job.workflow') ?? aiJobWorkflowModel()\n const unspent = (failure: string): AiJobStepOutcome => ({ ...aiUnspentOutcome(model), failure })\n const inputs = parseAiWorkflowJobInputs(job.inputs)\n if (typeof inputs === 'string') return unspent(inputs)\n const hostId = job.hostId\n if (!hostId) return unspent(AI_WORKFLOW_NO_SITE_COPY)\n // The door checks the caller's membership of the org the job is metered\n // against; the site is checked against that org here, before anything\n // about it is read into a prompt.\n const host = await firestore.collection('hosts').doc(hostId).get()\n if (!host.exists || host.get('orgId') !== job.orgId) return unspent(AI_WORKFLOW_NO_SITE_COPY)\n const subdomain = host.get('subdomain')\n const hostSubdomain = typeof subdomain === 'string' && subdomain ? subdomain : null\n const orgData = (org ?? (await firestore.collection('orgs').doc(job.orgId).get()).data() ?? null) as Record<\n string,\n unknown\n > | null\n const capabilities = aiAutomationCapabilities(orgData)\n\n if (inputs.mode === 'draft') {\n const writer = writerFor(AI_AUTOMATION_RESOURCE)\n if (!writer) return unspent(AI_WORKFLOW_UNAVAILABLE_COPY)\n const place = { hostId, hostSubdomain }\n // What an earlier run of this same job already wrote, under the id the job recorded.\n const draftId = aiJobDraftId(job, 'workflow')\n const written = await writer.read({ hostId, id: draftId })\n if (written) {\n return aiUnspentOutcome(model, {\n outputs: [draftOutput(written.id, written.name, place, 'It is off until you switch it on.')],\n })\n }\n const context = { orgId: job.orgId, hostId, uid: job.createdBy, org: orgData, now }\n const refusal = await writer.refusal(context)\n if (refusal) {\n return refusal.status === 403\n ? aiUnspentOutcome(model, { review: aiLimitReview(refusal.error) })\n : unspent(refusal.error)\n }\n const records = await readRecords(firestore, { orgId: job.orgId, hostId, crm: capabilities.crm })\n const generation = await runValidatedGeneration(\n 'workflow',\n aiJobWorkflowDraftGeneration({\n brief: job.brief,\n capabilities,\n records,\n model,\n ...(signal ? { signal } : {}),\n }),\n )\n const spent = { ...aiGenerationSpent(generation), ...(generation.effort ? { effort: generation.effort } : {}) }\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, review: aiDoctrineReview(generation) }\n const answer = generation.value\n if (answer.unsupported) return { ...spent, failure: AI_AUTOMATION_UNSUPPORTED_COPY[answer.unsupported] }\n if (!answer.steps.length) return { ...spent, failure: AI_WORKFLOW_NO_DRAFT_COPY }\n const draft = aiAutomationDraft(answer, records)\n const write = await writer.write({\n ...context,\n id: draftId,\n name: draft.action.name,\n content: { action: draft.action },\n })\n if (write.ok === false) {\n return write.status === 403\n ? { ...spent, review: aiLimitReview(write.error) }\n : { ...spent, failure: AI_WORKFLOW_SAVE_FAILURE_COPY }\n }\n return {\n ...spent,\n outputs: [draftOutput(write.id, write.name, place, aiAutomationDraftNote(draft, answer.notes))],\n }\n }\n\n const target = await readTarget({ hostId, type: inputs.targetType, id: inputs.targetId })\n if (!target) return unspent(AI_WORKFLOW_GONE_COPY)\n let run: AiRunRecord | null = null\n if (inputs.mode === 'diagnose') {\n const read = await readRun(firestore, { hostId, targetId: inputs.targetId, runId: inputs.runId })\n if (read.ok === false) {\n return unspent(read.reason === 'gone' ? AI_WORKFLOW_RUN_GONE_COPY : AI_WORKFLOW_RUN_NOT_FAILED_COPY)\n }\n run = read.run\n }\n // Only the kinds of record the automation's steps name are read, to say\n // whether each still exists.\n const outline =\n target.type === 'action'\n ? aiActionOutline(\n target.action,\n await readRecords(firestore, {\n orgId: job.orgId,\n hostId,\n crm: false,\n only: aiActionRecordKinds(target.action),\n }),\n )\n : aiWorkflowOutline(target.workflow, await readFunctions(firestore, hostId))\n const generation = await runValidatedGeneration(\n 'workflow',\n aiJobWorkflowExplainGeneration({\n brief: job.brief,\n mode: inputs.mode,\n outline,\n run: run ? aiRunOutline(run) : null,\n model,\n ...(signal ? { signal } : {}),\n }),\n )\n const spent = { ...aiGenerationSpent(generation), ...(generation.effort ? { effort: generation.effort } : {}) }\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, failure: AI_WORKFLOW_NO_EXPLANATION_COPY }\n const output: AiJobOutput = {\n resource: 'text',\n // An explanation has no document of its own; the id names what it is\n // within the job, as a text output's `draft` does.\n id: inputs.mode === 'diagnose' ? 'diagnosis' : 'explanation',\n hostId,\n hostSubdomain,\n label:\n inputs.mode === 'diagnose'\n ? `Why a run of ${quotedName(target.name)} failed`\n : `How ${quotedName(target.name)} works`,\n text: aiWorkflowExplanationText(generation.value, inputs.mode),\n }\n return { ...spent, outputs: [output] }\n }\n}\n\nfunction draftOutput(\n id: string,\n name: string,\n place: { hostId: string; hostSubdomain: string | null },\n note: string,\n): AiJobOutput {\n return {\n resource: 'workflow',\n id,\n versionId: null,\n hostId: place.hostId,\n hostSubdomain: place.hostSubdomain,\n label: name,\n note,\n }\n}\n\nexport const runAiJobWorkflowStep = createAiJobWorkflowStep()\n\n// ── Admission ─────────────────────────────────────────────────────────────\n\n/**\n * Whether the plugin that writes automations runs on this site: switched on,\n * and past its release flag. The owner is whichever plugin registered the\n * automation writer (AGL-3080); none registered is the same refusal.\n */\nasync function workflowsPluginRefusal(\n context: Parameters<AiJobAdmission>[0],\n hostId: string,\n): Promise<AiJobAdmissionRefusal | null> {\n const owner = aiPluginDraftOwner(AI_AUTOMATION_RESOURCE)\n if (!owner) return { status: 403, error: aiPluginDraftUnavailable('Automation') }\n const host = (await context.firestore.collection('hosts').doc(hostId).get()).data() ?? null\n const org = context.org as { enabledPlugins?: string[] } | null\n const released = await filterEnabledPluginsByReleaseFlags([owner], {\n orgId: context.orgId,\n authorization: null,\n })\n return released.includes(owner) && isHostPluginEnabled(org, host, owner)\n ? null\n : { status: 403, error: aiPluginDraftUnavailable('Automation') }\n}\n\nexport interface AiWorkflowJobAdmissionDeps {\n readTarget?: typeof readAiWorkflowTarget\n readRun?: typeof readAiWorkflowRun\n writerFor?: AiPluginDraftWriterLookup\n}\n\n/**\n * A workflow job is admitted for a site of its org with the Automation plugin\n * on. A draft also needs the draft writer and the member's room and role in\n * its own words; an explanation needs the automation it names to exist, and\n * a run's explanation a failed run of it.\n */\nexport function createAiWorkflowJobAdmission(deps: AiWorkflowJobAdmissionDeps = {}): AiJobAdmission {\n const readTarget = deps.readTarget ?? readAiWorkflowTarget\n const readRun = deps.readRun ?? readAiWorkflowRun\n return async (context) => {\n const inputs = parseAiWorkflowJobInputs(context.inputs)\n if (typeof inputs === 'string') return { status: 400, error: inputs }\n if (inputs.mode === 'draft') {\n return aiPluginDraftAdmissionRefusal(context, {\n kind: 'workflow',\n drafts: [{ resource: AI_AUTOMATION_RESOURCE, label: 'Automation' }],\n ...(deps.writerFor ? { writerFor: deps.writerFor } : {}),\n })\n }\n const hostId = context.hostId\n if (!hostId) return { status: 400, error: 'Open the site the automation is on before asking about it' }\n const owner = await resolveOrgIdForHost(hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n const plugin = await workflowsPluginRefusal(context, hostId)\n if (plugin) return plugin\n const target = await readTarget({ hostId, type: inputs.targetType, id: inputs.targetId })\n if (!target) return { status: 404, error: AI_WORKFLOW_GONE_COPY }\n if (inputs.mode === 'diagnose') {\n const run = await readRun(context.firestore, { hostId, targetId: inputs.targetId, runId: inputs.runId })\n if (run.ok === false) {\n return run.reason === 'gone'\n ? { status: 404, error: AI_WORKFLOW_RUN_GONE_COPY }\n : { status: 400, error: AI_WORKFLOW_RUN_NOT_FAILED_COPY }\n }\n }\n return null\n }\n}\n\nexport const aiWorkflowJobAdmission = createAiWorkflowJobAdmission()\n\n/** Registers the workflow step and the check a workflow job passes before it is created or resumed. */\nexport function registerAiWorkflowJob(): void {\n registerAiJobStep('workflow', runAiJobWorkflowStep, { minimumMs: AI_JOB_WORKFLOW_STEP_MINIMUM_MS })\n registerAiJobAdmission('workflow', aiWorkflowJobAdmission)\n}\n"],"names":["ACTION_MAX_CONDITIONS","ACTION_MAX_STEPS","CONTACT_LIFECYCLE_STAGES","CONTACT_TAG_MAX_LENGTH","CRM_TASK_MAX_DUE_DAYS","HOST_EVENT_PAYLOAD_KEYS","isHostPluginEnabled","filterEnabledPluginsByReleaseFlags","resolveOrgIdForHost","aiAutomationDraft","aiAutomationDraftNote","AI_AUTOMATION_TIMED_OUT_FIELD","AI_AUTOMATION_WAIT_MINUTES","aiStepLabel","aiActionOutline","aiActionRecordKinds","aiRunOutline","aiWorkflowExplanationText","aiWorkflowOutline","AI_AUTOMATION_NEED_LABELS","AI_AUTOMATION_RESOURCE","AI_AUTOMATION_STEP_NEEDS","AI_AUTOMATION_STEP_TYPES","AI_AUTOMATION_TRIGGER_NEEDS","AI_AUTOMATION_TRIGGERS","AI_AUTOMATION_UNSUPPORTED_COPY","AI_WORKFLOW_GONE_COPY","AI_WORKFLOW_NO_DRAFT_COPY","AI_WORKFLOW_NO_EXPLANATION_COPY","AI_WORKFLOW_NO_SITE_COPY","AI_WORKFLOW_RUN_GONE_COPY","AI_WORKFLOW_RUN_NOT_FAILED_COPY","AI_WORKFLOW_SAVE_FAILURE_COPY","AI_WORKFLOW_UNAVAILABLE_COPY","aiAutomationCapabilities","aiAutomationTriggerLabel","parseAiWorkflowJobInputs","AI_STEP_TIERS","AI_ROUTING_TABLE","aiModelForStep","runValidatedGeneration","AI_AUTOMATION_TOOL_NAME","AI_WORKFLOW_EXPLANATION_TOOL_NAME","aiAutomationTool","aiWorkflowExplanationTool","readAiAutomationAnswer","readAiWorkflowExplanation","registerAiJobAdmission","aiJobStepBudget","aiJobDraftId","aiDoctrineReview","aiGenerationSpent","aiLimitReview","aiUnspentOutcome","aiPluginDraftAdmissionRefusal","aiPluginDraftOwner","aiPluginDraftUnavailable","aiPluginDraftWriter","AI_JOB_BRIEF_MAX_CHARS","registerAiJobStep","readAiAutomationRecords","readAiWorkflowFunctions","readAiWorkflowRun","readAiWorkflowTarget","AI_WORKFLOW_RECORDS_READ_MS","AI_JOB_WORKFLOW_STEP_BUDGET","tier","maxTokens","lookups","ownReadsMs","AI_JOB_WORKFLOW_STEP_MINIMUM_MS","minimumMs","aiJobWorkflowModel","AI_WORKFLOW_FORMS_LISTED","AI_WORKFLOW_FORM_FIELDS_LISTED","AI_WORKFLOW_DATASETS_LISTED","STEP_USES","sendEmail","notifyAdmins","enrollList","assignCampaign","runWorkflow","datasetAppend","updateDataset","webhookPost","siteAlert","wait","waitForEvent","exitFlow","setContactStage","addContactTag","assignContactOwner","createCrmTask","logCrmActivity","triggerLine","event","fields","join","need","stepLine","type","AI_JOB_WORKFLOW_DRAFT_INSTRUCTIONS","text","map","max","cacheBreakpoint","AI_JOB_WORKFLOW_EXPLAIN_INSTRUCTIONS","yesNo","value","aiJobWorkflowDraftPrompt","input","crm","webhooks","bookings","capabilities","forms","records","slice","datasets","length","form","id","name","dataset","brief","aiJobWorkflowExplainPrompt","mode","outline","run","routedEffort","row","thinking","effort","aiJobWorkflowDraftGeneration","request","check","answer","step","model","instructions","messages","role","content","tool","signal","aiJobWorkflowExplainGeneration","quotedName","clean","replace","trim","createAiJobWorkflowStep","deps","writerFor","readRecords","readTarget","readRun","readFunctions","job","now","firestore","org","modelFor","unspent","failure","inputs","hostId","host","collection","doc","get","exists","orgId","subdomain","hostSubdomain","orgData","data","writer","place","draftId","written","read","outputs","draftOutput","context","uid","createdBy","refusal","status","review","error","generation","spent","refused","unsupported","steps","draft","write","action","ok","notes","target","targetType","targetId","runId","reason","only","workflow","output","resource","label","note","versionId","runAiJobWorkflowStep","workflowsPluginRefusal","owner","released","authorization","includes","createAiWorkflowJobAdmission","kind","drafts","plugin","aiWorkflowJobAdmission","registerAiWorkflowJob"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-workflow-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ACTION_MAX_CONDITIONS, ACTION_MAX_STEPS } from '@aglyn/aglyn/app-utils/site-interactions'\nimport {\n CONTACT_LIFECYCLE_STAGES,\n CONTACT_TAG_MAX_LENGTH,\n CRM_TASK_MAX_DUE_DAYS,\n} from '@aglyn/aglyn/app-utils/crm'\nimport { HOST_EVENT_PAYLOAD_KEYS, type HostEventType } from '@aglyn/aglyn/app-utils/host-events'\nimport { checkEntitlement } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { isHostPluginEnabled, isPluginEnabled } from '@aglyn/aglyn/plugin-manager/enabled-plugins'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { filterEnabledPluginsByReleaseFlags } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport {\n aiAutomationDraft,\n aiAutomationDraftNote,\n aiAutomationRevisionChanges,\n aiAutomationRevisionNote,\n type AiAutomationDraft,\n type AiAutomationRecords,\n} from '../model/ai-automation-draft'\nimport {\n AI_AUTOMATION_TIMED_OUT_FIELD,\n AI_AUTOMATION_WAIT_MINUTES,\n aiStepLabel,\n} from '../model/ai-automation-format'\nimport {\n aiActionOutline,\n aiActionRecordKinds,\n aiRunOutline,\n aiWorkflowExplanationText,\n aiWorkflowOutline,\n type AiRunRecord,\n} from '../model/ai-automation-outline'\nimport type { AiJobOutput } from '../model/ai-jobs.types'\nimport {\n AI_AUTOMATION_NEED_LABELS,\n AI_AUTOMATION_RESOURCE,\n AI_AUTOMATION_STEP_NEEDS,\n AI_AUTOMATION_STEP_TYPES,\n AI_AUTOMATION_TRIGGER_NEEDS,\n AI_AUTOMATION_TRIGGERS,\n AI_AUTOMATION_UNSUPPORTED_COPY,\n AI_WORKFLOW_GONE_COPY,\n AI_WORKFLOW_NO_DRAFT_COPY,\n AI_WORKFLOW_NO_EXPLANATION_COPY,\n AI_WORKFLOW_NO_SITE_COPY,\n AI_WORKFLOW_RUN_GONE_COPY,\n AI_WORKFLOW_RUN_NOT_FAILED_COPY,\n AI_WORKFLOW_SAVE_FAILURE_COPY,\n AI_WORKFLOW_REVISE_BLOCKER_COPY,\n AI_WORKFLOW_REVISE_WORKFLOW_COPY,\n AI_WORKFLOW_UNAVAILABLE_COPY,\n AI_ORG_AUTOMATION_PLAN_COPY,\n AI_ORG_AUTOMATION_RESOURCE,\n AI_ORG_AUTOMATION_UNAVAILABLE_COPY,\n aiActionReviseBlocker,\n aiAutomationCapabilities,\n aiAutomationTriggerLabel,\n parseAiWorkflowJobInputs,\n type AiAutomationCapabilities,\n type AiAutomationStepType,\n type AiOrgAutomationVocabulary,\n} from '../model/ai-workflow-job'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { AI_ROUTING_TABLE, aiModelForStep } from '../providers/routing'\nimport {\n runValidatedGeneration,\n type AiCustomGenerationInput,\n type AiGenerationCheck,\n} from '../runtime/ai-doctrine'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport {\n AI_AUTOMATION_TOOL_NAME,\n AI_WORKFLOW_EXPLANATION_TOOL_NAME,\n aiAutomationTool,\n aiWorkflowExplanationTool,\n holdAiAutomationAnswerToVocabulary,\n readAiAutomationAnswer,\n readAiWorkflowExplanation,\n type AiAutomationAnswer,\n type AiWorkflowExplanation,\n} from '../tools/ai-workflow-tool'\nimport { registerAiJobAdmission, type AiJobAdmission, type AiJobAdmissionRefusal } from './ai-job-admission'\nimport { aiJobStepBudget } from './ai-job-budget'\nimport { aiJobDraftId } from './ai-job-draft-ids'\nimport { aiDoctrineReview, aiGenerationSpent, aiLimitReview, aiUnspentOutcome } from './ai-job-generation'\nimport {\n aiPluginDraftAdmissionRefusal,\n aiPluginDraftOwner,\n aiPluginDraftUnavailable,\n aiPluginDraftWriter,\n type AiPluginDraftWriterLookup,\n} from './ai-job-plugin-drafts'\nimport { AI_JOB_BRIEF_MAX_CHARS, type AiJobStepOutcome, type AiJobStepRunner } from './ai-job-text-step'\nimport { registerAiJobStep } from './ai-jobs'\nimport {\n readAiAutomationRecords,\n readAiOrgAutomationRecords,\n readAiWorkflowFunctions,\n readAiWorkflowRun,\n readAiWorkflowTarget,\n} from './ai-workflow-records'\n\n/**\n * The `workflow` step (AGL-2919): an automation drafted from a description,\n * or a saved automation explained.\n *\n * ## Drafting\n *\n * The model is shown the platform's automation vocabulary — every trigger with\n * the fields it carries, every step with the fields it takes — in a cached\n * block, and in the user turn what this workspace can run, the site's forms\n * and datasets by name, and the description. It answers through\n * `submit_automation`, and the answer is held to the vocabulary and to what\n * the workspace can run before anything is written.\n *\n * A record the description names — a list, a campaign, a workflow, a webhook,\n * a dataset, a form, a deal stage — is answered in the description's WORDS,\n * and looked up among the site's records in code, after the answer\n * (`model/ai-automation-draft.ts`). The model is never shown the site's lists,\n * campaigns, workflows, webhooks or pipelines. Words that name no record, or\n * more than one, are kept as a placeholder the person fills in.\n *\n * The automation is written through the workflows plugin's draft writer —\n * that plugin's stored shape, validator, role, plan and cap — keyed by the\n * job's id, and it is written OFF. A run cut off after the write finds its\n * draft and spends nothing.\n *\n * ## Explaining\n *\n * The model is shown an outline of the saved automation, and for a failed run\n * what the run history recorded about it (`model/ai-automation-outline.ts`):\n * never the stored documents, never an email address, never a run's event\n * payload. It answers through `submit_explanation`, which becomes a `text`\n * output. Nothing is changed.\n *\n * ## Revising (AGL-3603)\n *\n * A saved ACTION and a change asked of it. The model is sent the drafting\n * request — the same cached vocabulary, the same tool, the same reach, forms\n * and datasets — with the action's outline in the user turn and the change as\n * the brief, and answers the whole action as it would be after the change.\n * That answer is held to the vocabulary and matched to the site's records as\n * a draft is, and written as a NEW draft, OFF, under the job's draft id: the\n * saved action is read and never written. What changed is worked out in code\n * from the two stored shapes. An action holding what the vocabulary cannot\n * write is refused before the model is asked, so a revision never drops an\n * on-page step the person did not ask to lose.\n *\n * ## A workspace's automation (AGL-3603)\n *\n * A draft with `scope: 'org'` names no site. It is asked as a draft is — the\n * same cached vocabulary, the same tool — with the org automation's narrower\n * vocabulary stated in the user turn and held by the check, and matched\n * against the workspace's lists, campaigns, datasets and stages. Nothing is\n * written: the automation rides on an `orgAutomation` output, which the Org\n * automations editor opens unsaved, where its sites are picked and its save\n * route — the workflows plugin's — holds it to that plugin's rules.\n */\n\n/** The longest an explanation or a draft's generation may take reading the site first. */\nexport const AI_WORKFLOW_RECORDS_READ_MS = 4_000\n\n/**\n * The step's time (AGL-3035): its answer and its re-ask at the routing\n * table's `job.workflow` ceiling on the tier the step is served from. It sends\n * no site inventory block, so it makes no lookup; its own reads — the records\n * a draft is matched against, or the automation and run an explanation\n * reads — are the declared `AI_WORKFLOW_RECORDS_READ_MS`.\n */\nexport const AI_JOB_WORKFLOW_STEP_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.workflow'],\n maxTokens: AI_ROUTING_TABLE['job.workflow'].maxTokens,\n lookups: 0,\n ownReadsMs: AI_WORKFLOW_RECORDS_READ_MS,\n})\n\n/** The least time one workflow step needs before it starts. */\nexport const AI_JOB_WORKFLOW_STEP_MINIMUM_MS = AI_JOB_WORKFLOW_STEP_BUDGET.minimumMs\n\n/** The routing table's answer for `job.workflow`. */\nexport function aiJobWorkflowModel(): string {\n return aiModelForStep('job.workflow')\n}\n\n/** How many forms and datasets the user turn lists, and how many fields a form. */\nexport const AI_WORKFLOW_FORMS_LISTED = 40\nexport const AI_WORKFLOW_FORM_FIELDS_LISTED = 20\nexport const AI_WORKFLOW_DATASETS_LISTED = 40\n\n// ── The vocabulary, for the model ─────────────────────────────────────────\n\nconst STEP_USES: Readonly<Record<AiAutomationStepType, string>> = {\n sendEmail: 'emails the person the event is about. Fields: subject, body (plain text), toField',\n notifyAdmins: 'notifies the site’s admins in the console. Fields: text (what the admins read)',\n enrollList: 'adds the person to an email list. Fields: reference (the list)',\n assignCampaign: 'files the person under a campaign. Fields: reference (the campaign)',\n runWorkflow: 'runs one of the site’s workflows. Fields: reference (the workflow)',\n datasetAppend: 'saves the event as a new record in a dataset. Fields: reference (the dataset)',\n updateDataset: 'updates the event’s record in a dataset. Fields: reference (the dataset)',\n webhookPost: 'sends the event to one of the site’s outbound webhooks. Fields: reference (the webhook)',\n siteAlert: 'shows the visitor who caused the event a short message. Fields: text (the message), severity',\n wait: 'waits before the next step. Fields: minutes',\n waitForEvent: 'waits until something else happens to the same person, or gives up. Fields: event, minutes',\n exitFlow: 'ends the automation here; with a when it is a branch. Fields: none',\n setContactStage: 'sets the person’s lifecycle stage. Fields: stage',\n addContactTag: 'tags the person. Fields: text (the tag)',\n assignContactOwner: 'gives the person an owner. Fields: text (the owner)',\n createCrmTask: 'creates a follow-up task. Fields: text (the task), taskKind, priority, dueInDays',\n logCrmActivity: 'logs what happened on the person’s record. Fields: activityKind, direction (a call’s or an email’s), text (what happened)',\n}\n\nfunction triggerLine(event: HostEventType): string {\n const fields =\n event === 'formSubmission'\n ? 'formName (the form’s name, as the request lists it), path, and every field the form collects, by its field name'\n : (HOST_EVENT_PAYLOAD_KEYS[event] ?? []).join(', ') || 'none'\n const need = AI_AUTOMATION_TRIGGER_NEEDS[event]\n return `- ${event} (${aiAutomationTriggerLabel(event)}). Fields: ${fields}.${\n need ? ` Needs ${AI_AUTOMATION_NEED_LABELS[need]}.` : ''\n }`\n}\n\nfunction stepLine(type: AiAutomationStepType): string {\n const need = AI_AUTOMATION_STEP_NEEDS[type]\n return `- ${type} (${aiStepLabel(type)}) ${STEP_USES[type]}.${\n need ? ` Needs ${AI_AUTOMATION_NEED_LABELS[need]}.` : ''\n }`\n}\n\n/**\n * The drafting instructions, byte-identical on every request so they cache.\n * Built from the platform's own trigger and step catalogs, so the vocabulary\n * the model is shown is the vocabulary the answer is held to.\n */\nexport const AI_JOB_WORKFLOW_DRAFT_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n `You turn a description into one automation for the Actions page of a website builder: something that happens on the site (the trigger), the conditions it must meet, and the steps that run, in order. Answer by calling ${AI_AUTOMATION_TOOL_NAME} exactly once. A reply in prose cannot be used.`,\n '',\n 'A step is written as when it runs and what it does: a when beside an action that carries its type and only that type’s fields. Use only these triggers and steps; each step lists the fields its action takes, and it carries only those.',\n '',\n 'Triggers, with the fields their conditions can read:',\n ...AI_AUTOMATION_TRIGGERS.map(triggerLine),\n '',\n 'Steps:',\n ...AI_AUTOMATION_STEP_TYPES.map(stepLine),\n '',\n 'Rules:',\n '- A step that names a list, campaign, workflow, webhook or dataset writes it as reference, in the description’s own words, such as \"newsletter\". The platform finds the site’s record by those words. Never write an id for one.',\n '- A form is named by the id or the name the request lists: formId on contactCreated, formName on formSubmission. A form the description names that the request does not list is written in the description’s words.',\n '- A deal stage in a condition on stageId or previousStageId is written as the stage’s name.',\n `- A lifecycle stage is one of: ${CONTACT_LIFECYCLE_STAGES.join(', ')}. A new lead is the stage lead.`,\n `- The trigger holds at most ${ACTION_MAX_CONDITIONS} conditions; combinator is and unless the description means any of them. A step's when holds one condition of its own at most, over the same fields. After waitForEvent, when on the field \"${AI_AUTOMATION_TIMED_OUT_FIELD}\" with notEmpty means the wait ran out of time.`,\n `- At most ${ACTION_MAX_STEPS} steps. minutes are whole minutes, at most ${AI_AUTOMATION_WAIT_MINUTES.max}; dueInDays is from 0 to ${CRM_TASK_MAX_DUE_DAYS}; addContactTag’s text is at most ${CONTACT_TAG_MAX_LENGTH} characters.`,\n '- assignContactOwner’s text is \"round robin\", or the teammate’s email address when the description gives one. A teammate named without an address goes in notes.',\n '- Write an email’s subject and body, and any text a person reads, in the site’s voice and the language of the description. Where the description lacks a fact such as a phone number, an address or a price, write a short description of it in square brackets instead of inventing it.',\n '- A trigger or a step the request says this workspace cannot use is never used. When the description needs one, or needs something no trigger or step here does, answer with unsupported set to the reason, no steps, and trigger event formSubmission with no conditions. unsupported is empty on every automation that is built.',\n '- notes holds what the person must decide that the automation cannot hold, in at most three short sentences; empty when there is nothing.',\n '- The automation is drafted switched off, and a person reviews it and switches it on. Never ask to turn it on or to run it.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n/** The explaining instructions, byte-identical on every request so they cache. */\nexport const AI_JOB_WORKFLOW_EXPLAIN_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n `You explain an automation on a website builder to the person who owns the site, in plain words for someone who does not write code. You are shown the automation as it is set up — what starts it, its conditions and its steps in order — and, when you are asked why a run failed, what the run history recorded about that run. Answer by calling ${AI_WORKFLOW_EXPLANATION_TOOL_NAME} exactly once.`,\n '',\n '- summary: in one or two sentences, what the automation does; or, for a failed run, the most likely reason it failed.',\n '- points: what happens, step by step, in the order it happens; or, for a failed run, what the run did and where it went wrong. One sentence each.',\n '- suggestions: what the person can check or change — a list, campaign or workflow the site no longer has, a condition that can never match, a placeholder nobody has filled in, a step the plan does not include. For a failed run, how to fix it. Empty when there is nothing to suggest.',\n '',\n 'Rules:',\n '- Explain only what you are shown. Never guess at settings, records or history you were not given, and never say you changed anything: you change nothing.',\n '- Name triggers and steps the way you are shown them, not by internal names.',\n '- A value in square brackets is a placeholder nobody has filled in yet.',\n '- Personal details were removed from what you are shown, and are written as [email address] or a named teammate. Never ask for them.',\n '- Write plain text, with no markdown and no HTML.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n// ── The user turns ────────────────────────────────────────────────────────\n\nfunction yesNo(value: boolean): string {\n return value ? 'yes' : 'no'\n}\n\n/**\n * What a draft is asked from: the workspace's reach, the site's forms and\n * datasets, and the brief. A revision adds the saved action's outline, and its\n * brief is the change asked for.\n */\nexport function aiJobWorkflowDraftPrompt(input: {\n brief: string\n capabilities: AiAutomationCapabilities\n records: Pick<AiAutomationRecords, 'forms' | 'datasets'>\n /** The saved action a revision starts from, as its outline. */\n revising?: { outline: string } | null\n /** A workspace's automation (AGL-3603): what it may start on and do. */\n org?: AiOrgAutomationVocabulary | null\n}): string {\n const { crm, webhooks, bookings } = input.capabilities\n const forms = input.records.forms.slice(0, AI_WORKFLOW_FORMS_LISTED)\n const datasets = input.records.datasets.slice(0, AI_WORKFLOW_DATASETS_LISTED)\n return [\n ...(input.org\n ? [\n 'This automation belongs to the workspace: it runs on each site it is placed on, as that site. It may start only on these triggers, and use only these steps; anything else, even if listed above, is never used.',\n `Triggers: ${input.org.triggers.join(', ')}.`,\n `Steps: ${input.org.steps.join(', ')}.`,\n ]\n : []),\n `This workspace can use: the CRM — ${yesNo(crm)}; webhooks — ${yesNo(webhooks)}; bookings — ${yesNo(bookings)}.`,\n ...(input.org\n ? ['Forms: an automation of the workspace runs on several sites, so none is listed; a form is named in the description’s words.']\n : [\n 'Forms on this site (id · name · fields):',\n ...(forms.length\n ? forms.map(\n (form) =>\n `- ${form.id} · ${form.name} · ${form.fields.slice(0, AI_WORKFLOW_FORM_FIELDS_LISTED).join(', ') || 'no fields'}`,\n )\n : ['- none']),\n ]),\n input.org ? 'Datasets in this workspace (name):' : 'Datasets on this site (name):',\n ...(datasets.length ? datasets.map((dataset) => `- ${dataset.name}`) : ['- none']),\n ...(input.revising\n ? [\n 'The automation to change, as it is set up now:',\n input.revising.outline,\n 'Answer with the whole automation as it should be after the change below. Keep every condition and step the change does not touch as it is, with the same records named in the same words, and keep its name unless the change asks for another. A detail shown as [email address] or a named teammate is written as a placeholder in square brackets.',\n `Change: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`,\n ]\n : [`Brief: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`]),\n ].join('\\n')\n}\n\n/** What an explanation is asked from: the mode, the outlines, and the member's question. */\nexport function aiJobWorkflowExplainPrompt(input: {\n brief: string\n mode: 'explain' | 'diagnose'\n outline: string\n run: string | null\n}): string {\n return [\n input.mode === 'diagnose'\n ? 'Asked: why a run of this automation failed.'\n : 'Asked: what this automation does.',\n input.outline,\n ...(input.run ? [input.run] : []),\n `Question: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`,\n ].join('\\n\\n')\n}\n\n/** The routing row's thinking and effort, as a generation input spells them. */\nfunction routedEffort(): Pick<AiCustomGenerationInput<unknown>, 'thinking' | 'effort'> {\n const row = AI_ROUTING_TABLE['job.workflow']\n return {\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n }\n}\n\n/** The draft generation as the doctrine's loop runs it; the eval harness records one through this same call. */\nexport function aiJobWorkflowDraftGeneration(request: {\n brief: string\n capabilities: AiAutomationCapabilities\n records: Pick<AiAutomationRecords, 'forms' | 'datasets'>\n revising?: { outline: string } | null\n org?: AiOrgAutomationVocabulary | null\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<AiAutomationAnswer> {\n const org = request.org\n const check: AiGenerationCheck<AiAutomationAnswer> = (answer) =>\n org\n ? holdAiAutomationAnswerToVocabulary(readAiAutomationAnswer(answer, request.capabilities), org)\n : readAiAutomationAnswer(answer, request.capabilities)\n return {\n step: 'job.workflow',\n model: request.model,\n instructions: AI_JOB_WORKFLOW_DRAFT_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobWorkflowDraftPrompt(request) }],\n tool: aiAutomationTool(),\n maxTokens: AI_JOB_WORKFLOW_STEP_BUDGET.maxTokens(request.model),\n ...routedEffort(),\n ...(request.signal ? { signal: request.signal } : {}),\n check,\n }\n}\n\n/** The explanation generation as the doctrine's loop runs it. */\nexport function aiJobWorkflowExplainGeneration(request: {\n brief: string\n mode: 'explain' | 'diagnose'\n outline: string\n run: string | null\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<AiWorkflowExplanation> {\n return {\n step: 'job.workflow',\n model: request.model,\n instructions: AI_JOB_WORKFLOW_EXPLAIN_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobWorkflowExplainPrompt(request) }],\n tool: aiWorkflowExplanationTool(),\n maxTokens: AI_JOB_WORKFLOW_STEP_BUDGET.maxTokens(request.model),\n ...routedEffort(),\n ...(request.signal ? { signal: request.signal } : {}),\n check: readAiWorkflowExplanation,\n }\n}\n\n// ── The runner ────────────────────────────────────────────────────────────\n\nexport interface AiJobWorkflowStepDeps {\n /** How the automation draft writer is found; the core's registry otherwise. */\n writerFor?: AiPluginDraftWriterLookup\n readRecords?: typeof readAiAutomationRecords\n readOrgRecords?: typeof readAiOrgAutomationRecords\n readTarget?: typeof readAiWorkflowTarget\n readRun?: typeof readAiWorkflowRun\n readFunctions?: typeof readAiWorkflowFunctions\n}\n\n/** A job label: the automation's name in quotes, cut to a line. */\nfunction quotedName(name: string): string {\n const clean = name.replace(/\\s+/g, ' ').trim()\n return `“${clean.length > 60 ? `${clean.slice(0, 60)}…` : clean}”`\n}\n\nexport function createAiJobWorkflowStep(deps: AiJobWorkflowStepDeps = {}): AiJobStepRunner {\n const writerFor = deps.writerFor ?? aiPluginDraftWriter\n const readRecords = deps.readRecords ?? readAiAutomationRecords\n const readOrgRecords = deps.readOrgRecords ?? readAiOrgAutomationRecords\n const readTarget = deps.readTarget ?? readAiWorkflowTarget\n const readRun = deps.readRun ?? readAiWorkflowRun\n const readFunctions = deps.readFunctions ?? readAiWorkflowFunctions\n return async ({ job, now, signal, firestore, org, modelFor }): Promise<AiJobStepOutcome> => {\n // The switch's answer for this job, else the routing table's (AGL-2942).\n const model = modelFor?.('job.workflow') ?? aiJobWorkflowModel()\n const unspent = (failure: string): AiJobStepOutcome => ({ ...aiUnspentOutcome(model), failure })\n const inputs = parseAiWorkflowJobInputs(job.inputs)\n if (typeof inputs === 'string') return unspent(inputs)\n\n if (inputs.mode === 'draft' && inputs.scope === 'org') {\n // A workspace's automation (AGL-3603): no site, and nothing written.\n const orgData = (org ?? (await firestore.collection('orgs').doc(job.orgId).get()).data() ?? null) as Record<\n string,\n unknown\n > | null\n if (!checkEntitlement(orgData as Partial<AglynOrgBilling> | null, 'actions')) {\n return aiUnspentOutcome(model, { review: aiLimitReview(AI_ORG_AUTOMATION_PLAN_COPY) })\n }\n const capabilities = aiAutomationCapabilities(orgData)\n const vocabulary = { triggers: inputs.triggers, steps: inputs.steps }\n const records = await readOrgRecords(firestore, { orgId: job.orgId, crm: capabilities.crm })\n const generation = await runValidatedGeneration(\n 'workflow',\n aiJobWorkflowDraftGeneration({\n brief: job.brief,\n capabilities,\n records,\n org: vocabulary,\n model,\n ...(signal ? { signal } : {}),\n }),\n )\n const spent = { ...aiGenerationSpent(generation), ...(generation.effort ? { effort: generation.effort } : {}) }\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, review: aiDoctrineReview(generation) }\n const answer = generation.value\n if (answer.unsupported) {\n return {\n ...spent,\n failure:\n answer.unsupported === 'no-trigger' || answer.unsupported === 'no-step'\n ? AI_ORG_AUTOMATION_UNSUPPORTED_COPY\n : AI_AUTOMATION_UNSUPPORTED_COPY[answer.unsupported],\n }\n }\n if (!answer.steps.length) return { ...spent, failure: AI_WORKFLOW_NO_DRAFT_COPY }\n const draft = aiAutomationDraft(answer, records)\n return { ...spent, outputs: [orgProposalOutput(draft, answer.notes)] }\n }\n\n const hostId = job.hostId\n if (!hostId) return unspent(AI_WORKFLOW_NO_SITE_COPY)\n // The door checks the caller's membership of the org the job is metered\n // against; the site is checked against that org here, before anything\n // about it is read into a prompt.\n const host = await firestore.collection('hosts').doc(hostId).get()\n if (!host.exists || host.get('orgId') !== job.orgId) return unspent(AI_WORKFLOW_NO_SITE_COPY)\n const subdomain = host.get('subdomain')\n const hostSubdomain = typeof subdomain === 'string' && subdomain ? subdomain : null\n const orgData = (org ?? (await firestore.collection('orgs').doc(job.orgId).get()).data() ?? null) as Record<\n string,\n unknown\n > | null\n const capabilities = aiAutomationCapabilities(orgData)\n\n if (inputs.mode === 'draft') {\n const writer = writerFor(AI_AUTOMATION_RESOURCE)\n if (!writer) return unspent(AI_WORKFLOW_UNAVAILABLE_COPY)\n const place = { hostId, hostSubdomain }\n // What an earlier run of this same job already wrote, under the id the job recorded.\n const draftId = aiJobDraftId(job, 'workflow')\n const written = await writer.read({ hostId, id: draftId })\n if (written) {\n return aiUnspentOutcome(model, {\n outputs: [draftOutput(written.id, written.name, place, 'It is off until you switch it on.')],\n })\n }\n const context = { orgId: job.orgId, hostId, uid: job.createdBy, org: orgData, now }\n const refusal = await writer.refusal(context)\n if (refusal) {\n return refusal.status === 403\n ? aiUnspentOutcome(model, { review: aiLimitReview(refusal.error) })\n : unspent(refusal.error)\n }\n const records = await readRecords(firestore, { orgId: job.orgId, hostId, crm: capabilities.crm })\n const generation = await runValidatedGeneration(\n 'workflow',\n aiJobWorkflowDraftGeneration({\n brief: job.brief,\n capabilities,\n records,\n model,\n ...(signal ? { signal } : {}),\n }),\n )\n const spent = { ...aiGenerationSpent(generation), ...(generation.effort ? { effort: generation.effort } : {}) }\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, review: aiDoctrineReview(generation) }\n const answer = generation.value\n if (answer.unsupported) return { ...spent, failure: AI_AUTOMATION_UNSUPPORTED_COPY[answer.unsupported] }\n if (!answer.steps.length) return { ...spent, failure: AI_WORKFLOW_NO_DRAFT_COPY }\n const draft = aiAutomationDraft(answer, records)\n const write = await writer.write({\n ...context,\n id: draftId,\n name: draft.action.name,\n content: { action: draft.action },\n })\n if (write.ok === false) {\n return write.status === 403\n ? { ...spent, review: aiLimitReview(write.error) }\n : { ...spent, failure: AI_WORKFLOW_SAVE_FAILURE_COPY }\n }\n return {\n ...spent,\n outputs: [draftOutput(write.id, write.name, place, aiAutomationDraftNote(draft, answer.notes))],\n }\n }\n\n if (inputs.mode === 'revise') {\n const writer = writerFor(AI_AUTOMATION_RESOURCE)\n if (!writer) return unspent(AI_WORKFLOW_UNAVAILABLE_COPY)\n const place = { hostId, hostSubdomain }\n const draftId = aiJobDraftId(job, 'workflow')\n const written = await writer.read({ hostId, id: draftId })\n if (written) {\n return aiUnspentOutcome(model, {\n outputs: [draftOutput(written.id, written.name, place, 'It is off until you switch it on.')],\n })\n }\n const saved = await readTarget({ hostId, type: 'action', id: inputs.targetId })\n if (!saved) return unspent(AI_WORKFLOW_GONE_COPY)\n if (saved.type !== 'action') return unspent(AI_WORKFLOW_REVISE_WORKFLOW_COPY)\n const blocker = aiActionReviseBlocker(saved.action)\n if (blocker) return unspent(AI_WORKFLOW_REVISE_BLOCKER_COPY[blocker])\n const context = { orgId: job.orgId, hostId, uid: job.createdBy, org: orgData, now }\n const refusal = await writer.refusal(context)\n if (refusal) {\n return refusal.status === 403\n ? aiUnspentOutcome(model, { review: aiLimitReview(refusal.error) })\n : unspent(refusal.error)\n }\n const records = await readRecords(firestore, { orgId: job.orgId, hostId, crm: capabilities.crm })\n const generation = await runValidatedGeneration(\n 'workflow',\n aiJobWorkflowDraftGeneration({\n brief: job.brief,\n capabilities,\n records,\n revising: { outline: aiActionOutline(saved.action, records) },\n model,\n ...(signal ? { signal } : {}),\n }),\n )\n const spent = { ...aiGenerationSpent(generation), ...(generation.effort ? { effort: generation.effort } : {}) }\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, review: aiDoctrineReview(generation) }\n const answer = generation.value\n if (answer.unsupported) return { ...spent, failure: AI_AUTOMATION_UNSUPPORTED_COPY[answer.unsupported] }\n if (!answer.steps.length) return { ...spent, failure: AI_WORKFLOW_NO_DRAFT_COPY }\n const draft = aiAutomationDraft(answer, records)\n // The copy never takes the saved action's name: two rows by one name\n // in the list are two rows nobody can tell apart.\n const name =\n draft.action.name.trim() && draft.action.name.trim() !== saved.name.trim()\n ? draft.action.name\n : aiRevisedName(saved.name)\n const write = await writer.write({ ...context, id: draftId, name, content: { action: { ...draft.action, name } } })\n if (write.ok === false) {\n return write.status === 403\n ? { ...spent, review: aiLimitReview(write.error) }\n : { ...spent, failure: AI_WORKFLOW_SAVE_FAILURE_COPY }\n }\n const changes = aiAutomationRevisionChanges(saved.action, draft.action, aiStepLabel)\n return {\n ...spent,\n outputs: [\n draftOutput(\n write.id,\n write.name,\n place,\n aiAutomationRevisionNote({ fromName: saved.name, changes, draft, notes: answer.notes }),\n ),\n ],\n }\n }\n\n const target = await readTarget({ hostId, type: inputs.targetType, id: inputs.targetId })\n if (!target) return unspent(AI_WORKFLOW_GONE_COPY)\n let run: AiRunRecord | null = null\n if (inputs.mode === 'diagnose') {\n const read = await readRun(firestore, { hostId, targetId: inputs.targetId, runId: inputs.runId })\n if (read.ok === false) {\n return unspent(read.reason === 'gone' ? AI_WORKFLOW_RUN_GONE_COPY : AI_WORKFLOW_RUN_NOT_FAILED_COPY)\n }\n run = read.run\n }\n // Only the kinds of record the automation's steps name are read, to say\n // whether each still exists.\n const outline =\n target.type === 'action'\n ? aiActionOutline(\n target.action,\n await readRecords(firestore, {\n orgId: job.orgId,\n hostId,\n crm: false,\n only: aiActionRecordKinds(target.action),\n }),\n )\n : aiWorkflowOutline(target.workflow, await readFunctions(firestore, hostId))\n const generation = await runValidatedGeneration(\n 'workflow',\n aiJobWorkflowExplainGeneration({\n brief: job.brief,\n mode: inputs.mode,\n outline,\n run: run ? aiRunOutline(run) : null,\n model,\n ...(signal ? { signal } : {}),\n }),\n )\n const spent = { ...aiGenerationSpent(generation), ...(generation.effort ? { effort: generation.effort } : {}) }\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, failure: AI_WORKFLOW_NO_EXPLANATION_COPY }\n const output: AiJobOutput = {\n resource: 'text',\n // An explanation has no document of its own; the id names what it is\n // within the job, as a text output's `draft` does.\n id: inputs.mode === 'diagnose' ? 'diagnosis' : 'explanation',\n hostId,\n hostSubdomain,\n label:\n inputs.mode === 'diagnose'\n ? `Why a run of ${quotedName(target.name)} failed`\n : `How ${quotedName(target.name)} works`,\n text: aiWorkflowExplanationText(generation.value, inputs.mode),\n }\n return { ...spent, outputs: [output] }\n }\n}\n\n/** What a person is told when a workspace's automation would need what only one site runs. */\nexport const AI_ORG_AUTOMATION_UNSUPPORTED_COPY =\n 'An org automation cannot do what this description asks — it starts only on what the server sees and uses only the steps every site runs the same way — so nothing was drafted. Build it as an action on the site instead.'\n\n/**\n * A workspace's drafted automation as the output that proposes it\n * (AGL-3603): the stored shape the Org automations editor opens — its name,\n * trigger and steps, never a placement, which the person picks — and what\n * to fill in before switching it on.\n */\nexport function orgProposalOutput(draft: AiAutomationDraft, notes: readonly string[]): AiJobOutput {\n const { name, trigger, steps } = draft.action\n return {\n resource: AI_ORG_AUTOMATION_RESOURCE as AiJobOutput['resource'],\n // A proposal has no document; the id names what it is within the job.\n id: 'proposal',\n hostId: null,\n hostSubdomain: null,\n label: name,\n note: [\n 'Nothing is saved yet: it opens in the org automation editor, switched off, where you choose the sites it runs on and save it.',\n ...(draft.placeholders.length\n ? [\n `Fill in ${draft.placeholders.length === 1 ? 'its placeholder' : `its ${draft.placeholders.length} placeholders`} before switching it on.`,\n ]\n : []),\n ...notes,\n ].join(' '),\n proposal: { automation: { name, trigger, steps } } as unknown as Record<string, unknown>,\n }\n}\n\n/** The name a revised copy is saved under when the change asked for no other. */\nexport function aiRevisedName(name: string): string {\n const clean = name.replace(/\\s+/g, ' ').trim() || 'Automation'\n return `${clean.length > 80 ? clean.slice(0, 80) : clean} (revised)`\n}\n\nfunction draftOutput(\n id: string,\n name: string,\n place: { hostId: string; hostSubdomain: string | null },\n note: string,\n): AiJobOutput {\n return {\n resource: 'workflow',\n id,\n versionId: null,\n hostId: place.hostId,\n hostSubdomain: place.hostSubdomain,\n label: name,\n note,\n }\n}\n\nexport const runAiJobWorkflowStep = createAiJobWorkflowStep()\n\n// ── Admission ─────────────────────────────────────────────────────────────\n\n/**\n * Whether the plugin that writes automations runs on this site: switched on,\n * and past its release flag. The owner is whichever plugin registered the\n * automation writer (AGL-3080); none registered is the same refusal.\n */\nasync function workflowsPluginRefusal(\n context: Parameters<AiJobAdmission>[0],\n hostId: string,\n): Promise<AiJobAdmissionRefusal | null> {\n const owner = aiPluginDraftOwner(AI_AUTOMATION_RESOURCE)\n if (!owner) return { status: 403, error: aiPluginDraftUnavailable('Automation') }\n const host = (await context.firestore.collection('hosts').doc(hostId).get()).data() ?? null\n const org = context.org as { enabledPlugins?: string[] } | null\n const released = await filterEnabledPluginsByReleaseFlags([owner], {\n orgId: context.orgId,\n authorization: null,\n })\n return released.includes(owner) && isHostPluginEnabled(org, host, owner)\n ? null\n : { status: 403, error: aiPluginDraftUnavailable('Automation') }\n}\n\n/**\n * Whether a workspace's automation may be drafted (AGL-3603): no site is\n * named, the plugin that keeps automations runs for the workspace and is\n * past its release flag, and the plan includes the actions builder that\n * section is sold under. Nothing is written, so no allowance is asked: the\n * section's save route counts its cap when the person saves.\n */\nasync function orgAutomationRefusal(context: Parameters<AiJobAdmission>[0]): Promise<AiJobAdmissionRefusal | null> {\n if (context.hostId) return { status: 400, error: 'An org automation belongs to no one site' }\n const owner = aiPluginDraftOwner(AI_AUTOMATION_RESOURCE)\n if (!owner) return { status: 403, error: AI_ORG_AUTOMATION_UNAVAILABLE_COPY }\n const org = context.org as ({ enabledPlugins?: string[] } & Partial<AglynOrgBilling>) | null\n const released = await filterEnabledPluginsByReleaseFlags([owner], {\n orgId: context.orgId,\n authorization: null,\n })\n if (!released.includes(owner) || !isPluginEnabled(org, owner)) {\n return { status: 403, error: AI_ORG_AUTOMATION_UNAVAILABLE_COPY }\n }\n return checkEntitlement(org, 'actions') ? null : { status: 403, error: AI_ORG_AUTOMATION_PLAN_COPY }\n}\n\nexport interface AiWorkflowJobAdmissionDeps {\n readTarget?: typeof readAiWorkflowTarget\n readRun?: typeof readAiWorkflowRun\n writerFor?: AiPluginDraftWriterLookup\n}\n\n/**\n * A workflow job is admitted for a site of its org with the Automation plugin\n * on. A draft also needs the draft writer and the member's room and role in\n * its own words; an explanation needs the automation it names to exist, and\n * a run's explanation a failed run of it.\n */\nexport function createAiWorkflowJobAdmission(deps: AiWorkflowJobAdmissionDeps = {}): AiJobAdmission {\n const readTarget = deps.readTarget ?? readAiWorkflowTarget\n const readRun = deps.readRun ?? readAiWorkflowRun\n return async (context) => {\n const inputs = parseAiWorkflowJobInputs(context.inputs)\n if (typeof inputs === 'string') return { status: 400, error: inputs }\n if (inputs.mode === 'draft' && inputs.scope === 'org') return orgAutomationRefusal(context)\n if (inputs.mode === 'draft') {\n return aiPluginDraftAdmissionRefusal(context, {\n kind: 'workflow',\n drafts: [{ resource: AI_AUTOMATION_RESOURCE, label: 'Automation' }],\n ...(deps.writerFor ? { writerFor: deps.writerFor } : {}),\n })\n }\n if (inputs.mode === 'revise') {\n // A revision writes a draft as a description does, and also needs the\n // action it starts from to exist and to hold only what AI writes.\n return aiPluginDraftAdmissionRefusal(context, {\n kind: 'workflow',\n drafts: [{ resource: AI_AUTOMATION_RESOURCE, label: 'Automation' }],\n ...(deps.writerFor ? { writerFor: deps.writerFor } : {}),\n ownCheck: async (hostId) => {\n const saved = await readTarget({ hostId, type: 'action', id: inputs.targetId })\n if (!saved || saved.type !== 'action') return { status: 404, error: AI_WORKFLOW_GONE_COPY }\n const blocker = aiActionReviseBlocker(saved.action)\n return blocker ? { status: 400, error: AI_WORKFLOW_REVISE_BLOCKER_COPY[blocker] } : null\n },\n })\n }\n const hostId = context.hostId\n if (!hostId) return { status: 400, error: 'Open the site the automation is on before asking about it' }\n const owner = await resolveOrgIdForHost(hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n const plugin = await workflowsPluginRefusal(context, hostId)\n if (plugin) return plugin\n const target = await readTarget({ hostId, type: inputs.targetType, id: inputs.targetId })\n if (!target) return { status: 404, error: AI_WORKFLOW_GONE_COPY }\n if (inputs.mode === 'diagnose') {\n const run = await readRun(context.firestore, { hostId, targetId: inputs.targetId, runId: inputs.runId })\n if (run.ok === false) {\n return run.reason === 'gone'\n ? { status: 404, error: AI_WORKFLOW_RUN_GONE_COPY }\n : { status: 400, error: AI_WORKFLOW_RUN_NOT_FAILED_COPY }\n }\n }\n return null\n }\n}\n\nexport const aiWorkflowJobAdmission = createAiWorkflowJobAdmission()\n\n/** Registers the workflow step and the check a workflow job passes before it is created or resumed. */\nexport function registerAiWorkflowJob(): void {\n registerAiJobStep('workflow', runAiJobWorkflowStep, { minimumMs: AI_JOB_WORKFLOW_STEP_MINIMUM_MS })\n registerAiJobAdmission('workflow', aiWorkflowJobAdmission)\n}\n"],"names":["ACTION_MAX_CONDITIONS","ACTION_MAX_STEPS","CONTACT_LIFECYCLE_STAGES","CONTACT_TAG_MAX_LENGTH","CRM_TASK_MAX_DUE_DAYS","HOST_EVENT_PAYLOAD_KEYS","checkEntitlement","isHostPluginEnabled","isPluginEnabled","filterEnabledPluginsByReleaseFlags","resolveOrgIdForHost","aiAutomationDraft","aiAutomationDraftNote","aiAutomationRevisionChanges","aiAutomationRevisionNote","AI_AUTOMATION_TIMED_OUT_FIELD","AI_AUTOMATION_WAIT_MINUTES","aiStepLabel","aiActionOutline","aiActionRecordKinds","aiRunOutline","aiWorkflowExplanationText","aiWorkflowOutline","AI_AUTOMATION_NEED_LABELS","AI_AUTOMATION_RESOURCE","AI_AUTOMATION_STEP_NEEDS","AI_AUTOMATION_STEP_TYPES","AI_AUTOMATION_TRIGGER_NEEDS","AI_AUTOMATION_TRIGGERS","AI_AUTOMATION_UNSUPPORTED_COPY","AI_WORKFLOW_GONE_COPY","AI_WORKFLOW_NO_DRAFT_COPY","AI_WORKFLOW_NO_EXPLANATION_COPY","AI_WORKFLOW_NO_SITE_COPY","AI_WORKFLOW_RUN_GONE_COPY","AI_WORKFLOW_RUN_NOT_FAILED_COPY","AI_WORKFLOW_SAVE_FAILURE_COPY","AI_WORKFLOW_REVISE_BLOCKER_COPY","AI_WORKFLOW_REVISE_WORKFLOW_COPY","AI_WORKFLOW_UNAVAILABLE_COPY","AI_ORG_AUTOMATION_PLAN_COPY","AI_ORG_AUTOMATION_RESOURCE","AI_ORG_AUTOMATION_UNAVAILABLE_COPY","aiActionReviseBlocker","aiAutomationCapabilities","aiAutomationTriggerLabel","parseAiWorkflowJobInputs","AI_STEP_TIERS","AI_ROUTING_TABLE","aiModelForStep","runValidatedGeneration","AI_AUTOMATION_TOOL_NAME","AI_WORKFLOW_EXPLANATION_TOOL_NAME","aiAutomationTool","aiWorkflowExplanationTool","holdAiAutomationAnswerToVocabulary","readAiAutomationAnswer","readAiWorkflowExplanation","registerAiJobAdmission","aiJobStepBudget","aiJobDraftId","aiDoctrineReview","aiGenerationSpent","aiLimitReview","aiUnspentOutcome","aiPluginDraftAdmissionRefusal","aiPluginDraftOwner","aiPluginDraftUnavailable","aiPluginDraftWriter","AI_JOB_BRIEF_MAX_CHARS","registerAiJobStep","readAiAutomationRecords","readAiOrgAutomationRecords","readAiWorkflowFunctions","readAiWorkflowRun","readAiWorkflowTarget","AI_WORKFLOW_RECORDS_READ_MS","AI_JOB_WORKFLOW_STEP_BUDGET","tier","maxTokens","lookups","ownReadsMs","AI_JOB_WORKFLOW_STEP_MINIMUM_MS","minimumMs","aiJobWorkflowModel","AI_WORKFLOW_FORMS_LISTED","AI_WORKFLOW_FORM_FIELDS_LISTED","AI_WORKFLOW_DATASETS_LISTED","STEP_USES","sendEmail","notifyAdmins","enrollList","assignCampaign","runWorkflow","datasetAppend","updateDataset","webhookPost","siteAlert","wait","waitForEvent","exitFlow","setContactStage","addContactTag","assignContactOwner","createCrmTask","logCrmActivity","triggerLine","event","fields","join","need","stepLine","type","AI_JOB_WORKFLOW_DRAFT_INSTRUCTIONS","text","map","max","cacheBreakpoint","AI_JOB_WORKFLOW_EXPLAIN_INSTRUCTIONS","yesNo","value","aiJobWorkflowDraftPrompt","input","crm","webhooks","bookings","capabilities","forms","records","slice","datasets","org","triggers","steps","length","form","id","name","dataset","revising","outline","brief","aiJobWorkflowExplainPrompt","mode","run","routedEffort","row","thinking","effort","aiJobWorkflowDraftGeneration","request","check","answer","step","model","instructions","messages","role","content","tool","signal","aiJobWorkflowExplainGeneration","quotedName","clean","replace","trim","createAiJobWorkflowStep","deps","writerFor","readRecords","readOrgRecords","readTarget","readRun","readFunctions","job","now","firestore","modelFor","unspent","failure","inputs","scope","orgData","collection","doc","orgId","get","data","review","vocabulary","generation","spent","status","refused","unsupported","AI_ORG_AUTOMATION_UNSUPPORTED_COPY","draft","outputs","orgProposalOutput","notes","hostId","host","exists","subdomain","hostSubdomain","writer","place","draftId","written","read","draftOutput","context","uid","createdBy","refusal","error","write","action","ok","saved","targetId","blocker","aiRevisedName","changes","fromName","target","targetType","runId","reason","only","workflow","output","resource","label","trigger","note","placeholders","proposal","automation","versionId","runAiJobWorkflowStep","workflowsPluginRefusal","owner","released","authorization","includes","orgAutomationRefusal","createAiWorkflowJobAdmission","kind","drafts","ownCheck","plugin","aiWorkflowJobAdmission","registerAiWorkflowJob"],"mappings":"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"}
|
|
@@ -14,13 +14,16 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { AI_JOB_PLAN_STEP, type AiJob, type AiJobApplied, type AiJobKind, type AiJobOutput, type AiJobPlan, type AiJobReview, type AiJobSitePublish, type AiJobStatus, type AiJobStepTokens, type AiJobSummary } from '../model/ai-jobs.types';
|
|
17
|
+
import { AI_JOB_PLAN_STEP, type AiJob, type AiJobApplied, type AiJobItemLedger, type AiJobKind, type AiJobOutput, type AiJobPlan, type AiJobReview, type AiJobSitePublish, type AiJobStatus, type AiJobStepTokens, type AiJobSummary } from '../model/ai-jobs.types';
|
|
18
18
|
import type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types';
|
|
19
19
|
import { type AiActivityActor } from '../activity/ai-activity';
|
|
20
20
|
import { type AiEffort, type AiUsage } from '../runtime/ai-runtime';
|
|
21
21
|
import { AI_JOB_INLINE_BUDGET_MS, AI_JOB_SWEEP_BUDGET_MS } from './ai-job-budget';
|
|
22
22
|
import { type AiJobStepOutcome, type AiJobStepRunner } from './ai-job-text-step';
|
|
23
23
|
import { type AssistReservation } from '../usage/assist-usage';
|
|
24
|
+
import { type AiJobRefundReason } from '../usage/assist-job-refund';
|
|
25
|
+
import type { AiJobItemOutcome } from './ai-job-text-step';
|
|
26
|
+
import { type FreeAssistAccount } from '../usage/assist-free-taste';
|
|
24
27
|
/**
|
|
25
28
|
* AI generation jobs — the Firestore state machine (AGL-2904).
|
|
26
29
|
*
|
|
@@ -331,7 +334,30 @@ export interface RecordStepInput {
|
|
|
331
334
|
* caller resolves at once.
|
|
332
335
|
*/
|
|
333
336
|
quiet?: boolean;
|
|
337
|
+
/**
|
|
338
|
+
* A `build` job's ledger to start from (AGL-3616), kept in this write;
|
|
339
|
+
* absent keeps the one the job has.
|
|
340
|
+
*/
|
|
341
|
+
items?: AiJobItemLedger[];
|
|
342
|
+
/**
|
|
343
|
+
* What this pass came to for the `build` item it ran (AGL-3616): the pass's
|
|
344
|
+
* `creditsSpent` is that item's, and lands on its row in this same
|
|
345
|
+
* transaction, with what was given back for it.
|
|
346
|
+
*/
|
|
347
|
+
item?: AiJobItemRecord;
|
|
334
348
|
}
|
|
349
|
+
/** One `build` pass as its item's row records it (AGL-3616). */
|
|
350
|
+
export interface AiJobItemRecord extends AiJobItemOutcome {
|
|
351
|
+
/** Given back for this pass's failure, before the record. */
|
|
352
|
+
creditsRefunded?: number;
|
|
353
|
+
refundKey?: string;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* A build's ledger with one pass applied (AGL-3616): the pass's credits on
|
|
357
|
+
* the item's row, its status, failure, note and outputs, and what was given
|
|
358
|
+
* back for it. Pure; the machine applies it inside `recordStep`.
|
|
359
|
+
*/
|
|
360
|
+
export declare function aiApplyJobItemRecord(ledger: readonly AiJobItemLedger[], record: AiJobItemRecord, credits: number): AiJobItemLedger[];
|
|
335
361
|
/** One run of a step's runner, as the machine measured it (AGL-2937). */
|
|
336
362
|
export interface AiJobStepTokenRun {
|
|
337
363
|
usage: AiUsage;
|
|
@@ -414,6 +440,51 @@ export declare function cancelAiJob(firestore: Firestore, orgId: string, jobId:
|
|
|
414
440
|
job: AiJob;
|
|
415
441
|
changed: boolean;
|
|
416
442
|
}>;
|
|
443
|
+
/**
|
|
444
|
+
* The kinds settled item by item (AGL-3616): a build, and a site scaffold,
|
|
445
|
+
* which is the build's preset. Their step writes an item ledger; a failed
|
|
446
|
+
* item gives back its own spend and the rest goes on.
|
|
447
|
+
*/
|
|
448
|
+
export declare function aiJobSettlesByItem(kind: AiJobKind): boolean;
|
|
449
|
+
/**
|
|
450
|
+
* Whether Try again may run a job's failed items: a finished build, done or
|
|
451
|
+
* failed; a site scaffold that delivered part of its site — one that built
|
|
452
|
+
* nothing starts over from its own answers instead.
|
|
453
|
+
*/
|
|
454
|
+
export declare function aiBuildRetryable(job: Pick<AiJob, 'kind' | 'status'>): boolean;
|
|
455
|
+
/** What a build that delivered nothing says; its planning was given back too. */
|
|
456
|
+
export declare const AI_BUILD_NOTHING_BUILT_COPY = "Nothing in this request could be built. Try again, or ask for less at once.";
|
|
457
|
+
/** What an item the build never reached says when the build stopped early. */
|
|
458
|
+
export declare const AI_BUILD_NOT_REACHED_COPY = "Not built: the build stopped before it reached this.";
|
|
459
|
+
/**
|
|
460
|
+
* Ends a build (AGL-3616), once nothing is left to build or the machine
|
|
461
|
+
* stopped it. A build that STOPPED — a provider failure, its attempts used up
|
|
462
|
+
* — fails the item it was on and gives back that attempt's spend, and leaves
|
|
463
|
+
* the items it never reached `skipped`. Then: anything delivered, and its
|
|
464
|
+
* planning is charged and the job is `done`, failed items and all; nothing
|
|
465
|
+
* delivered, and its planning is given back too and the job is `failed`.
|
|
466
|
+
*/
|
|
467
|
+
export declare function settleAiBuildJob(firestore: Firestore, orgId: string, jobId: string, input: {
|
|
468
|
+
now: Date;
|
|
469
|
+
free?: FreeAssistAccount | null;
|
|
470
|
+
stopped?: {
|
|
471
|
+
message: string;
|
|
472
|
+
reason: AiJobRefundReason;
|
|
473
|
+
};
|
|
474
|
+
}): Promise<AiJob>;
|
|
475
|
+
/**
|
|
476
|
+
* Try again on a build (AGL-3616): its failed items back to pending on their
|
|
477
|
+
* next attempt, with what they left unbuilt (`aiBuildRetryLedger`), and its
|
|
478
|
+
* generation step queued again. Never re-runs an item that succeeded, never
|
|
479
|
+
* re-asks the plan. Held at what the retried items are estimated to cost.
|
|
480
|
+
* `changed: false` for a job that is not a finished build, or has nothing to
|
|
481
|
+
* try again.
|
|
482
|
+
*/
|
|
483
|
+
export declare function retryAiBuildJob(firestore: Firestore, orgId: string, jobId: string, now?: Date): Promise<{
|
|
484
|
+
job: AiJob;
|
|
485
|
+
changed: boolean;
|
|
486
|
+
retried: string[];
|
|
487
|
+
}>;
|
|
417
488
|
/**
|
|
418
489
|
* Resume a job that stopped for a person (AGL-2935): confirm its plan, or
|
|
419
490
|
* try again the step whose answer broke a building rule. One transaction,
|
|
@@ -427,7 +498,14 @@ export declare function cancelAiJob(firestore: Firestore, orgId: string, jobId:
|
|
|
427
498
|
*/
|
|
428
499
|
export declare function resumeAiJob(firestore: Firestore, orgId: string, jobId: string, actor: {
|
|
429
500
|
uid: string;
|
|
430
|
-
}, now?: Date
|
|
501
|
+
}, now?: Date, options?: {
|
|
502
|
+
/**
|
|
503
|
+
* A build whose request asked to publish, confirmed with the plan card's
|
|
504
|
+
* box ticked (AGL-3616): kept on its inputs, which is what lets its last
|
|
505
|
+
* pass put its pages live.
|
|
506
|
+
*/
|
|
507
|
+
publishConfirmed?: boolean;
|
|
508
|
+
}): Promise<{
|
|
431
509
|
job: AiJob;
|
|
432
510
|
changed: boolean;
|
|
433
511
|
}>;
|