@rslsp1/fa-app-tools 7.2.0 → 7.4.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/dist/szenen.js CHANGED
@@ -40,6 +40,7 @@ __export(szenen_exports, {
40
40
  DERIVABLE_TYPES: () => DERIVABLE_TYPES,
41
41
  ELEMENT_VERSION_SCHEMA_FILE: () => ELEMENT_VERSION_SCHEMA_FILE,
42
42
  FLOW_EXECUTION_PATH: () => FLOW_EXECUTION_PATH,
43
+ MCP_CLIENT_PROVIDER: () => MCP_CLIENT_PROVIDER,
43
44
  PROBE_VERSION_ID: () => PROBE_VERSION_ID,
44
45
  PROMPT_RULE_EFFECT: () => PROMPT_RULE_EFFECT,
45
46
  REFERENCE_FIELD: () => REFERENCE_FIELD,
@@ -59,6 +60,7 @@ __export(szenen_exports, {
59
60
  SZENEN_SNAPSHOT_SCHEMA_VERSION: () => SZENEN_SNAPSHOT_SCHEMA_VERSION,
60
61
  SzenenView: () => SzenenView,
61
62
  UNCHECKED_PUBLISH_RULES: () => UNCHECKED_PUBLISH_RULES,
63
+ UNVERIFIED_MODEL_ID: () => UNVERIFIED_MODEL_ID,
62
64
  UPLOAD_MAX_BYTES: () => UPLOAD_MAX_BYTES,
63
65
  UnsupportedSchemaError: () => UnsupportedSchemaError,
64
66
  VersionDagError: () => VersionDagError,
@@ -100,14 +102,18 @@ __export(szenen_exports, {
100
102
  checkSzenenBatchOrigin: () => checkSzenenBatchOrigin,
101
103
  checkTitle: () => checkTitle,
102
104
  checkWriteDraftInput: () => checkWriteDraftInput,
105
+ claimWon: () => claimWon,
103
106
  collectImageBatches: () => collectImageBatches,
104
107
  collectImageGenerationOrders: () => collectImageGenerationOrders,
108
+ collectImageJobs: () => collectImageJobs,
109
+ collectPromptOperations: () => collectPromptOperations,
105
110
  collectPromptRuns: () => collectPromptRuns,
106
111
  collectProviderChecks: () => collectProviderChecks,
107
112
  collectSceneDerivationRecoveries: () => collectSceneDerivationRecoveries,
108
113
  collectSceneDerivations: () => collectSceneDerivations,
109
114
  collectVersionRefs: () => collectVersionRefs2,
110
115
  compileSchemas: () => compileSchemas,
116
+ completePromptOperation: () => completePromptOperation,
111
117
  createBrowserTextGenerationPort: () => createBrowserTextGenerationPort,
112
118
  createClientDerivationPort: () => createClientDerivationPort,
113
119
  createClientRunPort: () => createClientRunPort,
@@ -125,6 +131,7 @@ __export(szenen_exports, {
125
131
  createHfImageLibrary: () => createHfImageLibrary,
126
132
  createHfImageStore: () => createHfImageStore,
127
133
  createImageGenerationPort: () => createImageGenerationPort,
134
+ createImageJobPort: () => createImageJobPort,
128
135
  createInMemoryEventChannel: () => createInMemoryEventChannel,
129
136
  createMemoryViewPort: () => createMemoryViewPort,
130
137
  createSimulationSceneDerivationPort: () => createSimulationSceneDerivationPort,
@@ -143,6 +150,8 @@ __export(szenen_exports, {
143
150
  findExecutableImageModel: () => findExecutableImageModel,
144
151
  findImageBatch: () => findImageBatch,
145
152
  findImageGenerationOrder: () => findImageGenerationOrder,
153
+ findImageJob: () => findImageJob,
154
+ findPromptOperation: () => findPromptOperation,
146
155
  findPromptRun: () => findPromptRun,
147
156
  findProviderCheck: () => findProviderCheck,
148
157
  findSceneDerivation: () => findSceneDerivation,
@@ -152,6 +161,7 @@ __export(szenen_exports, {
152
161
  formatSeedListe: () => formatSeedListe,
153
162
  freezeDraftChain: () => freezeDraftChain,
154
163
  freezeSceneWorkingState: () => freezeSceneWorkingState,
164
+ generationBatchIdOf: () => generationBatchIdOf,
155
165
  gesamtHerkunft: () => gesamtHerkunft,
156
166
  getSzenenSchemas: () => getSzenenSchemas,
157
167
  gruppiereZuItems: () => gruppiereZuItems,
@@ -163,13 +173,17 @@ __export(szenen_exports, {
163
173
  istSzenenSnapshotDatei: () => istSzenenSnapshotDatei,
164
174
  istZipDatei: () => istZipDatei,
165
175
  itemIdForRun: () => itemIdForRun,
176
+ itemsAusBestand: () => itemsAusBestand,
177
+ jobsForPromptRun: () => jobsForPromptRun,
166
178
  ladeVorschauen: () => ladeVorschauen,
167
179
  leseBilderAusZip: () => leseBilderAusZip,
168
180
  linkFor: () => linkFor,
181
+ locatorAus: () => locatorAus,
169
182
  locatorTeile: () => locatorTeile,
170
183
  logRevisionOf: () => logRevisionOf,
171
184
  mergeSnapshotAndPending: () => mergeSnapshotAndPending,
172
185
  mergeSzenenBatchOrigin: () => mergeSzenenBatchOrigin,
186
+ mimeTypAus: () => mimeTypAus,
173
187
  mitDefaultVorlage: () => mitDefaultVorlage,
174
188
  noticeFor: () => noticeFor,
175
189
  ordersForPromptRun: () => ordersForPromptRun,
@@ -180,6 +194,7 @@ __export(szenen_exports, {
180
194
  parseSzenenSnapshot: () => parseSzenenSnapshot,
181
195
  preferredHeadRevisionOf: () => preferredHeadRevisionOf,
182
196
  preferredVersionId: () => preferredVersionId,
197
+ preparePromptOperation: () => preparePromptOperation,
183
198
  promptDiagnosticsOf: () => promptDiagnosticsOf,
184
199
  publishedHeadsOf: () => publishedHeadsOf,
185
200
  recoveriesForRun: () => recoveriesForRun,
@@ -192,13 +207,16 @@ __export(szenen_exports, {
192
207
  resolveShotPayload: () => resolveShotPayload,
193
208
  resolveTargetModelOver: () => resolveTargetModelOver,
194
209
  resolverFromQueries: () => resolverFromQueries,
210
+ responseContractOf: () => responseContractOf,
195
211
  roundOfRun: () => roundOfRun,
196
212
  rulesWithoutPromptEffect: () => rulesWithoutPromptEffect,
197
213
  runElementStoreContract: () => runElementStoreContract,
214
+ runOfOperation: () => runOfOperation,
198
215
  runPromptDerivation: () => runPromptDerivation,
199
216
  runPublishChecks: () => runPublishChecks,
200
217
  runSceneDerivation: () => runSceneDerivation,
201
218
  runStoreDifferential: () => runStoreDifferential,
219
+ sameResponseAs: () => sameResponseAs,
202
220
  sceneOnlyCapabilities: () => sceneOnlyCapabilities,
203
221
  scopeOfPath: () => scopeOfPath,
204
222
  seedFehlerText: () => seedFehlerText,
@@ -4806,11 +4824,11 @@ async function resolveShotPayload(input) {
4806
4824
  };
4807
4825
  }
4808
4826
  const shot = shotPayload;
4809
- for (const fehler4 of ohneKettenReferenz(
4827
+ for (const fehler5 of ohneKettenReferenz(
4810
4828
  validatePayload("shot", shotPayload).errors,
4811
4829
  chain ? "scene_setup_ref" : null
4812
4830
  )) {
4813
- diagnostics.push(diagnosticOfSchemaError(fehler4, `Shot ${shotElementId}`));
4831
+ diagnostics.push(diagnosticOfSchemaError(fehler5, `Shot ${shotElementId}`));
4814
4832
  }
4815
4833
  let setup = null;
4816
4834
  let report = null;
@@ -4922,8 +4940,8 @@ async function resolveScenePayload(input) {
4922
4940
  "Kein Scene Setup, kein Shot: Der Lauf entsteht aus der Szene allein. Bildaufbau, Kamera und Zielmodell wurden nicht ergaenzt, sondern sind nicht vorhanden (D-135)."
4923
4941
  ];
4924
4942
  const diagnostics = [];
4925
- for (const fehler4 of validatePayload("scene", scenePayload).errors) {
4926
- diagnostics.push(diagnosticOfSchemaError(fehler4, `Szene ${sceneElementId}`));
4943
+ for (const fehler5 of validatePayload("scene", scenePayload).errors) {
4944
+ diagnostics.push(diagnosticOfSchemaError(fehler5, `Szene ${sceneElementId}`));
4927
4945
  }
4928
4946
  const faehig = sceneOnlyCapabilities(scenePayload);
4929
4947
  return komponiere({
@@ -5813,7 +5831,60 @@ var SZENEN_EVENT_TYPES = {
5813
5831
  * Der Elementreducer ignoriert auch diesen Typ (`default:`-Zweig); gelesen
5814
5832
  * wird mit `collectImageBatches` (`imageBatchStore.ts`).
5815
5833
  */
5816
- imageBatchPersisted: "szenen.image_batch_persisted"
5834
+ imageBatchPersisted: "szenen.image_batch_persisted",
5835
+ /**
5836
+ * Ein vorbereiteter Promptvorgang — der Durchstich „Szene → ChatGPT → Lauf".
5837
+ *
5838
+ * Der bestehende Promptpfad ruft das Modell selbst
5839
+ * (`runPromptDerivation()`); ein aufrufendes Chatmodell formuliert dagegen
5840
+ * **zwischen** zwei Werkzeugaufrufen. Damit zerfaellt der eine Vorgang in
5841
+ * zwei, und der zweite braucht genau den Stand, den der erste eingefroren
5842
+ * hat — sonst loeste der Abschluss die inzwischen geaenderte Szene neu auf
5843
+ * und der Lauf behauptete eine Herkunft, die er nicht hat (D-22).
5844
+ *
5845
+ * Deshalb ein eigenes Ereignis und **kein** fluechtiger Prozesszustand: Der
5846
+ * Snapshot ueberlebt Neustart, Hostwechsel und Sitzungsende, weil er im
5847
+ * selben autoritativen Log liegt wie der Lauf, der daraus entsteht.
5848
+ *
5849
+ * Der Elementreducer ignoriert diesen Typ (`default:`-Zweig); gelesen wird
5850
+ * mit `collectPromptOperations` (`scenePromptOperation.ts`).
5851
+ */
5852
+ promptOperationPrepared: "szenen.prompt_operation_prepared",
5853
+ /**
5854
+ * Ein Bildauftrag wartet auf einen ausfuehrenden Flow-Host.
5855
+ *
5856
+ * Die vorhandene Auftragshistorie (`imageGenerationStarted`) beginnt
5857
+ * **unmittelbar vor** dem Provideraufruf und kennt deshalb keinen wartenden
5858
+ * Auftrag. Genau der entsteht hier: Ein Chatmodell beauftragt ueber MCP ein
5859
+ * Bild, der Auftrag wird dauerhaft abgelegt, und der Werkzeugaufruf endet
5860
+ * sofort mit seiner Kennung — er haelt keine Antwort minutenlang offen.
5861
+ *
5862
+ * Traegt **keinen** Prompt: Der steht im referenzierten Lauf, und ihn hier
5863
+ * zu kopieren waere eine zweite Wahrheit ueber denselben eingefrorenen Text
5864
+ * (D-103).
5865
+ */
5866
+ imageJobRequested: "szenen.image_job_requested",
5867
+ /**
5868
+ * Ein Flow-Host beansprucht einen wartenden Bildauftrag.
5869
+ *
5870
+ * Ein append-only Log kennt kein Lock: Zwei Tabs koennen beide anhaengen.
5871
+ * Deshalb ist die Uebernahme **nicht** der Append, sondern das Ergebnis
5872
+ * einer deterministischen Schiedsregel darueber (`winningClaimOf`) — der
5873
+ * erste Anspruch in Logreihenfolge gewinnt, und jeder Host liest nach
5874
+ * seinem Append erneut, bevor er einen bezahlten Provideraufruf startet.
5875
+ * Ein unterlegener Anspruch bleibt sichtbar stehen; er wird nicht geloescht,
5876
+ * weil das Log das nicht kann und weil der Versuch ein Beleg ist.
5877
+ */
5878
+ imageJobClaimed: "szenen.image_job_claimed",
5879
+ /**
5880
+ * Der Bildauftrag ist erledigt — mit dem Ausgang, den der Host gesehen hat.
5881
+ *
5882
+ * Getrennt von `imageGenerationFinished`: Jenes gehoert zum bezahlten
5883
+ * Provideraufruf, dieses zur Zustellung. Ein Auftrag kann fehlschlagen,
5884
+ * **bevor** ein Provider gerufen wurde (abgelehntes Profil), und dann gibt
5885
+ * es kein `imageGenerationFinished`, das den Wartenden erloesen wuerde.
5886
+ */
5887
+ imageJobSettled: "szenen.image_job_settled"
5817
5888
  };
5818
5889
  function sortForReplay(events) {
5819
5890
  return [...events].sort((a, b) => {
@@ -8379,9 +8450,9 @@ function mergeSnapshotAndPending(snapshot, pending, bereitsImSnapshot = 0) {
8379
8450
  }
8380
8451
 
8381
8452
  // src/lib/hfEventLog.ts
8382
- function treeUrl(namespace, subdir = "") {
8453
+ function treeUrl(namespace, subdir = "", revision = "main") {
8383
8454
  const parts = [namespace.replace(/\/$/, ""), subdir].filter(Boolean).join("/");
8384
- return `${HF_BASE}/api/datasets/${HF_REPO}/tree/main${parts ? "/" + parts : ""}`;
8455
+ return `${HF_BASE}/api/datasets/${HF_REPO}/tree/${encodeURIComponent(revision)}${parts ? "/" + parts : ""}`;
8385
8456
  }
8386
8457
  var DROSSEL_VERSUCHE = 4;
8387
8458
  var DROSSEL_BASIS_MS = 400;
@@ -8414,8 +8485,8 @@ async function mitGeduld(anfrage) {
8414
8485
  }
8415
8486
  return letzte;
8416
8487
  }
8417
- async function hfListDir(namespace, subdir, token) {
8418
- const res = await mitGeduld(() => holeMitZeitlimit(treeUrl(namespace, subdir), {
8488
+ async function hfListDir(namespace, subdir, token, revision = "main") {
8489
+ const res = await mitGeduld(() => holeMitZeitlimit(treeUrl(namespace, subdir, revision), {
8419
8490
  headers: { Authorization: `Bearer ${token}` }
8420
8491
  }));
8421
8492
  if (res.status === 404) return [];
@@ -8444,17 +8515,46 @@ function toBase64(text) {
8444
8515
  bytes.forEach((b) => binary += String.fromCharCode(b));
8445
8516
  return btoa(binary);
8446
8517
  }
8447
- async function hfUploadSmallFile(repoPath, content, token, summary = `Update ${repoPath}`) {
8518
+ var HfPreconditionFailedError = class extends Error {
8519
+ constructor(message) {
8520
+ super(message);
8521
+ this.name = "HfPreconditionFailed";
8522
+ }
8523
+ };
8524
+ async function hfRepoHead(token, revision = "main") {
8525
+ const res = await mitGeduld(() => holeMitZeitlimit(
8526
+ `${HF_BASE}/api/datasets/${HF_REPO}/revision/${encodeURIComponent(revision)}`,
8527
+ { headers: { Authorization: `Bearer ${token}` } }
8528
+ ));
8529
+ if (!res.ok) {
8530
+ throw new Error(`HF revision failed: ${res.status} ${res.statusText} (${revision})`);
8531
+ }
8532
+ const daten = await res.json();
8533
+ if (typeof daten.sha !== "string" || daten.sha.length === 0) {
8534
+ throw new Error(
8535
+ `HF revision ${revision}: die Antwort traegt kein "sha". Erhaltene Felder: ${Object.keys(daten || {}).join(", ") || "(keine)"}.`
8536
+ );
8537
+ }
8538
+ return daten.sha;
8539
+ }
8540
+ async function hfUploadSmallFile(repoPath, content, token, summary = `Update ${repoPath}`, options) {
8541
+ const kopf = { summary, description: "" };
8542
+ if (options?.parentCommit) kopf.parentCommit = options.parentCommit;
8448
8543
  const res = await fetch(`${HF_BASE}/api/datasets/${HF_REPO}/commit/main`, {
8449
8544
  method: "POST",
8450
8545
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/x-ndjson" },
8451
8546
  body: [
8452
- JSON.stringify({ key: "header", value: { summary, description: "" } }),
8547
+ JSON.stringify({ key: "header", value: kopf }),
8453
8548
  JSON.stringify({ key: "file", value: { path: repoPath, encoding: "base64", content: toBase64(content) } })
8454
8549
  ].join("\n")
8455
8550
  });
8456
8551
  if (!res.ok) {
8457
8552
  const err = await res.text().catch(() => "");
8553
+ if (options?.parentCommit && (res.status === 412 || res.status === 409)) {
8554
+ throw new HfPreconditionFailedError(
8555
+ `HF commit abgelehnt: Der Branch hat sich seit ${options.parentCommit} bewegt (${res.status}). Es wurde nichts geschrieben.`
8556
+ );
8557
+ }
8458
8558
  throw new Error(`HF upload failed: ${res.status} \u2014 ${err.slice(0, 200)}`);
8459
8559
  }
8460
8560
  }
@@ -8486,8 +8586,8 @@ async function mitBegrenzterParallelitaet(count, limit, task) {
8486
8586
  await Promise.all(Array.from({ length: Math.min(limit, count) }, worker));
8487
8587
  if (fehlerAufgetreten) throw ersterFehler;
8488
8588
  }
8489
- async function loadPendingEvents(namespace, token, sinceTs, knownPaths) {
8490
- const files = await hfListDir(namespace, "events", token);
8589
+ async function loadPendingEvents(namespace, token, sinceTs, knownPaths, revision = "main") {
8590
+ const files = await hfListDir(namespace, "events", token, revision);
8491
8591
  const pending = files.filter((f) => f.type === "file" && tsFromEventPath(f.path) > sinceTs && !knownPaths?.has(f.path)).sort((a, b) => a.path.localeCompare(b.path));
8492
8592
  if (!pending.length) return [];
8493
8593
  const raw = new Array(pending.length);
@@ -8529,7 +8629,13 @@ async function writeHFEvent(namespace, token, type, payload, prevTs, options) {
8529
8629
  const suffix = options?.ordered ? `${String(++writeSeq % 1e6).padStart(6, "0")}${uuid}` : uuid;
8530
8630
  const filename = `${tsToFilename(ts)}_${suffix}.json`;
8531
8631
  const repoPath = `${namespace}events/${filename}`;
8532
- await hfUploadSmallFile(repoPath, JSON.stringify(event, null, 2), token, `Event: ${type}`);
8632
+ await hfUploadSmallFile(
8633
+ repoPath,
8634
+ JSON.stringify(event, null, 2),
8635
+ token,
8636
+ `Event: ${type}`,
8637
+ options?.parentCommit ? { parentCommit: options.parentCommit } : void 0
8638
+ );
8533
8639
  return event;
8534
8640
  }
8535
8641
 
@@ -8541,7 +8647,7 @@ function createHfEventChannel(options) {
8541
8647
  let syncInFlight = null;
8542
8648
  let snapshot = null;
8543
8649
  let snapshotGeladen = ohneSnapshot;
8544
- const refresh = async () => {
8650
+ const refresh = async (revision = "main") => {
8545
8651
  if (!snapshotGeladen) {
8546
8652
  snapshot = await loadLatestSzenenSnapshot(namespace, token);
8547
8653
  snapshotGeladen = true;
@@ -8549,7 +8655,7 @@ function createHfEventChannel(options) {
8549
8655
  knownPaths.add(`${namespace}events/${name}`);
8550
8656
  }
8551
8657
  }
8552
- const neue = await loadPendingEvents(namespace, token, sinceTs, knownPaths);
8658
+ const neue = await loadPendingEvents(namespace, token, sinceTs, knownPaths, revision);
8553
8659
  if (neue.length) cachedRawEvents = [...cachedRawEvents, ...neue];
8554
8660
  };
8555
8661
  const sync = () => {
@@ -8560,16 +8666,34 @@ function createHfEventChannel(options) {
8560
8666
  }
8561
8667
  return syncInFlight;
8562
8668
  };
8669
+ const sicht = () => {
8670
+ const pending = cachedRawEvents.filter((event) => typeof event.type === "string" && event.type.startsWith(SZENEN_EVENT_PREFIX)).map((event) => ({
8671
+ type: event.type,
8672
+ payload: event.payload,
8673
+ clientId: event.clientId,
8674
+ ts: event.ts
8675
+ }));
8676
+ return mergeSnapshotAndPending(snapshot, pending).events;
8677
+ };
8563
8678
  return {
8564
8679
  async readEvents() {
8565
8680
  await sync();
8566
- const pending = cachedRawEvents.filter((event) => typeof event.type === "string" && event.type.startsWith(SZENEN_EVENT_PREFIX)).map((event) => ({
8567
- type: event.type,
8568
- payload: event.payload,
8569
- clientId: event.clientId,
8570
- ts: event.ts
8571
- }));
8572
- return mergeSnapshotAndPending(snapshot, pending).events;
8681
+ return sicht();
8682
+ },
8683
+ async readHead() {
8684
+ return hfRepoHead(token);
8685
+ },
8686
+ async readEventsAt(revision) {
8687
+ await refresh(revision);
8688
+ return sicht();
8689
+ },
8690
+ async appendEventAt(type, payload, parentCommit) {
8691
+ if (!type.startsWith(SZENEN_EVENT_PREFIX)) {
8692
+ throw new Error(
8693
+ `Event-Typ "${type}" gehoert nicht zur Domain szenen. Der geteilte Kanal wird ueber das Praefix "${SZENEN_EVENT_PREFIX}" getrennt.`
8694
+ );
8695
+ }
8696
+ await writeHFEvent(namespace, token, type, payload, [], { ordered: true, parentCommit });
8573
8697
  },
8574
8698
  async appendEvent(type, payload) {
8575
8699
  if (!type.startsWith(SZENEN_EVENT_PREFIX)) {
@@ -10142,7 +10266,8 @@ function capabilitiesOf(port) {
10142
10266
  imageBatchHistory: typeof port.imageBatchHistory?.listBatchesForPromptRun === "function",
10143
10267
  imageOrderHistory: typeof port.imageBatchHistory?.listOrdersForPromptRun === "function",
10144
10268
  imageBatchWrite: typeof port.imageBatchWrite?.importBatch === "function",
10145
- imageGeneration: typeof port.imageGeneration?.startFromPromptRun === "function"
10269
+ imageGeneration: typeof port.imageGeneration?.startFromPromptRun === "function",
10270
+ imageJobs: typeof port.imageJobs?.claimAndRun === "function"
10146
10271
  };
10147
10272
  }
10148
10273
  function unsupportedReason(capability) {
@@ -10476,6 +10601,44 @@ function gruppiereZuItems(bilder) {
10476
10601
  items.sort((a, b) => b.juengstes - a.juengstes);
10477
10602
  return items.map((e) => e.item);
10478
10603
  }
10604
+ function locatorAus(itemId, position, anzahl) {
10605
+ return anzahl === 1 ? itemId : `${itemId}-${position}`;
10606
+ }
10607
+ function mimeTypAus(dateiname) {
10608
+ const n = dateiname.toLowerCase();
10609
+ if (n.endsWith(".png")) return "image/png";
10610
+ if (n.endsWith(".webp")) return "image/webp";
10611
+ return "image/jpeg";
10612
+ }
10613
+ function passt(item, suche) {
10614
+ const f = suche.trim().toLowerCase();
10615
+ if (!f) return true;
10616
+ return (item.title ?? "").toLowerCase().includes(f) || item.id.toLowerCase().includes(f);
10617
+ }
10618
+ function itemsAusBestand(items, options = {}) {
10619
+ const suche = options.search ?? "";
10620
+ const werke = [];
10621
+ const passende = items.filter((i) => i && typeof i.id === "string" && i.id.length > 0 && passt(i, suche)).sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0) || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0));
10622
+ for (const item of passende) {
10623
+ const galerie = Array.isArray(item.gallery) ? item.gallery : [];
10624
+ const titel = item.title || item.id;
10625
+ const bilder = [];
10626
+ galerie.forEach((eintrag, position) => {
10627
+ const datei = eintrag?.file;
10628
+ if (!datei) return;
10629
+ bilder.push({
10630
+ mediaRef: locatorAus(item.id, position, galerie.length),
10631
+ title: galerie.length === 1 ? titel : `${titel} \xB7 Bild ${position + 1}`,
10632
+ mimeType: mimeTypAus(String(datei)),
10633
+ thumbUrl: options.thumbUrl ? options.thumbUrl(String(datei)) : null
10634
+ });
10635
+ });
10636
+ if (bilder.length === 0) continue;
10637
+ werke.push({ itemRef: item.id, title: titel, images: bilder });
10638
+ if (options.limit && werke.length >= options.limit) break;
10639
+ }
10640
+ return werke;
10641
+ }
10479
10642
 
10480
10643
  // src/lib/szenen/hfImageLibrary.ts
10481
10644
  function fehler(nachricht, retryable = false) {
@@ -12669,8 +12832,8 @@ function createFlowImageProvider(generateImage) {
12669
12832
  // Kein Seed: weder als Eingabe dokumentiert noch als Ausgabe
12670
12833
  // geliefert — nichts wird erfunden (D-107).
12671
12834
  });
12672
- } catch (fehler4) {
12673
- ersterFehler = fehler4 instanceof Error ? fehler4.message : String(fehler4);
12835
+ } catch (fehler5) {
12836
+ ersterFehler = fehler5 instanceof Error ? fehler5.message : String(fehler5);
12674
12837
  break;
12675
12838
  }
12676
12839
  }
@@ -12880,6 +13043,252 @@ function createHfImageBatchWrite(options) {
12880
13043
  };
12881
13044
  }
12882
13045
 
13046
+ // src/lib/szenen/imageJobStore.ts
13047
+ var istText7 = (wert) => typeof wert === "string" && wert.trim().length > 0;
13048
+ var SETTLED_STATUS = ["succeeded", "partial", "failed", "rejected"];
13049
+ function collectImageJobs(events) {
13050
+ const nachId = /* @__PURE__ */ new Map();
13051
+ for (const event of events) {
13052
+ if (event.type !== SZENEN_EVENT_TYPES.imageJobRequested) continue;
13053
+ const payload = event.payload;
13054
+ if (!payload || !istText7(payload.job_id) || !istText7(payload.prompt_run_id)) continue;
13055
+ if (nachId.has(payload.job_id)) continue;
13056
+ nachId.set(payload.job_id, {
13057
+ job_id: payload.job_id,
13058
+ prompt_run_id: payload.prompt_run_id,
13059
+ execution_target_model_key: payload.execution_target_model_key ?? "",
13060
+ execution_profile_id: payload.execution_profile_id ?? "",
13061
+ image_count: typeof payload.image_count === "number" ? payload.image_count : 0,
13062
+ ...payload.aspect_ratio ? { aspect_ratio: payload.aspect_ratio } : {},
13063
+ requested_by: payload.requested_by ?? "",
13064
+ store_id: payload.store_id ?? "",
13065
+ created_at: payload.created_at ?? "",
13066
+ status: "pending",
13067
+ claim_attempts: []
13068
+ });
13069
+ }
13070
+ for (const event of events) {
13071
+ if (event.type !== SZENEN_EVENT_TYPES.imageJobClaimed) continue;
13072
+ const payload = event.payload;
13073
+ if (!payload || !istText7(payload.job_id) || !istText7(payload.claim_id)) continue;
13074
+ const auftrag = nachId.get(payload.job_id);
13075
+ if (!auftrag) continue;
13076
+ const anspruch = {
13077
+ job_id: payload.job_id,
13078
+ claim_id: payload.claim_id,
13079
+ client_id: payload.client_id ?? "",
13080
+ claimed_at: payload.claimed_at ?? ""
13081
+ };
13082
+ nachId.set(payload.job_id, {
13083
+ ...auftrag,
13084
+ claim: auftrag.claim ?? anspruch,
13085
+ claim_attempts: [...auftrag.claim_attempts, anspruch],
13086
+ status: auftrag.status === "pending" ? "claimed" : auftrag.status
13087
+ });
13088
+ }
13089
+ for (const event of events) {
13090
+ if (event.type !== SZENEN_EVENT_TYPES.imageJobSettled) continue;
13091
+ const payload = event.payload;
13092
+ if (!payload || !istText7(payload.job_id)) continue;
13093
+ const auftrag = nachId.get(payload.job_id);
13094
+ if (!auftrag) continue;
13095
+ if (!auftrag.claim || auftrag.claim.claim_id !== payload.claim_id) continue;
13096
+ if (auftrag.status !== "claimed") continue;
13097
+ if (!SETTLED_STATUS.includes(payload.status)) continue;
13098
+ nachId.set(payload.job_id, {
13099
+ ...auftrag,
13100
+ status: payload.status,
13101
+ ...payload.generation_batch_id ? { generation_batch_id: payload.generation_batch_id } : {},
13102
+ ...payload.item_id ? { item_id: payload.item_id } : {},
13103
+ ...typeof payload.produced_count === "number" ? { produced_count: payload.produced_count } : {},
13104
+ ...payload.diagnostic ? { diagnostic: payload.diagnostic } : {},
13105
+ settled_at: payload.settled_at ?? ""
13106
+ });
13107
+ }
13108
+ return [...nachId.values()];
13109
+ }
13110
+ function jobsForPromptRun(events, runId) {
13111
+ return collectImageJobs(events).filter((j) => j.prompt_run_id === runId);
13112
+ }
13113
+ function findImageJob(events, jobId) {
13114
+ return collectImageJobs(events).find((j) => j.job_id === jobId) ?? null;
13115
+ }
13116
+ function claimWon(job, claimId) {
13117
+ return Boolean(job && job.claim && job.claim.claim_id === claimId);
13118
+ }
13119
+ function generationBatchIdOf(jobId) {
13120
+ return `job-${jobId}`;
13121
+ }
13122
+
13123
+ // src/lib/szenen/imageJobPort.ts
13124
+ var ANSPRUCH_VERSUCHE = 4;
13125
+ function fehler4(error, aktion) {
13126
+ return {
13127
+ message: `${aktion}: ${error instanceof Error ? error.message : String(error)}`
13128
+ };
13129
+ }
13130
+ function createImageJobPort(options) {
13131
+ const { channel, imageGeneration, storeId, clientId } = options;
13132
+ const newClaimId = options.newClaimId ?? (() => crypto.randomUUID());
13133
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
13134
+ return {
13135
+ async listJobs(runId) {
13136
+ try {
13137
+ return { kind: "ok", value: jobsForPromptRun(await channel.readEvents(), runId) };
13138
+ } catch (error) {
13139
+ return {
13140
+ kind: "error",
13141
+ ...fehler4(error, `Die Bildauftraege des Laufs ${runId} konnten nicht gelesen werden`),
13142
+ retryable: true
13143
+ };
13144
+ }
13145
+ },
13146
+ async claimAndRun(jobId) {
13147
+ let letzterGrund = "";
13148
+ for (let versuch = 1; versuch <= ANSPRUCH_VERSUCHE; versuch += 1) {
13149
+ let kopf;
13150
+ try {
13151
+ kopf = await channel.readHead();
13152
+ } catch (error) {
13153
+ return {
13154
+ kind: "error",
13155
+ ...fehler4(error, `Der Kopf-Commit des Bestands war nicht lesbar; Bildauftrag ${jobId} wurde nicht uebernommen`),
13156
+ retryable: true
13157
+ };
13158
+ }
13159
+ let auftrag;
13160
+ try {
13161
+ auftrag = findImageJob(await channel.readEventsAt(kopf), jobId);
13162
+ } catch (error) {
13163
+ return {
13164
+ kind: "error",
13165
+ ...fehler4(error, `Der Bildauftrag ${jobId} konnte nicht gelesen werden`),
13166
+ retryable: true
13167
+ };
13168
+ }
13169
+ if (!auftrag) {
13170
+ return {
13171
+ kind: "rejected",
13172
+ message: `Der Bildauftrag ${jobId} steht nicht im autoritativen Log dieses Bestands.`
13173
+ };
13174
+ }
13175
+ if (auftrag.store_id !== storeId) {
13176
+ return {
13177
+ kind: "rejected",
13178
+ message: `Der Bildauftrag ${jobId} gilt fuer den Bestand "${auftrag.store_id}", dieser Host arbeitet auf "${storeId}". Nutzer, Umgebung und Bestand muessen zusammenpassen.`
13179
+ };
13180
+ }
13181
+ if (auftrag.status !== "pending") {
13182
+ return {
13183
+ kind: "lost",
13184
+ job: auftrag,
13185
+ message: `Der Bildauftrag ${jobId} ist bereits "${auftrag.status}"` + (auftrag.claim ? ` (Client ${auftrag.claim.client_id})` : "") + ". Er wird nicht erneut ausgefuehrt \u2014 ein zweiter Lauf waere ein zweites Mal bezahlte Rechenzeit."
13186
+ };
13187
+ }
13188
+ const anspruch = {
13189
+ job_id: jobId,
13190
+ claim_id: newClaimId(),
13191
+ client_id: clientId,
13192
+ claimed_at: now().toISOString()
13193
+ };
13194
+ try {
13195
+ await channel.appendEventAt(
13196
+ SZENEN_EVENT_TYPES.imageJobClaimed,
13197
+ anspruch,
13198
+ kopf
13199
+ );
13200
+ } catch (error) {
13201
+ if (istPreconditionFehler(error)) {
13202
+ letzterGrund = error instanceof Error ? error.message : String(error);
13203
+ continue;
13204
+ }
13205
+ return {
13206
+ kind: "error",
13207
+ ...fehler4(error, `Der Anspruch auf Bildauftrag ${jobId} konnte nicht angehaengt werden`),
13208
+ retryable: true
13209
+ };
13210
+ }
13211
+ const gewonnen = {
13212
+ ...auftrag,
13213
+ status: "claimed",
13214
+ claim: anspruch,
13215
+ claim_attempts: [...auftrag.claim_attempts, anspruch]
13216
+ };
13217
+ return await fuehreAus(gewonnen, anspruch, jobId);
13218
+ }
13219
+ return {
13220
+ kind: "error",
13221
+ message: `Der Bildauftrag ${jobId} liess sich in ${ANSPRUCH_VERSUCHE} Versuchen nicht exklusiv uebernehmen \u2014 der Bestand wird gerade von anderer Seite beschrieben (${letzterGrund}). Es wurde nichts ausgefuehrt und nichts bezahlt; ein neuer Versuch ist gefahrlos.`,
13222
+ retryable: true
13223
+ };
13224
+ }
13225
+ };
13226
+ async function fuehreAus(gewonnen, anspruch, jobId) {
13227
+ const ergebnis = await imageGeneration.startFromPromptRun({
13228
+ runId: gewonnen.prompt_run_id,
13229
+ generationBatchId: generationBatchIdOf(jobId),
13230
+ executionTargetModelKey: gewonnen.execution_target_model_key,
13231
+ executionProfileId: gewonnen.execution_profile_id,
13232
+ imageCount: gewonnen.image_count,
13233
+ ...gewonnen.aspect_ratio ? { aspectRatio: gewonnen.aspect_ratio } : {}
13234
+ });
13235
+ const abschluss = {
13236
+ job_id: jobId,
13237
+ claim_id: anspruch.claim_id,
13238
+ ...abschlussFelder(ergebnis, jobId),
13239
+ settled_at: now().toISOString()
13240
+ };
13241
+ try {
13242
+ await channel.appendEvent(SZENEN_EVENT_TYPES.imageJobSettled, abschluss);
13243
+ } catch {
13244
+ }
13245
+ const gelesen = await channel.readEvents().catch(() => null);
13246
+ return {
13247
+ kind: "ok",
13248
+ job: (gelesen && findImageJob(gelesen, jobId)) ?? {
13249
+ ...gewonnen,
13250
+ status: abschluss.status,
13251
+ ...abschluss.generation_batch_id ? { generation_batch_id: abschluss.generation_batch_id } : {},
13252
+ ...abschluss.diagnostic ? { diagnostic: abschluss.diagnostic } : {},
13253
+ settled_at: abschluss.settled_at
13254
+ }
13255
+ };
13256
+ }
13257
+ }
13258
+ function istPreconditionFehler(error) {
13259
+ return Boolean(error && typeof error === "object" && error.name === "HfPreconditionFailed");
13260
+ }
13261
+ function abschlussFelder(ergebnis, jobId) {
13262
+ const batchId = generationBatchIdOf(jobId);
13263
+ switch (ergebnis.kind) {
13264
+ case "succeeded":
13265
+ return {
13266
+ status: "succeeded",
13267
+ generation_batch_id: batchId,
13268
+ item_id: ergebnis.batch.item_id,
13269
+ produced_count: ergebnis.batch.images.length
13270
+ };
13271
+ case "partial":
13272
+ return {
13273
+ status: "partial",
13274
+ generation_batch_id: batchId,
13275
+ item_id: ergebnis.batch.item_id,
13276
+ produced_count: ergebnis.produced,
13277
+ diagnostic: `Angefordert ${ergebnis.requested}, geliefert ${ergebnis.produced}.`
13278
+ };
13279
+ case "failed":
13280
+ return { status: "failed", produced_count: 0, diagnostic: ergebnis.message };
13281
+ case "unsupported":
13282
+ return {
13283
+ status: "rejected",
13284
+ produced_count: 0,
13285
+ diagnostic: `Zielmodell "${ergebnis.targetModelKey}" ist in dieser Umgebung nicht ausfuehrbar: ${ergebnis.reason}`
13286
+ };
13287
+ default:
13288
+ return { status: "rejected", produced_count: 0, diagnostic: ergebnis.message };
13289
+ }
13290
+ }
13291
+
12883
13292
  // src/lib/szenen/flowViewPort.ts
12884
13293
  var defaultContext = {
12885
13294
  async chainFor(contextId) {
@@ -12978,10 +13387,21 @@ function createFlowSzenenViewPort(options) {
12978
13387
  },
12979
13388
  ...options.now ? { now: options.now } : {}
12980
13389
  }) : void 0;
13390
+ const kanalMitRevision = typeof channel.readHead === "function" && typeof channel.readEventsAt === "function" && typeof channel.appendEventAt === "function";
13391
+ const imageJobs = imageGeneration && hatHfZugangsdaten && kanalMitRevision ? createImageJobPort({
13392
+ channel,
13393
+ imageGeneration,
13394
+ // Dieselbe Form, in der der Server seinen Bestand kennt (`storeId`).
13395
+ storeId: `hf:${options.namespace}`,
13396
+ clientId: options.imageJobClientId ?? crypto.randomUUID(),
13397
+ ...options.newImageJobClaimId ? { newClaimId: options.newImageJobClaimId } : {},
13398
+ ...options.now ? { now: options.now } : {}
13399
+ }) : void 0;
12981
13400
  const port = { elements, context, runs, derivation, imageBatchHistory };
12982
13401
  if (imageLibrary) port.imageLibrary = imageLibrary;
12983
13402
  if (imageBatchWrite) port.imageBatchWrite = imageBatchWrite;
12984
13403
  if (imageGeneration) port.imageGeneration = imageGeneration;
13404
+ if (imageJobs) port.imageJobs = imageJobs;
12985
13405
  return port;
12986
13406
  }
12987
13407
 
@@ -13121,7 +13541,7 @@ var VERBOTEN_JE_HERKUNFT = {
13121
13541
  draft_chain: ["shot_version_id", "scene_setup_version_id"],
13122
13542
  scene_direct: ["shot_version_id", "shot_element_id", "scene_setup_version_id", "camera_id"]
13123
13543
  };
13124
- function istText7(wert) {
13544
+ function istText8(wert) {
13125
13545
  return typeof wert === "string" && wert.trim().length > 0;
13126
13546
  }
13127
13547
  function isObject12(wert) {
@@ -13141,7 +13561,7 @@ function pruefeLaufherkunft(quelle) {
13141
13561
  }
13142
13562
  if (quelle.kind === "published") {
13143
13563
  for (const feld of ["shot_version_id", "scene_setup_version_id"]) {
13144
- if (!istText7(quelle[feld])) {
13564
+ if (!istText8(quelle[feld])) {
13145
13565
  return { ok: false, message: `"source.${feld}" fehlt oder ist leer.` };
13146
13566
  }
13147
13567
  }
@@ -13152,11 +13572,11 @@ function pruefeLaufherkunft(quelle) {
13152
13572
  if (!isObject12(szene)) {
13153
13573
  return { ok: false, message: '"source.scene" muss ein Objekt sein.' };
13154
13574
  }
13155
- if (!istText7(szene.element_id)) {
13575
+ if (!istText8(szene.element_id)) {
13156
13576
  return { ok: false, message: '"source.scene.element_id" fehlt oder ist leer.' };
13157
13577
  }
13158
- const ausEntwurf = istText7(szene.draft_id);
13159
- const ausVersion = istText7(szene.version_id);
13578
+ const ausEntwurf = istText8(szene.draft_id);
13579
+ const ausVersion = istText8(szene.version_id);
13160
13580
  if (ausEntwurf === ausVersion) {
13161
13581
  return {
13162
13582
  ok: false,
@@ -13177,7 +13597,7 @@ function pruefeLaufherkunft(quelle) {
13177
13597
  }
13178
13598
  return { ok: true };
13179
13599
  }
13180
- if (!istText7(quelle.chain_id)) {
13600
+ if (!istText8(quelle.chain_id)) {
13181
13601
  return { ok: false, message: '"source.chain_id" fehlt oder ist leer.' };
13182
13602
  }
13183
13603
  if (!Array.isArray(quelle.nodes) || quelle.nodes.length === 0) {
@@ -13196,7 +13616,7 @@ function pruefeLaufherkunft(quelle) {
13196
13616
  message: `"source.nodes[${index}].type" ist unbekannt: ${JSON.stringify(knoten.type)}.`
13197
13617
  };
13198
13618
  }
13199
- if (!istText7(knoten.element_id) || !istText7(knoten.draft_id)) {
13619
+ if (!istText8(knoten.element_id) || !istText8(knoten.draft_id)) {
13200
13620
  return {
13201
13621
  ok: false,
13202
13622
  message: `"source.nodes[${index}]" braucht element_id und draft_id.`
@@ -13209,10 +13629,10 @@ function pruefeLaufherkunft(quelle) {
13209
13629
  };
13210
13630
  }
13211
13631
  }
13212
- if (quelle.derivation_run_id !== void 0 && !istText7(quelle.derivation_run_id)) {
13632
+ if (quelle.derivation_run_id !== void 0 && !istText8(quelle.derivation_run_id)) {
13213
13633
  return { ok: false, message: '"source.derivation_run_id" ist gesetzt, aber leer.' };
13214
13634
  }
13215
- if (quelle.derivation_recovery_id !== void 0 && !istText7(quelle.derivation_recovery_id)) {
13635
+ if (quelle.derivation_recovery_id !== void 0 && !istText8(quelle.derivation_recovery_id)) {
13216
13636
  return { ok: false, message: '"source.derivation_recovery_id" ist gesetzt, aber leer.' };
13217
13637
  }
13218
13638
  return { ok: true };
@@ -13232,7 +13652,7 @@ function checkPromptRunRecord(candidate) {
13232
13652
  }
13233
13653
  const herkunft = isObject12(quelle) && typeof quelle.kind === "string" ? quelle.kind : "published";
13234
13654
  for (const feld of PFLICHTFELDER) {
13235
- if (!istText7(record[feld])) {
13655
+ if (!istText8(record[feld])) {
13236
13656
  return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
13237
13657
  }
13238
13658
  }
@@ -13245,7 +13665,7 @@ function checkPromptRunRecord(candidate) {
13245
13665
  }
13246
13666
  }
13247
13667
  for (const feld of PFLICHT_JE_HERKUNFT[herkunft] ?? []) {
13248
- if (!istText7(record[feld])) {
13668
+ if (!istText8(record[feld])) {
13249
13669
  return {
13250
13670
  ok: false,
13251
13671
  message: `"${feld}" fehlt oder ist leer, wird bei Herkunft "${herkunft}" aber gebraucht.`
@@ -13253,7 +13673,7 @@ function checkPromptRunRecord(candidate) {
13253
13673
  }
13254
13674
  }
13255
13675
  for (const feld of VERBOTEN_JE_HERKUNFT[herkunft] ?? []) {
13256
- if (istText7(record[feld])) {
13676
+ if (istText8(record[feld])) {
13257
13677
  return {
13258
13678
  ok: false,
13259
13679
  message: `"${feld}" ist bei einem Lauf der Herkunft "${herkunft}" gesetzt. Dort gibt es diesen Wert nicht, und erfundene sind unzulaessig (D-98/D-135).`
@@ -13290,7 +13710,7 @@ function checkPromptRunRecord(candidate) {
13290
13710
  message: `"failure.class" ist unbekannt: ${JSON.stringify(failure.class)}. Erlaubt sind ${FAILURE_CLASSES.join(", ")}.`
13291
13711
  };
13292
13712
  }
13293
- if (!istText7(failure.message)) {
13713
+ if (!istText8(failure.message)) {
13294
13714
  return { ok: false, message: '"failure.message" fehlt oder ist leer.' };
13295
13715
  }
13296
13716
  return { ok: true };
@@ -13332,7 +13752,7 @@ function checkSceneDerivationRecord(candidate) {
13332
13752
  }
13333
13753
  const record = candidate;
13334
13754
  for (const feld of DERIVATION_PFLICHTFELDER) {
13335
- if (!istText7(record[feld])) {
13755
+ if (!istText8(record[feld])) {
13336
13756
  return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
13337
13757
  }
13338
13758
  }
@@ -13387,13 +13807,13 @@ function checkSceneDerivationRecord(candidate) {
13387
13807
  return { ok: false, message: '"follows" muss ein Objekt sein.' };
13388
13808
  }
13389
13809
  const f = folgt;
13390
- if (!istText7(f.run_id)) {
13810
+ if (!istText8(f.run_id)) {
13391
13811
  return { ok: false, message: '"follows.run_id" fehlt oder ist leer.' };
13392
13812
  }
13393
13813
  if (f.run_id === record.run_id) {
13394
13814
  return { ok: false, message: '"follows.run_id" zeigt auf den Lauf selbst.' };
13395
13815
  }
13396
- if (!istText7(f.note)) {
13816
+ if (!istText8(f.note)) {
13397
13817
  return {
13398
13818
  ok: false,
13399
13819
  message: '"follows.note" fehlt oder ist leer \u2014 ohne Beanstandung ist ein Folgelauf nicht nachvollziehbar (D-89).'
@@ -13407,7 +13827,7 @@ function checkSceneDerivationRecord(candidate) {
13407
13827
  }
13408
13828
  }
13409
13829
  const reply = record.reply;
13410
- if (reply !== void 0 && !istText7(reply)) {
13830
+ if (reply !== void 0 && !istText8(reply)) {
13411
13831
  return {
13412
13832
  ok: false,
13413
13833
  message: `"reply" ist unbrauchbar: erwartet wird eine nicht leere Zeichenkette, angekommen ist ${JSON.stringify(reply)}. Ohne "reply" einreichen ist zulaessig.`
@@ -13427,7 +13847,7 @@ function checkSceneDerivationRecord(candidate) {
13427
13847
  message: `"failure.class" ist unbekannt: ${JSON.stringify(failure.class)}. Erlaubt sind ${FAILURE_CLASSES.join(", ")}.`
13428
13848
  };
13429
13849
  }
13430
- if (!istText7(failure.message)) {
13850
+ if (!istText8(failure.message)) {
13431
13851
  return { ok: false, message: '"failure.message" fehlt oder ist leer.' };
13432
13852
  }
13433
13853
  if (Array.isArray(record.proposals) && record.proposals.length > 0) {
@@ -13482,7 +13902,7 @@ function checkSceneDerivationRecord(candidate) {
13482
13902
  };
13483
13903
  }
13484
13904
  for (const [gapIndex, luecke] of gaps.entries()) {
13485
- if (!luecke || typeof luecke !== "object" || !istText7(luecke.pointer) || !istText7(luecke.reason)) {
13905
+ if (!luecke || typeof luecke !== "object" || !istText8(luecke.pointer) || !istText8(luecke.reason)) {
13486
13906
  return {
13487
13907
  ok: false,
13488
13908
  message: `"proposals[${index}].gaps[${gapIndex}]" braucht pointer und reason.`
@@ -13508,7 +13928,7 @@ function checkSceneDerivationRecoveryRecord(candidate) {
13508
13928
  }
13509
13929
  const record = candidate;
13510
13930
  for (const feld of ["recovery_id", "run_id", "created_at"]) {
13511
- if (!istText7(record[feld])) {
13931
+ if (!istText8(record[feld])) {
13512
13932
  return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
13513
13933
  }
13514
13934
  }
@@ -13535,7 +13955,7 @@ function checkSceneDerivationRecoveryRecord(candidate) {
13535
13955
  return { ok: false, message: '"diagnostics" muss ein Array sein (auch ein leeres).' };
13536
13956
  }
13537
13957
  for (const [index, befund] of record.diagnostics.entries()) {
13538
- if (!befund || typeof befund !== "object" || !istText7(befund.code) || !istText7(befund.message)) {
13958
+ if (!befund || typeof befund !== "object" || !istText8(befund.code) || !istText8(befund.message)) {
13539
13959
  return {
13540
13960
  ok: false,
13541
13961
  message: `"diagnostics[${index}]" braucht code und message.`
@@ -13587,7 +14007,7 @@ function checkSceneDerivationRecoveryRecord(candidate) {
13587
14007
  }
13588
14008
  if (Array.isArray(gaps)) {
13589
14009
  for (const [gapIndex, luecke] of gaps.entries()) {
13590
- if (!luecke || typeof luecke !== "object" || !istText7(luecke.pointer) || !istText7(luecke.reason)) {
14010
+ if (!luecke || typeof luecke !== "object" || !istText8(luecke.pointer) || !istText8(luecke.reason)) {
13591
14011
  return {
13592
14012
  ok: false,
13593
14013
  message: `"proposals[${index}].gaps[${gapIndex}]" braucht pointer und reason.`
@@ -13623,6 +14043,120 @@ function checkSceneDerivationRecoveryRecord(candidate) {
13623
14043
  return { ok: true };
13624
14044
  }
13625
14045
 
14046
+ // src/lib/szenen/scenePromptOperation.ts
14047
+ var MCP_CLIENT_PROVIDER = "mcp_client";
14048
+ var UNVERIFIED_MODEL_ID = "mcp-client-unspecified";
14049
+ var istText9 = (wert) => typeof wert === "string" && wert.trim().length > 0;
14050
+ function collectPromptOperations(events) {
14051
+ const nachId = /* @__PURE__ */ new Map();
14052
+ for (const event of events) {
14053
+ if (event.type !== SZENEN_EVENT_TYPES.promptOperationPrepared) continue;
14054
+ const payload = event.payload;
14055
+ if (!payload || !istText9(payload.operation_id)) continue;
14056
+ if (nachId.has(payload.operation_id)) continue;
14057
+ nachId.set(payload.operation_id, payload);
14058
+ }
14059
+ return [...nachId.values()];
14060
+ }
14061
+ function findPromptOperation(events, operationId) {
14062
+ return collectPromptOperations(events).find((v) => v.operation_id === operationId) ?? null;
14063
+ }
14064
+ async function preparePromptOperation(input) {
14065
+ const now = input.now ?? (() => /* @__PURE__ */ new Date());
14066
+ const eingefroren = await freezeSceneWorkingState({
14067
+ sceneElementId: input.sceneElementId,
14068
+ store: input.store,
14069
+ resolver: input.resolver,
14070
+ contextChain: input.contextChain,
14071
+ userInstruction: input.userInstruction ?? null
14072
+ });
14073
+ if (eingefroren.kind !== "ok") return eingefroren;
14074
+ const rendererInput = eingefroren.input;
14075
+ return {
14076
+ kind: "ok",
14077
+ operation: {
14078
+ operation_id: input.operationId,
14079
+ scene: eingefroren.scene,
14080
+ context_id: input.contextId,
14081
+ user_instruction: input.userInstruction ?? null,
14082
+ renderer_input: rendererInput,
14083
+ renderer_instruction: buildSystemInstruction(rendererInput),
14084
+ renderer_payload: buildUserPrompt(rendererInput),
14085
+ response_contract: responseContractOf(rendererInput),
14086
+ prepared_by: input.preparedBy,
14087
+ created_at: now().toISOString()
14088
+ }
14089
+ };
14090
+ }
14091
+ function responseContractOf(input) {
14092
+ const model = input.target_model ?? {};
14093
+ return {
14094
+ format: "json",
14095
+ required_fields: ["positive", "negative", "feedback", "visibility", "notes"],
14096
+ negative_prompt_allowed: model.supports_negative_prompt === true,
14097
+ node_ids: input.scene.nodes.map((node) => node.node_id),
14098
+ prompt_language: typeof model.prompt_language === "string" ? model.prompt_language : "en"
14099
+ };
14100
+ }
14101
+ function completePromptOperation(input) {
14102
+ const now = input.now ?? (() => /* @__PURE__ */ new Date());
14103
+ const { operation } = input;
14104
+ const geparst = parseRunResponse(input.response);
14105
+ if (!geparst.ok) {
14106
+ return {
14107
+ kind: "rejected",
14108
+ message: `Die Antwort zu Vorgang ${operation.operation_id} ist nicht verwertbar: ${geparst.message}`
14109
+ };
14110
+ }
14111
+ const geprueft = checkRunResponse(geparst.value, operation.renderer_input);
14112
+ if (!geprueft.ok) {
14113
+ return {
14114
+ kind: "rejected",
14115
+ message: `Die Antwort zu Vorgang ${operation.operation_id} passt nicht zur eingefrorenen Eingabe: ${geprueft.message}`
14116
+ };
14117
+ }
14118
+ const origin = {
14119
+ host: "mcp",
14120
+ ...istText9(input.declaredModelId) ? { declared_model_id: input.declaredModelId } : {},
14121
+ renderer_instruction_was_system_prompt: false
14122
+ };
14123
+ return {
14124
+ kind: "ok",
14125
+ record: {
14126
+ run_id: input.runId,
14127
+ // Keine fingierten Kennungen (D-98/D-75) — genau wie beim
14128
+ // Szene-Direktlauf des bestehenden Pfads.
14129
+ shot_version_id: "",
14130
+ shot_element_id: "",
14131
+ scene_setup_version_id: "",
14132
+ camera_id: "",
14133
+ target_model_version_id: operation.renderer_input.target_model_resolution?.version_id ?? "",
14134
+ provider: MCP_CLIENT_PROVIDER,
14135
+ model_id: UNVERIFIED_MODEL_ID,
14136
+ // Die Renderer-Anweisung, wie sie der Vorgang eingefroren hat — nicht
14137
+ // eine zweite, jetzt neu gebaute Fassung.
14138
+ system_prompt: operation.renderer_instruction,
14139
+ input_payload: operation.renderer_input,
14140
+ status: "succeeded",
14141
+ failure: null,
14142
+ output: geprueft.output,
14143
+ raw_output: input.response,
14144
+ source: { kind: "scene_direct", scene: operation.scene },
14145
+ operation_id: operation.operation_id,
14146
+ execution_origin: origin,
14147
+ created_at: now().toISOString()
14148
+ }
14149
+ };
14150
+ }
14151
+ function runOfOperation(runs, operationId) {
14152
+ return runs.find(
14153
+ (run) => run.operation_id === operationId
14154
+ ) ?? null;
14155
+ }
14156
+ function sameResponseAs(run, response) {
14157
+ return (run.raw_output ?? "") === response;
14158
+ }
14159
+
13626
14160
  // src/lib/szenen/seedListe.ts
13627
14161
  var DEFAULT_SEED_VORLAGE = {
13628
14162
  name: "Default",
@@ -13717,9 +14251,9 @@ async function leseBilderAusZip(datei) {
13717
14251
  );
13718
14252
  }
13719
14253
  const { default: JSZip2 } = await import("jszip");
13720
- const archiv = await JSZip2.loadAsync(datei).catch((fehler4) => {
14254
+ const archiv = await JSZip2.loadAsync(datei).catch((fehler5) => {
13721
14255
  throw new Error(
13722
- `${name} konnte nicht als ZIP gelesen werden: ${fehler4 instanceof Error ? fehler4.message : String(fehler4)}`
14256
+ `${name} konnte nicht als ZIP gelesen werden: ${fehler5 instanceof Error ? fehler5.message : String(fehler5)}`
13723
14257
  );
13724
14258
  });
13725
14259
  const pfade = [];
@@ -13817,13 +14351,13 @@ function noticeFor(ergebnis, was) {
13817
14351
  };
13818
14352
  }
13819
14353
  case "rejected": {
13820
- const fehler4 = ergebnis.errors ?? [];
14354
+ const fehler5 = ergebnis.errors ?? [];
13821
14355
  const ungeprueft = ergebnis.unchecked ?? [];
13822
14356
  return {
13823
14357
  tone: "rejected",
13824
- text: `${was}: abgelehnt \u2014 ${fehler4.length} Befund${fehler4.length === 1 ? "" : "e"}.`,
14358
+ text: `${was}: abgelehnt \u2014 ${fehler5.length} Befund${fehler5.length === 1 ? "" : "e"}.`,
13825
14359
  details: [
13826
- ...fehler4.map((f) => `${f.path ?? "(ohne Pfad)"}: ${f.message ?? "ohne Meldung"}`),
14360
+ ...fehler5.map((f) => `${f.path ?? "(ohne Pfad)"}: ${f.message ?? "ohne Meldung"}`),
13827
14361
  // Nicht verschweigen: was nicht geprüft wurde, ist nicht in Ordnung,
13828
14362
  // sondern ungeprüft.
13829
14363
  ...ungeprueft.map((u) => `ungepr\xFCft: ${u}`)
@@ -15707,7 +16241,7 @@ var ERKLAERUNG = {
15707
16241
  };
15708
16242
  var CapabilityPanel = ({ port, elementId, setupPayload }) => {
15709
16243
  const [bericht, setBericht] = (0, import_react5.useState)(null);
15710
- const [fehler4, setFehler] = (0, import_react5.useState)(null);
16244
+ const [fehler5, setFehler] = (0, import_react5.useState)(null);
15711
16245
  (0, import_react5.useEffect)(() => {
15712
16246
  let abgemeldet = false;
15713
16247
  setBericht(null);
@@ -15729,10 +16263,10 @@ var CapabilityPanel = ({ port, elementId, setupPayload }) => {
15729
16263
  abgemeldet = true;
15730
16264
  };
15731
16265
  }, [port, elementId, setupPayload]);
15732
- if (fehler4) {
16266
+ if (fehler5) {
15733
16267
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { "data-testid": "capability-fehler", role: "alert", children: [
15734
16268
  "F\xE4higkeitsbericht nicht erstellbar: ",
15735
- fehler4
16269
+ fehler5
15736
16270
  ] });
15737
16271
  }
15738
16272
  if (!bericht) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { "data-testid": "capability-laden", children: "F\xE4higkeitsbericht wird erstellt \u2026" });
@@ -16139,6 +16673,7 @@ var RunImagesPanel = ({ port, lauf }) => {
16139
16673
  const neuLesen = () => setNachladen((n) => n + 1);
16140
16674
  const [erzeugenOffen, setErzeugenOffen] = (0, import_react8.useState)(null);
16141
16675
  const [zuordnenOffen, setZuordnenOffen] = (0, import_react8.useState)(null);
16676
+ const [chatAuftraegeOffen, setChatAuftraegeOffen] = (0, import_react8.useState)(null);
16142
16677
  const quelle = sourceOf(lauf);
16143
16678
  const [wahlPhase] = usePortQuery(
16144
16679
  () => port.imageGeneration ? port.imageGeneration.imageModelChoiceForRun(lauf.run_id) : Promise.resolve({ kind: "ok", value: null }),
@@ -16153,10 +16688,17 @@ var RunImagesPanel = ({ port, lauf }) => {
16153
16688
  () => port.imageBatchHistory ? port.imageBatchHistory.listBatchesForPromptRun(lauf.run_id) : Promise.resolve({ kind: "ok", value: [] }),
16154
16689
  [port, lauf.run_id, nachladen]
16155
16690
  );
16691
+ const [chatAuftraegePhase] = usePortQuery(
16692
+ () => port.imageJobs ? port.imageJobs.listJobs(lauf.run_id) : Promise.resolve({ kind: "ok", value: [] }),
16693
+ [port, lauf.run_id, nachladen]
16694
+ );
16156
16695
  const auftraege = auftraegePhase.status === "ready" ? auftraegePhase.value : [];
16157
16696
  const batches = batchesPhase.status === "ready" ? batchesPhase.value : [];
16697
+ const chatAuftraege = chatAuftraegePhase.status === "ready" ? chatAuftraegePhase.value : [];
16698
+ const offeneChatAuftraege = chatAuftraege.filter((a) => a.status === "pending").length;
16158
16699
  const auffaellige = auftraege.filter((a) => a.status !== "succeeded");
16159
16700
  const erzeugenAuf = erzeugenOffen ?? batches.length === 0;
16701
+ const chatAuftraegeAuf = chatAuftraegeOffen ?? offeneChatAuftraege > 0;
16160
16702
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "szenen-bilder", "data-testid": `bilder-${lauf.run_id}`, children: [
16161
16703
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "szenen-bilder__eingang", "data-testid": `eingang-${lauf.run_id}`, children: [
16162
16704
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h5", { children: "Eingang \u2014 woraus dieser Prompt entstand" }),
@@ -16277,6 +16819,43 @@ var RunImagesPanel = ({ port, lauf }) => {
16277
16819
  }
16278
16820
  )
16279
16821
  ] }),
16822
+ faehig.imageJobs && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
16823
+ "details",
16824
+ {
16825
+ className: "szenen-bilder__aktion",
16826
+ "data-testid": `auftraege-chat-bereich-${lauf.run_id}`,
16827
+ open: chatAuftraegeAuf,
16828
+ children: [
16829
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
16830
+ "summary",
16831
+ {
16832
+ onClick: (e) => {
16833
+ e.preventDefault();
16834
+ setChatAuftraegeOffen(!chatAuftraegeAuf);
16835
+ },
16836
+ children: [
16837
+ "Bildauftraege aus dem Chat",
16838
+ offeneChatAuftraege > 0 ? ` (${offeneChatAuftraege} wartend)` : ""
16839
+ ]
16840
+ }
16841
+ ),
16842
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
16843
+ ChatAuftraegeAktion,
16844
+ {
16845
+ port,
16846
+ lauf,
16847
+ auftraege: chatAuftraege,
16848
+ fehler: chatAuftraegePhase.status === "error" ? chatAuftraegePhase.message : null,
16849
+ laedt: chatAuftraegePhase.status === "loading",
16850
+ onFertig: () => {
16851
+ setChatAuftraegeOffen(true);
16852
+ neuLesen();
16853
+ }
16854
+ }
16855
+ )
16856
+ ]
16857
+ }
16858
+ ),
16280
16859
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
16281
16860
  "details",
16282
16861
  {
@@ -16460,7 +17039,7 @@ function useBildQuellen(port, bilder) {
16460
17039
  erneutVersuchen: () => setVersuch((n) => n + 1)
16461
17040
  };
16462
17041
  }
16463
- var BildDetails = ({ bild, fehler: fehler4, aufloesbar }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "szenen-bilder__meta", "data-testid": `batchbild-${bild.media_ref}`, children: [
17042
+ var BildDetails = ({ bild, fehler: fehler5, aufloesbar }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "szenen-bilder__meta", "data-testid": `batchbild-${bild.media_ref}`, children: [
16464
17043
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: bild.media_ref }),
16465
17044
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
16466
17045
  "Position ",
@@ -16473,7 +17052,7 @@ var BildDetails = ({ bild, fehler: fehler4, aufloesbar }) => /* @__PURE__ */ (0,
16473
17052
  "\xD7",
16474
17053
  bild.height
16475
17054
  ] }) : null,
16476
- fehler4 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("em", { "data-testid": `batchbild-fehler-${bild.media_ref}`, children: fehler4 }),
17055
+ fehler5 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("em", { "data-testid": `batchbild-fehler-${bild.media_ref}`, children: fehler5 }),
16477
17056
  !aufloesbar && // Capability-Grenze, kein Fehler: Dieser Host kann Batches lesen,
16478
17057
  // aber keine Bilder auflösen (E). Kein erfundener Fallback auf eine
16479
17058
  // Serverroute (A6).
@@ -16489,18 +17068,18 @@ var HERKUNFT_KURZ = {
16489
17068
  external_import: "extern importiert"
16490
17069
  };
16491
17070
  var BatchKachel = ({ port, batch }) => {
16492
- const { quellen, fehler: fehler4, wiederholbar, erneutVersuchen } = useBildQuellen(port, batch.images);
17071
+ const { quellen, fehler: fehler5, wiederholbar, erneutVersuchen } = useBildQuellen(port, batch.images);
16493
17072
  const aufloesbar = Boolean(port.imageLibrary);
16494
17073
  const bilder = batch.images.map((bild) => ({
16495
17074
  id: bild.media_ref,
16496
17075
  quelle: quellen.get(bild.media_ref) ?? null,
16497
17076
  titel: `Bild ${bild.position + 1}`,
16498
- ...fehler4.get(bild.media_ref) ? { leerText: "Nicht ladbar" } : {},
17077
+ ...fehler5.get(bild.media_ref) ? { leerText: "Nicht ladbar" } : {},
16499
17078
  details: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
16500
17079
  BildDetails,
16501
17080
  {
16502
17081
  bild,
16503
- fehler: fehler4.get(bild.media_ref) ?? null,
17082
+ fehler: fehler5.get(bild.media_ref) ?? null,
16504
17083
  aufloesbar
16505
17084
  }
16506
17085
  )
@@ -16560,7 +17139,7 @@ var BatchKachel = ({ port, batch }) => {
16560
17139
  BildDetails,
16561
17140
  {
16562
17141
  bild,
16563
- fehler: fehler4.get(bild.media_ref) ?? null,
17142
+ fehler: fehler5.get(bild.media_ref) ?? null,
16564
17143
  aufloesbar
16565
17144
  }
16566
17145
  ) }, bild.media_ref)) })
@@ -16829,11 +17408,11 @@ var ZuordnenAktion = ({ port, lauf, onFertig }) => {
16829
17408
  setSeedListe(DEFAULT_SEED_VORLAGE.seeds);
16830
17409
  setVorlageKey(DEFAULT_VORLAGE_KEY);
16831
17410
  }
16832
- } catch (fehler4) {
17411
+ } catch (fehler5) {
16833
17412
  if (veraltet()) return;
16834
17413
  setNotiz({
16835
17414
  tone: "error",
16836
- text: fehler4 instanceof Error ? fehler4.message : String(fehler4)
17415
+ text: fehler5 instanceof Error ? fehler5.message : String(fehler5)
16837
17416
  });
16838
17417
  }
16839
17418
  if (veraltet()) return;
@@ -16852,10 +17431,10 @@ var ZuordnenAktion = ({ port, lauf, onFertig }) => {
16852
17431
  setNotiz(
16853
17432
  ergebnis.kind === "ok" ? { tone: "ok", text: `Importiert als Item ${ergebnis.value.item_id} mit ${bilder.length} Bild(ern).` } : noticeFor(ergebnis, "Externe Bilder importieren")
16854
17433
  );
16855
- } catch (fehler4) {
17434
+ } catch (fehler5) {
16856
17435
  setNotiz({
16857
17436
  tone: "error",
16858
- text: `Externe Bilder importieren: ${fehler4 instanceof Error ? fehler4.message : String(fehler4)}`
17437
+ text: `Externe Bilder importieren: ${fehler5 instanceof Error ? fehler5.message : String(fehler5)}`
16859
17438
  });
16860
17439
  }
16861
17440
  setLaeuft(false);
@@ -16877,10 +17456,10 @@ var ZuordnenAktion = ({ port, lauf, onFertig }) => {
16877
17456
  ...seed !== void 0 ? { seed } : {}
16878
17457
  });
16879
17458
  }
16880
- } catch (fehler4) {
17459
+ } catch (fehler5) {
16881
17460
  setNotiz({
16882
17461
  tone: "error",
16883
- text: `Externe Bilder importieren: ${fehler4 instanceof Error ? fehler4.message : String(fehler4)}`
17462
+ text: `Externe Bilder importieren: ${fehler5 instanceof Error ? fehler5.message : String(fehler5)}`
16884
17463
  });
16885
17464
  return;
16886
17465
  }
@@ -17216,6 +17795,101 @@ function readAsBase64(datei) {
17216
17795
  leser.readAsDataURL(datei);
17217
17796
  });
17218
17797
  }
17798
+ var CHAT_AUFTRAG_TEXT = {
17799
+ pending: "wartet auf \xDCbernahme",
17800
+ // Wie bei `started` (D-119): laufend und abgebrochen sind aus dem Log
17801
+ // nicht unterscheidbar, und es gibt keinen automatischen Retry, der die
17802
+ // Unterscheidung bräuchte.
17803
+ claimed: "\xFCbernommen (l\xE4uft oder unterbrochen)",
17804
+ succeeded: "erfolgreich",
17805
+ partial: "teilweise",
17806
+ failed: "fehlgeschlagen",
17807
+ rejected: "abgelehnt \u2014 es wurde nichts ausgef\xFChrt"
17808
+ };
17809
+ var ChatAuftraegeAktion = ({
17810
+ port,
17811
+ lauf,
17812
+ auftraege,
17813
+ fehler: fehler5,
17814
+ laedt,
17815
+ onFertig
17816
+ }) => {
17817
+ const [laufend, setLaufend] = (0, import_react8.useState)(null);
17818
+ const [notiz, setNotiz] = (0, import_react8.useState)(null);
17819
+ async function uebernehmen(jobId) {
17820
+ if (!port.imageJobs) return;
17821
+ setLaufend(jobId);
17822
+ setNotiz(null);
17823
+ try {
17824
+ const ergebnis = await port.imageJobs.claimAndRun(jobId);
17825
+ if (ergebnis.kind === "ok") {
17826
+ setNotiz({
17827
+ tone: ergebnis.job.status === "succeeded" ? "ok" : "rejected",
17828
+ text: `Auftrag ${jobId}: ${CHAT_AUFTRAG_TEXT[ergebnis.job.status]}.` + (ergebnis.job.diagnostic ? ` ${ergebnis.job.diagnostic}` : "")
17829
+ });
17830
+ } else if (ergebnis.kind === "lost") {
17831
+ setNotiz({ tone: "rejected", text: ergebnis.message });
17832
+ } else {
17833
+ setNotiz({ tone: "error", text: ergebnis.message });
17834
+ }
17835
+ } catch (e) {
17836
+ setNotiz({
17837
+ tone: "error",
17838
+ text: `Die \xDCbernahme von Auftrag ${jobId} ist technisch gescheitert: ` + (e instanceof Error ? e.message : String(e))
17839
+ });
17840
+ } finally {
17841
+ setLaufend(null);
17842
+ onFertig();
17843
+ }
17844
+ }
17845
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "szenen-bilder__aktion-inhalt", "data-testid": `chat-auftraege-${lauf.run_id}`, children: [
17846
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "szenen-area__lead", children: "Auftr\xE4ge, die \xFCber den MCP aus dem Chat kamen. Der Prompt wird nicht kopiert \u2014 ausgef\xFChrt wird der eingefrorene Prompt dieses Laufs." }),
17847
+ fehler5 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { role: "alert", "data-testid": `chat-auftraege-fehler-${lauf.run_id}`, children: [
17848
+ "Bildauftr\xE4ge aus dem Chat konnten nicht gelesen werden: ",
17849
+ fehler5
17850
+ ] }),
17851
+ !fehler5 && !laedt && auftraege.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { "data-testid": `chat-auftraege-leer-${lauf.run_id}`, children: "F\xFCr diesen Lauf liegt kein Auftrag aus dem Chat vor." }),
17852
+ notiz && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
17853
+ "p",
17854
+ {
17855
+ role: notiz.tone === "error" ? "alert" : void 0,
17856
+ "data-testid": `chat-auftraege-notiz-${lauf.run_id}`,
17857
+ children: notiz.text
17858
+ }
17859
+ ),
17860
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "szenen-bilder__auftraege", children: auftraege.map((auftrag) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { "data-testid": `chat-auftrag-${auftrag.job_id}`, children: [
17861
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: CHAT_AUFTRAG_TEXT[auftrag.status] }),
17862
+ " \u2014 ",
17863
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
17864
+ auftrag.image_count,
17865
+ " ",
17866
+ auftrag.image_count === 1 ? "Bild" : "Bilder",
17867
+ " mit",
17868
+ " ",
17869
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: auftrag.execution_target_model_key }),
17870
+ " / ",
17871
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { children: auftrag.execution_profile_id }),
17872
+ auftrag.aspect_ratio ? ` im Format ${auftrag.aspect_ratio}` : ""
17873
+ ] }),
17874
+ auftrag.diagnostic && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
17875
+ " ",
17876
+ auftrag.diagnostic
17877
+ ] }),
17878
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("br", {}),
17879
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { className: "szenen-bilder__auftragskennung", children: auftrag.job_id }),
17880
+ auftrag.status === "pending" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
17881
+ "button",
17882
+ {
17883
+ type: "button",
17884
+ disabled: laufend !== null,
17885
+ onClick: () => void uebernehmen(auftrag.job_id),
17886
+ "data-testid": `chat-auftrag-uebernehmen-${auftrag.job_id}`,
17887
+ children: laufend === auftrag.job_id ? "\xDCbernahme l\xE4uft\u2026" : "\xDCbernehmen und ausf\xFChren (kostet einen Bildaufruf)"
17888
+ }
17889
+ )
17890
+ ] }, auftrag.job_id)) })
17891
+ ] });
17892
+ };
17219
17893
 
17220
17894
  // src/features/szenen/areas/RunsPanel.tsx
17221
17895
  var import_jsx_runtime9 = require("react/jsx-runtime");
@@ -19498,6 +20172,7 @@ var SzenenView = ({
19498
20172
  DERIVABLE_TYPES,
19499
20173
  ELEMENT_VERSION_SCHEMA_FILE,
19500
20174
  FLOW_EXECUTION_PATH,
20175
+ MCP_CLIENT_PROVIDER,
19501
20176
  PROBE_VERSION_ID,
19502
20177
  PROMPT_RULE_EFFECT,
19503
20178
  REFERENCE_FIELD,
@@ -19517,6 +20192,7 @@ var SzenenView = ({
19517
20192
  SZENEN_SNAPSHOT_SCHEMA_VERSION,
19518
20193
  SzenenView,
19519
20194
  UNCHECKED_PUBLISH_RULES,
20195
+ UNVERIFIED_MODEL_ID,
19520
20196
  UPLOAD_MAX_BYTES,
19521
20197
  UnsupportedSchemaError,
19522
20198
  VersionDagError,
@@ -19558,14 +20234,18 @@ var SzenenView = ({
19558
20234
  checkSzenenBatchOrigin,
19559
20235
  checkTitle,
19560
20236
  checkWriteDraftInput,
20237
+ claimWon,
19561
20238
  collectImageBatches,
19562
20239
  collectImageGenerationOrders,
20240
+ collectImageJobs,
20241
+ collectPromptOperations,
19563
20242
  collectPromptRuns,
19564
20243
  collectProviderChecks,
19565
20244
  collectSceneDerivationRecoveries,
19566
20245
  collectSceneDerivations,
19567
20246
  collectVersionRefs,
19568
20247
  compileSchemas,
20248
+ completePromptOperation,
19569
20249
  createBrowserTextGenerationPort,
19570
20250
  createClientDerivationPort,
19571
20251
  createClientRunPort,
@@ -19583,6 +20263,7 @@ var SzenenView = ({
19583
20263
  createHfImageLibrary,
19584
20264
  createHfImageStore,
19585
20265
  createImageGenerationPort,
20266
+ createImageJobPort,
19586
20267
  createInMemoryEventChannel,
19587
20268
  createMemoryViewPort,
19588
20269
  createSimulationSceneDerivationPort,
@@ -19601,6 +20282,8 @@ var SzenenView = ({
19601
20282
  findExecutableImageModel,
19602
20283
  findImageBatch,
19603
20284
  findImageGenerationOrder,
20285
+ findImageJob,
20286
+ findPromptOperation,
19604
20287
  findPromptRun,
19605
20288
  findProviderCheck,
19606
20289
  findSceneDerivation,
@@ -19610,6 +20293,7 @@ var SzenenView = ({
19610
20293
  formatSeedListe,
19611
20294
  freezeDraftChain,
19612
20295
  freezeSceneWorkingState,
20296
+ generationBatchIdOf,
19613
20297
  gesamtHerkunft,
19614
20298
  getSzenenSchemas,
19615
20299
  gruppiereZuItems,
@@ -19621,13 +20305,17 @@ var SzenenView = ({
19621
20305
  istSzenenSnapshotDatei,
19622
20306
  istZipDatei,
19623
20307
  itemIdForRun,
20308
+ itemsAusBestand,
20309
+ jobsForPromptRun,
19624
20310
  ladeVorschauen,
19625
20311
  leseBilderAusZip,
19626
20312
  linkFor,
20313
+ locatorAus,
19627
20314
  locatorTeile,
19628
20315
  logRevisionOf,
19629
20316
  mergeSnapshotAndPending,
19630
20317
  mergeSzenenBatchOrigin,
20318
+ mimeTypAus,
19631
20319
  mitDefaultVorlage,
19632
20320
  noticeFor,
19633
20321
  ordersForPromptRun,
@@ -19638,6 +20326,7 @@ var SzenenView = ({
19638
20326
  parseSzenenSnapshot,
19639
20327
  preferredHeadRevisionOf,
19640
20328
  preferredVersionId,
20329
+ preparePromptOperation,
19641
20330
  promptDiagnosticsOf,
19642
20331
  publishedHeadsOf,
19643
20332
  recoveriesForRun,
@@ -19650,13 +20339,16 @@ var SzenenView = ({
19650
20339
  resolveShotPayload,
19651
20340
  resolveTargetModelOver,
19652
20341
  resolverFromQueries,
20342
+ responseContractOf,
19653
20343
  roundOfRun,
19654
20344
  rulesWithoutPromptEffect,
19655
20345
  runElementStoreContract,
20346
+ runOfOperation,
19656
20347
  runPromptDerivation,
19657
20348
  runPublishChecks,
19658
20349
  runSceneDerivation,
19659
20350
  runStoreDifferential,
20351
+ sameResponseAs,
19660
20352
  sceneOnlyCapabilities,
19661
20353
  scopeOfPath,
19662
20354
  seedFehlerText,