@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/model/assist-edit.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ScreenSeoTextField } from '@aglyn/aglyn/app-utils/screen-seo-fields'\nimport type { ReusableComponentProp } from '@aglyn/aglyn/foundation/definitions/platform.types'\n\n/**\n * Assist level 3, the edit contract (AGL-2906): what the chat door proposes\n * for a besigner canvas, and what the panel applies once the author says so.\n *\n * Shared by the server, which validates a model's proposal into these\n * shapes, and the client, which applies them. Pure data and pure functions,\n * so the panel imports it without pulling the palette or the runtime.\n *\n * ## The boundary\n *\n * A proposal is OPERATIONS, never a document. The server writes nothing: it\n * answers with ops that name elements already on the canvas, or a validated\n * subtree to insert, and the client applies them through the canvas's own\n * guarded mutators, on confirm, as one undoable step. Every change lands as\n * an unsaved edit on the version the editor has open — a draft — and on a\n * version the live site serves, the editor's own new-version flow runs first.\n */\n\n/** The eight operations a proposal may carry. */\nexport const ASSIST_EDIT_OP_KINDS = [\n 'insertSubtree',\n 'updateProps',\n 'updateSx',\n 'move',\n 'remove',\n 'setSeo',\n 'rename',\n 'saveAsComponent',\n] as const\n\nexport type AssistEditOpKind = (typeof ASSIST_EDIT_OP_KINDS)[number]\n\n/** The id of the besigner view's edit action — the one edit a view offers. */\nexport const ASSIST_EDIT_ACTION_ID = 'edit.canvas'\n\n/** The name of the structured-output tool a model proposes an edit through. */\nexport const ASSIST_EDIT_TOOL_NAME = 'propose_canvas_edit'\n\n/** The besigner documents the edit rung opens on: those that keep versions. */\nexport type AssistEditDocumentKind = 'screen' | 'component' | 'layout'\n\nexport const ASSIST_EDIT_DOCUMENT_KINDS: readonly AssistEditDocumentKind[] = [\n 'screen',\n 'component',\n 'layout',\n]\n\nconst COLLECTION_KINDS: Readonly<Record<string, AssistEditDocumentKind>> = {\n screens: 'screen',\n components: 'component',\n layouts: 'layout',\n}\n\nconst BESIGNER_DOCUMENT_ROUTE =\n /^\\/[^/]+\\/hosts\\/[^/]+\\/(screens|components|layouts)\\/([A-Za-z0-9_-]{1,64})\\/versions\\/([A-Za-z0-9_-]{1,64})\\/besigner\\/?$/\n\n/** The document a besigner route has open. */\nexport interface AssistEditDocument {\n kind: AssistEditDocumentKind\n documentId: string\n versionId: string\n}\n\n/**\n * The open document off a console path, or null off a route the edit rung\n * serves. Only the versioned editors qualify — a template or an email editor\n * has no version to make first, so the rung does not open there.\n */\nexport function assistEditDocumentOf(route: string): AssistEditDocument | null {\n const match = BESIGNER_DOCUMENT_ROUTE.exec(String(route ?? ''))\n if (!match) return null\n return {\n kind: COLLECTION_KINDS[match[1]],\n documentId: match[2],\n versionId: match[3],\n }\n}\n\n/* ------------------------------------------------------------------ *\n * What the client tells the server about the canvas\n * ------------------------------------------------------------------ */\n\n/** Elements a request describes at most — the selection, its surroundings, its subtree. */\nexport const ASSIST_EDIT_CONTEXT_MAX_NODES = 60\n/** Props described per element at most. */\nexport const ASSIST_EDIT_CONTEXT_MAX_PROPS = 16\n/** Characters of a string prop the selected element carries into a request. */\nexport const ASSIST_EDIT_SELECTED_TEXT_CHARS = 400\n/** Characters of a string prop every other element carries. */\nexport const ASSIST_EDIT_OUTLINE_TEXT_CHARS = 80\n\n/**\n * One element of the canvas outline a request carries. Ids, component ids\n * and short primitive values only — never a stored document, never markup.\n */\nexport interface AssistEditCanvasNode {\n id: string\n componentId: string\n /** Null for the document root. */\n parentId: string | null\n /** Position among the parent's children. */\n index: number\n childCount: number\n /** The layer name, when the author gave it one. */\n name?: string\n /** Primitive props, strings shortened. */\n props?: Record<string, string | number | boolean>\n /** The element's own styles — carried for the selected element only. */\n sx?: Record<string, unknown>\n /**\n * Described by its place alone, without props: an element around the\n * selection, there so the model knows it exists and can ask for it.\n */\n brief?: boolean\n /**\n * An element described earlier whose contents this one's are built like,\n * the way the cards of a row are. Its own contents are left out.\n */\n like?: string\n}\n\nexport interface AssistEditCanvasContext {\n /** The element the author has selected, or null. */\n selectedId: string | null\n /**\n * Elements in the whole document, the root included, so the prompt can say\n * how much of it `nodes` leaves out. Absent from an outline sent by a panel\n * that predates it.\n */\n total?: number\n nodes: AssistEditCanvasNode[]\n}\n\n/* ------------------------------------------------------------------ *\n * What the server proposes\n * ------------------------------------------------------------------ */\n\n/** An element of a validated subtree, in the flat shape the canvas stores. */\nexport interface AssistEditNode {\n $id: string\n componentId: string\n pluginId?: string\n parentId: string | null\n nodes: string[]\n props: Record<string, unknown>\n sx?: Record<string, unknown>\n hidden?: boolean\n}\n\n/**\n * Every op that acts on an element names the component the server validated\n * it as, so the client can refuse an element that has changed since.\n */\ninterface AssistEditNodeOpBase {\n nodeId: string\n componentId: string\n}\n\nexport interface AssistEditInsertOp {\n op: 'insertSubtree'\n parentId: string\n /** The component the parent was validated as. */\n parentComponentId: string\n /** Position among the parent's children; null appends. */\n index: number | null\n rootId: string\n nodes: Record<string, AssistEditNode>\n}\n\nexport interface AssistEditUpdatePropsOp extends AssistEditNodeOpBase {\n op: 'updateProps'\n /** Merged over the props the element has; nothing else it carries changes. */\n props: Record<string, unknown>\n}\n\nexport interface AssistEditUpdateSxOp extends AssistEditNodeOpBase {\n op: 'updateSx'\n /** Merged over the element's own styles, one key at a time. */\n sx: Record<string, unknown>\n}\n\nexport interface AssistEditMoveOp extends AssistEditNodeOpBase {\n op: 'move'\n parentId: string\n /** The component the new parent was validated as. */\n parentComponentId: string\n index: number | null\n}\n\nexport interface AssistEditRemoveOp extends AssistEditNodeOpBase {\n op: 'remove'\n}\n\nexport interface AssistEditRenameOp extends AssistEditNodeOpBase {\n op: 'rename'\n name: string\n}\n\nexport interface AssistEditSetSeoOp {\n op: 'setSeo'\n fields: Partial<Record<ScreenSeoTextField, string>>\n}\n\n/**\n * A property the promoted subtree declares (AGL-2908), in the shape the\n * Properties dialog stores one — without a default.\n *\n * The server never sees a full value: the outline it read the selection from\n * shortens every string. So the default is read off the live canvas at apply\n * time, from the very field the token is about to replace, which is what\n * makes the instance render what was there a moment before.\n */\nexport type AssistEditComponentProp = Omit<ReusableComponentProp, 'defaultValue'>\n\n/** Where one property's token goes: an element of the selection, and a field of it. */\nexport interface AssistEditPropBinding {\n nodeId: string\n /** The component the element was validated as, so a changed one is refused. */\n componentId: string\n /** A prop of that element, or `hideIf` for a part a Yes / no hides. */\n field: string\n /** The property whose `{{prop.<name>}}` token the field takes. */\n prop: string\n}\n\n/**\n * Save the selection as a reusable component (AGL-2908), with the properties\n * the model proposed and the tokens bound into the tree.\n *\n * The only op that creates a document. It creates exactly the one the manual\n * Save as reusable component creates, through the same host resources route,\n * where the plan's entitlement and the route's allow-list are enforced — and\n * it changes the open canvas the same way that action does, by swapping the\n * promoted subtree for an instance. Nothing is published and nothing is\n * saved: the swap is an unsaved edit on the version the editor has open.\n */\nexport interface AssistEditSaveAsComponentOp extends AssistEditNodeOpBase {\n op: 'saveAsComponent'\n /** The name the component is created under. */\n name: string\n props: AssistEditComponentProp[]\n bindings: AssistEditPropBinding[]\n}\n\nexport type AssistEditOp =\n | AssistEditInsertOp\n | AssistEditUpdatePropsOp\n | AssistEditUpdateSxOp\n | AssistEditMoveOp\n | AssistEditRemoveOp\n | AssistEditRenameOp\n | AssistEditSetSeoOp\n | AssistEditSaveAsComponentOp\n\n/** Where a proposal applies, as the server read it off the request. */\nexport interface AssistEditTarget extends AssistEditDocument {\n hostId: string\n}\n\n/** The counts the card shows before the author decides. */\nexport interface AssistEditDiff {\n /** Elements added, every element of every inserted subtree counted. */\n added: number\n /** Elements removed — each with whatever it contains. */\n removed: number\n propsChanged: number\n stylesChanged: number\n moved: number\n renamed: number\n /** Search fields filled in. */\n seoFields: number\n /** Properties the selection declares once it is saved as a component. */\n componentProps: number\n /** Selections saved as a reusable component — at most one per proposal. */\n componentsSaved: number\n}\n\n/** The most reasons a proposal carries for the changes validation left out. */\nexport const ASSIST_EDIT_MAX_DROPPED_REASONS = 10\n\nexport interface AssistEditProposal {\n id: typeof ASSIST_EDIT_ACTION_ID\n /** One line, in the model's words, of what the edit does. */\n summary: string\n ops: AssistEditOp[]\n diff: AssistEditDiff\n /** Why each change the model wrote and validation refused was left out. */\n dropped: string[]\n target: AssistEditTarget\n}\n\n/** The counts for a list of ops. */\nexport function summarizeAssistEditOps(ops: readonly AssistEditOp[]): AssistEditDiff {\n const diff: AssistEditDiff = {\n added: 0,\n removed: 0,\n propsChanged: 0,\n stylesChanged: 0,\n moved: 0,\n renamed: 0,\n seoFields: 0,\n componentProps: 0,\n componentsSaved: 0,\n }\n for (const op of ops) {\n switch (op.op) {\n case 'insertSubtree':\n diff.added += Object.keys(op.nodes).length\n break\n case 'remove':\n diff.removed += 1\n break\n case 'updateProps':\n diff.propsChanged += 1\n break\n case 'updateSx':\n diff.stylesChanged += 1\n break\n case 'move':\n diff.moved += 1\n break\n case 'rename':\n diff.renamed += 1\n break\n case 'setSeo':\n diff.seoFields += Object.keys(op.fields).length\n break\n case 'saveAsComponent':\n diff.componentsSaved += 1\n diff.componentProps += op.props.length\n break\n }\n }\n return diff\n}\n\nconst plural = (count: number, one: string, many: string): string =>\n `${count} ${count === 1 ? one : many}`\n\n/** The diff as the lines a person reads, zero counts omitted. */\nexport function describeAssistEditDiff(diff: AssistEditDiff): string[] {\n const lines: string[] = []\n if (diff.added) lines.push(`${plural(diff.added, 'element', 'elements')} added`)\n if (diff.removed) lines.push(`${plural(diff.removed, 'element', 'elements')} removed`)\n if (diff.propsChanged) {\n lines.push(`${plural(diff.propsChanged, 'element’s settings', 'elements’ settings')} changed`)\n }\n if (diff.stylesChanged) {\n lines.push(`${plural(diff.stylesChanged, 'element', 'elements')} restyled`)\n }\n if (diff.moved) lines.push(`${plural(diff.moved, 'element', 'elements')} moved`)\n if (diff.renamed) lines.push(`${plural(diff.renamed, 'layer', 'layers')} renamed`)\n if (diff.seoFields) {\n lines.push(`${plural(diff.seoFields, 'search field', 'search fields')} filled in`)\n }\n if (diff.componentsSaved) {\n lines.push(\n `saved as a reusable component with ${plural(diff.componentProps, 'property', 'properties')}`,\n )\n }\n return lines\n}\n\n/** The word each op kind is counted under in the activity row. */\nconst OP_COUNT_WORDS: Readonly<Record<AssistEditOpKind, string>> = {\n updateProps: 'set',\n updateSx: 'restyle',\n insertSubtree: 'insert',\n move: 'move',\n remove: 'remove',\n rename: 'rename',\n setSeo: 'seo',\n saveAsComponent: 'component',\n}\n\n/** The applied ops counted by kind, as the activity row names them (`{ set: 3, insert: 1 }`). */\nexport function assistEditOpCounts(ops: readonly AssistEditOp[]): Record<string, number> {\n const counts: Record<string, number> = {}\n for (const op of ops) {\n const word = OP_COUNT_WORDS[op.op]\n if (word) counts[word] = (counts[word] ?? 0) + 1\n }\n return counts\n}\n\n/** The words `assistEditOpCounts` counts under, for a door that reads them back. */\nexport const ASSIST_EDIT_OP_COUNT_WORDS: readonly string[] = Object.values(OP_COUNT_WORDS)\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Whether a `done` event's `edit` field is a proposal this client can apply.\n * The server built it, so this is a shape check rather than a validation: it\n * keeps a malformed or foreign payload from reaching the canvas mutators.\n */\nexport function isAssistEditProposal(value: unknown): value is AssistEditProposal {\n if (!isRecord(value) || value['id'] !== ASSIST_EDIT_ACTION_ID) return false\n const target = value['target']\n if (!isRecord(target)) return false\n if (!ASSIST_EDIT_DOCUMENT_KINDS.includes(target['kind'] as AssistEditDocumentKind)) return false\n if (typeof target['documentId'] !== 'string' || !target['documentId']) return false\n const ops = value['ops']\n if (!Array.isArray(ops) || !ops.length) return false\n return ops.every(\n (op) => isRecord(op) && ASSIST_EDIT_OP_KINDS.includes(op['op'] as AssistEditOpKind),\n )\n}\n\n/* ------------------------------------------------------------------ *\n * What the client reports once the author applied a proposal\n * ------------------------------------------------------------------ */\n\n/** The body of `POST /api/assist/edit-applied`. */\nexport interface AssistEditAppliedReport {\n orgId: string\n hostId: string\n /** The exchange whose answer carried the proposal. */\n exchangeId: string\n documentKind: AssistEditDocumentKind\n documentId: string\n /** The version the edits landed on — a new one when the open one was live. */\n versionId: string\n opCounts: Record<string, number>\n}\n"],"names":["ASSIST_EDIT_OP_KINDS","ASSIST_EDIT_ACTION_ID","ASSIST_EDIT_TOOL_NAME","ASSIST_EDIT_DOCUMENT_KINDS","COLLECTION_KINDS","screens","components","layouts","BESIGNER_DOCUMENT_ROUTE","assistEditDocumentOf","route","match","exec","String","kind","documentId","versionId","ASSIST_EDIT_CONTEXT_MAX_NODES","ASSIST_EDIT_CONTEXT_MAX_PROPS","ASSIST_EDIT_SELECTED_TEXT_CHARS","ASSIST_EDIT_OUTLINE_TEXT_CHARS","ASSIST_EDIT_MAX_DROPPED_REASONS","summarizeAssistEditOps","ops","diff","added","removed","propsChanged","stylesChanged","moved","renamed","seoFields","componentProps","componentsSaved","op","Object","keys","nodes","length","fields","props","plural","count","one","many","describeAssistEditDiff","lines","push","OP_COUNT_WORDS","updateProps","updateSx","insertSubtree","move","remove","rename","setSeo","saveAsComponent","assistEditOpCounts","counts","word","ASSIST_EDIT_OP_COUNT_WORDS","values","isRecord","value","Array","isArray","isAssistEditProposal","target","includes","every"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/assist-edit.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ScreenSeoTextField } from '@aglyn/aglyn/app-utils/screen-seo-fields'\nimport type { ReusableComponentProp } from '@aglyn/aglyn/foundation/definitions/platform.types'\nimport type { NodeInteraction } from '@aglyn/aglyn/app-utils/node-interactions'\n\n/**\n * Assist level 3, the edit contract (AGL-2906): what the chat door proposes\n * for a besigner canvas, and what the panel applies once the author says so.\n *\n * Shared by the server, which validates a model's proposal into these\n * shapes, and the client, which applies them. Pure data and pure functions,\n * so the panel imports it without pulling the palette or the runtime.\n *\n * ## The boundary\n *\n * A proposal is OPERATIONS, never a document. The server writes nothing: it\n * answers with ops that name elements already on the canvas, or a validated\n * subtree to insert, and the client applies them through the canvas's own\n * guarded mutators, on confirm, as one undoable step. Every change lands as\n * an unsaved edit on the version the editor has open — a draft — and on a\n * version the live site serves, the editor's own new-version flow runs first.\n */\n\n/** The nine operations a proposal may carry. */\nexport const ASSIST_EDIT_OP_KINDS = [\n 'insertSubtree',\n 'updateProps',\n 'updateSx',\n 'move',\n 'remove',\n 'setSeo',\n 'rename',\n 'saveAsComponent',\n 'addInteraction',\n] as const\n\nexport type AssistEditOpKind = (typeof ASSIST_EDIT_OP_KINDS)[number]\n\n/** The id of the besigner view's edit action — the one edit a view offers. */\nexport const ASSIST_EDIT_ACTION_ID = 'edit.canvas'\n\n/** The name of the structured-output tool a model proposes an edit through. */\nexport const ASSIST_EDIT_TOOL_NAME = 'propose_canvas_edit'\n\n/** The besigner documents the edit rung opens on: those that keep versions. */\nexport type AssistEditDocumentKind = 'screen' | 'component' | 'layout'\n\nexport const ASSIST_EDIT_DOCUMENT_KINDS: readonly AssistEditDocumentKind[] = [\n 'screen',\n 'component',\n 'layout',\n]\n\nconst COLLECTION_KINDS: Readonly<Record<string, AssistEditDocumentKind>> = {\n screens: 'screen',\n components: 'component',\n layouts: 'layout',\n}\n\nconst BESIGNER_DOCUMENT_ROUTE =\n /^\\/[^/]+\\/hosts\\/[^/]+\\/(screens|components|layouts)\\/([A-Za-z0-9_-]{1,64})\\/versions\\/([A-Za-z0-9_-]{1,64})\\/besigner\\/?$/\n\n/** The document a besigner route has open. */\nexport interface AssistEditDocument {\n kind: AssistEditDocumentKind\n documentId: string\n versionId: string\n}\n\n/**\n * The open document off a console path, or null off a route the edit rung\n * serves. Only the versioned editors qualify — a template or an email editor\n * has no version to make first, so the rung does not open there.\n */\nexport function assistEditDocumentOf(route: string): AssistEditDocument | null {\n const match = BESIGNER_DOCUMENT_ROUTE.exec(String(route ?? ''))\n if (!match) return null\n return {\n kind: COLLECTION_KINDS[match[1]],\n documentId: match[2],\n versionId: match[3],\n }\n}\n\n/* ------------------------------------------------------------------ *\n * What the client tells the server about the canvas\n * ------------------------------------------------------------------ */\n\n/** Elements a request describes at most — the selection, its surroundings, its subtree. */\nexport const ASSIST_EDIT_CONTEXT_MAX_NODES = 60\n/** Props described per element at most. */\nexport const ASSIST_EDIT_CONTEXT_MAX_PROPS = 16\n/** Characters of a string prop the selected element carries into a request. */\nexport const ASSIST_EDIT_SELECTED_TEXT_CHARS = 400\n/** Characters of a string prop every other element carries. */\nexport const ASSIST_EDIT_OUTLINE_TEXT_CHARS = 80\n\n/**\n * One element of the canvas outline a request carries. Ids, component ids\n * and short primitive values only — never a stored document, never markup.\n */\nexport interface AssistEditCanvasNode {\n id: string\n componentId: string\n /** Null for the document root. */\n parentId: string | null\n /** Position among the parent's children. */\n index: number\n childCount: number\n /** The layer name, when the author gave it one. */\n name?: string\n /** Primitive props, strings shortened. */\n props?: Record<string, string | number | boolean>\n /** The element's own styles — carried for the selected element only. */\n sx?: Record<string, unknown>\n /**\n * Described by its place alone, without props: an element around the\n * selection, there so the model knows it exists and can ask for it.\n */\n brief?: boolean\n /**\n * An element described earlier whose contents this one's are built like,\n * the way the cards of a row are. Its own contents are left out.\n */\n like?: string\n /**\n * The interactions the element carries (AGL-3603), each by its name, the\n * event it listens for and its steps' kinds — carried for the selected\n * element only, so Assist can say what it does. Never a selector, a script\n * or HTML.\n */\n interactions?: AssistEditInteractionSummary[]\n}\n\n/** One interaction on an element, as an outline describes it. */\nexport interface AssistEditInteractionSummary {\n name: string\n event: string\n steps: string[]\n enabled: boolean\n}\n\n/* ------------------------------------------------------------------ *\n * The interactions Assist may add (AGL-3603)\n * ------------------------------------------------------------------ */\n\n/**\n * The events an interaction Assist adds may listen for: those that watch the\n * element it is added to, the way the Besigner's Interactions section offers\n * them on a selected element.\n */\nexport const ASSIST_EDIT_INTERACTION_EVENTS = [\n 'elementClick',\n 'elementHoverEnter',\n 'elementHoverLeave',\n 'elementVisible',\n 'scrollToElement',\n] as const\n\nexport type AssistEditInteractionEvent = (typeof ASSIST_EDIT_INTERACTION_EVENTS)[number]\n\n/**\n * The steps it may take: the platform's basic presentational client steps,\n * which run on every plan and touch no data. No script, no HTML, no\n * attribute, no overlay, no analytics event — and no server step.\n */\nexport const ASSIST_EDIT_INTERACTION_STEPS = [\n 'showElement',\n 'hideElement',\n 'toggleElement',\n 'addClass',\n 'removeClass',\n 'toggleClass',\n 'scrollTo',\n 'playVideo',\n 'openDrawer',\n 'closeDrawer',\n 'toggleDrawer',\n 'openMenu',\n 'closeMenu',\n 'toggleMenu',\n 'redirect',\n 'siteAlert',\n] as const\n\nexport type AssistEditInteractionStep = (typeof ASSIST_EDIT_INTERACTION_STEPS)[number]\n\nexport interface AssistEditCanvasContext {\n /** The element the author has selected, or null. */\n selectedId: string | null\n /**\n * Elements in the whole document, the root included, so the prompt can say\n * how much of it `nodes` leaves out. Absent from an outline sent by a panel\n * that predates it.\n */\n total?: number\n nodes: AssistEditCanvasNode[]\n}\n\n/* ------------------------------------------------------------------ *\n * What the server proposes\n * ------------------------------------------------------------------ */\n\n/** An element of a validated subtree, in the flat shape the canvas stores. */\nexport interface AssistEditNode {\n $id: string\n componentId: string\n pluginId?: string\n parentId: string | null\n nodes: string[]\n props: Record<string, unknown>\n sx?: Record<string, unknown>\n hidden?: boolean\n}\n\n/**\n * Every op that acts on an element names the component the server validated\n * it as, so the client can refuse an element that has changed since.\n */\ninterface AssistEditNodeOpBase {\n nodeId: string\n componentId: string\n}\n\nexport interface AssistEditInsertOp {\n op: 'insertSubtree'\n parentId: string\n /** The component the parent was validated as. */\n parentComponentId: string\n /** Position among the parent's children; null appends. */\n index: number | null\n rootId: string\n nodes: Record<string, AssistEditNode>\n}\n\nexport interface AssistEditUpdatePropsOp extends AssistEditNodeOpBase {\n op: 'updateProps'\n /** Merged over the props the element has; nothing else it carries changes. */\n props: Record<string, unknown>\n}\n\nexport interface AssistEditUpdateSxOp extends AssistEditNodeOpBase {\n op: 'updateSx'\n /** Merged over the element's own styles, one key at a time. */\n sx: Record<string, unknown>\n}\n\nexport interface AssistEditMoveOp extends AssistEditNodeOpBase {\n op: 'move'\n parentId: string\n /** The component the new parent was validated as. */\n parentComponentId: string\n index: number | null\n}\n\nexport interface AssistEditRemoveOp extends AssistEditNodeOpBase {\n op: 'remove'\n}\n\nexport interface AssistEditRenameOp extends AssistEditNodeOpBase {\n op: 'rename'\n name: string\n}\n\nexport interface AssistEditSetSeoOp {\n op: 'setSeo'\n fields: Partial<Record<ScreenSeoTextField, string>>\n}\n\n/**\n * A property the promoted subtree declares (AGL-2908), in the shape the\n * Properties dialog stores one — without a default.\n *\n * The server never sees a full value: the outline it read the selection from\n * shortens every string. So the default is read off the live canvas at apply\n * time, from the very field the token is about to replace, which is what\n * makes the instance render what was there a moment before.\n */\nexport type AssistEditComponentProp = Omit<ReusableComponentProp, 'defaultValue'>\n\n/** Where one property's token goes: an element of the selection, and a field of it. */\nexport interface AssistEditPropBinding {\n nodeId: string\n /** The component the element was validated as, so a changed one is refused. */\n componentId: string\n /** A prop of that element, or `hideIf` for a part a Yes / no hides. */\n field: string\n /** The property whose `{{prop.<name>}}` token the field takes. */\n prop: string\n}\n\n/**\n * Save the selection as a reusable component (AGL-2908), with the properties\n * the model proposed and the tokens bound into the tree.\n *\n * The only op that creates a document. It creates exactly the one the manual\n * Save as reusable component creates, through the same host resources route,\n * where the plan's entitlement and the route's allow-list are enforced — and\n * it changes the open canvas the same way that action does, by swapping the\n * promoted subtree for an instance. Nothing is published and nothing is\n * saved: the swap is an unsaved edit on the version the editor has open.\n */\nexport interface AssistEditSaveAsComponentOp extends AssistEditNodeOpBase {\n op: 'saveAsComponent'\n /** The name the component is created under. */\n name: string\n props: AssistEditComponentProp[]\n bindings: AssistEditPropBinding[]\n}\n\n/**\n * Add one interaction to an element (AGL-3603), in the shape the element\n * stores it — its trigger with no selector, which the element's id derives.\n * It never replaces or removes one the element already carries.\n */\nexport interface AssistEditAddInteractionOp extends AssistEditNodeOpBase {\n op: 'addInteraction'\n interaction: NodeInteraction\n /** Every other element a step acts on, each with the component it was validated as. */\n targets: Array<{ nodeId: string; componentId: string }>\n}\n\nexport type AssistEditOp =\n | AssistEditAddInteractionOp\n | AssistEditInsertOp\n | AssistEditUpdatePropsOp\n | AssistEditUpdateSxOp\n | AssistEditMoveOp\n | AssistEditRemoveOp\n | AssistEditRenameOp\n | AssistEditSetSeoOp\n | AssistEditSaveAsComponentOp\n\n/** Where a proposal applies, as the server read it off the request. */\nexport interface AssistEditTarget extends AssistEditDocument {\n hostId: string\n}\n\n/** The counts the card shows before the author decides. */\nexport interface AssistEditDiff {\n /** Elements added, every element of every inserted subtree counted. */\n added: number\n /** Elements removed — each with whatever it contains. */\n removed: number\n propsChanged: number\n stylesChanged: number\n moved: number\n renamed: number\n /** Search fields filled in. */\n seoFields: number\n /** Properties the selection declares once it is saved as a component. */\n componentProps: number\n /** Selections saved as a reusable component — at most one per proposal. */\n componentsSaved: number\n /** Interactions added to elements. */\n interactionsAdded: number\n}\n\n/** The most reasons a proposal carries for the changes validation left out. */\nexport const ASSIST_EDIT_MAX_DROPPED_REASONS = 10\n\nexport interface AssistEditProposal {\n id: typeof ASSIST_EDIT_ACTION_ID\n /** One line, in the model's words, of what the edit does. */\n summary: string\n ops: AssistEditOp[]\n diff: AssistEditDiff\n /** Why each change the model wrote and validation refused was left out. */\n dropped: string[]\n target: AssistEditTarget\n}\n\n/** The counts for a list of ops. */\nexport function summarizeAssistEditOps(ops: readonly AssistEditOp[]): AssistEditDiff {\n const diff: AssistEditDiff = {\n added: 0,\n removed: 0,\n propsChanged: 0,\n stylesChanged: 0,\n moved: 0,\n renamed: 0,\n seoFields: 0,\n componentProps: 0,\n componentsSaved: 0,\n interactionsAdded: 0,\n }\n for (const op of ops) {\n switch (op.op) {\n case 'insertSubtree':\n diff.added += Object.keys(op.nodes).length\n break\n case 'remove':\n diff.removed += 1\n break\n case 'updateProps':\n diff.propsChanged += 1\n break\n case 'updateSx':\n diff.stylesChanged += 1\n break\n case 'move':\n diff.moved += 1\n break\n case 'rename':\n diff.renamed += 1\n break\n case 'setSeo':\n diff.seoFields += Object.keys(op.fields).length\n break\n case 'saveAsComponent':\n diff.componentsSaved += 1\n diff.componentProps += op.props.length\n break\n case 'addInteraction':\n diff.interactionsAdded += 1\n break\n }\n }\n return diff\n}\n\nconst plural = (count: number, one: string, many: string): string =>\n `${count} ${count === 1 ? one : many}`\n\n/** The diff as the lines a person reads, zero counts omitted. */\nexport function describeAssistEditDiff(diff: AssistEditDiff): string[] {\n const lines: string[] = []\n if (diff.added) lines.push(`${plural(diff.added, 'element', 'elements')} added`)\n if (diff.removed) lines.push(`${plural(diff.removed, 'element', 'elements')} removed`)\n if (diff.propsChanged) {\n lines.push(`${plural(diff.propsChanged, 'element’s settings', 'elements’ settings')} changed`)\n }\n if (diff.stylesChanged) {\n lines.push(`${plural(diff.stylesChanged, 'element', 'elements')} restyled`)\n }\n if (diff.moved) lines.push(`${plural(diff.moved, 'element', 'elements')} moved`)\n if (diff.renamed) lines.push(`${plural(diff.renamed, 'layer', 'layers')} renamed`)\n if (diff.seoFields) {\n lines.push(`${plural(diff.seoFields, 'search field', 'search fields')} filled in`)\n }\n if (diff.interactionsAdded) {\n lines.push(`${plural(diff.interactionsAdded, 'interaction', 'interactions')} added`)\n }\n if (diff.componentsSaved) {\n lines.push(\n `saved as a reusable component with ${plural(diff.componentProps, 'property', 'properties')}`,\n )\n }\n return lines\n}\n\n/** The word each op kind is counted under in the activity row. */\nconst OP_COUNT_WORDS: Readonly<Record<AssistEditOpKind, string>> = {\n updateProps: 'set',\n updateSx: 'restyle',\n insertSubtree: 'insert',\n move: 'move',\n remove: 'remove',\n rename: 'rename',\n setSeo: 'seo',\n saveAsComponent: 'component',\n addInteraction: 'interaction',\n}\n\n/** The applied ops counted by kind, as the activity row names them (`{ set: 3, insert: 1 }`). */\nexport function assistEditOpCounts(ops: readonly AssistEditOp[]): Record<string, number> {\n const counts: Record<string, number> = {}\n for (const op of ops) {\n const word = OP_COUNT_WORDS[op.op]\n if (word) counts[word] = (counts[word] ?? 0) + 1\n }\n return counts\n}\n\n/** The words `assistEditOpCounts` counts under, for a door that reads them back. */\nexport const ASSIST_EDIT_OP_COUNT_WORDS: readonly string[] = Object.values(OP_COUNT_WORDS)\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Whether a `done` event's `edit` field is a proposal this client can apply.\n * The server built it, so this is a shape check rather than a validation: it\n * keeps a malformed or foreign payload from reaching the canvas mutators.\n */\nexport function isAssistEditProposal(value: unknown): value is AssistEditProposal {\n if (!isRecord(value) || value['id'] !== ASSIST_EDIT_ACTION_ID) return false\n const target = value['target']\n if (!isRecord(target)) return false\n if (!ASSIST_EDIT_DOCUMENT_KINDS.includes(target['kind'] as AssistEditDocumentKind)) return false\n if (typeof target['documentId'] !== 'string' || !target['documentId']) return false\n const ops = value['ops']\n if (!Array.isArray(ops) || !ops.length) return false\n return ops.every(\n (op) => isRecord(op) && ASSIST_EDIT_OP_KINDS.includes(op['op'] as AssistEditOpKind),\n )\n}\n\n/* ------------------------------------------------------------------ *\n * What the client reports once the author applied a proposal\n * ------------------------------------------------------------------ */\n\n/** The body of `POST /api/assist/edit-applied`. */\nexport interface AssistEditAppliedReport {\n orgId: string\n hostId: string\n /** The exchange whose answer carried the proposal. */\n exchangeId: string\n documentKind: AssistEditDocumentKind\n documentId: string\n /** The version the edits landed on — a new one when the open one was live. */\n versionId: string\n opCounts: Record<string, number>\n}\n"],"names":["ASSIST_EDIT_OP_KINDS","ASSIST_EDIT_ACTION_ID","ASSIST_EDIT_TOOL_NAME","ASSIST_EDIT_DOCUMENT_KINDS","COLLECTION_KINDS","screens","components","layouts","BESIGNER_DOCUMENT_ROUTE","assistEditDocumentOf","route","match","exec","String","kind","documentId","versionId","ASSIST_EDIT_CONTEXT_MAX_NODES","ASSIST_EDIT_CONTEXT_MAX_PROPS","ASSIST_EDIT_SELECTED_TEXT_CHARS","ASSIST_EDIT_OUTLINE_TEXT_CHARS","ASSIST_EDIT_INTERACTION_EVENTS","ASSIST_EDIT_INTERACTION_STEPS","ASSIST_EDIT_MAX_DROPPED_REASONS","summarizeAssistEditOps","ops","diff","added","removed","propsChanged","stylesChanged","moved","renamed","seoFields","componentProps","componentsSaved","interactionsAdded","op","Object","keys","nodes","length","fields","props","plural","count","one","many","describeAssistEditDiff","lines","push","OP_COUNT_WORDS","updateProps","updateSx","insertSubtree","move","remove","rename","setSeo","saveAsComponent","addInteraction","assistEditOpCounts","counts","word","ASSIST_EDIT_OP_COUNT_WORDS","values","isRecord","value","Array","isArray","isAssistEditProposal","target","includes","every"],"mappings":"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"}
|
package/src/lib/plugin-config.js
CHANGED
|
@@ -38,6 +38,7 @@ import { AI_CATALOG_PROVIDERS, AI_MODEL_CATALOG } from "./providers/catalog.js";
|
|
|
38
38
|
'job.form': 'jobFormModel',
|
|
39
39
|
'job.insight': 'jobInsightModel',
|
|
40
40
|
'job.layout': 'jobLayoutModel',
|
|
41
|
+
'job.logic': 'jobLogicModel',
|
|
41
42
|
'job.template': 'jobTemplateModel',
|
|
42
43
|
'job.page': 'jobPageModel',
|
|
43
44
|
'job.products': 'jobProductsModel',
|
|
@@ -96,6 +97,7 @@ export const AI_CONFIG_SCHEMA = {
|
|
|
96
97
|
modelField('job.form', 'Generation job (form) model', 'Generating a form from a confirmed plan.'),
|
|
97
98
|
modelField('job.insight', 'Insights model', 'Answering a question about the site’s figures, and the weekly insights.'),
|
|
98
99
|
modelField('job.layout', 'Generation job (layout) model', 'Generating a shared layout from a confirmed plan.'),
|
|
100
|
+
modelField('job.logic', 'Generation job (logic) model', 'Proposing a site function or variable, and explaining a function.'),
|
|
99
101
|
modelField('job.template', 'Generation job (template) model', 'Generating a page template from a confirmed plan.'),
|
|
100
102
|
modelField('job.page', 'Generation job (page) model', 'Generating a page, one section at a time, from a confirmed plan.'),
|
|
101
103
|
modelField('job.products', 'Generation job (products) model', 'Writing product copy, and proposing products, categories and discounts for a store.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/plugin-config.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PluginConfigSchema } from '@aglyn/aglyn'\nimport { AI_PLUGIN_SETTINGS_ID } from './constants'\nimport { AI_CATALOG_PROVIDERS, AI_MODEL_CATALOG, type AiStepKind } from './providers/catalog'\n\n/**\n * The org's AI settings (AGL-2939), stored in `pluginSettings/ai` and\n * inherited per site the way every plugin setting is (AGL-428): which\n * provider serves the workspace, and which catalog model each kind of step\n * runs on. `platform` means \"whatever the deployment's environment says\",\n * which is what every workspace runs with until it chooses.\n *\n * PURE DATA (type-only aglyn import): the client barrel registers it via\n * '@aglyn/aglyn' and the /server entry via '@aglyn/aglyn/server'.\n */\n\n/** The value that defers to the deployment's environment. */\nexport const AI_SETTING_PLATFORM = 'platform'\n\n/** The setting key each step kind's model override is stored under. */\nexport const AI_STEP_MODEL_SETTING: Record<AiStepKind, string> = {\n 'assist.chat': 'chatModel',\n 'copy.element': 'copyElementModel',\n 'copy.section': 'copySectionModel',\n 'copy.blog': 'copyBlogModel',\n 'generate.section': 'generateModel',\n 'job.component': 'jobComponentModel',\n 'job.crm': 'jobCrmModel',\n 'job.experiment': 'jobExperimentModel',\n 'job.form': 'jobFormModel',\n 'job.insight': 'jobInsightModel',\n 'job.layout': 'jobLayoutModel',\n 'job.template': 'jobTemplateModel',\n 'job.page': 'jobPageModel',\n 'job.products': 'jobProductsModel',\n 'job.seo': 'jobSeoModel',\n 'job.text': 'jobTextModel',\n 'job.theme': 'jobThemeModel',\n 'job.plan': 'jobPlanModel',\n 'job.email': 'jobEmailModel',\n 'job.campaign': 'jobCampaignModel',\n 'job.workflow': 'jobWorkflowModel',\n}\n\nconst MODEL_OPTIONS = [\n { value: AI_SETTING_PLATFORM, label: 'Platform default' },\n ...AI_MODEL_CATALOG.map((entry) => ({\n value: entry.id,\n label: `${entry.label} (${entry.provider})`,\n })),\n]\n\nconst modelField = (kind: AiStepKind, label: string, description: string) => ({\n key: AI_STEP_MODEL_SETTING[kind],\n label,\n type: 'select' as const,\n options: MODEL_OPTIONS,\n description,\n})\n\nexport const AI_CONFIG_SCHEMA: PluginConfigSchema = {\n pluginId: AI_PLUGIN_SETTINGS_ID,\n fields: [\n {\n key: 'provider',\n label: 'AI provider',\n type: 'select',\n options: [\n { value: AI_SETTING_PLATFORM, label: 'Platform default' },\n ...AI_CATALOG_PROVIDERS.map((provider) => ({ value: provider.id, label: provider.label })),\n ],\n description:\n 'Which provider answers this workspace. A model chosen below must ' +\n 'be one the provider serves; otherwise the provider’s default for ' +\n 'that kind of step is used.',\n },\n modelField('assist.chat', 'Assistant model', 'The in-console assistant’s answers.'),\n modelField('copy.element', 'Copy assistant (element) model', 'Rewriting one element’s text.'),\n modelField('copy.section', 'Copy assistant (section) model', 'Writing a section’s copy.'),\n modelField('copy.blog', 'Copy assistant (blog) model', 'Drafting a blog post.'),\n modelField('generate.section', 'Section generation model', 'Generating a section’s structure.'),\n modelField('job.component', 'Generation job (component) model', 'Generating a reusable component and its properties.'),\n modelField('job.crm', 'Generation job (CRM) model', 'CRM record summaries and next steps, email drafts and import column matches.'),\n modelField(\n 'job.experiment',\n 'Generation job (A/B test) model',\n 'Writing variants for an A/B test, and explaining what a test’s result means.',\n ),\n modelField('job.form', 'Generation job (form) model', 'Generating a form from a confirmed plan.'),\n modelField('job.insight', 'Insights model', 'Answering a question about the site’s figures, and the weekly insights.'),\n modelField('job.layout', 'Generation job (layout) model', 'Generating a shared layout from a confirmed plan.'),\n modelField('job.template', 'Generation job (template) model', 'Generating a page template from a confirmed plan.'),\n modelField('job.page', 'Generation job (page) model', 'Generating a page, one section at a time, from a confirmed plan.'),\n modelField('job.products', 'Generation job (products) model', 'Writing product copy, and proposing products, categories and discounts for a store.'),\n modelField('job.seo', 'Generation job (SEO) model', 'Search listings, image descriptions and a site audit’s fixes.'),\n modelField('job.text', 'Generation job (text) model', 'The text step of a generation job.'),\n modelField('job.theme', 'Generation job (theme) model', 'Proposing a change to a site’s theme.'),\n modelField('job.plan', 'Generation job (plan) model', 'The plan step of a generation job.'),\n modelField('job.email', 'Generation job (email) model', 'Generating an email design from a confirmed plan.'),\n modelField('job.campaign', 'Generation job (campaign) model', 'Drafting a campaign and its email from a brief.'),\n modelField('job.workflow', 'Generation job (automation) model', 'Drafting an automation from a description, and explaining one.'),\n ],\n defaults: {\n provider: AI_SETTING_PLATFORM,\n ...Object.fromEntries(\n Object.values(AI_STEP_MODEL_SETTING).map((key) => [key, AI_SETTING_PLATFORM]),\n ),\n },\n}\n"],"names":["AI_PLUGIN_SETTINGS_ID","AI_CATALOG_PROVIDERS","AI_MODEL_CATALOG","AI_SETTING_PLATFORM","AI_STEP_MODEL_SETTING","MODEL_OPTIONS","value","label","map","entry","id","provider","modelField","kind","description","key","type","options","AI_CONFIG_SCHEMA","pluginId","fields","defaults","Object","fromEntries","values"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SAASA,qBAAqB,QAAQ,iBAAa;AACnD,SAASC,oBAAoB,EAAEC,gBAAgB,QAAyB,yBAAqB;AAE7F;;;;;;;;;CASC,GAED,2DAA2D,GAC3D,OAAO,MAAMC,sBAAsB,WAAU;AAE7C,qEAAqE,GACrE,OAAO,MAAMC,wBAAoD;IAC/D,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,oBAAoB;IACpB,iBAAiB;IACjB,WAAW;IACX,kBAAkB;IAClB,YAAY;IACZ,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,YAAY;IACZ,gBAAgB;IAChB,WAAW;IACX,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,aAAa;IACb,gBAAgB;IAChB,gBAAgB;AAClB,EAAC;AAED,MAAMC,gBAAgB;IACpB;QAAEC,OAAOH;QAAqBI,OAAO;IAAmB;OACrDL,iBAAiBM,GAAG,CAAC,CAACC,QAAW,CAAA;YAClCH,OAAOG,MAAMC,EAAE;YACfH,OAAO,GAAGE,MAAMF,KAAK,CAAC,EAAE,EAAEE,MAAME,QAAQ,CAAC,CAAC,CAAC;QAC7C,CAAA;CACD;AAED,MAAMC,aAAa,CAACC,MAAkBN,OAAeO,cAAyB,CAAA;QAC5EC,KAAKX,qBAAqB,CAACS,KAAK;QAChCN;QACAS,MAAM;QACNC,SAASZ;QACTS;IACF,CAAA;AAEA,OAAO,MAAMI,mBAAuC;IAClDC,UAAUnB;IACVoB,QAAQ;QACN;YACEL,KAAK;YACLR,OAAO;YACPS,MAAM;YACNC,SAAS;gBACP;oBAAEX,OAAOH;oBAAqBI,OAAO;gBAAmB;mBACrDN,qBAAqBO,GAAG,CAAC,CAACG,WAAc,CAAA;wBAAEL,OAAOK,SAASD,EAAE;wBAAEH,OAAOI,SAASJ,KAAK;oBAAC,CAAA;aACxF;YACDO,aACE,sEACA,sEACA;QACJ;QACAF,WAAW,eAAe,mBAAmB;QAC7CA,WAAW,gBAAgB,kCAAkC;QAC7DA,WAAW,gBAAgB,kCAAkC;QAC7DA,WAAW,aAAa,+BAA+B;QACvDA,WAAW,oBAAoB,4BAA4B;QAC3DA,WAAW,iBAAiB,oCAAoC;QAChEA,WAAW,WAAW,8BAA8B;QACpDA,WACE,kBACA,mCACA;QAEFA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,eAAe,kBAAkB;QAC5CA,WAAW,cAAc,iCAAiC;QAC1DA,WAAW,gBAAgB,mCAAmC;QAC9DA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,gBAAgB,mCAAmC;QAC9DA,WAAW,WAAW,8BAA8B;QACpDA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,aAAa,gCAAgC;QACxDA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,aAAa,gCAAgC;QACxDA,WAAW,gBAAgB,mCAAmC;QAC9DA,WAAW,gBAAgB,qCAAqC;KACjE;IACDS,UAAU;QACRV,UAAUR;OACPmB,OAAOC,WAAW,CACnBD,OAAOE,MAAM,CAACpB,uBAAuBI,GAAG,CAAC,CAACO,MAAQ;YAACA;YAAKZ;SAAoB;AAGlF,EAAC"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/plugin-config.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PluginConfigSchema } from '@aglyn/aglyn'\nimport { AI_PLUGIN_SETTINGS_ID } from './constants'\nimport { AI_CATALOG_PROVIDERS, AI_MODEL_CATALOG, type AiStepKind } from './providers/catalog'\n\n/**\n * The org's AI settings (AGL-2939), stored in `pluginSettings/ai` and\n * inherited per site the way every plugin setting is (AGL-428): which\n * provider serves the workspace, and which catalog model each kind of step\n * runs on. `platform` means \"whatever the deployment's environment says\",\n * which is what every workspace runs with until it chooses.\n *\n * PURE DATA (type-only aglyn import): the client barrel registers it via\n * '@aglyn/aglyn' and the /server entry via '@aglyn/aglyn/server'.\n */\n\n/** The value that defers to the deployment's environment. */\nexport const AI_SETTING_PLATFORM = 'platform'\n\n/** The setting key each step kind's model override is stored under. */\nexport const AI_STEP_MODEL_SETTING: Record<AiStepKind, string> = {\n 'assist.chat': 'chatModel',\n 'copy.element': 'copyElementModel',\n 'copy.section': 'copySectionModel',\n 'copy.blog': 'copyBlogModel',\n 'generate.section': 'generateModel',\n 'job.component': 'jobComponentModel',\n 'job.crm': 'jobCrmModel',\n 'job.experiment': 'jobExperimentModel',\n 'job.form': 'jobFormModel',\n 'job.insight': 'jobInsightModel',\n 'job.layout': 'jobLayoutModel',\n 'job.logic': 'jobLogicModel',\n 'job.template': 'jobTemplateModel',\n 'job.page': 'jobPageModel',\n 'job.products': 'jobProductsModel',\n 'job.seo': 'jobSeoModel',\n 'job.text': 'jobTextModel',\n 'job.theme': 'jobThemeModel',\n 'job.plan': 'jobPlanModel',\n 'job.email': 'jobEmailModel',\n 'job.campaign': 'jobCampaignModel',\n 'job.workflow': 'jobWorkflowModel',\n}\n\nconst MODEL_OPTIONS = [\n { value: AI_SETTING_PLATFORM, label: 'Platform default' },\n ...AI_MODEL_CATALOG.map((entry) => ({\n value: entry.id,\n label: `${entry.label} (${entry.provider})`,\n })),\n]\n\nconst modelField = (kind: AiStepKind, label: string, description: string) => ({\n key: AI_STEP_MODEL_SETTING[kind],\n label,\n type: 'select' as const,\n options: MODEL_OPTIONS,\n description,\n})\n\nexport const AI_CONFIG_SCHEMA: PluginConfigSchema = {\n pluginId: AI_PLUGIN_SETTINGS_ID,\n fields: [\n {\n key: 'provider',\n label: 'AI provider',\n type: 'select',\n options: [\n { value: AI_SETTING_PLATFORM, label: 'Platform default' },\n ...AI_CATALOG_PROVIDERS.map((provider) => ({ value: provider.id, label: provider.label })),\n ],\n description:\n 'Which provider answers this workspace. A model chosen below must ' +\n 'be one the provider serves; otherwise the provider’s default for ' +\n 'that kind of step is used.',\n },\n modelField('assist.chat', 'Assistant model', 'The in-console assistant’s answers.'),\n modelField('copy.element', 'Copy assistant (element) model', 'Rewriting one element’s text.'),\n modelField('copy.section', 'Copy assistant (section) model', 'Writing a section’s copy.'),\n modelField('copy.blog', 'Copy assistant (blog) model', 'Drafting a blog post.'),\n modelField('generate.section', 'Section generation model', 'Generating a section’s structure.'),\n modelField('job.component', 'Generation job (component) model', 'Generating a reusable component and its properties.'),\n modelField('job.crm', 'Generation job (CRM) model', 'CRM record summaries and next steps, email drafts and import column matches.'),\n modelField(\n 'job.experiment',\n 'Generation job (A/B test) model',\n 'Writing variants for an A/B test, and explaining what a test’s result means.',\n ),\n modelField('job.form', 'Generation job (form) model', 'Generating a form from a confirmed plan.'),\n modelField('job.insight', 'Insights model', 'Answering a question about the site’s figures, and the weekly insights.'),\n modelField('job.layout', 'Generation job (layout) model', 'Generating a shared layout from a confirmed plan.'),\n modelField('job.logic', 'Generation job (logic) model', 'Proposing a site function or variable, and explaining a function.'),\n modelField('job.template', 'Generation job (template) model', 'Generating a page template from a confirmed plan.'),\n modelField('job.page', 'Generation job (page) model', 'Generating a page, one section at a time, from a confirmed plan.'),\n modelField('job.products', 'Generation job (products) model', 'Writing product copy, and proposing products, categories and discounts for a store.'),\n modelField('job.seo', 'Generation job (SEO) model', 'Search listings, image descriptions and a site audit’s fixes.'),\n modelField('job.text', 'Generation job (text) model', 'The text step of a generation job.'),\n modelField('job.theme', 'Generation job (theme) model', 'Proposing a change to a site’s theme.'),\n modelField('job.plan', 'Generation job (plan) model', 'The plan step of a generation job.'),\n modelField('job.email', 'Generation job (email) model', 'Generating an email design from a confirmed plan.'),\n modelField('job.campaign', 'Generation job (campaign) model', 'Drafting a campaign and its email from a brief.'),\n modelField('job.workflow', 'Generation job (automation) model', 'Drafting an automation from a description, and explaining one.'),\n ],\n defaults: {\n provider: AI_SETTING_PLATFORM,\n ...Object.fromEntries(\n Object.values(AI_STEP_MODEL_SETTING).map((key) => [key, AI_SETTING_PLATFORM]),\n ),\n },\n}\n"],"names":["AI_PLUGIN_SETTINGS_ID","AI_CATALOG_PROVIDERS","AI_MODEL_CATALOG","AI_SETTING_PLATFORM","AI_STEP_MODEL_SETTING","MODEL_OPTIONS","value","label","map","entry","id","provider","modelField","kind","description","key","type","options","AI_CONFIG_SCHEMA","pluginId","fields","defaults","Object","fromEntries","values"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SAASA,qBAAqB,QAAQ,iBAAa;AACnD,SAASC,oBAAoB,EAAEC,gBAAgB,QAAyB,yBAAqB;AAE7F;;;;;;;;;CASC,GAED,2DAA2D,GAC3D,OAAO,MAAMC,sBAAsB,WAAU;AAE7C,qEAAqE,GACrE,OAAO,MAAMC,wBAAoD;IAC/D,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,oBAAoB;IACpB,iBAAiB;IACjB,WAAW;IACX,kBAAkB;IAClB,YAAY;IACZ,eAAe;IACf,cAAc;IACd,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,gBAAgB;IAChB,WAAW;IACX,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,aAAa;IACb,gBAAgB;IAChB,gBAAgB;AAClB,EAAC;AAED,MAAMC,gBAAgB;IACpB;QAAEC,OAAOH;QAAqBI,OAAO;IAAmB;OACrDL,iBAAiBM,GAAG,CAAC,CAACC,QAAW,CAAA;YAClCH,OAAOG,MAAMC,EAAE;YACfH,OAAO,GAAGE,MAAMF,KAAK,CAAC,EAAE,EAAEE,MAAME,QAAQ,CAAC,CAAC,CAAC;QAC7C,CAAA;CACD;AAED,MAAMC,aAAa,CAACC,MAAkBN,OAAeO,cAAyB,CAAA;QAC5EC,KAAKX,qBAAqB,CAACS,KAAK;QAChCN;QACAS,MAAM;QACNC,SAASZ;QACTS;IACF,CAAA;AAEA,OAAO,MAAMI,mBAAuC;IAClDC,UAAUnB;IACVoB,QAAQ;QACN;YACEL,KAAK;YACLR,OAAO;YACPS,MAAM;YACNC,SAAS;gBACP;oBAAEX,OAAOH;oBAAqBI,OAAO;gBAAmB;mBACrDN,qBAAqBO,GAAG,CAAC,CAACG,WAAc,CAAA;wBAAEL,OAAOK,SAASD,EAAE;wBAAEH,OAAOI,SAASJ,KAAK;oBAAC,CAAA;aACxF;YACDO,aACE,sEACA,sEACA;QACJ;QACAF,WAAW,eAAe,mBAAmB;QAC7CA,WAAW,gBAAgB,kCAAkC;QAC7DA,WAAW,gBAAgB,kCAAkC;QAC7DA,WAAW,aAAa,+BAA+B;QACvDA,WAAW,oBAAoB,4BAA4B;QAC3DA,WAAW,iBAAiB,oCAAoC;QAChEA,WAAW,WAAW,8BAA8B;QACpDA,WACE,kBACA,mCACA;QAEFA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,eAAe,kBAAkB;QAC5CA,WAAW,cAAc,iCAAiC;QAC1DA,WAAW,aAAa,gCAAgC;QACxDA,WAAW,gBAAgB,mCAAmC;QAC9DA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,gBAAgB,mCAAmC;QAC9DA,WAAW,WAAW,8BAA8B;QACpDA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,aAAa,gCAAgC;QACxDA,WAAW,YAAY,+BAA+B;QACtDA,WAAW,aAAa,gCAAgC;QACxDA,WAAW,gBAAgB,mCAAmC;QAC9DA,WAAW,gBAAgB,qCAAqC;KACjE;IACDS,UAAU;QACRV,UAAUR;OACPmB,OAAOC,WAAW,CACnBD,OAAOE,MAAM,CAACpB,uBAAuBI,GAAG,CAAC,CAACO,MAAQ;YAACA;YAAKZ;SAAoB;AAGlF,EAAC"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -39,16 +39,27 @@ import AiSiteSeoStartCard from "./components/ai-site-seo-start-card.component.js
|
|
|
39
39
|
import AiSiteStartCard from "./components/ai-site-start-card.component.js";
|
|
40
40
|
import AiSeoFieldsCard from "./components/ai-seo-fields-card.component.js";
|
|
41
41
|
import AiDescribeAutomationButton from "./components/ai-describe-automation.component.js";
|
|
42
|
+
import AiReviseAutomation from "./components/ai-revise-automation.component.js";
|
|
43
|
+
import AiDescribeOrgAutomationButton from "./components/ai-describe-org-automation.component.js";
|
|
44
|
+
import { AiInsightHostCard, AiInsightOrgCard } from "./components/ai-insight-card.component.js";
|
|
45
|
+
import { AiLogicCreateButton, AiLogicFixReference, AiLogicFunctionTools } from "./components/ai-logic.component.js";
|
|
46
|
+
import { AiFunnelAskButton, AiFunnelCreateButton } from "./components/ai-funnel-zones.component.js";
|
|
42
47
|
import AiCrmEmailDraft from "./components/ai-crm-email-draft.component.js";
|
|
43
48
|
import AiCrmImportMapping from "./components/ai-crm-import-mapping.component.js";
|
|
44
49
|
import AiCrmRecordCard from "./components/ai-crm-record-card.component.js";
|
|
45
50
|
import AiDescribePageButton from "./components/ai-describe-page.component.js";
|
|
51
|
+
import AiMediaCreateButton from "./components/ai-media-create.component.js";
|
|
46
52
|
import { AiDescribeComponentButton, AiDescribeFormButton, AiDescribeLayoutButton, AiDescribeTemplateButton } from "./components/ai-describe-button.component.js";
|
|
53
|
+
import { AiDescribeEmailButton } from "./components/ai-describe-email.component.js";
|
|
47
54
|
import { AiExperimentResultCard, AiExperimentVariantsCard } from "./components/ai-experiment-cards.component.js";
|
|
48
55
|
import { AiExplainAutomation, AiExplainRunFailure } from "./components/ai-explain-automation.component.js";
|
|
56
|
+
import AiCreateCampaignButton from "./components/ai-campaign-create.component.js";
|
|
57
|
+
import AiMarketingInsightButton from "./components/ai-marketing-insight.component.js";
|
|
58
|
+
import { AiCreateOverlayButton, AiOverlayEditorCard } from "./components/ai-overlay-cards.component.js";
|
|
49
59
|
import AiProductCopyCard from "./components/ai-product-copy-card.component.js";
|
|
50
60
|
import AiProductImportOption from "./components/ai-product-import-option.component.js";
|
|
51
61
|
import AiProductsHubCard from "./components/ai-products-hub-card.component.js";
|
|
62
|
+
import AiCreateProductsButton from "./components/ai-products-create-button.component.js";
|
|
52
63
|
import AiJobsPage from "./components/ai-jobs-page.component.js";
|
|
53
64
|
import { AI_PLUGIN_ID } from "./constants.js";
|
|
54
65
|
import { registerAiDeclarations } from "./declarations.js";
|
|
@@ -351,26 +362,33 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
351
362
|
Component: AiSeoAuditCard
|
|
352
363
|
},
|
|
353
364
|
// A page from a brief (AGL-2907): "Create with AI" beside Templates and
|
|
354
|
-
// Create New Screen. Gated as the other generative widgets are
|
|
355
|
-
//
|
|
365
|
+
// Create New Screen. Gated as the other generative widgets are.
|
|
366
|
+
// On a plan that could buy the AI add-on and has not, each "Create with
|
|
367
|
+
// AI" entry here is mounted anyway (`showWhenNotEntitled`) and opens
|
|
368
|
+
// the add-on's dialog instead of the brief (AGL-3601). The shell holds
|
|
369
|
+
// each behind `release_ai_generative` too, so an entry draws at once
|
|
370
|
+
// and asks the jobs route nothing until its brief is sent.
|
|
356
371
|
{
|
|
357
372
|
slot: 'hostScreens',
|
|
358
373
|
widgetId: 'ai-describe-page',
|
|
359
374
|
title: 'Describe a page',
|
|
360
375
|
featureFlag: 'aiGenerative',
|
|
361
376
|
permission: 'ai.generate',
|
|
377
|
+
showWhenNotEntitled: true,
|
|
378
|
+
releaseFlag: 'release_ai_generative',
|
|
362
379
|
Component: AiDescribePageButton
|
|
363
380
|
},
|
|
364
381
|
// The same entry for a page template, a layout and a form (AGL-3043),
|
|
365
382
|
// beside the create action of the page that lists each: the same
|
|
366
|
-
// dialog
|
|
367
|
-
// before it shows anything.
|
|
383
|
+
// dialog and the same gates.
|
|
368
384
|
{
|
|
369
385
|
slot: 'hostTemplates',
|
|
370
386
|
widgetId: 'ai-describe-template',
|
|
371
387
|
title: 'Describe a page template',
|
|
372
388
|
featureFlag: 'aiGenerative',
|
|
373
389
|
permission: 'ai.generate',
|
|
390
|
+
showWhenNotEntitled: true,
|
|
391
|
+
releaseFlag: 'release_ai_generative',
|
|
374
392
|
Component: AiDescribeTemplateButton
|
|
375
393
|
},
|
|
376
394
|
{
|
|
@@ -379,6 +397,8 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
379
397
|
title: 'Describe a layout',
|
|
380
398
|
featureFlag: 'aiGenerative',
|
|
381
399
|
permission: 'ai.generate',
|
|
400
|
+
showWhenNotEntitled: true,
|
|
401
|
+
releaseFlag: 'release_ai_generative',
|
|
382
402
|
Component: AiDescribeLayoutButton
|
|
383
403
|
},
|
|
384
404
|
{
|
|
@@ -387,47 +407,186 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
387
407
|
title: 'Describe a form',
|
|
388
408
|
featureFlag: 'aiGenerative',
|
|
389
409
|
permission: 'ai.generate',
|
|
410
|
+
showWhenNotEntitled: true,
|
|
411
|
+
releaseFlag: 'release_ai_generative',
|
|
390
412
|
Component: AiDescribeFormButton
|
|
391
413
|
},
|
|
392
414
|
// And a reusable component from a brief (AGL-3051), beside Templates
|
|
393
415
|
// and Create Component: the component job's first entry point, which
|
|
394
416
|
// had none in the console.
|
|
417
|
+
// Pictures from a description (AGL-3602): "Create with AI" beside Upload
|
|
418
|
+
// media in the media library, and in its empty state. Gated as the
|
|
419
|
+
// other generative widgets are, by the shell alone: it asks nothing of
|
|
420
|
+
// a server until someone creates a picture, and the door decides then.
|
|
421
|
+
{
|
|
422
|
+
slot: 'mediaLibrary',
|
|
423
|
+
widgetId: 'ai-media-create',
|
|
424
|
+
title: 'Create images with AI',
|
|
425
|
+
featureFlag: 'aiGenerative',
|
|
426
|
+
permission: 'ai.generate',
|
|
427
|
+
Component: AiMediaCreateButton
|
|
428
|
+
},
|
|
395
429
|
{
|
|
396
430
|
slot: 'hostComponents',
|
|
397
431
|
widgetId: 'ai-describe-component',
|
|
398
432
|
title: 'Describe a reusable component',
|
|
399
433
|
featureFlag: 'aiGenerative',
|
|
400
434
|
permission: 'ai.generate',
|
|
435
|
+
showWhenNotEntitled: true,
|
|
436
|
+
releaseFlag: 'release_ai_generative',
|
|
401
437
|
Component: AiDescribeComponentButton
|
|
402
438
|
},
|
|
439
|
+
// An email design from a brief (AGL-3596), beside New template on a
|
|
440
|
+
// site's email templates — the zone the email plugin hosts. Its dialog
|
|
441
|
+
// also offers the draft campaign that would send it; the Campaigns
|
|
442
|
+
// section's own door is `ai-create-campaign`, below.
|
|
443
|
+
{
|
|
444
|
+
slot: 'hostEmailTemplates',
|
|
445
|
+
widgetId: 'ai-describe-email',
|
|
446
|
+
title: 'Describe an email',
|
|
447
|
+
featureFlag: 'aiGenerative',
|
|
448
|
+
permission: 'ai.generate',
|
|
449
|
+
showWhenNotEntitled: true,
|
|
450
|
+
releaseFlag: 'release_ai_generative',
|
|
451
|
+
Component: AiDescribeEmailButton
|
|
452
|
+
},
|
|
403
453
|
// Automations by AI (AGL-2919), in the zones the workflows plugin hosts
|
|
404
454
|
// on its Automation page: "Create with AI" beside Add action and Recipes,
|
|
405
455
|
// "Explain it" in the editor of a saved automation, and "Why did this
|
|
406
|
-
// fail?" on a failed run. Gated as the other generative widgets are
|
|
407
|
-
//
|
|
408
|
-
// anything, and none of them changes an
|
|
456
|
+
// fail?" on a failed run. Gated as the other generative widgets are,
|
|
457
|
+
// the release flag included, by the shell alone (AGL-3601): none asks
|
|
458
|
+
// the jobs route anything until it is used, and none of them changes an
|
|
459
|
+
// automation.
|
|
409
460
|
{
|
|
410
461
|
slot: 'hostAutomations',
|
|
411
462
|
widgetId: 'ai-describe-automation',
|
|
412
463
|
title: 'Describe an automation',
|
|
413
464
|
featureFlag: 'aiGenerative',
|
|
414
465
|
permission: 'ai.generate',
|
|
466
|
+
showWhenNotEntitled: true,
|
|
467
|
+
releaseFlag: 'release_ai_generative',
|
|
415
468
|
Component: AiDescribeAutomationButton
|
|
416
469
|
},
|
|
470
|
+
// Funnels by AI (AGL-3605), in the zones the funnels plugin hosts on
|
|
471
|
+
// its card: a draft from a description, and its results explained.
|
|
472
|
+
{
|
|
473
|
+
slot: 'funnelsCreate',
|
|
474
|
+
widgetId: 'ai-describe-funnel',
|
|
475
|
+
title: 'Describe a funnel',
|
|
476
|
+
featureFlag: 'aiGenerative',
|
|
477
|
+
permission: 'ai.generate',
|
|
478
|
+
showWhenNotEntitled: true,
|
|
479
|
+
releaseFlag: 'release_ai_generative',
|
|
480
|
+
Component: AiFunnelCreateButton
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
slot: 'funnelInsight',
|
|
484
|
+
widgetId: 'ai-explain-funnel',
|
|
485
|
+
title: 'Ask AI about this funnel',
|
|
486
|
+
featureFlag: 'aiGenerative',
|
|
487
|
+
permission: 'ai.generate',
|
|
488
|
+
showWhenNotEntitled: true,
|
|
489
|
+
releaseFlag: 'release_ai_generative',
|
|
490
|
+
Component: AiFunnelAskButton
|
|
491
|
+
},
|
|
417
492
|
{
|
|
418
493
|
slot: 'automationEditor',
|
|
419
494
|
widgetId: 'ai-explain-automation',
|
|
420
495
|
title: 'Explain this automation',
|
|
421
496
|
featureFlag: 'aiGenerative',
|
|
422
497
|
permission: 'ai.generate',
|
|
498
|
+
releaseFlag: 'release_ai_generative',
|
|
423
499
|
Component: AiExplainAutomation
|
|
424
500
|
},
|
|
501
|
+
// "Change with AI" and "Fix with AI" in a saved action's editor
|
|
502
|
+
// (AGL-3603): a changed copy drafted OFF beside it, never the saved
|
|
503
|
+
// action written in place.
|
|
504
|
+
{
|
|
505
|
+
slot: 'automationEditor',
|
|
506
|
+
widgetId: 'ai-revise-automation',
|
|
507
|
+
title: 'Change this automation with AI',
|
|
508
|
+
featureFlag: 'aiGenerative',
|
|
509
|
+
permission: 'ai.generate',
|
|
510
|
+
releaseFlag: 'release_ai_generative',
|
|
511
|
+
Component: AiReviseAutomation
|
|
512
|
+
},
|
|
513
|
+
// "Create with AI" on the workspace's Org automations (AGL-3603): one
|
|
514
|
+
// of the workspace's automations drafted from a description and opened
|
|
515
|
+
// in that section's editor, unsaved and switched off.
|
|
516
|
+
{
|
|
517
|
+
slot: 'orgAutomations',
|
|
518
|
+
widgetId: 'ai-describe-org-automation',
|
|
519
|
+
title: 'Describe an org automation',
|
|
520
|
+
featureFlag: 'aiGenerative',
|
|
521
|
+
permission: 'ai.generate',
|
|
522
|
+
showWhenNotEntitled: true,
|
|
523
|
+
releaseFlag: 'release_ai_generative',
|
|
524
|
+
Component: AiDescribeOrgAutomationButton
|
|
525
|
+
},
|
|
526
|
+
// "Ask AI about these numbers" (AGL-3603): a tile on a site's
|
|
527
|
+
// dashboard and Analytics page, which both draw `hostDashboard`, and on
|
|
528
|
+
// the workspace's sites page. It opens the insight dialog the Assist
|
|
529
|
+
// panel opens, gated as every generative widget is.
|
|
530
|
+
{
|
|
531
|
+
slot: 'hostDashboard',
|
|
532
|
+
widgetId: 'ai-insight-ask',
|
|
533
|
+
title: 'Ask AI about these numbers',
|
|
534
|
+
featureFlag: 'aiGenerative',
|
|
535
|
+
permission: 'ai.generate',
|
|
536
|
+
showWhenNotEntitled: true,
|
|
537
|
+
releaseFlag: 'release_ai_generative',
|
|
538
|
+
Component: AiInsightHostCard
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
slot: 'orgDashboard',
|
|
542
|
+
widgetId: 'ai-insight-ask',
|
|
543
|
+
title: 'Ask AI about these numbers',
|
|
544
|
+
featureFlag: 'aiGenerative',
|
|
545
|
+
permission: 'ai.generate',
|
|
546
|
+
showWhenNotEntitled: true,
|
|
547
|
+
releaseFlag: 'release_ai_generative',
|
|
548
|
+
Component: AiInsightOrgCard
|
|
549
|
+
},
|
|
550
|
+
// Logic by AI (AGL-3603), in the zones the logic plugin hosts on its
|
|
551
|
+
// Functions & Variables page: Create with AI in the Functions and
|
|
552
|
+
// Variables card headers, Explain / Change / Fix in a saved function's
|
|
553
|
+
// editor, and Fix with AI on a broken reference an automation holds.
|
|
554
|
+
// Each proposal opens unsaved in the logic editor; none is saved here.
|
|
555
|
+
{
|
|
556
|
+
slot: 'hostLogic',
|
|
557
|
+
widgetId: 'ai-describe-logic',
|
|
558
|
+
title: 'Describe a function or variable',
|
|
559
|
+
featureFlag: 'aiGenerative',
|
|
560
|
+
permission: 'ai.generate',
|
|
561
|
+
showWhenNotEntitled: true,
|
|
562
|
+
releaseFlag: 'release_ai_generative',
|
|
563
|
+
Component: AiLogicCreateButton
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
slot: 'logicFunctionEditor',
|
|
567
|
+
widgetId: 'ai-logic-function',
|
|
568
|
+
title: 'This function with AI',
|
|
569
|
+
featureFlag: 'aiGenerative',
|
|
570
|
+
permission: 'ai.generate',
|
|
571
|
+
releaseFlag: 'release_ai_generative',
|
|
572
|
+
Component: AiLogicFunctionTools
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
slot: 'logicReferenceIssue',
|
|
576
|
+
widgetId: 'ai-logic-fix-reference',
|
|
577
|
+
title: 'Fix this reference with AI',
|
|
578
|
+
featureFlag: 'aiGenerative',
|
|
579
|
+
permission: 'ai.generate',
|
|
580
|
+
releaseFlag: 'release_ai_generative',
|
|
581
|
+
Component: AiLogicFixReference
|
|
582
|
+
},
|
|
425
583
|
{
|
|
426
584
|
slot: 'automationRun',
|
|
427
585
|
widgetId: 'ai-explain-run-failure',
|
|
428
586
|
title: 'Why did this run fail?',
|
|
429
587
|
featureFlag: 'aiGenerative',
|
|
430
588
|
permission: 'ai.generate',
|
|
589
|
+
releaseFlag: 'release_ai_generative',
|
|
431
590
|
Component: AiExplainRunFailure
|
|
432
591
|
},
|
|
433
592
|
// CRM by AI (AGL-2917): a record's summary and next step on its page,
|
|
@@ -504,8 +663,9 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
504
663
|
// Commerce by AI (AGL-2916): product copy in the product editor, the
|
|
505
664
|
// catalog, categories and discounts on the products hub, and copy for
|
|
506
665
|
// an import as it lands. The commerce plugin hosts the zones and makes
|
|
507
|
-
// every write
|
|
508
|
-
// before it
|
|
666
|
+
// every write. The shell holds the release flag; the products hub card
|
|
667
|
+
// reads its recent proposals before it draws its own controls, but
|
|
668
|
+
// offers the "Create with AI" door's brief from the moment it mounts.
|
|
509
669
|
{
|
|
510
670
|
slot: 'productEditor',
|
|
511
671
|
widgetId: 'ai-product-copy',
|
|
@@ -520,8 +680,22 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
520
680
|
title: 'Build your catalog with AI',
|
|
521
681
|
featureFlag: 'aiGenerative',
|
|
522
682
|
permission: 'ai.generate',
|
|
683
|
+
releaseFlag: 'release_ai_generative',
|
|
523
684
|
Component: AiProductsHubCard
|
|
524
685
|
},
|
|
686
|
+
// "Create with AI" beside Add product and in the empty catalog
|
|
687
|
+
// (AGL-3596): a door to the card's Propose products brief, shown only
|
|
688
|
+
// while that card is on the page to take it.
|
|
689
|
+
{
|
|
690
|
+
slot: 'productsCreate',
|
|
691
|
+
widgetId: 'ai-products-create',
|
|
692
|
+
title: 'Propose products',
|
|
693
|
+
featureFlag: 'aiGenerative',
|
|
694
|
+
permission: 'ai.generate',
|
|
695
|
+
showWhenNotEntitled: true,
|
|
696
|
+
releaseFlag: 'release_ai_generative',
|
|
697
|
+
Component: AiCreateProductsButton
|
|
698
|
+
},
|
|
525
699
|
{
|
|
526
700
|
slot: 'productImport',
|
|
527
701
|
widgetId: 'ai-product-import',
|
|
@@ -534,8 +708,8 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
534
708
|
// editor, and one test's result read in plain words below its figures.
|
|
535
709
|
// The A/B testing card hosts both zones, so they are drawn only where
|
|
536
710
|
// that card is and only on a site with A/B testing; the shell holds the
|
|
537
|
-
// plan band
|
|
538
|
-
// the
|
|
711
|
+
// plan band, `ai.generate` and the release flag, and neither card asks
|
|
712
|
+
// the jobs route anything until it is used (AGL-3601). Neither writes: the
|
|
539
713
|
// experiment editor's Save is the only write, and an explanation has
|
|
540
714
|
// nothing to apply.
|
|
541
715
|
{
|
|
@@ -544,6 +718,7 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
544
718
|
title: 'Write variants with AI',
|
|
545
719
|
featureFlag: 'aiGenerative',
|
|
546
720
|
permission: 'ai.generate',
|
|
721
|
+
releaseFlag: 'release_ai_generative',
|
|
547
722
|
Component: AiExperimentVariantsCard
|
|
548
723
|
},
|
|
549
724
|
{
|
|
@@ -552,7 +727,61 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
552
727
|
title: 'Explain this result with AI',
|
|
553
728
|
featureFlag: 'aiGenerative',
|
|
554
729
|
permission: 'ai.generate',
|
|
730
|
+
releaseFlag: 'release_ai_generative',
|
|
555
731
|
Component: AiExperimentResultCard
|
|
732
|
+
},
|
|
733
|
+
// Overlays by AI (AGL-3603), in the zones the marketing plugin's
|
|
734
|
+
// overlays list hosts: "Create with AI" beside New bar and New popup,
|
|
735
|
+
// and "Write with AI" among the overlay editor's fields. Both start a
|
|
736
|
+
// `text` job asked for overlay copy; neither writes — the list saves a
|
|
737
|
+
// created overlay switched off, and the editor's Save is the write.
|
|
738
|
+
{
|
|
739
|
+
slot: 'hostOverlays',
|
|
740
|
+
widgetId: 'ai-create-overlay',
|
|
741
|
+
title: 'Create an overlay with AI',
|
|
742
|
+
featureFlag: 'aiGenerative',
|
|
743
|
+
permission: 'ai.generate',
|
|
744
|
+
showWhenNotEntitled: true,
|
|
745
|
+
releaseFlag: 'release_ai_generative',
|
|
746
|
+
Component: AiCreateOverlayButton
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
slot: 'overlayEditor',
|
|
750
|
+
widgetId: 'ai-overlay-copy',
|
|
751
|
+
title: 'Write overlay copy with AI',
|
|
752
|
+
featureFlag: 'aiGenerative',
|
|
753
|
+
permission: 'ai.generate',
|
|
754
|
+
releaseFlag: 'release_ai_generative',
|
|
755
|
+
Component: AiOverlayEditorCard
|
|
756
|
+
},
|
|
757
|
+
// A campaign from a brief (AGL-3603), beside Create campaign on the
|
|
758
|
+
// Campaigns section the marketing plugin hosts: the `campaign` job's
|
|
759
|
+
// first console door, or the `email` job's where the plan sends no
|
|
760
|
+
// campaign email. Both write drafts that are aimed at nobody and sent
|
|
761
|
+
// by nobody until a member does.
|
|
762
|
+
{
|
|
763
|
+
slot: 'hostCampaigns',
|
|
764
|
+
widgetId: 'ai-create-campaign',
|
|
765
|
+
title: 'Create a campaign with AI',
|
|
766
|
+
featureFlag: 'aiGenerative',
|
|
767
|
+
permission: 'ai.generate',
|
|
768
|
+
showWhenNotEntitled: true,
|
|
769
|
+
releaseFlag: 'release_ai_generative',
|
|
770
|
+
Component: AiCreateCampaignButton
|
|
771
|
+
},
|
|
772
|
+
// The figures in words (AGL-3603), in the header of the Conversions
|
|
773
|
+
// section and of one campaign's report: the insight dialog the Assist
|
|
774
|
+
// panel opens, on the Marketing surface, for the site the figures are.
|
|
775
|
+
// It reads and cites; it changes nothing.
|
|
776
|
+
{
|
|
777
|
+
slot: 'marketingInsights',
|
|
778
|
+
widgetId: 'ai-marketing-insight',
|
|
779
|
+
title: 'Ask AI about these numbers',
|
|
780
|
+
featureFlag: 'aiGenerative',
|
|
781
|
+
permission: 'ai.generate',
|
|
782
|
+
showWhenNotEntitled: true,
|
|
783
|
+
releaseFlag: 'release_ai_generative',
|
|
784
|
+
Component: AiMarketingInsightButton
|
|
556
785
|
}
|
|
557
786
|
]
|
|
558
787
|
});
|