@aglyn/plugins-ai 1.0.0-beta.228 → 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-jobs-list-page.component.js +12 -1
- package/src/lib/components/ai-jobs-list-page.component.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.d.ts +1 -1
- package/src/lib/components/ai-site-build-page.component.js +177 -20
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.d.ts +10 -1
- package/src/lib/components/ai-site-start-card.component.js +7 -4
- package/src/lib/components/ai-site-start-card.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.d.ts +11 -0
- package/src/lib/components/assist-jobs-drawer.component.js +85 -4
- 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-layout-site-pages.d.ts +70 -0
- package/src/lib/jobs/ai-job-layout-site-pages.js +216 -0
- package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -0
- package/src/lib/jobs/ai-job-layout-step.d.ts +2 -2
- package/src/lib/jobs/ai-job-layout-step.js +19 -1
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-logic-step.d.ts +107 -0
- package/src/lib/jobs/ai-job-logic-step.js +395 -0
- package/src/lib/jobs/ai-job-logic-step.js.map +1 -0
- package/src/lib/jobs/ai-job-overlay-copy.d.ts +70 -0
- package/src/lib/jobs/ai-job-overlay-copy.js +178 -0
- package/src/lib/jobs/ai-job-overlay-copy.js.map +1 -0
- package/src/lib/jobs/ai-job-page-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 +207 -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 +90 -2
- package/src/lib/jobs/ai-jobs.js +495 -61
- 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-job-failure-copy.d.ts +20 -1
- package/src/lib/model/ai-job-failure-copy.js +28 -1
- package/src/lib/model/ai-job-failure-copy.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +3 -0
- package/src/lib/model/ai-job-notice.js +11 -2
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +87 -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 +28 -3
- package/src/lib/model/ai-site-build-progress.js +231 -17
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-start-seo.d.ts +16 -0
- package/src/lib/model/ai-site-start-seo.js +54 -4
- package/src/lib/model/ai-site-start-seo.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +14 -0
- package/src/lib/model/ai-site-start.js +43 -0
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/ai-svg.d.ts +69 -0
- package/src/lib/model/ai-svg.js +265 -0
- package/src/lib/model/ai-svg.js.map +1 -0
- package/src/lib/model/ai-usage-by-user.d.ts +3 -2
- package/src/lib/model/ai-usage-by-user.js.map +1 -1
- package/src/lib/model/ai-workflow-job.d.ts +92 -4
- package/src/lib/model/ai-workflow-job.js +124 -7
- package/src/lib/model/ai-workflow-job.js.map +1 -1
- package/src/lib/model/assist-build.d.ts +58 -0
- package/src/lib/model/assist-build.js +52 -0
- package/src/lib/model/assist-build.js.map +1 -0
- package/src/lib/model/assist-edit.d.ts +48 -3
- package/src/lib/model/assist-edit.js +48 -4
- package/src/lib/model/assist-edit.js.map +1 -1
- package/src/lib/plugin-config.js +2 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +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.d.ts +6 -0
- package/src/lib/runtime/ai-doctrine.js +16 -6
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.js +4 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-eval.d.ts +15 -1
- package/src/lib/runtime/ai-eval.js +52 -1
- package/src/lib/runtime/ai-eval.js.map +1 -1
- package/src/lib/runtime/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 +31 -3
- package/src/lib/usage/assist-job-refund.js +46 -10
- package/src/lib/usage/assist-job-refund.js.map +1 -1
- package/src/lib/usage/assist-usage.d.ts +5 -0
- package/src/lib/usage/assist-usage.js +2 -0
- package/src/lib/usage/assist-usage.js.map +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type HostFunction } from '@aglyn/aglyn/app-utils/functions';
|
|
18
|
+
import { type AiLogicContext, type AiLogicSiteVariable } from '../model/ai-logic-job';
|
|
19
|
+
import { type AiCustomGenerationInput } from '../runtime/ai-doctrine';
|
|
20
|
+
import type { AiSystemBlock } from '../runtime/ai-runtime';
|
|
21
|
+
import { type AiWorkflowExplanation } from '../tools/ai-workflow-tool';
|
|
22
|
+
import { type AiJobAdmission } from './ai-job-admission';
|
|
23
|
+
import { type AiJobStepRunner } from './ai-job-text-step';
|
|
24
|
+
import { readAiLogicFunction, readAiLogicRecords } from './ai-logic-records';
|
|
25
|
+
/**
|
|
26
|
+
* The `logic` step (AGL-3603): a function or a variable proposed from a
|
|
27
|
+
* description, a saved function changed or fixed, or one explained.
|
|
28
|
+
*
|
|
29
|
+
* The model is shown the expression grammar the evaluator runs — operators,
|
|
30
|
+
* built-ins, how a dictionary's member is read — and, in the user turn, the
|
|
31
|
+
* site's variables by name, type and value, and its function names. A saved
|
|
32
|
+
* function is shown as an outline of its own definition. It answers through
|
|
33
|
+
* `submit_function`, `submit_variable` or `submit_explanation`; a function
|
|
34
|
+
* is held to the grammar, to the names it may read and to a first run before
|
|
35
|
+
* it is kept (`checkAiLogicFunction`), and a re-ask names what failed.
|
|
36
|
+
*
|
|
37
|
+
* Nothing is written. A proposal rides on a `logic` output, and the logic
|
|
38
|
+
* editor opens it for a person to save.
|
|
39
|
+
*/
|
|
40
|
+
/** The longest the step may take reading the site first. */
|
|
41
|
+
export declare const AI_LOGIC_RECORDS_READ_MS = 2000;
|
|
42
|
+
/** The step's time: its answer and its re-ask at the `job.logic` ceiling, with its own reads. */
|
|
43
|
+
export declare const AI_JOB_LOGIC_STEP_BUDGET: import("./ai-job-budget").AiJobStepBudget;
|
|
44
|
+
export declare const AI_JOB_LOGIC_STEP_MINIMUM_MS: number;
|
|
45
|
+
export declare function aiJobLogicModel(): string;
|
|
46
|
+
/** How many site variables the user turn lists, and how much of each value. */
|
|
47
|
+
export declare const AI_LOGIC_VARIABLES_LISTED = 60;
|
|
48
|
+
export declare const AI_LOGIC_VALUE_LISTED_CHARS = 120;
|
|
49
|
+
/**
|
|
50
|
+
* The instructions, byte-identical on every request so they cache: one block
|
|
51
|
+
* for a function, a variable and an explanation alike, because a block of
|
|
52
|
+
* either half alone is under the balanced tier's cacheable minimum, and the
|
|
53
|
+
* two halves together clear it on every tool.
|
|
54
|
+
*/
|
|
55
|
+
export declare const AI_JOB_LOGIC_INSTRUCTIONS: readonly AiSystemBlock[];
|
|
56
|
+
/** A saved function as lines a model reads: its own definition, in the editor's terms. */
|
|
57
|
+
export declare function aiLogicFunctionOutline(definition: HostFunction): string;
|
|
58
|
+
/** What a function or a variable is asked from. */
|
|
59
|
+
export declare function aiJobLogicPrompt(input: {
|
|
60
|
+
brief: string;
|
|
61
|
+
mode: 'function' | 'variable' | 'explain';
|
|
62
|
+
context: AiLogicContext;
|
|
63
|
+
saved: HostFunction | null;
|
|
64
|
+
}): string;
|
|
65
|
+
/** The function generation as the doctrine's loop runs it. */
|
|
66
|
+
export declare function aiJobLogicFunctionGeneration(request: {
|
|
67
|
+
brief: string;
|
|
68
|
+
context: AiLogicContext;
|
|
69
|
+
saved: HostFunction | null;
|
|
70
|
+
model: string;
|
|
71
|
+
signal?: AbortSignal;
|
|
72
|
+
}): AiCustomGenerationInput<HostFunction>;
|
|
73
|
+
/** The variable generation. */
|
|
74
|
+
export declare function aiJobLogicVariableGeneration(request: {
|
|
75
|
+
brief: string;
|
|
76
|
+
context: AiLogicContext;
|
|
77
|
+
model: string;
|
|
78
|
+
signal?: AbortSignal;
|
|
79
|
+
}): AiCustomGenerationInput<AiLogicSiteVariable>;
|
|
80
|
+
/** The explanation generation. */
|
|
81
|
+
export declare function aiJobLogicExplainGeneration(request: {
|
|
82
|
+
brief: string;
|
|
83
|
+
context: AiLogicContext;
|
|
84
|
+
saved: HostFunction;
|
|
85
|
+
model: string;
|
|
86
|
+
signal?: AbortSignal;
|
|
87
|
+
}): AiCustomGenerationInput<AiWorkflowExplanation>;
|
|
88
|
+
export interface AiJobLogicStepDeps {
|
|
89
|
+
readRecords?: typeof readAiLogicRecords;
|
|
90
|
+
readFunction?: typeof readAiLogicFunction;
|
|
91
|
+
}
|
|
92
|
+
export declare function createAiJobLogicStep(deps?: AiJobLogicStepDeps): AiJobStepRunner;
|
|
93
|
+
export declare const runAiJobLogicStep: AiJobStepRunner;
|
|
94
|
+
/** The plugin that keeps Functions & Variables. */
|
|
95
|
+
export declare const AI_LOGIC_PLUGIN_ID = "logic";
|
|
96
|
+
export interface AiLogicJobAdmissionDeps {
|
|
97
|
+
readFunction?: typeof readAiLogicFunction;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A logic job is admitted for a site of its org with Logic on for it and past
|
|
101
|
+
* its release flag; a change or an explanation also needs the function it
|
|
102
|
+
* names to exist.
|
|
103
|
+
*/
|
|
104
|
+
export declare function createAiLogicJobAdmission(deps?: AiLogicJobAdmissionDeps): AiJobAdmission;
|
|
105
|
+
export declare const aiLogicJobAdmission: AiJobAdmission;
|
|
106
|
+
/** Registers the logic step and the check a logic job passes before it is created or resumed. */
|
|
107
|
+
export declare function registerAiLogicJob(): void;
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { FUNCTION_BUILTIN_NAMES } from "@aglyn/aglyn/app-utils/functions";
|
|
18
|
+
import { isHostPluginEnabled } from "@aglyn/aglyn/plugin-manager/enabled-plugins";
|
|
19
|
+
import { filterEnabledPluginsByReleaseFlags } from "@aglyn/tenant-data-admin/server/release-flags";
|
|
20
|
+
import { resolveOrgIdForHost } from "@aglyn/tenant-data-admin/server/organizations";
|
|
21
|
+
import { aiWorkflowExplanationText } from "../model/ai-automation-outline.js";
|
|
22
|
+
import { AI_LOGIC_GONE_COPY, AI_LOGIC_MAX_OPERATIONS, AI_LOGIC_MAX_PARAMETERS, AI_LOGIC_NO_EXPLANATION_COPY, AI_LOGIC_NO_FUNCTION_COPY, AI_LOGIC_NO_SITE_COPY, AI_LOGIC_NO_VARIABLE_COPY, AI_LOGIC_RESOURCE, AI_LOGIC_UNAVAILABLE_COPY, checkAiLogicFunction, checkAiLogicVariable, parseAiLogicJobInputs } from "../model/ai-logic-job.js";
|
|
23
|
+
import { AI_STEP_TIERS } from "../providers/catalog.js";
|
|
24
|
+
import { AI_ROUTING_TABLE, aiModelForStep } from "../providers/routing.js";
|
|
25
|
+
import { runValidatedGeneration } from "../runtime/ai-doctrine.js";
|
|
26
|
+
import { aiLogicFunctionTool, aiLogicVariableTool, AI_LOGIC_FUNCTION_TOOL_NAME, AI_LOGIC_VARIABLE_TOOL_NAME } from "../tools/ai-logic-tool.js";
|
|
27
|
+
import { AI_WORKFLOW_EXPLANATION_TOOL_NAME, aiWorkflowExplanationTool, readAiWorkflowExplanation } from "../tools/ai-workflow-tool.js";
|
|
28
|
+
import { registerAiJobAdmission } from "./ai-job-admission.js";
|
|
29
|
+
import { aiJobStepBudget } from "./ai-job-budget.js";
|
|
30
|
+
import { aiGenerationSpent, aiUnspentOutcome } from "./ai-job-generation.js";
|
|
31
|
+
import { AI_JOB_BRIEF_MAX_CHARS } from "./ai-job-text-step.js";
|
|
32
|
+
import { registerAiJobStep } from "./ai-jobs.js";
|
|
33
|
+
import { readAiLogicFunction, readAiLogicRecords } from "./ai-logic-records.js";
|
|
34
|
+
/**
|
|
35
|
+
* The `logic` step (AGL-3603): a function or a variable proposed from a
|
|
36
|
+
* description, a saved function changed or fixed, or one explained.
|
|
37
|
+
*
|
|
38
|
+
* The model is shown the expression grammar the evaluator runs — operators,
|
|
39
|
+
* built-ins, how a dictionary's member is read — and, in the user turn, the
|
|
40
|
+
* site's variables by name, type and value, and its function names. A saved
|
|
41
|
+
* function is shown as an outline of its own definition. It answers through
|
|
42
|
+
* `submit_function`, `submit_variable` or `submit_explanation`; a function
|
|
43
|
+
* is held to the grammar, to the names it may read and to a first run before
|
|
44
|
+
* it is kept (`checkAiLogicFunction`), and a re-ask names what failed.
|
|
45
|
+
*
|
|
46
|
+
* Nothing is written. A proposal rides on a `logic` output, and the logic
|
|
47
|
+
* editor opens it for a person to save.
|
|
48
|
+
*/ /** The longest the step may take reading the site first. */ export const AI_LOGIC_RECORDS_READ_MS = 2000;
|
|
49
|
+
/** The step's time: its answer and its re-ask at the `job.logic` ceiling, with its own reads. */ export const AI_JOB_LOGIC_STEP_BUDGET = aiJobStepBudget({
|
|
50
|
+
tier: AI_STEP_TIERS['job.logic'],
|
|
51
|
+
maxTokens: AI_ROUTING_TABLE['job.logic'].maxTokens,
|
|
52
|
+
lookups: 0,
|
|
53
|
+
ownReadsMs: AI_LOGIC_RECORDS_READ_MS
|
|
54
|
+
});
|
|
55
|
+
export const AI_JOB_LOGIC_STEP_MINIMUM_MS = AI_JOB_LOGIC_STEP_BUDGET.minimumMs;
|
|
56
|
+
export function aiJobLogicModel() {
|
|
57
|
+
return aiModelForStep('job.logic');
|
|
58
|
+
}
|
|
59
|
+
/** How many site variables the user turn lists, and how much of each value. */ export const AI_LOGIC_VARIABLES_LISTED = 60;
|
|
60
|
+
export const AI_LOGIC_VALUE_LISTED_CHARS = 120;
|
|
61
|
+
/**
|
|
62
|
+
* The instructions, byte-identical on every request so they cache: one block
|
|
63
|
+
* for a function, a variable and an explanation alike, because a block of
|
|
64
|
+
* either half alone is under the balanced tier's cacheable minimum, and the
|
|
65
|
+
* two halves together clear it on every tool.
|
|
66
|
+
*/ export const AI_JOB_LOGIC_INSTRUCTIONS = [
|
|
67
|
+
{
|
|
68
|
+
text: [
|
|
69
|
+
`You work on the Functions & Variables page of a website builder, for the person who owns the site. Asked for a function, call ${AI_LOGIC_FUNCTION_TOOL_NAME}; asked for a variable, call ${AI_LOGIC_VARIABLE_TOOL_NAME}; asked what a function does, call ${AI_WORKFLOW_EXPLANATION_TOOL_NAME}. Call exactly one, once. A reply in prose cannot be used.`,
|
|
70
|
+
'',
|
|
71
|
+
'A function has parameters (what it is given), locals (working values), operations run in order, and returnValue, the parameter or local whose final value it returns. Each operation is: if (left comparator right) then assign each of its then list, otherwise each of its otherwise list. A condition that should always hold is written 1 == 1.',
|
|
72
|
+
'',
|
|
73
|
+
'Expressions:',
|
|
74
|
+
'- Numbers, "quoted text", true and false; + - * / and parentheses; + also joins text.',
|
|
75
|
+
`- Built-in functions only: ${FUNCTION_BUILTIN_NAMES.map((name)=>`${name}()`).join(', ')}.`,
|
|
76
|
+
'- Names: the function’s own parameters and locals, and the site variables the request lists, by name; a dictionary variable’s member as name.member.',
|
|
77
|
+
'- An assignment sets only a parameter or a local, never a site variable.',
|
|
78
|
+
'',
|
|
79
|
+
'Writing a function or a variable:',
|
|
80
|
+
`- At most ${AI_LOGIC_MAX_PARAMETERS} parameters and ${AI_LOGIC_MAX_OPERATIONS} operations. Names start with a letter or _, then letters, digits or _.`,
|
|
81
|
+
'- Types are number, text or boolean. A parameter a visitor fills in gets a short label; defaultValue is what the input starts with, or empty.',
|
|
82
|
+
'- Use only the names and built-ins listed. Where the description needs a value the site does not hold, make it a parameter rather than inventing a number.',
|
|
83
|
+
'- When the request shows a saved function to change, answer with the whole function after the change, keeping what the change does not touch.',
|
|
84
|
+
'- A variable’s value is written as stored: digits; true or false; YYYY-MM-DD; HH:MM; a JSON object for a dictionary; a JSON list for a collection.',
|
|
85
|
+
'',
|
|
86
|
+
'Explaining a function, in plain words for someone who does not write code:',
|
|
87
|
+
'- summary: in one or two sentences, what the function computes from what it is given.',
|
|
88
|
+
'- points: what it does, operation by operation, in order. One sentence each.',
|
|
89
|
+
'- suggestions: what is worth checking — a condition that can never hold, a value it returns that nothing sets, a name it reads that the site does not have. Empty when there is nothing to suggest.',
|
|
90
|
+
'- Explain only what you are shown, and never say you changed anything: you change nothing. Write plain text, with no markdown and no HTML.'
|
|
91
|
+
].join('\n'),
|
|
92
|
+
cacheBreakpoint: true
|
|
93
|
+
}
|
|
94
|
+
];
|
|
95
|
+
// ── The user turns ────────────────────────────────────────────────────────
|
|
96
|
+
function variableLine(variable) {
|
|
97
|
+
var _variable_value;
|
|
98
|
+
const value = String((_variable_value = variable.value) != null ? _variable_value : '').replace(/\s+/g, ' ');
|
|
99
|
+
return `- ${variable.name} (${variable.type}) = ${value.length > AI_LOGIC_VALUE_LISTED_CHARS ? `${value.slice(0, AI_LOGIC_VALUE_LISTED_CHARS)}…` : value || '(empty)'}`;
|
|
100
|
+
}
|
|
101
|
+
/** A saved function as lines a model reads: its own definition, in the editor's terms. */ export function aiLogicFunctionOutline(definition) {
|
|
102
|
+
const lines = [
|
|
103
|
+
`Function: ${definition.name}`
|
|
104
|
+
];
|
|
105
|
+
lines.push('Parameters:', ...definition.parameters.length ? definition.parameters.map((parameter)=>`- ${parameter.name} (${parameter.type}${parameter.required ? ', required' : ''})${parameter.label ? ` labeled "${parameter.label}"` : ''}${parameter.defaultValue ? `, starts as ${parameter.defaultValue}` : ''}`) : [
|
|
106
|
+
'- none'
|
|
107
|
+
], 'Locals:', ...definition.variables.length ? definition.variables.map((local)=>`- ${local.name} (${local.type})`) : [
|
|
108
|
+
'- none'
|
|
109
|
+
], 'Operations, in order:');
|
|
110
|
+
definition.operations.forEach((operation, index)=>{
|
|
111
|
+
var _operation_then, _operation_otherwise;
|
|
112
|
+
var _operation_if, _operation_if1, _operation_if2;
|
|
113
|
+
const sets = (list)=>list.length ? list.map((set)=>`${set.set} = ${set.workflow ? `the workflow "${set.workflow}"` : set.expression}`).join('; ') : 'nothing';
|
|
114
|
+
lines.push(`${index + 1}. If ${(_operation_if = operation.if) == null ? void 0 : _operation_if.left} ${(_operation_if1 = operation.if) == null ? void 0 : _operation_if1.comparator} ${(_operation_if2 = operation.if) == null ? void 0 : _operation_if2.right}: ${sets((_operation_then = operation.then) != null ? _operation_then : [])}. Otherwise: ${sets((_operation_otherwise = operation.otherwise) != null ? _operation_otherwise : [])}.`);
|
|
115
|
+
});
|
|
116
|
+
lines.push(`Returns: ${definition.returnValue || '(nothing named)'}`);
|
|
117
|
+
return lines.join('\n');
|
|
118
|
+
}
|
|
119
|
+
/** What a function or a variable is asked from. */ export function aiJobLogicPrompt(input) {
|
|
120
|
+
const variables = input.context.variables.slice(0, AI_LOGIC_VARIABLES_LISTED);
|
|
121
|
+
return [
|
|
122
|
+
input.mode === 'variable' ? 'Asked: one site variable.' : input.mode === 'explain' ? 'Asked: what this function does.' : input.saved ? 'Asked: the saved function below, changed as the request says.' : 'Asked: one new function.',
|
|
123
|
+
'Site variables (name (type) = value):',
|
|
124
|
+
...variables.length ? variables.map(variableLine) : [
|
|
125
|
+
'- none'
|
|
126
|
+
],
|
|
127
|
+
`Function names already on the site: ${input.context.functions.join(', ') || 'none'}`,
|
|
128
|
+
...input.saved ? [
|
|
129
|
+
'The saved function:',
|
|
130
|
+
aiLogicFunctionOutline(input.saved)
|
|
131
|
+
] : [],
|
|
132
|
+
`Request: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`
|
|
133
|
+
].join('\n');
|
|
134
|
+
}
|
|
135
|
+
function routedEffort() {
|
|
136
|
+
const row = AI_ROUTING_TABLE['job.logic'];
|
|
137
|
+
return _extends({}, row.thinking ? {
|
|
138
|
+
thinking: row.thinking
|
|
139
|
+
} : {}, row.effort ? {
|
|
140
|
+
effort: row.effort
|
|
141
|
+
} : {});
|
|
142
|
+
}
|
|
143
|
+
/** The function generation as the doctrine's loop runs it. */ export function aiJobLogicFunctionGeneration(request) {
|
|
144
|
+
return _extends({
|
|
145
|
+
step: 'job.logic',
|
|
146
|
+
model: request.model,
|
|
147
|
+
instructions: AI_JOB_LOGIC_INSTRUCTIONS,
|
|
148
|
+
messages: [
|
|
149
|
+
{
|
|
150
|
+
role: 'user',
|
|
151
|
+
content: aiJobLogicPrompt(_extends({}, request, {
|
|
152
|
+
mode: 'function'
|
|
153
|
+
}))
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
tool: aiLogicFunctionTool(),
|
|
157
|
+
maxTokens: AI_JOB_LOGIC_STEP_BUDGET.maxTokens(request.model)
|
|
158
|
+
}, routedEffort(), request.signal ? {
|
|
159
|
+
signal: request.signal
|
|
160
|
+
} : {}, {
|
|
161
|
+
check: (answer)=>checkAiLogicFunction(answer, request.context)
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/** The variable generation. */ export function aiJobLogicVariableGeneration(request) {
|
|
165
|
+
return _extends({
|
|
166
|
+
step: 'job.logic',
|
|
167
|
+
model: request.model,
|
|
168
|
+
instructions: AI_JOB_LOGIC_INSTRUCTIONS,
|
|
169
|
+
messages: [
|
|
170
|
+
{
|
|
171
|
+
role: 'user',
|
|
172
|
+
content: aiJobLogicPrompt(_extends({}, request, {
|
|
173
|
+
mode: 'variable',
|
|
174
|
+
saved: null
|
|
175
|
+
}))
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
tool: aiLogicVariableTool(),
|
|
179
|
+
maxTokens: AI_JOB_LOGIC_STEP_BUDGET.maxTokens(request.model)
|
|
180
|
+
}, routedEffort(), request.signal ? {
|
|
181
|
+
signal: request.signal
|
|
182
|
+
} : {}, {
|
|
183
|
+
check: (answer)=>checkAiLogicVariable(answer, request.context)
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/** The explanation generation. */ export function aiJobLogicExplainGeneration(request) {
|
|
187
|
+
return _extends({
|
|
188
|
+
step: 'job.logic',
|
|
189
|
+
model: request.model,
|
|
190
|
+
instructions: AI_JOB_LOGIC_INSTRUCTIONS,
|
|
191
|
+
messages: [
|
|
192
|
+
{
|
|
193
|
+
role: 'user',
|
|
194
|
+
content: aiJobLogicPrompt(_extends({}, request, {
|
|
195
|
+
mode: 'explain'
|
|
196
|
+
}))
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
tool: aiWorkflowExplanationTool(),
|
|
200
|
+
maxTokens: AI_JOB_LOGIC_STEP_BUDGET.maxTokens(request.model)
|
|
201
|
+
}, routedEffort(), request.signal ? {
|
|
202
|
+
signal: request.signal
|
|
203
|
+
} : {}, {
|
|
204
|
+
check: readAiWorkflowExplanation
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function proposalOutput(place, id, label, proposal, note) {
|
|
208
|
+
return {
|
|
209
|
+
resource: AI_LOGIC_RESOURCE,
|
|
210
|
+
id,
|
|
211
|
+
hostId: place.hostId,
|
|
212
|
+
hostSubdomain: place.hostSubdomain,
|
|
213
|
+
label,
|
|
214
|
+
proposal: proposal,
|
|
215
|
+
note
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
export function createAiJobLogicStep(deps = {}) {
|
|
219
|
+
var _deps_readRecords, _deps_readFunction;
|
|
220
|
+
const readRecords = (_deps_readRecords = deps.readRecords) != null ? _deps_readRecords : readAiLogicRecords;
|
|
221
|
+
const readFunction = (_deps_readFunction = deps.readFunction) != null ? _deps_readFunction : readAiLogicFunction;
|
|
222
|
+
return async ({ job, signal, firestore, modelFor })=>{
|
|
223
|
+
var _ref, _ref1;
|
|
224
|
+
const model = (_ref = modelFor == null ? void 0 : modelFor('job.logic')) != null ? _ref : aiJobLogicModel();
|
|
225
|
+
const unspent = (failure)=>_extends({}, aiUnspentOutcome(model), {
|
|
226
|
+
failure
|
|
227
|
+
});
|
|
228
|
+
const inputs = parseAiLogicJobInputs(job.inputs);
|
|
229
|
+
if (typeof inputs === 'string') return unspent(inputs);
|
|
230
|
+
const hostId = job.hostId;
|
|
231
|
+
if (!hostId) return unspent(AI_LOGIC_NO_SITE_COPY);
|
|
232
|
+
const host = await firestore.collection('hosts').doc(hostId).get();
|
|
233
|
+
if (!host.exists || host.get('orgId') !== job.orgId) return unspent(AI_LOGIC_NO_SITE_COPY);
|
|
234
|
+
const subdomain = host.get('subdomain');
|
|
235
|
+
const place = {
|
|
236
|
+
hostId,
|
|
237
|
+
hostSubdomain: typeof subdomain === 'string' && subdomain ? subdomain : null
|
|
238
|
+
};
|
|
239
|
+
const functionId = inputs.mode === 'variable' ? null : inputs.functionId;
|
|
240
|
+
const saved = functionId ? await readFunction(firestore, {
|
|
241
|
+
hostId,
|
|
242
|
+
id: functionId
|
|
243
|
+
}) : null;
|
|
244
|
+
if (functionId && !saved) return unspent(AI_LOGIC_GONE_COPY);
|
|
245
|
+
const records = await readRecords(firestore, hostId);
|
|
246
|
+
const context = _extends({}, records, {
|
|
247
|
+
editing: (_ref1 = saved == null ? void 0 : saved.name) != null ? _ref1 : null
|
|
248
|
+
});
|
|
249
|
+
const signalled = signal ? {
|
|
250
|
+
signal
|
|
251
|
+
} : {};
|
|
252
|
+
if (inputs.mode === 'explain' && saved) {
|
|
253
|
+
const generation = await runValidatedGeneration('logic', aiJobLogicExplainGeneration(_extends({
|
|
254
|
+
brief: job.brief,
|
|
255
|
+
context,
|
|
256
|
+
saved,
|
|
257
|
+
model
|
|
258
|
+
}, signalled)));
|
|
259
|
+
const spent = _extends({}, aiGenerationSpent(generation), generation.effort ? {
|
|
260
|
+
effort: generation.effort
|
|
261
|
+
} : {});
|
|
262
|
+
if (generation.status === 'refused') return _extends({}, spent, {
|
|
263
|
+
refused: true
|
|
264
|
+
});
|
|
265
|
+
if (generation.status === 'needs_input') return _extends({}, spent, {
|
|
266
|
+
failure: AI_LOGIC_NO_EXPLANATION_COPY
|
|
267
|
+
});
|
|
268
|
+
return _extends({}, spent, {
|
|
269
|
+
outputs: [
|
|
270
|
+
{
|
|
271
|
+
resource: 'text',
|
|
272
|
+
id: 'explanation',
|
|
273
|
+
hostId,
|
|
274
|
+
hostSubdomain: place.hostSubdomain,
|
|
275
|
+
label: `How ${saved.name} works`,
|
|
276
|
+
text: aiWorkflowExplanationText(generation.value, 'explain')
|
|
277
|
+
}
|
|
278
|
+
]
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (inputs.mode === 'variable') {
|
|
282
|
+
const generation = await runValidatedGeneration('logic', aiJobLogicVariableGeneration(_extends({
|
|
283
|
+
brief: job.brief,
|
|
284
|
+
context,
|
|
285
|
+
model
|
|
286
|
+
}, signalled)));
|
|
287
|
+
const spent = _extends({}, aiGenerationSpent(generation), generation.effort ? {
|
|
288
|
+
effort: generation.effort
|
|
289
|
+
} : {});
|
|
290
|
+
if (generation.status === 'refused') return _extends({}, spent, {
|
|
291
|
+
refused: true
|
|
292
|
+
});
|
|
293
|
+
if (generation.status === 'needs_input') return _extends({}, spent, {
|
|
294
|
+
failure: AI_LOGIC_NO_VARIABLE_COPY
|
|
295
|
+
});
|
|
296
|
+
const variable = generation.value;
|
|
297
|
+
return _extends({}, spent, {
|
|
298
|
+
outputs: [
|
|
299
|
+
proposalOutput(place, 'variable', variable.name, {
|
|
300
|
+
kind: 'variable',
|
|
301
|
+
variable
|
|
302
|
+
}, 'Open it in Variables to review and save it.')
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
const generation = await runValidatedGeneration('logic', aiJobLogicFunctionGeneration(_extends({
|
|
307
|
+
brief: job.brief,
|
|
308
|
+
context,
|
|
309
|
+
saved,
|
|
310
|
+
model
|
|
311
|
+
}, signalled)));
|
|
312
|
+
const spent = _extends({}, aiGenerationSpent(generation), generation.effort ? {
|
|
313
|
+
effort: generation.effort
|
|
314
|
+
} : {});
|
|
315
|
+
if (generation.status === 'refused') return _extends({}, spent, {
|
|
316
|
+
refused: true
|
|
317
|
+
});
|
|
318
|
+
if (generation.status === 'needs_input') return _extends({}, spent, {
|
|
319
|
+
failure: AI_LOGIC_NO_FUNCTION_COPY
|
|
320
|
+
});
|
|
321
|
+
const definition = generation.value;
|
|
322
|
+
return _extends({}, spent, {
|
|
323
|
+
outputs: [
|
|
324
|
+
proposalOutput(place, functionId != null ? functionId : 'function', definition.name, {
|
|
325
|
+
kind: 'function',
|
|
326
|
+
functionId,
|
|
327
|
+
definition
|
|
328
|
+
}, saved ? `A changed ${saved.name}, checked against the expression grammar and run once. Nothing is saved until you save it in the editor.` : 'Checked against the expression grammar and run once. Nothing is saved until you save it in the editor.')
|
|
329
|
+
]
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
export const runAiJobLogicStep = createAiJobLogicStep();
|
|
334
|
+
// ── Admission ─────────────────────────────────────────────────────────────
|
|
335
|
+
/** The plugin that keeps Functions & Variables. */ export const AI_LOGIC_PLUGIN_ID = 'logic';
|
|
336
|
+
/**
|
|
337
|
+
* A logic job is admitted for a site of its org with Logic on for it and past
|
|
338
|
+
* its release flag; a change or an explanation also needs the function it
|
|
339
|
+
* names to exist.
|
|
340
|
+
*/ export function createAiLogicJobAdmission(deps = {}) {
|
|
341
|
+
var _deps_readFunction;
|
|
342
|
+
const readFunction = (_deps_readFunction = deps.readFunction) != null ? _deps_readFunction : readAiLogicFunction;
|
|
343
|
+
return async (context)=>{
|
|
344
|
+
var _data;
|
|
345
|
+
const inputs = parseAiLogicJobInputs(context.inputs);
|
|
346
|
+
if (typeof inputs === 'string') return {
|
|
347
|
+
status: 400,
|
|
348
|
+
error: inputs
|
|
349
|
+
};
|
|
350
|
+
const hostId = context.hostId;
|
|
351
|
+
if (!hostId) return {
|
|
352
|
+
status: 400,
|
|
353
|
+
error: 'Open the site the logic is for before starting the job'
|
|
354
|
+
};
|
|
355
|
+
const owner = await resolveOrgIdForHost(hostId);
|
|
356
|
+
if (!owner || owner !== context.orgId) return {
|
|
357
|
+
status: 404,
|
|
358
|
+
error: 'Unknown site'
|
|
359
|
+
};
|
|
360
|
+
const host = (_data = (await context.firestore.collection('hosts').doc(hostId).get()).data()) != null ? _data : null;
|
|
361
|
+
const org = context.org;
|
|
362
|
+
const released = await filterEnabledPluginsByReleaseFlags([
|
|
363
|
+
AI_LOGIC_PLUGIN_ID
|
|
364
|
+
], {
|
|
365
|
+
orgId: context.orgId,
|
|
366
|
+
authorization: null
|
|
367
|
+
});
|
|
368
|
+
if (!released.includes(AI_LOGIC_PLUGIN_ID) || !isHostPluginEnabled(org, host, AI_LOGIC_PLUGIN_ID)) {
|
|
369
|
+
return {
|
|
370
|
+
status: 403,
|
|
371
|
+
error: AI_LOGIC_UNAVAILABLE_COPY
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const functionId = inputs.mode === 'variable' ? null : inputs.functionId;
|
|
375
|
+
if (functionId && !await readFunction(context.firestore, {
|
|
376
|
+
hostId,
|
|
377
|
+
id: functionId
|
|
378
|
+
})) {
|
|
379
|
+
return {
|
|
380
|
+
status: 404,
|
|
381
|
+
error: AI_LOGIC_GONE_COPY
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
return null;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
export const aiLogicJobAdmission = createAiLogicJobAdmission();
|
|
388
|
+
/** Registers the logic step and the check a logic job passes before it is created or resumed. */ export function registerAiLogicJob() {
|
|
389
|
+
registerAiJobStep('logic', runAiJobLogicStep, {
|
|
390
|
+
minimumMs: AI_JOB_LOGIC_STEP_MINIMUM_MS
|
|
391
|
+
});
|
|
392
|
+
registerAiJobAdmission('logic', aiLogicJobAdmission);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
//# sourceMappingURL=ai-job-logic-step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-logic-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 { FUNCTION_BUILTIN_NAMES, type HostFunction } from '@aglyn/aglyn/app-utils/functions'\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 { aiWorkflowExplanationText } from '../model/ai-automation-outline'\nimport type { AiJobOutput, AiJobOutputResource } from '../model/ai-jobs.types'\nimport {\n AI_LOGIC_GONE_COPY,\n AI_LOGIC_MAX_OPERATIONS,\n AI_LOGIC_MAX_PARAMETERS,\n AI_LOGIC_NO_EXPLANATION_COPY,\n AI_LOGIC_NO_FUNCTION_COPY,\n AI_LOGIC_NO_SITE_COPY,\n AI_LOGIC_NO_VARIABLE_COPY,\n AI_LOGIC_RESOURCE,\n AI_LOGIC_UNAVAILABLE_COPY,\n checkAiLogicFunction,\n checkAiLogicVariable,\n parseAiLogicJobInputs,\n type AiLogicContext,\n type AiLogicProposal,\n type AiLogicSiteVariable,\n} from '../model/ai-logic-job'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { AI_ROUTING_TABLE, aiModelForStep } from '../providers/routing'\nimport { runValidatedGeneration, type AiCustomGenerationInput } from '../runtime/ai-doctrine'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport { aiLogicFunctionTool, aiLogicVariableTool, AI_LOGIC_FUNCTION_TOOL_NAME, AI_LOGIC_VARIABLE_TOOL_NAME } from '../tools/ai-logic-tool'\nimport {\n AI_WORKFLOW_EXPLANATION_TOOL_NAME,\n aiWorkflowExplanationTool,\n readAiWorkflowExplanation,\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 { aiGenerationSpent, aiUnspentOutcome } from './ai-job-generation'\nimport { AI_JOB_BRIEF_MAX_CHARS, type AiJobStepOutcome, type AiJobStepRunner } from './ai-job-text-step'\nimport { registerAiJobStep } from './ai-jobs'\nimport { readAiLogicFunction, readAiLogicRecords } from './ai-logic-records'\n\n/**\n * The `logic` step (AGL-3603): a function or a variable proposed from a\n * description, a saved function changed or fixed, or one explained.\n *\n * The model is shown the expression grammar the evaluator runs — operators,\n * built-ins, how a dictionary's member is read — and, in the user turn, the\n * site's variables by name, type and value, and its function names. A saved\n * function is shown as an outline of its own definition. It answers through\n * `submit_function`, `submit_variable` or `submit_explanation`; a function\n * is held to the grammar, to the names it may read and to a first run before\n * it is kept (`checkAiLogicFunction`), and a re-ask names what failed.\n *\n * Nothing is written. A proposal rides on a `logic` output, and the logic\n * editor opens it for a person to save.\n */\n\n/** The longest the step may take reading the site first. */\nexport const AI_LOGIC_RECORDS_READ_MS = 2_000\n\n/** The step's time: its answer and its re-ask at the `job.logic` ceiling, with its own reads. */\nexport const AI_JOB_LOGIC_STEP_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.logic'],\n maxTokens: AI_ROUTING_TABLE['job.logic'].maxTokens,\n lookups: 0,\n ownReadsMs: AI_LOGIC_RECORDS_READ_MS,\n})\n\nexport const AI_JOB_LOGIC_STEP_MINIMUM_MS = AI_JOB_LOGIC_STEP_BUDGET.minimumMs\n\nexport function aiJobLogicModel(): string {\n return aiModelForStep('job.logic')\n}\n\n/** How many site variables the user turn lists, and how much of each value. */\nexport const AI_LOGIC_VARIABLES_LISTED = 60\nexport const AI_LOGIC_VALUE_LISTED_CHARS = 120\n\n/**\n * The instructions, byte-identical on every request so they cache: one block\n * for a function, a variable and an explanation alike, because a block of\n * either half alone is under the balanced tier's cacheable minimum, and the\n * two halves together clear it on every tool.\n */\nexport const AI_JOB_LOGIC_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n `You work on the Functions & Variables page of a website builder, for the person who owns the site. Asked for a function, call ${AI_LOGIC_FUNCTION_TOOL_NAME}; asked for a variable, call ${AI_LOGIC_VARIABLE_TOOL_NAME}; asked what a function does, call ${AI_WORKFLOW_EXPLANATION_TOOL_NAME}. Call exactly one, once. A reply in prose cannot be used.`,\n '',\n 'A function has parameters (what it is given), locals (working values), operations run in order, and returnValue, the parameter or local whose final value it returns. Each operation is: if (left comparator right) then assign each of its then list, otherwise each of its otherwise list. A condition that should always hold is written 1 == 1.',\n '',\n 'Expressions:',\n '- Numbers, \"quoted text\", true and false; + - * / and parentheses; + also joins text.',\n `- Built-in functions only: ${FUNCTION_BUILTIN_NAMES.map((name) => `${name}()`).join(', ')}.`,\n '- Names: the function’s own parameters and locals, and the site variables the request lists, by name; a dictionary variable’s member as name.member.',\n '- An assignment sets only a parameter or a local, never a site variable.',\n '',\n 'Writing a function or a variable:',\n `- At most ${AI_LOGIC_MAX_PARAMETERS} parameters and ${AI_LOGIC_MAX_OPERATIONS} operations. Names start with a letter or _, then letters, digits or _.`,\n '- Types are number, text or boolean. A parameter a visitor fills in gets a short label; defaultValue is what the input starts with, or empty.',\n '- Use only the names and built-ins listed. Where the description needs a value the site does not hold, make it a parameter rather than inventing a number.',\n '- When the request shows a saved function to change, answer with the whole function after the change, keeping what the change does not touch.',\n '- A variable’s value is written as stored: digits; true or false; YYYY-MM-DD; HH:MM; a JSON object for a dictionary; a JSON list for a collection.',\n '',\n 'Explaining a function, in plain words for someone who does not write code:',\n '- summary: in one or two sentences, what the function computes from what it is given.',\n '- points: what it does, operation by operation, in order. One sentence each.',\n '- suggestions: what is worth checking — a condition that can never hold, a value it returns that nothing sets, a name it reads that the site does not have. Empty when there is nothing to suggest.',\n '- Explain only what you are shown, and never say you changed anything: you change nothing. Write plain text, with no markdown and no HTML.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n// ── The user turns ────────────────────────────────────────────────────────\n\nfunction variableLine(variable: AiLogicSiteVariable): string {\n const value = String(variable.value ?? '').replace(/\\s+/g, ' ')\n return `- ${variable.name} (${variable.type}) = ${value.length > AI_LOGIC_VALUE_LISTED_CHARS ? `${value.slice(0, AI_LOGIC_VALUE_LISTED_CHARS)}…` : value || '(empty)'}`\n}\n\n/** A saved function as lines a model reads: its own definition, in the editor's terms. */\nexport function aiLogicFunctionOutline(definition: HostFunction): string {\n const lines = [`Function: ${definition.name}`]\n lines.push(\n 'Parameters:',\n ...(definition.parameters.length\n ? definition.parameters.map(\n (parameter) =>\n `- ${parameter.name} (${parameter.type}${parameter.required ? ', required' : ''})${parameter.label ? ` labeled \"${parameter.label}\"` : ''}${parameter.defaultValue ? `, starts as ${parameter.defaultValue}` : ''}`,\n )\n : ['- none']),\n 'Locals:',\n ...(definition.variables.length\n ? definition.variables.map((local) => `- ${local.name} (${local.type})`)\n : ['- none']),\n 'Operations, in order:',\n )\n definition.operations.forEach((operation, index) => {\n const sets = (list: HostFunction['operations'][number]['then']) =>\n list.length ? list.map((set) => `${set.set} = ${set.workflow ? `the workflow \"${set.workflow}\"` : set.expression}`).join('; ') : 'nothing'\n lines.push(\n `${index + 1}. If ${operation.if?.left} ${operation.if?.comparator} ${operation.if?.right}: ${sets(operation.then ?? [])}. Otherwise: ${sets(operation.otherwise ?? [])}.`,\n )\n })\n lines.push(`Returns: ${definition.returnValue || '(nothing named)'}`)\n return lines.join('\\n')\n}\n\n/** What a function or a variable is asked from. */\nexport function aiJobLogicPrompt(input: {\n brief: string\n mode: 'function' | 'variable' | 'explain'\n context: AiLogicContext\n saved: HostFunction | null\n}): string {\n const variables = input.context.variables.slice(0, AI_LOGIC_VARIABLES_LISTED)\n return [\n input.mode === 'variable'\n ? 'Asked: one site variable.'\n : input.mode === 'explain'\n ? 'Asked: what this function does.'\n : input.saved\n ? 'Asked: the saved function below, changed as the request says.'\n : 'Asked: one new function.',\n 'Site variables (name (type) = value):',\n ...(variables.length ? variables.map(variableLine) : ['- none']),\n `Function names already on the site: ${input.context.functions.join(', ') || 'none'}`,\n ...(input.saved ? ['The saved function:', aiLogicFunctionOutline(input.saved)] : []),\n `Request: ${input.brief.slice(0, AI_JOB_BRIEF_MAX_CHARS)}`,\n ].join('\\n')\n}\n\nfunction routedEffort(): Pick<AiCustomGenerationInput<unknown>, 'thinking' | 'effort'> {\n const row = AI_ROUTING_TABLE['job.logic']\n return {\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n }\n}\n\n/** The function generation as the doctrine's loop runs it. */\nexport function aiJobLogicFunctionGeneration(request: {\n brief: string\n context: AiLogicContext\n saved: HostFunction | null\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<HostFunction> {\n return {\n step: 'job.logic',\n model: request.model,\n instructions: AI_JOB_LOGIC_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobLogicPrompt({ ...request, mode: 'function' }) }],\n tool: aiLogicFunctionTool(),\n maxTokens: AI_JOB_LOGIC_STEP_BUDGET.maxTokens(request.model),\n ...routedEffort(),\n ...(request.signal ? { signal: request.signal } : {}),\n check: (answer) => checkAiLogicFunction(answer, request.context),\n }\n}\n\n/** The variable generation. */\nexport function aiJobLogicVariableGeneration(request: {\n brief: string\n context: AiLogicContext\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<AiLogicSiteVariable> {\n return {\n step: 'job.logic',\n model: request.model,\n instructions: AI_JOB_LOGIC_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobLogicPrompt({ ...request, mode: 'variable', saved: null }) }],\n tool: aiLogicVariableTool(),\n maxTokens: AI_JOB_LOGIC_STEP_BUDGET.maxTokens(request.model),\n ...routedEffort(),\n ...(request.signal ? { signal: request.signal } : {}),\n check: (answer) => checkAiLogicVariable(answer, request.context),\n }\n}\n\n/** The explanation generation. */\nexport function aiJobLogicExplainGeneration(request: {\n brief: string\n context: AiLogicContext\n saved: HostFunction\n model: string\n signal?: AbortSignal\n}): AiCustomGenerationInput<AiWorkflowExplanation> {\n return {\n step: 'job.logic',\n model: request.model,\n instructions: AI_JOB_LOGIC_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiJobLogicPrompt({ ...request, mode: 'explain' }) }],\n tool: aiWorkflowExplanationTool(),\n maxTokens: AI_JOB_LOGIC_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 AiJobLogicStepDeps {\n readRecords?: typeof readAiLogicRecords\n readFunction?: typeof readAiLogicFunction\n}\n\nfunction proposalOutput(\n place: { hostId: string; hostSubdomain: string | null },\n id: string,\n label: string,\n proposal: AiLogicProposal,\n note: string,\n): AiJobOutput {\n return {\n resource: AI_LOGIC_RESOURCE as AiJobOutputResource,\n id,\n hostId: place.hostId,\n hostSubdomain: place.hostSubdomain,\n label,\n proposal: proposal as unknown as Record<string, unknown>,\n note,\n }\n}\n\nexport function createAiJobLogicStep(deps: AiJobLogicStepDeps = {}): AiJobStepRunner {\n const readRecords = deps.readRecords ?? readAiLogicRecords\n const readFunction = deps.readFunction ?? readAiLogicFunction\n return async ({ job, signal, firestore, modelFor }): Promise<AiJobStepOutcome> => {\n const model = modelFor?.('job.logic') ?? aiJobLogicModel()\n const unspent = (failure: string): AiJobStepOutcome => ({ ...aiUnspentOutcome(model), failure })\n const inputs = parseAiLogicJobInputs(job.inputs)\n if (typeof inputs === 'string') return unspent(inputs)\n const hostId = job.hostId\n if (!hostId) return unspent(AI_LOGIC_NO_SITE_COPY)\n const host = await firestore.collection('hosts').doc(hostId).get()\n if (!host.exists || host.get('orgId') !== job.orgId) return unspent(AI_LOGIC_NO_SITE_COPY)\n const subdomain = host.get('subdomain')\n const place = { hostId, hostSubdomain: typeof subdomain === 'string' && subdomain ? subdomain : null }\n\n const functionId = inputs.mode === 'variable' ? null : inputs.functionId\n const saved = functionId ? await readFunction(firestore, { hostId, id: functionId }) : null\n if (functionId && !saved) return unspent(AI_LOGIC_GONE_COPY)\n const records = await readRecords(firestore, hostId)\n const context: AiLogicContext = { ...records, editing: saved?.name ?? null }\n const signalled = signal ? { signal } : {}\n\n if (inputs.mode === 'explain' && saved) {\n const generation = await runValidatedGeneration(\n 'logic',\n aiJobLogicExplainGeneration({ brief: job.brief, context, saved, model, ...signalled }),\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_LOGIC_NO_EXPLANATION_COPY }\n return {\n ...spent,\n outputs: [\n {\n resource: 'text',\n id: 'explanation',\n hostId,\n hostSubdomain: place.hostSubdomain,\n label: `How ${saved.name} works`,\n text: aiWorkflowExplanationText(generation.value, 'explain'),\n },\n ],\n }\n }\n\n if (inputs.mode === 'variable') {\n const generation = await runValidatedGeneration(\n 'logic',\n aiJobLogicVariableGeneration({ brief: job.brief, context, model, ...signalled }),\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_LOGIC_NO_VARIABLE_COPY }\n const variable = generation.value\n return {\n ...spent,\n outputs: [\n proposalOutput(place, 'variable', variable.name, { kind: 'variable', variable }, 'Open it in Variables to review and save it.'),\n ],\n }\n }\n\n const generation = await runValidatedGeneration(\n 'logic',\n aiJobLogicFunctionGeneration({ brief: job.brief, context, saved, model, ...signalled }),\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_LOGIC_NO_FUNCTION_COPY }\n const definition = generation.value\n return {\n ...spent,\n outputs: [\n proposalOutput(\n place,\n functionId ?? 'function',\n definition.name,\n { kind: 'function', functionId, definition },\n saved\n ? `A changed ${saved.name}, checked against the expression grammar and run once. Nothing is saved until you save it in the editor.`\n : 'Checked against the expression grammar and run once. Nothing is saved until you save it in the editor.',\n ),\n ],\n }\n }\n}\n\nexport const runAiJobLogicStep = createAiJobLogicStep()\n\n// ── Admission ─────────────────────────────────────────────────────────────\n\n/** The plugin that keeps Functions & Variables. */\nexport const AI_LOGIC_PLUGIN_ID = 'logic'\n\nexport interface AiLogicJobAdmissionDeps {\n readFunction?: typeof readAiLogicFunction\n}\n\n/**\n * A logic job is admitted for a site of its org with Logic on for it and past\n * its release flag; a change or an explanation also needs the function it\n * names to exist.\n */\nexport function createAiLogicJobAdmission(deps: AiLogicJobAdmissionDeps = {}): AiJobAdmission {\n const readFunction = deps.readFunction ?? readAiLogicFunction\n return async (context): Promise<AiJobAdmissionRefusal | null> => {\n const inputs = parseAiLogicJobInputs(context.inputs)\n if (typeof inputs === 'string') return { status: 400, error: inputs }\n const hostId = context.hostId\n if (!hostId) return { status: 400, error: 'Open the site the logic is for before starting the job' }\n const owner = await resolveOrgIdForHost(hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\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([AI_LOGIC_PLUGIN_ID], {\n orgId: context.orgId,\n authorization: null,\n })\n if (!released.includes(AI_LOGIC_PLUGIN_ID) || !isHostPluginEnabled(org, host, AI_LOGIC_PLUGIN_ID)) {\n return { status: 403, error: AI_LOGIC_UNAVAILABLE_COPY }\n }\n const functionId = inputs.mode === 'variable' ? null : inputs.functionId\n if (functionId && !(await readFunction(context.firestore, { hostId, id: functionId }))) {\n return { status: 404, error: AI_LOGIC_GONE_COPY }\n }\n return null\n }\n}\n\nexport const aiLogicJobAdmission = createAiLogicJobAdmission()\n\n/** Registers the logic step and the check a logic job passes before it is created or resumed. */\nexport function registerAiLogicJob(): void {\n registerAiJobStep('logic', runAiJobLogicStep, { minimumMs: AI_JOB_LOGIC_STEP_MINIMUM_MS })\n registerAiJobAdmission('logic', aiLogicJobAdmission)\n}\n"],"names":["FUNCTION_BUILTIN_NAMES","isHostPluginEnabled","filterEnabledPluginsByReleaseFlags","resolveOrgIdForHost","aiWorkflowExplanationText","AI_LOGIC_GONE_COPY","AI_LOGIC_MAX_OPERATIONS","AI_LOGIC_MAX_PARAMETERS","AI_LOGIC_NO_EXPLANATION_COPY","AI_LOGIC_NO_FUNCTION_COPY","AI_LOGIC_NO_SITE_COPY","AI_LOGIC_NO_VARIABLE_COPY","AI_LOGIC_RESOURCE","AI_LOGIC_UNAVAILABLE_COPY","checkAiLogicFunction","checkAiLogicVariable","parseAiLogicJobInputs","AI_STEP_TIERS","AI_ROUTING_TABLE","aiModelForStep","runValidatedGeneration","aiLogicFunctionTool","aiLogicVariableTool","AI_LOGIC_FUNCTION_TOOL_NAME","AI_LOGIC_VARIABLE_TOOL_NAME","AI_WORKFLOW_EXPLANATION_TOOL_NAME","aiWorkflowExplanationTool","readAiWorkflowExplanation","registerAiJobAdmission","aiJobStepBudget","aiGenerationSpent","aiUnspentOutcome","AI_JOB_BRIEF_MAX_CHARS","registerAiJobStep","readAiLogicFunction","readAiLogicRecords","AI_LOGIC_RECORDS_READ_MS","AI_JOB_LOGIC_STEP_BUDGET","tier","maxTokens","lookups","ownReadsMs","AI_JOB_LOGIC_STEP_MINIMUM_MS","minimumMs","aiJobLogicModel","AI_LOGIC_VARIABLES_LISTED","AI_LOGIC_VALUE_LISTED_CHARS","AI_JOB_LOGIC_INSTRUCTIONS","text","map","name","join","cacheBreakpoint","variableLine","variable","value","String","replace","type","length","slice","aiLogicFunctionOutline","definition","lines","push","parameters","parameter","required","label","defaultValue","variables","local","operations","forEach","operation","index","sets","list","set","workflow","expression","if","left","comparator","right","then","otherwise","returnValue","aiJobLogicPrompt","input","context","mode","saved","functions","brief","routedEffort","row","thinking","effort","aiJobLogicFunctionGeneration","request","step","model","instructions","messages","role","content","tool","signal","check","answer","aiJobLogicVariableGeneration","aiJobLogicExplainGeneration","proposalOutput","place","id","proposal","note","resource","hostId","hostSubdomain","createAiJobLogicStep","deps","readRecords","readFunction","job","firestore","modelFor","unspent","failure","inputs","host","collection","doc","get","exists","orgId","subdomain","functionId","records","editing","signalled","generation","spent","status","refused","outputs","kind","runAiJobLogicStep","AI_LOGIC_PLUGIN_ID","createAiLogicJobAdmission","error","owner","data","org","released","authorization","includes","aiLogicJobAdmission","registerAiLogicJob"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,sBAAsB,QAA2B,mCAAkC;AAC5F,SAASC,mBAAmB,QAAQ,8CAA6C;AACjF,SAASC,kCAAkC,QAAQ,gDAA+C;AAClG,SAASC,mBAAmB,QAAQ,gDAA+C;AACnF,SAASC,yBAAyB,QAAQ,oCAAgC;AAE1E,SACEC,kBAAkB,EAClBC,uBAAuB,EACvBC,uBAAuB,EACvBC,4BAA4B,EAC5BC,yBAAyB,EACzBC,qBAAqB,EACrBC,yBAAyB,EACzBC,iBAAiB,EACjBC,yBAAyB,EACzBC,oBAAoB,EACpBC,oBAAoB,EACpBC,qBAAqB,QAIhB,2BAAuB;AAC9B,SAASC,aAAa,QAAQ,0BAAsB;AACpD,SAASC,gBAAgB,EAAEC,cAAc,QAAQ,0BAAsB;AACvE,SAASC,sBAAsB,QAAsC,4BAAwB;AAE7F,SAASC,mBAAmB,EAAEC,mBAAmB,EAAEC,2BAA2B,EAAEC,2BAA2B,QAAQ,4BAAwB;AAC3I,SACEC,iCAAiC,EACjCC,yBAAyB,EACzBC,yBAAyB,QAEpB,+BAA2B;AAClC,SAASC,sBAAsB,QAAyD,wBAAoB;AAC5G,SAASC,eAAe,QAAQ,qBAAiB;AACjD,SAASC,iBAAiB,EAAEC,gBAAgB,QAAQ,yBAAqB;AACzE,SAASC,sBAAsB,QAAqD,wBAAoB;AACxG,SAASC,iBAAiB,QAAQ,eAAW;AAC7C,SAASC,mBAAmB,EAAEC,kBAAkB,QAAQ,wBAAoB;AAE5E;;;;;;;;;;;;;;CAcC,GAED,0DAA0D,GAC1D,OAAO,MAAMC,2BAA2B,KAAK;AAE7C,+FAA+F,GAC/F,OAAO,MAAMC,2BAA2BR,gBAAgB;IACtDS,MAAMrB,aAAa,CAAC,YAAY;IAChCsB,WAAWrB,gBAAgB,CAAC,YAAY,CAACqB,SAAS;IAClDC,SAAS;IACTC,YAAYL;AACd,GAAE;AAEF,OAAO,MAAMM,+BAA+BL,yBAAyBM,SAAS,CAAA;AAE9E,OAAO,SAASC;IACd,OAAOzB,eAAe;AACxB;AAEA,6EAA6E,GAC7E,OAAO,MAAM0B,4BAA4B,GAAE;AAC3C,OAAO,MAAMC,8BAA8B,IAAG;AAE9C;;;;;CAKC,GACD,OAAO,MAAMC,4BAAsD;IACjE;QACEC,MAAM;YACJ,CAAC,8HAA8H,EAAEzB,4BAA4B,6BAA6B,EAAEC,4BAA4B,mCAAmC,EAAEC,kCAAkC,0DAA0D,CAAC;YAC1V;YACA;YACA;YACA;YACA;YACA,CAAC,2BAA2B,EAAEzB,uBAAuBiD,GAAG,CAAC,CAACC,OAAS,GAAGA,KAAK,EAAE,CAAC,EAAEC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7F;YACA;YACA;YACA;YACA,CAAC,UAAU,EAAE5C,wBAAwB,gBAAgB,EAAED,wBAAwB,uEAAuE,CAAC;YACvJ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD,CAAC6C,IAAI,CAAC;QACPC,iBAAiB;IACnB;CACD,CAAA;AAED,6EAA6E;AAE7E,SAASC,aAAaC,QAA6B;QAC5BA;IAArB,MAAMC,QAAQC,QAAOF,kBAAAA,SAASC,KAAK,YAAdD,kBAAkB,IAAIG,OAAO,CAAC,QAAQ;IAC3D,OAAO,CAAC,EAAE,EAAEH,SAASJ,IAAI,CAAC,EAAE,EAAEI,SAASI,IAAI,CAAC,IAAI,EAAEH,MAAMI,MAAM,GAAGb,8BAA8B,GAAGS,MAAMK,KAAK,CAAC,GAAGd,6BAA6B,CAAC,CAAC,GAAGS,SAAS,WAAW;AACzK;AAEA,wFAAwF,GACxF,OAAO,SAASM,uBAAuBC,UAAwB;IAC7D,MAAMC,QAAQ;QAAC,CAAC,UAAU,EAAED,WAAWZ,IAAI,EAAE;KAAC;IAC9Ca,MAAMC,IAAI,CACR,kBACIF,WAAWG,UAAU,CAACN,MAAM,GAC5BG,WAAWG,UAAU,CAAChB,GAAG,CACvB,CAACiB,YACC,CAAC,EAAE,EAAEA,UAAUhB,IAAI,CAAC,EAAE,EAAEgB,UAAUR,IAAI,GAAGQ,UAAUC,QAAQ,GAAG,eAAe,GAAG,CAAC,EAAED,UAAUE,KAAK,GAAG,CAAC,UAAU,EAAEF,UAAUE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAKF,UAAUG,YAAY,GAAG,CAAC,YAAY,EAAEH,UAAUG,YAAY,EAAE,GAAG,IAAI,IAEvN;QAAC;KAAS,EACd,cACIP,WAAWQ,SAAS,CAACX,MAAM,GAC3BG,WAAWQ,SAAS,CAACrB,GAAG,CAAC,CAACsB,QAAU,CAAC,EAAE,EAAEA,MAAMrB,IAAI,CAAC,EAAE,EAAEqB,MAAMb,IAAI,CAAC,CAAC,CAAC,IACrE;QAAC;KAAS,EACd;IAEFI,WAAWU,UAAU,CAACC,OAAO,CAAC,CAACC,WAAWC;YAI6DD,iBAA0CA;YAAzHA,eAAsBA,gBAA4BA;QAHxE,MAAME,OAAO,CAACC,OACZA,KAAKlB,MAAM,GAAGkB,KAAK5B,GAAG,CAAC,CAAC6B,MAAQ,GAAGA,IAAIA,GAAG,CAAC,GAAG,EAAEA,IAAIC,QAAQ,GAAG,CAAC,cAAc,EAAED,IAAIC,QAAQ,CAAC,CAAC,CAAC,GAAGD,IAAIE,UAAU,EAAE,EAAE7B,IAAI,CAAC,QAAQ;QACnIY,MAAMC,IAAI,CACR,GAAGW,QAAQ,EAAE,KAAK,GAAED,gBAAAA,UAAUO,EAAE,qBAAZP,cAAcQ,IAAI,CAAC,CAAC,GAAER,iBAAAA,UAAUO,EAAE,qBAAZP,eAAcS,UAAU,CAAC,CAAC,GAAET,iBAAAA,UAAUO,EAAE,qBAAZP,eAAcU,KAAK,CAAC,EAAE,EAAER,MAAKF,kBAAAA,UAAUW,IAAI,YAAdX,kBAAkB,EAAE,EAAE,aAAa,EAAEE,MAAKF,uBAAAA,UAAUY,SAAS,YAAnBZ,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE9K;IACAX,MAAMC,IAAI,CAAC,CAAC,SAAS,EAAEF,WAAWyB,WAAW,IAAI,mBAAmB;IACpE,OAAOxB,MAAMZ,IAAI,CAAC;AACpB;AAEA,iDAAiD,GACjD,OAAO,SAASqC,iBAAiBC,KAKhC;IACC,MAAMnB,YAAYmB,MAAMC,OAAO,CAACpB,SAAS,CAACV,KAAK,CAAC,GAAGf;IACnD,OAAO;QACL4C,MAAME,IAAI,KAAK,aACX,8BACAF,MAAME,IAAI,KAAK,YACb,oCACAF,MAAMG,KAAK,GACT,kEACA;QACR;WACItB,UAAUX,MAAM,GAAGW,UAAUrB,GAAG,CAACI,gBAAgB;YAAC;SAAS;QAC/D,CAAC,oCAAoC,EAAEoC,MAAMC,OAAO,CAACG,SAAS,CAAC1C,IAAI,CAAC,SAAS,QAAQ;WACjFsC,MAAMG,KAAK,GAAG;YAAC;YAAuB/B,uBAAuB4B,MAAMG,KAAK;SAAE,GAAG,EAAE;QACnF,CAAC,SAAS,EAAEH,MAAMK,KAAK,CAAClC,KAAK,CAAC,GAAG5B,yBAAyB;KAC3D,CAACmB,IAAI,CAAC;AACT;AAEA,SAAS4C;IACP,MAAMC,MAAM9E,gBAAgB,CAAC,YAAY;IACzC,OAAO,aACD8E,IAAIC,QAAQ,GAAG;QAAEA,UAAUD,IAAIC,QAAQ;IAAC,IAAI,CAAC,GAC7CD,IAAIE,MAAM,GAAG;QAAEA,QAAQF,IAAIE,MAAM;IAAC,IAAI,CAAC;AAE/C;AAEA,4DAA4D,GAC5D,OAAO,SAASC,6BAA6BC,OAM5C;IACC,OAAO;QACLC,MAAM;QACNC,OAAOF,QAAQE,KAAK;QACpBC,cAAcxD;QACdyD,UAAU;YAAC;gBAAEC,MAAM;gBAAQC,SAASlB,iBAAiB,aAAKY;oBAAST,MAAM;;YAAc;SAAE;QACzFgB,MAAMtF;QACNkB,WAAWF,yBAAyBE,SAAS,CAAC6D,QAAQE,KAAK;OACxDP,gBACCK,QAAQQ,MAAM,GAAG;QAAEA,QAAQR,QAAQQ,MAAM;IAAC,IAAI,CAAC;QACnDC,OAAO,CAACC,SAAWhG,qBAAqBgG,QAAQV,QAAQV,OAAO;;AAEnE;AAEA,6BAA6B,GAC7B,OAAO,SAASqB,6BAA6BX,OAK5C;IACC,OAAO;QACLC,MAAM;QACNC,OAAOF,QAAQE,KAAK;QACpBC,cAAcxD;QACdyD,UAAU;YAAC;gBAAEC,MAAM;gBAAQC,SAASlB,iBAAiB,aAAKY;oBAAST,MAAM;oBAAYC,OAAO;;YAAQ;SAAE;QACtGe,MAAMrF;QACNiB,WAAWF,yBAAyBE,SAAS,CAAC6D,QAAQE,KAAK;OACxDP,gBACCK,QAAQQ,MAAM,GAAG;QAAEA,QAAQR,QAAQQ,MAAM;IAAC,IAAI,CAAC;QACnDC,OAAO,CAACC,SAAW/F,qBAAqB+F,QAAQV,QAAQV,OAAO;;AAEnE;AAEA,gCAAgC,GAChC,OAAO,SAASsB,4BAA4BZ,OAM3C;IACC,OAAO;QACLC,MAAM;QACNC,OAAOF,QAAQE,KAAK;QACpBC,cAAcxD;QACdyD,UAAU;YAAC;gBAAEC,MAAM;gBAAQC,SAASlB,iBAAiB,aAAKY;oBAAST,MAAM;;YAAa;SAAE;QACxFgB,MAAMjF;QACNa,WAAWF,yBAAyBE,SAAS,CAAC6D,QAAQE,KAAK;OACxDP,gBACCK,QAAQQ,MAAM,GAAG;QAAEA,QAAQR,QAAQQ,MAAM;IAAC,IAAI,CAAC;QACnDC,OAAOlF;;AAEX;AASA,SAASsF,eACPC,KAAuD,EACvDC,EAAU,EACV/C,KAAa,EACbgD,QAAyB,EACzBC,IAAY;IAEZ,OAAO;QACLC,UAAU1G;QACVuG;QACAI,QAAQL,MAAMK,MAAM;QACpBC,eAAeN,MAAMM,aAAa;QAClCpD;QACAgD,UAAUA;QACVC;IACF;AACF;AAEA,OAAO,SAASI,qBAAqBC,OAA2B,CAAC,CAAC;QAC5CA,mBACCA;IADrB,MAAMC,eAAcD,oBAAAA,KAAKC,WAAW,YAAhBD,oBAAoBvF;IACxC,MAAMyF,gBAAeF,qBAAAA,KAAKE,YAAY,YAAjBF,qBAAqBxF;IAC1C,OAAO,OAAO,EAAE2F,GAAG,EAAEjB,MAAM,EAAEkB,SAAS,EAAEC,QAAQ,EAAE;;QAChD,MAAMzB,gBAAQyB,4BAAAA,SAAW,+BAAgBnF;QACzC,MAAMoF,UAAU,CAACC,UAAuC,aAAKlG,iBAAiBuE;gBAAQ2B;;QACtF,MAAMC,SAASlH,sBAAsB6G,IAAIK,MAAM;QAC/C,IAAI,OAAOA,WAAW,UAAU,OAAOF,QAAQE;QAC/C,MAAMX,SAASM,IAAIN,MAAM;QACzB,IAAI,CAACA,QAAQ,OAAOS,QAAQtH;QAC5B,MAAMyH,OAAO,MAAML,UAAUM,UAAU,CAAC,SAASC,GAAG,CAACd,QAAQe,GAAG;QAChE,IAAI,CAACH,KAAKI,MAAM,IAAIJ,KAAKG,GAAG,CAAC,aAAaT,IAAIW,KAAK,EAAE,OAAOR,QAAQtH;QACpE,MAAM+H,YAAYN,KAAKG,GAAG,CAAC;QAC3B,MAAMpB,QAAQ;YAAEK;YAAQC,eAAe,OAAOiB,cAAc,YAAYA,YAAYA,YAAY;QAAK;QAErG,MAAMC,aAAaR,OAAOvC,IAAI,KAAK,aAAa,OAAOuC,OAAOQ,UAAU;QACxE,MAAM9C,QAAQ8C,aAAa,MAAMd,aAAaE,WAAW;YAAEP;YAAQJ,IAAIuB;QAAW,KAAK;QACvF,IAAIA,cAAc,CAAC9C,OAAO,OAAOoC,QAAQ3H;QACzC,MAAMsI,UAAU,MAAMhB,YAAYG,WAAWP;QAC7C,MAAM7B,UAA0B,aAAKiD;YAASC,OAAO,WAAEhD,yBAAAA,MAAO1C,IAAI,oBAAI;;QACtE,MAAM2F,YAAYjC,SAAS;YAAEA;QAAO,IAAI,CAAC;QAEzC,IAAIsB,OAAOvC,IAAI,KAAK,aAAaC,OAAO;YACtC,MAAMkD,aAAa,MAAM1H,uBACvB,SACA4F,4BAA4B;gBAAElB,OAAO+B,IAAI/B,KAAK;gBAAEJ;gBAASE;gBAAOU;eAAUuC;YAE5E,MAAME,QAAQ,aAAKjH,kBAAkBgH,aAAiBA,WAAW5C,MAAM,GAAG;gBAAEA,QAAQ4C,WAAW5C,MAAM;YAAC,IAAI,CAAC;YAC3G,IAAI4C,WAAWE,MAAM,KAAK,WAAW,OAAO,aAAKD;gBAAOE,SAAS;;YACjE,IAAIH,WAAWE,MAAM,KAAK,eAAe,OAAO,aAAKD;gBAAOd,SAASzH;;YACrE,OAAO,aACFuI;gBACHG,SAAS;oBACP;wBACE5B,UAAU;wBACVH,IAAI;wBACJI;wBACAC,eAAeN,MAAMM,aAAa;wBAClCpD,OAAO,CAAC,IAAI,EAAEwB,MAAM1C,IAAI,CAAC,MAAM,CAAC;wBAChCF,MAAM5C,0BAA0B0I,WAAWvF,KAAK,EAAE;oBACpD;iBACD;;QAEL;QAEA,IAAI2E,OAAOvC,IAAI,KAAK,YAAY;YAC9B,MAAMmD,aAAa,MAAM1H,uBACvB,SACA2F,6BAA6B;gBAAEjB,OAAO+B,IAAI/B,KAAK;gBAAEJ;gBAASY;eAAUuC;YAEtE,MAAME,QAAQ,aAAKjH,kBAAkBgH,aAAiBA,WAAW5C,MAAM,GAAG;gBAAEA,QAAQ4C,WAAW5C,MAAM;YAAC,IAAI,CAAC;YAC3G,IAAI4C,WAAWE,MAAM,KAAK,WAAW,OAAO,aAAKD;gBAAOE,SAAS;;YACjE,IAAIH,WAAWE,MAAM,KAAK,eAAe,OAAO,aAAKD;gBAAOd,SAAStH;;YACrE,MAAM2C,WAAWwF,WAAWvF,KAAK;YACjC,OAAO,aACFwF;gBACHG,SAAS;oBACPjC,eAAeC,OAAO,YAAY5D,SAASJ,IAAI,EAAE;wBAAEiG,MAAM;wBAAY7F;oBAAS,GAAG;iBAClF;;QAEL;QAEA,MAAMwF,aAAa,MAAM1H,uBACvB,SACA+E,6BAA6B;YAAEL,OAAO+B,IAAI/B,KAAK;YAAEJ;YAASE;YAAOU;WAAUuC;QAE7E,MAAME,QAAQ,aAAKjH,kBAAkBgH,aAAiBA,WAAW5C,MAAM,GAAG;YAAEA,QAAQ4C,WAAW5C,MAAM;QAAC,IAAI,CAAC;QAC3G,IAAI4C,WAAWE,MAAM,KAAK,WAAW,OAAO,aAAKD;YAAOE,SAAS;;QACjE,IAAIH,WAAWE,MAAM,KAAK,eAAe,OAAO,aAAKD;YAAOd,SAASxH;;QACrE,MAAMqD,aAAagF,WAAWvF,KAAK;QACnC,OAAO,aACFwF;YACHG,SAAS;gBACPjC,eACEC,OACAwB,qBAAAA,aAAc,YACd5E,WAAWZ,IAAI,EACf;oBAAEiG,MAAM;oBAAYT;oBAAY5E;gBAAW,GAC3C8B,QACI,CAAC,UAAU,EAAEA,MAAM1C,IAAI,CAAC,wGAAwG,CAAC,GACjI;aAEP;;IAEL;AACF;AAEA,OAAO,MAAMkG,oBAAoB3B,uBAAsB;AAEvD,6EAA6E;AAE7E,iDAAiD,GACjD,OAAO,MAAM4B,qBAAqB,QAAO;AAMzC;;;;CAIC,GACD,OAAO,SAASC,0BAA0B5B,OAAgC,CAAC,CAAC;QACrDA;IAArB,MAAME,gBAAeF,qBAAAA,KAAKE,YAAY,YAAjBF,qBAAqBxF;IAC1C,OAAO,OAAOwD;YAOC;QANb,MAAMwC,SAASlH,sBAAsB0E,QAAQwC,MAAM;QACnD,IAAI,OAAOA,WAAW,UAAU,OAAO;YAAEc,QAAQ;YAAKO,OAAOrB;QAAO;QACpE,MAAMX,SAAS7B,QAAQ6B,MAAM;QAC7B,IAAI,CAACA,QAAQ,OAAO;YAAEyB,QAAQ;YAAKO,OAAO;QAAyD;QACnG,MAAMC,QAAQ,MAAMrJ,oBAAoBoH;QACxC,IAAI,CAACiC,SAASA,UAAU9D,QAAQ8C,KAAK,EAAE,OAAO;YAAEQ,QAAQ;YAAKO,OAAO;QAAe;QACnF,MAAMpB,QAAO,QAAA,AAAC,CAAA,MAAMzC,QAAQoC,SAAS,CAACM,UAAU,CAAC,SAASC,GAAG,CAACd,QAAQe,GAAG,EAAC,EAAGmB,IAAI,cAApE,QAA0E;QACvF,MAAMC,MAAMhE,QAAQgE,GAAG;QACvB,MAAMC,WAAW,MAAMzJ,mCAAmC;YAACmJ;SAAmB,EAAE;YAC9Eb,OAAO9C,QAAQ8C,KAAK;YACpBoB,eAAe;QACjB;QACA,IAAI,CAACD,SAASE,QAAQ,CAACR,uBAAuB,CAACpJ,oBAAoByJ,KAAKvB,MAAMkB,qBAAqB;YACjG,OAAO;gBAAEL,QAAQ;gBAAKO,OAAO1I;YAA0B;QACzD;QACA,MAAM6H,aAAaR,OAAOvC,IAAI,KAAK,aAAa,OAAOuC,OAAOQ,UAAU;QACxE,IAAIA,cAAc,CAAE,MAAMd,aAAalC,QAAQoC,SAAS,EAAE;YAAEP;YAAQJ,IAAIuB;QAAW,IAAK;YACtF,OAAO;gBAAEM,QAAQ;gBAAKO,OAAOlJ;YAAmB;QAClD;QACA,OAAO;IACT;AACF;AAEA,OAAO,MAAMyJ,sBAAsBR,4BAA2B;AAE9D,+FAA+F,GAC/F,OAAO,SAASS;IACd9H,kBAAkB,SAASmH,mBAAmB;QAAEzG,WAAWD;IAA6B;IACxFd,uBAAuB,SAASkI;AAClC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type AiOverlayCopyProposal, type AiOverlayKind, type AiOverlayTrigger } from '../model/ai-overlay-copy';
|
|
18
|
+
import type { AiJob, AiJobOutput } from '../model/ai-jobs.types';
|
|
19
|
+
import { type AiSystemBlock } from '../runtime/ai-runtime';
|
|
20
|
+
import type { AiJobStepOutcome } from './ai-job-text-step';
|
|
21
|
+
/**
|
|
22
|
+
* Overlay copy (AGL-3603): the `text` step asked, by `inputs.task: 'overlay'`,
|
|
23
|
+
* for an announcement bar's or a popup's copy as fields rather than prose.
|
|
24
|
+
*
|
|
25
|
+
* A text job rather than a kind of its own because it IS a text job — a brief
|
|
26
|
+
* in, a short piece of copy out, one request at the `job.text` route's model
|
|
27
|
+
* and ceiling — so it runs inline in the create door, is metered as any text
|
|
28
|
+
* job is and needs no plan. Only the answer's shape differs: one strict tool
|
|
29
|
+
* call, held by `checkAiOverlayCopy` to the limits and the triggers the
|
|
30
|
+
* request named.
|
|
31
|
+
*
|
|
32
|
+
* ## Nothing is written
|
|
33
|
+
*
|
|
34
|
+
* The answer is a proposal on the job's output. The overlay is the marketing
|
|
35
|
+
* plugin's; its editor fills its fields from the proposal unsaved, or its list
|
|
36
|
+
* writes a new overlay switched off, and in both a person decides what goes
|
|
37
|
+
* live. No link, schedule, page targeting or on-switch is ever proposed.
|
|
38
|
+
*
|
|
39
|
+
* ## What reaches the model
|
|
40
|
+
*
|
|
41
|
+
* The brief, what the overlay is (a bar or a popup), the triggers the site
|
|
42
|
+
* offers, and — when a person asked from an overlay that has copy — that copy
|
|
43
|
+
* as the editor holds it. Nothing about the site's visitors or its figures.
|
|
44
|
+
*/
|
|
45
|
+
/** The job's failure when the answer could not be used. */
|
|
46
|
+
export declare const AI_OVERLAY_NO_COPY_COPY = "The AI did not write copy that fits this overlay. Try the brief in different words.";
|
|
47
|
+
/** The job's failure when the inputs name no overlay kind. */
|
|
48
|
+
export declare const AI_OVERLAY_NO_KIND_COPY = "Say whether the copy is for an announcement bar or a popup.";
|
|
49
|
+
/** The rules, static and byte-identical for every workspace, so they cache. */
|
|
50
|
+
export declare const AI_OVERLAY_RULES: string;
|
|
51
|
+
export declare const AI_OVERLAY_SYSTEM: AiSystemBlock[];
|
|
52
|
+
/** The user turn: the brief, the overlay, its triggers and its copy as it stands. */
|
|
53
|
+
export declare function aiOverlayCopyPrompt(input: {
|
|
54
|
+
brief: string;
|
|
55
|
+
kind: AiOverlayKind;
|
|
56
|
+
triggers: ReadonlyMap<AiOverlayTrigger, {
|
|
57
|
+
min: number;
|
|
58
|
+
max: number;
|
|
59
|
+
} | null>;
|
|
60
|
+
current: string;
|
|
61
|
+
}): string;
|
|
62
|
+
/** A checked proposal as the job's output: shown as text, carried as fields. */
|
|
63
|
+
export declare function aiOverlayCopyOutput(job: Pick<AiJob, 'hostId' | 'inputs'>, proposal: AiOverlayCopyProposal): AiJobOutput;
|
|
64
|
+
/** The overlay task of the text step: one strict tool call, checked, never written. */
|
|
65
|
+
export declare function runAiOverlayCopy(input: {
|
|
66
|
+
job: Pick<AiJob, '$id' | 'brief' | 'hostId' | 'inputs'>;
|
|
67
|
+
model: string;
|
|
68
|
+
maxTokens: number;
|
|
69
|
+
signal?: AbortSignal;
|
|
70
|
+
}): Promise<AiJobStepOutcome>;
|