@aglyn/plugins-ai 1.0.0-beta.233 → 1.0.0-beta.234
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.d.ts +6 -0
- package/src/lib/components/ai-job-links.js +9 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +41 -3
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +91 -8
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/jobs/ai-job-admission.d.ts +2 -1
- package/src/lib/jobs/ai-job-admission.js.map +1 -1
- package/src/lib/jobs/ai-job-email-step.d.ts +39 -0
- package/src/lib/jobs/ai-job-email-step.js +116 -5
- package/src/lib/jobs/ai-job-email-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +3 -0
- package/src/lib/jobs/ai-job-layout-language.js +3 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-site-pages.d.ts +2 -0
- package/src/lib/jobs/ai-job-layout-site-pages.js +23 -11
- package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +3 -2
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +16 -0
- package/src/lib/jobs/ai-job-page-language.js +35 -6
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +3 -0
- package/src/lib/jobs/ai-job-page-step.js +18 -4
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +34 -0
- package/src/lib/jobs/ai-job-plan-step.js +106 -14
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +6 -6
- package/src/lib/jobs/ai-job-site-content.js +6 -12
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +11 -0
- package/src/lib/jobs/ai-job-site-step.js +96 -44
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +8 -4
- package/src/lib/jobs/ai-jobs.js +19 -2
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +98 -0
- package/src/lib/jobs/ai-layout-stock-photos.js +248 -0
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +11 -0
- package/src/lib/jobs/ai-site-publish.js +31 -1
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.d.ts +151 -0
- package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.js +183 -0
- package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.js +192 -0
- package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.js +222 -0
- package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +29 -0
- package/src/lib/layout-language/ai-layout-compiler.js +698 -12
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +107 -0
- package/src/lib/layout-language/ai-layout-design.js +197 -0
- package/src/lib/layout-language/ai-layout-design.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +6 -0
- package/src/lib/layout-language/ai-layout-frame.js +22 -6
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-language.js +15 -1
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-links.d.ts +11 -0
- package/src/lib/layout-language/ai-layout-links.js +4 -0
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +11 -5
- package/src/lib/layout-language/ai-layout-pictures.js +80 -17
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +9 -1
- package/src/lib/model/ai-job-notice.js +23 -0
- package/src/lib/model/ai-job-notice.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-build-progress.d.ts +12 -2
- package/src/lib/model/ai-site-build-progress.js +78 -4
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +209 -22
- package/src/lib/model/ai-site-job.js +247 -20
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.js +6 -1
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +21 -0
- package/src/lib/model/ai-site-look.js +63 -14
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +32 -1
- package/src/lib/runtime/ai-doctrine-validators.js +227 -4
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +5 -3
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.d.ts +2 -0
- package/src/lib/runtime/ai-palette.generated.js +18 -2
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +15 -3
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/server/assist-edit.js +5 -2
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/usage/free-ai-credits-left.d.ts +54 -0
- package/src/lib/usage/free-ai-credits-left.js +62 -0
- package/src/lib/usage/free-ai-credits-left.js.map +1 -0
|
@@ -18,6 +18,7 @@ import { type AiBuildPlanCreate, type AiBuildPlanScreen } from '../model/ai-buil
|
|
|
18
18
|
import type { AiJob, AiJobItemLedger, AiJobKind, AiJobOutput, AiJobOutputResource, AiJobPlan } from '../model/ai-jobs.types';
|
|
19
19
|
import { type AiBuildUnit } from '../model/ai-build-job';
|
|
20
20
|
import { type AiSiteJobInputs } from '../model/ai-site-job';
|
|
21
|
+
import { readFreeAiCreditsLeft } from '../usage/free-ai-credits-left';
|
|
21
22
|
import { type AiJobAdmission } from './ai-job-admission';
|
|
22
23
|
import { readAiDraftNodes } from './ai-job-drafts';
|
|
23
24
|
import { aiPublishGuidedSite } from './ai-site-publish';
|
|
@@ -219,11 +220,21 @@ export declare function aiSiteUnitJobId(job: Pick<AiJob, '$id' | 'steps'>, unit:
|
|
|
219
220
|
* for leaving it out.
|
|
220
221
|
*/
|
|
221
222
|
export declare function aiSiteUnitJob(job: AiJob, unit: AiSiteUnit, built: BuiltRefs): AiJob;
|
|
223
|
+
/**
|
|
224
|
+
* Whether this site start writes its first posts (AGL-3676): its ledger owes
|
|
225
|
+
* the posts part and has not given up on it. The ledger is written before the
|
|
226
|
+
* layout is built, so the header knows the blog before it exists.
|
|
227
|
+
*/
|
|
228
|
+
export declare function aiSiteWritesPosts(job: Pick<AiJob, 'items'>): boolean;
|
|
222
229
|
/**
|
|
223
230
|
* A scaffold is admitted with inputs that read, for a site of the job's own
|
|
224
231
|
* org, and only where this deployment has loaded the step that builds a page:
|
|
225
232
|
* a scaffold whose pages nothing can build is not a scaffold.
|
|
226
233
|
*/
|
|
234
|
+
export declare function createAiSiteJobAdmission(deps?: {
|
|
235
|
+
freeCreditsLeft?: typeof readFreeAiCreditsLeft;
|
|
236
|
+
now?: () => Date;
|
|
237
|
+
}): AiJobAdmission;
|
|
227
238
|
export declare const aiSiteJobAdmission: AiJobAdmission;
|
|
228
239
|
/** Whether a scaffold's workspace spends the Free taste (AGL-3594); a missing org reads as paid, as the band has always been. */
|
|
229
240
|
export declare function aiSiteFreeTaste(org: object | null | undefined): boolean;
|
|
@@ -19,13 +19,14 @@ import { resolveOrgIdForHost } from "@aglyn/tenant-data-admin/server/organizatio
|
|
|
19
19
|
import { isAiPlanNewRef } from "../model/ai-build-plan.js";
|
|
20
20
|
import { aiBuildDegradation, aiBuildInitialLedger, aiBuildItemDelivered, aiBuildItemOpen, aiBuildNextUnit } from "../model/ai-build-job.js";
|
|
21
21
|
import { aiBuildBuiltRefs, aiUnitErrorRetryable, aiUnitFailure, aiUnitSpend } from "./ai-build-unit-outcome.js";
|
|
22
|
-
import { AI_SITE_EMAIL_TYPE, AI_SITE_MAX_SECTIONS, AI_SITE_PAGES, aiSiteNameSentence, aiSitePagesRefusal, aiSitePlanRefusal, aiSiteSubmissions, aiSiteWords, parseAiSiteJobInputs } from "../model/ai-site-job.js";
|
|
22
|
+
import { AI_SITE_EMAIL_TYPE, AI_SITE_MAX_SECTIONS, AI_SITE_PAGES, aiFreeSiteShortfall, aiFreeSiteShortfallText, aiSiteNameSentence, aiSitePagesRefusal, aiSitePlanRefusal, aiSiteSubmissions, aiSiteWords, parseAiSiteJobInputs, aiSiteBlogNavPage } from "../model/ai-site-job.js";
|
|
23
|
+
import { readFreeAiCreditsLeft } from "../usage/free-ai-credits-left.js";
|
|
23
24
|
import { AI_SITE_SEO_OUTPUT_ID, aiSiteSeoProposalForInputs } from "../model/ai-site-start-seo.js";
|
|
24
25
|
import { aiModelForStep } from "../providers/routing.js";
|
|
25
26
|
import { registerAiJobAdmission } from "./ai-job-admission.js";
|
|
26
27
|
import { aiOriginJobId, aiRecordedJobDraftId } from "./ai-job-draft-ids.js";
|
|
27
28
|
import { readAiDraftNodes } from "./ai-job-drafts.js";
|
|
28
|
-
import { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from "./ai-job-layout-site-pages.js";
|
|
29
|
+
import { AI_LAYOUT_SITE_PAGES_INPUT, AI_LAYOUT_SITE_PAGES_MAX, aiLayoutIsHomeSlug, aiLayoutSitePagesOfPlan } from "./ai-job-layout-site-pages.js";
|
|
29
30
|
import { aiPageSectionNodeId } from "./ai-job-page-sections.js";
|
|
30
31
|
import { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from "./ai-job-page-language.js";
|
|
31
32
|
import { aiJobPublishesSite, aiPublishGuidedSite } from "./ai-site-publish.js";
|
|
@@ -429,10 +430,22 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
|
|
|
429
430
|
// ids are minted on the plan, and the platform writes the header's links.
|
|
430
431
|
// A page is told them too, so its buttons may go to a page built after it.
|
|
431
432
|
if (job.kind === 'site' && (unit.kind === 'layout' || unit.kind === 'page')) {
|
|
432
|
-
// A guided start links every page the person asked for (AGL-3660)
|
|
433
|
-
|
|
433
|
+
// A guided start links every page the person asked for (AGL-3660), and
|
|
434
|
+
// the blog its first posts are written into, by its path, second after
|
|
435
|
+
// Home (AGL-3676): the live Slow Roads start linked an "Articles" page
|
|
436
|
+
// and never the blog.
|
|
437
|
+
const planned = aiLayoutSitePagesOfPlan(plan.screens, {
|
|
434
438
|
guided: true
|
|
435
439
|
});
|
|
440
|
+
const blog = aiSiteWritesPosts(job) ? [
|
|
441
|
+
aiSiteBlogNavPage(plan.screens)
|
|
442
|
+
] : [];
|
|
443
|
+
const homes = planned.filter((page)=>aiLayoutIsHomeSlug(page.slug));
|
|
444
|
+
const pages = [
|
|
445
|
+
...homes,
|
|
446
|
+
...blog,
|
|
447
|
+
...planned.filter((page)=>!aiLayoutIsHomeSlug(page.slug))
|
|
448
|
+
].slice(0, AI_LAYOUT_SITE_PAGES_MAX);
|
|
436
449
|
if (pages.length) unitInputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages;
|
|
437
450
|
}
|
|
438
451
|
// A site's pages and its layout are designed in the layout language and
|
|
@@ -445,7 +458,8 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
|
|
|
445
458
|
const style = look == null ? void 0 : (_look_proposal = look.proposal) == null ? void 0 : _look_proposal['style'];
|
|
446
459
|
if (style) unitInputs['siteStyle'] = {
|
|
447
460
|
headerAlign: style['headerAlign'],
|
|
448
|
-
rhythm: style['rhythm']
|
|
461
|
+
rhythm: style['rhythm'],
|
|
462
|
+
seed: style['seed']
|
|
449
463
|
};
|
|
450
464
|
unitInputs[AI_LAYOUT_LANGUAGE_INPUT] = true;
|
|
451
465
|
const formPage = aiLayoutFormPageOfPlan(plan);
|
|
@@ -484,52 +498,84 @@ export const AI_SITE_NO_PLAN_COPY = 'This site job has no confirmed plan to buil
|
|
|
484
498
|
brief: brief.join('\n').slice(0, AI_JOB_BRIEF_MAX_CHARS)
|
|
485
499
|
});
|
|
486
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Whether this site start writes its first posts (AGL-3676): its ledger owes
|
|
503
|
+
* the posts part and has not given up on it. The ledger is written before the
|
|
504
|
+
* layout is built, so the header knows the blog before it exists.
|
|
505
|
+
*/ export function aiSiteWritesPosts(job) {
|
|
506
|
+
var _job_items;
|
|
507
|
+
return ((_job_items = job.items) != null ? _job_items : []).some((row)=>row.slot === 'posts' && row.status !== 'skipped' && row.status !== 'failed');
|
|
508
|
+
}
|
|
487
509
|
/**
|
|
488
510
|
* A scaffold is admitted with inputs that read, for a site of the job's own
|
|
489
511
|
* org, and only where this deployment has loaded the step that builds a page:
|
|
490
512
|
* a scaffold whose pages nothing can build is not a scaffold.
|
|
491
|
-
*/ export
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
// taste, four to eight on a paid plan.
|
|
499
|
-
const freeTaste = aiSiteFreeTaste(context.org);
|
|
500
|
-
const pages = aiSitePagesRefusal(inputs.pages, freeTaste);
|
|
501
|
-
if (pages) return {
|
|
502
|
-
status: 400,
|
|
503
|
-
error: pages
|
|
504
|
-
};
|
|
505
|
-
if (context.plan) {
|
|
506
|
-
const shape = aiSitePlanRefusal(context.plan, {
|
|
507
|
-
freeTaste
|
|
508
|
-
});
|
|
509
|
-
if (shape) return {
|
|
513
|
+
*/ export function createAiSiteJobAdmission(deps = {}) {
|
|
514
|
+
var _deps_freeCreditsLeft, _deps_now;
|
|
515
|
+
const freeCreditsLeft = (_deps_freeCreditsLeft = deps.freeCreditsLeft) != null ? _deps_freeCreditsLeft : readFreeAiCreditsLeft;
|
|
516
|
+
const now = (_deps_now = deps.now) != null ? _deps_now : ()=>new Date();
|
|
517
|
+
return async (context)=>{
|
|
518
|
+
const inputs = parseAiSiteJobInputs(context.inputs);
|
|
519
|
+
if (typeof inputs === 'string') return {
|
|
510
520
|
status: 400,
|
|
511
|
-
error:
|
|
521
|
+
error: inputs
|
|
512
522
|
};
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
523
|
+
// The workspace's own page band (AGL-3594): one or two pages on the Free
|
|
524
|
+
// taste, four to eight on a paid plan.
|
|
525
|
+
const freeTaste = aiSiteFreeTaste(context.org);
|
|
526
|
+
const pages = aiSitePagesRefusal(inputs.pages, freeTaste);
|
|
527
|
+
if (pages) return {
|
|
516
528
|
status: 400,
|
|
517
|
-
error:
|
|
529
|
+
error: pages
|
|
518
530
|
};
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
531
|
+
// A Free start that what is left of the month's Free credits cannot pay for
|
|
532
|
+
// is refused before it spends (AGL-3660), on the figure the dialog quotes —
|
|
533
|
+
// the dialog asks the same, and this is what a stale dialog meets. Only at
|
|
534
|
+
// creation: a resume is the same job carrying on from where it paused.
|
|
535
|
+
if (freeTaste && !context.plan) {
|
|
536
|
+
const credits = await freeCreditsLeft(context.firestore, {
|
|
537
|
+
orgId: context.orgId,
|
|
538
|
+
org: context.org,
|
|
539
|
+
now: now()
|
|
540
|
+
});
|
|
541
|
+
const shortfall = aiFreeSiteShortfall(credits, inputs.pages);
|
|
542
|
+
if (credits && shortfall) {
|
|
543
|
+
return {
|
|
544
|
+
status: 429,
|
|
545
|
+
error: aiFreeSiteShortfallText(shortfall, credits.resetsOn)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (context.plan) {
|
|
550
|
+
const shape = aiSitePlanRefusal(context.plan, {
|
|
551
|
+
freeTaste
|
|
552
|
+
});
|
|
553
|
+
if (shape) return {
|
|
554
|
+
status: 400,
|
|
555
|
+
error: shape
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
if (!context.hostId) {
|
|
559
|
+
return {
|
|
560
|
+
status: 400,
|
|
561
|
+
error: 'Open the site the scaffold is for before starting the job'
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
const owner = await resolveOrgIdForHost(context.hostId);
|
|
565
|
+
if (!owner || owner !== context.orgId) return {
|
|
566
|
+
status: 404,
|
|
567
|
+
error: 'Unknown site'
|
|
529
568
|
};
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
569
|
+
if (!aiJobStepRunnerFor('page')) {
|
|
570
|
+
return {
|
|
571
|
+
status: 400,
|
|
572
|
+
error: AI_SITE_NO_PAGE_STEP_COPY
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
export const aiSiteJobAdmission = createAiSiteJobAdmission();
|
|
533
579
|
/** Whether a scaffold's workspace spends the Free taste (AGL-3594); a missing org reads as paid, as the band has always been. */ export function aiSiteFreeTaste(org) {
|
|
534
580
|
return Boolean(org) && resolveEffectivePlan(org) === 'free';
|
|
535
581
|
}
|
|
@@ -709,12 +755,18 @@ export function createAiJobSiteStep(deps = {}) {
|
|
|
709
755
|
]));
|
|
710
756
|
const next = aiBuildNextUnit(ledgerUnits, ledger);
|
|
711
757
|
/** A guided start's last pass puts what it built on the site, once (AGL-3596): only its pages that were built. */ const finish = async (outcome, pages)=>{
|
|
758
|
+
var _postsRow_outputs;
|
|
712
759
|
if (!aiJobPublishesSite(job) || job.sitePublish || !job.hostId || !pages.length) return outcome;
|
|
713
|
-
|
|
760
|
+
// A blog the header links by path before its posts exist (AGL-3660):
|
|
761
|
+
// owed and not delivered, its links come out of what is published.
|
|
762
|
+
const postsRow = rows.get('posts');
|
|
763
|
+
const sitePublish = await publish(context.firestore, _extends({
|
|
714
764
|
job,
|
|
715
765
|
outputs: pages,
|
|
716
766
|
now: context.now
|
|
717
|
-
}
|
|
767
|
+
}, postsRow ? {
|
|
768
|
+
blogUnwritten: !aiBuildItemDelivered(postsRow) || !((_postsRow_outputs = postsRow.outputs) == null ? void 0 : _postsRow_outputs.length)
|
|
769
|
+
} : {})).catch((error)=>{
|
|
718
770
|
// The site is built either way; the pages stay drafts and say so.
|
|
719
771
|
console.error('ai site publish threw', {
|
|
720
772
|
orgId: job.orgId,
|