@pixerate/editor 0.23.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 +167 -2
- package/THIRD_PARTY_NOTICES.md +80 -0
- package/dist/agent/index.cjs +10 -8
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +4 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +4437 -411
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +934 -4
- package/dist/canvas/index.d.ts +934 -4
- package/dist/canvas/index.js +4309 -283
- 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-664LQYFJ.js +115 -0
- package/dist/chunk-664LQYFJ.js.map +1 -0
- package/dist/chunk-7WISYZFO.cjs +740 -0
- package/dist/chunk-7WISYZFO.cjs.map +1 -0
- package/dist/chunk-AL6JMGWW.cjs +783 -0
- 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-RIKBJLS2.cjs → chunk-C7P22VIP.cjs} +2001 -279
- package/dist/chunk-C7P22VIP.cjs.map +1 -0
- package/dist/chunk-D6FH2YAX.cjs +131 -0
- package/dist/chunk-D6FH2YAX.cjs.map +1 -0
- package/dist/chunk-ECCCYKGL.js +740 -0
- package/dist/chunk-ECCCYKGL.js.map +1 -0
- package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
- package/dist/chunk-FD4LPFAE.cjs.map +1 -0
- package/dist/{chunk-QBJ22YZR.js → chunk-FH6F67DN.js} +1999 -277
- package/dist/chunk-FH6F67DN.js.map +1 -0
- package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
- package/dist/chunk-FPENXAEJ.js.map +1 -0
- package/dist/chunk-HLIMTC6N.js +1 -0
- package/dist/chunk-HLIMTC6N.js.map +1 -0
- package/dist/chunk-HRMEDT2L.js +1406 -0
- package/dist/chunk-HRMEDT2L.js.map +1 -0
- package/dist/{chunk-QGHGJ56O.js → chunk-IXHSYOVY.js} +2518 -122
- package/dist/chunk-IXHSYOVY.js.map +1 -0
- package/dist/chunk-MKA3AHLV.cjs +256 -0
- package/dist/chunk-MKA3AHLV.cjs.map +1 -0
- package/dist/chunk-NAXVVS5I.js +783 -0
- 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-OXSV64JX.js +689 -0
- package/dist/chunk-OXSV64JX.js.map +1 -0
- package/dist/chunk-P3RQ5UJE.cjs +689 -0
- package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
- package/dist/chunk-P6ODPZ4W.js +256 -0
- package/dist/chunk-P6ODPZ4W.js.map +1 -0
- package/dist/chunk-PL4JB3BF.cjs +1 -0
- package/dist/chunk-PL4JB3BF.cjs.map +1 -0
- package/dist/{chunk-GVSMRPHB.cjs → chunk-PO6A6QQH.cjs} +2607 -211
- package/dist/chunk-PO6A6QQH.cjs.map +1 -0
- package/dist/{chunk-JJDLPEWL.js → chunk-QGYDWPRM.js} +2 -2
- package/dist/chunk-RR7F5GUM.js +5726 -0
- package/dist/chunk-RR7F5GUM.js.map +1 -0
- package/dist/chunk-TNNJXF46.cjs +115 -0
- package/dist/chunk-TNNJXF46.cjs.map +1 -0
- package/dist/chunk-U5HZSFCS.js +131 -0
- package/dist/chunk-U5HZSFCS.js.map +1 -0
- package/dist/{chunk-MJZBNWG7.js → chunk-UAKDG62Z.js} +309 -581
- package/dist/chunk-UAKDG62Z.js.map +1 -0
- package/dist/{chunk-CL37JGFW.cjs → chunk-V3CHHWOE.cjs} +4 -4
- package/dist/{chunk-CL37JGFW.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-AA4ZEVCC.cjs → chunk-X4N4WUKB.cjs} +336 -608
- 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 +38 -353
- package/dist/commands/index.d.ts +38 -353
- package/dist/commands/index.js +73 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/comment-store-BEMgVlAA.d.cts +135 -0
- package/dist/comment-store-BEMgVlAA.d.ts +135 -0
- package/dist/compare/index.cjs +15 -0
- package/dist/compare/index.cjs.map +1 -0
- package/dist/compare/index.d.cts +58 -0
- package/dist/compare/index.d.ts +58 -0
- package/dist/compare/index.js +15 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/controller-BIJiNoVs.d.cts +1842 -0
- package/dist/controller-BIJiNoVs.d.ts +1842 -0
- package/dist/documents-CHT1U5Vs.d.ts +86 -0
- package/dist/documents-Gp7wb0Me.d.cts +86 -0
- package/dist/extensions/index.cjs +100 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +16 -4
- package/dist/extensions/index.d.ts +16 -4
- package/dist/extensions/index.js +100 -5
- package/dist/generation/index.cjs +2317 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +1015 -0
- package/dist/generation/index.d.ts +1015 -0
- package/dist/generation/index.js +2317 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/grammar/index.cjs +48 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +322 -100
- package/dist/grammar/index.d.ts +322 -100
- package/dist/grammar/index.js +54 -9
- package/dist/image-editor/index.cjs +4392 -481
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +1249 -97
- package/dist/image-editor/index.d.ts +1249 -97
- package/dist/image-editor/index.js +4281 -370
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index-7a6bHTLy.d.ts +1754 -0
- package/dist/index-Csd5qI8u.d.cts +1754 -0
- package/dist/index.cjs +1682 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -21
- package/dist/index.d.ts +118 -21
- package/dist/index.js +1630 -47
- 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/migrate-iTlm3a8h.d.cts +112 -0
- package/dist/migrate-iTlm3a8h.d.ts +112 -0
- package/dist/model-C1zApQM8.d.cts +219 -0
- package/dist/model-C1zApQM8.d.ts +219 -0
- package/dist/persistence/index.cjs +676 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +230 -0
- package/dist/persistence/index.d.ts +230 -0
- package/dist/persistence/index.js +676 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
- package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.cts} +12 -1
- package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.ts} +12 -1
- package/dist/registry-D32LpIc4.d.cts +354 -0
- package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
- package/dist/registry-evKTP4ls.d.ts +354 -0
- package/dist/schema-DYDGdYL9.d.cts +41 -0
- package/dist/schema-DYDGdYL9.d.ts +41 -0
- package/dist/serializers/index.cjs +12 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +40 -12
- package/dist/serializers/index.d.ts +40 -12
- package/dist/serializers/index.js +12 -3
- package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
- package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
- package/dist/spreadsheet/index.cjs +161 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +611 -20
- package/dist/spreadsheet/index.d.ts +611 -20
- package/dist/spreadsheet/index.js +168 -10
- 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/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
- package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
- package/dist/{track-changes-BSF58RK0.d.cts → track-changes-D_VAPELi.d.cts} +110 -144
- package/dist/{track-changes-BSF58RK0.d.ts → track-changes-Db_fGEvx.d.ts} +110 -144
- package/package.json +21 -1
- package/dist/chunk-4SUNJZWB.cjs.map +0 -1
- package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
- package/dist/chunk-AXV2ZW34.cjs +0 -118
- package/dist/chunk-AXV2ZW34.cjs.map +0 -1
- package/dist/chunk-B2ZRLN4S.js +0 -118
- package/dist/chunk-B2ZRLN4S.js.map +0 -1
- package/dist/chunk-GVSMRPHB.cjs.map +0 -1
- package/dist/chunk-K3R5NG2D.js +0 -3100
- package/dist/chunk-K3R5NG2D.js.map +0 -1
- package/dist/chunk-MJZBNWG7.js.map +0 -1
- package/dist/chunk-OYXSKQFR.js.map +0 -1
- package/dist/chunk-QBJ22YZR.js.map +0 -1
- package/dist/chunk-QGHGJ56O.js.map +0 -1
- package/dist/chunk-RIKBJLS2.cjs.map +0 -1
- package/dist/chunk-XDMXXC4Z.cjs +0 -3100
- package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
- package/dist/controller-pePCJLT1.d.cts +0 -959
- package/dist/controller-pePCJLT1.d.ts +0 -959
- package/dist/index-CCr_z9kF.d.cts +0 -899
- package/dist/index-Ck6ajwXh.d.ts +0 -899
- /package/dist/{chunk-JJDLPEWL.js.map → chunk-QGYDWPRM.js.map} +0 -0
|
@@ -0,0 +1,2317 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
var _chunkFD4LPFAEcjs = require('../chunk-FD4LPFAE.cjs');
|
|
7
|
+
require('../chunk-MKA3AHLV.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
var _chunkCPOKFNBGcjs = require('../chunk-CPOKFNBG.cjs');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
var _chunkBVP3TSLHcjs = require('../chunk-BVP3TSLH.cjs');
|
|
16
|
+
|
|
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
|
+
}
|
|
22
|
+
var REFERENCE_ROLES = [
|
|
23
|
+
"start_frame",
|
|
24
|
+
"end_frame",
|
|
25
|
+
"style_ref",
|
|
26
|
+
"character_ref",
|
|
27
|
+
"background_ref",
|
|
28
|
+
"mask",
|
|
29
|
+
"image_ref",
|
|
30
|
+
"video_ref",
|
|
31
|
+
"audio_ref"
|
|
32
|
+
];
|
|
33
|
+
var REFERENCE_ROLE_LABELS = {
|
|
34
|
+
start_frame: "Start frame",
|
|
35
|
+
end_frame: "End frame",
|
|
36
|
+
style_ref: "Style reference",
|
|
37
|
+
character_ref: "Character reference",
|
|
38
|
+
background_ref: "Background reference",
|
|
39
|
+
mask: "Mask",
|
|
40
|
+
image_ref: "Image reference",
|
|
41
|
+
video_ref: "Video reference",
|
|
42
|
+
audio_ref: "Audio reference"
|
|
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 = _optionalChain([caps, 'optionalAccess', _ => _.references, 'optionalAccess', _2 => _2.roles, 'access', _3 => _3[role], 'optionalAccess', _4 => _4.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 ? !!_optionalChain([caps, 'access', _5 => _5.references, 'optionalAccess', _6 => _6.roles, 'access', _7 => _7[name]]) : isBuiltinRole(name)) return name;
|
|
76
|
+
const lower = name.toLowerCase();
|
|
77
|
+
if (_optionalChain([caps, 'optionalAccess', _8 => _8.references, 'optionalAccess', _9 => _9.roles, 'access', _10 => _10[lower]])) return lower;
|
|
78
|
+
if (!caps && isBuiltinRole(lower)) return lower;
|
|
79
|
+
return _nullishCoalesce(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
|
+
}
|
|
94
|
+
var GENERATION_REQUEST_FIELDS = [
|
|
95
|
+
"model",
|
|
96
|
+
"prompt",
|
|
97
|
+
"negativePrompt",
|
|
98
|
+
"systemPrompt",
|
|
99
|
+
"aspectRatio",
|
|
100
|
+
"resolution",
|
|
101
|
+
"quality",
|
|
102
|
+
"count",
|
|
103
|
+
"duration",
|
|
104
|
+
"seed",
|
|
105
|
+
"mode",
|
|
106
|
+
"references",
|
|
107
|
+
"params"
|
|
108
|
+
];
|
|
109
|
+
function textFieldCapability(value) {
|
|
110
|
+
if (!value) return null;
|
|
111
|
+
return value === true ? {} : value;
|
|
112
|
+
}
|
|
113
|
+
function seedCapability(value) {
|
|
114
|
+
if (!value) return null;
|
|
115
|
+
return value === true ? {} : value;
|
|
116
|
+
}
|
|
117
|
+
function supportedReferenceRoles(caps) {
|
|
118
|
+
const roles = _nullishCoalesce(_optionalChain([caps, 'access', _11 => _11.references, 'optionalAccess', _12 => _12.roles]), () => ( {}));
|
|
119
|
+
const builtin = REFERENCE_ROLES.filter((role) => (_nullishCoalesce(_optionalChain([roles, 'access', _13 => _13[role], 'optionalAccess', _14 => _14.max]), () => ( 0))) > 0);
|
|
120
|
+
const custom = Object.keys(roles).filter(
|
|
121
|
+
(role) => !isBuiltinRole(role) && isReferenceRoleName(role) && (_nullishCoalesce(_optionalChain([roles, 'access', _15 => _15[role], 'optionalAccess', _16 => _16.max]), () => ( 0))) > 0
|
|
122
|
+
);
|
|
123
|
+
return [...builtin, ...custom];
|
|
124
|
+
}
|
|
125
|
+
function supportedModes(caps) {
|
|
126
|
+
const modes = ["generate"];
|
|
127
|
+
if (caps.editing) modes.push("edit");
|
|
128
|
+
if (caps.inpainting) modes.push("inpaint");
|
|
129
|
+
return modes;
|
|
130
|
+
}
|
|
131
|
+
var PRESENTATION_KEYS = ["name", "description", "badges", "icon", "group"];
|
|
132
|
+
function mergeCapabilities(remote, overlay = []) {
|
|
133
|
+
const overlayById = new Map(overlay.map((entry) => [entry.id, entry]));
|
|
134
|
+
const remoteIds = new Set(remote.map((model) => model.id));
|
|
135
|
+
const merged = remote.map((model) => {
|
|
136
|
+
const extra = overlayById.get(model.id);
|
|
137
|
+
if (!extra) return { ...model };
|
|
138
|
+
const next = { ...model };
|
|
139
|
+
for (const key of PRESENTATION_KEYS) {
|
|
140
|
+
if (extra[key] !== void 0) next[key] = extra[key];
|
|
141
|
+
}
|
|
142
|
+
return next;
|
|
143
|
+
});
|
|
144
|
+
for (const entry of overlay) {
|
|
145
|
+
if (remoteIds.has(entry.id) || !entry.media) continue;
|
|
146
|
+
remoteIds.add(entry.id);
|
|
147
|
+
merged.push({ ...entry });
|
|
148
|
+
}
|
|
149
|
+
return merged;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/generation/plan.ts
|
|
153
|
+
var EPSILON = 1e-9;
|
|
154
|
+
function aspectRatioRank(value) {
|
|
155
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*[:x/×]\s*(\d+(?:\.\d+)?)\s*$/i.exec(String(value));
|
|
156
|
+
if (!match) return void 0;
|
|
157
|
+
const w = Number(match[1]);
|
|
158
|
+
const h = Number(match[2]);
|
|
159
|
+
if (!(w > 0) || !(h > 0)) return void 0;
|
|
160
|
+
return Math.log(w / h);
|
|
161
|
+
}
|
|
162
|
+
function resolutionRank(value) {
|
|
163
|
+
const text = String(value).trim().toLowerCase();
|
|
164
|
+
let pixels;
|
|
165
|
+
let match = /^(\d+(?:\.\d+)?)\s*[x×*]\s*(\d+(?:\.\d+)?)$/.exec(text);
|
|
166
|
+
if (match) pixels = Number(match[1]) * Number(match[2]);
|
|
167
|
+
else if (match = /^(\d+(?:\.\d+)?)p$/.exec(text)) pixels = Number(match[1]) ** 2 * 16 / 9;
|
|
168
|
+
else if (match = /^(\d+(?:\.\d+)?)k$/.exec(text)) pixels = (Number(match[1]) * 1024) ** 2;
|
|
169
|
+
return pixels && pixels > 0 ? Math.log(pixels) : void 0;
|
|
170
|
+
}
|
|
171
|
+
function resolutionMegapixels(value) {
|
|
172
|
+
const rank = resolutionRank(value);
|
|
173
|
+
return rank === void 0 ? void 0 : Math.exp(rank) / 1e6;
|
|
174
|
+
}
|
|
175
|
+
var QUALITY_LADDER = {
|
|
176
|
+
draft: 0,
|
|
177
|
+
preview: 0,
|
|
178
|
+
low: 1,
|
|
179
|
+
fast: 1,
|
|
180
|
+
turbo: 1,
|
|
181
|
+
standard: 2,
|
|
182
|
+
normal: 2,
|
|
183
|
+
medium: 2,
|
|
184
|
+
balanced: 2,
|
|
185
|
+
high: 3,
|
|
186
|
+
hd: 3,
|
|
187
|
+
quality: 3,
|
|
188
|
+
ultra: 4,
|
|
189
|
+
max: 5,
|
|
190
|
+
best: 5
|
|
191
|
+
};
|
|
192
|
+
function qualityRank(value) {
|
|
193
|
+
return QUALITY_LADDER[String(value).trim().toLowerCase()];
|
|
194
|
+
}
|
|
195
|
+
var numberRank = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
196
|
+
function snapToOption(value, options, rank, tie) {
|
|
197
|
+
const target = rank(value);
|
|
198
|
+
if (target === void 0) return void 0;
|
|
199
|
+
let best;
|
|
200
|
+
for (const option of options) {
|
|
201
|
+
const r = rank(option);
|
|
202
|
+
if (r === void 0) continue;
|
|
203
|
+
const distance = Math.abs(r - target);
|
|
204
|
+
if (!best || distance < best.distance - EPSILON || Math.abs(distance - best.distance) <= EPSILON && (tie === "lower" ? r < best.rank : r > best.rank)) {
|
|
205
|
+
best = { option, distance, rank: r };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return _optionalChain([best, 'optionalAccess', _17 => _17.option]);
|
|
209
|
+
}
|
|
210
|
+
function truncateText(text, max) {
|
|
211
|
+
if (text.length <= max) return text;
|
|
212
|
+
let end = max;
|
|
213
|
+
const code = text.charCodeAt(end - 1);
|
|
214
|
+
if (end > 0 && code >= 55296 && code <= 56319) end -= 1;
|
|
215
|
+
return text.slice(0, end);
|
|
216
|
+
}
|
|
217
|
+
function cloneRequest(request) {
|
|
218
|
+
const copy = { ...request };
|
|
219
|
+
if (request.references) copy.references = request.references.map((ref) => ({ ...ref }));
|
|
220
|
+
if (request.params) copy.params = { ...request.params };
|
|
221
|
+
return copy;
|
|
222
|
+
}
|
|
223
|
+
var describe = (value) => typeof value === "string" ? `"${value}"` : JSON.stringify(value);
|
|
224
|
+
var list = (options) => options.map(describe).join(", ");
|
|
225
|
+
var Planner = (_class = class {
|
|
226
|
+
constructor(caps, request, options, strategy) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
|
|
227
|
+
this.caps = caps;
|
|
228
|
+
this.request = request;
|
|
229
|
+
this.options = options;
|
|
230
|
+
this.strategy = strategy;
|
|
231
|
+
this.tie = strategy === "downgrade" ? "lower" : "higher";
|
|
232
|
+
this.strict = strategy === "error";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
__init() {this.adjustments = []}
|
|
239
|
+
__init2() {this.errors = []}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
adjust(field, from, to, kind, reason) {
|
|
243
|
+
this.adjustments.push({ field, from, to, kind, reason });
|
|
244
|
+
}
|
|
245
|
+
error(field, value, message) {
|
|
246
|
+
this.errors.push({ field, value, message });
|
|
247
|
+
}
|
|
248
|
+
/** Removes an unsupported field (or reports it under `error`). */
|
|
249
|
+
unsupported(field, message) {
|
|
250
|
+
const value = this.request[field];
|
|
251
|
+
if (this.strict) {
|
|
252
|
+
this.error(field, value, message);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
delete this.request[field];
|
|
256
|
+
this.adjust(field, value, void 0, "dropped", message);
|
|
257
|
+
}
|
|
258
|
+
defaulted(field, value, set) {
|
|
259
|
+
if (!this.options.fillDefaults || value === void 0) return;
|
|
260
|
+
set();
|
|
261
|
+
this.adjust(field, void 0, value, "defaulted", "Filled with the model default.");
|
|
262
|
+
}
|
|
263
|
+
planText(field, maxLength, measured) {
|
|
264
|
+
const value = this.request[field];
|
|
265
|
+
if (value === void 0 || maxLength === void 0) return;
|
|
266
|
+
if (typeof value !== "string") {
|
|
267
|
+
this.error(field, value, `Expected text.`);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const text = _nullishCoalesce(measured, () => ( value));
|
|
271
|
+
if (text.length <= maxLength) return;
|
|
272
|
+
if (this.strict || measured !== void 0) {
|
|
273
|
+
this.error(
|
|
274
|
+
field,
|
|
275
|
+
text.length,
|
|
276
|
+
`${measured !== void 0 ? "Resolved text" : "Text"} is ${text.length} characters; the model accepts at most ${maxLength}.`
|
|
277
|
+
);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const next = truncateText(value, maxLength);
|
|
281
|
+
this.request[field] = next;
|
|
282
|
+
this.adjust(field, value.length, next.length, "truncated", `Truncated to the model's ${maxLength}-character limit.`);
|
|
283
|
+
}
|
|
284
|
+
planEnum(field, cap, rank, label) {
|
|
285
|
+
const value = this.request[field];
|
|
286
|
+
if (value === void 0) {
|
|
287
|
+
if (cap) this.defaulted(field, cap.default, () => this.request[field] = cap.default);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (!cap || cap.options.length === 0) {
|
|
291
|
+
this.unsupported(field, `The model does not take a ${label}.`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (cap.options.includes(value)) return;
|
|
295
|
+
if (this.strict) {
|
|
296
|
+
this.error(field, value, `${describe(value)} is not a supported ${label}; supported: ${list(cap.options)}.`);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const snapped = snapToOption(value, cap.options, rank, this.tie);
|
|
300
|
+
const next = _nullishCoalesce(_nullishCoalesce(snapped, () => ( cap.default)), () => ( cap.options[0]));
|
|
301
|
+
this.request[field] = next;
|
|
302
|
+
this.adjust(
|
|
303
|
+
field,
|
|
304
|
+
value,
|
|
305
|
+
next,
|
|
306
|
+
"snapped",
|
|
307
|
+
snapped !== void 0 ? `${describe(value)} is not supported; using the nearest ${label}.` : `${describe(value)} is not supported; using ${cap.default !== void 0 ? "the default" : "the first option"}.`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
/** Clamps/rounds/snaps a number. Returns the next value or `undefined` after an error. */
|
|
311
|
+
planNumber(field, value, spec, label) {
|
|
312
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
313
|
+
this.error(field, value, `Expected a number for ${label}.`);
|
|
314
|
+
return void 0;
|
|
315
|
+
}
|
|
316
|
+
const options = _optionalChain([spec, 'access', _18 => _18.options, 'optionalAccess', _19 => _19.filter, 'call', _20 => _20(
|
|
317
|
+
(o) => (spec.min === void 0 || o >= spec.min) && (spec.max === void 0 || o <= spec.max)
|
|
318
|
+
)]);
|
|
319
|
+
if (options && options.length > 0) {
|
|
320
|
+
if (options.includes(value)) return { value, changed: false };
|
|
321
|
+
if (this.strict) {
|
|
322
|
+
this.error(field, value, `${value} is not a supported ${label}; supported: ${list(options)}.`);
|
|
323
|
+
return void 0;
|
|
324
|
+
}
|
|
325
|
+
const next2 = snapToOption(value, options, numberRank, this.tie);
|
|
326
|
+
this.adjust(field, value, next2, "snapped", `${value} is not supported; using the nearest ${label}.`);
|
|
327
|
+
return { value: next2, changed: true };
|
|
328
|
+
}
|
|
329
|
+
let next = value;
|
|
330
|
+
if (spec.step !== void 0 && spec.step > 0) {
|
|
331
|
+
const base = _nullishCoalesce(spec.min, () => ( 0));
|
|
332
|
+
const steps = (next - base) / spec.step;
|
|
333
|
+
const rounded = Math.abs(steps - Math.trunc(steps) - 0.5) < EPSILON ? this.tie === "lower" ? Math.floor(steps) : Math.ceil(steps) : Math.round(steps);
|
|
334
|
+
next = Number((base + rounded * spec.step).toPrecision(12));
|
|
335
|
+
}
|
|
336
|
+
if (spec.integer && !Number.isInteger(next)) {
|
|
337
|
+
const frac = next - Math.floor(next);
|
|
338
|
+
next = Math.abs(frac - 0.5) < EPSILON ? this.tie === "lower" ? Math.floor(next) : Math.ceil(next) : Math.round(next);
|
|
339
|
+
}
|
|
340
|
+
let kind = "snapped";
|
|
341
|
+
if (spec.min !== void 0 && next < spec.min) {
|
|
342
|
+
next = spec.min;
|
|
343
|
+
kind = "clamped";
|
|
344
|
+
}
|
|
345
|
+
if (spec.max !== void 0 && next > spec.max) {
|
|
346
|
+
next = spec.max;
|
|
347
|
+
kind = "clamped";
|
|
348
|
+
}
|
|
349
|
+
if (next === value) return { value, changed: false };
|
|
350
|
+
const range = `${_nullishCoalesce(spec.min, () => ( "-\u221E"))}\u2013${_nullishCoalesce(spec.max, () => ( "\u221E"))}`;
|
|
351
|
+
if (this.strict) {
|
|
352
|
+
this.error(
|
|
353
|
+
field,
|
|
354
|
+
value,
|
|
355
|
+
kind === "clamped" ? `${label} must be within ${range}.` : `${value} is not a valid ${label} (try ${next}).`
|
|
356
|
+
);
|
|
357
|
+
return void 0;
|
|
358
|
+
}
|
|
359
|
+
this.adjust(
|
|
360
|
+
field,
|
|
361
|
+
value,
|
|
362
|
+
next,
|
|
363
|
+
kind,
|
|
364
|
+
kind === "clamped" ? `Clamped to the supported range ${range}.` : `Rounded to a supported ${label}.`
|
|
365
|
+
);
|
|
366
|
+
return { value: next, changed: true };
|
|
367
|
+
}
|
|
368
|
+
planCount() {
|
|
369
|
+
const value = this.request.count;
|
|
370
|
+
const cap = this.caps.count;
|
|
371
|
+
if (value === void 0) {
|
|
372
|
+
if (cap) this.defaulted("count", cap.default, () => this.request.count = cap.default);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (!cap) {
|
|
376
|
+
if (value === 1) return;
|
|
377
|
+
this.unsupported("count", "The model produces one output per request.");
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const result = this.planNumber("count", value, { min: 1, max: cap.max, integer: true, options: cap.options }, "output count");
|
|
381
|
+
if (result) this.request.count = result.value;
|
|
382
|
+
}
|
|
383
|
+
planDuration() {
|
|
384
|
+
const value = this.request.duration;
|
|
385
|
+
const cap = this.caps.duration;
|
|
386
|
+
if (value === void 0) {
|
|
387
|
+
if (cap) this.defaulted("duration", cap.default, () => this.request.duration = cap.default);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (!cap) {
|
|
391
|
+
this.unsupported("duration", "The model does not take a duration.");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const result = this.planNumber("duration", value, cap, "duration");
|
|
395
|
+
if (result) this.request.duration = result.value;
|
|
396
|
+
}
|
|
397
|
+
planSeed() {
|
|
398
|
+
const value = this.request.seed;
|
|
399
|
+
if (value === void 0) return;
|
|
400
|
+
const cap = seedCapability(this.caps.seed);
|
|
401
|
+
if (!cap) {
|
|
402
|
+
this.unsupported("seed", "The model does not take a seed.");
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const result = this.planNumber("seed", value, { ...cap, integer: true }, "seed");
|
|
406
|
+
if (result) this.request.seed = result.value;
|
|
407
|
+
}
|
|
408
|
+
planMode() {
|
|
409
|
+
const mode = this.request.mode;
|
|
410
|
+
if (mode === void 0) return;
|
|
411
|
+
const modes = supportedModes(this.caps);
|
|
412
|
+
if (!modes.includes(mode)) {
|
|
413
|
+
this.error("mode", mode, `The model does not support ${describe(mode)}; supported: ${list(modes)}.`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
roleCapability(role) {
|
|
417
|
+
const cap = _optionalChain([this, 'access', _21 => _21.caps, 'access', _22 => _22.references, 'optionalAccess', _23 => _23.roles, 'access', _24 => _24[role]]);
|
|
418
|
+
if (cap && cap.max > 0) return cap;
|
|
419
|
+
if (role === "mask" && this.caps.inpainting) return { max: 1 };
|
|
420
|
+
return void 0;
|
|
421
|
+
}
|
|
422
|
+
/** Turns `options.mentions` into references (appended after the request's own). */
|
|
423
|
+
addMentions() {
|
|
424
|
+
const mentions = this.options.mentions;
|
|
425
|
+
if (!_optionalChain([mentions, 'optionalAccess', _25 => _25.length])) return;
|
|
426
|
+
const refs = [..._nullishCoalesce(this.request.references, () => ( []))];
|
|
427
|
+
for (const mention of mentions) {
|
|
428
|
+
if (!mention || typeof mention.id !== "string" || mention.id === "") continue;
|
|
429
|
+
let role = _nullishCoalesce(mention.role, () => ( void 0));
|
|
430
|
+
if (!role) {
|
|
431
|
+
role = _nullishCoalesce(this.options.defaultMentionRole, () => ( this.inferRole(mention.mediaType)));
|
|
432
|
+
this.adjust(
|
|
433
|
+
`references.${role}`,
|
|
434
|
+
void 0,
|
|
435
|
+
role,
|
|
436
|
+
"defaulted",
|
|
437
|
+
`@${_nullishCoalesce(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
|
+
}
|
|
459
|
+
planReferences() {
|
|
460
|
+
const refs = this.request.references;
|
|
461
|
+
const allowDrop = !this.strict && (_nullishCoalesce(this.options.dropUnsupportedReferences, () => ( (this.strategy === "nearest" || this.strategy === "downgrade"))));
|
|
462
|
+
const byRole = /* @__PURE__ */ new Map();
|
|
463
|
+
const kept = [];
|
|
464
|
+
const unsupported = /* @__PURE__ */ new Map();
|
|
465
|
+
for (const [index, original] of (_nullishCoalesce(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`.");
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (!this.roleCapability(ref.role)) {
|
|
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, (_nullishCoalesce(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(_nullishCoalesce(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);
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
const group = _nullishCoalesce(byRole.get(ref.role), () => ( []));
|
|
499
|
+
if (group.some((other) => other.id === ref.id)) {
|
|
500
|
+
this.adjust(`references.${ref.role}`, ref.id, void 0, "dropped", `Duplicate reference "${ref.id}" removed.`);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
group.push(ref);
|
|
504
|
+
byRole.set(ref.role, group);
|
|
505
|
+
kept.push(ref);
|
|
506
|
+
}
|
|
507
|
+
for (const [role, count] of unsupported) {
|
|
508
|
+
const message = this.caps.media === "text" || !this.caps.references ? `The ${this.caps.media} model "${this.caps.id}" does not accept reference inputs (${role}).` : `The model does not accept ${role} references.`;
|
|
509
|
+
if (allowDrop) this.adjust(`references.${role}`, count, 0, "dropped", message);
|
|
510
|
+
else this.error(`references.${role}`, count, message);
|
|
511
|
+
}
|
|
512
|
+
const removed = /* @__PURE__ */ new Set();
|
|
513
|
+
const custom = supportedReferenceRoles(this.caps).filter(
|
|
514
|
+
(role) => !REFERENCE_ROLES.includes(role)
|
|
515
|
+
);
|
|
516
|
+
for (const role of [...REFERENCE_ROLES, ...custom]) {
|
|
517
|
+
const cap = this.roleCapability(role);
|
|
518
|
+
const group = _nullishCoalesce(byRole.get(role), () => ( []));
|
|
519
|
+
if (!cap) continue;
|
|
520
|
+
if (group.length > cap.max) {
|
|
521
|
+
if (this.strict) {
|
|
522
|
+
this.error(`references.${role}`, group.length, `At most ${cap.max} ${role} reference(s) are supported.`);
|
|
523
|
+
} else {
|
|
524
|
+
group.slice(cap.max).forEach((ref) => removed.add(ref));
|
|
525
|
+
this.adjust(
|
|
526
|
+
`references.${role}`,
|
|
527
|
+
group.length,
|
|
528
|
+
cap.max,
|
|
529
|
+
"truncated",
|
|
530
|
+
`Kept the first ${cap.max} ${role} reference(s); the model accepts no more.`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (cap.min !== void 0 && group.length < cap.min) {
|
|
535
|
+
this.error(`references.${role}`, group.length, `At least ${cap.min} ${role} reference(s) are required.`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
let next = kept.filter((ref) => !removed.has(ref));
|
|
539
|
+
const maxTotal = _optionalChain([this, 'access', _26 => _26.caps, 'access', _27 => _27.references, 'optionalAccess', _28 => _28.maxTotal]);
|
|
540
|
+
if (maxTotal !== void 0 && next.length > maxTotal) {
|
|
541
|
+
if (this.strict) {
|
|
542
|
+
this.error("references", next.length, `At most ${maxTotal} references are supported in total.`);
|
|
543
|
+
} else {
|
|
544
|
+
this.adjust(
|
|
545
|
+
"references",
|
|
546
|
+
next.length,
|
|
547
|
+
maxTotal,
|
|
548
|
+
"truncated",
|
|
549
|
+
`Kept the first ${maxTotal} references; the model accepts no more in total.`
|
|
550
|
+
);
|
|
551
|
+
next = next.slice(0, maxTotal);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (this.request.mode === "inpaint" && !next.some((ref) => ref.role === "mask")) {
|
|
555
|
+
this.error("references.mask", 0, "Inpainting needs a `mask` reference.");
|
|
556
|
+
}
|
|
557
|
+
if (refs === void 0) return;
|
|
558
|
+
if (!this.strict) {
|
|
559
|
+
if (next.length > 0) this.request.references = next;
|
|
560
|
+
else delete this.request.references;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
planParam(name, spec, value) {
|
|
564
|
+
const field = `params.${name}`;
|
|
565
|
+
if (!spec) {
|
|
566
|
+
if (this.strict) this.error(field, value, `Unknown parameter "${name}".`);
|
|
567
|
+
else this.adjust(field, value, void 0, "dropped", `The model has no "${name}" parameter.`);
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
const label = _nullishCoalesce(spec.label, () => ( name));
|
|
571
|
+
if (spec.type === "boolean") {
|
|
572
|
+
if (typeof value !== "boolean") this.error(field, value, `Expected true or false for ${label}.`);
|
|
573
|
+
return value;
|
|
574
|
+
}
|
|
575
|
+
if (spec.type === "enum") {
|
|
576
|
+
if (spec.options.includes(value)) return value;
|
|
577
|
+
if (this.strict) {
|
|
578
|
+
this.error(field, value, `${describe(value)} is not a supported ${label}; supported: ${list(spec.options)}.`);
|
|
579
|
+
return value;
|
|
580
|
+
}
|
|
581
|
+
const numeric = spec.options.every((o) => typeof o === "number");
|
|
582
|
+
const snapped = numeric ? snapToOption(value, spec.options, numberRank, this.tie) : void 0;
|
|
583
|
+
const next = _nullishCoalesce(_nullishCoalesce(snapped, () => ( spec.default)), () => ( spec.options[0]));
|
|
584
|
+
this.adjust(
|
|
585
|
+
field,
|
|
586
|
+
value,
|
|
587
|
+
next,
|
|
588
|
+
"snapped",
|
|
589
|
+
snapped !== void 0 ? `Using the nearest supported ${label}.` : `${describe(value)} is not supported; using ${spec.default !== void 0 ? "the default" : "the first option"}.`
|
|
590
|
+
);
|
|
591
|
+
return next;
|
|
592
|
+
}
|
|
593
|
+
const result = this.planNumber(field, value, { ...spec, integer: spec.type === "integer" }, label);
|
|
594
|
+
return result ? result.value : value;
|
|
595
|
+
}
|
|
596
|
+
planParams() {
|
|
597
|
+
const params = this.request.params;
|
|
598
|
+
const specs = _nullishCoalesce(this.caps.params, () => ( {}));
|
|
599
|
+
const next = {};
|
|
600
|
+
for (const [name, value] of Object.entries(_nullishCoalesce(params, () => ( {})))) {
|
|
601
|
+
if (value === void 0) continue;
|
|
602
|
+
const planned = this.planParam(name, specs[name], value);
|
|
603
|
+
if (planned !== void 0) next[name] = planned;
|
|
604
|
+
else if (this.strict) next[name] = value;
|
|
605
|
+
}
|
|
606
|
+
if (this.options.fillDefaults) {
|
|
607
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
608
|
+
if (next[name] === void 0 && spec.default !== void 0) {
|
|
609
|
+
next[name] = spec.default;
|
|
610
|
+
this.adjust(`params.${name}`, void 0, spec.default, "defaulted", "Filled with the model default.");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (Object.keys(next).length > 0) this.request.params = next;
|
|
615
|
+
else delete this.request.params;
|
|
616
|
+
}
|
|
617
|
+
run() {
|
|
618
|
+
const { caps, request } = this;
|
|
619
|
+
for (const key of Object.keys(request)) {
|
|
620
|
+
if (GENERATION_REQUEST_FIELDS.includes(key)) continue;
|
|
621
|
+
const value = request[key];
|
|
622
|
+
if (this.strict) this.error(key, value, `Unknown request field "${key}".`);
|
|
623
|
+
else {
|
|
624
|
+
delete request[key];
|
|
625
|
+
this.adjust(key, value, void 0, "dropped", `Unknown request field "${key}".`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (request.model !== void 0 && request.model !== caps.id) {
|
|
629
|
+
this.error("model", request.model, `The request targets "${request.model}" but the plan is for "${caps.id}".`);
|
|
630
|
+
}
|
|
631
|
+
request.model = caps.id;
|
|
632
|
+
const promptCap = _nullishCoalesce(caps.prompt, () => ( {}));
|
|
633
|
+
if (promptCap.required && !(_nullishCoalesce(request.prompt, () => ( ""))).trim()) {
|
|
634
|
+
this.error("prompt", request.prompt, "A prompt is required.");
|
|
635
|
+
}
|
|
636
|
+
const countResolved = _nullishCoalesce(promptCap.countResolved, () => ( true));
|
|
637
|
+
const measured = countResolved && this.options.resolvedPrompt !== void 0 && this.options.resolvedPrompt !== request.prompt ? this.options.resolvedPrompt : void 0;
|
|
638
|
+
this.planText("prompt", promptCap.maxLength, measured);
|
|
639
|
+
for (const field of ["negativePrompt", "systemPrompt"]) {
|
|
640
|
+
if (request[field] === void 0) continue;
|
|
641
|
+
const cap = textFieldCapability(caps[field]);
|
|
642
|
+
if (!cap) {
|
|
643
|
+
this.unsupported(field, `The model does not take a ${field === "negativePrompt" ? "negative" : "system"} prompt.`);
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
this.planText(field, cap.maxLength);
|
|
647
|
+
}
|
|
648
|
+
this.planEnum("aspectRatio", caps.aspectRatios, aspectRatioRank, "aspect ratio");
|
|
649
|
+
this.planEnum("resolution", caps.resolutions, resolutionRank, "resolution");
|
|
650
|
+
this.planEnum("quality", caps.quality, qualityRank, "quality");
|
|
651
|
+
this.planCount();
|
|
652
|
+
this.planDuration();
|
|
653
|
+
this.planSeed();
|
|
654
|
+
this.planMode();
|
|
655
|
+
this.addMentions();
|
|
656
|
+
this.planReferences();
|
|
657
|
+
this.planParams();
|
|
658
|
+
}
|
|
659
|
+
}, _class);
|
|
660
|
+
function planGenerationRequest(request, caps, options = {}) {
|
|
661
|
+
const strategy = _nullishCoalesce(options.strategy, () => ( "nearest"));
|
|
662
|
+
const planner = new Planner(caps, cloneRequest(_nullishCoalesce(request, () => ( {}))), options, strategy);
|
|
663
|
+
planner.run();
|
|
664
|
+
return {
|
|
665
|
+
ok: planner.errors.length === 0,
|
|
666
|
+
request: planner.request,
|
|
667
|
+
adjustments: planner.adjustments,
|
|
668
|
+
errors: planner.errors,
|
|
669
|
+
model: caps.id,
|
|
670
|
+
strategy
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// src/generation/schema.ts
|
|
675
|
+
function enumSchema(cap, description) {
|
|
676
|
+
return {
|
|
677
|
+
type: "string",
|
|
678
|
+
enum: [...cap.options],
|
|
679
|
+
...cap.default !== void 0 ? { default: cap.default } : {},
|
|
680
|
+
description
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
function paramSchema(name, spec) {
|
|
684
|
+
const description = _nullishCoalesce(_nullishCoalesce(spec.description, () => ( spec.label)), () => ( name));
|
|
685
|
+
if (spec.type === "boolean") {
|
|
686
|
+
return { type: "boolean", description, ...spec.default !== void 0 ? { default: spec.default } : {} };
|
|
687
|
+
}
|
|
688
|
+
if (spec.type === "enum") {
|
|
689
|
+
const numeric = spec.options.every((o) => typeof o === "number");
|
|
690
|
+
return {
|
|
691
|
+
type: numeric ? "number" : "string",
|
|
692
|
+
enum: [...spec.options],
|
|
693
|
+
description,
|
|
694
|
+
...spec.default !== void 0 ? { default: spec.default } : {}
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
type: spec.type,
|
|
699
|
+
description: spec.step !== void 0 ? `${description} (step ${spec.step})` : description,
|
|
700
|
+
...spec.min !== void 0 ? { minimum: spec.min } : {},
|
|
701
|
+
...spec.max !== void 0 ? { maximum: spec.max } : {},
|
|
702
|
+
...spec.default !== void 0 ? { default: spec.default } : {}
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
function capabilitiesToJsonSchema(caps) {
|
|
706
|
+
const properties = {
|
|
707
|
+
model: { type: "string", const: caps.id, description: "Model id." }
|
|
708
|
+
};
|
|
709
|
+
const required = [];
|
|
710
|
+
const prompt = _nullishCoalesce(caps.prompt, () => ( {}));
|
|
711
|
+
const countResolved = _nullishCoalesce(prompt.countResolved, () => ( true));
|
|
712
|
+
properties.prompt = {
|
|
713
|
+
type: "string",
|
|
714
|
+
description: prompt.maxLength !== void 0 ? `Prompt text. At most ${prompt.maxLength} characters${countResolved ? " after templates and variables are resolved" : ""}.` : "Prompt text.",
|
|
715
|
+
...prompt.maxLength !== void 0 && !countResolved ? { maxLength: prompt.maxLength } : {},
|
|
716
|
+
...prompt.required ? { minLength: 1 } : {}
|
|
717
|
+
};
|
|
718
|
+
if (prompt.required) required.push("prompt");
|
|
719
|
+
const negative = textFieldCapability(caps.negativePrompt);
|
|
720
|
+
if (negative) {
|
|
721
|
+
properties.negativePrompt = {
|
|
722
|
+
type: "string",
|
|
723
|
+
description: "What to avoid in the output.",
|
|
724
|
+
...negative.maxLength !== void 0 ? { maxLength: negative.maxLength } : {}
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
const system = textFieldCapability(caps.systemPrompt);
|
|
728
|
+
if (system) {
|
|
729
|
+
properties.systemPrompt = {
|
|
730
|
+
type: "string",
|
|
731
|
+
description: "System instructions.",
|
|
732
|
+
...system.maxLength !== void 0 ? { maxLength: system.maxLength } : {}
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
if (_optionalChain([caps, 'access', _29 => _29.aspectRatios, 'optionalAccess', _30 => _30.options, 'access', _31 => _31.length])) properties.aspectRatio = enumSchema(caps.aspectRatios, "Aspect ratio (width:height).");
|
|
736
|
+
if (_optionalChain([caps, 'access', _32 => _32.resolutions, 'optionalAccess', _33 => _33.options, 'access', _34 => _34.length])) properties.resolution = enumSchema(caps.resolutions, "Output resolution, low to high.");
|
|
737
|
+
if (_optionalChain([caps, 'access', _35 => _35.quality, 'optionalAccess', _36 => _36.options, 'access', _37 => _37.length])) properties.quality = enumSchema(caps.quality, "Quality level, low to high.");
|
|
738
|
+
if (caps.count) {
|
|
739
|
+
const options = _optionalChain([caps, 'access', _38 => _38.count, 'access', _39 => _39.options, 'optionalAccess', _40 => _40.filter, 'call', _41 => _41((o) => o >= 1 && o <= caps.count.max)]);
|
|
740
|
+
properties.count = _optionalChain([options, 'optionalAccess', _42 => _42.length]) ? { type: "integer", enum: options, description: "Number of outputs." } : { type: "integer", minimum: 1, maximum: caps.count.max, description: "Number of outputs." };
|
|
741
|
+
if (caps.count.default !== void 0) properties.count.default = caps.count.default;
|
|
742
|
+
}
|
|
743
|
+
if (caps.duration) {
|
|
744
|
+
const d = caps.duration;
|
|
745
|
+
const options = _optionalChain([d, 'access', _43 => _43.options, 'optionalAccess', _44 => _44.filter, 'call', _45 => _45((o) => (d.min === void 0 || o >= d.min) && (d.max === void 0 || o <= d.max))]);
|
|
746
|
+
properties.duration = _optionalChain([options, 'optionalAccess', _46 => _46.length]) ? { type: "number", enum: options, description: "Duration in seconds." } : {
|
|
747
|
+
type: "number",
|
|
748
|
+
description: d.step !== void 0 ? `Duration in seconds (step ${d.step}).` : "Duration in seconds.",
|
|
749
|
+
...d.min !== void 0 ? { minimum: d.min } : {},
|
|
750
|
+
...d.max !== void 0 ? { maximum: d.max } : {}
|
|
751
|
+
};
|
|
752
|
+
if (d.default !== void 0) properties.duration.default = d.default;
|
|
753
|
+
}
|
|
754
|
+
const seed = seedCapability(caps.seed);
|
|
755
|
+
if (seed) {
|
|
756
|
+
properties.seed = {
|
|
757
|
+
type: "integer",
|
|
758
|
+
description: "Random seed for reproducible output.",
|
|
759
|
+
...seed.min !== void 0 ? { minimum: seed.min } : {},
|
|
760
|
+
...seed.max !== void 0 ? { maximum: seed.max } : {}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
const modes = supportedModes(caps);
|
|
764
|
+
if (modes.length > 1) {
|
|
765
|
+
properties.mode = { type: "string", enum: modes, default: "generate", description: "Generate, edit a source, or inpaint with a mask." };
|
|
766
|
+
}
|
|
767
|
+
const roles = supportedReferenceRoles(caps);
|
|
768
|
+
if (caps.inpainting && !roles.includes("mask")) roles.push("mask");
|
|
769
|
+
if (roles.length > 0) {
|
|
770
|
+
const limits = roles.map((role) => {
|
|
771
|
+
const cap = _nullishCoalesce(_optionalChain([caps, 'access', _47 => _47.references, 'optionalAccess', _48 => _48.roles, 'access', _49 => _49[role]]), () => ( { max: 1 }));
|
|
772
|
+
const min = cap.min ? `${cap.min}\u2013` : "up to ";
|
|
773
|
+
const accepts = "accepts" in cap && _optionalChain([cap, 'access', _50 => _50.accepts, 'optionalAccess', _51 => _51.length]) ? `, ${cap.accepts.join("/")} only` : "";
|
|
774
|
+
return `${role} (${referenceRoleLabel(role, caps)}): ${min}${cap.max}${accepts}`;
|
|
775
|
+
});
|
|
776
|
+
const perRoleTotal = roles.reduce((sum, role) => sum + (_nullishCoalesce(_optionalChain([caps, 'access', _52 => _52.references, 'optionalAccess', _53 => _53.roles, 'access', _54 => _54[role], 'optionalAccess', _55 => _55.max]), () => ( 1))), 0);
|
|
777
|
+
const maxItems = Math.min(_nullishCoalesce(_optionalChain([caps, 'access', _56 => _56.references, 'optionalAccess', _57 => _57.maxTotal]), () => ( Infinity)), perRoleTotal);
|
|
778
|
+
properties.references = {
|
|
779
|
+
type: "array",
|
|
780
|
+
description: `Reference inputs by role. Limits: ${limits.join("; ")}${_optionalChain([caps, 'access', _58 => _58.references, 'optionalAccess', _59 => _59.maxTotal]) !== void 0 ? `; at most ${caps.references.maxTotal} in total` : ""}.`,
|
|
781
|
+
maxItems,
|
|
782
|
+
items: {
|
|
783
|
+
type: "object",
|
|
784
|
+
properties: {
|
|
785
|
+
id: { type: "string", minLength: 1, description: "Asset id." },
|
|
786
|
+
role: { type: "string", enum: roles },
|
|
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" }
|
|
790
|
+
},
|
|
791
|
+
required: ["id", "role"],
|
|
792
|
+
additionalProperties: false
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
if (roles.some((role) => (_nullishCoalesce(_optionalChain([caps, 'access', _60 => _60.references, 'optionalAccess', _61 => _61.roles, 'access', _62 => _62[role], 'optionalAccess', _63 => _63.min]), () => ( 0))) > 0)) required.push("references");
|
|
796
|
+
}
|
|
797
|
+
const params = Object.entries(_nullishCoalesce(caps.params, () => ( {})));
|
|
798
|
+
if (params.length > 0) {
|
|
799
|
+
properties.params = {
|
|
800
|
+
type: "object",
|
|
801
|
+
description: "Model-specific parameters.",
|
|
802
|
+
properties: Object.fromEntries(params.map(([name, spec]) => [name, paramSchema(name, spec)])),
|
|
803
|
+
additionalProperties: false
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
type: "object",
|
|
808
|
+
title: _nullishCoalesce(caps.name, () => ( caps.id)),
|
|
809
|
+
description: `${caps.description ? `${caps.description} ` : ""}(${caps.media} model "${caps.id}")`,
|
|
810
|
+
properties,
|
|
811
|
+
...required.length ? { required } : {},
|
|
812
|
+
additionalProperties: false
|
|
813
|
+
};
|
|
814
|
+
}
|
|
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 _nullishCoalesce(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
|
+
|
|
858
|
+
// src/generation/tools.ts
|
|
859
|
+
var STRATEGIES = ["nearest", "upgrade", "downgrade", "error"];
|
|
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) => ({
|
|
868
|
+
type: "object",
|
|
869
|
+
description: "Generation request. Call list_models for the fields each model supports; unsupported values are adjusted per `strategy`.",
|
|
870
|
+
properties: {
|
|
871
|
+
prompt: { type: "string" },
|
|
872
|
+
negativePrompt: { type: "string" },
|
|
873
|
+
systemPrompt: { type: "string" },
|
|
874
|
+
aspectRatio: { type: "string", description: 'E.g. "16:9".' },
|
|
875
|
+
resolution: { type: "string" },
|
|
876
|
+
quality: { type: "string" },
|
|
877
|
+
count: { type: "integer", minimum: 1 },
|
|
878
|
+
duration: { type: "number", minimum: 0, description: "Seconds." },
|
|
879
|
+
seed: { type: "integer" },
|
|
880
|
+
mode: { type: "string", enum: ["generate", "edit", "inpaint"] },
|
|
881
|
+
references: {
|
|
882
|
+
type: "array",
|
|
883
|
+
items: {
|
|
884
|
+
type: "object",
|
|
885
|
+
properties: {
|
|
886
|
+
id: { type: "string", minLength: 1 },
|
|
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" }
|
|
895
|
+
},
|
|
896
|
+
required: ["id", "role"],
|
|
897
|
+
additionalProperties: false
|
|
898
|
+
}
|
|
899
|
+
},
|
|
900
|
+
params: { type: "object", additionalProperties: { type: ["string", "number", "boolean"] } }
|
|
901
|
+
},
|
|
902
|
+
additionalProperties: false
|
|
903
|
+
});
|
|
904
|
+
var strategySchema = {
|
|
905
|
+
type: "string",
|
|
906
|
+
enum: STRATEGIES,
|
|
907
|
+
description: "How to handle unsupported values: nearest (snap/clamp, ties up), downgrade (ties down), upgrade (ties up, never drops references), error (change nothing)."
|
|
908
|
+
};
|
|
909
|
+
function planFailure(plan) {
|
|
910
|
+
return {
|
|
911
|
+
isError: true,
|
|
912
|
+
content: [
|
|
913
|
+
{
|
|
914
|
+
type: "text",
|
|
915
|
+
text: `The request cannot be sent to "${plan.model}":
|
|
916
|
+
${plan.errors.map((e) => `- ${e.field}: ${e.message}`).join("\n")}`
|
|
917
|
+
}
|
|
918
|
+
],
|
|
919
|
+
structuredContent: { error: { code: "plan_failed", message: "Request planning failed." }, plan }
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
function createGenerationToolProvider(options) {
|
|
923
|
+
const readModels = () => typeof options.models === "function" ? options.models() : options.models;
|
|
924
|
+
const defaultStrategy = _nullishCoalesce(options.defaultStrategy, () => ( "nearest"));
|
|
925
|
+
const maxKeys = Math.max(1, _nullishCoalesce(options.maxIdempotencyKeys, () => ( 500)));
|
|
926
|
+
const calls = /* @__PURE__ */ new Map();
|
|
927
|
+
const findModel2 = (id) => {
|
|
928
|
+
const model = readModels().find((m) => m.id === id);
|
|
929
|
+
if (!model) throw new Error(`Unknown model "${String(id)}". Call list_models for the available ids.`);
|
|
930
|
+
return model;
|
|
931
|
+
};
|
|
932
|
+
const plan = (args) => {
|
|
933
|
+
const model = findModel2(args.model);
|
|
934
|
+
const request = { ..._nullishCoalesce(args.request, () => ( {})), model: model.id };
|
|
935
|
+
return {
|
|
936
|
+
model,
|
|
937
|
+
plan: planGenerationRequest(request, model, {
|
|
938
|
+
strategy: _nullishCoalesce(args.strategy, () => ( defaultStrategy)),
|
|
939
|
+
resolvedPrompt: args.resolvedPrompt
|
|
940
|
+
})
|
|
941
|
+
};
|
|
942
|
+
};
|
|
943
|
+
const planInput = () => {
|
|
944
|
+
const models = readModels();
|
|
945
|
+
const ids = models.map((m) => m.id);
|
|
946
|
+
return {
|
|
947
|
+
type: "object",
|
|
948
|
+
properties: {
|
|
949
|
+
model: { type: "string", ...ids.length ? { enum: ids } : {}, description: "Model id from list_models." },
|
|
950
|
+
request: requestSchemaFor(knownRoles(models)),
|
|
951
|
+
strategy: strategySchema,
|
|
952
|
+
resolvedPrompt: {
|
|
953
|
+
type: "string",
|
|
954
|
+
description: "The prompt with templates and variables resolved, when `request.prompt` is a template."
|
|
955
|
+
}
|
|
956
|
+
},
|
|
957
|
+
required: ["model", "request"],
|
|
958
|
+
additionalProperties: false
|
|
959
|
+
};
|
|
960
|
+
};
|
|
961
|
+
const tools = () => {
|
|
962
|
+
const list2 = [
|
|
963
|
+
{
|
|
964
|
+
name: "list_models",
|
|
965
|
+
title: "List generation models",
|
|
966
|
+
description: "Lists the available generation models with their media kind, description and the JSON Schema of the request each accepts.",
|
|
967
|
+
inputSchema: {
|
|
968
|
+
type: "object",
|
|
969
|
+
properties: {
|
|
970
|
+
media: { type: "string", enum: ["image", "video", "audio", "text"], description: "Only models of this kind." }
|
|
971
|
+
},
|
|
972
|
+
additionalProperties: false
|
|
973
|
+
},
|
|
974
|
+
annotations: {
|
|
975
|
+
title: "List generation models",
|
|
976
|
+
readOnlyHint: true,
|
|
977
|
+
destructiveHint: false,
|
|
978
|
+
idempotentHint: true,
|
|
979
|
+
openWorldHint: false
|
|
980
|
+
},
|
|
981
|
+
handler: (args) => ({
|
|
982
|
+
models: readModels().filter((m) => !args.media || m.media === args.media).map((m) => ({
|
|
983
|
+
id: m.id,
|
|
984
|
+
media: m.media,
|
|
985
|
+
...m.name ? { name: m.name } : {},
|
|
986
|
+
...m.description ? { description: m.description } : {},
|
|
987
|
+
..._optionalChain([m, 'access', _64 => _64.badges, 'optionalAccess', _65 => _65.length]) ? { badges: [...m.badges] } : {},
|
|
988
|
+
requestSchema: capabilitiesToJsonSchema(m)
|
|
989
|
+
}))
|
|
990
|
+
})
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
name: "plan_generation",
|
|
994
|
+
title: "Plan a generation request",
|
|
995
|
+
description: "Checks a request against a model without generating: returns the adjusted request, every adjustment (field, from, to, reason) and errors.",
|
|
996
|
+
inputSchema: planInput(),
|
|
997
|
+
annotations: {
|
|
998
|
+
title: "Plan a generation request",
|
|
999
|
+
readOnlyHint: true,
|
|
1000
|
+
destructiveHint: false,
|
|
1001
|
+
idempotentHint: true,
|
|
1002
|
+
openWorldHint: false
|
|
1003
|
+
},
|
|
1004
|
+
handler: (args) => ({ plan: plan(args).plan })
|
|
1005
|
+
}
|
|
1006
|
+
];
|
|
1007
|
+
if (options.estimate) {
|
|
1008
|
+
const estimate = options.estimate;
|
|
1009
|
+
list2.push({
|
|
1010
|
+
name: "estimate_generation",
|
|
1011
|
+
title: "Estimate a generation",
|
|
1012
|
+
description: "Estimates cost and/or time of a request after planning it. Does not generate anything.",
|
|
1013
|
+
inputSchema: planInput(),
|
|
1014
|
+
annotations: {
|
|
1015
|
+
title: "Estimate a generation",
|
|
1016
|
+
readOnlyHint: true,
|
|
1017
|
+
destructiveHint: false,
|
|
1018
|
+
idempotentHint: true,
|
|
1019
|
+
openWorldHint: true
|
|
1020
|
+
},
|
|
1021
|
+
handler: async (args, context) => {
|
|
1022
|
+
const planned = plan(args);
|
|
1023
|
+
if (!planned.plan.ok) return planFailure(planned.plan);
|
|
1024
|
+
const value = await estimate(planned.plan.request, { ...planned, signal: context.signal });
|
|
1025
|
+
return { plan: planned.plan, estimate: value };
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
const generateInput = planInput();
|
|
1030
|
+
list2.push({
|
|
1031
|
+
name: "generate",
|
|
1032
|
+
title: "Generate media",
|
|
1033
|
+
description: "Plans the request and starts a generation. Pass a fresh `idempotencyKey` per intended generation and reuse it when retrying, so a retry never generates twice.",
|
|
1034
|
+
inputSchema: {
|
|
1035
|
+
...generateInput,
|
|
1036
|
+
properties: {
|
|
1037
|
+
...generateInput.properties,
|
|
1038
|
+
idempotencyKey: {
|
|
1039
|
+
type: "string",
|
|
1040
|
+
minLength: 1,
|
|
1041
|
+
maxLength: 200,
|
|
1042
|
+
description: "Unique per intended generation; reuse it to retry safely."
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
required: ["model", "request", "idempotencyKey"]
|
|
1046
|
+
},
|
|
1047
|
+
annotations: {
|
|
1048
|
+
title: "Generate media",
|
|
1049
|
+
readOnlyHint: false,
|
|
1050
|
+
destructiveHint: true,
|
|
1051
|
+
idempotentHint: true,
|
|
1052
|
+
openWorldHint: true
|
|
1053
|
+
},
|
|
1054
|
+
handler: async (args, context) => {
|
|
1055
|
+
const key = String(args.idempotencyKey);
|
|
1056
|
+
const { idempotencyKey: _key, ...rest } = args;
|
|
1057
|
+
const signature = stableStringify(rest);
|
|
1058
|
+
const existing = calls.get(key);
|
|
1059
|
+
if (existing) {
|
|
1060
|
+
if (existing.signature !== signature) {
|
|
1061
|
+
throw new Error(
|
|
1062
|
+
`Idempotency key "${key}" was already used with different arguments. Use a new key for a new generation.`
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
return { ...await existing.result, deduplicated: true };
|
|
1066
|
+
}
|
|
1067
|
+
const planned = plan(args);
|
|
1068
|
+
if (!planned.plan.ok) return planFailure(planned.plan);
|
|
1069
|
+
const result = Promise.resolve().then(
|
|
1070
|
+
() => options.generate(planned.plan.request, {
|
|
1071
|
+
...planned,
|
|
1072
|
+
idempotencyKey: key,
|
|
1073
|
+
signal: context.signal
|
|
1074
|
+
})
|
|
1075
|
+
).then((value) => ({
|
|
1076
|
+
result: value,
|
|
1077
|
+
plan: planned.plan,
|
|
1078
|
+
idempotencyKey: key
|
|
1079
|
+
}));
|
|
1080
|
+
calls.set(key, { signature, result });
|
|
1081
|
+
while (calls.size > maxKeys) calls.delete(calls.keys().next().value);
|
|
1082
|
+
try {
|
|
1083
|
+
return await result;
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
if (_optionalChain([calls, 'access', _66 => _66.get, 'call', _67 => _67(key), 'optionalAccess', _68 => _68.result]) === result) calls.delete(key);
|
|
1086
|
+
throw error;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
return list2;
|
|
1091
|
+
};
|
|
1092
|
+
return {
|
|
1093
|
+
id: _nullishCoalesce(options.id, () => ( "generation")),
|
|
1094
|
+
...options.namespace ? { namespace: options.namespace } : {},
|
|
1095
|
+
tools,
|
|
1096
|
+
...options.subscribe ? { subscribe: options.subscribe } : {},
|
|
1097
|
+
clearIdempotencyKeys(key) {
|
|
1098
|
+
if (key === void 0) calls.clear();
|
|
1099
|
+
else calls.delete(key);
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// src/generation/provenance.ts
|
|
1105
|
+
var PROVENANCE_FORMAT = "pixerate.generation-provenance";
|
|
1106
|
+
var PROVENANCE_VERSION = 1;
|
|
1107
|
+
var ProvenanceParseError = class extends Error {
|
|
1108
|
+
constructor(message) {
|
|
1109
|
+
super(message);
|
|
1110
|
+
this.name = "ProvenanceParseError";
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
var toIso = (value) => new Date(value).toISOString();
|
|
1114
|
+
var clone = (value) => value === void 0 ? value : JSON.parse(JSON.stringify(value));
|
|
1115
|
+
function pinTemplates(rawPrompt, templates, bindings, maxDepth) {
|
|
1116
|
+
const byName = new Map(templates.map((t) => [t.name, t]));
|
|
1117
|
+
const pinned = /* @__PURE__ */ new Map();
|
|
1118
|
+
const visit = (text, depth) => {
|
|
1119
|
+
if (depth > maxDepth) return;
|
|
1120
|
+
for (const token of _chunkFD4LPFAEcjs.tokenizePrompt.call(void 0, text)) {
|
|
1121
|
+
if (token.type !== "template" || pinned.has(token.value)) continue;
|
|
1122
|
+
const template = byName.get(token.value);
|
|
1123
|
+
if (!template) continue;
|
|
1124
|
+
const body = _chunkFD4LPFAEcjs.getTemplateBody.call(void 0, template, bindings);
|
|
1125
|
+
if (body === void 0) continue;
|
|
1126
|
+
const bound = bindings[template.name];
|
|
1127
|
+
const version = bound && template.versions ? template.versions.find((v) => v.id === bound || v.version === bound) : _chunkFD4LPFAEcjs.getLatestVersion.call(void 0, template);
|
|
1128
|
+
const isVersioned = !!_optionalChain([template, 'access', _69 => _69.versions, 'optionalAccess', _70 => _70.length]) && !!version;
|
|
1129
|
+
pinned.set(template.name, {
|
|
1130
|
+
name: template.name,
|
|
1131
|
+
...template.id !== void 0 ? { templateId: template.id } : {},
|
|
1132
|
+
...isVersioned ? { versionId: version.id, version: version.version } : {},
|
|
1133
|
+
body
|
|
1134
|
+
});
|
|
1135
|
+
visit(body, depth + 1);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
visit(rawPrompt, 0);
|
|
1139
|
+
return [...pinned.values()];
|
|
1140
|
+
}
|
|
1141
|
+
function pinnedTemplatesToTemplates(pinned) {
|
|
1142
|
+
return pinned.map(
|
|
1143
|
+
(p) => p.versionId !== void 0 ? {
|
|
1144
|
+
...p.templateId !== void 0 ? { id: p.templateId } : {},
|
|
1145
|
+
name: p.name,
|
|
1146
|
+
latestVersion: p.version,
|
|
1147
|
+
versions: [{ id: p.versionId, version: _nullishCoalesce(p.version, () => ( p.versionId)), body: p.body }]
|
|
1148
|
+
} : { ...p.templateId !== void 0 ? { id: p.templateId } : {}, name: p.name, body: p.body }
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
function createProvenance(options) {
|
|
1152
|
+
const templates = _nullishCoalesce(options.templates, () => ( []));
|
|
1153
|
+
const maxDepth = _nullishCoalesce(options.maxDepth, () => ( 10));
|
|
1154
|
+
const resolved = _chunkFD4LPFAEcjs.resolvePrompt.call(void 0, options.rawPrompt, templates, {
|
|
1155
|
+
bindings: options.bindings,
|
|
1156
|
+
values: options.values,
|
|
1157
|
+
maxDepth
|
|
1158
|
+
});
|
|
1159
|
+
const pinned = pinTemplates(options.rawPrompt, templates, _nullishCoalesce(options.bindings, () => ( {})), maxDepth);
|
|
1160
|
+
const bindings = {};
|
|
1161
|
+
for (const p of pinned) if (p.versionId !== void 0) bindings[p.name] = p.versionId;
|
|
1162
|
+
const modelId = typeof options.model === "string" ? options.model : options.model.id;
|
|
1163
|
+
const request = clone(_nullishCoalesce(_nullishCoalesce(_optionalChain([options, 'access', _71 => _71.plan, 'optionalAccess', _72 => _72.request]), () => ( options.request)), () => ( {})));
|
|
1164
|
+
request.model = modelId;
|
|
1165
|
+
if (request.prompt === void 0) request.prompt = resolved.text;
|
|
1166
|
+
const adjustments = clone(_nullishCoalesce(_nullishCoalesce(options.adjustments, () => ( _optionalChain([options, 'access', _73 => _73.plan, 'optionalAccess', _74 => _74.adjustments]))), () => ( [])));
|
|
1167
|
+
return {
|
|
1168
|
+
format: PROVENANCE_FORMAT,
|
|
1169
|
+
version: PROVENANCE_VERSION,
|
|
1170
|
+
rawPrompt: options.rawPrompt,
|
|
1171
|
+
templates: pinned,
|
|
1172
|
+
bindings,
|
|
1173
|
+
values: options.values ? clone(options.values) : null,
|
|
1174
|
+
resolvedPrompt: resolved.text,
|
|
1175
|
+
sourceMap: resolved.map.map((segment) => {
|
|
1176
|
+
const { locked: _locked, ...rest } = segment;
|
|
1177
|
+
return rest;
|
|
1178
|
+
}),
|
|
1179
|
+
modelId,
|
|
1180
|
+
request,
|
|
1181
|
+
adjustments,
|
|
1182
|
+
references: (_nullishCoalesce(request.references, () => ( []))).map(({ id, role }) => ({ id, role })),
|
|
1183
|
+
createdAt: toIso(_nullishCoalesce(options.createdAt, () => ( Date.now()))),
|
|
1184
|
+
...options.startedAt !== void 0 ? { startedAt: toIso(options.startedAt) } : {},
|
|
1185
|
+
...options.completedAt !== void 0 ? { completedAt: toIso(options.completedAt) } : {},
|
|
1186
|
+
...options.outputIds ? { outputIds: [...options.outputIds] } : {},
|
|
1187
|
+
...options.meta ? { meta: clone(options.meta) } : {}
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
function serializeProvenance(provenance) {
|
|
1191
|
+
return JSON.stringify(provenance);
|
|
1192
|
+
}
|
|
1193
|
+
var isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
1194
|
+
function parseProvenance(input) {
|
|
1195
|
+
let data = input;
|
|
1196
|
+
if (typeof input === "string") {
|
|
1197
|
+
try {
|
|
1198
|
+
data = JSON.parse(input);
|
|
1199
|
+
} catch (e2) {
|
|
1200
|
+
throw new ProvenanceParseError("Provenance is not valid JSON.");
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if (!isRecord(data) || data.format !== PROVENANCE_FORMAT) {
|
|
1204
|
+
throw new ProvenanceParseError("Not a generation provenance record.");
|
|
1205
|
+
}
|
|
1206
|
+
if (typeof data.version !== "number" || data.version > PROVENANCE_VERSION) {
|
|
1207
|
+
throw new ProvenanceParseError(`Unsupported provenance version ${JSON.stringify(data.version)}.`);
|
|
1208
|
+
}
|
|
1209
|
+
const checks = [
|
|
1210
|
+
["rawPrompt", typeof data.rawPrompt === "string"],
|
|
1211
|
+
["resolvedPrompt", typeof data.resolvedPrompt === "string"],
|
|
1212
|
+
["modelId", typeof data.modelId === "string"],
|
|
1213
|
+
["createdAt", typeof data.createdAt === "string"],
|
|
1214
|
+
["request", isRecord(data.request)],
|
|
1215
|
+
["templates", Array.isArray(data.templates) && data.templates.every((t) => isRecord(t) && typeof t.name === "string" && typeof t.body === "string")],
|
|
1216
|
+
["sourceMap", Array.isArray(data.sourceMap)],
|
|
1217
|
+
["adjustments", Array.isArray(data.adjustments)],
|
|
1218
|
+
["references", Array.isArray(data.references)]
|
|
1219
|
+
];
|
|
1220
|
+
const bad = checks.find(([, ok]) => !ok);
|
|
1221
|
+
if (bad) throw new ProvenanceParseError(`Invalid provenance field "${bad[0]}".`);
|
|
1222
|
+
return {
|
|
1223
|
+
...data,
|
|
1224
|
+
bindings: isRecord(data.bindings) ? data.bindings : {},
|
|
1225
|
+
values: isRecord(data.values) ? data.values : null
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
function replayProvenancePrompt(provenance) {
|
|
1229
|
+
const result = _chunkFD4LPFAEcjs.resolvePrompt.call(void 0, provenance.rawPrompt, pinnedTemplatesToTemplates(provenance.templates), {
|
|
1230
|
+
bindings: provenance.bindings,
|
|
1231
|
+
...provenance.values ? { values: provenance.values } : {}
|
|
1232
|
+
});
|
|
1233
|
+
return { text: result.text, map: result.map, matches: result.text === provenance.resolvedPrompt };
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// src/generation/batch.ts
|
|
1237
|
+
function createBatchResolver(options) {
|
|
1238
|
+
const maxBatch = Math.max(1, Math.floor(_nullishCoalesce(options.maxBatch, () => ( 50))));
|
|
1239
|
+
const delayMs = Math.max(0, _nullishCoalesce(options.delayMs, () => ( 0)));
|
|
1240
|
+
const settled = /* @__PURE__ */ new Map();
|
|
1241
|
+
const failures = /* @__PURE__ */ new Set();
|
|
1242
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
1243
|
+
let queue = [];
|
|
1244
|
+
let timer = null;
|
|
1245
|
+
const run = (keys) => {
|
|
1246
|
+
const pendings = keys.map((key) => inFlight.get(key));
|
|
1247
|
+
const finish = (values, error) => {
|
|
1248
|
+
if (values === null) _optionalChain([options, 'access', _75 => _75.onError, 'optionalCall', _76 => _76(error, keys)]);
|
|
1249
|
+
keys.forEach((key, index) => {
|
|
1250
|
+
const pending = pendings[index];
|
|
1251
|
+
const value = _optionalChain([values, 'optionalAccess', _77 => _77.get, 'call', _78 => _78(key)]);
|
|
1252
|
+
if (pending && inFlight.get(key) === pending) {
|
|
1253
|
+
inFlight.delete(key);
|
|
1254
|
+
settled.set(key, value);
|
|
1255
|
+
if (values === null) failures.add(key);
|
|
1256
|
+
}
|
|
1257
|
+
_optionalChain([pending, 'optionalAccess', _79 => _79.resolve, 'call', _80 => _80(value)]);
|
|
1258
|
+
});
|
|
1259
|
+
};
|
|
1260
|
+
let promise;
|
|
1261
|
+
try {
|
|
1262
|
+
promise = Promise.resolve(options.fetch(keys));
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
promise = Promise.reject(error);
|
|
1265
|
+
}
|
|
1266
|
+
promise.then(
|
|
1267
|
+
(values) => finish(values instanceof Map ? values : /* @__PURE__ */ new Map()),
|
|
1268
|
+
(error) => finish(null, _nullishCoalesce(error, () => ( new Error("Batch fetch failed."))))
|
|
1269
|
+
);
|
|
1270
|
+
};
|
|
1271
|
+
const flush = () => {
|
|
1272
|
+
if (timer !== null) clearTimeout(timer);
|
|
1273
|
+
timer = null;
|
|
1274
|
+
const keys = queue;
|
|
1275
|
+
queue = [];
|
|
1276
|
+
for (let i = 0; i < keys.length; i += maxBatch) run(keys.slice(i, i + maxBatch));
|
|
1277
|
+
};
|
|
1278
|
+
const load = (key) => {
|
|
1279
|
+
if (settled.has(key)) return Promise.resolve(settled.get(key));
|
|
1280
|
+
const existing = inFlight.get(key);
|
|
1281
|
+
if (existing) return existing.promise;
|
|
1282
|
+
let resolve;
|
|
1283
|
+
const promise = new Promise((r) => resolve = r);
|
|
1284
|
+
inFlight.set(key, { promise, resolve });
|
|
1285
|
+
queue.push(key);
|
|
1286
|
+
if (queue.length >= maxBatch) flush();
|
|
1287
|
+
else if (timer === null) timer = setTimeout(flush, delayMs);
|
|
1288
|
+
return promise;
|
|
1289
|
+
};
|
|
1290
|
+
return {
|
|
1291
|
+
load,
|
|
1292
|
+
loadMany: (keys) => Promise.all(keys.map(load)),
|
|
1293
|
+
peek: (key) => settled.get(key),
|
|
1294
|
+
has: (key) => settled.has(key),
|
|
1295
|
+
failed: (key) => failures.has(key),
|
|
1296
|
+
prime(key, value) {
|
|
1297
|
+
settled.set(key, value);
|
|
1298
|
+
failures.delete(key);
|
|
1299
|
+
},
|
|
1300
|
+
clear(key) {
|
|
1301
|
+
if (key === void 0) {
|
|
1302
|
+
settled.clear();
|
|
1303
|
+
failures.clear();
|
|
1304
|
+
for (const k of [...inFlight.keys()]) if (!queue.includes(k)) inFlight.delete(k);
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
settled.delete(key);
|
|
1308
|
+
failures.delete(key);
|
|
1309
|
+
if (!queue.includes(key)) inFlight.delete(key);
|
|
1310
|
+
},
|
|
1311
|
+
flush
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// src/generation/progress.ts
|
|
1316
|
+
var MAX_PENDING_PERCENT = 95;
|
|
1317
|
+
var ALMOST_DONE_MS = 5e3;
|
|
1318
|
+
var UNKNOWN_DURATION_TAU_MS = 3e4;
|
|
1319
|
+
var toMs = (value) => typeof value === "number" ? value : new Date(value).getTime();
|
|
1320
|
+
function formatRemaining(ms) {
|
|
1321
|
+
const seconds = Math.ceil(ms / 1e3);
|
|
1322
|
+
if (seconds < 60) return `~${Math.max(1, seconds)}s left`;
|
|
1323
|
+
const minutes = Math.ceil(ms / 6e4);
|
|
1324
|
+
if (minutes < 60) return `~${minutes}m left`;
|
|
1325
|
+
const hours = Math.floor(minutes / 60);
|
|
1326
|
+
const rest = minutes % 60;
|
|
1327
|
+
return rest ? `~${hours}h ${rest}m left` : `~${hours}h left`;
|
|
1328
|
+
}
|
|
1329
|
+
function estimateJobProgress(input) {
|
|
1330
|
+
const started = toMs(input.startedAt);
|
|
1331
|
+
const now = toMs(_nullishCoalesce(input.now, () => ( Date.now())));
|
|
1332
|
+
const elapsedMs = Math.max(0, now - started);
|
|
1333
|
+
if (input.done) return { percent: 100, label: "Done", elapsedMs, remainingMs: 0, overdue: false };
|
|
1334
|
+
if (!Number.isFinite(started) || now <= started) {
|
|
1335
|
+
return { percent: 0, label: "Starting\u2026", elapsedMs: 0, ...input.expectedMs ? { remainingMs: input.expectedMs } : {}, overdue: false };
|
|
1336
|
+
}
|
|
1337
|
+
const expected = input.expectedMs;
|
|
1338
|
+
if (!expected || !(expected > 0)) {
|
|
1339
|
+
const percent2 = MAX_PENDING_PERCENT * (1 - Math.exp(-elapsedMs / UNKNOWN_DURATION_TAU_MS));
|
|
1340
|
+
return { percent: Math.floor(percent2), label: "Working\u2026", elapsedMs, overdue: false };
|
|
1341
|
+
}
|
|
1342
|
+
const remainingMs = Math.max(0, expected - elapsedMs);
|
|
1343
|
+
const percent = Math.min(MAX_PENDING_PERCENT, Math.floor(elapsedMs / expected * 100));
|
|
1344
|
+
return {
|
|
1345
|
+
percent,
|
|
1346
|
+
label: remainingMs <= ALMOST_DONE_MS ? "Almost done\u2026" : formatRemaining(remainingMs),
|
|
1347
|
+
elapsedMs,
|
|
1348
|
+
remainingMs,
|
|
1349
|
+
overdue: elapsedMs > expected
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
function expectedDurationFor(caps, request = {}) {
|
|
1353
|
+
const timing = caps.timing;
|
|
1354
|
+
if (!timing) return void 0;
|
|
1355
|
+
const count = _nullishCoalesce(_nullishCoalesce(request.count, () => ( _optionalChain([caps, 'access', _81 => _81.count, 'optionalAccess', _82 => _82.default]))), () => ( 1));
|
|
1356
|
+
const duration = _nullishCoalesce(_nullishCoalesce(request.duration, () => ( _optionalChain([caps, 'access', _83 => _83.duration, 'optionalAccess', _84 => _84.default]))), () => ( 0));
|
|
1357
|
+
const resolution = _nullishCoalesce(request.resolution, () => ( _optionalChain([caps, 'access', _85 => _85.resolutions, 'optionalAccess', _86 => _86.default])));
|
|
1358
|
+
const megapixels = resolution ? _nullishCoalesce(resolutionMegapixels(resolution), () => ( 0)) : 0;
|
|
1359
|
+
return Math.round(
|
|
1360
|
+
timing.baseMs + (_nullishCoalesce(timing.perItemMs, () => ( 0))) * Math.max(0, count - 1) + (_nullishCoalesce(timing.perSecondMs, () => ( 0))) * duration + (_nullishCoalesce(timing.perMegapixelMs, () => ( 0))) * megapixels
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// src/generation/controls.ts
|
|
1365
|
+
function enumControl(key, label, cap) {
|
|
1366
|
+
if (!_optionalChain([cap, 'optionalAccess', _87 => _87.options, 'access', _88 => _88.length])) return null;
|
|
1367
|
+
return {
|
|
1368
|
+
key,
|
|
1369
|
+
label,
|
|
1370
|
+
kind: "select",
|
|
1371
|
+
valueType: "string",
|
|
1372
|
+
options: cap.options.map((value) => ({ value, label: _nullishCoalesce(_optionalChain([cap, 'access', _89 => _89.labels, 'optionalAccess', _90 => _90[value]]), () => ( value)) })),
|
|
1373
|
+
...cap.default !== void 0 ? { defaultValue: cap.default } : {}
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
function getGenerationControls(caps) {
|
|
1377
|
+
const controls = [];
|
|
1378
|
+
const modes = supportedModes(caps);
|
|
1379
|
+
if (modes.length > 1) {
|
|
1380
|
+
controls.push({
|
|
1381
|
+
key: "mode",
|
|
1382
|
+
label: "Mode",
|
|
1383
|
+
kind: "select",
|
|
1384
|
+
valueType: "string",
|
|
1385
|
+
options: modes.map((m) => ({ value: m, label: m[0].toUpperCase() + m.slice(1) })),
|
|
1386
|
+
defaultValue: "generate"
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
const negative = textFieldCapability(caps.negativePrompt);
|
|
1390
|
+
if (negative) controls.push({ key: "negativePrompt", label: "Negative prompt", kind: "textarea", valueType: "string", maxLength: negative.maxLength });
|
|
1391
|
+
const system = textFieldCapability(caps.systemPrompt);
|
|
1392
|
+
if (system) controls.push({ key: "systemPrompt", label: "System prompt", kind: "textarea", valueType: "string", maxLength: system.maxLength });
|
|
1393
|
+
controls.push(enumControl("aspectRatio", "Aspect ratio", caps.aspectRatios));
|
|
1394
|
+
controls.push(enumControl("resolution", "Resolution", caps.resolutions));
|
|
1395
|
+
controls.push(enumControl("quality", "Quality", caps.quality));
|
|
1396
|
+
if (caps.count) {
|
|
1397
|
+
const options = _optionalChain([caps, 'access', _91 => _91.count, 'access', _92 => _92.options, 'optionalAccess', _93 => _93.filter, 'call', _94 => _94((o) => o >= 1 && o <= caps.count.max)]);
|
|
1398
|
+
controls.push(
|
|
1399
|
+
_optionalChain([options, 'optionalAccess', _95 => _95.length]) ? { key: "count", label: "Outputs", kind: "select", valueType: "number", options: options.map((o) => ({ value: o, label: String(o) })), defaultValue: caps.count.default } : { key: "count", label: "Outputs", kind: "range", valueType: "number", min: 1, max: caps.count.max, step: 1, defaultValue: _nullishCoalesce(caps.count.default, () => ( 1)) }
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
if (caps.duration) {
|
|
1403
|
+
const d = caps.duration;
|
|
1404
|
+
const options = _optionalChain([d, 'access', _96 => _96.options, 'optionalAccess', _97 => _97.filter, 'call', _98 => _98((o) => (d.min === void 0 || o >= d.min) && (d.max === void 0 || o <= d.max))]);
|
|
1405
|
+
controls.push(
|
|
1406
|
+
_optionalChain([options, 'optionalAccess', _99 => _99.length]) ? { key: "duration", label: "Duration (s)", kind: "select", valueType: "number", options: options.map((o) => ({ value: o, label: `${o}s` })), defaultValue: d.default } : {
|
|
1407
|
+
key: "duration",
|
|
1408
|
+
label: "Duration (s)",
|
|
1409
|
+
kind: d.min !== void 0 && d.max !== void 0 ? "range" : "number",
|
|
1410
|
+
valueType: "number",
|
|
1411
|
+
min: d.min,
|
|
1412
|
+
max: d.max,
|
|
1413
|
+
step: d.step,
|
|
1414
|
+
defaultValue: d.default
|
|
1415
|
+
}
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
const seed = seedCapability(caps.seed);
|
|
1419
|
+
if (seed) controls.push({ key: "seed", label: "Seed", kind: "number", valueType: "number", min: seed.min, max: seed.max, step: 1 });
|
|
1420
|
+
for (const [name, spec] of Object.entries(_nullishCoalesce(caps.params, () => ( {})))) {
|
|
1421
|
+
const base = { key: `params.${name}`, label: _nullishCoalesce(spec.label, () => ( name)), ...spec.description ? { description: spec.description } : {} };
|
|
1422
|
+
if (spec.type === "boolean") {
|
|
1423
|
+
controls.push({ ...base, kind: "checkbox", valueType: "boolean", defaultValue: spec.default });
|
|
1424
|
+
} else if (spec.type === "enum") {
|
|
1425
|
+
const numeric = spec.options.every((o) => typeof o === "number");
|
|
1426
|
+
controls.push({
|
|
1427
|
+
...base,
|
|
1428
|
+
kind: "select",
|
|
1429
|
+
valueType: numeric ? "number" : "string",
|
|
1430
|
+
options: spec.options.map((value) => ({ value, label: String(value) })),
|
|
1431
|
+
defaultValue: spec.default
|
|
1432
|
+
});
|
|
1433
|
+
} else {
|
|
1434
|
+
controls.push({
|
|
1435
|
+
...base,
|
|
1436
|
+
kind: spec.min !== void 0 && spec.max !== void 0 ? "range" : "number",
|
|
1437
|
+
valueType: "number",
|
|
1438
|
+
min: spec.min,
|
|
1439
|
+
max: spec.max,
|
|
1440
|
+
step: _nullishCoalesce(spec.step, () => ( (spec.type === "integer" ? 1 : void 0))),
|
|
1441
|
+
defaultValue: spec.default
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
return controls.filter((c) => c !== null);
|
|
1446
|
+
}
|
|
1447
|
+
function getRequestValue(request, key) {
|
|
1448
|
+
if (key.startsWith("params.")) return _optionalChain([request, 'access', _100 => _100.params, 'optionalAccess', _101 => _101[key.slice(7)]]);
|
|
1449
|
+
return request[key];
|
|
1450
|
+
}
|
|
1451
|
+
function setRequestValue(request, key, value) {
|
|
1452
|
+
const remove = value === void 0 || value === "" || typeof value === "number" && Number.isNaN(value);
|
|
1453
|
+
if (key.startsWith("params.")) {
|
|
1454
|
+
const name = key.slice(7);
|
|
1455
|
+
const params = { ..._nullishCoalesce(request.params, () => ( {})) };
|
|
1456
|
+
if (remove) delete params[name];
|
|
1457
|
+
else params[name] = value;
|
|
1458
|
+
const next2 = { ...request, params };
|
|
1459
|
+
if (Object.keys(params).length === 0) delete next2.params;
|
|
1460
|
+
return next2;
|
|
1461
|
+
}
|
|
1462
|
+
const next = { ...request };
|
|
1463
|
+
if (remove) delete next[key];
|
|
1464
|
+
else next[key] = value;
|
|
1465
|
+
return next;
|
|
1466
|
+
}
|
|
1467
|
+
function parseControlValue(control, raw) {
|
|
1468
|
+
if (control.valueType === "boolean") return Boolean(raw);
|
|
1469
|
+
if (raw === "" || raw === void 0) return void 0;
|
|
1470
|
+
if (control.valueType === "number") {
|
|
1471
|
+
const n = Number(raw);
|
|
1472
|
+
return Number.isFinite(n) ? n : void 0;
|
|
1473
|
+
}
|
|
1474
|
+
return String(raw);
|
|
1475
|
+
}
|
|
1476
|
+
function getReferenceSlots(caps, request = {}) {
|
|
1477
|
+
const roles = supportedReferenceRoles(caps);
|
|
1478
|
+
if (caps.inpainting && !roles.includes("mask")) roles.push("mask");
|
|
1479
|
+
const refs = _nullishCoalesce(request.references, () => ( []));
|
|
1480
|
+
const total = refs.length;
|
|
1481
|
+
const maxTotal = _nullishCoalesce(_optionalChain([caps, 'access', _102 => _102.references, 'optionalAccess', _103 => _103.maxTotal]), () => ( Infinity));
|
|
1482
|
+
return roles.map((role) => {
|
|
1483
|
+
const cap = _nullishCoalesce(_optionalChain([caps, 'access', _104 => _104.references, 'optionalAccess', _105 => _105.roles, 'access', _106 => _106[role]]), () => ( { max: 1 }));
|
|
1484
|
+
const references = refs.filter((ref) => ref.role === role);
|
|
1485
|
+
return {
|
|
1486
|
+
role,
|
|
1487
|
+
label: referenceRoleLabel(role, caps),
|
|
1488
|
+
...cap.description ? { description: cap.description } : {},
|
|
1489
|
+
..."accepts" in cap && _optionalChain([cap, 'access', _107 => _107.accepts, 'optionalAccess', _108 => _108.length]) ? { accepts: [...cap.accepts] } : {},
|
|
1490
|
+
min: _nullishCoalesce(cap.min, () => ( 0)),
|
|
1491
|
+
max: cap.max,
|
|
1492
|
+
references,
|
|
1493
|
+
canAdd: references.length < cap.max && total < maxTotal
|
|
1494
|
+
};
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
function addReference(request, reference) {
|
|
1498
|
+
return { ...request, references: [..._nullishCoalesce(request.references, () => ( [])), { ...reference }] };
|
|
1499
|
+
}
|
|
1500
|
+
function removeReference(request, role, id) {
|
|
1501
|
+
const references = (_nullishCoalesce(request.references, () => ( []))).filter((ref) => !(ref.role === role && ref.id === id));
|
|
1502
|
+
const next = { ...request, references };
|
|
1503
|
+
if (references.length === 0) delete next.references;
|
|
1504
|
+
return next;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/generation/assets.ts
|
|
1508
|
+
function toAssetResolver(lookup) {
|
|
1509
|
+
if (!lookup) return void 0;
|
|
1510
|
+
if (typeof lookup === "function") return (id) => _nullishCoalesce(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 = _optionalChain([caps, 'access', _109 => _109.references, 'optionalAccess', _110 => _110.roles, 'access', _111 => _111[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 = _nullishCoalesce(roleCap(caps, role), () => ( { max: 1 }));
|
|
1526
|
+
return {
|
|
1527
|
+
role,
|
|
1528
|
+
label: referenceRoleLabel(role, caps),
|
|
1529
|
+
...cap.description ? { description: cap.description } : {},
|
|
1530
|
+
min: _nullishCoalesce(cap.min, () => ( 0)),
|
|
1531
|
+
max: cap.max,
|
|
1532
|
+
..._optionalChain([cap, 'access', _112 => _112.accepts, 'optionalAccess', _113 => _113.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 = `@${_nullishCoalesce(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}: ${_nullishCoalesce(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 = _nullishCoalesce(mention.mediaType, () => ( _optionalChain([resolve, 'optionalCall', _114 => _114(id), 'optionalAccess', _115 => _115.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 ${(_nullishCoalesce(cap.accepts, () => ( []))).join(", ")}.`
|
|
1583
|
+
});
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
counts[role] = (_nullishCoalesce(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) => (_nullishCoalesce(counts[option.role], () => ( 0))) < option.min).map((option) => ({ role: option.role, min: option.min, count: _nullishCoalesce(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 = _nullishCoalesce(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 = _nullishCoalesce(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 = _optionalChain([globalThis, 'access', _116 => _116.crypto, 'optionalAccess', _117 => _117.randomUUID, 'optionalCall', _118 => _118()]);
|
|
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 (_nullishCoalesce(references, () => ( []))).map((ref) => {
|
|
1677
|
+
const info = _optionalChain([resolve, 'optionalCall', _119 => _119(ref.id)]);
|
|
1678
|
+
const contentHash = _nullishCoalesce(ref.contentHash, () => ( _optionalChain([info, 'optionalAccess', _120 => _120.contentHash])));
|
|
1679
|
+
const mediaType = _nullishCoalesce(ref.mediaType, () => ( _optionalChain([info, 'optionalAccess', _121 => _121.mediaType])));
|
|
1680
|
+
const url = _nullishCoalesce(ref.url, () => ( _optionalChain([info, 'optionalAccess', _122 => _122.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(_nullishCoalesce(_nullishCoalesce(settingsInput, () => ( _optionalChain([planInput, 'optionalAccess', _123 => _123.request]))), () => ( {})));
|
|
1706
|
+
let plan = planInput;
|
|
1707
|
+
if (!plan && caps) {
|
|
1708
|
+
const resolved = _chunkFD4LPFAEcjs.resolvePrompt.call(void 0, options.rawPrompt, _nullishCoalesce(options.templates, () => ( [])), {
|
|
1709
|
+
bindings: options.bindings,
|
|
1710
|
+
values: options.values,
|
|
1711
|
+
maxDepth: options.maxDepth
|
|
1712
|
+
});
|
|
1713
|
+
plan = planGenerationRequest(settings, caps, {
|
|
1714
|
+
strategy: _nullishCoalesce(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 = _nullishCoalesce(seedInput, () => ( provenance.request.seed));
|
|
1725
|
+
return {
|
|
1726
|
+
format: GENERATION_RECORD_FORMAT,
|
|
1727
|
+
version: GENERATION_RECORD_VERSION,
|
|
1728
|
+
id: _nullishCoalesce(id, () => ( createGenerationRecordId())),
|
|
1729
|
+
...parentId !== void 0 ? { parentId } : {},
|
|
1730
|
+
kind: _nullishCoalesce(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: _nullishCoalesce(_nullishCoalesce(strategyInput, () => ( _optionalChain([plan, 'optionalAccess', _124 => _124.strategy]))), () => ( "nearest")),
|
|
1737
|
+
...seed !== void 0 ? { seed } : {},
|
|
1738
|
+
assets: recordAssets(provenance.request.references, assets),
|
|
1739
|
+
..._optionalChain([mentions, 'optionalAccess', _125 => _125.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(_nullishCoalesce(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 = { ..._nullishCoalesce(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 (e3) {
|
|
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 = _nullishCoalesce(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 = _chunkFD4LPFAEcjs.getTemplateBody.call(void 0, template, {});
|
|
1821
|
+
const hash = body === void 0 ? void 0 : hashText(body);
|
|
1822
|
+
if (hash === recorded.hash) continue;
|
|
1823
|
+
const latest = _chunkFD4LPFAEcjs.getLatestVersion.call(void 0, template);
|
|
1824
|
+
const toVersion = _optionalChain([template, 'access', _126 => _126.versions, 'optionalAccess', _127 => _127.length]) ? _nullishCoalesce(_optionalChain([latest, 'optionalAccess', _128 => _128.version]), () => ( _optionalChain([latest, 'optionalAccess', _129 => _129.id]))) : void 0;
|
|
1825
|
+
const versions = fromVersion !== void 0 || toVersion !== void 0 ? ` (${_nullishCoalesce(fromVersion, () => ( "unversioned"))} \u2192 ${_nullishCoalesce(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(_nullishCoalesce(cap.min, () => ( 0)));
|
|
1842
|
+
const max = Math.floor(_nullishCoalesce(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 = _nullishCoalesce(options.mode, () => ( "exact"));
|
|
1853
|
+
const provenance = record.provenance;
|
|
1854
|
+
const drift = templateDrift(record, options.templates, mode);
|
|
1855
|
+
const rawPrompt = _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _130 => _130.rawPrompt]), () => ( provenance.rawPrompt));
|
|
1856
|
+
const values = _optionalChain([overrides, 'optionalAccess', _131 => _131.values]) !== void 0 ? { ..._nullishCoalesce(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 = _chunkFD4LPFAEcjs.resolvePrompt.call(void 0, 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" && _optionalChain([record, 'access', _132 => _132.mentions, 'optionalAccess', _133 => _133.length])) {
|
|
1892
|
+
const plannedRole = new Map((_nullishCoalesce(recordedPlanned.references, () => ( []))).map((ref) => [ref.id, ref.role]));
|
|
1893
|
+
base.references = [
|
|
1894
|
+
..._nullishCoalesce(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 = { ..._nullishCoalesce(base.params, () => ( {})), ...clone2(params) };
|
|
1914
|
+
}
|
|
1915
|
+
if (overrides.seed === null) delete base.seed;
|
|
1916
|
+
else base.seed = _nullishCoalesce(overrides.seed, () => ( randomSeed(caps, record.seed, _nullishCoalesce(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 = _nullishCoalesce(_optionalChain([recordedById, 'access', _134 => _134.get, 'call', _135 => _135(refKey(ref)), 'optionalAccess', _136 => _136.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 "${_nullishCoalesce(caps.name, () => ( caps.id))}" changed since this generation.`
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
plan = planGenerationRequest(base, caps, {
|
|
1978
|
+
strategy: _nullishCoalesce(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(_nullishCoalesce(recordedPlanned.params, () => ( {}))), ...Object.keys(_nullishCoalesce(request.params, () => ( {})))]);
|
|
2004
|
+
for (const name of [...paramNames].sort()) {
|
|
2005
|
+
const from = _optionalChain([recordedPlanned, 'access', _137 => _137.params, 'optionalAccess', _138 => _138[name]]);
|
|
2006
|
+
const to = _optionalChain([request, 'access', _139 => _139.params, 'optionalAccess', _140 => _140[name]]);
|
|
2007
|
+
if (!sameValue(from, to)) describeChange(`params.${name}`, from, to);
|
|
2008
|
+
}
|
|
2009
|
+
if (!sameValue(_nullishCoalesce(record.seed, () => ( recordedPlanned.seed)), request.seed)) describeChange("seed", _nullishCoalesce(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 = (_nullishCoalesce(recordedPlanned.references, () => ( []))).map(refKey).filter((key) => !missing.has(key));
|
|
2012
|
+
const toRefs = (_nullishCoalesce(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: _nullishCoalesce(caps, () => ( provenance.modelId)),
|
|
2032
|
+
request,
|
|
2033
|
+
...plan ? { plan } : {},
|
|
2034
|
+
strategy: _nullishCoalesce(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, _nullishCoalesce(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 = _nullishCoalesce(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 (e4) {
|
|
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, _nullishCoalesce(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 (_optionalChain([prune, 'access', _141 => _141.keep, 'optionalCall', _142 => _142(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 (e5) {
|
|
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 (e6) {
|
|
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
|
+
}
|
|
2243
|
+
|
|
2244
|
+
|
|
2245
|
+
|
|
2246
|
+
|
|
2247
|
+
|
|
2248
|
+
|
|
2249
|
+
|
|
2250
|
+
|
|
2251
|
+
|
|
2252
|
+
|
|
2253
|
+
|
|
2254
|
+
|
|
2255
|
+
|
|
2256
|
+
|
|
2257
|
+
|
|
2258
|
+
|
|
2259
|
+
|
|
2260
|
+
|
|
2261
|
+
|
|
2262
|
+
|
|
2263
|
+
|
|
2264
|
+
|
|
2265
|
+
|
|
2266
|
+
|
|
2267
|
+
|
|
2268
|
+
|
|
2269
|
+
|
|
2270
|
+
|
|
2271
|
+
|
|
2272
|
+
|
|
2273
|
+
|
|
2274
|
+
|
|
2275
|
+
|
|
2276
|
+
|
|
2277
|
+
|
|
2278
|
+
|
|
2279
|
+
|
|
2280
|
+
|
|
2281
|
+
|
|
2282
|
+
|
|
2283
|
+
|
|
2284
|
+
|
|
2285
|
+
|
|
2286
|
+
|
|
2287
|
+
|
|
2288
|
+
|
|
2289
|
+
|
|
2290
|
+
|
|
2291
|
+
|
|
2292
|
+
|
|
2293
|
+
|
|
2294
|
+
|
|
2295
|
+
|
|
2296
|
+
|
|
2297
|
+
|
|
2298
|
+
|
|
2299
|
+
|
|
2300
|
+
|
|
2301
|
+
|
|
2302
|
+
|
|
2303
|
+
|
|
2304
|
+
|
|
2305
|
+
|
|
2306
|
+
|
|
2307
|
+
|
|
2308
|
+
|
|
2309
|
+
|
|
2310
|
+
|
|
2311
|
+
|
|
2312
|
+
|
|
2313
|
+
|
|
2314
|
+
|
|
2315
|
+
|
|
2316
|
+
exports.DRIFT_TYPE_LABELS = DRIFT_TYPE_LABELS; exports.GENERATION_RECORD_FORMAT = GENERATION_RECORD_FORMAT; exports.GENERATION_RECORD_VERSION = GENERATION_RECORD_VERSION; exports.GENERATION_REQUEST_FIELDS = GENERATION_REQUEST_FIELDS; exports.MAX_PENDING_PERCENT = MAX_PENDING_PERCENT; exports.PROVENANCE_FORMAT = PROVENANCE_FORMAT; exports.PROVENANCE_VERSION = PROVENANCE_VERSION; exports.ProvenanceParseError = ProvenanceParseError; exports.QUALITY_LADDER = QUALITY_LADDER; exports.REFERENCE_ROLES = REFERENCE_ROLES; exports.REFERENCE_ROLE_ALIASES = REFERENCE_ROLE_ALIASES; exports.REFERENCE_ROLE_LABELS = REFERENCE_ROLE_LABELS; exports.REFERENCE_ROLE_NAME_REGEX = REFERENCE_ROLE_NAME_REGEX; exports.addReference = addReference; exports.aspectRatioRank = aspectRatioRank; exports.blockingDrift = blockingDrift; exports.capabilitiesToJsonSchema = capabilitiesToJsonSchema; exports.completeGenerationRecord = completeGenerationRecord; exports.createBatchResolver = createBatchResolver; exports.createGenerationRecord = createGenerationRecord; exports.createGenerationRecordId = createGenerationRecordId; exports.createGenerationRecordStore = createGenerationRecordStore; exports.createGenerationToolProvider = createGenerationToolProvider; exports.createProvenance = createProvenance; exports.defaultAssetRoleOptions = defaultAssetRoleOptions; exports.describeAssetMentions = describeAssetMentions; exports.estimateJobProgress = estimateJobProgress; exports.expectedDurationFor = expectedDurationFor; exports.findTextMentions = _chunkBVP3TSLHcjs.findTextMentions; exports.formatMentionText = _chunkBVP3TSLHcjs.formatMentionText; exports.formatRemaining = formatRemaining; exports.getAssetRoleOptions = getAssetRoleOptions; exports.getGenerationControls = getGenerationControls; exports.getReferenceSlots = getReferenceSlots; exports.getRequestValue = getRequestValue; exports.hashCapabilities = hashCapabilities; exports.hashText = hashText; exports.hashValue = hashValue; exports.isGenerationRecord = isGenerationRecord; exports.isReferenceRoleName = isReferenceRoleName; exports.matchesRecordFilter = matchesRecordFilter; exports.mediaTypeMatches = mediaTypeMatches; exports.mergeCapabilities = mergeCapabilities; exports.normalizeReferenceRole = normalizeReferenceRole; exports.parseControlValue = parseControlValue; exports.parseGenerationRecord = parseGenerationRecord; exports.parseProvenance = parseProvenance; exports.pinnedTemplatesToTemplates = pinnedTemplatesToTemplates; exports.planGenerationRequest = planGenerationRequest; exports.qualityRank = qualityRank; exports.recreateRequest = recreateRequest; exports.referenceRoleLabel = referenceRoleLabel; exports.removeReference = removeReference; exports.replayProvenancePrompt = replayProvenancePrompt; exports.resolutionMegapixels = resolutionMegapixels; exports.resolutionRank = resolutionRank; exports.resolveAssetMentions = resolveAssetMentions; exports.seedCapability = seedCapability; exports.serializeGenerationRecord = serializeGenerationRecord; exports.serializeProvenance = serializeProvenance; exports.setMentionRoleInText = _chunkBVP3TSLHcjs.setMentionRoleInText; exports.setRequestValue = setRequestValue; exports.snapToOption = snapToOption; exports.stableStringify = stableStringify; exports.summarizeGenerationRecord = summarizeGenerationRecord; exports.supportedModes = supportedModes; exports.supportedReferenceRoles = supportedReferenceRoles; exports.textFieldCapability = textFieldCapability; exports.toAssetResolver = toAssetResolver; exports.validateAssetMentions = validateAssetMentions; exports.validateJsonSchema = _chunkCPOKFNBGcjs.validateJsonSchema; exports.variationRequest = variationRequest;
|
|
2317
|
+
//# sourceMappingURL=index.cjs.map
|