@pixerate/editor 0.24.0 → 0.25.0
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/README.md +71 -1
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/dist/agent/index.cjs +10 -9
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +4 -3
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +3173 -340
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +617 -4
- package/dist/canvas/index.d.ts +617 -4
- package/dist/canvas/index.js +3105 -272
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4BVP64JJ.cjs +1406 -0
- package/dist/chunk-4BVP64JJ.cjs.map +1 -0
- package/dist/{chunk-XNORY7M6.cjs → chunk-7WISYZFO.cjs} +105 -50
- package/dist/chunk-7WISYZFO.cjs.map +1 -0
- package/dist/{chunk-OLZJXL4R.cjs → chunk-AL6JMGWW.cjs} +59 -25
- package/dist/chunk-AL6JMGWW.cjs.map +1 -0
- package/dist/chunk-BVP3TSLH.cjs +69 -0
- package/dist/chunk-BVP3TSLH.cjs.map +1 -0
- package/dist/{chunk-MCSJFWAO.cjs → chunk-C7P22VIP.cjs} +670 -96
- package/dist/chunk-C7P22VIP.cjs.map +1 -0
- package/dist/{chunk-PGNZKFQS.js → chunk-ECCCYKGL.js} +76 -21
- package/dist/chunk-ECCCYKGL.js.map +1 -0
- package/dist/{chunk-3CN2WD3X.js → chunk-FH6F67DN.js} +646 -72
- package/dist/chunk-FH6F67DN.js.map +1 -0
- package/dist/chunk-HRMEDT2L.js +1406 -0
- package/dist/chunk-HRMEDT2L.js.map +1 -0
- package/dist/{chunk-ITBSKI26.js → chunk-IXHSYOVY.js} +941 -9
- package/dist/chunk-IXHSYOVY.js.map +1 -0
- package/dist/{chunk-FODNLX5N.js → chunk-NAXVVS5I.js} +38 -4
- package/dist/chunk-NAXVVS5I.js.map +1 -0
- package/dist/chunk-O5RYH2PG.js +69 -0
- package/dist/chunk-O5RYH2PG.js.map +1 -0
- package/dist/{chunk-SBCZ6RN5.cjs → chunk-PO6A6QQH.cjs} +1039 -107
- package/dist/chunk-PO6A6QQH.cjs.map +1 -0
- package/dist/{chunk-3LV6RRPH.js → chunk-QGYDWPRM.js} +2 -2
- package/dist/{chunk-U5KWZU4X.js → chunk-RR7F5GUM.js} +2632 -129
- package/dist/chunk-RR7F5GUM.js.map +1 -0
- package/dist/{chunk-5S3Z4PPF.js → chunk-UAKDG62Z.js} +232 -25
- package/dist/chunk-UAKDG62Z.js.map +1 -0
- package/dist/{chunk-SML64VJG.cjs → chunk-V3CHHWOE.cjs} +4 -4
- package/dist/{chunk-SML64VJG.cjs.map → chunk-V3CHHWOE.cjs.map} +1 -1
- package/dist/chunk-WSQKHXW7.cjs +5726 -0
- package/dist/chunk-WSQKHXW7.cjs.map +1 -0
- package/dist/{chunk-D27YFC46.cjs → chunk-X4N4WUKB.cjs} +267 -60
- package/dist/chunk-X4N4WUKB.cjs.map +1 -0
- package/dist/commands/index.cjs +74 -1
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +34 -1
- package/dist/commands/index.d.ts +34 -1
- package/dist/commands/index.js +73 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/compare/index.cjs +3 -3
- package/dist/compare/index.d.cts +1 -1
- package/dist/compare/index.d.ts +1 -1
- package/dist/compare/index.js +2 -2
- package/dist/controller-BIJiNoVs.d.cts +1842 -0
- package/dist/controller-BIJiNoVs.d.ts +1842 -0
- package/dist/{documents-BQjzJNe2.d.ts → documents-CHT1U5Vs.d.ts} +10 -0
- package/dist/{documents-KRTPhvst.d.cts → documents-Gp7wb0Me.d.cts} +10 -0
- package/dist/extensions/index.cjs +53 -6
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +12 -4
- package/dist/extensions/index.d.ts +12 -4
- package/dist/extensions/index.js +53 -6
- package/dist/generation/index.cjs +1013 -69
- package/dist/generation/index.cjs.map +1 -1
- package/dist/generation/index.d.cts +474 -13
- package/dist/generation/index.d.ts +474 -13
- package/dist/generation/index.js +976 -32
- package/dist/generation/index.js.map +1 -1
- package/dist/image-editor/index.cjs +3385 -1275
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +693 -128
- package/dist/image-editor/index.d.ts +693 -128
- package/dist/image-editor/index.js +3325 -1215
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-fJrlkJCd.d.ts → index-7a6bHTLy.d.ts} +494 -5
- package/dist/{index-BhJBSm2d.d.cts → index-Csd5qI8u.d.cts} +494 -5
- package/dist/index.cjs +1491 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -19
- package/dist/index.d.ts +110 -19
- package/dist/index.js +1464 -18
- package/dist/index.js.map +1 -1
- package/dist/mention-text-CDnCFd3c.d.cts +53 -0
- package/dist/mention-text-CDnCFd3c.d.ts +53 -0
- package/dist/model-C1zApQM8.d.cts +219 -0
- package/dist/model-C1zApQM8.d.ts +219 -0
- package/dist/persistence/index.d.cts +3 -120
- package/dist/persistence/index.d.ts +3 -120
- package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.cts} +12 -1
- package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.ts} +12 -1
- package/dist/serializers/index.cjs +12 -4
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +39 -12
- package/dist/serializers/index.d.ts +39 -12
- package/dist/serializers/index.js +12 -4
- package/dist/spreadsheet/index.cjs +127 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +431 -11
- package/dist/spreadsheet/index.d.ts +431 -11
- package/dist/spreadsheet/index.js +127 -3
- package/dist/storage-BpFfspHm.d.cts +120 -0
- package/dist/storage-BpFfspHm.d.ts +120 -0
- package/dist/tokens/index.cjs +115 -0
- package/dist/tokens/index.cjs.map +1 -0
- package/dist/tokens/index.d.cts +212 -0
- package/dist/tokens/index.d.ts +212 -0
- package/dist/tokens/index.js +115 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/{track-changes-BK5sVf4_.d.cts → track-changes-D_VAPELi.d.cts} +95 -11
- package/dist/{track-changes-CDjCrwKe.d.ts → track-changes-Db_fGEvx.d.ts} +95 -11
- package/package.json +6 -1
- package/dist/chunk-3CN2WD3X.js.map +0 -1
- package/dist/chunk-5S3Z4PPF.js.map +0 -1
- package/dist/chunk-D27YFC46.cjs.map +0 -1
- package/dist/chunk-FODNLX5N.js.map +0 -1
- package/dist/chunk-ITBSKI26.js.map +0 -1
- package/dist/chunk-MA2F5KHF.cjs +0 -3223
- package/dist/chunk-MA2F5KHF.cjs.map +0 -1
- package/dist/chunk-MCSJFWAO.cjs.map +0 -1
- package/dist/chunk-OLZJXL4R.cjs.map +0 -1
- package/dist/chunk-PGNZKFQS.js.map +0 -1
- package/dist/chunk-SBCZ6RN5.cjs.map +0 -1
- package/dist/chunk-U5KWZU4X.js.map +0 -1
- package/dist/chunk-XNORY7M6.cjs.map +0 -1
- package/dist/controller-BhLLAoi8.d.cts +0 -1000
- package/dist/controller-BhLLAoi8.d.ts +0 -1000
- /package/dist/{chunk-3LV6RRPH.js.map → chunk-QGYDWPRM.js.map} +0 -0
package/dist/generation/index.js
CHANGED
|
@@ -8,8 +8,17 @@ import "../chunk-P6ODPZ4W.js";
|
|
|
8
8
|
import {
|
|
9
9
|
validateJsonSchema
|
|
10
10
|
} from "../chunk-ARRTP33I.js";
|
|
11
|
+
import {
|
|
12
|
+
findTextMentions,
|
|
13
|
+
formatMentionText,
|
|
14
|
+
setMentionRoleInText
|
|
15
|
+
} from "../chunk-O5RYH2PG.js";
|
|
11
16
|
|
|
12
17
|
// src/generation/capabilities.ts
|
|
18
|
+
var REFERENCE_ROLE_NAME_REGEX = /^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$/;
|
|
19
|
+
function isReferenceRoleName(value) {
|
|
20
|
+
return typeof value === "string" && value.length <= 64 && REFERENCE_ROLE_NAME_REGEX.test(value);
|
|
21
|
+
}
|
|
13
22
|
var REFERENCE_ROLES = [
|
|
14
23
|
"start_frame",
|
|
15
24
|
"end_frame",
|
|
@@ -32,6 +41,56 @@ var REFERENCE_ROLE_LABELS = {
|
|
|
32
41
|
video_ref: "Video reference",
|
|
33
42
|
audio_ref: "Audio reference"
|
|
34
43
|
};
|
|
44
|
+
var REFERENCE_ROLE_ALIASES = {
|
|
45
|
+
reference: "image_ref",
|
|
46
|
+
image: "image_ref",
|
|
47
|
+
style: "style_ref",
|
|
48
|
+
character: "character_ref",
|
|
49
|
+
background: "background_ref",
|
|
50
|
+
"start-frame": "start_frame",
|
|
51
|
+
"first-frame": "start_frame",
|
|
52
|
+
first_frame: "start_frame",
|
|
53
|
+
"end-frame": "end_frame",
|
|
54
|
+
"last-frame": "end_frame",
|
|
55
|
+
last_frame: "end_frame",
|
|
56
|
+
"style-ref": "style_ref",
|
|
57
|
+
"character-ref": "character_ref",
|
|
58
|
+
"background-ref": "background_ref",
|
|
59
|
+
"image-ref": "image_ref",
|
|
60
|
+
"video-ref": "video_ref",
|
|
61
|
+
"audio-ref": "audio_ref",
|
|
62
|
+
video: "video_ref",
|
|
63
|
+
audio: "audio_ref"
|
|
64
|
+
};
|
|
65
|
+
var isBuiltinRole = (role) => REFERENCE_ROLES.includes(role);
|
|
66
|
+
function referenceRoleLabel(role, caps) {
|
|
67
|
+
const declared = caps?.references?.roles[role]?.label;
|
|
68
|
+
if (declared) return declared;
|
|
69
|
+
if (isBuiltinRole(role)) return REFERENCE_ROLE_LABELS[role];
|
|
70
|
+
const words = String(role).replace(/[_-]+/g, " ").trim();
|
|
71
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
72
|
+
}
|
|
73
|
+
function normalizeReferenceRole(role, caps) {
|
|
74
|
+
const name = String(role).trim();
|
|
75
|
+
if (caps ? !!caps.references?.roles[name] : isBuiltinRole(name)) return name;
|
|
76
|
+
const lower = name.toLowerCase();
|
|
77
|
+
if (caps?.references?.roles[lower]) return lower;
|
|
78
|
+
if (!caps && isBuiltinRole(lower)) return lower;
|
|
79
|
+
return REFERENCE_ROLE_ALIASES[lower] ?? (isBuiltinRole(lower) ? lower : name);
|
|
80
|
+
}
|
|
81
|
+
function mediaTypeMatches(mediaType, accepts) {
|
|
82
|
+
if (!accepts || accepts.length === 0) return true;
|
|
83
|
+
if (!mediaType) return false;
|
|
84
|
+
const type = mediaType.split(";")[0].trim().toLowerCase();
|
|
85
|
+
const kind = type.split("/")[0];
|
|
86
|
+
return accepts.some((entry) => {
|
|
87
|
+
const pattern = entry.trim().toLowerCase();
|
|
88
|
+
if (pattern === "*" || pattern === "*/*" || pattern === type) return true;
|
|
89
|
+
if (!pattern.includes("/")) return pattern === kind;
|
|
90
|
+
if (pattern.endsWith("/*")) return pattern.slice(0, -2) === kind;
|
|
91
|
+
return false;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
35
94
|
var GENERATION_REQUEST_FIELDS = [
|
|
36
95
|
"model",
|
|
37
96
|
"prompt",
|
|
@@ -57,7 +116,11 @@ function seedCapability(value) {
|
|
|
57
116
|
}
|
|
58
117
|
function supportedReferenceRoles(caps) {
|
|
59
118
|
const roles = caps.references?.roles ?? {};
|
|
60
|
-
|
|
119
|
+
const builtin = REFERENCE_ROLES.filter((role) => (roles[role]?.max ?? 0) > 0);
|
|
120
|
+
const custom = Object.keys(roles).filter(
|
|
121
|
+
(role) => !isBuiltinRole(role) && isReferenceRoleName(role) && (roles[role]?.max ?? 0) > 0
|
|
122
|
+
);
|
|
123
|
+
return [...builtin, ...custom];
|
|
61
124
|
}
|
|
62
125
|
function supportedModes(caps) {
|
|
63
126
|
const modes = ["generate"];
|
|
@@ -356,19 +419,80 @@ var Planner = class {
|
|
|
356
419
|
if (role === "mask" && this.caps.inpainting) return { max: 1 };
|
|
357
420
|
return void 0;
|
|
358
421
|
}
|
|
422
|
+
/** Turns `options.mentions` into references (appended after the request's own). */
|
|
423
|
+
addMentions() {
|
|
424
|
+
const mentions = this.options.mentions;
|
|
425
|
+
if (!mentions?.length) return;
|
|
426
|
+
const refs = [...this.request.references ?? []];
|
|
427
|
+
for (const mention of mentions) {
|
|
428
|
+
if (!mention || typeof mention.id !== "string" || mention.id === "") continue;
|
|
429
|
+
let role = mention.role ?? void 0;
|
|
430
|
+
if (!role) {
|
|
431
|
+
role = this.options.defaultMentionRole ?? this.inferRole(mention.mediaType);
|
|
432
|
+
this.adjust(
|
|
433
|
+
`references.${role}`,
|
|
434
|
+
void 0,
|
|
435
|
+
role,
|
|
436
|
+
"defaulted",
|
|
437
|
+
`@${mention.label ?? mention.id} has no role; using ${role}.`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
refs.push({
|
|
441
|
+
id: mention.id,
|
|
442
|
+
role,
|
|
443
|
+
...mention.url !== void 0 ? { url: mention.url } : {},
|
|
444
|
+
...mention.mediaType !== void 0 ? { mediaType: mention.mediaType } : {},
|
|
445
|
+
...mention.contentHash !== void 0 ? { contentHash: mention.contentHash } : {}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
this.request.references = refs;
|
|
449
|
+
}
|
|
450
|
+
/** First role of the model (other than `mask`) whose `accepts` matches `mediaType`. */
|
|
451
|
+
inferRole(mediaType) {
|
|
452
|
+
for (const role of supportedReferenceRoles(this.caps)) {
|
|
453
|
+
if (role === "mask") continue;
|
|
454
|
+
const cap = this.roleCapability(role);
|
|
455
|
+
if (cap && (mediaType === void 0 || mediaTypeMatches(mediaType, cap.accepts))) return role;
|
|
456
|
+
}
|
|
457
|
+
return "image_ref";
|
|
458
|
+
}
|
|
359
459
|
planReferences() {
|
|
360
460
|
const refs = this.request.references;
|
|
361
461
|
const allowDrop = !this.strict && (this.options.dropUnsupportedReferences ?? (this.strategy === "nearest" || this.strategy === "downgrade"));
|
|
362
462
|
const byRole = /* @__PURE__ */ new Map();
|
|
363
463
|
const kept = [];
|
|
364
464
|
const unsupported = /* @__PURE__ */ new Map();
|
|
365
|
-
for (const [index,
|
|
366
|
-
|
|
367
|
-
|
|
465
|
+
for (const [index, original] of (refs ?? []).entries()) {
|
|
466
|
+
let ref = original;
|
|
467
|
+
if (!ref || typeof ref.id !== "string" || ref.id === "" || !isReferenceRoleName(ref.role)) {
|
|
468
|
+
this.error(`references.${index}`, ref, "Each reference needs an `id` and a valid `role`.");
|
|
368
469
|
continue;
|
|
369
470
|
}
|
|
370
471
|
if (!this.roleCapability(ref.role)) {
|
|
371
|
-
|
|
472
|
+
const alias = normalizeReferenceRole(ref.role, this.caps);
|
|
473
|
+
if (alias !== ref.role && this.roleCapability(alias)) {
|
|
474
|
+
if (this.strict) {
|
|
475
|
+
this.error(`references.${ref.role}`, ref.role, `The model calls this role ${describe(alias)}.`);
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
this.adjust(
|
|
479
|
+
`references.${ref.role}`,
|
|
480
|
+
ref.role,
|
|
481
|
+
alias,
|
|
482
|
+
"snapped",
|
|
483
|
+
`Using the model's ${alias} role for ${describe(ref.role)}.`
|
|
484
|
+
);
|
|
485
|
+
ref = { ...ref, role: alias };
|
|
486
|
+
} else {
|
|
487
|
+
unsupported.set(ref.role, (unsupported.get(ref.role) ?? 0) + 1);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const cap = this.roleCapability(ref.role);
|
|
492
|
+
if (ref.mediaType !== void 0 && !mediaTypeMatches(ref.mediaType, cap.accepts)) {
|
|
493
|
+
const message = `${describe(ref.id)} is ${describe(ref.mediaType)}; ${ref.role} accepts ${list(cap.accepts ?? [])}.`;
|
|
494
|
+
if (allowDrop) this.adjust(`references.${ref.role}`, ref.id, void 0, "dropped", message);
|
|
495
|
+
else this.error(`references.${ref.role}`, ref.id, message);
|
|
372
496
|
continue;
|
|
373
497
|
}
|
|
374
498
|
const group = byRole.get(ref.role) ?? [];
|
|
@@ -386,7 +510,10 @@ var Planner = class {
|
|
|
386
510
|
else this.error(`references.${role}`, count, message);
|
|
387
511
|
}
|
|
388
512
|
const removed = /* @__PURE__ */ new Set();
|
|
389
|
-
|
|
513
|
+
const custom = supportedReferenceRoles(this.caps).filter(
|
|
514
|
+
(role) => !REFERENCE_ROLES.includes(role)
|
|
515
|
+
);
|
|
516
|
+
for (const role of [...REFERENCE_ROLES, ...custom]) {
|
|
390
517
|
const cap = this.roleCapability(role);
|
|
391
518
|
const group = byRole.get(role) ?? [];
|
|
392
519
|
if (!cap) continue;
|
|
@@ -525,6 +652,7 @@ var Planner = class {
|
|
|
525
652
|
this.planDuration();
|
|
526
653
|
this.planSeed();
|
|
527
654
|
this.planMode();
|
|
655
|
+
this.addMentions();
|
|
528
656
|
this.planReferences();
|
|
529
657
|
this.planParams();
|
|
530
658
|
}
|
|
@@ -642,7 +770,8 @@ function capabilitiesToJsonSchema(caps) {
|
|
|
642
770
|
const limits = roles.map((role) => {
|
|
643
771
|
const cap = caps.references?.roles[role] ?? { max: 1 };
|
|
644
772
|
const min = cap.min ? `${cap.min}\u2013` : "up to ";
|
|
645
|
-
|
|
773
|
+
const accepts = "accepts" in cap && cap.accepts?.length ? `, ${cap.accepts.join("/")} only` : "";
|
|
774
|
+
return `${role} (${referenceRoleLabel(role, caps)}): ${min}${cap.max}${accepts}`;
|
|
646
775
|
});
|
|
647
776
|
const perRoleTotal = roles.reduce((sum, role) => sum + (caps.references?.roles[role]?.max ?? 1), 0);
|
|
648
777
|
const maxItems = Math.min(caps.references?.maxTotal ?? Infinity, perRoleTotal);
|
|
@@ -655,7 +784,9 @@ function capabilitiesToJsonSchema(caps) {
|
|
|
655
784
|
properties: {
|
|
656
785
|
id: { type: "string", minLength: 1, description: "Asset id." },
|
|
657
786
|
role: { type: "string", enum: roles },
|
|
658
|
-
url: { type: "string" }
|
|
787
|
+
url: { type: "string" },
|
|
788
|
+
mediaType: { type: "string", description: 'MIME type or media kind of the asset, e.g. "image/png".' },
|
|
789
|
+
contentHash: { type: "string" }
|
|
659
790
|
},
|
|
660
791
|
required: ["id", "role"],
|
|
661
792
|
additionalProperties: false
|
|
@@ -682,9 +813,58 @@ function capabilitiesToJsonSchema(caps) {
|
|
|
682
813
|
};
|
|
683
814
|
}
|
|
684
815
|
|
|
816
|
+
// src/generation/hash.ts
|
|
817
|
+
function stableStringify(value) {
|
|
818
|
+
if (Array.isArray(value)) return `[${value.map((item) => item === void 0 ? "null" : stableStringify(item)).join(",")}]`;
|
|
819
|
+
if (value && typeof value === "object") {
|
|
820
|
+
const entries = Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`);
|
|
821
|
+
return `{${entries.join(",")}}`;
|
|
822
|
+
}
|
|
823
|
+
return JSON.stringify(value) ?? "null";
|
|
824
|
+
}
|
|
825
|
+
var FNV_PRIME = 16777619;
|
|
826
|
+
function hashText(text) {
|
|
827
|
+
let a = 2166136261;
|
|
828
|
+
let b = 789454171;
|
|
829
|
+
for (let i = 0; i < text.length; i++) {
|
|
830
|
+
const unit = text.charCodeAt(i);
|
|
831
|
+
a = Math.imul(a ^ unit & 255, FNV_PRIME);
|
|
832
|
+
a = Math.imul(a ^ unit >>> 8, FNV_PRIME);
|
|
833
|
+
b = Math.imul(b ^ unit >>> 8, FNV_PRIME);
|
|
834
|
+
b = Math.imul(b ^ unit & 255, FNV_PRIME);
|
|
835
|
+
b ^= b >>> 15;
|
|
836
|
+
}
|
|
837
|
+
a ^= a >>> 16;
|
|
838
|
+
a = Math.imul(a, 2246822507);
|
|
839
|
+
a ^= a >>> 13;
|
|
840
|
+
b ^= b >>> 16;
|
|
841
|
+
b = Math.imul(b, 3266489909);
|
|
842
|
+
b ^= b >>> 13;
|
|
843
|
+
const hex = (n) => (n >>> 0).toString(16).padStart(8, "0");
|
|
844
|
+
return `h1-${hex(a)}${hex(b)}`;
|
|
845
|
+
}
|
|
846
|
+
function hashValue(value) {
|
|
847
|
+
return hashText(stableStringify(value));
|
|
848
|
+
}
|
|
849
|
+
var PRESENTATION_ONLY = /* @__PURE__ */ new Set(["name", "description", "badges", "icon", "group", "timing"]);
|
|
850
|
+
function hashCapabilities(caps) {
|
|
851
|
+
const relevant = {};
|
|
852
|
+
for (const key of Object.keys(caps)) {
|
|
853
|
+
if (!PRESENTATION_ONLY.has(key)) relevant[key] = caps[key];
|
|
854
|
+
}
|
|
855
|
+
return hashValue(relevant);
|
|
856
|
+
}
|
|
857
|
+
|
|
685
858
|
// src/generation/tools.ts
|
|
686
859
|
var STRATEGIES = ["nearest", "upgrade", "downgrade", "error"];
|
|
687
|
-
|
|
860
|
+
function knownRoles(models) {
|
|
861
|
+
const roles = [...REFERENCE_ROLES];
|
|
862
|
+
for (const model of models) {
|
|
863
|
+
for (const role of supportedReferenceRoles(model)) if (!roles.includes(role)) roles.push(role);
|
|
864
|
+
}
|
|
865
|
+
return roles;
|
|
866
|
+
}
|
|
867
|
+
var requestSchemaFor = (roles) => ({
|
|
688
868
|
type: "object",
|
|
689
869
|
description: "Generation request. Call list_models for the fields each model supports; unsupported values are adjusted per `strategy`.",
|
|
690
870
|
properties: {
|
|
@@ -704,8 +884,14 @@ var requestSchema = {
|
|
|
704
884
|
type: "object",
|
|
705
885
|
properties: {
|
|
706
886
|
id: { type: "string", minLength: 1 },
|
|
707
|
-
role: {
|
|
708
|
-
|
|
887
|
+
role: {
|
|
888
|
+
type: "string",
|
|
889
|
+
enum: [...roles],
|
|
890
|
+
description: "What the asset is used for. Each model lists the roles it accepts (list_models)."
|
|
891
|
+
},
|
|
892
|
+
url: { type: "string" },
|
|
893
|
+
mediaType: { type: "string", description: 'MIME type or media kind, e.g. "image/png".' },
|
|
894
|
+
contentHash: { type: "string" }
|
|
709
895
|
},
|
|
710
896
|
required: ["id", "role"],
|
|
711
897
|
additionalProperties: false
|
|
@@ -714,20 +900,12 @@ var requestSchema = {
|
|
|
714
900
|
params: { type: "object", additionalProperties: { type: ["string", "number", "boolean"] } }
|
|
715
901
|
},
|
|
716
902
|
additionalProperties: false
|
|
717
|
-
};
|
|
903
|
+
});
|
|
718
904
|
var strategySchema = {
|
|
719
905
|
type: "string",
|
|
720
906
|
enum: STRATEGIES,
|
|
721
907
|
description: "How to handle unsupported values: nearest (snap/clamp, ties up), downgrade (ties down), upgrade (ties up, never drops references), error (change nothing)."
|
|
722
908
|
};
|
|
723
|
-
function stableStringify(value) {
|
|
724
|
-
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
725
|
-
if (value && typeof value === "object") {
|
|
726
|
-
const entries = Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`);
|
|
727
|
-
return `{${entries.join(",")}}`;
|
|
728
|
-
}
|
|
729
|
-
return JSON.stringify(value) ?? "null";
|
|
730
|
-
}
|
|
731
909
|
function planFailure(plan) {
|
|
732
910
|
return {
|
|
733
911
|
isError: true,
|
|
@@ -746,13 +924,13 @@ function createGenerationToolProvider(options) {
|
|
|
746
924
|
const defaultStrategy = options.defaultStrategy ?? "nearest";
|
|
747
925
|
const maxKeys = Math.max(1, options.maxIdempotencyKeys ?? 500);
|
|
748
926
|
const calls = /* @__PURE__ */ new Map();
|
|
749
|
-
const
|
|
927
|
+
const findModel2 = (id) => {
|
|
750
928
|
const model = readModels().find((m) => m.id === id);
|
|
751
929
|
if (!model) throw new Error(`Unknown model "${String(id)}". Call list_models for the available ids.`);
|
|
752
930
|
return model;
|
|
753
931
|
};
|
|
754
932
|
const plan = (args) => {
|
|
755
|
-
const model =
|
|
933
|
+
const model = findModel2(args.model);
|
|
756
934
|
const request = { ...args.request ?? {}, model: model.id };
|
|
757
935
|
return {
|
|
758
936
|
model,
|
|
@@ -763,12 +941,13 @@ function createGenerationToolProvider(options) {
|
|
|
763
941
|
};
|
|
764
942
|
};
|
|
765
943
|
const planInput = () => {
|
|
766
|
-
const
|
|
944
|
+
const models = readModels();
|
|
945
|
+
const ids = models.map((m) => m.id);
|
|
767
946
|
return {
|
|
768
947
|
type: "object",
|
|
769
948
|
properties: {
|
|
770
949
|
model: { type: "string", ...ids.length ? { enum: ids } : {}, description: "Model id from list_models." },
|
|
771
|
-
request:
|
|
950
|
+
request: requestSchemaFor(knownRoles(models)),
|
|
772
951
|
strategy: strategySchema,
|
|
773
952
|
resolvedPrompt: {
|
|
774
953
|
type: "string",
|
|
@@ -1046,12 +1225,6 @@ function parseProvenance(input) {
|
|
|
1046
1225
|
values: isRecord(data.values) ? data.values : null
|
|
1047
1226
|
};
|
|
1048
1227
|
}
|
|
1049
|
-
function recreateRequest(provenance) {
|
|
1050
|
-
const request = clone(provenance.request);
|
|
1051
|
-
request.model = provenance.modelId;
|
|
1052
|
-
if (request.prompt === void 0) request.prompt = provenance.resolvedPrompt;
|
|
1053
|
-
return request;
|
|
1054
|
-
}
|
|
1055
1228
|
function replayProvenancePrompt(provenance) {
|
|
1056
1229
|
const result = resolvePrompt(provenance.rawPrompt, pinnedTemplatesToTemplates(provenance.templates), {
|
|
1057
1230
|
bindings: provenance.bindings,
|
|
@@ -1311,8 +1484,9 @@ function getReferenceSlots(caps, request = {}) {
|
|
|
1311
1484
|
const references = refs.filter((ref) => ref.role === role);
|
|
1312
1485
|
return {
|
|
1313
1486
|
role,
|
|
1314
|
-
label:
|
|
1487
|
+
label: referenceRoleLabel(role, caps),
|
|
1315
1488
|
...cap.description ? { description: cap.description } : {},
|
|
1489
|
+
..."accepts" in cap && cap.accepts?.length ? { accepts: [...cap.accepts] } : {},
|
|
1316
1490
|
min: cap.min ?? 0,
|
|
1317
1491
|
max: cap.max,
|
|
1318
1492
|
references,
|
|
@@ -1329,7 +1503,747 @@ function removeReference(request, role, id) {
|
|
|
1329
1503
|
if (references.length === 0) delete next.references;
|
|
1330
1504
|
return next;
|
|
1331
1505
|
}
|
|
1506
|
+
|
|
1507
|
+
// src/generation/assets.ts
|
|
1508
|
+
function toAssetResolver(lookup) {
|
|
1509
|
+
if (!lookup) return void 0;
|
|
1510
|
+
if (typeof lookup === "function") return (id) => lookup(id) ?? void 0;
|
|
1511
|
+
if (lookup instanceof Map) return (id) => lookup.get(id);
|
|
1512
|
+
const byId = new Map(lookup.map((asset) => [asset.id, asset]));
|
|
1513
|
+
return (id) => byId.get(id);
|
|
1514
|
+
}
|
|
1515
|
+
function roleCap(caps, role) {
|
|
1516
|
+
const cap = caps.references?.roles[role];
|
|
1517
|
+
if (cap && cap.max > 0) return cap;
|
|
1518
|
+
if (role === "mask" && caps.inpainting) return { max: 1 };
|
|
1519
|
+
return void 0;
|
|
1520
|
+
}
|
|
1521
|
+
function getAssetRoleOptions(caps) {
|
|
1522
|
+
const roles = supportedReferenceRoles(caps);
|
|
1523
|
+
if (caps.inpainting && !roles.includes("mask")) roles.push("mask");
|
|
1524
|
+
return roles.map((role) => {
|
|
1525
|
+
const cap = roleCap(caps, role) ?? { max: 1 };
|
|
1526
|
+
return {
|
|
1527
|
+
role,
|
|
1528
|
+
label: referenceRoleLabel(role, caps),
|
|
1529
|
+
...cap.description ? { description: cap.description } : {},
|
|
1530
|
+
min: cap.min ?? 0,
|
|
1531
|
+
max: cap.max,
|
|
1532
|
+
...cap.accepts?.length ? { accepts: [...cap.accepts] } : {}
|
|
1533
|
+
};
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
function validateAssetMentions(mentions, caps, options = {}) {
|
|
1537
|
+
const resolve = toAssetResolver(options.assets);
|
|
1538
|
+
const issues = [];
|
|
1539
|
+
const counts = {};
|
|
1540
|
+
mentions.forEach((mention, index) => {
|
|
1541
|
+
const id = mention.id;
|
|
1542
|
+
const label = `@${mention.label ?? id}`;
|
|
1543
|
+
if (!mention.role) {
|
|
1544
|
+
issues.push({ index, id, code: "missing-role", severity: "warning", message: `${label} has no role.` });
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
let role = mention.role;
|
|
1548
|
+
if (!roleCap(caps, role)) {
|
|
1549
|
+
const alias = normalizeReferenceRole(role, caps);
|
|
1550
|
+
if (alias !== role && roleCap(caps, alias)) {
|
|
1551
|
+
issues.push({
|
|
1552
|
+
index,
|
|
1553
|
+
id,
|
|
1554
|
+
role,
|
|
1555
|
+
code: "renamed-role",
|
|
1556
|
+
severity: "warning",
|
|
1557
|
+
suggestion: alias,
|
|
1558
|
+
message: `${label}: this model calls "${role}" ${referenceRoleLabel(alias, caps)} (${alias}).`
|
|
1559
|
+
});
|
|
1560
|
+
role = alias;
|
|
1561
|
+
} else {
|
|
1562
|
+
issues.push({
|
|
1563
|
+
index,
|
|
1564
|
+
id,
|
|
1565
|
+
role,
|
|
1566
|
+
code: "unsupported-role",
|
|
1567
|
+
severity: "error",
|
|
1568
|
+
message: `${label}: ${caps.name ?? caps.id} does not accept ${referenceRoleLabel(role, caps).toLowerCase()} assets.`
|
|
1569
|
+
});
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
const cap = roleCap(caps, role);
|
|
1574
|
+
const mediaType = mention.mediaType ?? resolve?.(id)?.mediaType;
|
|
1575
|
+
if (mediaType !== void 0 && !mediaTypeMatches(mediaType, cap.accepts)) {
|
|
1576
|
+
issues.push({
|
|
1577
|
+
index,
|
|
1578
|
+
id,
|
|
1579
|
+
role,
|
|
1580
|
+
code: "media-mismatch",
|
|
1581
|
+
severity: "error",
|
|
1582
|
+
message: `${label} is ${mediaType}; ${referenceRoleLabel(role, caps)} accepts ${(cap.accepts ?? []).join(", ")}.`
|
|
1583
|
+
});
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
counts[role] = (counts[role] ?? 0) + 1;
|
|
1587
|
+
if (counts[role] > cap.max) {
|
|
1588
|
+
issues.push({
|
|
1589
|
+
index,
|
|
1590
|
+
id,
|
|
1591
|
+
role,
|
|
1592
|
+
code: "too-many",
|
|
1593
|
+
severity: "warning",
|
|
1594
|
+
message: `${label}: at most ${cap.max} ${referenceRoleLabel(role, caps).toLowerCase()} asset(s); extra ones are left out.`
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
const missing = getAssetRoleOptions(caps).filter((option) => (counts[option.role] ?? 0) < option.min).map((option) => ({ role: option.role, min: option.min, count: counts[option.role] ?? 0 }));
|
|
1599
|
+
return { ok: !issues.some((issue) => issue.severity === "error") && missing.length === 0, issues, counts, missing };
|
|
1600
|
+
}
|
|
1601
|
+
function resolveAssetMentions(mentions, assets) {
|
|
1602
|
+
const byId = new Map(assets.map((asset) => [asset.id, asset]));
|
|
1603
|
+
const byLabel = new Map(assets.filter((a) => a.label).map((asset) => [asset.label.toLowerCase(), asset]));
|
|
1604
|
+
const result = [];
|
|
1605
|
+
for (const mention of mentions) {
|
|
1606
|
+
const asset = byId.get(mention.handle) ?? byLabel.get(mention.handle.toLowerCase());
|
|
1607
|
+
if (!asset) continue;
|
|
1608
|
+
result.push({
|
|
1609
|
+
id: asset.id,
|
|
1610
|
+
label: mention.handle,
|
|
1611
|
+
...mention.role ? { role: mention.role } : {},
|
|
1612
|
+
...asset.mediaType !== void 0 ? { mediaType: asset.mediaType } : {},
|
|
1613
|
+
...asset.contentHash !== void 0 ? { contentHash: asset.contentHash } : {},
|
|
1614
|
+
...asset.url !== void 0 ? { url: asset.url } : {}
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
return result;
|
|
1618
|
+
}
|
|
1619
|
+
function defaultAssetRoleOptions() {
|
|
1620
|
+
return REFERENCE_ROLES.map((role) => ({ role, label: referenceRoleLabel(role), min: 0, max: 1 }));
|
|
1621
|
+
}
|
|
1622
|
+
function describeAssetMentions(mentions, assets, caps) {
|
|
1623
|
+
const byId = new Map(assets.map((asset) => [asset.id, asset]));
|
|
1624
|
+
const byLabel = new Map(assets.filter((a) => a.label).map((asset) => [asset.label.toLowerCase(), asset]));
|
|
1625
|
+
const chips = [];
|
|
1626
|
+
for (const mention of mentions) {
|
|
1627
|
+
const asset = byId.get(mention.handle) ?? byLabel.get(mention.handle.toLowerCase());
|
|
1628
|
+
if (!asset) continue;
|
|
1629
|
+
const role = mention.role || void 0;
|
|
1630
|
+
chips.push({
|
|
1631
|
+
index: chips.length,
|
|
1632
|
+
...mention.start !== void 0 ? { start: mention.start } : {},
|
|
1633
|
+
handle: mention.handle,
|
|
1634
|
+
asset,
|
|
1635
|
+
...role ? { role, roleLabel: referenceRoleLabel(caps ? normalizeReferenceRole(role, caps) : role, caps) } : {},
|
|
1636
|
+
issues: []
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
if (caps) {
|
|
1640
|
+
const validation = validateAssetMentions(
|
|
1641
|
+
chips.map((chip) => ({
|
|
1642
|
+
id: chip.asset.id,
|
|
1643
|
+
label: chip.handle,
|
|
1644
|
+
...chip.role ? { role: chip.role } : {},
|
|
1645
|
+
...chip.asset.mediaType ? { mediaType: chip.asset.mediaType } : {}
|
|
1646
|
+
})),
|
|
1647
|
+
caps
|
|
1648
|
+
);
|
|
1649
|
+
for (const issue of validation.issues) chips[issue.index].issues.push(issue);
|
|
1650
|
+
}
|
|
1651
|
+
return chips;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/generation/record.ts
|
|
1655
|
+
var GENERATION_RECORD_FORMAT = "pixerate.generation-record";
|
|
1656
|
+
var GENERATION_RECORD_VERSION = 1;
|
|
1657
|
+
var idCounter = 0;
|
|
1658
|
+
function createGenerationRecordId() {
|
|
1659
|
+
const uuid = globalThis.crypto?.randomUUID?.();
|
|
1660
|
+
if (typeof uuid === "string") return `gen_${uuid}`;
|
|
1661
|
+
idCounter = (idCounter + 1) % 1679616;
|
|
1662
|
+
const random = Math.floor(Math.random() * 2 ** 48).toString(36).padStart(10, "0");
|
|
1663
|
+
return `gen_${Date.now().toString(36)}${idCounter.toString(36).padStart(4, "0")}${random}`;
|
|
1664
|
+
}
|
|
1665
|
+
var clone2 = (value) => value === void 0 ? value : JSON.parse(JSON.stringify(value));
|
|
1666
|
+
function recordTemplates(pinned) {
|
|
1667
|
+
return pinned.map((p) => ({
|
|
1668
|
+
name: p.name,
|
|
1669
|
+
...p.templateId !== void 0 ? { templateId: p.templateId } : {},
|
|
1670
|
+
...p.versionId !== void 0 ? { versionId: p.versionId, version: p.version } : {},
|
|
1671
|
+
hash: hashText(p.body)
|
|
1672
|
+
}));
|
|
1673
|
+
}
|
|
1674
|
+
function recordAssets(references, lookup) {
|
|
1675
|
+
const resolve = toAssetResolver(lookup);
|
|
1676
|
+
return (references ?? []).map((ref) => {
|
|
1677
|
+
const info = resolve?.(ref.id);
|
|
1678
|
+
const contentHash = ref.contentHash ?? info?.contentHash;
|
|
1679
|
+
const mediaType = ref.mediaType ?? info?.mediaType;
|
|
1680
|
+
const url = ref.url ?? info?.url;
|
|
1681
|
+
return {
|
|
1682
|
+
id: ref.id,
|
|
1683
|
+
role: ref.role,
|
|
1684
|
+
...contentHash !== void 0 ? { contentHash } : {},
|
|
1685
|
+
...mediaType !== void 0 ? { mediaType } : {},
|
|
1686
|
+
...url !== void 0 ? { url } : {}
|
|
1687
|
+
};
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
function createGenerationRecord(options) {
|
|
1691
|
+
const {
|
|
1692
|
+
model,
|
|
1693
|
+
request: settingsInput,
|
|
1694
|
+
plan: planInput,
|
|
1695
|
+
strategy: strategyInput,
|
|
1696
|
+
mentions,
|
|
1697
|
+
assets,
|
|
1698
|
+
seed: seedInput,
|
|
1699
|
+
id,
|
|
1700
|
+
parentId,
|
|
1701
|
+
kind,
|
|
1702
|
+
...provenanceOptions
|
|
1703
|
+
} = options;
|
|
1704
|
+
const caps = typeof model === "string" ? void 0 : model;
|
|
1705
|
+
const settings = clone2(settingsInput ?? planInput?.request ?? {});
|
|
1706
|
+
let plan = planInput;
|
|
1707
|
+
if (!plan && caps) {
|
|
1708
|
+
const resolved = resolvePrompt(options.rawPrompt, options.templates ?? [], {
|
|
1709
|
+
bindings: options.bindings,
|
|
1710
|
+
values: options.values,
|
|
1711
|
+
maxDepth: options.maxDepth
|
|
1712
|
+
});
|
|
1713
|
+
plan = planGenerationRequest(settings, caps, {
|
|
1714
|
+
strategy: strategyInput ?? "nearest",
|
|
1715
|
+
resolvedPrompt: resolved.text,
|
|
1716
|
+
...mentions ? { mentions } : {}
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
const provenance = createProvenance({
|
|
1720
|
+
...provenanceOptions,
|
|
1721
|
+
model,
|
|
1722
|
+
...plan ? { plan } : { request: settings }
|
|
1723
|
+
});
|
|
1724
|
+
const seed = seedInput ?? provenance.request.seed;
|
|
1725
|
+
return {
|
|
1726
|
+
format: GENERATION_RECORD_FORMAT,
|
|
1727
|
+
version: GENERATION_RECORD_VERSION,
|
|
1728
|
+
id: id ?? createGenerationRecordId(),
|
|
1729
|
+
...parentId !== void 0 ? { parentId } : {},
|
|
1730
|
+
kind: kind ?? (parentId !== void 0 ? "recreate" : "generate"),
|
|
1731
|
+
provenance,
|
|
1732
|
+
templates: recordTemplates(provenance.templates),
|
|
1733
|
+
promptHash: hashText(provenance.resolvedPrompt),
|
|
1734
|
+
...caps ? { capabilityHash: hashCapabilities(caps) } : {},
|
|
1735
|
+
settings,
|
|
1736
|
+
strategy: strategyInput ?? plan?.strategy ?? "nearest",
|
|
1737
|
+
...seed !== void 0 ? { seed } : {},
|
|
1738
|
+
assets: recordAssets(provenance.request.references, assets),
|
|
1739
|
+
...mentions?.length ? { mentions: clone2([...mentions]) } : {},
|
|
1740
|
+
createdAt: provenance.createdAt
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
function completeGenerationRecord(record, update) {
|
|
1744
|
+
const next = clone2(record);
|
|
1745
|
+
const now = new Date(update.completedAt ?? Date.now()).toISOString();
|
|
1746
|
+
if (update.outputIds) next.provenance.outputIds = [...update.outputIds];
|
|
1747
|
+
next.provenance.completedAt = now;
|
|
1748
|
+
if (update.meta) next.provenance.meta = { ...next.provenance.meta ?? {}, ...clone2(update.meta) };
|
|
1749
|
+
if (update.seed !== void 0) next.seed = update.seed;
|
|
1750
|
+
next.updatedAt = now;
|
|
1751
|
+
return next;
|
|
1752
|
+
}
|
|
1753
|
+
function serializeGenerationRecord(record) {
|
|
1754
|
+
return JSON.stringify(record);
|
|
1755
|
+
}
|
|
1756
|
+
var isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
1757
|
+
function parseGenerationRecord(input) {
|
|
1758
|
+
let data = input;
|
|
1759
|
+
if (typeof input === "string") {
|
|
1760
|
+
try {
|
|
1761
|
+
data = JSON.parse(input);
|
|
1762
|
+
} catch {
|
|
1763
|
+
throw new ProvenanceParseError("Generation record is not valid JSON.");
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
if (!isObject(data) || data.format !== GENERATION_RECORD_FORMAT) {
|
|
1767
|
+
throw new ProvenanceParseError("Not a generation record.");
|
|
1768
|
+
}
|
|
1769
|
+
if (typeof data.version !== "number" || data.version > GENERATION_RECORD_VERSION) {
|
|
1770
|
+
throw new ProvenanceParseError(`Unsupported generation record version ${JSON.stringify(data.version)}.`);
|
|
1771
|
+
}
|
|
1772
|
+
const checks = [
|
|
1773
|
+
["id", typeof data.id === "string" && data.id !== ""],
|
|
1774
|
+
["templates", Array.isArray(data.templates) && data.templates.every((t) => isObject(t) && typeof t.name === "string" && typeof t.hash === "string")],
|
|
1775
|
+
["assets", Array.isArray(data.assets) && data.assets.every((a) => isObject(a) && typeof a.id === "string" && typeof a.role === "string")],
|
|
1776
|
+
["settings", isObject(data.settings)],
|
|
1777
|
+
["promptHash", typeof data.promptHash === "string"],
|
|
1778
|
+
["createdAt", typeof data.createdAt === "string"]
|
|
1779
|
+
];
|
|
1780
|
+
const bad = checks.find(([, ok]) => !ok);
|
|
1781
|
+
if (bad) throw new ProvenanceParseError(`Invalid generation record field "${bad[0]}".`);
|
|
1782
|
+
const provenance = parseProvenance(data.provenance);
|
|
1783
|
+
return {
|
|
1784
|
+
...data,
|
|
1785
|
+
kind: data.kind === "recreate" || data.kind === "variation" ? data.kind : "generate",
|
|
1786
|
+
strategy: ["nearest", "upgrade", "downgrade", "error"].includes(data.strategy) ? data.strategy : "nearest",
|
|
1787
|
+
provenance
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
function isGenerationRecord(value) {
|
|
1791
|
+
return isObject(value) && value.format === GENERATION_RECORD_FORMAT;
|
|
1792
|
+
}
|
|
1793
|
+
var SKIPPED_SETTING_FIELDS = /* @__PURE__ */ new Set(["model", "prompt", "references", "params", "seed"]);
|
|
1794
|
+
function findModel(capabilities, modelId) {
|
|
1795
|
+
if (!capabilities) return { given: false };
|
|
1796
|
+
const list2 = Array.isArray(capabilities) ? capabilities : [capabilities];
|
|
1797
|
+
return { given: true, caps: list2.find((m) => m.id === modelId) };
|
|
1798
|
+
}
|
|
1799
|
+
var sameValue = (a, b) => stableStringify(a) === stableStringify(b);
|
|
1800
|
+
var show = (value) => value === void 0 ? "unset" : typeof value === "string" ? `"${value}"` : JSON.stringify(value);
|
|
1801
|
+
var refKey = (ref) => `${ref.role}:${ref.id}`;
|
|
1802
|
+
function templateDrift(record, current, mode) {
|
|
1803
|
+
if (!current) return [];
|
|
1804
|
+
const byName = new Map(current.map((t) => [t.name, t]));
|
|
1805
|
+
const drift = [];
|
|
1806
|
+
for (const recorded of record.templates) {
|
|
1807
|
+
const template = byName.get(recorded.name);
|
|
1808
|
+
const fromVersion = recorded.version ?? recorded.versionId;
|
|
1809
|
+
if (!template) {
|
|
1810
|
+
drift.push({
|
|
1811
|
+
type: "template-missing",
|
|
1812
|
+
severity: "warning",
|
|
1813
|
+
template: recorded.name,
|
|
1814
|
+
from: fromVersion,
|
|
1815
|
+
applied: false,
|
|
1816
|
+
message: `Template "${recorded.name}" no longer exists; the recorded body is used.`
|
|
1817
|
+
});
|
|
1818
|
+
continue;
|
|
1819
|
+
}
|
|
1820
|
+
const body = getTemplateBody(template, {});
|
|
1821
|
+
const hash = body === void 0 ? void 0 : hashText(body);
|
|
1822
|
+
if (hash === recorded.hash) continue;
|
|
1823
|
+
const latest = getLatestVersion(template);
|
|
1824
|
+
const toVersion = template.versions?.length ? latest?.version ?? latest?.id : void 0;
|
|
1825
|
+
const versions = fromVersion !== void 0 || toVersion !== void 0 ? ` (${fromVersion ?? "unversioned"} \u2192 ${toVersion ?? "unversioned"})` : "";
|
|
1826
|
+
drift.push({
|
|
1827
|
+
type: "template-changed",
|
|
1828
|
+
severity: mode === "latest" ? "info" : "warning",
|
|
1829
|
+
template: recorded.name,
|
|
1830
|
+
from: { version: fromVersion, hash: recorded.hash },
|
|
1831
|
+
to: { version: toVersion, hash },
|
|
1832
|
+
applied: mode === "latest",
|
|
1833
|
+
message: mode === "latest" ? `Template "${recorded.name}" changed since this generation${versions}; using the current version.` : `Template "${recorded.name}" changed since this generation${versions}; recreating with the recorded version.`
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
return drift;
|
|
1837
|
+
}
|
|
1838
|
+
function randomSeed(caps, previous, random) {
|
|
1839
|
+
const cap = caps ? seedCapability(caps.seed) : {};
|
|
1840
|
+
if (!cap) return void 0;
|
|
1841
|
+
const min = Math.ceil(cap.min ?? 0);
|
|
1842
|
+
const max = Math.floor(cap.max ?? 2 ** 31 - 1);
|
|
1843
|
+
if (max < min) return min;
|
|
1844
|
+
let seed = previous;
|
|
1845
|
+
for (let attempt = 0; attempt < 8 && (seed === void 0 || seed === previous); attempt++) {
|
|
1846
|
+
seed = min + Math.floor(random() * (max - min + 1));
|
|
1847
|
+
}
|
|
1848
|
+
if (seed === previous && max > min) seed = previous === max ? min : previous + 1;
|
|
1849
|
+
return seed;
|
|
1850
|
+
}
|
|
1851
|
+
function rebuild(record, options, kind, overrides) {
|
|
1852
|
+
const mode = options.mode ?? "exact";
|
|
1853
|
+
const provenance = record.provenance;
|
|
1854
|
+
const drift = templateDrift(record, options.templates, mode);
|
|
1855
|
+
const rawPrompt = overrides?.rawPrompt ?? provenance.rawPrompt;
|
|
1856
|
+
const values = overrides?.values !== void 0 ? { ...provenance.values ?? {}, ...overrides.values } : provenance.values ? clone2(provenance.values) : null;
|
|
1857
|
+
const pinned = pinnedTemplatesToTemplates(provenance.templates);
|
|
1858
|
+
let templates;
|
|
1859
|
+
let bindings;
|
|
1860
|
+
if (mode === "latest" && options.templates) {
|
|
1861
|
+
const currentNames = new Set(options.templates.map((t) => t.name));
|
|
1862
|
+
const fallback = pinned.filter((t) => !currentNames.has(t.name));
|
|
1863
|
+
templates = [...options.templates.map((t) => ({ ...t })), ...fallback];
|
|
1864
|
+
bindings = {};
|
|
1865
|
+
for (const t of fallback) {
|
|
1866
|
+
if (provenance.bindings[t.name] !== void 0) bindings[t.name] = provenance.bindings[t.name];
|
|
1867
|
+
}
|
|
1868
|
+
} else {
|
|
1869
|
+
templates = pinned;
|
|
1870
|
+
bindings = { ...provenance.bindings };
|
|
1871
|
+
}
|
|
1872
|
+
const resolved = resolvePrompt(rawPrompt, templates, { bindings, ...values ? { values } : {} });
|
|
1873
|
+
const sourceMap = resolved.map.map((segment) => {
|
|
1874
|
+
const { locked: _locked, ...rest } = segment;
|
|
1875
|
+
return rest;
|
|
1876
|
+
});
|
|
1877
|
+
if (resolved.text !== provenance.resolvedPrompt && !overrides) {
|
|
1878
|
+
drift.push({
|
|
1879
|
+
type: "prompt-changed",
|
|
1880
|
+
severity: "info",
|
|
1881
|
+
from: provenance.resolvedPrompt,
|
|
1882
|
+
to: resolved.text,
|
|
1883
|
+
applied: true,
|
|
1884
|
+
message: "The resolved prompt differs from the recorded one."
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
const base = clone2(mode === "exact" ? provenance.request : record.settings);
|
|
1888
|
+
const recordedPlanned = provenance.request;
|
|
1889
|
+
if (base.prompt === void 0 || base.prompt === provenance.resolvedPrompt) base.prompt = resolved.text;
|
|
1890
|
+
else if (base.prompt === provenance.rawPrompt) base.prompt = rawPrompt;
|
|
1891
|
+
if (mode === "latest" && record.mentions?.length) {
|
|
1892
|
+
const plannedRole = new Map((recordedPlanned.references ?? []).map((ref) => [ref.id, ref.role]));
|
|
1893
|
+
base.references = [
|
|
1894
|
+
...base.references ?? [],
|
|
1895
|
+
...record.mentions.map((m) => ({
|
|
1896
|
+
id: m.id,
|
|
1897
|
+
role: m.role || plannedRole.get(m.id) || "image_ref",
|
|
1898
|
+
...m.url !== void 0 ? { url: m.url } : {},
|
|
1899
|
+
...m.mediaType !== void 0 ? { mediaType: m.mediaType } : {},
|
|
1900
|
+
...m.contentHash !== void 0 ? { contentHash: m.contentHash } : {}
|
|
1901
|
+
}))
|
|
1902
|
+
];
|
|
1903
|
+
} else if (mode === "latest" && base.references === void 0 && recordedPlanned.references) {
|
|
1904
|
+
base.references = clone2(recordedPlanned.references);
|
|
1905
|
+
}
|
|
1906
|
+
if (record.seed !== void 0) base.seed = record.seed;
|
|
1907
|
+
base.model = provenance.modelId;
|
|
1908
|
+
const { given, caps } = findModel(options.capabilities, provenance.modelId);
|
|
1909
|
+
if (overrides) {
|
|
1910
|
+
if (overrides.settings) {
|
|
1911
|
+
const { params, ...rest } = overrides.settings;
|
|
1912
|
+
Object.assign(base, clone2(rest));
|
|
1913
|
+
if (params) base.params = { ...base.params ?? {}, ...clone2(params) };
|
|
1914
|
+
}
|
|
1915
|
+
if (overrides.seed === null) delete base.seed;
|
|
1916
|
+
else base.seed = overrides.seed ?? randomSeed(caps, record.seed, overrides.random ?? Math.random);
|
|
1917
|
+
if (base.seed === void 0) delete base.seed;
|
|
1918
|
+
}
|
|
1919
|
+
const resolveAsset = toAssetResolver(options.assets);
|
|
1920
|
+
if (resolveAsset && base.references) {
|
|
1921
|
+
const recordedById = new Map(record.assets.map((a) => [refKey(a), a]));
|
|
1922
|
+
const kept = [];
|
|
1923
|
+
for (const ref of base.references) {
|
|
1924
|
+
const info = resolveAsset(ref.id);
|
|
1925
|
+
if (!info) {
|
|
1926
|
+
drift.push({
|
|
1927
|
+
type: "asset-missing",
|
|
1928
|
+
severity: "error",
|
|
1929
|
+
assetId: ref.id,
|
|
1930
|
+
role: ref.role,
|
|
1931
|
+
message: `Asset "${ref.id}" (${ref.role}) is no longer available.`
|
|
1932
|
+
});
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
const recordedHash = recordedById.get(refKey(ref))?.contentHash ?? ref.contentHash;
|
|
1936
|
+
if (recordedHash !== void 0 && info.contentHash !== void 0 && recordedHash !== info.contentHash) {
|
|
1937
|
+
drift.push({
|
|
1938
|
+
type: "asset-changed",
|
|
1939
|
+
severity: "warning",
|
|
1940
|
+
assetId: ref.id,
|
|
1941
|
+
role: ref.role,
|
|
1942
|
+
from: recordedHash,
|
|
1943
|
+
to: info.contentHash,
|
|
1944
|
+
applied: true,
|
|
1945
|
+
message: `Asset "${ref.id}" (${ref.role}) has changed since this generation.`
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
const next = { ...ref };
|
|
1949
|
+
if (info.contentHash !== void 0) next.contentHash = info.contentHash;
|
|
1950
|
+
if (next.mediaType === void 0 && info.mediaType !== void 0) next.mediaType = info.mediaType;
|
|
1951
|
+
kept.push(next);
|
|
1952
|
+
}
|
|
1953
|
+
if (kept.length) base.references = kept;
|
|
1954
|
+
else delete base.references;
|
|
1955
|
+
}
|
|
1956
|
+
let plan;
|
|
1957
|
+
let request = base;
|
|
1958
|
+
if (given && !caps) {
|
|
1959
|
+
drift.push({
|
|
1960
|
+
type: "model-missing",
|
|
1961
|
+
severity: "error",
|
|
1962
|
+
modelId: provenance.modelId,
|
|
1963
|
+
message: `Model "${provenance.modelId}" is no longer available.`
|
|
1964
|
+
});
|
|
1965
|
+
} else if (caps) {
|
|
1966
|
+
const capabilityHash = hashCapabilities(caps);
|
|
1967
|
+
if (record.capabilityHash !== void 0 && record.capabilityHash !== capabilityHash) {
|
|
1968
|
+
drift.push({
|
|
1969
|
+
type: "model-changed",
|
|
1970
|
+
severity: "warning",
|
|
1971
|
+
modelId: caps.id,
|
|
1972
|
+
from: record.capabilityHash,
|
|
1973
|
+
to: capabilityHash,
|
|
1974
|
+
message: `The capabilities of "${caps.name ?? caps.id}" changed since this generation.`
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
plan = planGenerationRequest(base, caps, {
|
|
1978
|
+
strategy: options.strategy ?? record.strategy,
|
|
1979
|
+
resolvedPrompt: resolved.text
|
|
1980
|
+
});
|
|
1981
|
+
request = plan.request;
|
|
1982
|
+
const severity = mode === "exact" && !overrides ? "warning" : "info";
|
|
1983
|
+
const type = mode === "exact" && !overrides ? "setting-unsupported" : "setting-changed";
|
|
1984
|
+
const describeChange = (field, from, to) => {
|
|
1985
|
+
const adjustment = plan.adjustments.find((a) => a.field === field || a.field.startsWith(`${field}.`));
|
|
1986
|
+
drift.push({
|
|
1987
|
+
type,
|
|
1988
|
+
severity,
|
|
1989
|
+
field,
|
|
1990
|
+
from,
|
|
1991
|
+
to,
|
|
1992
|
+
applied: true,
|
|
1993
|
+
message: type === "setting-unsupported" ? `${field} ${show(from)} is no longer supported; using ${show(to)}.${adjustment ? ` ${adjustment.reason}` : ""}` : `${field} was ${show(from)}, now ${show(to)}.${adjustment ? ` ${adjustment.reason}` : ""}`
|
|
1994
|
+
});
|
|
1995
|
+
};
|
|
1996
|
+
if (!overrides) {
|
|
1997
|
+
for (const field of GENERATION_REQUEST_FIELDS) {
|
|
1998
|
+
if (SKIPPED_SETTING_FIELDS.has(field)) continue;
|
|
1999
|
+
const from = recordedPlanned[field];
|
|
2000
|
+
const to = request[field];
|
|
2001
|
+
if (!sameValue(from, to)) describeChange(field, from, to);
|
|
2002
|
+
}
|
|
2003
|
+
const paramNames = /* @__PURE__ */ new Set([...Object.keys(recordedPlanned.params ?? {}), ...Object.keys(request.params ?? {})]);
|
|
2004
|
+
for (const name of [...paramNames].sort()) {
|
|
2005
|
+
const from = recordedPlanned.params?.[name];
|
|
2006
|
+
const to = request.params?.[name];
|
|
2007
|
+
if (!sameValue(from, to)) describeChange(`params.${name}`, from, to);
|
|
2008
|
+
}
|
|
2009
|
+
if (!sameValue(record.seed ?? recordedPlanned.seed, request.seed)) describeChange("seed", record.seed ?? recordedPlanned.seed, request.seed);
|
|
2010
|
+
const missing = new Set(drift.filter((d) => d.type === "asset-missing").map((d) => `${d.role}:${d.assetId}`));
|
|
2011
|
+
const fromRefs = (recordedPlanned.references ?? []).map(refKey).filter((key) => !missing.has(key));
|
|
2012
|
+
const toRefs = (request.references ?? []).map(refKey);
|
|
2013
|
+
if (!sameValue(fromRefs, toRefs)) describeChange("references", fromRefs, toRefs);
|
|
2014
|
+
}
|
|
2015
|
+
for (const error of plan.errors) {
|
|
2016
|
+
drift.push({
|
|
2017
|
+
type: "setting-unsupported",
|
|
2018
|
+
severity: "error",
|
|
2019
|
+
field: error.field,
|
|
2020
|
+
from: error.value,
|
|
2021
|
+
message: error.message
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
const ok = !drift.some((d) => d.severity === "error") && (plan ? plan.ok : true);
|
|
2026
|
+
const recordOptions = {
|
|
2027
|
+
rawPrompt,
|
|
2028
|
+
templates,
|
|
2029
|
+
bindings,
|
|
2030
|
+
...values ? { values } : {},
|
|
2031
|
+
model: caps ?? provenance.modelId,
|
|
2032
|
+
request,
|
|
2033
|
+
...plan ? { plan } : {},
|
|
2034
|
+
strategy: options.strategy ?? record.strategy,
|
|
2035
|
+
parentId: record.id,
|
|
2036
|
+
kind
|
|
2037
|
+
};
|
|
2038
|
+
return {
|
|
2039
|
+
mode,
|
|
2040
|
+
ok,
|
|
2041
|
+
request,
|
|
2042
|
+
...plan ? { plan } : {},
|
|
2043
|
+
rawPrompt,
|
|
2044
|
+
resolvedPrompt: resolved.text,
|
|
2045
|
+
sourceMap,
|
|
2046
|
+
values,
|
|
2047
|
+
templates,
|
|
2048
|
+
bindings,
|
|
2049
|
+
drift,
|
|
2050
|
+
parentId: record.id,
|
|
2051
|
+
kind,
|
|
2052
|
+
recordOptions
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
function recreateRequest(input, options) {
|
|
2056
|
+
if (isGenerationRecord(input)) return rebuild(input, options ?? {}, "recreate");
|
|
2057
|
+
const provenance = input;
|
|
2058
|
+
const request = clone2(provenance.request);
|
|
2059
|
+
request.model = provenance.modelId;
|
|
2060
|
+
if (request.prompt === void 0) request.prompt = provenance.resolvedPrompt;
|
|
2061
|
+
return request;
|
|
2062
|
+
}
|
|
2063
|
+
function variationRequest(record, overrides = {}, options = {}) {
|
|
2064
|
+
return rebuild(record, options, "variation", overrides);
|
|
2065
|
+
}
|
|
2066
|
+
var DRIFT_TYPE_LABELS = {
|
|
2067
|
+
"template-changed": "Template changed",
|
|
2068
|
+
"template-missing": "Template deleted",
|
|
2069
|
+
"prompt-changed": "Prompt changed",
|
|
2070
|
+
"model-missing": "Model unavailable",
|
|
2071
|
+
"model-changed": "Model changed",
|
|
2072
|
+
"setting-unsupported": "Setting unsupported",
|
|
2073
|
+
"setting-changed": "Setting changed",
|
|
2074
|
+
"asset-missing": "Asset missing",
|
|
2075
|
+
"asset-changed": "Asset changed"
|
|
2076
|
+
};
|
|
2077
|
+
function blockingDrift(drift) {
|
|
2078
|
+
return drift.filter((d) => d.severity === "error");
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// src/generation/store.ts
|
|
2082
|
+
var INDEX_VERSION = 1;
|
|
2083
|
+
var time = (value) => new Date(value).getTime();
|
|
2084
|
+
function summarizeGenerationRecord(record) {
|
|
2085
|
+
const unique = (values) => [...new Set(values)];
|
|
2086
|
+
return {
|
|
2087
|
+
id: record.id,
|
|
2088
|
+
modelId: record.provenance.modelId,
|
|
2089
|
+
kind: record.kind,
|
|
2090
|
+
...record.parentId !== void 0 ? { parentId: record.parentId } : {},
|
|
2091
|
+
createdAt: record.createdAt,
|
|
2092
|
+
templates: unique(record.templates.map((t) => t.name)),
|
|
2093
|
+
templateIds: unique(record.templates.flatMap((t) => t.templateId !== void 0 ? [t.templateId] : [])),
|
|
2094
|
+
assets: unique(record.assets.map((a) => a.id)),
|
|
2095
|
+
roles: unique(record.assets.map((a) => a.role)),
|
|
2096
|
+
preview: record.provenance.resolvedPrompt.slice(0, 160)
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function matchesRecordFilter(summary, filter = {}) {
|
|
2100
|
+
if (filter.model !== void 0) {
|
|
2101
|
+
const models = typeof filter.model === "string" ? [filter.model] : filter.model;
|
|
2102
|
+
if (!models.includes(summary.modelId)) return false;
|
|
2103
|
+
}
|
|
2104
|
+
if (filter.template !== void 0 && !summary.templates.includes(filter.template) && !summary.templateIds.includes(filter.template)) {
|
|
2105
|
+
return false;
|
|
2106
|
+
}
|
|
2107
|
+
if (filter.asset !== void 0 && !summary.assets.includes(filter.asset)) return false;
|
|
2108
|
+
if (filter.role !== void 0 && !summary.roles.includes(filter.role)) return false;
|
|
2109
|
+
if (filter.kind !== void 0 && summary.kind !== filter.kind) return false;
|
|
2110
|
+
if (filter.parentId !== void 0 && summary.parentId !== filter.parentId) return false;
|
|
2111
|
+
const created = time(summary.createdAt);
|
|
2112
|
+
if (filter.since !== void 0 && created < time(filter.since)) return false;
|
|
2113
|
+
if (filter.until !== void 0 && created >= time(filter.until)) return false;
|
|
2114
|
+
if (filter.text !== void 0 && !summary.preview.toLowerCase().includes(filter.text.toLowerCase())) return false;
|
|
2115
|
+
return true;
|
|
2116
|
+
}
|
|
2117
|
+
var newestFirst = (a, b) => time(b.createdAt) - time(a.createdAt) || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
|
|
2118
|
+
function createGenerationRecordStore(options) {
|
|
2119
|
+
const storage = options.storage;
|
|
2120
|
+
const ns = options.namespace ?? "pixerate.generation-records";
|
|
2121
|
+
const indexKey = `${ns}:index`;
|
|
2122
|
+
const recordKey = (id) => `${ns}:record:${id}`;
|
|
2123
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2124
|
+
let index = null;
|
|
2125
|
+
let queue = Promise.resolve();
|
|
2126
|
+
const run = (task) => {
|
|
2127
|
+
const result = queue.then(task, task);
|
|
2128
|
+
queue = result.catch(() => void 0);
|
|
2129
|
+
return result;
|
|
2130
|
+
};
|
|
2131
|
+
const notify = () => listeners.forEach((listener) => listener());
|
|
2132
|
+
const loadIndex = async () => {
|
|
2133
|
+
if (index) return index;
|
|
2134
|
+
const raw = await storage.get(indexKey);
|
|
2135
|
+
let items = [];
|
|
2136
|
+
if (raw) {
|
|
2137
|
+
try {
|
|
2138
|
+
const data = JSON.parse(raw);
|
|
2139
|
+
if (data && Array.isArray(data.items)) {
|
|
2140
|
+
items = data.items.filter((item) => item && typeof item.id === "string" && typeof item.createdAt === "string");
|
|
2141
|
+
}
|
|
2142
|
+
} catch {
|
|
2143
|
+
items = [];
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
index = items;
|
|
2147
|
+
return index;
|
|
2148
|
+
};
|
|
2149
|
+
const saveIndex = async (items) => {
|
|
2150
|
+
await storage.set(indexKey, JSON.stringify({ version: INDEX_VERSION, items }));
|
|
2151
|
+
index = items;
|
|
2152
|
+
};
|
|
2153
|
+
const select = (items, filter = {}) => {
|
|
2154
|
+
const matched = items.filter((s) => matchesRecordFilter(s, filter)).sort(newestFirst);
|
|
2155
|
+
const offset = Math.max(0, filter.offset ?? 0);
|
|
2156
|
+
return matched.slice(offset, filter.limit !== void 0 ? offset + Math.max(0, filter.limit) : void 0);
|
|
2157
|
+
};
|
|
2158
|
+
const pruneLocked = async (prune) => {
|
|
2159
|
+
const items = [...await loadIndex()].sort(newestFirst);
|
|
2160
|
+
const removed = [];
|
|
2161
|
+
const kept = [];
|
|
2162
|
+
let candidates = 0;
|
|
2163
|
+
const cutoff = prune.olderThan !== void 0 ? time(prune.olderThan) : void 0;
|
|
2164
|
+
for (const item of items) {
|
|
2165
|
+
if (prune.keep?.(item)) {
|
|
2166
|
+
kept.push(item);
|
|
2167
|
+
candidates++;
|
|
2168
|
+
continue;
|
|
2169
|
+
}
|
|
2170
|
+
const tooOld = cutoff !== void 0 && time(item.createdAt) < cutoff;
|
|
2171
|
+
const overLimit = prune.maxRecords !== void 0 && candidates >= Math.max(0, prune.maxRecords);
|
|
2172
|
+
if (tooOld || overLimit) removed.push(item);
|
|
2173
|
+
else {
|
|
2174
|
+
kept.push(item);
|
|
2175
|
+
candidates++;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
if (removed.length === 0) return [];
|
|
2179
|
+
await saveIndex(kept);
|
|
2180
|
+
for (const item of removed) await storage.remove(recordKey(item.id));
|
|
2181
|
+
return removed.map((item) => item.id);
|
|
2182
|
+
};
|
|
2183
|
+
return {
|
|
2184
|
+
put: (record) => run(async () => {
|
|
2185
|
+
const serialized = serializeGenerationRecord(record);
|
|
2186
|
+
await storage.set(recordKey(record.id), serialized);
|
|
2187
|
+
const items = (await loadIndex()).filter((item) => item.id !== record.id);
|
|
2188
|
+
items.push(summarizeGenerationRecord(record));
|
|
2189
|
+
await saveIndex(items);
|
|
2190
|
+
if (options.maxRecords !== void 0) await pruneLocked({ maxRecords: options.maxRecords });
|
|
2191
|
+
notify();
|
|
2192
|
+
}),
|
|
2193
|
+
get: (id) => run(async () => {
|
|
2194
|
+
const raw = await storage.get(recordKey(id));
|
|
2195
|
+
if (!raw) return null;
|
|
2196
|
+
try {
|
|
2197
|
+
return parseGenerationRecord(raw);
|
|
2198
|
+
} catch {
|
|
2199
|
+
return null;
|
|
2200
|
+
}
|
|
2201
|
+
}),
|
|
2202
|
+
summaries: (filter) => run(async () => select(await loadIndex(), filter)),
|
|
2203
|
+
list: (filter) => run(async () => {
|
|
2204
|
+
const records = [];
|
|
2205
|
+
for (const summary of select(await loadIndex(), filter)) {
|
|
2206
|
+
const raw = await storage.get(recordKey(summary.id));
|
|
2207
|
+
if (!raw) continue;
|
|
2208
|
+
try {
|
|
2209
|
+
records.push(parseGenerationRecord(raw));
|
|
2210
|
+
} catch {
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
return records;
|
|
2214
|
+
}),
|
|
2215
|
+
remove: (id) => run(async () => {
|
|
2216
|
+
const items = await loadIndex();
|
|
2217
|
+
const next = items.filter((item) => item.id !== id);
|
|
2218
|
+
if (next.length === items.length) return false;
|
|
2219
|
+
await saveIndex(next);
|
|
2220
|
+
await storage.remove(recordKey(id));
|
|
2221
|
+
notify();
|
|
2222
|
+
return true;
|
|
2223
|
+
}),
|
|
2224
|
+
prune: (prune) => run(async () => {
|
|
2225
|
+
const removed = await pruneLocked(prune);
|
|
2226
|
+
if (removed.length) notify();
|
|
2227
|
+
return removed;
|
|
2228
|
+
}),
|
|
2229
|
+
clear: () => run(async () => {
|
|
2230
|
+
const items = await loadIndex();
|
|
2231
|
+
await saveIndex([]);
|
|
2232
|
+
for (const item of items) await storage.remove(recordKey(item.id));
|
|
2233
|
+
notify();
|
|
2234
|
+
}),
|
|
2235
|
+
subscribe(listener) {
|
|
2236
|
+
listeners.add(listener);
|
|
2237
|
+
return () => {
|
|
2238
|
+
listeners.delete(listener);
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
1332
2243
|
export {
|
|
2244
|
+
DRIFT_TYPE_LABELS,
|
|
2245
|
+
GENERATION_RECORD_FORMAT,
|
|
2246
|
+
GENERATION_RECORD_VERSION,
|
|
1333
2247
|
GENERATION_REQUEST_FIELDS,
|
|
1334
2248
|
MAX_PENDING_PERCENT,
|
|
1335
2249
|
PROVENANCE_FORMAT,
|
|
@@ -1337,37 +2251,67 @@ export {
|
|
|
1337
2251
|
ProvenanceParseError,
|
|
1338
2252
|
QUALITY_LADDER,
|
|
1339
2253
|
REFERENCE_ROLES,
|
|
2254
|
+
REFERENCE_ROLE_ALIASES,
|
|
1340
2255
|
REFERENCE_ROLE_LABELS,
|
|
2256
|
+
REFERENCE_ROLE_NAME_REGEX,
|
|
1341
2257
|
addReference,
|
|
1342
2258
|
aspectRatioRank,
|
|
2259
|
+
blockingDrift,
|
|
1343
2260
|
capabilitiesToJsonSchema,
|
|
2261
|
+
completeGenerationRecord,
|
|
1344
2262
|
createBatchResolver,
|
|
2263
|
+
createGenerationRecord,
|
|
2264
|
+
createGenerationRecordId,
|
|
2265
|
+
createGenerationRecordStore,
|
|
1345
2266
|
createGenerationToolProvider,
|
|
1346
2267
|
createProvenance,
|
|
2268
|
+
defaultAssetRoleOptions,
|
|
2269
|
+
describeAssetMentions,
|
|
1347
2270
|
estimateJobProgress,
|
|
1348
2271
|
expectedDurationFor,
|
|
2272
|
+
findTextMentions,
|
|
2273
|
+
formatMentionText,
|
|
1349
2274
|
formatRemaining,
|
|
2275
|
+
getAssetRoleOptions,
|
|
1350
2276
|
getGenerationControls,
|
|
1351
2277
|
getReferenceSlots,
|
|
1352
2278
|
getRequestValue,
|
|
2279
|
+
hashCapabilities,
|
|
2280
|
+
hashText,
|
|
2281
|
+
hashValue,
|
|
2282
|
+
isGenerationRecord,
|
|
2283
|
+
isReferenceRoleName,
|
|
2284
|
+
matchesRecordFilter,
|
|
2285
|
+
mediaTypeMatches,
|
|
1353
2286
|
mergeCapabilities,
|
|
2287
|
+
normalizeReferenceRole,
|
|
1354
2288
|
parseControlValue,
|
|
2289
|
+
parseGenerationRecord,
|
|
1355
2290
|
parseProvenance,
|
|
1356
2291
|
pinnedTemplatesToTemplates,
|
|
1357
2292
|
planGenerationRequest,
|
|
1358
2293
|
qualityRank,
|
|
1359
2294
|
recreateRequest,
|
|
2295
|
+
referenceRoleLabel,
|
|
1360
2296
|
removeReference,
|
|
1361
2297
|
replayProvenancePrompt,
|
|
1362
2298
|
resolutionMegapixels,
|
|
1363
2299
|
resolutionRank,
|
|
2300
|
+
resolveAssetMentions,
|
|
1364
2301
|
seedCapability,
|
|
2302
|
+
serializeGenerationRecord,
|
|
1365
2303
|
serializeProvenance,
|
|
2304
|
+
setMentionRoleInText,
|
|
1366
2305
|
setRequestValue,
|
|
1367
2306
|
snapToOption,
|
|
2307
|
+
stableStringify,
|
|
2308
|
+
summarizeGenerationRecord,
|
|
1368
2309
|
supportedModes,
|
|
1369
2310
|
supportedReferenceRoles,
|
|
1370
2311
|
textFieldCapability,
|
|
1371
|
-
|
|
2312
|
+
toAssetResolver,
|
|
2313
|
+
validateAssetMentions,
|
|
2314
|
+
validateJsonSchema,
|
|
2315
|
+
variationRequest
|
|
1372
2316
|
};
|
|
1373
2317
|
//# sourceMappingURL=index.js.map
|