@rslsp1/fa-app-tools 2.0.73 → 2.0.81
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/dist/chunk-43TWCAG5.mjs +1299 -0
- package/dist/chunk-FUY2OCVC.mjs +157 -0
- package/dist/chunk-GEGJD43Y.mjs +11310 -0
- package/dist/{chunk-PVLOJQWS.mjs → chunk-VBWQP7PO.mjs} +113 -66
- package/dist/contracts-DdYOMBl9.d.mts +166 -0
- package/dist/contracts-DdYOMBl9.d.ts +166 -0
- package/dist/flowTextGenerationPort-CeDUFutP.d.mts +73 -0
- package/dist/flowTextGenerationPort-KHjCGt_S.d.ts +73 -0
- package/dist/{hfStateService-E5MHAF3M.mjs → hfStateService-WKQLNDHO.mjs} +3 -1
- package/dist/index.d.mts +397 -102
- package/dist/index.d.ts +397 -102
- package/dist/index.js +14013 -1365
- package/dist/index.mjs +2763 -1223
- package/dist/storeContract-B2BDgvhN.d.mts +1379 -0
- package/dist/storeContract-D7vBM8nv.d.ts +1379 -0
- package/dist/szenen-contract.d.mts +12 -0
- package/dist/szenen-contract.d.ts +12 -0
- package/dist/szenen-contract.js +1450 -0
- package/dist/szenen-contract.mjs +27 -0
- package/dist/szenen.d.mts +2747 -0
- package/dist/szenen.d.ts +2747 -0
- package/dist/szenen.js +14677 -0
- package/dist/szenen.mjs +1811 -0
- package/package.json +17 -4
package/dist/szenen.mjs
ADDED
|
@@ -0,0 +1,1811 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_PUBLISH_RULES,
|
|
3
|
+
CATALOGUE_TYPES,
|
|
4
|
+
CHAIN_EDGES,
|
|
5
|
+
CHAIN_LINK_FIELDS,
|
|
6
|
+
CapabilityAnchorError,
|
|
7
|
+
DERIVABLE_TYPES,
|
|
8
|
+
ELEMENT_VERSION_SCHEMA_FILE,
|
|
9
|
+
MAX_PROPOSAL_TITLE_LENGTH,
|
|
10
|
+
PROBE_VERSION_ID,
|
|
11
|
+
REFERENCE_FIELD,
|
|
12
|
+
RULES_WITHOUT_CAPABILITY_EFFECT,
|
|
13
|
+
RULE_SCOPES,
|
|
14
|
+
ResolveTechnicalError,
|
|
15
|
+
SIMULATION_PROVIDER,
|
|
16
|
+
SZENEN_ELEMENT_TYPES,
|
|
17
|
+
SZENEN_EVENT_PREFIX,
|
|
18
|
+
SZENEN_EVENT_TYPES,
|
|
19
|
+
SZENEN_ITEM_PREFIX,
|
|
20
|
+
SZENEN_SCHEMAS,
|
|
21
|
+
SzenenView,
|
|
22
|
+
UNCHECKED_PUBLISH_RULES,
|
|
23
|
+
UnsupportedSchemaError,
|
|
24
|
+
acceptProposalTitle,
|
|
25
|
+
areasFor,
|
|
26
|
+
assessDerivationResponse,
|
|
27
|
+
buildSystemInstruction,
|
|
28
|
+
buildSystemInstruction2,
|
|
29
|
+
buildUserPrompt,
|
|
30
|
+
buildUserPrompt2,
|
|
31
|
+
callOptional,
|
|
32
|
+
capabilitiesOf,
|
|
33
|
+
capabilityGate,
|
|
34
|
+
capabilityReport,
|
|
35
|
+
catalogueFor,
|
|
36
|
+
checkChainTargets,
|
|
37
|
+
checkCreateElementInput,
|
|
38
|
+
checkDerivationResponse,
|
|
39
|
+
checkDraftChainMeta,
|
|
40
|
+
checkElementType,
|
|
41
|
+
checkOptionalId,
|
|
42
|
+
checkParents,
|
|
43
|
+
checkPayloadPresent,
|
|
44
|
+
checkPublishVersionInput,
|
|
45
|
+
checkRequiredId,
|
|
46
|
+
checkReviseMetadataInput,
|
|
47
|
+
checkRevision,
|
|
48
|
+
checkRunResponse,
|
|
49
|
+
checkSetPreferredHeadInput,
|
|
50
|
+
checkSzenenBatchOrigin,
|
|
51
|
+
checkTitle,
|
|
52
|
+
checkWriteDraftInput,
|
|
53
|
+
collectPromptRuns,
|
|
54
|
+
collectSceneDerivationRecoveries,
|
|
55
|
+
collectSceneDerivations,
|
|
56
|
+
collectVersionRefs,
|
|
57
|
+
compileSchemas,
|
|
58
|
+
createClientDerivationPort,
|
|
59
|
+
createClientRunPort,
|
|
60
|
+
createEventLogDerivationPersistence,
|
|
61
|
+
createEventLogRunPersistence,
|
|
62
|
+
createFakeTextGenerationPort,
|
|
63
|
+
createFlowSzenenViewPort,
|
|
64
|
+
createFlowTextGenerationPort,
|
|
65
|
+
createHfElementStore,
|
|
66
|
+
createHfEventChannel,
|
|
67
|
+
createHfImageLibrary,
|
|
68
|
+
createSimulationSceneDerivationPort,
|
|
69
|
+
createSimulationTextGenerationPort,
|
|
70
|
+
derivationPoliciesOf,
|
|
71
|
+
deriveItemFromRun,
|
|
72
|
+
deriveLineage,
|
|
73
|
+
describeTargetModelFailure,
|
|
74
|
+
draftRevisionOf,
|
|
75
|
+
findPromptRun,
|
|
76
|
+
findSceneDerivation,
|
|
77
|
+
findSceneDerivationRecovery,
|
|
78
|
+
firstError,
|
|
79
|
+
formatSchemaErrors,
|
|
80
|
+
freezeDraftChain,
|
|
81
|
+
getSzenenSchemas,
|
|
82
|
+
hasPlacementCapability,
|
|
83
|
+
isKnownElementType,
|
|
84
|
+
isOk,
|
|
85
|
+
isProjectionCurrent,
|
|
86
|
+
isSzenenItemId,
|
|
87
|
+
itemIdForRun,
|
|
88
|
+
linkFor,
|
|
89
|
+
logRevisionOf,
|
|
90
|
+
mergeSzenenBatchOrigin,
|
|
91
|
+
noticeFor,
|
|
92
|
+
parseDerivationResponse,
|
|
93
|
+
parseRunResponse,
|
|
94
|
+
preferredHeadRevisionOf,
|
|
95
|
+
publishedHeadsOf,
|
|
96
|
+
recoveriesForRun,
|
|
97
|
+
recoveryStatusOf,
|
|
98
|
+
reduceElementEvents,
|
|
99
|
+
resolveArea,
|
|
100
|
+
resolveShot,
|
|
101
|
+
resolveShotPayload,
|
|
102
|
+
resolveTargetModelOver,
|
|
103
|
+
resolverFromQueries,
|
|
104
|
+
roundOfRun,
|
|
105
|
+
runPromptDerivation,
|
|
106
|
+
runPublishChecks,
|
|
107
|
+
runSceneDerivation,
|
|
108
|
+
scopeOfPath,
|
|
109
|
+
showChain,
|
|
110
|
+
simulatedAnswerFor,
|
|
111
|
+
unclassifiedPublishRules,
|
|
112
|
+
unsupportedReason,
|
|
113
|
+
validateAgainst,
|
|
114
|
+
validateDerivationInput,
|
|
115
|
+
validateElementVersion,
|
|
116
|
+
validatePayload,
|
|
117
|
+
withReference
|
|
118
|
+
} from "./chunk-GEGJD43Y.mjs";
|
|
119
|
+
import {
|
|
120
|
+
ContractViolation,
|
|
121
|
+
STYLE_PAYLOAD,
|
|
122
|
+
STYLE_PAYLOAD_V2,
|
|
123
|
+
elementStoreContractChecks,
|
|
124
|
+
runElementStoreContract
|
|
125
|
+
} from "./chunk-43TWCAG5.mjs";
|
|
126
|
+
import {
|
|
127
|
+
VersionDagError,
|
|
128
|
+
buildVersionDag,
|
|
129
|
+
preferredVersionId,
|
|
130
|
+
resolvePreferredHead
|
|
131
|
+
} from "./chunk-FUY2OCVC.mjs";
|
|
132
|
+
import "./chunk-VBWQP7PO.mjs";
|
|
133
|
+
|
|
134
|
+
// src/lib/szenen/providerCheckStore.ts
|
|
135
|
+
function collectProviderChecks(events) {
|
|
136
|
+
const byId = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const event of events) {
|
|
138
|
+
if (event.type !== SZENEN_EVENT_TYPES.providerCheckRecorded) continue;
|
|
139
|
+
const payload = event.payload;
|
|
140
|
+
if (!payload || typeof payload.check_id !== "string") continue;
|
|
141
|
+
if (!byId.has(payload.check_id)) byId.set(payload.check_id, payload);
|
|
142
|
+
}
|
|
143
|
+
return [...byId.values()];
|
|
144
|
+
}
|
|
145
|
+
function findProviderCheck(events, checkId) {
|
|
146
|
+
return collectProviderChecks(events).find((c) => c.check_id === checkId) ?? null;
|
|
147
|
+
}
|
|
148
|
+
function totalModelCalls(checks) {
|
|
149
|
+
return checks.reduce((summe, check) => summe + (Number(check.model_calls) || 0), 0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/lib/szenen/imageGenerationOrderStore.ts
|
|
153
|
+
function istText(wert) {
|
|
154
|
+
return typeof wert === "string" && wert.trim().length > 0;
|
|
155
|
+
}
|
|
156
|
+
function collectImageGenerationOrders(events) {
|
|
157
|
+
const byBatchId = /* @__PURE__ */ new Map();
|
|
158
|
+
for (const event of events) {
|
|
159
|
+
if (event.type !== SZENEN_EVENT_TYPES.imageGenerationStarted) continue;
|
|
160
|
+
const payload = event.payload;
|
|
161
|
+
if (!payload || !istText(payload.generation_batch_id) || !istText(payload.prompt_run_id)) continue;
|
|
162
|
+
if (byBatchId.has(payload.generation_batch_id)) continue;
|
|
163
|
+
byBatchId.set(payload.generation_batch_id, {
|
|
164
|
+
generation_batch_id: payload.generation_batch_id,
|
|
165
|
+
prompt_run_id: payload.prompt_run_id,
|
|
166
|
+
source_kind: "generated_in_app",
|
|
167
|
+
request: payload.request,
|
|
168
|
+
created_at: payload.created_at ?? "",
|
|
169
|
+
status: "started"
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
for (const event of events) {
|
|
173
|
+
if (event.type !== SZENEN_EVENT_TYPES.imageGenerationFinished) continue;
|
|
174
|
+
const payload = event.payload;
|
|
175
|
+
if (!payload || !istText(payload.generation_batch_id)) continue;
|
|
176
|
+
const auftrag = byBatchId.get(payload.generation_batch_id);
|
|
177
|
+
if (!auftrag) continue;
|
|
178
|
+
if (auftrag.status !== "started") continue;
|
|
179
|
+
if (payload.status !== "succeeded" && payload.status !== "partial" && payload.status !== "failed") continue;
|
|
180
|
+
byBatchId.set(payload.generation_batch_id, {
|
|
181
|
+
...auftrag,
|
|
182
|
+
status: payload.status,
|
|
183
|
+
...payload.item_id ? { item_id: payload.item_id } : {},
|
|
184
|
+
produced_count: payload.produced_count ?? 0,
|
|
185
|
+
...payload.diagnostic ? { diagnostic: payload.diagnostic } : {},
|
|
186
|
+
finished_at: payload.finished_at ?? ""
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return [...byBatchId.values()];
|
|
190
|
+
}
|
|
191
|
+
function ordersForPromptRun(events, runId) {
|
|
192
|
+
return collectImageGenerationOrders(events).filter((o) => o.prompt_run_id === runId);
|
|
193
|
+
}
|
|
194
|
+
function findImageGenerationOrder(events, batchId) {
|
|
195
|
+
return collectImageGenerationOrders(events).find((o) => o.generation_batch_id === batchId) ?? null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/lib/szenen/inMemoryEventChannel.ts
|
|
199
|
+
function createInMemoryEventChannel(options = {}) {
|
|
200
|
+
const log = options.shared ?? [];
|
|
201
|
+
let tick = 0;
|
|
202
|
+
const now = options.now ?? (() => ++tick);
|
|
203
|
+
const clientId = options.clientId ?? "client-a";
|
|
204
|
+
const channel = {
|
|
205
|
+
get events() {
|
|
206
|
+
return log;
|
|
207
|
+
},
|
|
208
|
+
async readEvents() {
|
|
209
|
+
return log.map((event) => ({ ...event }));
|
|
210
|
+
},
|
|
211
|
+
async appendEvent(type, payload) {
|
|
212
|
+
log.push({ type, payload, clientId, ts: now() });
|
|
213
|
+
},
|
|
214
|
+
appendRaw(event) {
|
|
215
|
+
log.push(event);
|
|
216
|
+
},
|
|
217
|
+
withClient(otherClientId) {
|
|
218
|
+
return createInMemoryEventChannel({ clientId: otherClientId, now, shared: log });
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
return channel;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/lib/szenen/storeDifferential.ts
|
|
225
|
+
var IGNORED_FIELDS = /* @__PURE__ */ new Set([
|
|
226
|
+
"message",
|
|
227
|
+
/** Der schreibende Client heißt je Untergrund anders. */
|
|
228
|
+
"updated_by_client",
|
|
229
|
+
/** Unterscheidet sich zwangsläufig und sagt fachlich nichts. */
|
|
230
|
+
"server_received_at"
|
|
231
|
+
]);
|
|
232
|
+
function normalize(value, state) {
|
|
233
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
234
|
+
replacements.set(state.elementId, "<element>");
|
|
235
|
+
state.versionIds.forEach((id, i) => replacements.set(id, `<version:${i + 1}>`));
|
|
236
|
+
if (state.draftId) replacements.set(state.draftId, "<draft>");
|
|
237
|
+
const UUID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;
|
|
238
|
+
const walk = (node) => {
|
|
239
|
+
if (typeof node === "string") {
|
|
240
|
+
if (replacements.has(node)) return replacements.get(node);
|
|
241
|
+
return node.replace(UUID, (match) => replacements.get(match) ?? "<uuid>");
|
|
242
|
+
}
|
|
243
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
244
|
+
if (node && typeof node === "object") {
|
|
245
|
+
const out = {};
|
|
246
|
+
for (const key of Object.keys(node).sort()) {
|
|
247
|
+
if (IGNORED_FIELDS.has(key)) continue;
|
|
248
|
+
out[key] = walk(node[key]);
|
|
249
|
+
}
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
return node;
|
|
253
|
+
};
|
|
254
|
+
return walk(value);
|
|
255
|
+
}
|
|
256
|
+
function differentialSteps() {
|
|
257
|
+
const shape = (result) => result;
|
|
258
|
+
return [
|
|
259
|
+
{
|
|
260
|
+
name: "createElement",
|
|
261
|
+
async run(store, state) {
|
|
262
|
+
const result = await store.createElement({
|
|
263
|
+
type: "style",
|
|
264
|
+
title: "Kohle",
|
|
265
|
+
contextId: "diff",
|
|
266
|
+
description: "erste Notiz"
|
|
267
|
+
});
|
|
268
|
+
if (result.kind === "ok") state.elementId = result.value.element_id;
|
|
269
|
+
return shape(result);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: "writeDraft (erste Revision)",
|
|
274
|
+
async run(store, state) {
|
|
275
|
+
const result = await store.writeDraft({
|
|
276
|
+
elementId: state.elementId,
|
|
277
|
+
payload: STYLE_PAYLOAD,
|
|
278
|
+
expectedRevision: 0
|
|
279
|
+
});
|
|
280
|
+
if (result.kind === "ok") state.draftId = result.value.draft_id;
|
|
281
|
+
return shape(result);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: "writeDraft mit veralteter Revision \u2192 conflict",
|
|
286
|
+
async run(store, state) {
|
|
287
|
+
return shape(
|
|
288
|
+
await store.writeDraft({
|
|
289
|
+
elementId: state.elementId,
|
|
290
|
+
payload: STYLE_PAYLOAD_V2,
|
|
291
|
+
expectedRevision: 0
|
|
292
|
+
})
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "writeDraft mit unbekannter base_version_id \u2192 error",
|
|
298
|
+
async run(store, state) {
|
|
299
|
+
return shape(
|
|
300
|
+
await store.writeDraft({
|
|
301
|
+
elementId: state.elementId,
|
|
302
|
+
payload: STYLE_PAYLOAD,
|
|
303
|
+
expectedRevision: 1,
|
|
304
|
+
baseVersionId: "00000000-0000-7000-8000-0000000affff"
|
|
305
|
+
})
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: "publishVersion",
|
|
311
|
+
async run(store, state) {
|
|
312
|
+
const result = await store.publishVersion({
|
|
313
|
+
elementId: state.elementId,
|
|
314
|
+
payload: STYLE_PAYLOAD,
|
|
315
|
+
schemaVersion: "1.0.0",
|
|
316
|
+
publishedBy: "diff"
|
|
317
|
+
});
|
|
318
|
+
if (result.kind === "ok") state.versionIds.push(result.value.version_id);
|
|
319
|
+
return shape(result);
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: "publishVersion mit derived_from",
|
|
324
|
+
async run(store, state) {
|
|
325
|
+
const result = await store.publishVersion({
|
|
326
|
+
elementId: state.elementId,
|
|
327
|
+
payload: STYLE_PAYLOAD_V2,
|
|
328
|
+
schemaVersion: "1.0.0",
|
|
329
|
+
publishedBy: "diff",
|
|
330
|
+
parents: [{ parent_version_id: state.versionIds[0], relation: "derived_from" }]
|
|
331
|
+
});
|
|
332
|
+
if (result.kind === "ok") state.versionIds.push(result.value.version_id);
|
|
333
|
+
return shape(result);
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: "publishVersion schemawidrig \u2192 rejected",
|
|
338
|
+
async run(store, state) {
|
|
339
|
+
return shape(
|
|
340
|
+
await store.publishVersion({
|
|
341
|
+
elementId: state.elementId,
|
|
342
|
+
payload: { role: "gibt-es-nicht", name: "X", text: "Y", locale: "de" },
|
|
343
|
+
schemaVersion: "1.0.0",
|
|
344
|
+
publishedBy: "diff"
|
|
345
|
+
})
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
name: "createElement mit unbekanntem Typ \u2192 error",
|
|
351
|
+
async run(store) {
|
|
352
|
+
return shape(await store.createElement({ type: "weltmodell", title: "X" }));
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
name: "reviseMetadata ohne description (\xA78)",
|
|
357
|
+
async run(store, state) {
|
|
358
|
+
if (!store.reviseMetadata) return shape({ kind: "unsupported", capability: "reviseMetadata" });
|
|
359
|
+
return shape(
|
|
360
|
+
await store.reviseMetadata({
|
|
361
|
+
elementId: state.elementId,
|
|
362
|
+
title: "Neu",
|
|
363
|
+
expectedRevision: 1
|
|
364
|
+
})
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "setPreferredHead",
|
|
370
|
+
async run(store, state) {
|
|
371
|
+
if (!store.setPreferredHead) {
|
|
372
|
+
return shape({ kind: "unsupported", capability: "setPreferredHead" });
|
|
373
|
+
}
|
|
374
|
+
return shape(
|
|
375
|
+
await store.setPreferredHead({
|
|
376
|
+
elementId: state.elementId,
|
|
377
|
+
contextId: "diff",
|
|
378
|
+
versionId: state.versionIds[1],
|
|
379
|
+
expectedRevision: 0,
|
|
380
|
+
selectedBy: "diff"
|
|
381
|
+
})
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: "getElement (vollstaendiger Stand)",
|
|
387
|
+
async run(store, state) {
|
|
388
|
+
return shape(await store.getElement(state.elementId));
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: "listElements im Kontext",
|
|
393
|
+
async run(store) {
|
|
394
|
+
return shape(await store.listElements({ contextId: "diff" }));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
];
|
|
398
|
+
}
|
|
399
|
+
async function runStoreDifferential(left, right) {
|
|
400
|
+
const steps = differentialSteps();
|
|
401
|
+
const leftStore = await left();
|
|
402
|
+
const rightStore = await right();
|
|
403
|
+
const leftState = { elementId: "", versionIds: [], draftId: null };
|
|
404
|
+
const rightState = { elementId: "", versionIds: [], draftId: null };
|
|
405
|
+
const divergences = [];
|
|
406
|
+
for (const step of steps) {
|
|
407
|
+
const leftRaw = await step.run(leftStore, leftState);
|
|
408
|
+
const rightRaw = await step.run(rightStore, rightState);
|
|
409
|
+
const leftText = JSON.stringify(normalize(leftRaw, leftState));
|
|
410
|
+
const rightText = JSON.stringify(normalize(rightRaw, rightState));
|
|
411
|
+
if (leftText !== rightText) {
|
|
412
|
+
divergences.push({ step: step.name, left: leftText, right: rightText });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return { steps: steps.length, divergences, identical: divergences.length === 0 };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/lib/szenen/imageGenerationCapability.ts
|
|
419
|
+
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
420
|
+
var IMAGE_MODEL_CATALOGUE = {
|
|
421
|
+
imagen_4: {
|
|
422
|
+
callable_model_id: "imagen-4.0-generate-001",
|
|
423
|
+
provider: "google",
|
|
424
|
+
max_images: 4,
|
|
425
|
+
aspect_ratios: ["1:1", "3:4", "4:3", "9:16", "16:9"],
|
|
426
|
+
supports_seed: true
|
|
427
|
+
},
|
|
428
|
+
imagen_3: {
|
|
429
|
+
callable_model_id: "imagen-3.0-generate-001",
|
|
430
|
+
provider: "google",
|
|
431
|
+
max_images: 4,
|
|
432
|
+
aspect_ratios: ["1:1", "3:4", "4:3", "9:16", "16:9"],
|
|
433
|
+
supports_seed: true
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
function callableImageModelFor(targetModelKey) {
|
|
437
|
+
return IMAGE_MODEL_CATALOGUE[targetModelKey] ?? null;
|
|
438
|
+
}
|
|
439
|
+
function targetModelKeyOf(targetModel) {
|
|
440
|
+
if (!isObject(targetModel)) return null;
|
|
441
|
+
return typeof targetModel.key === "string" && targetModel.key.length > 0 ? targetModel.key : null;
|
|
442
|
+
}
|
|
443
|
+
function capabilityForTargetModel(targetModel, hasAccess) {
|
|
444
|
+
const key = targetModelKeyOf(targetModel);
|
|
445
|
+
if (!key) {
|
|
446
|
+
return {
|
|
447
|
+
kind: "unsupported",
|
|
448
|
+
target_model_key: "(unbekannt)",
|
|
449
|
+
reason: 'Der eingefrorene Lauf tr\xE4gt kein "target_model.key" \u2014 es gibt nichts zuzuordnen.'
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
const modell = callableImageModelFor(key);
|
|
453
|
+
if (!modell) {
|
|
454
|
+
return {
|
|
455
|
+
kind: "unsupported",
|
|
456
|
+
target_model_key: key,
|
|
457
|
+
reason: `F\xFCr das Zielmodell "${key}" ist in diesem Host kein Bildpfad katalogisiert.`
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
if (!hasAccess(modell)) {
|
|
461
|
+
return {
|
|
462
|
+
kind: "unsupported",
|
|
463
|
+
target_model_key: key,
|
|
464
|
+
reason: `Dieser Host hat keinen Zugang zu ${modell.callable_model_id} (${modell.provider}).`
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
kind: "supported",
|
|
469
|
+
target_model_key: key,
|
|
470
|
+
provider: modell.provider,
|
|
471
|
+
callable_model_id: modell.callable_model_id,
|
|
472
|
+
max_images: modell.max_images,
|
|
473
|
+
aspect_ratios: modell.aspect_ratios,
|
|
474
|
+
supports_seed: modell.supports_seed
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/lib/szenen/imageGenerationPort.ts
|
|
479
|
+
function queryError(error, action) {
|
|
480
|
+
return {
|
|
481
|
+
kind: "error",
|
|
482
|
+
message: `${action}: ${error instanceof Error ? error.message : String(error)}`,
|
|
483
|
+
retryable: true
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function createImageGenerationPort(options) {
|
|
487
|
+
const { runs, provider, batches, events, hasAccess } = options;
|
|
488
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
489
|
+
async function readRun(runId) {
|
|
490
|
+
try {
|
|
491
|
+
return await runs.getRun(runId);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
return queryError(error, `Lauf ${runId} konnte nicht gelesen werden`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
async capabilityForRun(runId) {
|
|
498
|
+
const gelesen = await readRun(runId);
|
|
499
|
+
if (gelesen.kind !== "ok") return gelesen;
|
|
500
|
+
if (!gelesen.value) {
|
|
501
|
+
return { kind: "error", message: `Lauf ${runId} ist unbekannt.`, retryable: false };
|
|
502
|
+
}
|
|
503
|
+
const targetModel = gelesen.value.input_payload?.target_model;
|
|
504
|
+
return { kind: "ok", value: capabilityForTargetModel(targetModel, hasAccess) };
|
|
505
|
+
},
|
|
506
|
+
async startFromPromptRun(input) {
|
|
507
|
+
const gelesen = await readRun(input.runId);
|
|
508
|
+
if (gelesen.kind !== "ok") return { kind: "rejected", message: gelesen.message };
|
|
509
|
+
if (!gelesen.value) {
|
|
510
|
+
return { kind: "rejected", message: `Lauf ${input.runId} ist unbekannt.` };
|
|
511
|
+
}
|
|
512
|
+
const run = gelesen.value;
|
|
513
|
+
if (run.status !== "succeeded" || !run.output) {
|
|
514
|
+
return {
|
|
515
|
+
kind: "rejected",
|
|
516
|
+
message: `Lauf ${input.runId} ist nicht erfolgreich \u2014 ein Bildauftrag braucht einen eingefrorenen Prompt (D-103).`
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
const targetModel = run.input_payload?.target_model;
|
|
520
|
+
const capability = capabilityForTargetModel(targetModel, hasAccess);
|
|
521
|
+
if (capability.kind !== "supported") {
|
|
522
|
+
return { kind: "unsupported", targetModelKey: capability.target_model_key, reason: capability.reason };
|
|
523
|
+
}
|
|
524
|
+
const startedPayload = {
|
|
525
|
+
generation_batch_id: input.generationBatchId,
|
|
526
|
+
prompt_run_id: input.runId,
|
|
527
|
+
source_kind: "generated_in_app",
|
|
528
|
+
request: {
|
|
529
|
+
image_count: input.imageCount,
|
|
530
|
+
...input.aspectRatio ? { aspect_ratio: input.aspectRatio } : {},
|
|
531
|
+
...input.seeds ? { seeds: input.seeds } : {},
|
|
532
|
+
callable_model_id: capability.callable_model_id
|
|
533
|
+
},
|
|
534
|
+
created_at: now().toISOString()
|
|
535
|
+
};
|
|
536
|
+
try {
|
|
537
|
+
await events.appendEvent(SZENEN_EVENT_TYPES.imageGenerationStarted, startedPayload);
|
|
538
|
+
} catch (error) {
|
|
539
|
+
return {
|
|
540
|
+
kind: "failed",
|
|
541
|
+
message: `Der Auftrag ${input.generationBatchId} konnte nicht protokolliert werden: ${error instanceof Error ? error.message : String(error)}`
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
let produced = [];
|
|
545
|
+
let providerFehler = null;
|
|
546
|
+
try {
|
|
547
|
+
const antwort = await provider.generate({
|
|
548
|
+
callableModelId: capability.callable_model_id,
|
|
549
|
+
provider: capability.provider,
|
|
550
|
+
positivePrompt: run.output.positive,
|
|
551
|
+
negativePrompt: run.output.negative,
|
|
552
|
+
imageCount: input.imageCount,
|
|
553
|
+
...input.aspectRatio ? { aspectRatio: input.aspectRatio } : {},
|
|
554
|
+
...input.seeds ? { seeds: input.seeds } : {}
|
|
555
|
+
});
|
|
556
|
+
produced = antwort.images;
|
|
557
|
+
} catch (error) {
|
|
558
|
+
providerFehler = error instanceof Error ? error.message : String(error);
|
|
559
|
+
}
|
|
560
|
+
if (providerFehler || produced.length === 0) {
|
|
561
|
+
const finishedPayload2 = {
|
|
562
|
+
generation_batch_id: input.generationBatchId,
|
|
563
|
+
status: "failed",
|
|
564
|
+
produced_count: 0,
|
|
565
|
+
diagnostic: providerFehler ?? "Der Provider hat kein verwertbares Bild geliefert.",
|
|
566
|
+
finished_at: now().toISOString()
|
|
567
|
+
};
|
|
568
|
+
await events.appendEvent(SZENEN_EVENT_TYPES.imageGenerationFinished, finishedPayload2).catch(() => {
|
|
569
|
+
});
|
|
570
|
+
return {
|
|
571
|
+
kind: "failed",
|
|
572
|
+
message: finishedPayload2.diagnostic
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
const persistiert = await batches.persist({
|
|
576
|
+
runId: input.runId,
|
|
577
|
+
generationBatchId: input.generationBatchId,
|
|
578
|
+
images: produced
|
|
579
|
+
});
|
|
580
|
+
if (persistiert.kind !== "ok") {
|
|
581
|
+
const finishedPayload2 = {
|
|
582
|
+
generation_batch_id: input.generationBatchId,
|
|
583
|
+
status: "failed",
|
|
584
|
+
produced_count: 0,
|
|
585
|
+
diagnostic: persistiert.kind === "error" ? persistiert.message : `Batch ${input.generationBatchId} konnte nicht gespeichert werden (${persistiert.kind}).`,
|
|
586
|
+
finished_at: now().toISOString()
|
|
587
|
+
};
|
|
588
|
+
await events.appendEvent(SZENEN_EVENT_TYPES.imageGenerationFinished, finishedPayload2).catch(() => {
|
|
589
|
+
});
|
|
590
|
+
return { kind: "failed", message: finishedPayload2.diagnostic };
|
|
591
|
+
}
|
|
592
|
+
const istPartial = produced.length < input.imageCount;
|
|
593
|
+
const finishedPayload = {
|
|
594
|
+
generation_batch_id: input.generationBatchId,
|
|
595
|
+
status: istPartial ? "partial" : "succeeded",
|
|
596
|
+
item_id: persistiert.value.item_id,
|
|
597
|
+
produced_count: produced.length,
|
|
598
|
+
finished_at: now().toISOString()
|
|
599
|
+
};
|
|
600
|
+
await events.appendEvent(SZENEN_EVENT_TYPES.imageGenerationFinished, finishedPayload).catch(() => {
|
|
601
|
+
});
|
|
602
|
+
return istPartial ? { kind: "partial", batch: persistiert.value, requested: input.imageCount, produced: produced.length } : { kind: "succeeded", batch: persistiert.value };
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// src/lib/szenen/memoryViewPort.ts
|
|
608
|
+
function ok(value) {
|
|
609
|
+
return { kind: "ok", value };
|
|
610
|
+
}
|
|
611
|
+
function done(value) {
|
|
612
|
+
return { kind: "ok", value };
|
|
613
|
+
}
|
|
614
|
+
var laufender = 0;
|
|
615
|
+
var defaultIds = () => `mem-${Date.now().toString(36)}-${(laufender += 1).toString(36)}`;
|
|
616
|
+
function simulierterLauf(input, runId) {
|
|
617
|
+
return {
|
|
618
|
+
run_id: runId,
|
|
619
|
+
shot_version_id: input.shotVersionId,
|
|
620
|
+
shot_element_id: `element-of-${input.shotVersionId}`,
|
|
621
|
+
scene_setup_version_id: "setup-simuliert",
|
|
622
|
+
camera_id: "kamera-simuliert",
|
|
623
|
+
target_model_version_id: "zielmodell-simuliert",
|
|
624
|
+
// Sichtbar als Simulation, nicht als echter Anbieter.
|
|
625
|
+
provider: "simulation",
|
|
626
|
+
model_id: "simulation",
|
|
627
|
+
system_prompt: "(simuliert)",
|
|
628
|
+
input_payload: {},
|
|
629
|
+
status: "succeeded",
|
|
630
|
+
failure: null,
|
|
631
|
+
output: {
|
|
632
|
+
positive: `Simulierter positiver Prompt f\xFCr ${input.shotVersionId}` + (input.userInstruction ? ` \u2014 Anweisung: ${input.userInstruction}` : ""),
|
|
633
|
+
negative: "Simulierter negativer Prompt",
|
|
634
|
+
feedback: "Simulierter Lauf \u2014 kein Anbieter beteiligt.",
|
|
635
|
+
visibility: { basis: "assumed", nodes: [], assumptions: ["Simulierter Lauf ohne Anbieter"] },
|
|
636
|
+
notes: []
|
|
637
|
+
},
|
|
638
|
+
raw_output: null,
|
|
639
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function simulierteRekonstruktion(input, runId) {
|
|
643
|
+
return {
|
|
644
|
+
run_id: runId,
|
|
645
|
+
policy_version_id: input.policyVersionId,
|
|
646
|
+
policy_element_id: `element-of-${input.policyVersionId}`,
|
|
647
|
+
context_id: input.contextId ?? null,
|
|
648
|
+
provider: "simulation",
|
|
649
|
+
model_id: "simulation",
|
|
650
|
+
system_prompt: "(simuliert)",
|
|
651
|
+
// D-73: die Herkunft, nie die Bilddaten.
|
|
652
|
+
input: {
|
|
653
|
+
mode: input.mode,
|
|
654
|
+
prompt_text: input.promptText ?? null,
|
|
655
|
+
images: (input.images ?? []).map((b) => b.provenance)
|
|
656
|
+
},
|
|
657
|
+
status: "succeeded",
|
|
658
|
+
failure: null,
|
|
659
|
+
proposals: [
|
|
660
|
+
{
|
|
661
|
+
type: "scene",
|
|
662
|
+
payload: {
|
|
663
|
+
nodes: [
|
|
664
|
+
{ node_id: "simuliert", type: "subject", semantic: { description: "simuliert" } }
|
|
665
|
+
],
|
|
666
|
+
relations: []
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
],
|
|
670
|
+
feedback: "Simulierte Rekonstruktion \u2014 kein Anbieter beteiligt.",
|
|
671
|
+
assumptions: ["Simulierter Lauf ohne Anbieter"],
|
|
672
|
+
not_derivable: [{ field: "/", reason: "Ohne Modell ist nichts ableitbar." }],
|
|
673
|
+
conflicts: [],
|
|
674
|
+
raw_output: null,
|
|
675
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
function createMemoryViewPort(options = {}) {
|
|
679
|
+
const ids = options.ids ?? defaultIds;
|
|
680
|
+
const elements = createHfElementStore({ channel: createInMemoryEventChannel() });
|
|
681
|
+
const laeufe = [...options.runs ?? []];
|
|
682
|
+
const items = /* @__PURE__ */ new Map();
|
|
683
|
+
const versionMedien = /* @__PURE__ */ new Map();
|
|
684
|
+
const itemMedien = /* @__PURE__ */ new Map();
|
|
685
|
+
const runs = {
|
|
686
|
+
async listRunsForShot(shotVersionId) {
|
|
687
|
+
return ok(laeufe.filter((l) => l.shot_version_id === shotVersionId));
|
|
688
|
+
},
|
|
689
|
+
async getRun(runId) {
|
|
690
|
+
return ok(laeufe.find((l) => l.run_id === runId) ?? null);
|
|
691
|
+
},
|
|
692
|
+
async startRun(input) {
|
|
693
|
+
const runId = ids();
|
|
694
|
+
const lauf = (options.deriveRun ?? simulierterLauf)(input, runId);
|
|
695
|
+
laeufe.push(lauf);
|
|
696
|
+
return done(lauf);
|
|
697
|
+
},
|
|
698
|
+
// ── Der Lauf aus einer Draft-Kette (Stufe 6.6, C3) ────────────────────
|
|
699
|
+
//
|
|
700
|
+
// Der Speicherport bildet die Form ab: ein Lauf mit `source.kind ===
|
|
701
|
+
// 'draft_chain'` und ohne Versionskennungen. Ob eine Kette gueltig ist und
|
|
702
|
+
// ob das Einfrieren traegt, entscheidet `clientRunPort` gegen einen echten
|
|
703
|
+
// Speicher — hier waere es eine zweite Wahrheit.
|
|
704
|
+
async startRunFromDraft(input) {
|
|
705
|
+
const runId = ids();
|
|
706
|
+
const basis = (options.deriveRun ?? simulierterLauf)(
|
|
707
|
+
{ shotVersionId: "", ...input.userInstruction ? { userInstruction: input.userInstruction } : {} },
|
|
708
|
+
runId
|
|
709
|
+
);
|
|
710
|
+
const lauf = {
|
|
711
|
+
...basis,
|
|
712
|
+
shot_version_id: "",
|
|
713
|
+
shot_element_id: input.shotElementId,
|
|
714
|
+
scene_setup_version_id: "",
|
|
715
|
+
source: {
|
|
716
|
+
kind: "draft_chain",
|
|
717
|
+
chain_id: `kette-${runId}`,
|
|
718
|
+
nodes: [{
|
|
719
|
+
type: "shot",
|
|
720
|
+
element_id: input.shotElementId,
|
|
721
|
+
draft_id: `draft-${input.shotElementId}`,
|
|
722
|
+
revision: 1
|
|
723
|
+
}]
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
laeufe.push(lauf);
|
|
727
|
+
return done(lauf);
|
|
728
|
+
},
|
|
729
|
+
async listRunsForChain(chainId) {
|
|
730
|
+
return ok(laeufe.filter(
|
|
731
|
+
(r) => r.source?.kind === "draft_chain" && r.source.chain_id === chainId
|
|
732
|
+
));
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
const itemPort = {
|
|
736
|
+
async getItemForRun(runId) {
|
|
737
|
+
return ok(items.get(runId) ?? null);
|
|
738
|
+
},
|
|
739
|
+
async saveRunAsItem(input) {
|
|
740
|
+
const lauf = laeufe.find((l) => l.run_id === input.runId);
|
|
741
|
+
if (!lauf) {
|
|
742
|
+
return { kind: "error", message: `Lauf ${input.runId} ist unbekannt.`, retryable: false };
|
|
743
|
+
}
|
|
744
|
+
if (lauf.status !== "succeeded") {
|
|
745
|
+
return {
|
|
746
|
+
kind: "error",
|
|
747
|
+
message: `Lauf ${input.runId} ist fehlgeschlagen \u2014 aus einem Fehlerlauf entsteht kein Item.`,
|
|
748
|
+
retryable: false
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
const bestehend = items.get(input.runId);
|
|
752
|
+
if (bestehend) return done({ reference: bestehend, created: false });
|
|
753
|
+
const referenz = {
|
|
754
|
+
itemId: itemIdForRun(input.runId),
|
|
755
|
+
title: input.title ?? `Runde aus ${input.runId}`,
|
|
756
|
+
item: null
|
|
757
|
+
};
|
|
758
|
+
items.set(input.runId, referenz);
|
|
759
|
+
return done({ reference: referenz, created: true });
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
const mediaPort = {
|
|
763
|
+
async listVersionMedia(versionId) {
|
|
764
|
+
return ok([...versionMedien.get(versionId) ?? []].sort((a, b) => a.position - b.position));
|
|
765
|
+
},
|
|
766
|
+
async listItemMedia(itemId) {
|
|
767
|
+
return ok([...itemMedien.get(itemId) ?? []].sort((a, b) => a.position - b.position));
|
|
768
|
+
},
|
|
769
|
+
async attachVersionMedium(input) {
|
|
770
|
+
const vorhanden = versionMedien.get(input.versionId) ?? [];
|
|
771
|
+
const schon = vorhanden.find((m) => m.assetId === input.assetId && m.role === input.role);
|
|
772
|
+
if (schon) return done(schon);
|
|
773
|
+
const medium = {
|
|
774
|
+
assetId: input.assetId,
|
|
775
|
+
role: input.role,
|
|
776
|
+
position: input.position ?? vorhanden.length,
|
|
777
|
+
url: null
|
|
778
|
+
};
|
|
779
|
+
versionMedien.set(input.versionId, [...vorhanden, medium]);
|
|
780
|
+
return done(medium);
|
|
781
|
+
},
|
|
782
|
+
async detachVersionMedium(input) {
|
|
783
|
+
const vorhanden = versionMedien.get(input.versionId) ?? [];
|
|
784
|
+
const rest = vorhanden.filter((m) => !(m.assetId === input.assetId && m.role === input.role));
|
|
785
|
+
versionMedien.set(input.versionId, rest);
|
|
786
|
+
return done({ removed: rest.length !== vorhanden.length });
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
const rekonstruktionen = [];
|
|
790
|
+
const fassungen = [];
|
|
791
|
+
const uebernommen = /* @__PURE__ */ new Map();
|
|
792
|
+
const derivationPort = {
|
|
793
|
+
async listPolicies() {
|
|
794
|
+
return ok(options.policies ?? [{
|
|
795
|
+
elementId: "policy-element",
|
|
796
|
+
versionId: "policy-version",
|
|
797
|
+
title: "Testregel",
|
|
798
|
+
inputModes: ["prompt", "image", "image_prompt"],
|
|
799
|
+
produces: ["scene"]
|
|
800
|
+
}]);
|
|
801
|
+
},
|
|
802
|
+
async getDerivation(runId) {
|
|
803
|
+
return ok(rekonstruktionen.find((r) => r.run_id === runId) ?? null);
|
|
804
|
+
},
|
|
805
|
+
async startDerivation(input) {
|
|
806
|
+
const runId = ids();
|
|
807
|
+
const lauf = (options.deriveScene ?? simulierteRekonstruktion)(input, runId);
|
|
808
|
+
rekonstruktionen.push(lauf);
|
|
809
|
+
return done(lauf);
|
|
810
|
+
},
|
|
811
|
+
async adoptProposal(input) {
|
|
812
|
+
const lauf = rekonstruktionen.find((r) => r.run_id === input.runId);
|
|
813
|
+
if (!lauf) {
|
|
814
|
+
return { kind: "error", message: `Lauf ${input.runId} ist unbekannt.`, retryable: false };
|
|
815
|
+
}
|
|
816
|
+
const schluessel = `${input.runId}:${input.type}`;
|
|
817
|
+
const schon = uebernommen.get(schluessel);
|
|
818
|
+
if (schon) return done({ runId: input.runId, type: input.type, elementId: schon });
|
|
819
|
+
const elementId = ids();
|
|
820
|
+
uebernommen.set(schluessel, elementId);
|
|
821
|
+
return done({ runId: input.runId, type: input.type, elementId });
|
|
822
|
+
},
|
|
823
|
+
// ── Graph-Uebernahme (Stufe 6.6) ──────────────────────────────────────
|
|
824
|
+
//
|
|
825
|
+
// Der Speicherport bildet die **Form** ab, nicht die Fachlichkeit: eine
|
|
826
|
+
// Kette mit einer chain_id und je Typ einem Knoten. Ob Vertraege halten
|
|
827
|
+
// und Links stimmen, entscheidet `clientDerivationPort` gegen einen echten
|
|
828
|
+
// Speicher — hier waere es eine zweite Wahrheit.
|
|
829
|
+
async adoptProposalGraph(input) {
|
|
830
|
+
if ((input.runId ? 1 : 0) + (input.recoveryId ? 1 : 0) !== 1) {
|
|
831
|
+
return {
|
|
832
|
+
kind: "error",
|
|
833
|
+
message: "Eine Graph-Uebernahme braucht genau einen Ursprung.",
|
|
834
|
+
retryable: false
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const lauf = rekonstruktionen.find((r) => r.run_id === input.runId) ?? rekonstruktionen.find(
|
|
838
|
+
(r) => r.run_id === fassungen.find((f) => f.recovery_id === input.recoveryId)?.run_id
|
|
839
|
+
);
|
|
840
|
+
if (!lauf) {
|
|
841
|
+
return { kind: "error", message: "Ursprung ist unbekannt.", retryable: false };
|
|
842
|
+
}
|
|
843
|
+
const gewuenscht = input.types ?? lauf.proposals.map((p) => p.type);
|
|
844
|
+
const chainId = ids();
|
|
845
|
+
const created = gewuenscht.map((type) => ({
|
|
846
|
+
type,
|
|
847
|
+
elementId: ids(),
|
|
848
|
+
draftId: ids(),
|
|
849
|
+
revision: 1
|
|
850
|
+
}));
|
|
851
|
+
return done({
|
|
852
|
+
chainId,
|
|
853
|
+
sourceRunId: lauf.run_id,
|
|
854
|
+
...input.recoveryId ? { sourceRecoveryId: input.recoveryId } : {},
|
|
855
|
+
created,
|
|
856
|
+
missing: [],
|
|
857
|
+
complete: true
|
|
858
|
+
});
|
|
859
|
+
},
|
|
860
|
+
// ── Fehlerrettung (Stufe 6.6) ─────────────────────────────────────────
|
|
861
|
+
//
|
|
862
|
+
// Der Speicherport simuliert nicht den Parser: Er haelt Fassungen und gibt
|
|
863
|
+
// zurueck, was hineingegeben wurde. Was eine Bewertung fachlich leistet,
|
|
864
|
+
// gehoert in `clientDerivationPort` und wird dort geprueft — hier waere es
|
|
865
|
+
// eine zweite Wahrheit.
|
|
866
|
+
async assessRawOutput(input) {
|
|
867
|
+
const lauf = rekonstruktionen.find((r) => r.run_id === input.runId);
|
|
868
|
+
if (!lauf) {
|
|
869
|
+
return { kind: "error", message: `Lauf ${input.runId} ist unbekannt.`, retryable: false };
|
|
870
|
+
}
|
|
871
|
+
if (typeof lauf.raw_output !== "string" || lauf.raw_output.length === 0) {
|
|
872
|
+
return {
|
|
873
|
+
kind: "error",
|
|
874
|
+
message: `Lauf ${input.runId} hat keine Rohantwort \u2014 es gibt nichts zu pruefen.`,
|
|
875
|
+
retryable: false
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
const text = input.text ?? lauf.raw_output;
|
|
879
|
+
return ok({
|
|
880
|
+
runId: input.runId,
|
|
881
|
+
source_text: text,
|
|
882
|
+
edited: text !== lauf.raw_output,
|
|
883
|
+
diagnostics: [],
|
|
884
|
+
proposals: lauf.proposals,
|
|
885
|
+
rejected: [],
|
|
886
|
+
status: lauf.proposals.length > 0 ? "usable" : "invalid"
|
|
887
|
+
});
|
|
888
|
+
},
|
|
889
|
+
async recordRecovery(input) {
|
|
890
|
+
const geprueft = await derivationPort.assessRawOutput(input);
|
|
891
|
+
if (geprueft.kind !== "ok") {
|
|
892
|
+
return { kind: "error", message: geprueft.message, retryable: geprueft.retryable };
|
|
893
|
+
}
|
|
894
|
+
const record = {
|
|
895
|
+
recovery_id: ids(),
|
|
896
|
+
run_id: geprueft.value.runId,
|
|
897
|
+
source_text: geprueft.value.source_text,
|
|
898
|
+
edited: geprueft.value.edited,
|
|
899
|
+
diagnostics: geprueft.value.diagnostics,
|
|
900
|
+
proposals: geprueft.value.proposals,
|
|
901
|
+
status: geprueft.value.status,
|
|
902
|
+
created_at: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
903
|
+
};
|
|
904
|
+
fassungen.push(record);
|
|
905
|
+
return done(record);
|
|
906
|
+
},
|
|
907
|
+
async getRecovery(recoveryId) {
|
|
908
|
+
return ok(fassungen.find((r) => r.recovery_id === recoveryId) ?? null);
|
|
909
|
+
},
|
|
910
|
+
async listRecoveries(runId) {
|
|
911
|
+
return ok(fassungen.filter((r) => r.run_id === runId));
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
const bilder = /* @__PURE__ */ new Map();
|
|
915
|
+
for (const bild of options.images ?? []) {
|
|
916
|
+
bilder.set(bild.mediaRef, { bild, data: "AAAA" });
|
|
917
|
+
}
|
|
918
|
+
const imageLibraryPort = {
|
|
919
|
+
async listImages(query) {
|
|
920
|
+
const alle = [...bilder.values()].map((e) => e.bild);
|
|
921
|
+
const gesucht = query?.search?.trim().toLowerCase();
|
|
922
|
+
const gefiltert = gesucht ? alle.filter((b) => b.title.toLowerCase().includes(gesucht)) : alle;
|
|
923
|
+
return ok(query?.limit ? gefiltert.slice(0, query.limit) : gefiltert);
|
|
924
|
+
},
|
|
925
|
+
async resolveImage(mediaRef) {
|
|
926
|
+
const eintrag = bilder.get(mediaRef);
|
|
927
|
+
if (!eintrag) {
|
|
928
|
+
return { kind: "error", message: `Bild ${mediaRef} ist unbekannt.`, retryable: false };
|
|
929
|
+
}
|
|
930
|
+
return ok({ data: eintrag.data, mime_type: eintrag.bild.mimeType });
|
|
931
|
+
},
|
|
932
|
+
async putImage(input) {
|
|
933
|
+
const mediaRef = ids();
|
|
934
|
+
const bild = {
|
|
935
|
+
mediaRef,
|
|
936
|
+
title: input.title,
|
|
937
|
+
mimeType: input.mime_type,
|
|
938
|
+
thumbUrl: null
|
|
939
|
+
};
|
|
940
|
+
bilder.set(mediaRef, { bild, data: input.data });
|
|
941
|
+
return done(bild);
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
const batches = [...options.batches ?? []];
|
|
945
|
+
const imageGenerationEvents = createInMemoryEventChannel();
|
|
946
|
+
const imageBatchHistoryPort = {
|
|
947
|
+
async listBatchesForPromptRun(runId) {
|
|
948
|
+
return ok(batches.filter((b) => b.prompt_run_id === runId));
|
|
949
|
+
},
|
|
950
|
+
async getBatch(batchId) {
|
|
951
|
+
return ok(batches.find((b) => b.generation_batch_ids.includes(batchId)) ?? null);
|
|
952
|
+
},
|
|
953
|
+
async listOrdersForPromptRun(runId) {
|
|
954
|
+
return ok(ordersForPromptRun(await imageGenerationEvents.readEvents(), runId));
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
const imageBatchWritePort = {
|
|
958
|
+
async importBatch(input) {
|
|
959
|
+
const bestehend = batches.find((b) => b.generation_batch_ids.includes(input.generationBatchId));
|
|
960
|
+
if (bestehend) return done(bestehend);
|
|
961
|
+
const vorhandenesItem = batches.find((b) => b.prompt_run_id === input.runId);
|
|
962
|
+
const startPosition = vorhandenesItem?.images.length ?? 0;
|
|
963
|
+
const neueBilder = input.images.map((bild, offset) => ({
|
|
964
|
+
media_ref: `${input.generationBatchId}-${startPosition + offset}`,
|
|
965
|
+
position: startPosition + offset,
|
|
966
|
+
model: bild.model ?? null,
|
|
967
|
+
seed: bild.seed ?? null,
|
|
968
|
+
width: bild.width ?? null,
|
|
969
|
+
height: bild.height ?? null
|
|
970
|
+
}));
|
|
971
|
+
const neu = {
|
|
972
|
+
item_id: vorhandenesItem?.item_id ?? `szn-mem-batch-${input.generationBatchId}`,
|
|
973
|
+
prompt_run_id: input.runId,
|
|
974
|
+
generation_batch_ids: [
|
|
975
|
+
...vorhandenesItem?.generation_batch_ids ?? [],
|
|
976
|
+
input.generationBatchId
|
|
977
|
+
],
|
|
978
|
+
source_kind: vorhandenesItem?.source_kind ?? "external_import",
|
|
979
|
+
title: vorhandenesItem?.title ?? input.title ?? `Batch aus Lauf ${input.runId}`,
|
|
980
|
+
images: [...vorhandenesItem?.images ?? [], ...neueBilder]
|
|
981
|
+
};
|
|
982
|
+
if (vorhandenesItem) {
|
|
983
|
+
batches.splice(batches.indexOf(vorhandenesItem), 1, neu);
|
|
984
|
+
} else {
|
|
985
|
+
batches.push(neu);
|
|
986
|
+
}
|
|
987
|
+
for (const bild of neueBilder) {
|
|
988
|
+
bilder.set(bild.media_ref, {
|
|
989
|
+
bild: { mediaRef: bild.media_ref, title: neu.title, mimeType: "image/png", thumbUrl: null },
|
|
990
|
+
data: "AAAA"
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
return done(neu);
|
|
994
|
+
},
|
|
995
|
+
async attachLibraryItem(input) {
|
|
996
|
+
const gefunden = batches.find((b) => b.item_id === input.itemId);
|
|
997
|
+
if (!gefunden) {
|
|
998
|
+
return { kind: "error", message: `Item ${input.itemId} ist unbekannt.`, retryable: false };
|
|
999
|
+
}
|
|
1000
|
+
if (gefunden.prompt_run_id !== input.runId) {
|
|
1001
|
+
return {
|
|
1002
|
+
kind: "conflict",
|
|
1003
|
+
message: `Item ${input.itemId} geh\xF6rt bereits zu Lauf ${gefunden.prompt_run_id}.`,
|
|
1004
|
+
existingPromptRunId: gefunden.prompt_run_id
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
return { kind: "ok", value: gefunden };
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
const simulierterBildProvider = {
|
|
1011
|
+
async generate(input) {
|
|
1012
|
+
const bilder2 = Array.from({ length: input.imageCount }, (_, position) => ({
|
|
1013
|
+
imageBase64: "AAAA",
|
|
1014
|
+
seed: input.seeds?.[position],
|
|
1015
|
+
model: `simulation:${input.callableModelId}`
|
|
1016
|
+
}));
|
|
1017
|
+
return { images: bilder2 };
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
const imageGenerationPort = createImageGenerationPort({
|
|
1021
|
+
runs: { async getRun(runId) {
|
|
1022
|
+
return runs.getRun(runId);
|
|
1023
|
+
} },
|
|
1024
|
+
provider: options.imageProvider ?? simulierterBildProvider,
|
|
1025
|
+
batches: {
|
|
1026
|
+
async persist(input) {
|
|
1027
|
+
const vorhandenesItem = batches.find((b) => b.prompt_run_id === input.runId);
|
|
1028
|
+
const startPosition = vorhandenesItem?.images.length ?? 0;
|
|
1029
|
+
const neueBilder = input.images.map((bild, offset) => ({
|
|
1030
|
+
media_ref: `${input.generationBatchId}-${startPosition + offset}`,
|
|
1031
|
+
position: startPosition + offset,
|
|
1032
|
+
model: bild.model ?? null,
|
|
1033
|
+
seed: bild.seed ?? null,
|
|
1034
|
+
width: bild.width ?? null,
|
|
1035
|
+
height: bild.height ?? null
|
|
1036
|
+
}));
|
|
1037
|
+
const neu = {
|
|
1038
|
+
item_id: vorhandenesItem?.item_id ?? `szn-mem-gen-${input.generationBatchId}`,
|
|
1039
|
+
prompt_run_id: input.runId,
|
|
1040
|
+
generation_batch_ids: [
|
|
1041
|
+
...vorhandenesItem?.generation_batch_ids ?? [],
|
|
1042
|
+
input.generationBatchId
|
|
1043
|
+
],
|
|
1044
|
+
source_kind: "generated_in_app",
|
|
1045
|
+
title: vorhandenesItem?.title ?? `Batch aus Lauf ${input.runId}`,
|
|
1046
|
+
images: [...vorhandenesItem?.images ?? [], ...neueBilder]
|
|
1047
|
+
};
|
|
1048
|
+
if (vorhandenesItem) {
|
|
1049
|
+
batches.splice(batches.indexOf(vorhandenesItem), 1, neu);
|
|
1050
|
+
} else {
|
|
1051
|
+
batches.push(neu);
|
|
1052
|
+
}
|
|
1053
|
+
for (const bild of neueBilder) {
|
|
1054
|
+
bilder.set(bild.media_ref, {
|
|
1055
|
+
bild: { mediaRef: bild.media_ref, title: neu.title, mimeType: "image/png", thumbUrl: null },
|
|
1056
|
+
data: "AAAA"
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
return done(neu);
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
events: { async appendEvent(type, payload) {
|
|
1063
|
+
await imageGenerationEvents.appendEvent(type, payload);
|
|
1064
|
+
} },
|
|
1065
|
+
hasAccess: options.imageProviderHasAccess ?? (() => true)
|
|
1066
|
+
});
|
|
1067
|
+
const port = {
|
|
1068
|
+
elements,
|
|
1069
|
+
context: {
|
|
1070
|
+
// Ein Host ohne Kontextgraph liefert `[eigener, null]` — das ist dort
|
|
1071
|
+
// nicht die verkürzte Vererbung, sondern die vollständige.
|
|
1072
|
+
async chainFor(contextId) {
|
|
1073
|
+
return ok(contextId === null ? [null] : [contextId, null]);
|
|
1074
|
+
}
|
|
1075
|
+
},
|
|
1076
|
+
runs
|
|
1077
|
+
};
|
|
1078
|
+
if (options.items !== false) port.items = itemPort;
|
|
1079
|
+
if (options.media !== false) port.media = mediaPort;
|
|
1080
|
+
if (options.imageLibrary !== false) port.imageLibrary = imageLibraryPort;
|
|
1081
|
+
if (options.derivation !== false) port.derivation = derivationPort;
|
|
1082
|
+
if (options.imageBatchHistory !== false) port.imageBatchHistory = imageBatchHistoryPort;
|
|
1083
|
+
if (options.imageBatchWrite !== false) port.imageBatchWrite = imageBatchWritePort;
|
|
1084
|
+
if (options.imageGeneration !== false) port.imageGeneration = imageGenerationPort;
|
|
1085
|
+
return port;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// src/lib/szenen/browserTextGenerationPort.ts
|
|
1089
|
+
var DEFAULT_MODEL = "gemini-2.5-flash";
|
|
1090
|
+
var PROVIDER = "google";
|
|
1091
|
+
var ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
1092
|
+
function createBrowserTextGenerationPort(options = {}) {
|
|
1093
|
+
const modelId = options.modelId ?? DEFAULT_MODEL;
|
|
1094
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
1095
|
+
return {
|
|
1096
|
+
async generate(request) {
|
|
1097
|
+
if (typeof fetchImpl !== "function") {
|
|
1098
|
+
throw new Error(
|
|
1099
|
+
"Browser-Textport: kein fetch verfuegbar. Der Host muss eines mitgeben."
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
const parts = [{ text: request.prompt }];
|
|
1103
|
+
for (const image of request.images ?? []) {
|
|
1104
|
+
if (!image || typeof image.data !== "string" || typeof image.mime_type !== "string") {
|
|
1105
|
+
throw new Error("Bild ohne Daten oder ohne mime_type \u2014 der Typ wird nicht geraten.");
|
|
1106
|
+
}
|
|
1107
|
+
parts.push({ inlineData: { mimeType: image.mime_type, data: image.data } });
|
|
1108
|
+
}
|
|
1109
|
+
const body = {
|
|
1110
|
+
systemInstruction: { parts: [{ text: request.systemInstruction }] },
|
|
1111
|
+
contents: [{ role: "user", parts }],
|
|
1112
|
+
generationConfig: {
|
|
1113
|
+
...request.responseFormat === "json" ? { responseMimeType: "application/json" } : {}
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
const basis = `${ENDPOINT}/${modelId}:generateContent`;
|
|
1117
|
+
const url = options.apiKey ? `${basis}?key=${options.apiKey}` : basis;
|
|
1118
|
+
let response;
|
|
1119
|
+
try {
|
|
1120
|
+
response = await fetchImpl(url, {
|
|
1121
|
+
method: "POST",
|
|
1122
|
+
headers: { "Content-Type": "application/json" },
|
|
1123
|
+
body: JSON.stringify(body)
|
|
1124
|
+
});
|
|
1125
|
+
} catch (e) {
|
|
1126
|
+
throw new Error(
|
|
1127
|
+
`Modellaufruf nicht moeglich (${modelId}): ${e instanceof Error ? e.message : String(e)}`
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
if (!response.ok) {
|
|
1131
|
+
const text2 = await response.text().catch(() => "");
|
|
1132
|
+
return {
|
|
1133
|
+
kind: "failed",
|
|
1134
|
+
class: "provider_error",
|
|
1135
|
+
message: `Provider antwortete mit HTTP ${response.status} (${modelId}).`,
|
|
1136
|
+
model_id: modelId,
|
|
1137
|
+
provider: PROVIDER,
|
|
1138
|
+
provider_detail: { status: response.status, body: text2.slice(0, 2e3) }
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
const data = await response.json();
|
|
1142
|
+
const blockReason = data?.promptFeedback?.blockReason;
|
|
1143
|
+
if (blockReason) {
|
|
1144
|
+
return {
|
|
1145
|
+
kind: "failed",
|
|
1146
|
+
class: "safety_blocked",
|
|
1147
|
+
message: `Der Provider hat die Anfrage blockiert: ${blockReason}.`,
|
|
1148
|
+
model_id: modelId,
|
|
1149
|
+
provider: PROVIDER,
|
|
1150
|
+
provider_detail: data.promptFeedback
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
const candidate = data?.candidates?.[0];
|
|
1154
|
+
if (!candidate) {
|
|
1155
|
+
return {
|
|
1156
|
+
kind: "failed",
|
|
1157
|
+
class: "empty_content",
|
|
1158
|
+
message: "Der Provider lieferte keinen Kandidaten zurueck.",
|
|
1159
|
+
model_id: modelId,
|
|
1160
|
+
provider: PROVIDER,
|
|
1161
|
+
provider_detail: data
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
const finishReason = candidate.finishReason;
|
|
1165
|
+
if (finishReason && finishReason !== "STOP") {
|
|
1166
|
+
return {
|
|
1167
|
+
kind: "failed",
|
|
1168
|
+
class: finishReason === "SAFETY" ? "safety_blocked" : "finish_reason",
|
|
1169
|
+
message: `Der Lauf endete mit finishReason "${finishReason}".`,
|
|
1170
|
+
model_id: modelId,
|
|
1171
|
+
provider: PROVIDER,
|
|
1172
|
+
provider_detail: { finishReason, safetyRatings: candidate.safetyRatings }
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
const text = (candidate.content?.parts ?? []).map((part) => part.text ?? "").join("").trim();
|
|
1176
|
+
if (!text) {
|
|
1177
|
+
return {
|
|
1178
|
+
kind: "failed",
|
|
1179
|
+
class: "empty_content",
|
|
1180
|
+
message: "Der Provider lieferte einen leeren Text zurueck.",
|
|
1181
|
+
model_id: modelId,
|
|
1182
|
+
provider: PROVIDER,
|
|
1183
|
+
provider_detail: candidate
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
return { kind: "ok", text, model_id: modelId, provider: PROVIDER };
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// src/lib/szenen/runIntegrity.ts
|
|
1192
|
+
var FAILURE_CLASSES = [
|
|
1193
|
+
"response_parse",
|
|
1194
|
+
"response_schema",
|
|
1195
|
+
"safety_blocked",
|
|
1196
|
+
"finish_reason",
|
|
1197
|
+
"empty_content",
|
|
1198
|
+
"provider_error"
|
|
1199
|
+
];
|
|
1200
|
+
var PFLICHTFELDER = [
|
|
1201
|
+
"run_id",
|
|
1202
|
+
"shot_version_id",
|
|
1203
|
+
"shot_element_id",
|
|
1204
|
+
"scene_setup_version_id",
|
|
1205
|
+
"camera_id",
|
|
1206
|
+
"target_model_version_id",
|
|
1207
|
+
"provider",
|
|
1208
|
+
"model_id",
|
|
1209
|
+
"system_prompt",
|
|
1210
|
+
"created_at"
|
|
1211
|
+
];
|
|
1212
|
+
function istText2(wert) {
|
|
1213
|
+
return typeof wert === "string" && wert.trim().length > 0;
|
|
1214
|
+
}
|
|
1215
|
+
function isObject2(wert) {
|
|
1216
|
+
return typeof wert === "object" && wert !== null && !Array.isArray(wert);
|
|
1217
|
+
}
|
|
1218
|
+
var VERSIONSFELDER = ["shot_version_id", "scene_setup_version_id"];
|
|
1219
|
+
var KETTEN_TYPEN = ["scene", "scene_setup", "shot"];
|
|
1220
|
+
function pruefeLaufherkunft(quelle) {
|
|
1221
|
+
if (!isObject2(quelle)) {
|
|
1222
|
+
return { ok: false, message: '"source" muss ein Objekt sein.' };
|
|
1223
|
+
}
|
|
1224
|
+
if (quelle.kind === "published") {
|
|
1225
|
+
for (const feld of VERSIONSFELDER) {
|
|
1226
|
+
if (!istText2(quelle[feld])) {
|
|
1227
|
+
return { ok: false, message: `"source.${feld}" fehlt oder ist leer.` };
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return { ok: true };
|
|
1231
|
+
}
|
|
1232
|
+
if (quelle.kind !== "draft_chain") {
|
|
1233
|
+
return {
|
|
1234
|
+
ok: false,
|
|
1235
|
+
message: `"source.kind" ist unbekannt: ${JSON.stringify(quelle.kind)}. Erlaubt: published, draft_chain.`
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
if (!istText2(quelle.chain_id)) {
|
|
1239
|
+
return { ok: false, message: '"source.chain_id" fehlt oder ist leer.' };
|
|
1240
|
+
}
|
|
1241
|
+
if (!Array.isArray(quelle.nodes) || quelle.nodes.length === 0) {
|
|
1242
|
+
return {
|
|
1243
|
+
ok: false,
|
|
1244
|
+
message: '"source.nodes" fehlt oder ist leer. Ohne Knoten waere nicht nachvollziehbar, welche Entwuerfe eingefroren wurden (G21).'
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
for (const [index, knoten] of quelle.nodes.entries()) {
|
|
1248
|
+
if (!isObject2(knoten)) {
|
|
1249
|
+
return { ok: false, message: `"source.nodes[${index}]" ist kein Objekt.` };
|
|
1250
|
+
}
|
|
1251
|
+
if (!KETTEN_TYPEN.includes(knoten.type)) {
|
|
1252
|
+
return {
|
|
1253
|
+
ok: false,
|
|
1254
|
+
message: `"source.nodes[${index}].type" ist unbekannt: ${JSON.stringify(knoten.type)}.`
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
if (!istText2(knoten.element_id) || !istText2(knoten.draft_id)) {
|
|
1258
|
+
return {
|
|
1259
|
+
ok: false,
|
|
1260
|
+
message: `"source.nodes[${index}]" braucht element_id und draft_id.`
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
if (typeof knoten.revision !== "number" || !Number.isInteger(knoten.revision)) {
|
|
1264
|
+
return {
|
|
1265
|
+
ok: false,
|
|
1266
|
+
message: `"source.nodes[${index}].revision" muss eine ganze Zahl sein \u2014 ohne sie ist der eingefrorene Stand nicht benennbar (D-97).`
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (quelle.derivation_run_id !== void 0 && !istText2(quelle.derivation_run_id)) {
|
|
1271
|
+
return { ok: false, message: '"source.derivation_run_id" ist gesetzt, aber leer.' };
|
|
1272
|
+
}
|
|
1273
|
+
if (quelle.derivation_recovery_id !== void 0 && !istText2(quelle.derivation_recovery_id)) {
|
|
1274
|
+
return { ok: false, message: '"source.derivation_recovery_id" ist gesetzt, aber leer.' };
|
|
1275
|
+
}
|
|
1276
|
+
return { ok: true };
|
|
1277
|
+
}
|
|
1278
|
+
function checkPromptRunRecord(candidate) {
|
|
1279
|
+
if (candidate === null || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
1280
|
+
return {
|
|
1281
|
+
ok: false,
|
|
1282
|
+
message: `Ein Lauf muss ein Objekt sein, angekommen ist ${Array.isArray(candidate) ? "ein Array" : typeof candidate}.`
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
const record = candidate;
|
|
1286
|
+
const quelle = record.source;
|
|
1287
|
+
const ausKette = isObject2(quelle) && quelle.kind === "draft_chain";
|
|
1288
|
+
if (quelle !== void 0) {
|
|
1289
|
+
const urteil2 = pruefeLaufherkunft(quelle);
|
|
1290
|
+
if (!urteil2.ok) return urteil2;
|
|
1291
|
+
}
|
|
1292
|
+
const pflicht = ausKette ? PFLICHTFELDER.filter((f) => !VERSIONSFELDER.includes(f)) : PFLICHTFELDER;
|
|
1293
|
+
for (const feld of pflicht) {
|
|
1294
|
+
if (!istText2(record[feld])) {
|
|
1295
|
+
return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
if (ausKette) {
|
|
1299
|
+
for (const feld of VERSIONSFELDER) {
|
|
1300
|
+
if (istText2(record[feld])) {
|
|
1301
|
+
return {
|
|
1302
|
+
ok: false,
|
|
1303
|
+
message: `"${feld}" ist bei einem Lauf aus einer Draft-Kette gesetzt. Dort gibt es keine Versionen, und erfundene sind unzulaessig (D-98).`
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
if (record.status !== "succeeded" && record.status !== "failed") {
|
|
1309
|
+
return {
|
|
1310
|
+
ok: false,
|
|
1311
|
+
message: `"status" muss succeeded oder failed sein, angekommen ist ${JSON.stringify(record.status)}.`
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
const eingabe = record.input_payload;
|
|
1315
|
+
if (eingabe === null || typeof eingabe !== "object") {
|
|
1316
|
+
return { ok: false, message: '"input_payload" fehlt \u2014 ohne sie ist der Lauf nicht pruefbar.' };
|
|
1317
|
+
}
|
|
1318
|
+
if (record.status === "failed") {
|
|
1319
|
+
if (record.output !== null && record.output !== void 0) {
|
|
1320
|
+
return {
|
|
1321
|
+
ok: false,
|
|
1322
|
+
message: 'Ein gescheiterter Lauf traegt kein "output" \u2014 er hat keines erzeugt.'
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
const failure = record.failure;
|
|
1326
|
+
if (!failure || typeof failure !== "object") {
|
|
1327
|
+
return {
|
|
1328
|
+
ok: false,
|
|
1329
|
+
message: 'Ein gescheiterter Lauf braucht ein "failure" \u2014 der Grund ist der Beleg.'
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
if (!FAILURE_CLASSES.includes(failure.class)) {
|
|
1333
|
+
return {
|
|
1334
|
+
ok: false,
|
|
1335
|
+
message: `"failure.class" ist unbekannt: ${JSON.stringify(failure.class)}. Erlaubt sind ${FAILURE_CLASSES.join(", ")}.`
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
if (!istText2(failure.message)) {
|
|
1339
|
+
return { ok: false, message: '"failure.message" fehlt oder ist leer.' };
|
|
1340
|
+
}
|
|
1341
|
+
return { ok: true };
|
|
1342
|
+
}
|
|
1343
|
+
if (record.failure !== null && record.failure !== void 0) {
|
|
1344
|
+
return {
|
|
1345
|
+
ok: false,
|
|
1346
|
+
message: 'Ein erfolgreicher Lauf traegt kein "failure".'
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
if (!record.output || typeof record.output !== "object") {
|
|
1350
|
+
return {
|
|
1351
|
+
ok: false,
|
|
1352
|
+
message: 'Ein erfolgreicher Lauf braucht ein "output" \u2014 sonst belegt er nichts.'
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
const urteil = checkRunResponse(record.output, eingabe);
|
|
1356
|
+
if (!urteil.ok) {
|
|
1357
|
+
return { ok: false, message: `Das Ergebnis passt nicht zur Eingabe: ${urteil.message}` };
|
|
1358
|
+
}
|
|
1359
|
+
return { ok: true };
|
|
1360
|
+
}
|
|
1361
|
+
var INPUT_MODES = ["prompt", "image", "image_prompt"];
|
|
1362
|
+
var DERIVATION_PFLICHTFELDER = [
|
|
1363
|
+
"run_id",
|
|
1364
|
+
"policy_version_id",
|
|
1365
|
+
"policy_element_id",
|
|
1366
|
+
"provider",
|
|
1367
|
+
"model_id",
|
|
1368
|
+
"system_prompt",
|
|
1369
|
+
"created_at"
|
|
1370
|
+
];
|
|
1371
|
+
function checkSceneDerivationRecord(candidate) {
|
|
1372
|
+
if (candidate === null || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
1373
|
+
return {
|
|
1374
|
+
ok: false,
|
|
1375
|
+
message: `Ein Lauf muss ein Objekt sein, angekommen ist ${Array.isArray(candidate) ? "ein Array" : typeof candidate}.`
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
const record = candidate;
|
|
1379
|
+
for (const feld of DERIVATION_PFLICHTFELDER) {
|
|
1380
|
+
if (!istText2(record[feld])) {
|
|
1381
|
+
return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
if (record.context_id !== null && typeof record.context_id !== "string") {
|
|
1385
|
+
return {
|
|
1386
|
+
ok: false,
|
|
1387
|
+
message: '"context_id" muss eine Zeichenkette oder null sein \u2014 er bestimmt, wo uebernommene Entwuerfe landen.'
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
if (record.status !== "succeeded" && record.status !== "failed") {
|
|
1391
|
+
return {
|
|
1392
|
+
ok: false,
|
|
1393
|
+
message: `"status" muss succeeded oder failed sein, angekommen ist ${JSON.stringify(record.status)}.`
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
const eingabe = record.input;
|
|
1397
|
+
if (!eingabe || typeof eingabe !== "object") {
|
|
1398
|
+
return { ok: false, message: '"input" fehlt \u2014 ohne sie ist der Lauf nicht nachvollziehbar.' };
|
|
1399
|
+
}
|
|
1400
|
+
if (!INPUT_MODES.includes(eingabe.mode)) {
|
|
1401
|
+
return {
|
|
1402
|
+
ok: false,
|
|
1403
|
+
message: `"input.mode" ist unbekannt: ${JSON.stringify(eingabe.mode)}. Erlaubt sind ${INPUT_MODES.join(", ")}.`
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
if (eingabe.prompt_text !== null && typeof eingabe.prompt_text !== "string") {
|
|
1407
|
+
return { ok: false, message: '"input.prompt_text" muss eine Zeichenkette oder null sein.' };
|
|
1408
|
+
}
|
|
1409
|
+
if (!Array.isArray(eingabe.images)) {
|
|
1410
|
+
return { ok: false, message: '"input.images" muss eine Liste sein, auch eine leere.' };
|
|
1411
|
+
}
|
|
1412
|
+
for (const [index, bild] of eingabe.images.entries()) {
|
|
1413
|
+
if (!bild || typeof bild !== "object") {
|
|
1414
|
+
return { ok: false, message: `"input.images[${index}]" ist keine Herkunftsangabe.` };
|
|
1415
|
+
}
|
|
1416
|
+
if (typeof bild.mime_type !== "string") {
|
|
1417
|
+
return {
|
|
1418
|
+
ok: false,
|
|
1419
|
+
message: `"input.images[${index}].mime_type" fehlt \u2014 der Typ wird nicht geraten.`
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
if ("data" in bild) {
|
|
1423
|
+
return {
|
|
1424
|
+
ok: false,
|
|
1425
|
+
message: `"input.images[${index}]" traegt Bilddaten. Eingefroren wird die Herkunft, nicht das Bild (D-73).`
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
const folgt = record.follows;
|
|
1430
|
+
if (folgt !== void 0) {
|
|
1431
|
+
if (!folgt || typeof folgt !== "object" || Array.isArray(folgt)) {
|
|
1432
|
+
return { ok: false, message: '"follows" muss ein Objekt sein.' };
|
|
1433
|
+
}
|
|
1434
|
+
const f = folgt;
|
|
1435
|
+
if (!istText2(f.run_id)) {
|
|
1436
|
+
return { ok: false, message: '"follows.run_id" fehlt oder ist leer.' };
|
|
1437
|
+
}
|
|
1438
|
+
if (f.run_id === record.run_id) {
|
|
1439
|
+
return { ok: false, message: '"follows.run_id" zeigt auf den Lauf selbst.' };
|
|
1440
|
+
}
|
|
1441
|
+
if (!istText2(f.note)) {
|
|
1442
|
+
return {
|
|
1443
|
+
ok: false,
|
|
1444
|
+
message: '"follows.note" fehlt oder ist leer \u2014 ohne Beanstandung ist ein Folgelauf nicht nachvollziehbar (D-89).'
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
if (f.user_instruction !== null && typeof f.user_instruction !== "string") {
|
|
1448
|
+
return {
|
|
1449
|
+
ok: false,
|
|
1450
|
+
message: '"follows.user_instruction" muss eine Zeichenkette oder null sein.'
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
const reply = record.reply;
|
|
1455
|
+
if (reply !== void 0 && !istText2(reply)) {
|
|
1456
|
+
return {
|
|
1457
|
+
ok: false,
|
|
1458
|
+
message: `"reply" ist unbrauchbar: erwartet wird eine nicht leere Zeichenkette, angekommen ist ${JSON.stringify(reply)}. Ohne "reply" einreichen ist zulaessig.`
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
if (record.status === "failed") {
|
|
1462
|
+
const failure = record.failure;
|
|
1463
|
+
if (!failure || typeof failure !== "object") {
|
|
1464
|
+
return {
|
|
1465
|
+
ok: false,
|
|
1466
|
+
message: 'Ein gescheiterter Lauf braucht ein "failure" \u2014 der Grund ist der Beleg.'
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
if (!FAILURE_CLASSES.includes(failure.class)) {
|
|
1470
|
+
return {
|
|
1471
|
+
ok: false,
|
|
1472
|
+
message: `"failure.class" ist unbekannt: ${JSON.stringify(failure.class)}. Erlaubt sind ${FAILURE_CLASSES.join(", ")}.`
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
if (!istText2(failure.message)) {
|
|
1476
|
+
return { ok: false, message: '"failure.message" fehlt oder ist leer.' };
|
|
1477
|
+
}
|
|
1478
|
+
if (Array.isArray(record.proposals) && record.proposals.length > 0) {
|
|
1479
|
+
return {
|
|
1480
|
+
ok: false,
|
|
1481
|
+
message: 'Ein gescheiterter Lauf traegt keine "proposals" \u2014 er hat keine erzeugt.'
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
return { ok: true };
|
|
1485
|
+
}
|
|
1486
|
+
if (record.failure !== null && record.failure !== void 0) {
|
|
1487
|
+
return { ok: false, message: 'Ein erfolgreicher Lauf traegt kein "failure".' };
|
|
1488
|
+
}
|
|
1489
|
+
if (!Array.isArray(record.proposals)) {
|
|
1490
|
+
return { ok: false, message: '"proposals" muss eine Liste sein, auch eine leere.' };
|
|
1491
|
+
}
|
|
1492
|
+
for (const [index, vorschlag] of record.proposals.entries()) {
|
|
1493
|
+
if (!vorschlag || typeof vorschlag !== "object") {
|
|
1494
|
+
return { ok: false, message: `"proposals[${index}]" ist kein Vorschlag.` };
|
|
1495
|
+
}
|
|
1496
|
+
const typ = vorschlag.type;
|
|
1497
|
+
if (!DERIVABLE_TYPES.includes(typ)) {
|
|
1498
|
+
return {
|
|
1499
|
+
ok: false,
|
|
1500
|
+
message: `"proposals[${index}].type" ist ${JSON.stringify(typ)} \u2014 erlaubt sind ${DERIVABLE_TYPES.join(", ")}.`
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
const payload = vorschlag.payload;
|
|
1504
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
1505
|
+
return { ok: false, message: `"proposals[${index}].payload" fehlt oder ist kein Objekt.` };
|
|
1506
|
+
}
|
|
1507
|
+
const titel = vorschlag.title;
|
|
1508
|
+
if (titel !== void 0 && acceptProposalTitle(titel) === null) {
|
|
1509
|
+
return {
|
|
1510
|
+
ok: false,
|
|
1511
|
+
message: `"proposals[${index}].title" ist unbrauchbar: erwartet wird eine nicht leere einzeilige Zeichenkette mit hoechstens ${MAX_PROPOSAL_TITLE_LENGTH} Zeichen, angekommen ist ${JSON.stringify(titel)}. Ohne Titel einreichen ist zulaessig (D-83).`
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
const status = vorschlag.status;
|
|
1515
|
+
if (status !== void 0 && status !== "complete" && status !== "partial") {
|
|
1516
|
+
return {
|
|
1517
|
+
ok: false,
|
|
1518
|
+
message: `"proposals[${index}].status" ist ${JSON.stringify(status)} \u2014 erlaubt sind complete und partial (D-82).`
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
const gaps = vorschlag.gaps;
|
|
1522
|
+
if (status === "partial") {
|
|
1523
|
+
if (!Array.isArray(gaps) || gaps.length === 0) {
|
|
1524
|
+
return {
|
|
1525
|
+
ok: false,
|
|
1526
|
+
message: `"proposals[${index}]" ist partial, nennt aber keine gaps. Ein unvollstaendiger Vorschlag ohne benannte Luecken ist nicht uebernehmbar (D-82).`
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
for (const [gapIndex, luecke] of gaps.entries()) {
|
|
1530
|
+
if (!luecke || typeof luecke !== "object" || !istText2(luecke.pointer) || !istText2(luecke.reason)) {
|
|
1531
|
+
return {
|
|
1532
|
+
ok: false,
|
|
1533
|
+
message: `"proposals[${index}].gaps[${gapIndex}]" braucht pointer und reason.`
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
if (status !== "partial" && Array.isArray(gaps) && gaps.length > 0) {
|
|
1539
|
+
return {
|
|
1540
|
+
ok: false,
|
|
1541
|
+
message: `"proposals[${index}]" nennt gaps, ist aber nicht partial (D-82).`
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return { ok: true };
|
|
1546
|
+
}
|
|
1547
|
+
function checkSceneDerivationRecoveryRecord(candidate) {
|
|
1548
|
+
if (candidate === null || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
1549
|
+
return {
|
|
1550
|
+
ok: false,
|
|
1551
|
+
message: `Eine Arbeitsfassung muss ein Objekt sein, angekommen ist ${Array.isArray(candidate) ? "ein Array" : typeof candidate}.`
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
const record = candidate;
|
|
1555
|
+
for (const feld of ["recovery_id", "run_id", "created_at"]) {
|
|
1556
|
+
if (!istText2(record[feld])) {
|
|
1557
|
+
return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
if (typeof record.source_text !== "string") {
|
|
1561
|
+
return {
|
|
1562
|
+
ok: false,
|
|
1563
|
+
message: '"source_text" fehlt \u2014 ohne ihn ist die Arbeitsfassung nicht nachvollziehbar.'
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
if (typeof record.edited !== "boolean") {
|
|
1567
|
+
return {
|
|
1568
|
+
ok: false,
|
|
1569
|
+
message: '"edited" muss true oder false sein \u2014 ob der Text bearbeitet wurde, darf nicht offenbleiben (D-99).'
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
const RECOVERY_STATUS = ["usable", "partial", "invalid"];
|
|
1573
|
+
if (!RECOVERY_STATUS.includes(record.status)) {
|
|
1574
|
+
return {
|
|
1575
|
+
ok: false,
|
|
1576
|
+
message: `"status" muss usable, partial oder invalid sein, angekommen ist ${JSON.stringify(record.status)}.`
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
if (!Array.isArray(record.diagnostics)) {
|
|
1580
|
+
return { ok: false, message: '"diagnostics" muss ein Array sein (auch ein leeres).' };
|
|
1581
|
+
}
|
|
1582
|
+
for (const [index, befund] of record.diagnostics.entries()) {
|
|
1583
|
+
if (!befund || typeof befund !== "object" || !istText2(befund.code) || !istText2(befund.message)) {
|
|
1584
|
+
return {
|
|
1585
|
+
ok: false,
|
|
1586
|
+
message: `"diagnostics[${index}]" braucht code und message.`
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
const schwere = befund.severity;
|
|
1590
|
+
if (schwere !== "error" && schwere !== "warning") {
|
|
1591
|
+
return {
|
|
1592
|
+
ok: false,
|
|
1593
|
+
message: `"diagnostics[${index}].severity" muss error oder warning sein.`
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
if (!Array.isArray(record.proposals)) {
|
|
1598
|
+
return { ok: false, message: '"proposals" muss ein Array sein (auch ein leeres).' };
|
|
1599
|
+
}
|
|
1600
|
+
for (const [index, vorschlag] of record.proposals.entries()) {
|
|
1601
|
+
if (!vorschlag || typeof vorschlag !== "object") {
|
|
1602
|
+
return { ok: false, message: `"proposals[${index}]" ist kein Objekt.` };
|
|
1603
|
+
}
|
|
1604
|
+
const p = vorschlag;
|
|
1605
|
+
if (!DERIVABLE_TYPES.includes(p.type)) {
|
|
1606
|
+
return {
|
|
1607
|
+
ok: false,
|
|
1608
|
+
message: `"proposals[${index}].type" ist unbekannt: ${JSON.stringify(p.type)}.`
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
if (!p.payload || typeof p.payload !== "object" || Array.isArray(p.payload)) {
|
|
1612
|
+
return { ok: false, message: `"proposals[${index}].payload" fehlt oder ist kein Objekt.` };
|
|
1613
|
+
}
|
|
1614
|
+
if (p.status !== "complete" && p.status !== "partial") {
|
|
1615
|
+
return {
|
|
1616
|
+
ok: false,
|
|
1617
|
+
message: `"proposals[${index}].status" muss complete oder partial sein. Anders als bei einem Lauf von vor D-82 gibt es hier keine Altfaelle.`
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
const gaps = p.gaps;
|
|
1621
|
+
if (p.status === "partial" && (!Array.isArray(gaps) || gaps.length === 0)) {
|
|
1622
|
+
return {
|
|
1623
|
+
ok: false,
|
|
1624
|
+
message: `"proposals[${index}]" ist partial, nennt aber keine gaps (D-82).`
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
if (p.status !== "partial" && Array.isArray(gaps) && gaps.length > 0) {
|
|
1628
|
+
return {
|
|
1629
|
+
ok: false,
|
|
1630
|
+
message: `"proposals[${index}]" nennt gaps, ist aber nicht partial (D-82).`
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
if (Array.isArray(gaps)) {
|
|
1634
|
+
for (const [gapIndex, luecke] of gaps.entries()) {
|
|
1635
|
+
if (!luecke || typeof luecke !== "object" || !istText2(luecke.pointer) || !istText2(luecke.reason)) {
|
|
1636
|
+
return {
|
|
1637
|
+
ok: false,
|
|
1638
|
+
message: `"proposals[${index}].gaps[${gapIndex}]" braucht pointer und reason.`
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
if (p.title !== void 0 && acceptProposalTitle(p.title) === null) {
|
|
1644
|
+
return {
|
|
1645
|
+
ok: false,
|
|
1646
|
+
message: `"proposals[${index}].title" ist unbrauchbar \u2014 leer, kein Text oder laenger als ${MAX_PROPOSAL_TITLE_LENGTH} Zeichen.`
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
if (record.status === "invalid" && record.proposals.length > 0) {
|
|
1651
|
+
return {
|
|
1652
|
+
ok: false,
|
|
1653
|
+
message: '"status" ist invalid, es stehen aber Vorschlaege im Datensatz. Entweder ist etwas verwertbar oder nicht.'
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
if (record.status !== "invalid" && record.proposals.length === 0) {
|
|
1657
|
+
return {
|
|
1658
|
+
ok: false,
|
|
1659
|
+
message: `"status" ist ${record.status}, es steht aber kein Vorschlag im Datensatz.`
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
if (record.status === "usable" && record.diagnostics.some((d) => d.severity === "error")) {
|
|
1663
|
+
return {
|
|
1664
|
+
ok: false,
|
|
1665
|
+
message: '"status" ist usable, es stehen aber Fehlerbefunde im Datensatz. Vertragstreu und fehlerhaft zugleich gibt es nicht.'
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
return { ok: true };
|
|
1669
|
+
}
|
|
1670
|
+
export {
|
|
1671
|
+
ALL_PUBLISH_RULES,
|
|
1672
|
+
CATALOGUE_TYPES,
|
|
1673
|
+
CHAIN_EDGES,
|
|
1674
|
+
CHAIN_LINK_FIELDS,
|
|
1675
|
+
CapabilityAnchorError,
|
|
1676
|
+
ContractViolation,
|
|
1677
|
+
DERIVABLE_TYPES,
|
|
1678
|
+
ELEMENT_VERSION_SCHEMA_FILE,
|
|
1679
|
+
PROBE_VERSION_ID,
|
|
1680
|
+
REFERENCE_FIELD,
|
|
1681
|
+
RULES_WITHOUT_CAPABILITY_EFFECT,
|
|
1682
|
+
RULE_SCOPES,
|
|
1683
|
+
ResolveTechnicalError,
|
|
1684
|
+
SIMULATION_PROVIDER,
|
|
1685
|
+
STYLE_PAYLOAD,
|
|
1686
|
+
STYLE_PAYLOAD_V2,
|
|
1687
|
+
SZENEN_ELEMENT_TYPES,
|
|
1688
|
+
SZENEN_EVENT_PREFIX,
|
|
1689
|
+
SZENEN_EVENT_TYPES,
|
|
1690
|
+
SZENEN_ITEM_PREFIX,
|
|
1691
|
+
SZENEN_SCHEMAS,
|
|
1692
|
+
SzenenView,
|
|
1693
|
+
UNCHECKED_PUBLISH_RULES,
|
|
1694
|
+
UnsupportedSchemaError,
|
|
1695
|
+
VersionDagError,
|
|
1696
|
+
areasFor,
|
|
1697
|
+
assessDerivationResponse,
|
|
1698
|
+
buildSystemInstruction as buildDerivationSystemInstruction,
|
|
1699
|
+
buildUserPrompt as buildDerivationUserPrompt,
|
|
1700
|
+
buildSystemInstruction2 as buildSystemInstruction,
|
|
1701
|
+
buildUserPrompt2 as buildUserPrompt,
|
|
1702
|
+
buildVersionDag,
|
|
1703
|
+
callOptional,
|
|
1704
|
+
callableImageModelFor,
|
|
1705
|
+
capabilitiesOf,
|
|
1706
|
+
capabilityForTargetModel,
|
|
1707
|
+
capabilityGate,
|
|
1708
|
+
capabilityReport,
|
|
1709
|
+
catalogueFor,
|
|
1710
|
+
checkChainTargets,
|
|
1711
|
+
checkCreateElementInput,
|
|
1712
|
+
checkDerivationResponse,
|
|
1713
|
+
checkDraftChainMeta,
|
|
1714
|
+
checkElementType,
|
|
1715
|
+
checkOptionalId,
|
|
1716
|
+
checkParents,
|
|
1717
|
+
checkPayloadPresent,
|
|
1718
|
+
checkPromptRunRecord,
|
|
1719
|
+
checkPublishVersionInput,
|
|
1720
|
+
checkRequiredId,
|
|
1721
|
+
checkReviseMetadataInput,
|
|
1722
|
+
checkRevision,
|
|
1723
|
+
checkRunResponse,
|
|
1724
|
+
checkSceneDerivationRecord,
|
|
1725
|
+
checkSceneDerivationRecoveryRecord,
|
|
1726
|
+
checkSetPreferredHeadInput,
|
|
1727
|
+
checkSzenenBatchOrigin,
|
|
1728
|
+
checkTitle,
|
|
1729
|
+
checkWriteDraftInput,
|
|
1730
|
+
collectImageGenerationOrders,
|
|
1731
|
+
collectPromptRuns,
|
|
1732
|
+
collectProviderChecks,
|
|
1733
|
+
collectSceneDerivationRecoveries,
|
|
1734
|
+
collectSceneDerivations,
|
|
1735
|
+
collectVersionRefs,
|
|
1736
|
+
compileSchemas,
|
|
1737
|
+
createBrowserTextGenerationPort,
|
|
1738
|
+
createClientDerivationPort,
|
|
1739
|
+
createClientRunPort,
|
|
1740
|
+
createEventLogDerivationPersistence,
|
|
1741
|
+
createEventLogRunPersistence,
|
|
1742
|
+
createFakeTextGenerationPort,
|
|
1743
|
+
createFlowSzenenViewPort,
|
|
1744
|
+
createFlowTextGenerationPort,
|
|
1745
|
+
createHfElementStore,
|
|
1746
|
+
createHfEventChannel,
|
|
1747
|
+
createHfImageLibrary,
|
|
1748
|
+
createImageGenerationPort,
|
|
1749
|
+
createInMemoryEventChannel,
|
|
1750
|
+
createMemoryViewPort,
|
|
1751
|
+
createSimulationSceneDerivationPort,
|
|
1752
|
+
createSimulationTextGenerationPort,
|
|
1753
|
+
derivationPoliciesOf,
|
|
1754
|
+
deriveItemFromRun,
|
|
1755
|
+
deriveLineage,
|
|
1756
|
+
describeTargetModelFailure,
|
|
1757
|
+
differentialSteps,
|
|
1758
|
+
draftRevisionOf,
|
|
1759
|
+
elementStoreContractChecks,
|
|
1760
|
+
findImageGenerationOrder,
|
|
1761
|
+
findPromptRun,
|
|
1762
|
+
findProviderCheck,
|
|
1763
|
+
findSceneDerivation,
|
|
1764
|
+
findSceneDerivationRecovery,
|
|
1765
|
+
firstError,
|
|
1766
|
+
formatSchemaErrors,
|
|
1767
|
+
freezeDraftChain,
|
|
1768
|
+
getSzenenSchemas,
|
|
1769
|
+
hasPlacementCapability,
|
|
1770
|
+
isKnownElementType,
|
|
1771
|
+
isOk,
|
|
1772
|
+
isProjectionCurrent,
|
|
1773
|
+
isSzenenItemId,
|
|
1774
|
+
itemIdForRun,
|
|
1775
|
+
linkFor,
|
|
1776
|
+
logRevisionOf,
|
|
1777
|
+
mergeSzenenBatchOrigin,
|
|
1778
|
+
noticeFor,
|
|
1779
|
+
ordersForPromptRun,
|
|
1780
|
+
parseDerivationResponse,
|
|
1781
|
+
parseRunResponse,
|
|
1782
|
+
preferredHeadRevisionOf,
|
|
1783
|
+
preferredVersionId,
|
|
1784
|
+
publishedHeadsOf,
|
|
1785
|
+
recoveriesForRun,
|
|
1786
|
+
recoveryStatusOf,
|
|
1787
|
+
reduceElementEvents,
|
|
1788
|
+
resolveArea,
|
|
1789
|
+
resolvePreferredHead,
|
|
1790
|
+
resolveShot,
|
|
1791
|
+
resolveShotPayload,
|
|
1792
|
+
resolveTargetModelOver,
|
|
1793
|
+
resolverFromQueries,
|
|
1794
|
+
roundOfRun,
|
|
1795
|
+
runElementStoreContract,
|
|
1796
|
+
runPromptDerivation,
|
|
1797
|
+
runPublishChecks,
|
|
1798
|
+
runSceneDerivation,
|
|
1799
|
+
runStoreDifferential,
|
|
1800
|
+
scopeOfPath,
|
|
1801
|
+
showChain,
|
|
1802
|
+
simulatedAnswerFor,
|
|
1803
|
+
totalModelCalls,
|
|
1804
|
+
unclassifiedPublishRules,
|
|
1805
|
+
unsupportedReason,
|
|
1806
|
+
validateAgainst,
|
|
1807
|
+
validateDerivationInput,
|
|
1808
|
+
validateElementVersion,
|
|
1809
|
+
validatePayload,
|
|
1810
|
+
withReference
|
|
1811
|
+
};
|