@neta-art/generation 0.1.2 → 0.1.4

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.
@@ -1,4 +1,4 @@
1
- import { a as compactArray, c as slugifyFileName, i as cloneJson, l as MODEL_SCHEMA, n as getBuiltinGenerationModel, o as compactObject, r as listBuiltinGenerationModels, s as getBlockMeta, t as builtinGenerationModels } from "./builtins-B1AheaEa.js";
1
+ import { a as compactArray, c as slugifyFileName, i as cloneJson, l as MODEL_SCHEMA, n as getBuiltinGenerationModel, o as compactObject, r as listBuiltinGenerationModels, s as getBlockMeta, t as builtinGenerationModels } from "./builtins-FumzmWvj.js";
2
2
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
3
3
  import { extname, join } from "node:path";
4
4
  import { parse, stringify } from "yaml";
@@ -161,7 +161,12 @@ function validateGenerationContent(declaration, content) {
161
161
  function resolveGenerationParameters(declaration, parameters) {
162
162
  const specs = declaration.parameters ?? {};
163
163
  const resolved = {};
164
- for (const key of Object.keys(parameters ?? {})) if (!specs[key]) throw new GenerationValidationError(`Unknown parameter: ${key}`);
164
+ const allowUnknownParameters = declaration.allowUnknownParameters ?? false;
165
+ for (const key of Object.keys(parameters ?? {})) if (!specs[key]) {
166
+ if (!allowUnknownParameters) throw new GenerationValidationError(`Unknown parameter: ${key}`);
167
+ const value = parameters?.[key];
168
+ if (value !== void 0) resolved[key] = value;
169
+ }
165
170
  for (const [key, spec] of Object.entries(specs)) {
166
171
  const value = parameters?.[key];
167
172
  if (value === void 0) {
@@ -169,27 +174,73 @@ function resolveGenerationParameters(declaration, parameters) {
169
174
  else if (!spec.optional) throw new GenerationValidationError(`Missing required parameter: ${key}`);
170
175
  continue;
171
176
  }
172
- switch (spec.type) {
173
- case "string":
174
- if (typeof value !== "string") throw new GenerationValidationError(`Parameter ${key} must be a string`);
175
- if (spec.enum && !spec.enum.includes(value)) throw new GenerationValidationError(`Parameter ${key} must be one of: ${spec.enum.join(", ")}`);
176
- break;
177
- case "number":
178
- if (typeof value !== "number" || !Number.isFinite(value)) throw new GenerationValidationError(`Parameter ${key} must be a number`);
179
- if (spec.min !== void 0 && value < spec.min) throw new GenerationValidationError(`Parameter ${key} must be >= ${spec.min}`);
180
- if (spec.max !== void 0 && value > spec.max) throw new GenerationValidationError(`Parameter ${key} must be <= ${spec.max}`);
181
- break;
182
- case "integer":
183
- if (typeof value !== "number" || !Number.isInteger(value)) throw new GenerationValidationError(`Parameter ${key} must be an integer`);
184
- if (spec.min !== void 0 && value < spec.min) throw new GenerationValidationError(`Parameter ${key} must be >= ${spec.min}`);
185
- if (spec.max !== void 0 && value > spec.max) throw new GenerationValidationError(`Parameter ${key} must be <= ${spec.max}`);
186
- break;
187
- case "boolean":
188
- if (typeof value !== "boolean") throw new GenerationValidationError(`Parameter ${key} must be a boolean`);
189
- break;
177
+ validateSpecValue(`Parameter ${key}`, spec, value);
178
+ resolved[key] = value;
179
+ }
180
+ return resolved;
181
+ }
182
+ function mergeGenerationMeta(requestMeta, content) {
183
+ const merged = {};
184
+ mergeMetaFields(merged, requestMeta);
185
+ for (const block of content) mergeMetaFields(merged, block.meta);
186
+ return merged;
187
+ }
188
+ function normalizeMetaKey(key) {
189
+ return key === "metadataParams" ? "metadata_params" : key;
190
+ }
191
+ function mergeMetaFields(target, meta) {
192
+ for (const [key, value] of Object.entries(meta ?? {})) {
193
+ const normalizedKey = normalizeMetaKey(key);
194
+ if (value !== void 0 && target[normalizedKey] === void 0) target[normalizedKey] = value;
195
+ }
196
+ }
197
+ function validateSpecValue(label, spec, value) {
198
+ switch (spec.type) {
199
+ case "string":
200
+ if (typeof value !== "string") throw new GenerationValidationError(`${label} must be a string`);
201
+ if (spec.enum && !spec.enum.includes(value)) throw new GenerationValidationError(`${label} must be one of: ${spec.enum.join(", ")}`);
202
+ break;
203
+ case "number":
204
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new GenerationValidationError(`${label} must be a number`);
205
+ if (spec.min !== void 0 && value < spec.min) throw new GenerationValidationError(`${label} must be >= ${spec.min}`);
206
+ if (spec.max !== void 0 && value > spec.max) throw new GenerationValidationError(`${label} must be <= ${spec.max}`);
207
+ break;
208
+ case "integer":
209
+ if (typeof value !== "number" || !Number.isInteger(value)) throw new GenerationValidationError(`${label} must be an integer`);
210
+ if (spec.min !== void 0 && value < spec.min) throw new GenerationValidationError(`${label} must be >= ${spec.min}`);
211
+ if (spec.max !== void 0 && value > spec.max) throw new GenerationValidationError(`${label} must be <= ${spec.max}`);
212
+ break;
213
+ case "boolean":
214
+ if (typeof value !== "boolean") throw new GenerationValidationError(`${label} must be a boolean`);
215
+ break;
216
+ case "object":
217
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new GenerationValidationError(`${label} must be an object`);
218
+ break;
219
+ }
220
+ }
221
+ function resolveGenerationMeta(declaration, meta, content) {
222
+ const specs = declaration.meta?.fields ?? {};
223
+ const resolved = {};
224
+ for (const key of Object.keys(meta ?? {})) if (!specs[key]) {
225
+ const value = meta?.[key];
226
+ if (value !== void 0) resolved[key] = value;
227
+ }
228
+ for (const [key, spec] of Object.entries(specs)) {
229
+ const value = meta?.[key];
230
+ if (value === void 0) {
231
+ if (!spec.optional) throw new GenerationValidationError(`Missing required meta: ${key}`);
232
+ continue;
190
233
  }
234
+ validateSpecValue(`meta.${key}`, spec, value);
191
235
  resolved[key] = value;
192
236
  }
237
+ const taskField = declaration.meta?.taskField;
238
+ const task = taskField && typeof resolved[taskField] === "string" ? resolved[taskField] : void 0;
239
+ if (!task) return resolved;
240
+ const variant = declaration.meta?.taskVariants?.[task];
241
+ if (!variant) throw new GenerationValidationError(`Unsupported meta.${taskField}: ${task}`);
242
+ for (const key of variant.required ?? []) if (resolved[key] === void 0 || resolved[key] === null || resolved[key] === "") throw new GenerationValidationError(`meta.${taskField} ${task} requires meta.${key}`);
243
+ for (const type of variant.requiredContent ?? []) if (!content.some((block) => block.type === type)) throw new GenerationValidationError(`meta.${taskField} ${task} requires ${type} content`);
193
244
  return resolved;
194
245
  }
195
246
  function mergeTextBlocks(declaration, content) {
@@ -200,9 +251,9 @@ function mergeTextBlocks(declaration, content) {
200
251
 
201
252
  //#endregion
202
253
  //#region src/adapters/ark-video-generations.ts
203
- const REQUEST_TIMEOUT_MS$2 = 6e4;
204
- const DEFAULT_POLL_INTERVAL_SEC = 2;
205
- const DEFAULT_MAX_WAIT_SEC = 600;
254
+ const REQUEST_TIMEOUT_MS$3 = 6e4;
255
+ const DEFAULT_POLL_INTERVAL_SEC$1 = 2;
256
+ const DEFAULT_MAX_WAIT_SEC$1 = 600;
206
257
  const RESOLUTION_SHORT_EDGE = {
207
258
  "480p": 480,
208
259
  "720p": 720,
@@ -220,10 +271,10 @@ const ASPECT_RATIOS = {
220
271
  "21:9": [21, 9],
221
272
  adaptive: null
222
273
  };
223
- function sleep(ms) {
274
+ function sleep$1(ms) {
224
275
  return new Promise((resolve) => setTimeout(resolve, ms));
225
276
  }
226
- function asString(value) {
277
+ function asString$1(value) {
227
278
  return typeof value === "string" && value ? value : void 0;
228
279
  }
229
280
  function asNumber(value) {
@@ -232,7 +283,7 @@ function asNumber(value) {
232
283
  function asBoolean(value) {
233
284
  return typeof value === "boolean" ? value : void 0;
234
285
  }
235
- function normalizeStatus(value) {
286
+ function normalizeStatus$1(value) {
236
287
  const status = value.toLowerCase();
237
288
  return status === "success" ? "succeeded" : status;
238
289
  }
@@ -286,8 +337,8 @@ function buildMetadataContent(prompt, images, mode) {
286
337
  }
287
338
  return content;
288
339
  }
289
- function extractTaskId(response) {
290
- const taskId = asString(response.task_id) ?? asString(response.id);
340
+ function extractTaskId$1(response) {
341
+ const taskId = asString$1(response.task_id) ?? asString$1(response.id);
291
342
  if (!taskId) throw new GenerationProviderError("Video generation provider did not return a task id", { details: { response } });
292
343
  return taskId;
293
344
  }
@@ -295,9 +346,9 @@ function normalizeTaskStatus(response) {
295
346
  if (response.data) {
296
347
  const wrapper = response.data;
297
348
  const native = wrapper.data;
298
- const status = normalizeStatus(asString(native?.status) ?? asString(wrapper.status) ?? "unknown");
299
- const videoUrl = asString(wrapper.result_url) ?? asString(native?.content?.video_url);
300
- const lastFrameUrl = asString(wrapper.first_frame) ?? asString(native?.content?.first_frame);
349
+ const status = normalizeStatus$1(asString$1(native?.status) ?? asString$1(wrapper.status) ?? "unknown");
350
+ const videoUrl = asString$1(wrapper.result_url) ?? asString$1(native?.content?.video_url);
351
+ const lastFrameUrl = asString$1(wrapper.first_frame) ?? asString$1(native?.content?.first_frame);
301
352
  const metadata = {
302
353
  progress: wrapper.progress,
303
354
  resolution: native?.resolution,
@@ -324,7 +375,7 @@ function normalizeTaskStatus(response) {
324
375
  metadata: {}
325
376
  };
326
377
  }
327
- async function requestJson(input, path, init) {
378
+ async function requestJson$1(input, path, init) {
328
379
  const response = await fetchWithTimeout(input.context.fetch, joinUrl(input.context.baseUrl, path), {
329
380
  ...init,
330
381
  headers: {
@@ -332,7 +383,7 @@ async function requestJson(input, path, init) {
332
383
  "Content-Type": "application/json",
333
384
  ...init.headers
334
385
  }
335
- }, REQUEST_TIMEOUT_MS$2);
386
+ }, REQUEST_TIMEOUT_MS$3);
336
387
  if (!response.ok) {
337
388
  const body = await response.text().catch(() => response.statusText);
338
389
  throw new GenerationProviderError("Video generation provider request failed", {
@@ -351,12 +402,12 @@ async function arkVideoGenerationsAdapter(input) {
351
402
  role: getImageRole(block)
352
403
  })));
353
404
  const mode = classifyImages(images);
354
- const resolution = asString(input.parameters.resolution) ?? "720p";
355
- const aspectRatio = asString(input.parameters.aspect_ratio) ?? "16:9";
405
+ const resolution = asString$1(input.parameters.resolution) ?? "720p";
406
+ const aspectRatio = asString$1(input.parameters.aspect_ratio) ?? "16:9";
356
407
  const duration = getIntegerParameter(input.parameters, "duration", 5);
357
408
  const fps = getIntegerParameter(input.parameters, "fps", 30);
358
- const pollIntervalSec = getIntegerParameter(input.parameters, "poll_interval", DEFAULT_POLL_INTERVAL_SEC);
359
- const maxWaitSec = getIntegerParameter(input.parameters, "max_wait", DEFAULT_MAX_WAIT_SEC);
409
+ const pollIntervalSec = getIntegerParameter(input.parameters, "poll_interval", DEFAULT_POLL_INTERVAL_SEC$1);
410
+ const maxWaitSec = getIntegerParameter(input.parameters, "max_wait", DEFAULT_MAX_WAIT_SEC$1);
360
411
  const generateAudio = asBoolean(input.parameters.generate_audio) ?? true;
361
412
  const returnLastFrame = asBoolean(input.parameters.return_last_frame) ?? true;
362
413
  const cameraFixed = asBoolean(input.parameters.camera_fixed) ?? false;
@@ -388,14 +439,14 @@ async function arkVideoGenerationsAdapter(input) {
388
439
  if (images[0]) payload.image = images[0].url;
389
440
  }
390
441
  payload.metadata = metadata;
391
- const taskId = extractTaskId(await requestJson(input, "/v1/video/generations", {
442
+ const taskId = extractTaskId$1(await requestJson$1(input, "/v1/video/generations", {
392
443
  method: "POST",
393
444
  body: JSON.stringify(payload)
394
445
  }));
395
446
  const startedAt = Date.now();
396
447
  while (Date.now() - startedAt <= maxWaitSec * 1e3) {
397
- await sleep(pollIntervalSec * 1e3);
398
- const rawStatus = await requestJson(input, `/v1/video/generations/${encodeURIComponent(taskId)}`, { method: "GET" });
448
+ await sleep$1(pollIntervalSec * 1e3);
449
+ const rawStatus = await requestJson$1(input, `/v1/video/generations/${encodeURIComponent(taskId)}`, { method: "GET" });
399
450
  const status = normalizeTaskStatus(rawStatus);
400
451
  if (status.status === "succeeded") {
401
452
  if (!status.videoUrl) throw new GenerationProviderError("Video generation succeeded but returned no video URL", { details: compactObject({
@@ -442,7 +493,7 @@ async function arkVideoGenerationsAdapter(input) {
442
493
 
443
494
  //#endregion
444
495
  //#region src/adapters/gemini-generate-content.ts
445
- const REQUEST_TIMEOUT_MS$1 = 3e5;
496
+ const REQUEST_TIMEOUT_MS$2 = 3e5;
446
497
  const IMAGE_FETCH_TIMEOUT_MS = 6e4;
447
498
  const MAX_REFERENCE_IMAGE_BYTES = 10 * 1024 * 1024;
448
499
  const DATA_URI_PATTERN = /^data:([^;]+);base64,(.+)$/s;
@@ -580,7 +631,7 @@ async function geminiGenerateContentAdapter(input) {
580
631
  "Content-Type": "application/json"
581
632
  },
582
633
  body: JSON.stringify(payload)
583
- }, REQUEST_TIMEOUT_MS$1);
634
+ }, REQUEST_TIMEOUT_MS$2);
584
635
  if (!response.ok) {
585
636
  const body = await response.text().catch(() => response.statusText);
586
637
  throw new GenerationProviderError("Gemini generation provider request failed", {
@@ -597,7 +648,7 @@ async function geminiGenerateContentAdapter(input) {
597
648
 
598
649
  //#endregion
599
650
  //#region src/adapters/openai-images.ts
600
- const REQUEST_TIMEOUT_MS = 3e5;
651
+ const REQUEST_TIMEOUT_MS$1 = 3e5;
601
652
  function collectOpenAiImagesNoOutputDetails(raw) {
602
653
  const data = raw.data ?? [];
603
654
  return compactObject({
@@ -632,7 +683,7 @@ async function openAiImagesAdapter(input) {
632
683
  "Content-Type": "application/json"
633
684
  },
634
685
  body: JSON.stringify(payload)
635
- }, REQUEST_TIMEOUT_MS);
686
+ }, REQUEST_TIMEOUT_MS$1);
636
687
  if (!response.ok) {
637
688
  const body = await response.text().catch(() => response.statusText);
638
689
  throw new GenerationProviderError("Image generation provider request failed", {
@@ -668,12 +719,322 @@ async function openAiImagesAdapter(input) {
668
719
  return output;
669
720
  }
670
721
 
722
+ //#endregion
723
+ //#region src/adapters/suno-tasks.ts
724
+ const REQUEST_TIMEOUT_MS = 6e4;
725
+ const DEFAULT_POLL_INTERVAL_SEC = 5;
726
+ const DEFAULT_MAX_WAIT_SEC = 600;
727
+ const DEFAULT_MUSIC_VERSION = "chirp-v5-5";
728
+ const OPERATION_PATHS = {
729
+ music: {
730
+ path: "/suno/submit/music",
731
+ poll: true,
732
+ defaultMusicVersion: true,
733
+ textField: "prompt"
734
+ },
735
+ lyrics: {
736
+ path: "/suno/submit/lyrics",
737
+ poll: true,
738
+ textField: "prompt",
739
+ requireText: true
740
+ },
741
+ concat: {
742
+ path: "/suno/submit/concat",
743
+ poll: true
744
+ },
745
+ upsample_tags: {
746
+ path: "/suno/submit/upsample-tags",
747
+ poll: false,
748
+ textField: "original_tags",
749
+ requireText: true
750
+ },
751
+ upload_audio: {
752
+ path: "/suno/uploads/audio",
753
+ poll: true
754
+ }
755
+ };
756
+ const FINAL_SUCCESS_STATUSES = new Set([
757
+ "success",
758
+ "succeeded",
759
+ "completed"
760
+ ]);
761
+ const FINAL_FAILURE_STATUSES = new Set([
762
+ "failure",
763
+ "failed",
764
+ "error",
765
+ "cancelled",
766
+ "canceled",
767
+ "expired"
768
+ ]);
769
+ function sleep(ms) {
770
+ return new Promise((resolve) => setTimeout(resolve, ms));
771
+ }
772
+ function isRecord$1(value) {
773
+ return !!value && typeof value === "object" && !Array.isArray(value);
774
+ }
775
+ function asString(value) {
776
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
777
+ }
778
+ function asInteger(value, fallback) {
779
+ return typeof value === "number" && Number.isInteger(value) ? value : fallback;
780
+ }
781
+ function successCode(value) {
782
+ const code = String(value ?? "").trim().toLowerCase();
783
+ return code === "success" || code === "200" || code === "0";
784
+ }
785
+ function requireSuccess(response, fallbackMessage) {
786
+ if (!successCode(response.code)) throw new GenerationProviderError(fallbackMessage, { details: {
787
+ code: response.code,
788
+ message: response.message,
789
+ data: response.data
790
+ } });
791
+ return response.data;
792
+ }
793
+ function extractTaskId(value) {
794
+ if (typeof value === "string" && value.trim()) return value.trim();
795
+ if (!isRecord$1(value)) return void 0;
796
+ for (const key of [
797
+ "task_id",
798
+ "id",
799
+ "taskBatchId"
800
+ ]) {
801
+ const taskId = asString(value[key]);
802
+ if (taskId) return taskId;
803
+ }
804
+ }
805
+ function normalizeStatus(value) {
806
+ return String(value ?? "").trim().toLowerCase();
807
+ }
808
+ function normalizeTask(operation, data) {
809
+ if (Array.isArray(data)) return data.length > 0 ? normalizeTask(operation, data[0]) : null;
810
+ if (!isRecord$1(data)) return null;
811
+ if ("status" in data || "task_id" in data) return data;
812
+ if (Array.isArray(data.data) && data.data.length > 0) return normalizeTask(operation, data.data[0]);
813
+ return {
814
+ action: operation,
815
+ status: "SUCCESS",
816
+ data
817
+ };
818
+ }
819
+ function getOperation(input) {
820
+ const operation = asString(input.parameters.operation) ?? "music";
821
+ if (!OPERATION_PATHS[operation]) throw new GenerationValidationError(`Unsupported Suno operation: ${operation}`);
822
+ return operation;
823
+ }
824
+ async function buildPayload(input, operation) {
825
+ const payload = { ...input.meta };
826
+ const config = OPERATION_PATHS[operation];
827
+ const prompt = mergeTextBlocks(input.declaration, input.request.content);
828
+ if (prompt && config?.textField && payload[config.textField] === void 0) payload[config.textField] = prompt;
829
+ if (config?.textField && config.textField !== "prompt" && payload[config.textField] === void 0 && payload.prompt !== void 0) payload[config.textField] = payload.prompt;
830
+ const audioBlock = input.request.content.find((block) => block.type === "audio");
831
+ if (audioBlock && payload.url === void 0) payload.url = await input.context.resolveSource(audioBlock.source);
832
+ const imageBlock = input.request.content.find((block) => block.type === "image");
833
+ if (imageBlock && payload.image_url === void 0) payload.image_url = await input.context.resolveSource(imageBlock.source);
834
+ const videoBlock = input.request.content.find((block) => block.type === "video");
835
+ if (videoBlock && payload.video_url === void 0) payload.video_url = await input.context.resolveSource(videoBlock.source);
836
+ normalizeMusicTaskPayload(input, operation, payload);
837
+ if (config?.defaultMusicVersion && payload.mv === void 0 && payload.model_name === void 0) payload.mv = DEFAULT_MUSIC_VERSION;
838
+ validateSunoPayload(operation, payload);
839
+ return payload;
840
+ }
841
+ function contentCount(content, type) {
842
+ return content.filter((block) => block.type === type).length;
843
+ }
844
+ function normalizeMusicTaskPayload(input, operation, payload) {
845
+ if (operation !== "music") return;
846
+ const taskField = input.declaration.meta?.taskField ?? "task";
847
+ const task = asString(payload[taskField]);
848
+ if (!task) return;
849
+ const taskVariant = input.declaration.meta?.taskVariants?.[task];
850
+ if (!taskVariant) throw new GenerationValidationError(`Unsupported Suno music task: ${task}`);
851
+ for (const key of taskVariant.required ?? []) if (payload[key] === void 0 || payload[key] === null || payload[key] === "") throw new GenerationValidationError(`Suno task ${task} requires meta.${key}`);
852
+ for (const type of taskVariant.requiredContent ?? []) if (contentCount(input.request.content, type) === 0) throw new GenerationValidationError(`Suno task ${task} requires ${type} content`);
853
+ if (taskVariant.sendTask === false) delete payload[taskField];
854
+ }
855
+ function validateSunoPayload(operation, payload) {
856
+ const config = OPERATION_PATHS[operation];
857
+ const task = asString(payload.task);
858
+ if (operation === "music" && task) {
859
+ if (task === "lyrics") throw new GenerationValidationError("Use operation=lyrics instead of task=lyrics");
860
+ }
861
+ if (config?.requireText && !asString(payload[config.textField ?? "prompt"])) throw new GenerationValidationError(`${config.textField ?? "prompt"} text is required`);
862
+ if (operation === "upload_audio" && !asString(payload.url)) throw new GenerationValidationError("Audio url is required for Suno upload_audio");
863
+ if (operation === "concat" && !asString(payload.clip_id)) throw new GenerationValidationError("clip_id is required for Suno concat");
864
+ }
865
+ async function requestJson(input, path, init) {
866
+ const response = await fetchWithTimeout(input.context.fetch, joinUrl(input.context.baseUrl, path), {
867
+ ...init,
868
+ headers: {
869
+ Authorization: `Bearer ${input.context.apiKey}`,
870
+ "Content-Type": "application/json",
871
+ ...init.headers
872
+ }
873
+ }, REQUEST_TIMEOUT_MS);
874
+ const body = await response.text();
875
+ let parsed;
876
+ try {
877
+ parsed = body ? JSON.parse(body) : {};
878
+ } catch {
879
+ throw new GenerationProviderError("Suno provider returned invalid JSON", {
880
+ status: response.status,
881
+ body
882
+ });
883
+ }
884
+ if (!response.ok) throw new GenerationProviderError("Suno provider request failed", {
885
+ status: response.status,
886
+ details: { body: parsed }
887
+ });
888
+ return parsed;
889
+ }
890
+ function appendUrlBlock(output, type, url, meta) {
891
+ const value = asString(url);
892
+ if (!value) return;
893
+ output.push({
894
+ type,
895
+ source: {
896
+ type: "url",
897
+ url: value
898
+ },
899
+ meta: compactObject(meta)
900
+ });
901
+ }
902
+ function appendSunoContent(output, value, meta = {}) {
903
+ if (Array.isArray(value)) {
904
+ for (const item of value) appendSunoContent(output, item, meta);
905
+ return;
906
+ }
907
+ if (!isRecord$1(value)) return;
908
+ if (isRecord$1(value.clips)) for (const clip of Object.values(value.clips)) appendSunoContent(output, clip, meta);
909
+ if (Array.isArray(value.items)) for (const item of value.items) appendSunoContent(output, item, meta);
910
+ const itemMeta = compactObject({
911
+ ...meta,
912
+ id: value.id,
913
+ clip_id: value.clipId ?? value.clip_id ?? meta.clip_id,
914
+ task_id: value.task_id ?? value.taskId ?? meta.task_id,
915
+ title: value.title,
916
+ status: value.status ?? meta.status,
917
+ model: value.model_name ?? value.modelName,
918
+ duration: value.duration ?? (isRecord$1(value.metadata) ? value.metadata.duration : void 0),
919
+ tags: value.tags ?? (isRecord$1(value.metadata) ? value.metadata.tags : void 0),
920
+ prompt: value.prompt ?? (isRecord$1(value.metadata) ? value.metadata.prompt : void 0),
921
+ progress: value.progress ?? meta.progress,
922
+ progress_message: value.progressMsg ?? value.progress_msg,
923
+ task_batch_id: value.taskBatchId ?? value.task_batch_id,
924
+ continue_clip_id: value.continueClipId ?? value.continue_clip_id,
925
+ input_type: value.inputType ?? value.input_type,
926
+ make_instrumental: value.makeInstrumental ?? value.make_instrumental,
927
+ created_at: value.createTime ?? value.created_at
928
+ });
929
+ appendUrlBlock(output, "audio", value.audio_url ?? value.audioUrl ?? value.cld2AudioUrl ?? value.cld2_audio_url, itemMeta);
930
+ appendUrlBlock(output, "audio", value.vocal_audio_url ?? value.vocalAudioUrl, itemMeta);
931
+ appendUrlBlock(output, "audio", value.instrumental_audio_url ?? value.instrumentalAudioUrl, itemMeta);
932
+ appendUrlBlock(output, "audio", value.source_audio_url ?? value.sourceAudioUrl, itemMeta);
933
+ appendUrlBlock(output, "video", value.video_url ?? value.videoUrl ?? value.cld2VideoUrl ?? value.cld2_video_url, itemMeta);
934
+ appendUrlBlock(output, "image", value.image_large_url ?? value.image_url ?? value.imageUrl ?? value.cld2ImageUrl ?? value.cld2_image_url, itemMeta);
935
+ const text = asString(value.upsampled_tags) ?? asString(value.text) ?? asString(value.lyrics);
936
+ if (text) output.push({
937
+ type: "text",
938
+ text,
939
+ meta: itemMeta
940
+ });
941
+ if (isRecord$1(value.data)) appendSunoContent(output, value.data, itemMeta);
942
+ }
943
+ function buildImmediateResult(operation, data, raw) {
944
+ const output = [];
945
+ const metadata = compactObject({
946
+ operation,
947
+ raw
948
+ });
949
+ appendSunoContent(output, data, metadata);
950
+ if (output.length > 0) return output;
951
+ const value = extractTaskId(data) ?? asString(data);
952
+ if (value) output.push({
953
+ type: "text",
954
+ text: value,
955
+ meta: metadata
956
+ });
957
+ return requireSunoOutput(output, "Suno provider returned no output", {
958
+ operation,
959
+ raw
960
+ });
961
+ }
962
+ function requireSunoOutput(output, message, details) {
963
+ if (output.length === 0) throw new GenerationProviderError(message, { details });
964
+ return output;
965
+ }
966
+ function buildResult(operation, task, raw) {
967
+ const output = [];
968
+ const metadata = compactObject({
969
+ operation,
970
+ task_id: task.task_id,
971
+ action: task.action,
972
+ status: task.status,
973
+ fail_reason: task.fail_reason,
974
+ progress: task.progress,
975
+ submit_time: task.submit_time,
976
+ start_time: task.start_time,
977
+ finish_time: task.finish_time,
978
+ raw
979
+ });
980
+ appendSunoContent(output, task.data, metadata);
981
+ appendUrlBlock(output, "audio", task.result_url, metadata);
982
+ return requireSunoOutput(output, "Suno task succeeded but returned no output", {
983
+ operation,
984
+ task,
985
+ raw
986
+ });
987
+ }
988
+ async function pollSunoTask(input, operation, taskId, pollIntervalSec, maxWaitSec) {
989
+ const startedAt = Date.now();
990
+ while (Date.now() - startedAt <= maxWaitSec * 1e3) {
991
+ await sleep(pollIntervalSec * 1e3);
992
+ let raw;
993
+ try {
994
+ raw = await requestJson(input, `/suno/fetch/${encodeURIComponent(taskId)}`, { method: "GET" });
995
+ } catch (error) {
996
+ if (error instanceof GenerationProviderError) throw error;
997
+ continue;
998
+ }
999
+ const data = requireSuccess(raw, "Suno task fetch failed");
1000
+ const task = normalizeTask(operation, data);
1001
+ if (!task) throw new GenerationProviderError("Suno task fetch returned invalid task data", { details: { data } });
1002
+ const status = normalizeStatus(task.status);
1003
+ if (FINAL_SUCCESS_STATUSES.has(status)) return buildResult(operation, task, data);
1004
+ if (FINAL_FAILURE_STATUSES.has(status)) throw new GenerationProviderError("Suno task failed", { details: {
1005
+ task_id: taskId,
1006
+ status: task.status,
1007
+ fail_reason: task.fail_reason
1008
+ } });
1009
+ }
1010
+ throw new GenerationTimeoutError("Timed out waiting for Suno task", {
1011
+ task_id: taskId,
1012
+ operation
1013
+ });
1014
+ }
1015
+ async function sunoTasksAdapter(input) {
1016
+ const operation = getOperation(input);
1017
+ const payload = await buildPayload(input, operation);
1018
+ const config = OPERATION_PATHS[operation];
1019
+ if (!config) throw new GenerationValidationError(`Unsupported Suno operation: ${operation}`);
1020
+ const raw = await requestJson(input, config.path, {
1021
+ method: "POST",
1022
+ body: JSON.stringify(payload)
1023
+ });
1024
+ const data = requireSuccess(raw, "Suno task submit failed");
1025
+ if (!config.poll) return buildImmediateResult(operation, data, raw);
1026
+ const taskId = extractTaskId(data);
1027
+ if (!taskId) return buildImmediateResult(operation, data, raw);
1028
+ return pollSunoTask(input, operation, taskId, asInteger(input.parameters.poll_interval, DEFAULT_POLL_INTERVAL_SEC), asInteger(input.parameters.max_wait, DEFAULT_MAX_WAIT_SEC));
1029
+ }
1030
+
671
1031
  //#endregion
672
1032
  //#region src/adapters/index.ts
673
1033
  const builtinGenerationAdapters = {
674
1034
  "ark.videoGenerations": arkVideoGenerationsAdapter,
675
1035
  "gemini.generateContent": geminiGenerateContentAdapter,
676
- "openai.images": openAiImagesAdapter
1036
+ "openai.images": openAiImagesAdapter,
1037
+ "suno.tasks": sunoTasksAdapter
677
1038
  };
678
1039
  function getGenerationAdapter(type, adapters = {}) {
679
1040
  const adapter = adapters[type] ?? builtinGenerationAdapters[type];
@@ -700,13 +1061,26 @@ function isParameterSpec(value) {
700
1061
  "boolean"
701
1062
  ].includes(String(value.type));
702
1063
  }
1064
+ function isMetaFieldSpec(value) {
1065
+ if (!isRecord(value)) return false;
1066
+ return isParameterSpec(value) || String(value.type) === "object";
1067
+ }
1068
+ function isMetaTaskVariantSpec(value) {
1069
+ if (!isRecord(value)) return false;
1070
+ return (value.description === void 0 || typeof value.description === "string") && (value.required === void 0 || Array.isArray(value.required) && value.required.every((item) => typeof item === "string")) && (value.requiredContent === void 0 || Array.isArray(value.requiredContent) && value.requiredContent.every((item) => typeof item === "string")) && (value.sendTask === void 0 || typeof value.sendTask === "boolean");
1071
+ }
1072
+ function isMetaSpec(value) {
1073
+ if (!isRecord(value)) return false;
1074
+ return (value.fields === void 0 || isRecord(value.fields) && Object.values(value.fields).every((field) => isMetaFieldSpec(field))) && (value.taskField === void 0 || typeof value.taskField === "string") && (value.taskVariants === void 0 || isRecord(value.taskVariants) && Object.values(value.taskVariants).every((variant) => isMetaTaskVariantSpec(variant)));
1075
+ }
703
1076
  function isGenerationModelDeclaration(value) {
704
1077
  if (!isRecord(value)) return false;
705
1078
  const adapter = value.adapter;
706
1079
  const content = value.content;
707
1080
  const parameters = value.parameters;
1081
+ const meta = value.meta;
708
1082
  const examples = value.examples;
709
- return value.schema === MODEL_SCHEMA && typeof value.model === "string" && value.model.trim().length > 0 && isRecord(adapter) && typeof adapter.type === "string" && isRecord(content) && Array.isArray(content.input) && (parameters === void 0 || isRecord(parameters) && Object.values(parameters).every(isParameterSpec)) && (examples === void 0 || Array.isArray(examples));
1083
+ return value.schema === MODEL_SCHEMA && typeof value.model === "string" && value.model.trim().length > 0 && (value.allowUnknownParameters === void 0 || typeof value.allowUnknownParameters === "boolean") && isRecord(adapter) && typeof adapter.type === "string" && isRecord(content) && Array.isArray(content.input) && (parameters === void 0 || isRecord(parameters) && Object.values(parameters).every(isParameterSpec)) && (meta === void 0 || isMetaSpec(meta)) && (examples === void 0 || Array.isArray(examples));
710
1084
  }
711
1085
  function parseGenerationModelDeclaration(rawText, filePath = "model.yaml") {
712
1086
  const parsed = extname(filePath) === ".json" ? JSON.parse(rawText) : parse(rawText);
@@ -805,10 +1179,15 @@ function createGenerationClient(options = {}) {
805
1179
  const declaration = requireModel(request.model);
806
1180
  validateGenerationContent(declaration, request.content);
807
1181
  const parameters = resolveGenerationParameters(declaration, request.parameters);
1182
+ const meta = resolveGenerationMeta(declaration, mergeGenerationMeta({
1183
+ ...request.metadata ?? {},
1184
+ ...request.meta ?? {}
1185
+ }, request.content), request.content);
808
1186
  return {
809
1187
  declaration: cloneJson(declaration),
810
1188
  request: cloneJson(request),
811
- parameters
1189
+ parameters,
1190
+ meta
812
1191
  };
813
1192
  },
814
1193
  async generate(request) {
@@ -880,5 +1259,5 @@ async function exportBuiltinModelConfigs(directory) {
880
1259
  }
881
1260
 
882
1261
  //#endregion
883
- export { GenerationUnsupportedAdapterError as A, mergeTextBlocks as C, GenerationError as D, GenerationConfigError as E, GenerationProviderError as O, arkVideoGenerationsAdapter as S, validateGenerationContent as T, writeGenerationModelDeclarations as _, createGenerationClientFromDirectory as a, openAiImagesAdapter as b, defaultGenerationSourceResolver as c, parseGenerationModelDeclaration as d, readGenerationModelDeclaration as f, writeGenerationModelDeclaration as g, stringifyGenerationModelDeclaration as h, createGenerationClient as i, GenerationValidationError as j, GenerationTimeoutError as k, isGenerationModelDeclaration as l, readGenerationModelDeclarationsFromFiles as m, exportBuiltinModelConfigs as n, createGenerationClientFromFile as o, readGenerationModelDeclarationsFromDirectory as p, stringifyBuiltinModelConfig as r, createGenerationClientFromFiles as s, exportBuiltinModelConfig as t, mergeGenerationModelDeclarations as u, builtinGenerationAdapters as v, resolveGenerationParameters as w, geminiGenerateContentAdapter as x, getGenerationAdapter as y };
884
- //# sourceMappingURL=export-config-BPnZYpmN.js.map
1262
+ export { GenerationError as A, arkVideoGenerationsAdapter as C, resolveGenerationParameters as D, resolveGenerationMeta as E, GenerationTimeoutError as M, GenerationUnsupportedAdapterError as N, validateGenerationContent as O, GenerationValidationError as P, geminiGenerateContentAdapter as S, mergeTextBlocks as T, writeGenerationModelDeclarations as _, createGenerationClientFromDirectory as a, sunoTasksAdapter as b, defaultGenerationSourceResolver as c, parseGenerationModelDeclaration as d, readGenerationModelDeclaration as f, writeGenerationModelDeclaration as g, stringifyGenerationModelDeclaration as h, createGenerationClient as i, GenerationProviderError as j, GenerationConfigError as k, isGenerationModelDeclaration as l, readGenerationModelDeclarationsFromFiles as m, exportBuiltinModelConfigs as n, createGenerationClientFromFile as o, readGenerationModelDeclarationsFromDirectory as p, stringifyBuiltinModelConfig as r, createGenerationClientFromFiles as s, exportBuiltinModelConfig as t, mergeGenerationModelDeclarations as u, builtinGenerationAdapters as v, mergeGenerationMeta as w, openAiImagesAdapter as x, getGenerationAdapter as y };
1263
+ //# sourceMappingURL=export-config-D8By2_r7.js.map