@aglyn/plugins-ai 1.0.0-beta.266 → 1.0.0-beta.268
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 +18 -18
- package/src/lib/components/ai-job-site.d.ts +8 -1
- package/src/lib/components/ai-job-site.js +7 -0
- package/src/lib/components/ai-job-site.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +37 -0
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +25 -6
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +8 -2
- package/src/lib/components/ai-site-start-steps.component.js +55 -26
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-start-tracking.d.ts +11 -3
- package/src/lib/components/ai-site-start-tracking.js +28 -9
- package/src/lib/components/ai-site-start-tracking.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +24 -2
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/jobs/ai-empty-site-sweep.d.ts +154 -0
- package/src/lib/jobs/ai-empty-site-sweep.js +346 -0
- package/src/lib/jobs/ai-empty-site-sweep.js.map +1 -0
- package/src/lib/jobs/ai-jobs-beat.d.ts +11 -3
- package/src/lib/jobs/ai-jobs-beat.js +23 -6
- package/src/lib/jobs/ai-jobs-beat.js.map +1 -1
- package/src/lib/jobs/ai-jobs.js +46 -7
- package/src/lib/jobs/ai-jobs.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 +321 -19
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3923-recordings.d.ts +35 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3923-recordings.js +379 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3923-recordings.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-brightvale-recordings.d.ts +31 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-brightvale-recordings.js +208 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-brightvale-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-design.js +5 -0
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +20 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-start-handoff.d.ts +49 -0
- package/src/lib/model/ai-site-start-handoff.js +88 -0
- package/src/lib/model/ai-site-start-handoff.js.map +1 -0
package/src/lib/jobs/ai-jobs.js
CHANGED
|
@@ -47,6 +47,7 @@ import { AI_SITE_GUIDED_BUILD_FAILED_COPY, aiCustomerSafeCopy, aiCustomerSafeIte
|
|
|
47
47
|
import { aiSiteStartInputsOf } from "../model/ai-site-start.js";
|
|
48
48
|
import { addAdminAudit } from "@aglyn/tenant-data-admin/server/admin-audit-write";
|
|
49
49
|
import { AI_JOB_CANCELED_ITEM_NOTE, aiJobCancelPending, isAiJobCanceledError, watchAiJobCancel } from "./ai-job-cancel.js";
|
|
50
|
+
import { clearAiEmptySiteSweep, scheduleAiEmptySiteSweep } from "./ai-empty-site-sweep.js";
|
|
50
51
|
/**
|
|
51
52
|
* AI generation jobs — the Firestore state machine (AGL-2904).
|
|
52
53
|
*
|
|
@@ -256,6 +257,16 @@ let transitionListener = null;
|
|
|
256
257
|
/** Whether a transition listener is registered: what a surface that runs jobs must have. */ export function aiJobTransitionListenerRegistered() {
|
|
257
258
|
return transitionListener !== null;
|
|
258
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* A job just ENDED `canceled` or `failed`, in the write the caller made
|
|
262
|
+
* (AGL-3936): a site start that built nothing schedules the removal of the
|
|
263
|
+
* empty site it was for, an hour out (`ai-empty-site-sweep.ts`). Every write
|
|
264
|
+
* that ends a job calls this once, after its transaction commits. Never
|
|
265
|
+
* throws.
|
|
266
|
+
*/ async function noteAiJobEnded(firestore, job, now) {
|
|
267
|
+
if (!job || job.status !== 'canceled' && job.status !== 'failed') return;
|
|
268
|
+
await scheduleAiEmptySiteSweep(firestore, job, now);
|
|
269
|
+
}
|
|
259
270
|
/** Tells the listener; a listener that throws never fails the write it follows. */ async function announceAiJobTransition(job, to, failure) {
|
|
260
271
|
if (!transitionListener) return;
|
|
261
272
|
try {
|
|
@@ -408,6 +419,8 @@ function jobFrom(snapshot) {
|
|
|
408
419
|
creditsConfirmed: input.creditsConfirmed
|
|
409
420
|
} : {});
|
|
410
421
|
await ref.set(data);
|
|
422
|
+
// A new job on the site — a guided start begun again — keeps it (AGL-3936).
|
|
423
|
+
await clearAiEmptySiteSweep(firestore, input.hostId);
|
|
411
424
|
await logAiJobCreated(input.orgId, {
|
|
412
425
|
uid: input.createdBy,
|
|
413
426
|
email: (_input_createdByEmail = input.createdByEmail) != null ? _input_createdByEmail : null
|
|
@@ -527,6 +540,8 @@ export async function getAiJob(firestore, orgId, jobId) {
|
|
|
527
540
|
publishAsked: true
|
|
528
541
|
} : {}, aiJobCancelPending(job) ? {
|
|
529
542
|
cancelRequested: true
|
|
543
|
+
} : {}, job.siteRemoved ? {
|
|
544
|
+
siteRemoved: true
|
|
530
545
|
} : {});
|
|
531
546
|
}
|
|
532
547
|
function leaseIsLive(job, owner, nowMs) {
|
|
@@ -607,16 +622,20 @@ function nextStepIndex(job) {
|
|
|
607
622
|
* stale lease is released by being taken, not by a sweep of its own.
|
|
608
623
|
*/ export async function claimNextStep(firestore, orgId, jobId, owner, now = new Date()) {
|
|
609
624
|
const ref = jobsCollection(firestore, orgId).doc(jobId);
|
|
610
|
-
|
|
625
|
+
let ended = null;
|
|
626
|
+
const claimed = await firestore.runTransaction(async (tx)=>{
|
|
627
|
+
ended = null;
|
|
611
628
|
const job = jobFrom(await tx.get(ref));
|
|
612
629
|
if (!job) return null;
|
|
613
630
|
// A cancel asked while a step ran, whose runner never came back to end
|
|
614
631
|
// it (AGL-3616): the lease ran out, so the job ends here, unclaimed.
|
|
615
632
|
if (aiJobCancelPending(job)) {
|
|
616
633
|
if (!leaseIsLive(job, owner, now.getTime())) {
|
|
617
|
-
|
|
634
|
+
const patch = aiJobCanceledPatch(job, now, cancelRequestOf(job, now));
|
|
635
|
+
tx.set(ref, patch, {
|
|
618
636
|
merge: true
|
|
619
637
|
});
|
|
638
|
+
ended = _extends({}, job, patch);
|
|
620
639
|
}
|
|
621
640
|
return null;
|
|
622
641
|
}
|
|
@@ -652,6 +671,8 @@ function nextStepIndex(job) {
|
|
|
652
671
|
stepIndex
|
|
653
672
|
};
|
|
654
673
|
});
|
|
674
|
+
await noteAiJobEnded(firestore, ended, now);
|
|
675
|
+
return claimed;
|
|
655
676
|
}
|
|
656
677
|
/**
|
|
657
678
|
* Extend the lease while a long step is still running. `false` when the
|
|
@@ -689,15 +710,19 @@ function nextStepIndex(job) {
|
|
|
689
710
|
* parked, no step left, or another owner's live lease.
|
|
690
711
|
*/ export async function holdPausedAiJob(firestore, orgId, jobId, owner, now = new Date()) {
|
|
691
712
|
const ref = jobsCollection(firestore, orgId).doc(jobId);
|
|
692
|
-
|
|
713
|
+
let ended = null;
|
|
714
|
+
const held = await firestore.runTransaction(async (tx)=>{
|
|
715
|
+
ended = null;
|
|
693
716
|
const job = jobFrom(await tx.get(ref));
|
|
694
717
|
if (!job) return null;
|
|
695
718
|
// A paused workspace's job a person canceled ends canceled (AGL-3616).
|
|
696
719
|
if (aiJobCancelPending(job)) {
|
|
697
720
|
if (!leaseIsLive(job, owner, now.getTime())) {
|
|
698
|
-
|
|
721
|
+
const patch = aiJobCanceledPatch(job, now, cancelRequestOf(job, now));
|
|
722
|
+
tx.set(ref, patch, {
|
|
699
723
|
merge: true
|
|
700
724
|
});
|
|
725
|
+
ended = _extends({}, job, patch);
|
|
701
726
|
}
|
|
702
727
|
return null;
|
|
703
728
|
}
|
|
@@ -711,6 +736,8 @@ function nextStepIndex(job) {
|
|
|
711
736
|
updatedAt: now
|
|
712
737
|
});
|
|
713
738
|
});
|
|
739
|
+
await noteAiJobEnded(firestore, ended, now);
|
|
740
|
+
return held;
|
|
714
741
|
}
|
|
715
742
|
/**
|
|
716
743
|
* A build's ledger with one pass applied (AGL-3616): the pass's credits on
|
|
@@ -874,9 +901,12 @@ function nextStepIndex(job) {
|
|
|
874
901
|
job: _extends({}, job, patch),
|
|
875
902
|
remaining,
|
|
876
903
|
// Entered `needs_review` in this write, rather than parked again.
|
|
877
|
-
parked: parksForReview && job.status !== 'needs_review'
|
|
904
|
+
parked: parksForReview && job.status !== 'needs_review',
|
|
905
|
+
// Ended `canceled` in this write (AGL-3936).
|
|
906
|
+
ended: canceling && !isAiJobTerminal(job.status)
|
|
878
907
|
};
|
|
879
908
|
});
|
|
909
|
+
if (recorded.ended) await noteAiJobEnded(firestore, recorded.job, now);
|
|
880
910
|
if (recorded.parked && !input.quiet) await announceAiJobTransition(recorded.job, 'needs-review');
|
|
881
911
|
return {
|
|
882
912
|
job: recorded.job,
|
|
@@ -912,6 +942,7 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
912
942
|
updatedAt: now
|
|
913
943
|
});
|
|
914
944
|
if (changed && job.status === 'done') await announceAiJobTransition(job, 'done');
|
|
945
|
+
if (changed) await noteAiJobEnded(firestore, job, now);
|
|
915
946
|
return job;
|
|
916
947
|
}
|
|
917
948
|
/**
|
|
@@ -946,6 +977,7 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
946
977
|
error: (detail == null ? void 0 : detail.error) instanceof Error ? detail.error.message : (detail == null ? void 0 : detail.error) == null ? null : String(detail.error)
|
|
947
978
|
});
|
|
948
979
|
}
|
|
980
|
+
if (changed) await noteAiJobEnded(firestore, job, now);
|
|
949
981
|
return job;
|
|
950
982
|
}
|
|
951
983
|
/**
|
|
@@ -953,7 +985,7 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
953
985
|
* step goes back to `pending` so the same step is what runs when the beat
|
|
954
986
|
* tries again; its attempt is not counted, because nothing was attempted.
|
|
955
987
|
*/ export async function markAiJobNeedsInput(firestore, orgId, jobId, reason, now = new Date()) {
|
|
956
|
-
const { job } = await transition(firestore, orgId, jobId, (current)=>isAiJobTerminal(current.status) ? null : aiJobCancelPending(current) ? aiJobCanceledPatch(current, now, cancelRequestOf(current, now)) : {
|
|
988
|
+
const { job, changed } = await transition(firestore, orgId, jobId, (current)=>isAiJobTerminal(current.status) ? null : aiJobCancelPending(current) ? aiJobCanceledPatch(current, now, cancelRequestOf(current, now)) : {
|
|
957
989
|
status: 'needs_input',
|
|
958
990
|
error: reason,
|
|
959
991
|
lease: null,
|
|
@@ -966,6 +998,7 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
966
998
|
}),
|
|
967
999
|
updatedAt: now
|
|
968
1000
|
});
|
|
1001
|
+
if (changed) await noteAiJobEnded(firestore, job, now);
|
|
969
1002
|
return job;
|
|
970
1003
|
}
|
|
971
1004
|
/**
|
|
@@ -1016,6 +1049,7 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
1016
1049
|
kind: result.job.kind
|
|
1017
1050
|
});
|
|
1018
1051
|
}
|
|
1052
|
+
if (result.changed) await noteAiJobEnded(firestore, result.job, now);
|
|
1019
1053
|
return result;
|
|
1020
1054
|
}
|
|
1021
1055
|
/**
|
|
@@ -1372,6 +1406,8 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
1372
1406
|
updatedAt: now
|
|
1373
1407
|
});
|
|
1374
1408
|
});
|
|
1409
|
+
// A site start tried again keeps its site (AGL-3936).
|
|
1410
|
+
if (result.changed) await clearAiEmptySiteSweep(firestore, result.job.hostId);
|
|
1375
1411
|
return _extends({}, result, {
|
|
1376
1412
|
retried: result.changed ? retried : []
|
|
1377
1413
|
});
|
|
@@ -1388,7 +1424,7 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
1388
1424
|
* and a confirmed plan is held at what the whole job is estimated to cost
|
|
1389
1425
|
* (AGL-3031), creations included, where that is more.
|
|
1390
1426
|
*/ export async function resumeAiJob(firestore, orgId, jobId, actor, now = new Date(), options = {}) {
|
|
1391
|
-
|
|
1427
|
+
const resumed = await transition(firestore, orgId, jobId, (current)=>{
|
|
1392
1428
|
var _options_reducePlan;
|
|
1393
1429
|
var _current_review, _current_inputs;
|
|
1394
1430
|
// A job the meter paused (AGL-3660) carries on from the step it paused
|
|
@@ -1435,6 +1471,9 @@ async function transition(firestore, orgId, jobId, apply) {
|
|
|
1435
1471
|
updatedAt: now
|
|
1436
1472
|
});
|
|
1437
1473
|
});
|
|
1474
|
+
// A site start resumed keeps its site (AGL-3936).
|
|
1475
|
+
if (resumed.changed) await clearAiEmptySiteSweep(firestore, resumed.job.hostId);
|
|
1476
|
+
return resumed;
|
|
1438
1477
|
}
|
|
1439
1478
|
/**
|
|
1440
1479
|
* Record what a person applied from a finished job's outputs (AGL-2910): the
|