@aglyn/plugins-ai 1.0.0-beta.236 → 1.0.0-beta.238
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-credits-prompt.component.d.ts +44 -0
- package/src/lib/components/ai-credits-prompt.component.js +117 -0
- package/src/lib/components/ai-credits-prompt.component.js.map +1 -0
- package/src/lib/components/ai-job-cancel.component.d.ts +38 -0
- package/src/lib/components/ai-job-cancel.component.js +156 -0
- package/src/lib/components/ai-job-cancel.component.js.map +1 -0
- package/src/lib/components/ai-job-plan.component.d.ts +5 -4
- package/src/lib/components/ai-job-plan.component.js +48 -12
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +10 -0
- package/src/lib/components/ai-job-requests.js +12 -4
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-jobs-list-page.component.js +141 -72
- package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +48 -9
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +68 -22
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-usage-strip.component.d.ts +19 -2
- package/src/lib/components/ai-usage-strip.component.js +40 -9
- package/src/lib/components/ai-usage-strip.component.js.map +1 -1
- package/src/lib/components/assist-build-card.component.d.ts +3 -1
- package/src/lib/components/assist-build-card.component.js +58 -7
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +66 -22
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +89 -52
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/jobs/ai-job-admission.d.ts +22 -2
- package/src/lib/jobs/ai-job-admission.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +24 -11
- package/src/lib/jobs/ai-job-build-step.js +54 -35
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-cancel.d.ts +71 -0
- package/src/lib/jobs/ai-job-cancel.js +102 -0
- package/src/lib/jobs/ai-job-cancel.js.map +1 -0
- package/src/lib/jobs/ai-job-component-step.js +4 -1
- package/src/lib/jobs/ai-job-component-step.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.js +2 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.js +4 -1
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +2 -0
- package/src/lib/jobs/ai-job-layout-language.js +13 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +6 -1
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.js +12 -0
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +13 -0
- package/src/lib/jobs/ai-job-page-step.js +46 -4
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +42 -0
- package/src/lib/jobs/ai-job-plan-step.js +118 -18
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +49 -3
- package/src/lib/jobs/ai-job-site-content.js +196 -37
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +49 -16
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-template-step.js +4 -1
- package/src/lib/jobs/ai-job-template-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 +55 -13
- package/src/lib/jobs/ai-jobs.js +213 -41
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +194 -34
- package/src/lib/jobs/ai-layout-stock-photos.js +861 -146
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.d.ts +30 -0
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.js +220 -0
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.js +151 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +33 -0
- package/src/lib/layout-language/ai-layout-compiler.js +381 -18
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +6 -3
- package/src/lib/layout-language/ai-layout-design.js +5 -3
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-frame.js +58 -3
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-gaps.js +3 -1
- package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.js +1 -1
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +49 -1
- package/src/lib/layout-language/ai-layout-listings.js +117 -47
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +10 -1
- package/src/lib/layout-language/ai-layout-pictures.js +5 -2
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/layout-language/ai-layout-storefront.d.ts +82 -0
- package/src/lib/layout-language/ai-layout-storefront.js +223 -0
- package/src/lib/layout-language/ai-layout-storefront.js.map +1 -0
- package/src/lib/model/ai-build-job.d.ts +39 -0
- package/src/lib/model/ai-build-job.js +100 -1
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-progress.d.ts +8 -0
- package/src/lib/model/ai-build-progress.js +35 -0
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +249 -0
- package/src/lib/model/ai-credit-estimate.js +278 -0
- package/src/lib/model/ai-credit-estimate.js.map +1 -0
- package/src/lib/model/ai-job-cancel-copy.d.ts +44 -0
- package/src/lib/model/ai-job-cancel-copy.js +53 -0
- package/src/lib/model/ai-job-cancel-copy.js.map +1 -0
- package/src/lib/model/ai-job-failure-copy.d.ts +4 -1
- package/src/lib/model/ai-job-failure-copy.js +8 -3
- package/src/lib/model/ai-job-failure-copy.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +35 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-build-progress.js +7 -4
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +76 -22
- package/src/lib/model/ai-site-job.js +125 -23
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.d.ts +4 -1
- package/src/lib/model/ai-site-kinds.js +35 -7
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +37 -1
- package/src/lib/runtime/ai-doctrine-validators.js +161 -7
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +4 -3
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +11 -0
- package/src/lib/runtime/ai-node-tree.js +26 -0
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +592 -14
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/server/ai-jobs-cancel.d.ts +13 -5
- package/src/lib/server/ai-jobs-cancel.js +27 -9
- package/src/lib/server/ai-jobs-cancel.js.map +1 -1
- package/src/lib/server/ai-jobs-gate.d.ts +12 -2
- package/src/lib/server/ai-jobs-gate.js +20 -9
- package/src/lib/server/ai-jobs-gate.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js +93 -35
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +45 -4
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/server/assist-chat.js +4 -1
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit.js +3 -1
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/server/assist-music.d.ts +36 -0
- package/src/lib/server/assist-music.js +36 -0
- package/src/lib/server/assist-music.js.map +1 -0
- package/src/lib/server.js +6 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/usage/ai-usage-meter.d.ts +2 -1
- package/src/lib/usage/ai-usage-meter.js +17 -1
- package/src/lib/usage/ai-usage-meter.js.map +1 -1
- package/src/lib/usage/ai-usage-wire.d.ts +6 -0
- package/src/lib/usage/ai-usage-wire.js.map +1 -1
- package/src/lib/usage/assist-usage.d.ts +7 -0
- package/src/lib/usage/assist-usage.js +14 -4
- package/src/lib/usage/assist-usage.js.map +1 -1
- package/src/lib/usage/free-ai-credits-left.d.ts +7 -0
- package/src/lib/usage/free-ai-credits-left.js +4 -2
- package/src/lib/usage/free-ai-credits-left.js.map +1 -1
|
@@ -17,12 +17,15 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
17
17
|
*/ import { aiSiteKindOfInputs } from "../model/ai-site-kinds.js";
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
19
19
|
import { AI_BUILD_PLAN_TOOL, aiBuildPlanToolFor, isAiPlanNewRef } from "../model/ai-build-plan.js";
|
|
20
|
+
import { readFreeAiCreditsLeft } from "../usage/free-ai-credits-left.js";
|
|
20
21
|
import { AI_TEMPLATE_SUBJECT_DEFINITIONS, aiTemplateShownTokens } from "../model/ai-template-subjects.js";
|
|
21
22
|
import { AI_JOB_CREATE_KINDS, AI_JOB_CREATE_NOUNS } from "../model/ai-job-creations.js";
|
|
22
23
|
import { AI_PAGE_CREATE_KINDS, aiPagePlanShapeRefusal } from "../model/ai-page-job.js";
|
|
23
24
|
import { AI_PLAN_COMPILED_REPEATS_SENTENCE, AI_PLAN_NO_FORM_SENTENCE, aiPlanCanPlaceForm, aiPlanCapabilitiesForJob, aiPlanCapabilityLines } from "../model/ai-plan-capabilities.js";
|
|
24
25
|
import { AI_FREE_SITE_WORST_CASE_CREDITS, AI_SITE_CREATE_KINDS, AI_SITE_FREE_PAGES, AI_SITE_PLAN_MAX_TOKENS, AI_SITE_HOME_BANDS, aiFreeSiteSectionsWithin, aiSiteFullPlanSentence, aiSiteHomeMinSections, aiSiteNameSentence, aiSitePlanIsHome, aiSitePlanShapeRefusal, aiSiteBlogStandInViolations, aiSiteThinHomeViolations, AI_SITE_GALLERY_SENTENCE, aiSiteEmptyGalleryViolations } from "../model/ai-site-job.js";
|
|
25
26
|
import { aiSiteContentPart } from "./ai-job-site-content.js";
|
|
27
|
+
import { aiLayoutIsShopPage, aiLayoutShopGridSection } from "../layout-language/ai-layout-listings.js";
|
|
28
|
+
import { aiStorefrontPlanScreens } from "../layout-language/ai-layout-storefront.js";
|
|
26
29
|
import { AI_GENERATION_MAX_ATTEMPTS } from "../runtime/ai-generation-bounds.js";
|
|
27
30
|
import { aiPlanFailureCopy, aiPlanRetryRefusal } from "../model/ai-job-failure-copy.js";
|
|
28
31
|
import { FREE_AI_TASTE_CREDITS_PER_MONTH } from "../plan-entitlements.js";
|
|
@@ -39,6 +42,7 @@ import { aiInstructionsWithSiteContext } from "../model/ai-site-context.js";
|
|
|
39
42
|
import { AI_BUILD_CREATE_KINDS, AI_BUILD_STRUCTURAL_OPS, aiBuildPageLimit, aiBuildPlanShapeRefusal } from "../model/ai-build-job.js";
|
|
40
43
|
import { aiBuildOpLines, aiBuildOps } from "./ai-build-capabilities.js";
|
|
41
44
|
import { aiJobAdmissionRefusal } from "./ai-job-admission.js";
|
|
45
|
+
import { AI_CREDITS_CONFIRM_CODE } from "../model/ai-credit-estimate.js";
|
|
42
46
|
import { readAiPlanCapabilities } from "./ai-job-drafts.js";
|
|
43
47
|
import { AI_JOB_BRIEF_MAX_CHARS } from "./ai-job-text-step.js";
|
|
44
48
|
import { aiJobStepBudget } from "./ai-job-budget.js";
|
|
@@ -187,7 +191,10 @@ import { AI_JOBS_COLLECTION, registerAiJobPlanStep } from "./ai-jobs.js";
|
|
|
187
191
|
// left to a ceiling the outline is free to stay far under.
|
|
188
192
|
const plansHome = !pages.some((page)=>!page.replaceable && aiSitePlanIsHome(page));
|
|
189
193
|
if (home.min > 0 && plansHome) {
|
|
190
|
-
|
|
194
|
+
var _aiSiteKindOfInputs;
|
|
195
|
+
// A store's home is a storefront (AGL-3676): its own parts, in its own order.
|
|
196
|
+
const bands = ((_aiSiteKindOfInputs = aiSiteKindOfInputs(job.inputs)) == null ? void 0 : _aiSiteKindOfInputs.id) === 'store' ? AI_SITE_STORE_HOME_BANDS : AI_SITE_HOME_BANDS;
|
|
197
|
+
lines.push(`The home page at / reads as a full website: at least ${home.min} sections — ${bands}.`);
|
|
191
198
|
}
|
|
192
199
|
// The sections are a budget to use (AGL-3660): a prod start of 2026-10-08
|
|
193
200
|
// read "at most 8" as leave to plan a home of two.
|
|
@@ -204,12 +211,24 @@ import { AI_JOBS_COLLECTION, registerAiJobPlanStep } from "./ai-jobs.js";
|
|
|
204
211
|
// A section that shows the work counts its pieces (AGL-3660): a planned
|
|
205
212
|
// gallery of no items let a page about the work show none.
|
|
206
213
|
lines.push(AI_SITE_GALLERY_SENTENCE);
|
|
214
|
+
// A section that asks for something places the form (AGL-3660): a live
|
|
215
|
+
// portfolio start planned a commissions inquiry beside the form it made
|
|
216
|
+
// for its Contact page, without placing it.
|
|
217
|
+
if (aiPlanCanPlaceForm(inventory, capabilities)) lines.push(AI_SITE_FORM_SENTENCE);
|
|
207
218
|
// The kind of site the person picked (AGL-3660): the pages it usually has.
|
|
208
219
|
const kind = aiSiteKindOfInputs(job.inputs);
|
|
209
220
|
if (kind) lines.push(`This is a ${kind.label.toLowerCase()} site. ${kind.pages}`);
|
|
221
|
+
// A store's Shop page IS its storefront (AGL-3676): the platform lists the
|
|
222
|
+
// real products there, so the plan names the section and draws no range.
|
|
223
|
+
if ((kind == null ? void 0 : kind.id) === 'store') lines.push(AI_SITE_STORE_SHOP_SENTENCE);
|
|
210
224
|
lines.push("Keep the plan an outline: each page's title, address, a short search title and description, and its sections named in a few words. The build writes the copy.");
|
|
211
225
|
return lines;
|
|
212
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* The sentence a site plan's turn states about a section that collects
|
|
229
|
+
* answers (AGL-3660): it places the saved form by reference, and one form
|
|
230
|
+
* may be placed on more than one page.
|
|
231
|
+
*/ export const AI_SITE_FORM_SENTENCE = "A section that asks visitors for something (contact, inquiry, commissions, booking, sign-up) places the form: put new:<the form's name> or the site's form id in its uses. One form may be placed on several pages.";
|
|
213
232
|
/**
|
|
214
233
|
* What a site start's home page is held to (AGL-3660): its fewest sections,
|
|
215
234
|
* and on the Free taste the sections the wall fits across the pages, which
|
|
@@ -252,6 +271,51 @@ import { AI_JOBS_COLLECTION, registerAiJobPlanStep } from "./ai-jobs.js";
|
|
|
252
271
|
return aiSiteThinHomeViolations(plan, rule);
|
|
253
272
|
};
|
|
254
273
|
}
|
|
274
|
+
/** What a store's plan is told about its Shop page (AGL-3676). */ export const AI_SITE_STORE_SHOP_SENTENCE = 'Plan a Shop page at /shop: a short title section, then a section named "Product grid" second, where the platform lists the store\'s real products with sort, filters, photos, prices and cart, then at most one or two short sections (care, shipping, gifting help). Never open it with a hero, and never plan the products themselves as cards of your own.';
|
|
275
|
+
/** What a store's home is composed of (AGL-3676): a storefront's parts, in a storefront's order. */ export const AI_SITE_STORE_HOME_BANDS = 'a hero that sells first, then "Bestsellers" (the platform lists the real products), "Shop by collection" with 3 or 4 items, the brand story, why buy here with 3 or 4 items, "Customer reviews" (the platform shows the store\'s real ones) and a "Newsletter sign-up" band last';
|
|
276
|
+
/**
|
|
277
|
+
* A store plan held to a storefront (AGL-3676, `ai-layout-storefront.ts`):
|
|
278
|
+
* on a paid start its home gains the parts a shopper expects that the plan
|
|
279
|
+
* left out — bestsellers, collections, reviews, a newsletter sign-up —
|
|
280
|
+
* while the page has room; on any start its Shop page opens on its grid.
|
|
281
|
+
* Settled, never re-asked: each part has one answer, and the Free wall's
|
|
282
|
+
* home keeps the sections it planned.
|
|
283
|
+
*/ export function aiSiteStorefrontPlan(plan, options) {
|
|
284
|
+
const screens = aiStorefrontPlanScreens(plan.screens, {
|
|
285
|
+
paid: options.paid,
|
|
286
|
+
isShopPage: aiLayoutIsShopPage,
|
|
287
|
+
gridSection: aiLayoutShopGridSection
|
|
288
|
+
});
|
|
289
|
+
return screens.every((screen, index)=>screen === plan.screens[index]) ? plan : _extends({}, plan, {
|
|
290
|
+
screens
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/** The code a store plan with no Shop page is re-asked under. */ export const AI_SITE_STORE_SHOP_CODE = 'plan-store-shop-page';
|
|
294
|
+
/**
|
|
295
|
+
* A store plan of two or more pages with no Shop page (AGL-3676): the page
|
|
296
|
+
* the platform lists the catalog on is the one a shopper looks for. A
|
|
297
|
+
* one-page Free taste lists its products on the home instead.
|
|
298
|
+
*/ export function aiSiteStoreShopPageViolations(plan) {
|
|
299
|
+
if (plan.screens.length < 2 || plan.screens.some((screen)=>aiLayoutIsShopPage(screen))) return [];
|
|
300
|
+
return [
|
|
301
|
+
{
|
|
302
|
+
rule: null,
|
|
303
|
+
code: AI_SITE_STORE_SHOP_CODE,
|
|
304
|
+
message: 'This store has no Shop page. Plan one at /shop, its second section named "Product grid": the platform lists the real products there.',
|
|
305
|
+
paths: [
|
|
306
|
+
'screens'
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
];
|
|
310
|
+
}
|
|
311
|
+
/** A store plan's missing Shop page, asked about on the FIRST answer only, like a thin home. */ export function aiSiteStoreShopCheck() {
|
|
312
|
+
let answers = 0;
|
|
313
|
+
return (plan)=>{
|
|
314
|
+
answers += 1;
|
|
315
|
+
if (answers >= AI_GENERATION_MAX_ATTEMPTS) return [];
|
|
316
|
+
return aiSiteStoreShopPageViolations(plan);
|
|
317
|
+
};
|
|
318
|
+
}
|
|
255
319
|
/**
|
|
256
320
|
* A site plan's section that shows the work without its pieces (AGL-3660),
|
|
257
321
|
* asked about on the FIRST answer only, like a thin home: the re-ask names
|
|
@@ -343,8 +407,9 @@ import { AI_JOBS_COLLECTION, registerAiJobPlanStep } from "./ai-jobs.js";
|
|
|
343
407
|
* violations the plan's one re-ask names: the players the plan lists against
|
|
344
408
|
* the brief it answers (AGL-3433), which only this step reads beside the plan,
|
|
345
409
|
* and a kind's shape refusal.
|
|
346
|
-
*/ function planViolations(scope, brief, freeTaste = false, ops = null, home = null, blog = false, site = false) {
|
|
410
|
+
*/ function planViolations(scope, brief, freeTaste = false, ops = null, home = null, blog = false, site = false, store = false) {
|
|
347
411
|
const thinHome = home && home.min > 0 ? aiSiteThinHomeCheck(home) : null;
|
|
412
|
+
const storeShop = store ? aiSiteStoreShopCheck() : null;
|
|
348
413
|
const blogStandIn = blog ? aiSiteBlogStandInCheck() : null;
|
|
349
414
|
const emptyGallery = site ? aiSiteEmptyGalleryCheck() : null;
|
|
350
415
|
return (plan)=>{
|
|
@@ -369,7 +434,8 @@ import { AI_JOBS_COLLECTION, registerAiJobPlanStep } from "./ai-jobs.js";
|
|
|
369
434
|
] : [],
|
|
370
435
|
...thinHome ? thinHome(plan) : [],
|
|
371
436
|
...blogStandIn ? blogStandIn(plan) : [],
|
|
372
|
-
...emptyGallery ? emptyGallery(plan) : []
|
|
437
|
+
...emptyGallery ? emptyGallery(plan) : [],
|
|
438
|
+
...storeShop ? storeShop(plan) : []
|
|
373
439
|
];
|
|
374
440
|
};
|
|
375
441
|
}
|
|
@@ -559,8 +625,10 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
559
625
|
const admissionRefusal = (_deps_admissionRefusal = deps.admissionRefusal) != null ? _deps_admissionRefusal : aiJobAdmissionRefusal;
|
|
560
626
|
const readOps = (_deps_readOps = deps.readOps) != null ? _deps_readOps : readAiBuildOps;
|
|
561
627
|
const readContext = deps.readSiteContext === undefined ? readAiJobSiteContext : deps.readSiteContext;
|
|
628
|
+
const readFreeCredits = deps.readFreeCredits === undefined ? readFreeAiCreditsLeft : deps.readFreeCredits;
|
|
562
629
|
return async ({ job, now, signal, firestore, modelFor, org: orgDocument })=>{
|
|
563
630
|
var _AI_JOB_PLAN_SCOPES_job_kind, _job_inputs, _ref;
|
|
631
|
+
var _aiSiteKindOfInputs, _aiSiteKindOfInputs1;
|
|
564
632
|
const org = orgDocument != null ? orgDocument : null;
|
|
565
633
|
const [inventory, workspace, siteContext] = await Promise.all([
|
|
566
634
|
job.hostId ? readInventory(job.orgId, job.hostId, {
|
|
@@ -591,6 +659,29 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
591
659
|
freeTaste
|
|
592
660
|
}) : null;
|
|
593
661
|
const site = job.kind === 'site';
|
|
662
|
+
// A kept plan waits for its confirmation; a Free build's card is told what
|
|
663
|
+
// is left, so it says before Confirm whether the build fits (AGL-3722).
|
|
664
|
+
// Net of what THIS plan just spent: the machine meters the step after it
|
|
665
|
+
// returns, so the meters read here do not hold it yet, and a card told
|
|
666
|
+
// the figure from before the plan (101) offered Confirm to a person with
|
|
667
|
+
// 48 left, who met the prompt only after pressing it (2026-10-10).
|
|
668
|
+
const planReview = async (spentUsd = 0)=>{
|
|
669
|
+
const review = {
|
|
670
|
+
reason: 'plan',
|
|
671
|
+
message: AI_JOB_PLAN_REVIEW_COPY,
|
|
672
|
+
findings: []
|
|
673
|
+
};
|
|
674
|
+
if (job.kind !== 'build' || !freeTaste || !readFreeCredits) return review;
|
|
675
|
+
const credits = await readFreeCredits(firestore, {
|
|
676
|
+
orgId: job.orgId,
|
|
677
|
+
org,
|
|
678
|
+
now,
|
|
679
|
+
pendingUsd: spentUsd
|
|
680
|
+
});
|
|
681
|
+
return credits ? _extends({}, review, {
|
|
682
|
+
freeCredits: credits
|
|
683
|
+
}) : review;
|
|
684
|
+
};
|
|
594
685
|
// The model switch's answer for this job (AGL-2942): the creator's pick
|
|
595
686
|
// where the plan, the org restriction and the allotment allowlists allow
|
|
596
687
|
// it, and Auto held to those same lists otherwise. Without a resolver the
|
|
@@ -605,6 +696,16 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
605
696
|
* door hands it. A refusal fails the job with the door's sentence; a door
|
|
606
697
|
* that could not answer keeps the plan, since the resume door asks again
|
|
607
698
|
* before anything is built.
|
|
699
|
+
*
|
|
700
|
+
* Two answers are about the month's Free credits, not the plan (AGL-3722):
|
|
701
|
+
* - the 409 credits prompt KEEPS the plan. The card is told what is left
|
|
702
|
+
* (`planReview`) and offers Build what fits / the home page first /
|
|
703
|
+
* Upgrade, and the confirm door asks with the person's choice. Failing
|
|
704
|
+
* here instead failed every Free build past its p90 before the card
|
|
705
|
+
* could offer them — and paged staff with `ai.jobFailed`, as at
|
|
706
|
+
* 2026-10-09 16:38Z (600 credits estimated, 164 left).
|
|
707
|
+
* - the 429 "nothing left" still fails the job with its sentence, but as
|
|
708
|
+
* the customer's limit, which raises no staff alert.
|
|
608
709
|
*/ const refusalOnKeep = async (plan, outcome)=>{
|
|
609
710
|
let refusal = null;
|
|
610
711
|
try {
|
|
@@ -625,9 +726,12 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
625
726
|
error
|
|
626
727
|
});
|
|
627
728
|
}
|
|
628
|
-
|
|
729
|
+
if (!refusal || refusal.code === AI_CREDITS_CONFIRM_CODE) return null;
|
|
730
|
+
return _extends({}, outcome, {
|
|
629
731
|
failure: refusal.error
|
|
630
|
-
}
|
|
732
|
+
}, refusal.status === 429 ? {
|
|
733
|
+
customerLimit: true
|
|
734
|
+
} : {});
|
|
631
735
|
};
|
|
632
736
|
// Reuse before asking (AGL-2937). The key covers the whole request, so a
|
|
633
737
|
// hit is a request that would have been sent the same bytes to the same
|
|
@@ -672,11 +776,7 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
672
776
|
const unspent = aiUnspentOutcome(resolved);
|
|
673
777
|
return (_ref1 = await refusalOnKeep(plan, unspent)) != null ? _ref1 : _extends({}, unspent, {
|
|
674
778
|
plan,
|
|
675
|
-
review:
|
|
676
|
-
reason: 'plan',
|
|
677
|
-
message: AI_JOB_PLAN_REVIEW_COPY,
|
|
678
|
-
findings: []
|
|
679
|
-
}
|
|
779
|
+
review: await planReview()
|
|
680
780
|
});
|
|
681
781
|
}
|
|
682
782
|
const result = await runValidatedGeneration('plan', _extends({
|
|
@@ -707,7 +807,7 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
707
807
|
signal
|
|
708
808
|
} : {}, {
|
|
709
809
|
capabilities,
|
|
710
|
-
extend: planViolations(scope, job.brief, freeTaste, ops, site ? aiSitePlanHomeRule(inventory, capabilities) : null, site && aiSiteContentPart((_job_inputs = job.inputs) != null ? _job_inputs : null, freeTaste) === 'posts', site)
|
|
810
|
+
extend: planViolations(scope, job.brief, freeTaste, ops, site ? aiSitePlanHomeRule(inventory, capabilities) : null, site && aiSiteContentPart((_job_inputs = job.inputs) != null ? _job_inputs : null, freeTaste) === 'posts', site, site && ((_aiSiteKindOfInputs = aiSiteKindOfInputs(job.inputs)) == null ? void 0 : _aiSiteKindOfInputs.id) === 'store')
|
|
711
811
|
}));
|
|
712
812
|
const spent = _extends({
|
|
713
813
|
outputs: [],
|
|
@@ -750,10 +850,14 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
750
850
|
} : {})
|
|
751
851
|
});
|
|
752
852
|
}
|
|
853
|
+
// A store's plan is a storefront's (AGL-3676): settled before it is kept and priced.
|
|
854
|
+
const answered = site && ((_aiSiteKindOfInputs1 = aiSiteKindOfInputs(job.inputs)) == null ? void 0 : _aiSiteKindOfInputs1.id) === 'store' ? aiSiteStorefrontPlan(result.value, {
|
|
855
|
+
paid: !freeTaste
|
|
856
|
+
}) : result.value;
|
|
753
857
|
// Each draft the plan decides is named as the plan is kept, before anything is built (AGL-3079).
|
|
754
|
-
const plan = aiPlanWithItemCredits(ops, aiPlanWithDraftIds(job.kind, _extends({},
|
|
858
|
+
const plan = aiPlanWithItemCredits(ops, aiPlanWithDraftIds(job.kind, _extends({}, answered, {
|
|
755
859
|
status: 'proposed',
|
|
756
|
-
labels: aiPlanLabels(
|
|
860
|
+
labels: aiPlanLabels(answered, inventory),
|
|
757
861
|
// A Date the Admin SDK stores as a timestamp, like every instant the machine writes.
|
|
758
862
|
proposedAt: now,
|
|
759
863
|
confirmedAt: null,
|
|
@@ -762,11 +866,7 @@ export function createAiJobPlanStep(deps = {}) {
|
|
|
762
866
|
})));
|
|
763
867
|
return (_ref = await refusalOnKeep(plan, spent)) != null ? _ref : _extends({}, spent, {
|
|
764
868
|
plan,
|
|
765
|
-
review:
|
|
766
|
-
reason: 'plan',
|
|
767
|
-
message: AI_JOB_PLAN_REVIEW_COPY,
|
|
768
|
-
findings: []
|
|
769
|
-
}
|
|
869
|
+
review: await planReview(result.estCostUsd)
|
|
770
870
|
});
|
|
771
871
|
};
|
|
772
872
|
}
|