@aglyn/plugins-ai 1.0.0-beta.238 → 1.0.0-beta.239
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/package.json +17 -17
- package/src/lib/components/ai-job-links.js +8 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-jobs-store.d.ts +12 -0
- package/src/lib/components/ai-jobs-store.js +15 -0
- package/src/lib/components/ai-jobs-store.js.map +1 -1
- package/src/lib/components/ai-usage-meter-refresh.d.ts +35 -0
- package/src/lib/components/ai-usage-meter-refresh.js +63 -0
- package/src/lib/components/ai-usage-meter-refresh.js.map +1 -0
- package/src/lib/components/assist-panel.component.js +4 -0
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/use-ai-usage-meter.d.ts +2 -0
- package/src/lib/components/use-ai-usage-meter.js +8 -3
- package/src/lib/components/use-ai-usage-meter.js.map +1 -1
- package/src/lib/jobs/ai-build-unit-outcome.d.ts +3 -1
- package/src/lib/jobs/ai-build-unit-outcome.js +19 -3
- package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.js +29 -2
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-draft-ids.js +7 -2
- package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
- package/src/lib/jobs/ai-job-form-dataset.d.ts +100 -0
- package/src/lib/jobs/ai-job-form-dataset.js +161 -0
- package/src/lib/jobs/ai-job-form-dataset.js.map +1 -0
- package/src/lib/jobs/ai-job-form-step.d.ts +15 -3
- package/src/lib/jobs/ai-job-form-step.js +37 -9
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +9 -0
- package/src/lib/jobs/ai-job-page-language.js +37 -2
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +18 -0
- package/src/lib/jobs/ai-job-plan-step.js +41 -4
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +170 -0
- package/src/lib/jobs/ai-job-site-datasets.js +499 -0
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -0
- package/src/lib/jobs/ai-job-site-step.d.ts +15 -8
- package/src/lib/jobs/ai-job-site-step.js +148 -29
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-dataset-site-plan-recordings.d.ts +30 -0
- package/src/lib/jobs/fixtures/ai-dataset-site-plan-recordings.js +637 -0
- package/src/lib/jobs/fixtures/ai-dataset-site-plan-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +10 -0
- package/src/lib/layout-language/ai-layout-compiler.js +93 -1
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-gaps.js +17 -1
- package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +32 -3
- package/src/lib/layout-language/ai-layout-listings.js +62 -9
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +2 -0
- package/src/lib/model/ai-build-job.js +16 -1
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +23 -3
- package/src/lib/model/ai-build-plan.js +47 -6
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-plan-capabilities.d.ts +7 -0
- package/src/lib/model/ai-plan-capabilities.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +19 -2
- package/src/lib/model/ai-site-job.js +21 -6
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +77 -0
- package/src/lib/runtime/ai-dataset-generation.js +127 -0
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +40 -0
- package/src/lib/runtime/ai-doctrine-validators.js +130 -1
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +8 -3
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +2 -0
- package/src/lib/runtime/ai-node-tree.js +16 -0
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/tools/ai-dataset-tool.d.ts +68 -0
- package/src/lib/tools/ai-dataset-tool.js +231 -0
- package/src/lib/tools/ai-dataset-tool.js.map +1 -0
- package/src/lib/usage/free-ai-credits-left.js +26 -2
- package/src/lib/usage/free-ai-credits-left.js.map +1 -1
|
@@ -754,6 +754,46 @@ export declare function detectPlanSplitLists(plan: AiBuildPlan, inventory: AiSit
|
|
|
754
754
|
* can answer with the form's bare name, which is no reference at all.
|
|
755
755
|
*/
|
|
756
756
|
export declare function aiSettlePlanRefs(plan: AiBuildPlan, inventory?: AiSiteInventory | null): AiBuildPlan;
|
|
757
|
+
/**
|
|
758
|
+
* What customers say, which no dataset of the site's holds: a review, a
|
|
759
|
+
* testimonial, a rating, a quote (AGL-3616). A job never writes them for the
|
|
760
|
+
* people who did not, so a dataset of them is one nothing can seed.
|
|
761
|
+
*/
|
|
762
|
+
export declare const AI_DATASET_SAID_NAME: RegExp;
|
|
763
|
+
/**
|
|
764
|
+
* A plan that creates more datasets than this job may make is settled in
|
|
765
|
+
* code, never re-asked (AGL-3616). The live eval of 2026-10-10 refused a
|
|
766
|
+
* dental practice's plan four times over for a fourth dataset, and a food
|
|
767
|
+
* bank's re-ask for one broke a layout rule its first answer had kept.
|
|
768
|
+
*
|
|
769
|
+
* A dataset of what customers say (`AI_DATASET_SAID_NAME`, in its name or a
|
|
770
|
+
* field) is let go first, whatever the cap: both of those plans made one of
|
|
771
|
+
* testimonials, which nothing may seed.
|
|
772
|
+
*
|
|
773
|
+
* The datasets kept are the most useful: the ones the most sections list,
|
|
774
|
+
* a record template counting double, plan order breaking ties. Each one let
|
|
775
|
+
* go leaves the plan whole — its `new:` reference comes off every section,
|
|
776
|
+
* a record template of it becomes a page of its own, and a section that
|
|
777
|
+
* listed it shows fewer items than rule 8 binds, so its items are written
|
|
778
|
+
* out on the page. Where the job may create no dataset at all, rule 7 still
|
|
779
|
+
* asks, as it does for any creation.
|
|
780
|
+
*/
|
|
781
|
+
export declare function aiSettlePlanDatasets(plan: AiBuildPlan, capabilities?: AiPlanCapabilities | null): AiBuildPlan;
|
|
782
|
+
/**
|
|
783
|
+
* A form's dataset, settled in code before the rules read the plan
|
|
784
|
+
* (AGL-3616, Zach 2026-10-10: Aglyn AI's forms write to its datasets).
|
|
785
|
+
*
|
|
786
|
+
* - A `writesTo` that names nothing the form can write to comes off: a
|
|
787
|
+
* `new:` of no dataset this plan creates, an id the inventory does not
|
|
788
|
+
* hold, or a dataset this job may not create. The form is then the
|
|
789
|
+
* form it always was, its submissions in the Inbox. A dataset the
|
|
790
|
+
* inventory holds, named by its name rather than its id, is given its id.
|
|
791
|
+
* - A dataset this plan creates for a form holds the people who send it:
|
|
792
|
+
* no page lists it and none is its record template, so its `new:` comes
|
|
793
|
+
* off every section and record that named it, and a section that listed
|
|
794
|
+
* it shows fewer items than rule 8 binds.
|
|
795
|
+
*/
|
|
796
|
+
export declare function aiSettlePlanFormDatasets(plan: AiBuildPlan, inventory: AiSiteInventory | null, capabilities?: AiPlanCapabilities | null): AiBuildPlan;
|
|
757
797
|
/**
|
|
758
798
|
* A page that names no layout, on a site where only one layout can frame it,
|
|
759
799
|
* is put in that layout before the rules read the plan (2026-10-07). The
|
|
@@ -23,7 +23,7 @@ import { FREE_AI_TASTE_CREDITS_PER_MONTH } from "../plan-entitlements.js";
|
|
|
23
23
|
import { REUSABLE_INSTANCE_COMPONENT_ID, REUSABLE_INSTANCE_PROP_VALUES_KEY } from "@aglyn/aglyn/app-utils/reusable-component-keys";
|
|
24
24
|
import { parseBreakpointSpan } from "@aglyn/shared-data-enums/breakpoint-span";
|
|
25
25
|
import { renderEmailHtml } from "@aglyn/shared-util-email/email-render";
|
|
26
|
-
import { AI_BUILD_PLAN_CREATION_NOUNS, AI_BUILD_PLAN_EMBED_HOST_NAMES, AI_BUILD_PLAN_LIMITS, AI_PLAN_ASKS_FOR_VIDEO, aiEmbedHostOf, aiEmbedVideoKey, aiPlanCreateFor, aiPlanItemFor, aiPlanSlugKey, aiPlanUndeclaredRefs, isAiPlanNewRef } from "../model/ai-build-plan.js";
|
|
26
|
+
import { AI_BUILD_PLAN_CREATION_NOUNS, AI_BUILD_PLAN_EMBED_HOST_NAMES, AI_BUILD_PLAN_LIMITS, AI_PLAN_ASKS_FOR_VIDEO, aiEmbedHostOf, aiEmbedVideoKey, AI_PLAN_DATASET_ITEM_OP, aiPlanCreateFor, aiPlanFormDatasetNames, aiPlanItemFor, aiPlanSlugKey, aiPlanUndeclaredRefs, isAiPlanNewRef } from "../model/ai-build-plan.js";
|
|
27
27
|
import { aiCreationNoun, aiPlanCanPlaceForm, aiPlanUncreatable, aiPlanUncreatableKind } from "../model/ai-plan-capabilities.js";
|
|
28
28
|
import { aiFreeSiteSectionsWithin, aiSiteHomeMinSections, aiSitePlanIsHome } from "../model/ai-site-job.js";
|
|
29
29
|
import { AI_INSTANCE_REF_PROP, validateAiNodeTree } from "./ai-node-tree.js";
|
|
@@ -3324,6 +3324,135 @@ const FORM_SECTION_NAME = /\bform\b|\bsign[- ]?up\b|\bsubscribe\b|\bnewsletter\b
|
|
|
3324
3324
|
screens
|
|
3325
3325
|
}) : plan;
|
|
3326
3326
|
}
|
|
3327
|
+
/**
|
|
3328
|
+
* What customers say, which no dataset of the site's holds: a review, a
|
|
3329
|
+
* testimonial, a rating, a quote (AGL-3616). A job never writes them for the
|
|
3330
|
+
* people who did not, so a dataset of them is one nothing can seed.
|
|
3331
|
+
*/ export const AI_DATASET_SAID_NAME = /\b(reviews?|testimonials?|ratings?|quotes?|stars?|endorsements?)\b/i;
|
|
3332
|
+
/**
|
|
3333
|
+
* A plan that creates more datasets than this job may make is settled in
|
|
3334
|
+
* code, never re-asked (AGL-3616). The live eval of 2026-10-10 refused a
|
|
3335
|
+
* dental practice's plan four times over for a fourth dataset, and a food
|
|
3336
|
+
* bank's re-ask for one broke a layout rule its first answer had kept.
|
|
3337
|
+
*
|
|
3338
|
+
* A dataset of what customers say (`AI_DATASET_SAID_NAME`, in its name or a
|
|
3339
|
+
* field) is let go first, whatever the cap: both of those plans made one of
|
|
3340
|
+
* testimonials, which nothing may seed.
|
|
3341
|
+
*
|
|
3342
|
+
* The datasets kept are the most useful: the ones the most sections list,
|
|
3343
|
+
* a record template counting double, plan order breaking ties. Each one let
|
|
3344
|
+
* go leaves the plan whole — its `new:` reference comes off every section,
|
|
3345
|
+
* a record template of it becomes a page of its own, and a section that
|
|
3346
|
+
* listed it shows fewer items than rule 8 binds, so its items are written
|
|
3347
|
+
* out on the page. Where the job may create no dataset at all, rule 7 still
|
|
3348
|
+
* asks, as it does for any creation.
|
|
3349
|
+
*/ export function aiSettlePlanDatasets(plan, capabilities = null) {
|
|
3350
|
+
var _ref, _entry_left;
|
|
3351
|
+
const entry = capabilities == null ? void 0 : capabilities.create.dataset;
|
|
3352
|
+
if (!(entry == null ? void 0 : entry.allowed)) return plan;
|
|
3353
|
+
const cap = Math.min((_ref = capabilities == null ? void 0 : capabilities.datasetsMax) != null ? _ref : Infinity, (_entry_left = entry.left) != null ? _entry_left : Infinity);
|
|
3354
|
+
const datasets = plan.create.filter((one)=>one.kind === 'dataset');
|
|
3355
|
+
// A dataset a form writes to holds what visitors send (AGL-3616): its
|
|
3356
|
+
// fields may well be a rating or a quote request, and nothing seeds it.
|
|
3357
|
+
const forForms = aiPlanFormDatasetNames(plan);
|
|
3358
|
+
const said = (one)=>!forForms.has(one.name.trim().toLowerCase()) && (AI_DATASET_SAID_NAME.test(one.name) || one.fields.some((field)=>AI_DATASET_SAID_NAME.test(field)));
|
|
3359
|
+
if (!datasets.some(said) && (!Number.isFinite(cap) || datasets.length <= cap)) return plan;
|
|
3360
|
+
const named = (ref, name)=>!!ref && isAiPlanNewRef(ref) && ref.slice('new:'.length).trim().toLowerCase() === name.trim().toLowerCase();
|
|
3361
|
+
// A form's dataset counts as much as a record template: the form the
|
|
3362
|
+
// person asked for is built around it.
|
|
3363
|
+
const score = (name)=>(forForms.has(name.trim().toLowerCase()) ? 2 : 0) + plan.screens.reduce((total, screen)=>{
|
|
3364
|
+
var _screen_record;
|
|
3365
|
+
return total + (named((_screen_record = screen.record) == null ? void 0 : _screen_record.dataset, name) ? 2 : 0) + screen.sections.filter((section)=>section.uses.some((ref)=>named(ref, name))).length;
|
|
3366
|
+
}, 0);
|
|
3367
|
+
const ranked = datasets.filter((one)=>!said(one)).map((one, index)=>({
|
|
3368
|
+
name: one.name,
|
|
3369
|
+
index,
|
|
3370
|
+
score: score(one.name)
|
|
3371
|
+
})).sort((a, b)=>b.score - a.score || a.index - b.index);
|
|
3372
|
+
const kept = new Set(ranked.slice(0, Math.max(0, cap)).map((one)=>one.name.trim().toLowerCase()));
|
|
3373
|
+
const dropped = new Set(datasets.map((one)=>one.name.trim().toLowerCase()).filter((name)=>!kept.has(name)));
|
|
3374
|
+
const isDropped = (ref)=>[
|
|
3375
|
+
...dropped
|
|
3376
|
+
].some((name)=>named(ref, name));
|
|
3377
|
+
return _extends({}, plan, {
|
|
3378
|
+
create: plan.create.filter((one)=>one.kind !== 'dataset' || !dropped.has(one.name.trim().toLowerCase()))// A form whose dataset was let go sends its submissions to the Inbox only.
|
|
3379
|
+
.map((one)=>one.kind === 'form' && isDropped(one.writesTo) ? withoutWritesTo(one) : one),
|
|
3380
|
+
screens: plan.screens.map((screen)=>_extends({}, screen, {
|
|
3381
|
+
record: screen.record && isDropped(screen.record.dataset) ? null : screen.record,
|
|
3382
|
+
sections: screen.sections.map((section)=>section.uses.some(isDropped) ? _extends({}, section, {
|
|
3383
|
+
uses: section.uses.filter((ref)=>!isDropped(ref)),
|
|
3384
|
+
items: Math.min(section.items, AI_TYPED_LIST_MIN_ITEMS - 1)
|
|
3385
|
+
}) : section)
|
|
3386
|
+
}))
|
|
3387
|
+
});
|
|
3388
|
+
}
|
|
3389
|
+
/** A creation with no `writesTo`, as a plan that never said one reads. */ function withoutWritesTo(creation) {
|
|
3390
|
+
const rest = _extends({}, creation);
|
|
3391
|
+
delete rest.writesTo;
|
|
3392
|
+
return rest;
|
|
3393
|
+
}
|
|
3394
|
+
/**
|
|
3395
|
+
* A form's dataset, settled in code before the rules read the plan
|
|
3396
|
+
* (AGL-3616, Zach 2026-10-10: Aglyn AI's forms write to its datasets).
|
|
3397
|
+
*
|
|
3398
|
+
* - A `writesTo` that names nothing the form can write to comes off: a
|
|
3399
|
+
* `new:` of no dataset this plan creates, an id the inventory does not
|
|
3400
|
+
* hold, or a dataset this job may not create. The form is then the
|
|
3401
|
+
* form it always was, its submissions in the Inbox. A dataset the
|
|
3402
|
+
* inventory holds, named by its name rather than its id, is given its id.
|
|
3403
|
+
* - A dataset this plan creates for a form holds the people who send it:
|
|
3404
|
+
* no page lists it and none is its record template, so its `new:` comes
|
|
3405
|
+
* off every section and record that named it, and a section that listed
|
|
3406
|
+
* it shows fewer items than rule 8 binds.
|
|
3407
|
+
*/ export function aiSettlePlanFormDatasets(plan, inventory, capabilities = null) {
|
|
3408
|
+
var _ref;
|
|
3409
|
+
if (!plan.create.some((one)=>one.kind === 'form' && one.writesTo)) return plan;
|
|
3410
|
+
const held = (_ref = inventory == null ? void 0 : inventory.datasets) != null ? _ref : [];
|
|
3411
|
+
const creatable = !capabilities || capabilities.create.dataset.allowed;
|
|
3412
|
+
let changed = false;
|
|
3413
|
+
const create = plan.create.map((one)=>{
|
|
3414
|
+
if (one.kind !== 'form' || !one.writesTo) return one;
|
|
3415
|
+
const ref = one.writesTo.trim();
|
|
3416
|
+
if (isAiPlanNewRef(ref)) {
|
|
3417
|
+
var _aiPlanCreateFor, _aiPlanItemFor;
|
|
3418
|
+
if (creatable && ((_aiPlanCreateFor = aiPlanCreateFor(plan, ref)) == null ? void 0 : _aiPlanCreateFor.kind) === 'dataset') return one;
|
|
3419
|
+
// A build's dataset item, which the data plugin's operation makes.
|
|
3420
|
+
if (((_aiPlanItemFor = aiPlanItemFor(plan, ref)) == null ? void 0 : _aiPlanItemFor.op) === AI_PLAN_DATASET_ITEM_OP) return one;
|
|
3421
|
+
} else {
|
|
3422
|
+
if (held.some((row)=>row.id === ref)) return one;
|
|
3423
|
+
const byName = held.find((row)=>aiNamesMatch(row.name, ref));
|
|
3424
|
+
if (byName) {
|
|
3425
|
+
changed = true;
|
|
3426
|
+
return _extends({}, one, {
|
|
3427
|
+
writesTo: byName.id
|
|
3428
|
+
});
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
changed = true;
|
|
3432
|
+
return withoutWritesTo(one);
|
|
3433
|
+
});
|
|
3434
|
+
const settled = _extends({}, plan, {
|
|
3435
|
+
create
|
|
3436
|
+
});
|
|
3437
|
+
const forForms = aiPlanFormDatasetNames(settled);
|
|
3438
|
+
const listsOne = (ref)=>isAiPlanNewRef(ref) && forForms.has(ref.slice('new:'.length).trim().toLowerCase());
|
|
3439
|
+
const screens = plan.screens.map((screen)=>{
|
|
3440
|
+
const record = screen.record && listsOne(screen.record.dataset) ? null : screen.record;
|
|
3441
|
+
const sections = screen.sections.map((section)=>section.uses.some(listsOne) ? _extends({}, section, {
|
|
3442
|
+
uses: section.uses.filter((ref)=>!listsOne(ref)),
|
|
3443
|
+
items: Math.min(section.items, AI_TYPED_LIST_MIN_ITEMS - 1)
|
|
3444
|
+
}) : section);
|
|
3445
|
+
if (record === screen.record && sections.every((section, index)=>section === screen.sections[index])) return screen;
|
|
3446
|
+
changed = true;
|
|
3447
|
+
return _extends({}, screen, {
|
|
3448
|
+
record,
|
|
3449
|
+
sections
|
|
3450
|
+
});
|
|
3451
|
+
});
|
|
3452
|
+
return changed ? _extends({}, settled, {
|
|
3453
|
+
screens
|
|
3454
|
+
}) : plan;
|
|
3455
|
+
}
|
|
3327
3456
|
/**
|
|
3328
3457
|
* A page that names no layout, on a site where only one layout can frame it,
|
|
3329
3458
|
* is put in that layout before the rules read the plan (2026-10-07). The
|