@sogni-ai/sogni-client 4.2.0-alpha.2 → 4.2.0-alpha.21

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.
Files changed (109) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/CLAUDE.md +25 -3
  3. package/README.md +411 -136
  4. package/dist/Account/index.d.ts +4 -2
  5. package/dist/Account/index.js +27 -23
  6. package/dist/Account/index.js.map +1 -1
  7. package/dist/Account/types.d.ts +7 -0
  8. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.d.ts +3 -1
  9. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js +26 -2
  10. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js.map +1 -1
  11. package/dist/ApiClient/WebSocketClient/eventSubscriptions.d.ts +33 -0
  12. package/dist/ApiClient/WebSocketClient/eventSubscriptions.js +39 -0
  13. package/dist/ApiClient/WebSocketClient/eventSubscriptions.js.map +1 -0
  14. package/dist/ApiClient/WebSocketClient/events.d.ts +24 -7
  15. package/dist/ApiClient/WebSocketClient/index.d.ts +5 -1
  16. package/dist/ApiClient/WebSocketClient/index.js +24 -1
  17. package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
  18. package/dist/ApiClient/WebSocketClient/messages.d.ts +2 -0
  19. package/dist/ApiClient/WebSocketClient/types.d.ts +2 -0
  20. package/dist/ApiClient/index.d.ts +6 -1
  21. package/dist/ApiClient/index.js +7 -3
  22. package/dist/ApiClient/index.js.map +1 -1
  23. package/dist/Chat/ChatTools.d.ts +5 -49
  24. package/dist/Chat/ChatTools.js +311 -88
  25. package/dist/Chat/ChatTools.js.map +1 -1
  26. package/dist/Chat/index.d.ts +11 -2
  27. package/dist/Chat/index.js +78 -4
  28. package/dist/Chat/index.js.map +1 -1
  29. package/dist/Chat/modelRouting.d.ts +100 -0
  30. package/dist/Chat/modelRouting.js +441 -0
  31. package/dist/Chat/modelRouting.js.map +1 -0
  32. package/dist/Chat/sogniHostedTools.generated.json +529 -0
  33. package/dist/Chat/tools.d.ts +9 -55
  34. package/dist/Chat/tools.js +72 -228
  35. package/dist/Chat/tools.js.map +1 -1
  36. package/dist/Chat/types.d.ts +91 -2
  37. package/dist/CreativeWorkflows/index.d.ts +23 -0
  38. package/dist/CreativeWorkflows/index.js +274 -0
  39. package/dist/CreativeWorkflows/index.js.map +1 -0
  40. package/dist/CreativeWorkflows/types.d.ts +106 -0
  41. package/dist/CreativeWorkflows/types.js +3 -0
  42. package/dist/CreativeWorkflows/types.js.map +1 -0
  43. package/dist/Projects/Job.d.ts +6 -0
  44. package/dist/Projects/Job.js +60 -5
  45. package/dist/Projects/Job.js.map +1 -1
  46. package/dist/Projects/Project.js +15 -3
  47. package/dist/Projects/Project.js.map +1 -1
  48. package/dist/Projects/createJobRequestMessage.js +140 -6
  49. package/dist/Projects/createJobRequestMessage.js.map +1 -1
  50. package/dist/Projects/index.d.ts +10 -1
  51. package/dist/Projects/index.js +197 -58
  52. package/dist/Projects/index.js.map +1 -1
  53. package/dist/Projects/types/ModelOptions.d.ts +3 -3
  54. package/dist/Projects/types/ModelOptions.js +12 -5
  55. package/dist/Projects/types/ModelOptions.js.map +1 -1
  56. package/dist/Projects/types/ModelTiersRaw.d.ts +7 -7
  57. package/dist/Projects/types/RawProject.d.ts +2 -0
  58. package/dist/Projects/types/events.d.ts +5 -4
  59. package/dist/Projects/types/index.d.ts +77 -7
  60. package/dist/Projects/types/index.js.map +1 -1
  61. package/dist/Projects/utils/index.d.ts +8 -1
  62. package/dist/Projects/utils/index.js +22 -8
  63. package/dist/Projects/utils/index.js.map +1 -1
  64. package/dist/index.d.ts +28 -3
  65. package/dist/index.js +19 -1
  66. package/dist/index.js.map +1 -1
  67. package/dist/lib/RestClient.d.ts +4 -1
  68. package/dist/lib/RestClient.js +17 -9
  69. package/dist/lib/RestClient.js.map +1 -1
  70. package/dist/lib/mediaValidation.d.ts +16 -0
  71. package/dist/lib/mediaValidation.js +280 -0
  72. package/dist/lib/mediaValidation.js.map +1 -0
  73. package/dist/lib/validation.d.ts +6 -1
  74. package/dist/lib/validation.js +28 -2
  75. package/dist/lib/validation.js.map +1 -1
  76. package/llms-full.txt +372 -133
  77. package/llms.txt +197 -86
  78. package/package.json +13 -4
  79. package/src/Account/index.ts +22 -2
  80. package/src/Account/types.ts +7 -0
  81. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/index.ts +47 -3
  82. package/src/ApiClient/WebSocketClient/eventSubscriptions.ts +92 -0
  83. package/src/ApiClient/WebSocketClient/events.ts +25 -7
  84. package/src/ApiClient/WebSocketClient/index.ts +33 -1
  85. package/src/ApiClient/WebSocketClient/messages.ts +2 -0
  86. package/src/ApiClient/WebSocketClient/types.ts +2 -0
  87. package/src/ApiClient/index.ts +32 -2
  88. package/src/Chat/ChatTools.ts +395 -95
  89. package/src/Chat/index.ts +149 -5
  90. package/src/Chat/modelRouting.ts +602 -0
  91. package/src/Chat/sogniHostedTools.generated.json +529 -0
  92. package/src/Chat/tools.ts +98 -245
  93. package/src/Chat/types.ts +100 -2
  94. package/src/CreativeWorkflows/index.ts +290 -0
  95. package/src/CreativeWorkflows/types.ts +134 -0
  96. package/src/Projects/Job.ts +76 -5
  97. package/src/Projects/Project.ts +13 -3
  98. package/src/Projects/createJobRequestMessage.ts +152 -13
  99. package/src/Projects/index.ts +230 -52
  100. package/src/Projects/types/ModelOptions.ts +15 -8
  101. package/src/Projects/types/ModelTiersRaw.ts +7 -7
  102. package/src/Projects/types/RawProject.ts +2 -0
  103. package/src/Projects/types/events.ts +5 -4
  104. package/src/Projects/types/index.ts +86 -6
  105. package/src/Projects/utils/index.ts +24 -8
  106. package/src/index.ts +93 -0
  107. package/src/lib/RestClient.ts +15 -5
  108. package/src/lib/mediaValidation.ts +367 -0
  109. package/src/lib/validation.ts +38 -2
@@ -29,7 +29,8 @@ import {
29
29
  VIDEO_WORKFLOW_ASSETS,
30
30
  calculateVideoFrames,
31
31
  isLtx2Model,
32
- isWanAnimateModel
32
+ isWanAnimateModel,
33
+ isSeedanceModel
33
34
  } from './utils';
34
35
  import { ApiError } from '../ApiClient';
35
36
  import {
@@ -44,6 +45,19 @@ import {
44
45
  * Throws an error if required assets are missing or forbidden assets are provided.
45
46
  */
46
47
  function validateVideoWorkflowAssets(params: VideoProjectParams): void {
48
+ if (isSeedanceModel(params.modelId)) {
49
+ validateSeedanceReferenceAssets(params);
50
+ return;
51
+ }
52
+ if (params.referenceImageUrls || params.referenceVideoUrls || params.referenceAudioUrls) {
53
+ throw new ApiError(400, {
54
+ status: 'error',
55
+ errorCode: 0,
56
+ message:
57
+ 'referenceImageUrls, referenceVideoUrls, and referenceAudioUrls are supported only by Seedance models.'
58
+ });
59
+ }
60
+
47
61
  const workflowType = getVideoWorkflowType(params.modelId);
48
62
  if (!workflowType) return;
49
63
 
@@ -94,6 +108,92 @@ function validateVideoWorkflowAssets(params: VideoProjectParams): void {
94
108
  }
95
109
  }
96
110
 
111
+ function asReferenceUrlArray(value: unknown): string[] {
112
+ if (!Array.isArray(value)) return [];
113
+ return value.filter((url): url is string => typeof url === 'string' && url.trim().length > 0);
114
+ }
115
+
116
+ function validateReferenceUrlArray(value: unknown, propertyName: string): void {
117
+ if (value === undefined) return;
118
+ if (!Array.isArray(value)) {
119
+ throw new ApiError(400, {
120
+ status: 'error',
121
+ errorCode: 0,
122
+ message: `${propertyName} must be an array of URL strings.`
123
+ });
124
+ }
125
+ if (value.some((url) => typeof url !== 'string' || url.trim().length === 0)) {
126
+ throw new ApiError(400, {
127
+ status: 'error',
128
+ errorCode: 0,
129
+ message: `${propertyName} must contain only non-empty URL strings.`
130
+ });
131
+ }
132
+ }
133
+
134
+ function validateSeedanceReferenceAssets(params: VideoProjectParams): void {
135
+ validateReferenceUrlArray(params.referenceImageUrls, 'referenceImageUrls');
136
+ validateReferenceUrlArray(params.referenceVideoUrls, 'referenceVideoUrls');
137
+ validateReferenceUrlArray(params.referenceAudioUrls, 'referenceAudioUrls');
138
+
139
+ const imageCount =
140
+ (params.referenceImage ? 1 : 0) +
141
+ (params.referenceImageEnd ? 1 : 0) +
142
+ asReferenceUrlArray(params.referenceImageUrls).length;
143
+ const videoCount =
144
+ (params.referenceVideo ? 1 : 0) + asReferenceUrlArray(params.referenceVideoUrls).length;
145
+ const audioCount =
146
+ (params.referenceAudio || params.referenceAudioIdentity ? 1 : 0) +
147
+ asReferenceUrlArray(params.referenceAudioUrls).length;
148
+ const totalAssetCount = imageCount + videoCount + audioCount;
149
+
150
+ if (imageCount > 9) {
151
+ throw new ApiError(400, {
152
+ status: 'error',
153
+ errorCode: 0,
154
+ message: 'Seedance supports at most 9 image assets.'
155
+ });
156
+ }
157
+ if (videoCount > 3) {
158
+ throw new ApiError(400, {
159
+ status: 'error',
160
+ errorCode: 0,
161
+ message: 'Seedance supports at most 3 video assets.'
162
+ });
163
+ }
164
+ if (audioCount > 3) {
165
+ throw new ApiError(400, {
166
+ status: 'error',
167
+ errorCode: 0,
168
+ message: 'Seedance supports at most 3 audio assets.'
169
+ });
170
+ }
171
+ if (totalAssetCount > 12) {
172
+ throw new ApiError(400, {
173
+ status: 'error',
174
+ errorCode: 0,
175
+ message: 'Seedance supports at most 12 total asset files.'
176
+ });
177
+ }
178
+ if (audioCount > 0 && imageCount === 0 && videoCount === 0) {
179
+ throw new ApiError(400, {
180
+ status: 'error',
181
+ errorCode: 0,
182
+ message: 'Seedance audio references require at least one image or video reference.'
183
+ });
184
+ }
185
+ }
186
+
187
+ function getMaxVideoDuration(modelId: string): number {
188
+ if (isSeedanceModel(modelId)) {
189
+ return 15;
190
+ }
191
+ if (isLtx2Model(modelId) || isWanAnimateModel(modelId)) {
192
+ return 20;
193
+ }
194
+ return 10;
195
+ }
196
+
97
197
  // Mac worker can't process the data if some of the fields are missing, so we need to provide a default template
98
198
  function getTemplate() {
99
199
  return {
@@ -226,14 +326,12 @@ function applyImageParams(
226
326
  ) {
227
327
  const keyFrame: Record<string, any> = {
228
328
  ...inputKeyframe,
229
- sizePreset: params.sizePreset,
230
- hasContextImage1: !!params.contextImages?.[0],
231
- hasContextImage2: !!params.contextImages?.[1],
232
- hasContextImage3: !!params.contextImages?.[2],
233
- hasContextImage4: !!params.contextImages?.[3],
234
- hasContextImage5: !!params.contextImages?.[4],
235
- hasContextImage6: !!params.contextImages?.[5]
329
+ sizePreset: params.sizePreset
236
330
  };
331
+ const contextImages = params.contextImages || [];
332
+ for (let index = 1; index <= 16; index += 1) {
333
+ keyFrame[`hasContextImage${index}`] = !!contextImages[index - 1];
334
+ }
237
335
  // Sampler/scheduler handling: SDK validates and passes through as-is.
238
336
  // sogni-socket normalizes values for both ComfyUI and Forge workers.
239
337
  if (isComfyModel(params.modelId)) {
@@ -264,8 +362,20 @@ function applyImageParams(
264
362
  keyFrame.sizePreset = effectiveSizePreset;
265
363
 
266
364
  if (effectiveSizePreset === 'custom' && params.width && params.height) {
267
- keyFrame.width = validateCustomImageSize(params.width);
268
- keyFrame.height = validateCustomImageSize(params.height);
365
+ keyFrame.width = validateCustomImageSize(params.width, {
366
+ modelId: params.modelId,
367
+ propertyName: 'Width'
368
+ });
369
+ keyFrame.height = validateCustomImageSize(params.height, {
370
+ modelId: params.modelId,
371
+ propertyName: 'Height'
372
+ });
373
+ }
374
+ if (params.gptImageQuality !== undefined) {
375
+ keyFrame.gptImageQuality = params.gptImageQuality;
376
+ }
377
+ if (params.gptImageBackground !== undefined) {
378
+ keyFrame.gptImageBackground = params.gptImageBackground;
269
379
  }
270
380
  return keyFrame;
271
381
  }
@@ -287,18 +397,33 @@ function applyVideoParams(
287
397
  if (params.referenceImage) {
288
398
  keyFrame.hasReferenceImage = true;
289
399
  }
400
+ const referenceImageUrls = asReferenceUrlArray(params.referenceImageUrls);
401
+ if (referenceImageUrls.length) {
402
+ keyFrame.referenceImageURLs = referenceImageUrls;
403
+ }
290
404
  if (params.referenceImageEnd) {
291
405
  keyFrame.hasReferenceImageEnd = true;
292
406
  }
293
407
  if (params.referenceAudio) {
294
408
  keyFrame.hasReferenceAudio = true;
295
409
  }
410
+ const referenceAudioUrls = asReferenceUrlArray(params.referenceAudioUrls);
411
+ if (referenceAudioUrls.length) {
412
+ keyFrame.referenceAudioURLs = referenceAudioUrls;
413
+ }
296
414
  if (params.referenceVideo) {
297
415
  keyFrame.hasReferenceVideo = true;
298
416
  }
417
+ const referenceVideoUrls = asReferenceUrlArray(params.referenceVideoUrls);
418
+ if (referenceVideoUrls.length) {
419
+ keyFrame.referenceVideoURLs = referenceVideoUrls;
420
+ }
299
421
  if (params.referenceAudioIdentity) {
300
422
  keyFrame.hasReferenceAudioIdentity = true;
301
423
  }
424
+ if (params.generateAudio !== undefined) {
425
+ keyFrame.generateAudio = params.generateAudio;
426
+ }
302
427
  if (params.audioIdentityStrength !== undefined) {
303
428
  keyFrame.identityGuidanceScale = params.audioIdentityStrength;
304
429
  }
@@ -307,19 +432,23 @@ function applyVideoParams(
307
432
  // Note: fps must be processed before duration to correctly calculate frames for LTX-2.3 models
308
433
  if (params.fps !== undefined) {
309
434
  keyFrame.fps = params.fps;
435
+ } else if (isSeedanceModel(params.modelId)) {
436
+ keyFrame.fps = 24;
310
437
  }
311
438
  if (params.frames !== undefined) {
312
439
  keyFrame.frames = params.frames;
313
440
  }
314
441
  if (params.duration !== undefined) {
442
+ const isSeedance = isSeedanceModel(params.modelId);
315
443
  const duration = validateVideoDuration(
316
444
  params.duration,
317
- 1,
318
- isLtx2Model(params.modelId) || isWanAnimateModel(params.modelId) ? 20 : 10
445
+ isSeedance ? 4 : 1,
446
+ getMaxVideoDuration(params.modelId)
319
447
  );
320
448
  // Use fps from params or default based on model type:
321
449
  // - WAN 2.2: fps doesn't affect frame count (always generates at 16fps)
322
450
  // - LTX-2.3: fps directly affects frame count (default 24fps if not specified)
451
+ // - Seedance: fixed 24fps external API generation
323
452
  const fps = params.fps ?? 24;
324
453
  keyFrame.frames = calculateVideoFrames(params.modelId, duration, fps);
325
454
  }
@@ -432,6 +561,10 @@ function applyAudioParams(
432
561
 
433
562
  function createJobRequestMessage(id: string, params: ProjectParams, options: ModelOptions) {
434
563
  const template = getTemplate();
564
+ const negativePrompt =
565
+ isImageParams(params) || (isVideoParams(params) && !isSeedanceModel(params.modelId))
566
+ ? params.negativePrompt
567
+ : undefined;
435
568
  // Base keyFrame with common params
436
569
  let keyFrame: Record<string, any> = {
437
570
  ...template.keyFrames[0],
@@ -442,13 +575,16 @@ function createJobRequestMessage(id: string, params: ProjectParams, options: Mod
442
575
  positivePrompt: params.positivePrompt,
443
576
  // Only include optional prompts if they have actual non-empty values
444
577
  // This allows the server to use its defaults when not specified
445
- ...(params.negativePrompt && { negativePrompt: params.negativePrompt }),
578
+ ...(negativePrompt && { negativePrompt }),
446
579
  ...(params.stylePrompt && { stylePrompt: params.stylePrompt }),
447
580
  // LoRA IDs for LoRA loading (resolved to filenames by worker via config API)
448
581
  ...(params.loras && params.loras.length > 0 && { loras: params.loras }),
449
582
  ...(params.loraStrengths &&
450
583
  params.loraStrengths.length > 0 && { loraStrengths: params.loraStrengths })
451
584
  };
585
+ if (isAudioParams(params) || (isVideoParams(params) && isSeedanceModel(params.modelId))) {
586
+ delete keyFrame.negativePrompt;
587
+ }
452
588
 
453
589
  switch (params.type) {
454
590
  case 'image':
@@ -507,6 +643,9 @@ function createJobRequestMessage(id: string, params: ProjectParams, options: Mod
507
643
  if (params.network) {
508
644
  jobRequest.network = params.network;
509
645
  }
646
+ if (params.appSource) {
647
+ jobRequest.appSource = params.appSource;
648
+ }
510
649
 
511
650
  return jobRequest;
512
651
  }