@aglyn/plugins-ai 1.0.0-beta.272 → 1.0.0-beta.273
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-site-start-card.component.js +237 -234
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/jobs/ai-empty-site-sweep.d.ts +12 -1
- package/src/lib/jobs/ai-empty-site-sweep.js +15 -3
- package/src/lib/jobs/ai-empty-site-sweep.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +21 -2
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-seo-step.js +8 -4
- package/src/lib/jobs/ai-job-seo-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +39 -1
- package/src/lib/jobs/ai-job-site-datasets.js +111 -15
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +12 -3
- package/src/lib/jobs/ai-job-site-step.js +85 -11
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +8 -0
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +3 -0
- package/src/lib/jobs/ai-jobs.js +4 -0
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-owner-photos.js +4 -4
- package/src/lib/jobs/ai-layout-owner-photos.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +35 -0
- package/src/lib/jobs/ai-layout-stock-photos.js +114 -43
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-late-photos.d.ts +143 -0
- package/src/lib/jobs/ai-site-late-photos.js +486 -0
- package/src/lib/jobs/ai-site-late-photos.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +18 -0
- package/src/lib/jobs/ai-site-publish.js +123 -5
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-site-late-photos-laurel-fork.d.ts +83 -0
- package/src/lib/jobs/fixtures/ai-site-late-photos-laurel-fork.js +1553 -0
- package/src/lib/jobs/fixtures/ai-site-late-photos-laurel-fork.js.map +1 -0
- package/src/lib/layout-language/ai-layout-pictures.d.ts +50 -13
- package/src/lib/layout-language/ai-layout-pictures.js +81 -19
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +10 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-photos.d.ts +119 -0
- package/src/lib/model/ai-site-photos.js +128 -0
- package/src/lib/model/ai-site-photos.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +3 -1
- package/src/lib/runtime/ai-doctrine-validators.js +3 -1
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/seo-fields.d.ts +29 -4
- package/src/lib/runtime/seo-fields.js +58 -11
- package/src/lib/runtime/seo-fields.js.map +1 -1
- package/src/lib/tools/ai-seo-tool.d.ts +25 -1
- package/src/lib/tools/ai-seo-tool.js +61 -0
- package/src/lib/tools/ai-seo-tool.js.map +1 -1
|
@@ -29,7 +29,7 @@ import { aiModelForStep } from "../providers/routing.js";
|
|
|
29
29
|
import { registerAiJobAdmission } from "./ai-job-admission.js";
|
|
30
30
|
import { aiOriginJobId, aiRecordedJobDraftId } from "./ai-job-draft-ids.js";
|
|
31
31
|
import { readAiDraftNodes } from "./ai-job-drafts.js";
|
|
32
|
-
import { AI_STOCK_PHOTO_AVOID_INPUT, AI_STOCK_PHOTO_JOB_PHOTOS_INPUT, AI_STOCK_PHOTO_PAGES_INPUT } from "./ai-layout-stock-photos.js";
|
|
32
|
+
import { AI_STOCK_PHOTO_AVOID_INPUT, AI_STOCK_PHOTO_JOB_PHOTOS_INPUT, AI_STOCK_PHOTO_LATE_PASS_INPUT, AI_STOCK_PHOTO_PAGES_INPUT } from "./ai-layout-stock-photos.js";
|
|
33
33
|
import { AI_LAYOUT_SITE_ALIASES_INPUT, AI_LAYOUT_SITE_PAGES_INPUT, AI_LAYOUT_SITE_PAGES_MAX, aiLayoutIsHomeSlug, aiLayoutSitePagesOfPlan } from "./ai-job-layout-site-pages.js";
|
|
34
34
|
import { aiPageSectionNodeId } from "./ai-job-page-sections.js";
|
|
35
35
|
import { AI_LAYOUT_LISTINGS_INPUT, aiLayoutIsShopPage } from "../layout-language/ai-layout-listings.js";
|
|
@@ -47,6 +47,8 @@ import { AI_FORM_DATASET_MADE_INPUT } from "./ai-job-form-dataset.js";
|
|
|
47
47
|
import { aiConfirmedPlan, aiUnspentOutcome } from "./ai-job-generation.js";
|
|
48
48
|
import { AI_JOB_BRIEF_MAX_CHARS } from "./ai-job-text-step.js";
|
|
49
49
|
import { AI_JOB_PAGE_STEP_MINIMUM_MS } from "./ai-job-page-budget.js";
|
|
50
|
+
import { aiSiteMergePhotos, aiSitePhotosOwed } from "../model/ai-site-photos.js";
|
|
51
|
+
import { AI_SITE_LATE_PHOTOS_MINIMUM_MS, aiSiteLatePhotos } from "./ai-site-late-photos.js";
|
|
50
52
|
import { AI_SITE_INSPIRATION_SIGNALS_INPUT, aiSiteInspirationReleased } from "./ai-site-inspiration.js";
|
|
51
53
|
import { aiSiteInspirationRefusal } from "../model/ai-site-inspiration.js";
|
|
52
54
|
import { aiJobStepRunMinimumMs, aiJobStepRunnerFor, registerAiJobStep, registerAiJobStepPasses } from "./ai-jobs.js";
|
|
@@ -142,13 +144,18 @@ import { aiJobStepRunMinimumMs, aiJobStepRunnerFor, registerAiJobStep, registerA
|
|
|
142
144
|
export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to build.';
|
|
143
145
|
/** What a scaffold answers where the step that builds a page is not loaded. */ export const AI_SITE_NO_PAGE_STEP_COPY = 'Building a whole site is not available yet.';
|
|
144
146
|
/** A unit that finished without reporting what it built; the scaffold cannot go on. */ export const AI_SITE_UNIT_EMPTY_COPY = 'Part of this site could not be built. Try the site brief again.';
|
|
147
|
+
/**
|
|
148
|
+
* The passes the late photo pass may add (AGL-3988): the one that hands the
|
|
149
|
+
* publish to it, its own, and one more where a beat's time ran out on it.
|
|
150
|
+
* That last one publishes whatever the pictures hold (`latePasses`).
|
|
151
|
+
*/ export const AI_SITE_LATE_PHOTOS_PASSES = 3;
|
|
145
152
|
/**
|
|
146
153
|
* The most passes a scaffold's step may take: the largest plan it admits —
|
|
147
154
|
* eight pages of eight sections, its three creations, a blog's first posts
|
|
148
|
-
* (one a pass, the largest part)
|
|
149
|
-
* spare, so a runner that never finishes is
|
|
150
|
-
* is not.
|
|
151
|
-
*/ export const AI_SITE_MAX_PASSES = AI_SITE_PAGES.max * (AI_SITE_MAX_SECTIONS + 1) + CREATION_UNITS.length + AI_SITE_DATASETS_MAX + AI_SITE_EVENTS_MAX + AI_SITE_POSTS + 2;
|
|
155
|
+
* (one a pass, the largest part), a welcome email and the late photo pass
|
|
156
|
+
* (AGL-3988) — with nothing to spare, so a runner that never finishes is
|
|
157
|
+
* still bounded while a real site is not.
|
|
158
|
+
*/ export const AI_SITE_MAX_PASSES = AI_SITE_PAGES.max * (AI_SITE_MAX_SECTIONS + 1) + CREATION_UNITS.length + AI_SITE_DATASETS_MAX + AI_SITE_EVENTS_MAX + AI_SITE_POSTS + 2 + AI_SITE_LATE_PHOTOS_PASSES;
|
|
152
159
|
/**
|
|
153
160
|
* The units a plan implies, in build order: the palette first, because a
|
|
154
161
|
* member reads it while the pages are still building; then the layout every
|
|
@@ -546,6 +553,8 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
|
|
|
546
553
|
// Which a picture the library fails takes before any starter (AGL-3988).
|
|
547
554
|
const recordPhotos = aiSiteDatasetPlacedPhotoDetails((_job_outputs4 = job.outputs) != null ? _job_outputs4 : []);
|
|
548
555
|
if (recordPhotos.length) unitInputs[AI_STOCK_PHOTO_JOB_PHOTOS_INPUT] = recordPhotos;
|
|
556
|
+
// And that the site's late photo pass fills what none of them fits yet (AGL-3988).
|
|
557
|
+
if (job.kind === 'site') unitInputs[AI_STOCK_PHOTO_LATE_PASS_INPUT] = true;
|
|
549
558
|
}
|
|
550
559
|
// The layout is built before the pages, so it is told them (AGL-3596): their
|
|
551
560
|
// ids are minted on the plan, and the platform writes the header's links.
|
|
@@ -906,6 +915,10 @@ export const aiSiteJobAdmission = createAiSiteJobAdmission();
|
|
|
906
915
|
built: true
|
|
907
916
|
};
|
|
908
917
|
}
|
|
918
|
+
/** The photos state a site job holds once its late photo pass is done: nothing left (AGL-3988). */ const AI_SITE_PHOTOS_SETTLED = {
|
|
919
|
+
pages: [],
|
|
920
|
+
lists: []
|
|
921
|
+
};
|
|
909
922
|
/** A page the scaffold reported built that holds none of its plan's sections. */ export const AI_SITE_PAGE_NOT_WRITTEN_COPY = 'A page of this site was not written from its plan. Try the site brief again.';
|
|
910
923
|
/**
|
|
911
924
|
* Whether a page unit's draft holds the sections its plan named, under the
|
|
@@ -1004,7 +1017,7 @@ export const aiSiteJobAdmission = createAiSiteJobAdmission();
|
|
|
1004
1017
|
}).filter((unit)=>unit.kind === 'store' && ledgered('store') || unit.kind === 'theme' || unit.kind === 'posts' && ledgered('posts') || unit.kind === 'dataset' || unit.kind === 'event' || unit.kind !== 'store' && runnerFor(unit.jobKind));
|
|
1005
1018
|
}
|
|
1006
1019
|
export function createAiJobSiteStep(deps = {}) {
|
|
1007
|
-
var _deps_runnerFor, _deps_readNodes, _deps_publish, _deps_siteName, _deps_look, _deps_contentRefusal, _deps_datasetRefusal, _deps_eventRefusal, _deps_storePagesRefusal, _deps_publishPosts, _deps_dropCache, _deps_restoreBlogEntry;
|
|
1020
|
+
var _deps_runnerFor, _deps_readNodes, _deps_publish, _deps_siteName, _deps_look, _deps_contentRefusal, _deps_datasetRefusal, _deps_eventRefusal, _deps_storePagesRefusal, _deps_publishPosts, _deps_dropCache, _deps_restoreBlogEntry, _deps_latePhotos;
|
|
1008
1021
|
const runnerFor = (_deps_runnerFor = deps.runnerFor) != null ? _deps_runnerFor : aiJobStepRunnerFor;
|
|
1009
1022
|
const readNodes = (_deps_readNodes = deps.readNodes) != null ? _deps_readNodes : readAiDraftNodes;
|
|
1010
1023
|
const publish = (_deps_publish = deps.publish) != null ? _deps_publish : aiPublishGuidedSite;
|
|
@@ -1017,8 +1030,9 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
1017
1030
|
const publishPosts = (_deps_publishPosts = deps.publishPosts) != null ? _deps_publishPosts : aiPublishSitePosts;
|
|
1018
1031
|
const dropCache = (_deps_dropCache = deps.dropCache) != null ? _deps_dropCache : dropPluginSiteCache;
|
|
1019
1032
|
const restoreBlogEntry = (_deps_restoreBlogEntry = deps.restoreBlogEntry) != null ? _deps_restoreBlogEntry : aiRestoreGuidedBlogEntry;
|
|
1033
|
+
const latePhotos = (_deps_latePhotos = deps.latePhotos) != null ? _deps_latePhotos : aiSiteLatePhotos;
|
|
1020
1034
|
return async (context)=>{
|
|
1021
|
-
var _ref, _job_outputs, _deps_posts, _deps_products, _deps_dataset, _deps_event, _deps_storePages, _job_outputs1;
|
|
1035
|
+
var _ref, _job_outputs, _job_sitePhotos, _deps_posts, _deps_products, _deps_dataset, _deps_event, _deps_storePages, _job_outputs1;
|
|
1022
1036
|
var _job_items, _rows_get, _rows_get1, _rows_get2, _rows_get3;
|
|
1023
1037
|
const { job } = context;
|
|
1024
1038
|
// The scaffold asks no model of its own. What it names where it spends
|
|
@@ -1059,6 +1073,17 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
1059
1073
|
]));
|
|
1060
1074
|
const next = aiBuildNextUnit(ledgerUnits, ledger);
|
|
1061
1075
|
/**
|
|
1076
|
+
* The pictures the start left on a starter (AGL-3988): what the job
|
|
1077
|
+
* holds, with what this pass's unit reported merged in once it ran.
|
|
1078
|
+
*/ let photos = (_job_sitePhotos = job.sitePhotos) != null ? _job_sitePhotos : null;
|
|
1079
|
+
let photosReported = false;
|
|
1080
|
+
/**
|
|
1081
|
+
* Whether the publish waits for the late photo pass: a record, or a
|
|
1082
|
+
* picture of a page it puts live, is still on a starter. A page that
|
|
1083
|
+
* failed is not published, so its pictures owe nothing. `pages`: the
|
|
1084
|
+
* pages built so far, the one this pass built among them.
|
|
1085
|
+
*/ const latePhotosOwed = (pages)=>Boolean(job.hostId) && aiSitePhotosOwed(photos, pages.map((page)=>page.id));
|
|
1086
|
+
/**
|
|
1062
1087
|
* A guided start's last pass puts what it built on the site (AGL-3596):
|
|
1063
1088
|
* only its pages that were built. Once it has, Try again's last pass puts
|
|
1064
1089
|
* only the pages the retry built live (AGL-3730), never the home address
|
|
@@ -1240,7 +1265,40 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
1240
1265
|
unit.screen.id
|
|
1241
1266
|
] : [];
|
|
1242
1267
|
});
|
|
1243
|
-
if (!next)
|
|
1268
|
+
if (!next) {
|
|
1269
|
+
// Every part is built: the pictures left on a starter take the job's
|
|
1270
|
+
// own photos before the site goes live (AGL-3988), in a pass of their
|
|
1271
|
+
// own, sized to wait out the image hosts' burst.
|
|
1272
|
+
if (latePhotosOwed(builtPages()) && photos && !await aiJobCancelAsked(context.firestore, job, context.signal)) {
|
|
1273
|
+
var _context_org, _photos_latePasses;
|
|
1274
|
+
const late = await latePhotos(_extends({
|
|
1275
|
+
firestore: context.firestore,
|
|
1276
|
+
job,
|
|
1277
|
+
photos,
|
|
1278
|
+
pageIds: builtPages().map((page)=>page.id),
|
|
1279
|
+
org: (_context_org = context.org) != null ? _context_org : null,
|
|
1280
|
+
now: context.now
|
|
1281
|
+
}, context.signal ? {
|
|
1282
|
+
signal: context.signal
|
|
1283
|
+
} : {}));
|
|
1284
|
+
// A pass whose time ran out while it waited hands what is left to the
|
|
1285
|
+
// next, inside the passes the bound gives it: the last one publishes
|
|
1286
|
+
// whatever the pictures hold, so a site is never held back by them.
|
|
1287
|
+
const latePasses = ((_photos_latePasses = photos.latePasses) != null ? _photos_latePasses : 0) + 1;
|
|
1288
|
+
if (late.photos && latePasses < AI_SITE_LATE_PHOTOS_PASSES - 1) {
|
|
1289
|
+
return _extends({}, aiUnspentOutcome(model), init, {
|
|
1290
|
+
continue: true,
|
|
1291
|
+
sitePhotos: _extends({}, late.photos, {
|
|
1292
|
+
latePasses
|
|
1293
|
+
})
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
return finish(_extends({}, aiUnspentOutcome(model), init, {
|
|
1297
|
+
sitePhotos: AI_SITE_PHOTOS_SETTLED
|
|
1298
|
+
}), builtPages());
|
|
1299
|
+
}
|
|
1300
|
+
return finish(_extends({}, aiUnspentOutcome(model), init), builtPages());
|
|
1301
|
+
}
|
|
1244
1302
|
const unit = units.find((one)=>one.slot === next.slot);
|
|
1245
1303
|
// The look is the scaffold's own pass (AGL-3660), not the theme job's proposal.
|
|
1246
1304
|
const catalog = unit.kind === 'products' ? runnerFor('products') : undefined;
|
|
@@ -1267,13 +1325,17 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
1267
1325
|
item
|
|
1268
1326
|
}, item.status === 'running' || othersOpen ? {
|
|
1269
1327
|
continue: true
|
|
1328
|
+
} : {}, photosReported ? {
|
|
1329
|
+
sitePhotos: photos != null ? photos : AI_SITE_PHOTOS_SETTLED
|
|
1270
1330
|
} : {});
|
|
1271
1331
|
/**
|
|
1272
1332
|
* A unit that failed or was skipped with nothing else open ends the job
|
|
1273
1333
|
* on this pass (AGL-3676): a guided start whose last unit — its welcome
|
|
1274
1334
|
* email — failed was never published, because the pass that publishes is
|
|
1275
1335
|
* the one after. So the end is the publish, whatever the last unit came to.
|
|
1276
|
-
*/ const closing = async (outcome)=>outcome.continue ? outcome :
|
|
1336
|
+
*/ const closing = async (outcome)=>outcome.continue ? outcome : latePhotosOwed(builtPages()) ? _extends({}, outcome, {
|
|
1337
|
+
continue: true
|
|
1338
|
+
}) : finish(outcome, builtPages());
|
|
1277
1339
|
// A blog's posts and a store's products ask, before their first pass,
|
|
1278
1340
|
// whether this member may have them here (AGL-3676): a refusal spends
|
|
1279
1341
|
// nothing, and the row says why, as a build's item does.
|
|
@@ -1424,6 +1486,11 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
1424
1486
|
}
|
|
1425
1487
|
}));
|
|
1426
1488
|
}
|
|
1489
|
+
// The pictures this unit left on a starter, kept on the job for the late photo pass (AGL-3988).
|
|
1490
|
+
if (outcome.sitePhotos) {
|
|
1491
|
+
photos = aiSiteMergePhotos(photos, outcome.sitePhotos);
|
|
1492
|
+
photosReported = true;
|
|
1493
|
+
}
|
|
1427
1494
|
const spent = aiUnitSpend(outcome);
|
|
1428
1495
|
const stopped = aiUnitFailure(unit.slot, outcome);
|
|
1429
1496
|
if (stopped) {
|
|
@@ -1472,7 +1539,12 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
1472
1539
|
rows.set(unit.slot, _extends({}, rows.get(unit.slot), {
|
|
1473
1540
|
status: degraded ? 'degraded' : 'succeeded'
|
|
1474
1541
|
}));
|
|
1475
|
-
|
|
1542
|
+
const live = builtPages(unit.kind === 'page' && !templates.has(unit.slot) || unit.kind === 'store' ? outcome.outputs.filter((output)=>output.resource === 'screen') : []);
|
|
1543
|
+
// The publish waits a pass for the late photo pass (AGL-3988).
|
|
1544
|
+
if (latePhotosOwed(live)) return _extends({}, done, {
|
|
1545
|
+
continue: true
|
|
1546
|
+
});
|
|
1547
|
+
return finish(done, live);
|
|
1476
1548
|
};
|
|
1477
1549
|
}
|
|
1478
1550
|
export const runAiJobSiteStep = createAiJobSiteStep();
|
|
@@ -1501,7 +1573,9 @@ export const runAiJobSiteStep = createAiJobSiteStep();
|
|
|
1501
1573
|
const ledger = ((_job_items1 = job.items) == null ? void 0 : _job_items1.length) ? job.items : aiSiteInitialLedger(units, outputs);
|
|
1502
1574
|
const next = aiBuildNextUnit(aiSiteLedgerUnits(units), ledger);
|
|
1503
1575
|
const unit = next ? units.find((one)=>one.slot === next.slot) : undefined;
|
|
1504
|
-
|
|
1576
|
+
// Nothing left to build: the late photo pass, where a picture is still on
|
|
1577
|
+
// a starter (AGL-3988), and the publish in the same pass.
|
|
1578
|
+
if (!unit) return aiSitePhotosOwed(job.sitePhotos) ? Math.max(AI_JOB_PAGE_STEP_MINIMUM_MS, AI_SITE_LATE_PHOTOS_MINIMUM_MS) : AI_JOB_PAGE_STEP_MINIMUM_MS;
|
|
1505
1579
|
if (unit.kind === 'theme') return AI_SITE_LOOK_BUDGET.minimumMs;
|
|
1506
1580
|
if (unit.kind === 'posts') return AI_SITE_POST_BUDGET.minimumMs;
|
|
1507
1581
|
if (unit.kind === 'dataset') return AI_SITE_DATASET_BUDGET.minimumMs;
|