vidspotai-shared 1.0.130 → 1.0.131

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 (43) hide show
  1. package/lib/globals/aiModels/enums.d.ts +2 -0
  2. package/lib/globals/aiModels/enums.d.ts.map +1 -1
  3. package/lib/globals/aiModels/enums.js +22 -1
  4. package/lib/globals/aiModels/providers/bytedance.d.ts.map +1 -1
  5. package/lib/globals/aiModels/providers/bytedance.js +4 -0
  6. package/lib/globals/aiModels/tierHelpers.d.ts +3 -1
  7. package/lib/globals/aiModels/tierHelpers.d.ts.map +1 -1
  8. package/lib/globals/aiModels/tierHelpers.js +7 -1
  9. package/lib/globals/aiModels/types.d.ts +7 -0
  10. package/lib/globals/aiModels/types.d.ts.map +1 -1
  11. package/lib/services/agent/planner/Planner.d.ts.map +1 -1
  12. package/lib/services/agent/planner/Planner.js +9 -0
  13. package/lib/services/agent/providerFallback/chains.d.ts.map +1 -1
  14. package/lib/services/agent/providerFallback/chains.js +5 -1
  15. package/lib/services/agent/tools/searchUserLibrary.tool.d.ts.map +1 -1
  16. package/lib/services/agent/tools/searchUserLibrary.tool.js +7 -1
  17. package/lib/services/aiGen/helpers.d.ts.map +1 -1
  18. package/lib/services/aiGen/helpers.js +5 -0
  19. package/lib/services/aiGen/providers/alibaba/alibaba.d.ts.map +1 -1
  20. package/lib/services/aiGen/providers/alibaba/alibaba.js +27 -0
  21. package/lib/services/aiGen/providers/bytedance/bytedance.service.d.ts.map +1 -1
  22. package/lib/services/aiGen/providers/bytedance/bytedance.service.js +6 -0
  23. package/lib/services/aiGen/providers/google/googleMusic.d.ts.map +1 -1
  24. package/lib/services/aiGen/providers/google/googleMusic.js +14 -1
  25. package/lib/services/aiGen/providers/runway/runway.service.d.ts +2 -2
  26. package/lib/services/aiGen/providers/runway/runway.service.d.ts.map +1 -1
  27. package/lib/services/aiGen/providers/runway/runway.service.js +81 -3
  28. package/lib/services/bullmq.service.d.ts +11 -0
  29. package/lib/services/bullmq.service.d.ts.map +1 -1
  30. package/lib/services/bullmq.service.js +79 -18
  31. package/lib/services/translation/index.d.ts +1 -1
  32. package/lib/services/translation/index.d.ts.map +1 -1
  33. package/lib/services/translation/index.js +2 -1
  34. package/lib/services/translation/outputLanguage.d.ts +9 -0
  35. package/lib/services/translation/outputLanguage.d.ts.map +1 -1
  36. package/lib/services/translation/outputLanguage.js +53 -1
  37. package/lib/services/translation/translation.service.d.ts +16 -0
  38. package/lib/services/translation/translation.service.d.ts.map +1 -1
  39. package/lib/services/translation/translation.service.js +47 -0
  40. package/lib/utils/errors.d.ts +7 -0
  41. package/lib/utils/errors.d.ts.map +1 -1
  42. package/lib/utils/errors.js +23 -0
  43. package/package.json +1 -1
@@ -133,6 +133,8 @@ export declare enum EMusicGenModels {
133
133
  GOOGLE_LYRIA_3 = "google-lyria-3",
134
134
  GOOGLE_LYRIA_3_PRO = "google-lyria-3-pro"
135
135
  }
136
+ export declare const DEFAULT_MUSIC_MODEL = EMusicGenModels.GOOGLE_LYRIA_2;
137
+ export declare function resolveMusicModelKey(key: EMusicGenModels): EMusicGenModels;
136
138
  export declare enum ETextGenModels {
137
139
  OPENAI_GPT_5_5 = "openai-gpt-5.5",
138
140
  OPENAI_GPT_5_4_MINI = "openai-gpt-5.4-mini",
@@ -1 +1 @@
1
- {"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../src/globals/aiModels/enums.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../src/globals/aiModels/enums.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EUpscaleVideoModels = exports.EUpscaleImageModels = exports.ESfxGenModels = exports.ETextGenModels = exports.EMusicGenModels = exports.EImageGenModels = exports.EVideoGenModels = void 0;
3
+ exports.EUpscaleVideoModels = exports.EUpscaleImageModels = exports.ESfxGenModels = exports.ETextGenModels = exports.DEFAULT_MUSIC_MODEL = exports.EMusicGenModels = exports.EImageGenModels = exports.EVideoGenModels = void 0;
4
+ exports.resolveMusicModelKey = resolveMusicModelKey;
4
5
  var EVideoGenModels;
5
6
  (function (EVideoGenModels) {
6
7
  EVideoGenModels["PIXVERSE_C1"] = "pixverse-c1";
@@ -175,6 +176,26 @@ var EMusicGenModels;
175
176
  EMusicGenModels["GOOGLE_LYRIA_3"] = "google-lyria-3";
176
177
  EMusicGenModels["GOOGLE_LYRIA_3_PRO"] = "google-lyria-3-pro";
177
178
  })(EMusicGenModels || (exports.EMusicGenModels = EMusicGenModels = {}));
179
+ /**
180
+ * Music keys that can no longer be served, mapped to the live model that
181
+ * replaces them. Resolve every incoming music key through
182
+ * resolveMusicModelKey() so old clients / saved MCP configs keep working.
183
+ * - minimax-music-1.5: MiniMax withdrew the Music API from our account
184
+ * (status 2153 "no longer available to new users", 100% failing since
185
+ * 2026-09-14).
186
+ * - google-lyria-3 / -3-pro: their modelIds (lyria-003, lyria-3-pro) are not
187
+ * Vertex publisher models — GET publishers/google/models/<id> → 404
188
+ * (verified 2026-10-20); lyria-002 is GA and reachable.
189
+ */
190
+ const RETIRED_MUSIC_MODELS = {
191
+ [EMusicGenModels.MINIMAX_MUSIC_1_5]: EMusicGenModels.GOOGLE_LYRIA_2,
192
+ [EMusicGenModels.GOOGLE_LYRIA_3]: EMusicGenModels.GOOGLE_LYRIA_2,
193
+ [EMusicGenModels.GOOGLE_LYRIA_3_PRO]: EMusicGenModels.GOOGLE_LYRIA_2,
194
+ };
195
+ exports.DEFAULT_MUSIC_MODEL = EMusicGenModels.GOOGLE_LYRIA_2;
196
+ function resolveMusicModelKey(key) {
197
+ return RETIRED_MUSIC_MODELS[key] ?? key;
198
+ }
178
199
  var ETextGenModels;
179
200
  (function (ETextGenModels) {
180
201
  // ── OpenAI ──────────────────────────────────────────────────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"bytedance.d.ts","sourceRoot":"","sources":["../../../../src/globals/aiModels/providers/bytedance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAWxC,eAAO,MAAM,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CA+ZvE,CAAC"}
1
+ {"version":3,"file":"bytedance.d.ts","sourceRoot":"","sources":["../../../../src/globals/aiModels/providers/bytedance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAWxC,eAAO,MAAM,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAmavE,CAAC"}
@@ -237,6 +237,10 @@ exports.bytedanceConfigs = {
237
237
  // docs.byteplus.com/en/docs/ModelArk/2607688 + /1544106 (2026-08-09).
238
238
  "bytedance-seedance-2.0-mini": {
239
239
  modelId: "dreamina-seedance-2-0-mini-260615",
240
+ // BytePlus returns ModelNotOpen until Mini is activated in the Ark console
241
+ // (prod 2026-10). Backend mirror of the frontend's NEXT_PUBLIC_SEEDANCE_MINI_LIVE:
242
+ // set SEEDANCE_MINI_LIVE=true (Doppler + Railway) once activated.
243
+ gatedByEnv: "SEEDANCE_MINI_LIVE",
240
244
  type: ["text-to-video", "image-to-video", "video-to-video"],
241
245
  acceptedImageFormats: ["image/jpeg", "image/jpg", "image/png"],
242
246
  // Same language set as the rest of the Seedance 2.0 series (shared Dreamina pipeline).
@@ -10,7 +10,9 @@ export interface ModelMatch {
10
10
  }
11
11
  /** False for retired (shut down) and deprecated (still served, no longer
12
12
  * offered) models — the gate for every "which models can I pick" list. */
13
- export declare function isModelOffered(config: Pick<IModelSchema, "retired" | "deprecated"> | undefined): boolean;
13
+ export declare function isModelOffered(config: Pick<IModelSchema, "retired" | "deprecated" | "gatedByEnv"> | undefined): boolean;
14
+ /** False while the model's `gatedByEnv` flag is set but not `"true"`. */
15
+ export declare function isModelEnvEnabled(config: Pick<IModelSchema, "gatedByEnv"> | undefined): boolean;
14
16
  /** Return every model whose tier matches. Optionally filter by GenerationType. */
15
17
  export declare function getModelsByTier(tier: Tier, type?: GenerationType): ModelMatch[];
16
18
  /** Return the cheapest model satisfying (tier, type). Uses cost.fixed → cost.perSecond → 0. */
@@ -1 +1 @@
1
- {"version":3,"file":"tierHelpers.d.ts","sourceRoot":"","sources":["../../../src/globals/aiModels/tierHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAGzD,OAAO,KAAK,EAAE,cAAc,EAAc,YAAY,EAAE,MAAM,SAAS,CAAC;AAExE;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;2EAC2E;AAC3E,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC,GAAG,SAAS,GAAG,OAAO,CAExG;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,UAAU,EAAE,CAS/E;AAED,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,cAAc,GACnB,UAAU,GAAG,SAAS,CAIxB;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE,CAMlE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAc3E;AAWD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,GAAE,cAAgC,GACrC,MAAM,CAeR;AAgCD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,MAAM,GAAG,IAAI,CASf;AA8DD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAU1E"}
1
+ {"version":3,"file":"tierHelpers.d.ts","sourceRoot":"","sources":["../../../src/globals/aiModels/tierHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAGzD,OAAO,KAAK,EAAE,cAAc,EAAc,YAAY,EAAE,MAAM,SAAS,CAAC;AAExE;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;2EAC2E;AAC3E,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,GAAG,YAAY,CAAC,GAAG,SAAS,GAC9E,OAAO,CAET;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,GAAG,SAAS,GAAG,OAAO,CAG/F;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,UAAU,EAAE,CAS/E;AAED,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,cAAc,GACnB,UAAU,GAAG,SAAS,CAIxB;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE,CAMlE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAc3E;AAWD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,GAAE,cAAgC,GACrC,MAAM,CAeR;AAgCD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,MAAM,GAAG,IAAI,CASf;AA8DD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAU1E"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isModelOffered = isModelOffered;
4
+ exports.isModelEnvEnabled = isModelEnvEnabled;
4
5
  exports.getModelsByTier = getModelsByTier;
5
6
  exports.getCheapestModel = getCheapestModel;
6
7
  exports.getModelsByType = getModelsByType;
@@ -13,7 +14,12 @@ const creditUnit_1 = require("../creditUnit");
13
14
  /** False for retired (shut down) and deprecated (still served, no longer
14
15
  * offered) models — the gate for every "which models can I pick" list. */
15
16
  function isModelOffered(config) {
16
- return !!config && !config.retired && !config.deprecated;
17
+ return !!config && !config.retired && !config.deprecated && isModelEnvEnabled(config);
18
+ }
19
+ /** False while the model's `gatedByEnv` flag is set but not `"true"`. */
20
+ function isModelEnvEnabled(config) {
21
+ const flag = config?.gatedByEnv;
22
+ return !flag || process.env[flag] === "true";
17
23
  }
18
24
  /** Return every model whose tier matches. Optionally filter by GenerationType. */
19
25
  function getModelsByTier(tier, type) {
@@ -92,6 +92,13 @@ export interface IModelSchema {
92
92
  reason: string;
93
93
  replacement?: string;
94
94
  };
95
+ /**
96
+ * Env flag that must be `"true"` for this model to be offered — for models
97
+ * integrated ahead of provider-side activation (e.g. BytePlus ModelNotOpen).
98
+ * While unset: validateParams rejects it (non-paging), and the planner,
99
+ * fallback chains, capacity spill, repair and MCP list_models skip it.
100
+ */
101
+ gatedByEnv?: string;
95
102
  fields: Record<string, ISchemaField>;
96
103
  resolutionRules?: Record<string, string[]>;
97
104
  durationRules?: Record<number, string[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/globals/aiModels/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEzD,MAAM,MAAM,cAAc,GACtB,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,UAAU,GACV,cAAc,GACd,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,aAAa,GACb,eAAe,GACf,eAAe,GACf,eAAe,GACf,eAAe,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,gBAAgB,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,WAAW,EAAE,WAAW,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACpC;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAErC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACzC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB;;;;WAIG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QAKrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC,KAAK,CAAC,EAAE,UAAU,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IACF;;;;;OAKG;IACH,QAAQ,CAAC,EAAE;QACT,mEAAmE;QACnE,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,2DAA2D;QAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,4CAA4C;QAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,+CAA+C;QAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,4FAA4F;IAC5F,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,kHAAkH;IAClH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC;;;;;;;;;;OAUG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/globals/aiModels/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Planner.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/planner/Planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAoB,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,SAAS,EAEV,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAkB7C;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,OAAO;IAIN,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAEP,IAAI,EAAE,cAAc;IAK3C,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;QACvC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;QAChC;;;;;;WAMG;QACH,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;KAC9B,GACL,OAAO,CAAC,SAAS,CAAC;IAyRrB;;;;;;;;;;;OAWG;IACH,UAAU,CACR,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;QACvC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;KAC5B,GACL;QAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;KAAE;IAqEhE;;;;;;;;;;;;;;;;OAgBG;IACG,0BAA0B,CAC9B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;QAChC,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,0EAA0E;QAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;KACjB,GACL,OAAO,CAAC,WAAW,EAAE,CAAC;CAQ1B"}
1
+ {"version":3,"file":"Planner.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/planner/Planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAoB,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,SAAS,EAEV,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAkB7C;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,OAAO;IAIN,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAEP,IAAI,EAAE,cAAc;IAK3C,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;QACvC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;QAChC;;;;;;WAMG;QACH,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;KAC9B,GACL,OAAO,CAAC,SAAS,CAAC;IA8RrB;;;;;;;;;;;OAWG;IACH,UAAU,CACR,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;QACvC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;KAC5B,GACL;QAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;KAAE;IAuEhE;;;;;;;;;;;;;;;;OAgBG;IACG,0BAA0B,CAC9B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;QAChC,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,0EAA0E;QAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;KACjB,GACL,OAAO,CAAC,WAAW,EAAE,CAAC;CAQ1B"}
@@ -249,6 +249,12 @@ class Planner {
249
249
  // TTS language and the caption ASR hint, so it must survive even when
250
250
  // the LLM omits it (it's marked ORCHESTRATOR-ONLY in the schema).
251
251
  reparsed.data.outputLanguage = brief.outputLanguage;
252
+ // The aspect the user picked is a hard constraint, not a hint: the
253
+ // executor renders every scene and the final cut at plan.aspect, so an
254
+ // LLM that drifts to its landscape habit would ship a 16:9 video for a
255
+ // 9:16 request. Overlay deterministically, same as outputLanguage.
256
+ if (brief.aspect)
257
+ reparsed.data.aspect = brief.aspect;
252
258
  // Soft-validation pass: vo-clip (if we downgraded after maxRetries)
253
259
  // + trailing-silence. These ship with the plan; the UI surfaces them.
254
260
  reparsed.data.warnings = (0, validators_1.collectPlanWarnings)(reparsed.data);
@@ -336,6 +342,9 @@ class Planner {
336
342
  if (reparsed.success) {
337
343
  // Stream path skipped the validators loop; still attach soft warnings.
338
344
  reparsed.data.warnings = (0, validators_1.collectPlanWarnings)(reparsed.data);
345
+ // Requested aspect is a hard constraint — see plan().
346
+ if (brief.aspect)
347
+ reparsed.data.aspect = brief.aspect;
339
348
  return reparsed.data;
340
349
  }
341
350
  // Validation tripped on a streamed payload — fall back to retry pass.
@@ -1 +1 @@
1
- {"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/providerFallback/chains.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,eAAe,EACf,aAAa,EAEb,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAGnC;;;;;;;;;;;;GAYG;AAGH,eAAO,MAAM,sBAAsB,EAAE,SAAS,eAAe,EAY5D,CAAC;AAKF,eAAO,MAAM,sBAAsB,EAAE,SAAS,eAAe,EAW5D,CAAC;AAQF,eAAO,MAAM,uBAAuB,EAAE,SAAS,eAAe,EAW7D,CAAC;AAKF,eAAO,MAAM,uBAAuB,EAAE,SAAS,eAAe,EAU7D,CAAC;AASF,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAIxD,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,SAAS,eAAe,EAGjD,CAAC;AAGF,eAAO,MAAM,SAAS,EAAE,SAAS,aAAa,EAE7C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAuCT;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CASjD;AA6DD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,CAI5E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,KAAK,EAAE,eAAe,GACrB,eAAe,EAAE,CAInB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAOtE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,eAAe,EAC5B,aAAa,EAAE,SAAS,eAAe,EAAE,GACxC,eAAe,EAAE,CAMnB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,eAAe,EAC/B,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,mBAAwB,GAC7B,kBAAkB,GAAG,IAAI,CAyB3B"}
1
+ {"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/providerFallback/chains.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,eAAe,EACf,aAAa,EAGb,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAGnC;;;;;;;;;;;;GAYG;AAGH,eAAO,MAAM,sBAAsB,EAAE,SAAS,eAAe,EAY5D,CAAC;AAKF,eAAO,MAAM,sBAAsB,EAAE,SAAS,eAAe,EAW5D,CAAC;AAQF,eAAO,MAAM,uBAAuB,EAAE,SAAS,eAAe,EAW7D,CAAC;AAKF,eAAO,MAAM,uBAAuB,EAAE,SAAS,eAAe,EAU7D,CAAC;AASF,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAIxD,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,SAAS,eAAe,EAIjD,CAAC;AAGF,eAAO,MAAM,SAAS,EAAE,SAAS,aAAa,EAE7C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAyCT;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CASjD;AA6DD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,CAI5E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,KAAK,EAAE,eAAe,GACrB,eAAe,EAAE,CAInB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAOtE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,eAAe,EAC5B,aAAa,EAAE,SAAS,eAAe,EAAE,GACxC,eAAe,EAAE,CAMnB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,eAAe,EAC/B,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,mBAAwB,GAC7B,kBAAkB,GAAG,IAAI,CAyB3B"}
@@ -99,7 +99,8 @@ exports.AVATAR_VIDEO_CHAIN = [
99
99
  // ── Music: search/gen ─────────────────────────────────────────────────
100
100
  exports.MUSIC_CHAIN = [
101
101
  aiModels_1.EMusicGenModels.GOOGLE_LYRIA_2,
102
- aiModels_1.EMusicGenModels.MINIMAX_MUSIC_1_5,
102
+ // REMOVED FOR v1 — kept for reference: MiniMax Music API withdrawn (2153).
103
+ // EMusicGenModels.MINIMAX_MUSIC_1_5,
103
104
  ];
104
105
  // ── SFX: ElevenLabs only ──────────────────────────────────────────────
105
106
  exports.SFX_CHAIN = [
@@ -109,6 +110,9 @@ function isVideoModelCapable(model, req) {
109
110
  const cfg = aiModels_1.aiModelConfigs[model];
110
111
  if (!cfg)
111
112
  return true; // unknown model → optimistic
113
+ // Not offered (retired / env-gated pending provider activation) → can't serve.
114
+ if (!(0, aiModels_1.isModelOffered)(cfg))
115
+ return false;
112
116
  // Type gate (text-to-video vs image-to-video).
113
117
  if (req.type && cfg.type && !cfg.type.includes(req.type))
114
118
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"searchUserLibrary.tool.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/tools/searchUserLibrary.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAgB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE/D;;;;;;;GAOG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;CACf,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAGlC,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,mBAAmB,GAAG,IAAI,CAElE;AAED,QAAA,MAAM,WAAW;;;;;;;;;;iBASf,CAAC;AAEH,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;iBAahB,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAChD,OAAO,WAAW,EAClB,OAAO,YAAY,CA2BpB,CAAC"}
1
+ {"version":3,"file":"searchUserLibrary.tool.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/tools/searchUserLibrary.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAgB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE/D;;;;;;;GAOG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;CACf,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAGlC,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,mBAAmB,GAAG,IAAI,CAElE;AAED,QAAA,MAAM,WAAW;;;;;;;;;;iBASf,CAAC;AAEH,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;iBAahB,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAChD,OAAO,WAAW,EAClB,OAAO,YAAY,CAiCpB,CAAC"}
@@ -52,7 +52,13 @@ exports.searchUserLibraryTool = {
52
52
  kind: input.kind,
53
53
  limit: input.limit,
54
54
  });
55
- return { assets };
55
+ // Only real, fetchable media is a library asset. The Firestore searcher
56
+ // scans projectJson clips, and the run's own C23 shell write (plus any
57
+ // earlier failed project) carries skeleton clips whose src is the
58
+ // `data:,placeholder` sentinel — a valid URL to zod, so a user-asset scene
59
+ // "found" it, succeeded with no visual, and the auto-render then failed
60
+ // with SCENES_NOT_READY (prod 2026-10-15). Drop anything not http(s).
61
+ return { assets: assets.filter((a) => /^https?:\/\//i.test(a.url)) };
56
62
  },
57
63
  };
58
64
  (0, toolRegistry_1.registerTool)(exports.searchUserLibraryTool);
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGhE;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,EAAE,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG3E;AAED,gFAAgF;AAChF,6FAA6F;AAC7F,MAAM,WAAW,uBAAuB;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,4DAA4D;IAC5D,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,uBAAuB,GAAG;IAClE,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAC;CACxB,CAqBA;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CA6KrE"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGhE;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,EAAE,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG3E;AAED,gFAAgF;AAChF,6FAA6F;AAC7F,MAAM,WAAW,uBAAuB;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,4DAA4D;IAC5D,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,uBAAuB,GAAG;IAClE,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAC;CACxB,CAqBA;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAsLrE"}
@@ -83,6 +83,11 @@ function validateParams(params) {
83
83
  if (modelConfig.retired) {
84
84
  throw new errors_1.UserFacingError(`Model ${params.modelKey} is no longer available: ${modelConfig.retired.reason} Please pick a different model.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
85
85
  }
86
+ // 0b. Integrated but not yet activated provider-side (gatedByEnv unset) —
87
+ // same non-paging rejection instead of a provider ModelNotOpen round-trip.
88
+ if (!(0, aiModels_1.isModelEnvEnabled)(modelConfig)) {
89
+ throw new errors_1.UserFacingError(`Model ${params.modelKey} isn't available yet. Please pick a different model.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
90
+ }
86
91
  const errors = [];
87
92
  // 1. Field-level validation (required + allowedValues)
88
93
  for (const [field, rules] of Object.entries(modelConfig.fields)) {
@@ -1 +1 @@
1
- {"version":3,"file":"alibaba.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/alibaba/alibaba.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAwFlB;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,qBAAqB,GAC5B;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAgJzE;AA2CD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAmBpB;AAED,qBAAa,cAAe,SAAQ,wBAAwB;IAE1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;;IAiBjC;;;;OAIG;YACW,OAAO;IAwDf,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;YAyInB,WAAW;IAwBnB,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,EACzB,QAAQ,GACT,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqEjD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA6EjC;;;OAGG;YACW,iBAAiB;IAoD/B;;;OAGG;YACW,kBAAkB;IA6DhC,aAAa,CAAC,EACZ,QAAQ,EACR,UAAU,EACV,WAAW,EACX,QAAQ,EACR,SAAiB,EACjB,SAAa,EACb,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,KAAK,EACL,cAAc,GACf,EAAE,iBAAiB,GAAG,MAAM;CA4C9B"}
1
+ {"version":3,"file":"alibaba.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/alibaba/alibaba.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAoGlB;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,qBAAqB,GAC5B;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAgJzE;AA2CD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAmBpB;AAED,qBAAa,cAAe,SAAQ,wBAAwB;IAE1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;;IAiBjC;;;;OAIG;YACW,OAAO;IA8Df,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;YAyInB,WAAW;IAwBnB,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,EACzB,QAAQ,GACT,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA8EjD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA6EjC;;;OAGG;YACW,iBAAiB;IAoD/B;;;OAGG;YACW,kBAAkB;IAmEhC,aAAa,CAAC,EACZ,QAAQ,EACR,UAAU,EACV,WAAW,EACX,QAAQ,EACR,SAAiB,EACjB,SAAa,EACb,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,KAAK,EACL,cAAc,GACf,EAAE,iBAAiB,GAAG,MAAM;CA4C9B"}
@@ -16,6 +16,18 @@ const helpers_2 = require("../../helpers");
16
16
  const utils_1 = require("../../../../utils");
17
17
  const logger_1 = require("../../../../utils/logger");
18
18
  const errors_1 = require("../../../../utils/errors");
19
+ /**
20
+ * DashScope content-safety rejections ("Green" is Alibaba's moderation
21
+ * service). Seen as code DataInspectionFailed / message "Green net check
22
+ * rejected text (input)" or "…may contain inappropriate content" — on submit
23
+ * (HTTP 400 body) and on poll (task FAILED). The user's prompt/image, not a
24
+ * system fault: surface as CONTENT_POLICY_VIOLATION so it doesn't page.
25
+ */
26
+ function isDashScopeModeration(code, message) {
27
+ if (code && /DataInspection|IPInfringement|InappropriateContent/i.test(code))
28
+ return true;
29
+ return !!message && /green net|data inspection|inappropriate content/i.test(message);
30
+ }
19
31
  // Endpoint topology (verified 2026-06-06 against intl docs + live probes):
20
32
  //
21
33
  // T2V + I2V → /services/aigc/video-generation/video-synthesis (async; X-DashScope-Async: enable)
@@ -339,6 +351,9 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
339
351
  // stored job errorMessage.
340
352
  const axiosErr = err;
341
353
  const data = axiosErr.response?.data;
354
+ if (data && isDashScopeModeration(data.code, data.message)) {
355
+ throw new errors_1.UserFacingError((0, errors_1.friendlyMessageForCode)(errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION), errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION);
356
+ }
342
357
  if (data && (data.code || data.message)) {
343
358
  logger_1.logger.error("Alibaba DashScope request failed", {
344
359
  url,
@@ -547,6 +562,15 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
547
562
  }
548
563
  }
549
564
  if (status === "FAILED" || status === "failed") {
565
+ if (isDashScopeModeration(result.output?.code, result.output?.message)) {
566
+ return {
567
+ status: types_1.EVideoSceneStatus.FAILED,
568
+ errorMessage: JSON.stringify({
569
+ code: errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION,
570
+ message: (0, errors_1.friendlyMessageForCode)(errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION),
571
+ }),
572
+ };
573
+ }
550
574
  return {
551
575
  status: types_1.EVideoSceneStatus.FAILED,
552
576
  errorMessage: result.output?.message || "Video generation failed",
@@ -722,6 +746,9 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
722
746
  break;
723
747
  }
724
748
  if (status === "FAILED" || status === "failed") {
749
+ if (isDashScopeModeration(poll?.output?.code, poll?.output?.message)) {
750
+ throw new errors_1.UserFacingError((0, errors_1.friendlyMessageForCode)(errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION), errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION);
751
+ }
725
752
  throw new Error(`DashScope image task failed: ${poll?.output?.message ?? "unknown"}`);
726
753
  }
727
754
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bytedance.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/bytedance/bytedance.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AA8BlB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQlF;AAsBD,qBAAa,gBAAiB,SAAQ,wBAAwB;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CACsD;IAQ9E,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAIb,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA+Q3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkJjD;;;;;;;;;;;OAWG;IACG,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAyIlF,+EAA+E;YACjE,mBAAmB;IAoCjC;;;OAGG;YACW,eAAe;IAgD7B,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;CAsFjD"}
1
+ {"version":3,"file":"bytedance.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/bytedance/bytedance.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AA8BlB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQlF;AAsBD,qBAAa,gBAAiB,SAAQ,wBAAwB;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CACsD;IAQ9E,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAIb,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAyR3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkJjD;;;;;;;;;;;OAWG;IACG,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAyIlF,+EAA+E;YACjE,mBAAmB;IAoCjC;;;OAGG;YACW,eAAe;IAgD7B,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;CAsFjD"}
@@ -273,6 +273,12 @@ class ByteDanceService extends baseAiGenProvider_service_1.BaseAiGenProviderServ
273
273
  }
274
274
  throw new errors_1.UserFacingError(`Your input image is not valid: ${message}`, errors_1.USER_FACING_ERROR_CODES.INPUT_IMAGE_REJECTED);
275
275
  }
276
+ // Model not activated on our Ark account (prod 2026-10, 2.0 Mini).
277
+ // Operator action (activate in the Ark console) — PROVIDER_AUTH_ERROR
278
+ // still pages, but the user gets the canned message, not Ark internals.
279
+ if (code === "ModelNotOpen" || code?.startsWith("ModelNotOpen")) {
280
+ throw new errors_1.UserFacingError(`ByteDance model ${modelId} is not activated on the Ark account: ${message}`, errors_1.USER_FACING_ERROR_CODES.PROVIDER_AUTH_ERROR);
281
+ }
276
282
  throw new Error(`ByteDance generateVideo failed (${resp.status}): ${errText}`);
277
283
  }
278
284
  const data = await resp.json();
@@ -1 +1 @@
1
- {"version":3,"file":"googleMusic.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/google/googleMusic.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAExE;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CA+DhC"}
1
+ {"version":3,"file":"googleMusic.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/google/googleMusic.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAExE;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CA6EhC"}
@@ -19,13 +19,26 @@ const storage_1 = require("../../../../libs/storage");
19
19
  async function generateGoogleMusic(params) {
20
20
  const modelConfig = aiModels_1.aiModelConfigs[params.modelKey];
21
21
  const modelId = modelConfig?.modelId ?? "lyria-002";
22
- const projectId = process.env.GCP_PROJECT_ID;
22
+ // Prod never set GCP_PROJECT_ID, so every Lyria call threw before reaching
23
+ // Vertex. Fall back to the runtime project (Cloud Functions sets
24
+ // GCLOUD_PROJECT) and then the backend service account's own project.
25
+ const clientEmail = process.env.GOOGLE_CLIENT_EMAIL;
26
+ const privateKey = process.env.GOOGLE_PRIVATE_KEY;
27
+ const projectId = process.env.GCP_PROJECT_ID ||
28
+ process.env.GOOGLE_CLOUD_PROJECT ||
29
+ process.env.GCLOUD_PROJECT ||
30
+ clientEmail?.match(/@([^.]+)\.iam\.gserviceaccount\.com$/)?.[1];
23
31
  if (!projectId) {
24
32
  throw new Error("Missing GCP_PROJECT_ID env var (required for Vertex Lyria)");
25
33
  }
26
34
  const location = process.env.GCP_LOCATION ?? "us-central1";
35
+ // Railway has no ADC — use the backend service account from env when it's
36
+ // there (same creds GCPService uses); otherwise ADC (Cloud Functions SA).
27
37
  const auth = new google_auth_library_1.GoogleAuth({
28
38
  scopes: ["https://www.googleapis.com/auth/cloud-platform"],
39
+ ...(clientEmail && privateKey
40
+ ? { credentials: { client_email: clientEmail, private_key: privateKey.replace(/\\n/g, "\n") } }
41
+ : {}),
29
42
  });
30
43
  const client = await auth.getClient();
31
44
  const tokenRes = await client.getAccessToken();
@@ -5,7 +5,7 @@ export declare class RunwayService extends BaseAiGenProviderService {
5
5
  private readonly apiKey;
6
6
  constructor();
7
7
  private request;
8
- generateVideo(params: VideoGenerationParams): Promise<VideoGenerationResult>;
8
+ generateVideo(rawParams: VideoGenerationParams): Promise<VideoGenerationResult>;
9
9
  checkVideoStatus({ task, outputFilename, outputFilePath, }: VideoStatusParams): Promise<VideoStatusResult>;
10
10
  getCreditUsed({ modelKey, duration, multiClip, numImages, aspectRatio, creditFloor, resolution, audio, hasInputVideo, inputVideoDurationSec, numInputImages, numInputAudios, }: CreditUsageParams): number;
11
11
  /**
@@ -17,6 +17,6 @@ export declare class RunwayService extends BaseAiGenProviderService {
17
17
  * Runway requires concrete pixel ratios (`"1920:1080"` etc.) per the
18
18
  * Gen-4 Image spec.
19
19
  */
20
- generateImage(params: ImageGenerationParams): Promise<ImageGenerationResult>;
20
+ generateImage(rawParams: ImageGenerationParams): Promise<ImageGenerationResult>;
21
21
  }
22
22
  //# sourceMappingURL=runway.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runway.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/runway/runway.service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAWlB,qBAAa,aAAc,SAAQ,wBAAwB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;YAUlB,OAAO;IA8Cf,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAyJ3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAuDjD,aAAa,CAAC,EACZ,QAAQ,EACR,QAAY,EACZ,SAAiB,EACjB,SAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,EACL,aAAa,EACb,qBAAqB,EACrB,cAAkB,EAClB,cAAkB,GACnB,EAAE,iBAAiB,GAAG,MAAM;IAwD7B;;;;;;;;OAQG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;CA+ElC"}
1
+ {"version":3,"file":"runway.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/runway/runway.service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAiFlB,qBAAa,aAAc,SAAQ,wBAAwB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;YAUlB,OAAO;IA0Df,aAAa,CACjB,SAAS,EAAE,qBAAqB,GAC/B,OAAO,CAAC,qBAAqB,CAAC;IA0J3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAuDjD,aAAa,CAAC,EACZ,QAAQ,EACR,QAAY,EACZ,SAAiB,EACjB,SAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,EACL,aAAa,EACb,qBAAqB,EACrB,cAAkB,EAClB,cAAkB,GACnB,EAAE,iBAAiB,GAAG,MAAM;IAwD7B;;;;;;;;OAQG;IACG,aAAa,CACjB,SAAS,EAAE,qBAAqB,GAC/B,OAAO,CAAC,qBAAqB,CAAC;CAgFlC"}
@@ -16,6 +16,73 @@ const types_2 = require("./types");
16
16
  const errors_1 = require("../../../../utils/errors");
17
17
  const cameraAdapter_1 = require("./cameraAdapter");
18
18
  const hostedModels_1 = require("./hostedModels");
19
+ // Runway only fetches assets served with an image Content-Type. Some of our
20
+ // own objects are served as application/octet-stream (a missing type at
21
+ // upload time), and Runway 400s on them (prod 2026-10-10, grok-imagine-1.5).
22
+ const RUNWAY_IMAGE_TYPES = new Set(["image/jpeg", "image/png", "image/webp"]);
23
+ function sniffImageType(buf) {
24
+ if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff)
25
+ return "image/jpeg";
26
+ if (buf.length >= 8 && buf.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
27
+ return "image/png";
28
+ }
29
+ if (buf.length >= 12 && buf.toString("ascii", 0, 4) === "RIFF" && buf.toString("ascii", 8, 12) === "WEBP") {
30
+ return "image/webp";
31
+ }
32
+ return null;
33
+ }
34
+ /**
35
+ * Return `uri` unchanged when Runway will accept it; otherwise re-host the
36
+ * bytes under the sniffed image type and return the new URL. Best-effort: on
37
+ * any probe failure the original URI is passed through, so Runway's own error
38
+ * (not ours) is what surfaces.
39
+ */
40
+ async function ensureRunwayImageUri(uri) {
41
+ if (uri.startsWith("data:"))
42
+ return uri;
43
+ try {
44
+ const head = await axios_1.default.get(uri, {
45
+ responseType: "arraybuffer",
46
+ headers: { Range: "bytes=0-0" },
47
+ timeout: 15000,
48
+ validateStatus: () => true,
49
+ });
50
+ const served = String(head.headers["content-type"] ?? "").split(";")[0].trim().toLowerCase();
51
+ if (RUNWAY_IMAGE_TYPES.has(served))
52
+ return uri;
53
+ const full = await axios_1.default.get(uri, { responseType: "arraybuffer", timeout: 60000 });
54
+ const buf = Buffer.from(full.data);
55
+ const sniffed = sniffImageType(buf);
56
+ if (!sniffed) {
57
+ logger_1.logger.warn("Runway input image has an unsupported type; passing through", { served, uri: uri.slice(0, 160) });
58
+ return uri;
59
+ }
60
+ const ext = sniffed.split("/")[1];
61
+ const path = `images/runway-inputs/${Date.now()}-${Math.random().toString(36).slice(2, 8)}.${ext}`;
62
+ const rehosted = await storage_1.mediaStorage.put(path, buf, sniffed);
63
+ logger_1.logger.info("Runway input image re-hosted with a proper Content-Type", { served, sniffed, path });
64
+ return rehosted;
65
+ }
66
+ catch (err) {
67
+ logger_1.logger.warn("Runway input image probe failed; passing through", {
68
+ uri: uri.slice(0, 160),
69
+ err: err instanceof Error ? err.message : String(err),
70
+ });
71
+ return uri;
72
+ }
73
+ }
74
+ async function withRunwayImageUris(params) {
75
+ const out = { ...params };
76
+ await Promise.all([
77
+ out.inputImageUrl && ensureRunwayImageUri(out.inputImageUrl).then((u) => { out.inputImageUrl = u; }),
78
+ out.lastFrameImageUrl && ensureRunwayImageUri(out.lastFrameImageUrl).then((u) => { out.lastFrameImageUrl = u; }),
79
+ out.referenceImageUrls &&
80
+ Promise.all(out.referenceImageUrls.map(ensureRunwayImageUri)).then((u) => { out.referenceImageUrls = u; }),
81
+ out.inputImageUrls &&
82
+ Promise.all(out.inputImageUrls.map(ensureRunwayImageUri)).then((u) => { out.inputImageUrls = u; }),
83
+ ]);
84
+ return out;
85
+ }
19
86
  class RunwayService extends baseAiGenProvider_service_1.BaseAiGenProviderService {
20
87
  constructor() {
21
88
  super();
@@ -49,12 +116,22 @@ class RunwayService extends baseAiGenProvider_service_1.BaseAiGenProviderService
49
116
  if (tooLong) {
50
117
  throw new errors_1.UserFacingError(`Your prompt is too long for this model${tooLong.maximum ? ` (max ${tooLong.maximum} characters)` : ""}. Please shorten it and try again.`, errors_1.USER_FACING_ERROR_CODES.PROMPT_TOO_LONG);
51
118
  }
119
+ // OUR Runway account is out of credits (prod 2026-10, 400 "You do not
120
+ // have enough credits to run this task."). Ops must top up — classify as
121
+ // ACCOUNT_QUOTA_EXCEEDED so it still pages (errorPaging excludes that
122
+ // code from the quiet set) but the user sees the canned "pick another
123
+ // model" message instead of raw provider text.
124
+ const errText = typeof response.data?.error === "string" ? response.data.error : "";
125
+ if (/not have enough credits|insufficient credits/i.test(errText)) {
126
+ throw new errors_1.UserFacingError("This video model is temporarily unavailable. You haven't been charged — please pick a different model or retry shortly.", errors_1.USER_FACING_ERROR_CODES.ACCOUNT_QUOTA_EXCEEDED);
127
+ }
52
128
  throw new Error(`Runway API Error: ${response.status} ${response.statusText} - ${JSON.stringify(response.data)}`);
53
129
  }
54
130
  return response.data;
55
131
  }
56
- async generateVideo(params) {
57
- (0, helpers_2.validateParams)(params);
132
+ async generateVideo(rawParams) {
133
+ (0, helpers_2.validateParams)(rawParams);
134
+ const params = await withRunwayImageUris(rawParams);
58
135
  const modelId = aiModels_1.aiModelConfigs[params.modelKey]?.modelId;
59
136
  if (!modelId)
60
137
  throw new Error(`Unknown modelKey: ${params.modelKey}`);
@@ -298,7 +375,8 @@ class RunwayService extends baseAiGenProvider_service_1.BaseAiGenProviderService
298
375
  * Runway requires concrete pixel ratios (`"1920:1080"` etc.) per the
299
376
  * Gen-4 Image spec.
300
377
  */
301
- async generateImage(params) {
378
+ async generateImage(rawParams) {
379
+ const params = await withRunwayImageUris(rawParams);
302
380
  const modelConfig = aiModels_1.aiModelConfigs[params.modelKey];
303
381
  const modelId = modelConfig?.modelId;
304
382
  if (!modelId)
@@ -1,5 +1,8 @@
1
1
  import { Job } from "bullmq";
2
2
  import { RedisOptions } from "ioredis";
3
+ export declare class EnqueueTimeoutError extends Error {
4
+ constructor();
5
+ }
3
6
  export type JobData = Record<string, any>;
4
7
  interface BullMQServiceOptions {
5
8
  redisOptions: RedisOptions;
@@ -89,6 +92,14 @@ declare class BullMQService {
89
92
  count?: number;
90
93
  };
91
94
  }): Promise<void>;
95
+ /**
96
+ * After an enqueue timeout, drop the (likely half-open) shared connection so
97
+ * the next call dials a fresh one — and so the stalled command is rejected
98
+ * rather than flushed late. Only in producer-only processes: a worker host
99
+ * shares this connection with its Workers, so tearing it down there would
100
+ * kill job processing; there we just surface the timeout.
101
+ */
102
+ private resetProducerConnection;
92
103
  /** Get (or lazily create) the Queue handle for a name, reusing the cache. */
93
104
  private getQueue;
94
105
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"bullmq.service.d.ts","sourceRoot":"","sources":["../../src/services/bullmq.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bullmq.service.d.ts","sourceRoot":"","sources":["../../src/services/bullmq.service.ts"],"names":[],"mappings":"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"}
@@ -3,11 +3,39 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.bullmq = void 0;
6
+ exports.bullmq = exports.EnqueueTimeoutError = void 0;
7
7
  // libs/bullmqService.ts
8
8
  const bullmq_1 = require("bullmq");
9
9
  const ioredis_1 = __importDefault(require("ioredis"));
10
10
  const logger_1 = require("../utils/logger");
11
+ const errors_1 = require("../utils/errors");
12
+ /** Upper bound for a single enqueue (init + add) before we give up. */
13
+ const ENQUEUE_TIMEOUT_MS = 20000;
14
+ class EnqueueTimeoutError extends Error {
15
+ constructor() {
16
+ super(`Job enqueue timed out after ${ENQUEUE_TIMEOUT_MS}ms`);
17
+ this.name = "EnqueueTimeoutError";
18
+ }
19
+ }
20
+ exports.EnqueueTimeoutError = EnqueueTimeoutError;
21
+ async function withEnqueueTimeout(work, onTimeout) {
22
+ let timer;
23
+ const timeout = new Promise((_, reject) => {
24
+ timer = setTimeout(() => {
25
+ onTimeout();
26
+ reject(new EnqueueTimeoutError());
27
+ }, ENQUEUE_TIMEOUT_MS);
28
+ });
29
+ // A late rejection of `work` after the timeout won (e.g. "Connection is
30
+ // closed" from the reset) must not surface as an unhandled rejection.
31
+ work.catch(() => undefined);
32
+ try {
33
+ return await Promise.race([work, timeout]);
34
+ }
35
+ finally {
36
+ clearTimeout(timer);
37
+ }
38
+ }
11
39
  const redisOptions_1 = require("./redisOptions");
12
40
  // Transient ioredis socket errors that BullMQ's worker `error` event surfaces
13
41
  // verbatim. ioredis reconnects from these on its own — they're noise, not
@@ -121,23 +149,48 @@ class BullMQService {
121
149
  logger_1.logger.info("[BullMQ] enqueue skipped (dev): set ENABLE_QUEUE=true to enqueue", { queueName, jobId: opts?.jobId });
122
150
  return;
123
151
  }
124
- if (!this.initialized)
125
- await this.init();
126
- const queue = this.queues.get(queueName) ??
127
- new bullmq_1.Queue(queueName, { connection: this.getConnection() });
128
- this.queues.set(queueName, queue);
129
- await queue.add(opts?.jobId || "default", data, {
130
- delay: opts?.delay,
131
- attempts: opts?.attempts,
132
- backoff: opts?.backoff,
133
- // Auto-evict finished jobs so their hashes don't accumulate forever.
134
- // Without this BullMQ keeps every completed/failed job hash with no TTL
135
- // (this is what filled prod Redis to ~75% of 30MB / 41k orphan keys).
136
- // Completed: keep 1 day or last 1000. Failed: keep longer (7 days /
137
- // last 5000) since failures are worth inspecting.
138
- removeOnComplete: opts?.removeOnComplete ?? { age: 24 * 3600, count: 1000 },
139
- removeOnFail: opts?.removeOnFail ?? { age: 7 * 24 * 3600, count: 5000 },
152
+ // Bounded enqueue. sharedRedisOptions (maxRetriesPerRequest: null +
153
+ // offline queue) lets a command wait FOREVER on a dead/half-open socket —
154
+ // prod 2026-10 saw bullmq.addJob(VIDEO_JOBS) take 86 min inside a
155
+ // Functions request (user charged, video stuck QUEUED). Fail fast instead
156
+ // so the caller can refund and tell the user to retry.
157
+ await withEnqueueTimeout((async () => {
158
+ if (!this.initialized)
159
+ await this.init();
160
+ await this.getQueue(queueName).add(opts?.jobId || "default", data, {
161
+ delay: opts?.delay,
162
+ attempts: opts?.attempts,
163
+ backoff: opts?.backoff,
164
+ // Auto-evict finished jobs so their hashes don't accumulate forever.
165
+ // Without this BullMQ keeps every completed/failed job hash with no TTL
166
+ // (this is what filled prod Redis to ~75% of 30MB / 41k orphan keys).
167
+ // Completed: keep 1 day or last 1000. Failed: keep longer (7 days /
168
+ // last 5000) since failures are worth inspecting.
169
+ removeOnComplete: opts?.removeOnComplete ?? { age: 24 * 3600, count: 1000 },
170
+ removeOnFail: opts?.removeOnFail ?? { age: 7 * 24 * 3600, count: 5000 },
171
+ });
172
+ })(), () => this.resetProducerConnection(queueName));
173
+ }
174
+ /**
175
+ * After an enqueue timeout, drop the (likely half-open) shared connection so
176
+ * the next call dials a fresh one — and so the stalled command is rejected
177
+ * rather than flushed late. Only in producer-only processes: a worker host
178
+ * shares this connection with its Workers, so tearing it down there would
179
+ * kill job processing; there we just surface the timeout.
180
+ */
181
+ resetProducerConnection(queueName) {
182
+ logger_1.logger.error("[BullMQ] enqueue timed out", {
183
+ queueName,
184
+ timeoutMs: ENQUEUE_TIMEOUT_MS,
185
+ producerOnly: this.workers.length === 0,
140
186
  });
187
+ if (this.workers.length > 0 || !this.connection)
188
+ return;
189
+ const stale = this.connection;
190
+ this.connection = undefined;
191
+ this.queues.clear();
192
+ this.initialized = false;
193
+ stale.disconnect();
141
194
  }
142
195
  /** Get (or lazily create) the Queue handle for a name, reusing the cache. */
143
196
  getQueue(queueName) {
@@ -239,13 +292,21 @@ class BullMQService {
239
292
  // Slack via the winston error transport so a stuck provider or a
240
293
  // bad payload always surfaces. Stack tail truncated to keep Slack
241
294
  // payloads under their block-size limits.
295
+ // A UserFacingError (render not ready, prompt rejected, …) is an
296
+ // expected outcome the user already sees — warn, don't page. Operator
297
+ // codes (bad key / account out of credit) still page.
242
298
  worker.on("failed", (job, err) => {
243
- logger_1.logger.error(`BullMQ job failed`, {
299
+ // A non-final attempt will be retried by BullMQ — only the final
300
+ // failure is worth paging on.
301
+ const willRetry = !!job && job.attemptsMade < (job.opts?.attempts ?? 1);
302
+ const logFn = willRetry || (0, errors_1.isQuietUserFacingError)(err) ? logger_1.logger.warn.bind(logger_1.logger) : logger_1.logger.error.bind(logger_1.logger);
303
+ logFn(`BullMQ job failed`, {
244
304
  queueName,
245
305
  jobId: job?.id,
246
306
  jobName: job?.name,
247
307
  userId: job?.data?.userId,
248
308
  attemptsMade: job?.attemptsMade,
309
+ willRetry,
249
310
  failedReason: job?.failedReason,
250
311
  err: err?.stack ?? err?.message ?? String(err),
251
312
  });
@@ -1,3 +1,3 @@
1
1
  export { translationService } from "./translation.service";
2
- export { LANGUAGE_DISPLAY_NAMES, buildOutputLanguageSection, isEnglish, languageDisplayName, normalizeLanguageTag, resolveOutputLanguage, } from "./outputLanguage";
2
+ export { LANGUAGE_DISPLAY_NAMES, buildOutputLanguageSection, isEnglish, languageDisplayName, normalizeLanguageTag, resolveOutputLanguage, settleCloseLanguage, } from "./outputLanguage";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/translation/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,SAAS,EACT,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/translation/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,SAAS,EACT,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveOutputLanguage = exports.normalizeLanguageTag = exports.languageDisplayName = exports.isEnglish = exports.buildOutputLanguageSection = exports.LANGUAGE_DISPLAY_NAMES = exports.translationService = void 0;
3
+ exports.settleCloseLanguage = exports.resolveOutputLanguage = exports.normalizeLanguageTag = exports.languageDisplayName = exports.isEnglish = exports.buildOutputLanguageSection = exports.LANGUAGE_DISPLAY_NAMES = exports.translationService = void 0;
4
4
  // Only the new API is exported from the services barrel. The legacy aliases
5
5
  // (getTranslationWrapper / detectLang / TRANSLATION_FAILED) are re-exported via
6
6
  // utils/helpers instead, so each name reaches the package root through exactly
@@ -14,3 +14,4 @@ Object.defineProperty(exports, "isEnglish", { enumerable: true, get: function ()
14
14
  Object.defineProperty(exports, "languageDisplayName", { enumerable: true, get: function () { return outputLanguage_1.languageDisplayName; } });
15
15
  Object.defineProperty(exports, "normalizeLanguageTag", { enumerable: true, get: function () { return outputLanguage_1.normalizeLanguageTag; } });
16
16
  Object.defineProperty(exports, "resolveOutputLanguage", { enumerable: true, get: function () { return outputLanguage_1.resolveOutputLanguage; } });
17
+ Object.defineProperty(exports, "settleCloseLanguage", { enumerable: true, get: function () { return outputLanguage_1.settleCloseLanguage; } });
@@ -48,6 +48,15 @@ export declare function normalizeLanguageTag(locale?: string): string | undefine
48
48
  export declare function languageDisplayName(code: string): string;
49
49
  /** True when `code` resolves to English (or is absent). */
50
50
  export declare function isEnglish(code?: string): boolean;
51
+ /**
52
+ * Settle a detector verdict that falls in a CLOSE_LANGUAGE_GROUPS cluster.
53
+ * Exported for callers that run the detector themselves, such as
54
+ * /v1/video/generate, which uses the result to pick the spoken language.
55
+ * The UI locale wins when it's in the same cluster (an Indonesian UI plus
56
+ * "Malay" text is Indonesian). Otherwise a constrained LLM pick decides, and
57
+ * the detector's verdict stands if that fails.
58
+ */
59
+ export declare function settleCloseLanguage(text: string, detected: string, uiTag: string | undefined): Promise<string>;
51
60
  /**
52
61
  * Decide the output language for a piece of work. See the resolution order in
53
62
  * the module docblock.
@@ -1 +1 @@
1
- {"version":3,"file":"outputLanguage.d.ts","sourceRoot":"","sources":["../../../src/services/translation/outputLanguage.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAwCzD,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOxE;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAGhD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,KAAK,EAAE,MAAM,GACZ,MAAM,CAeR"}
1
+ {"version":3,"file":"outputLanguage.d.ts","sourceRoot":"","sources":["../../../src/services/translation/outputLanguage.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0CzD,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOxE;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAGhD;AAoBD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmClB;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,KAAK,EAAE,MAAM,GACZ,MAAM,CAeR"}
@@ -4,6 +4,7 @@ exports.LANGUAGE_DISPLAY_NAMES = void 0;
4
4
  exports.normalizeLanguageTag = normalizeLanguageTag;
5
5
  exports.languageDisplayName = languageDisplayName;
6
6
  exports.isEnglish = isEnglish;
7
+ exports.settleCloseLanguage = settleCloseLanguage;
7
8
  exports.resolveOutputLanguage = resolveOutputLanguage;
8
9
  exports.buildOutputLanguageSection = buildOutputLanguageSection;
9
10
  const types_1 = require("../../globals/types");
@@ -76,6 +77,8 @@ exports.LANGUAGE_DISPLAY_NAMES = {
76
77
  ro: "Romanian",
77
78
  ru: "Russian",
78
79
  sk: "Slovak",
80
+ sr: "Serbian",
81
+ bs: "Bosnian",
79
82
  sv: "Swedish",
80
83
  th: "Thai",
81
84
  tl: "Filipino",
@@ -117,6 +120,55 @@ function isEnglish(code) {
117
120
  const tag = normalizeLanguageTag(code);
118
121
  return !tag || tag === types_1.ELANGUAGE_CODE.en;
119
122
  }
123
+ /**
124
+ * Language pairs the primary detector can't reliably tell apart. Its verdicts
125
+ * here come back `reliable: true` regardless, so the confidence flag doesn't
126
+ * help. A user who writes Indonesian and gets a Malay-narrated video reads it
127
+ * as the product ignoring them (prod complaint 2026-10-10). `hint` lists
128
+ * telltale words so the LLM tie-break has something concrete to go on.
129
+ */
130
+ const CLOSE_LANGUAGE_GROUPS = [
131
+ {
132
+ codes: ["id", "ms"],
133
+ hint: "Indonesian: tidak/nggak/banget/kalau/bisa/uang/sekolah dasar; " +
134
+ "Malay: tak/nak/sangat/boleh/duit/kanak-kanak/kedai/pasal",
135
+ },
136
+ { codes: ["hr", "sr", "bs"] },
137
+ { codes: ["no", "da"] },
138
+ ];
139
+ /**
140
+ * Settle a detector verdict that falls in a CLOSE_LANGUAGE_GROUPS cluster.
141
+ * Exported for callers that run the detector themselves, such as
142
+ * /v1/video/generate, which uses the result to pick the spoken language.
143
+ * The UI locale wins when it's in the same cluster (an Indonesian UI plus
144
+ * "Malay" text is Indonesian). Otherwise a constrained LLM pick decides, and
145
+ * the detector's verdict stands if that fails.
146
+ */
147
+ async function settleCloseLanguage(text, detected, uiTag) {
148
+ const group = CLOSE_LANGUAGE_GROUPS.find((g) => g.codes.includes(detected));
149
+ if (!group)
150
+ return detected;
151
+ if (uiTag && group.codes.includes(uiTag))
152
+ return uiTag;
153
+ try {
154
+ const picked = await translation_service_1.translationService.pickCloseLanguage(text, group.codes.map((code) => ({ code, name: languageDisplayName(code) })), group.hint);
155
+ if (picked !== detected) {
156
+ logger_1.logger.info("outputLanguage: close-language tie-break overrode detector", {
157
+ detected,
158
+ picked,
159
+ uiLocale: uiTag,
160
+ });
161
+ }
162
+ return picked;
163
+ }
164
+ catch (err) {
165
+ logger_1.logger.warn("outputLanguage: close-language tie-break failed, keeping detector verdict", {
166
+ detected,
167
+ err: err instanceof Error ? err.message : String(err),
168
+ });
169
+ return detected;
170
+ }
171
+ }
120
172
  /**
121
173
  * Decide the output language for a piece of work. See the resolution order in
122
174
  * the module docblock.
@@ -147,7 +199,7 @@ async function resolveOutputLanguage(params) {
147
199
  if (detected.reliable && top?.code) {
148
200
  const tag = normalizeLanguageTag(top.code);
149
201
  if (tag)
150
- return tag;
202
+ return await settleCloseLanguage(text, tag, uiTag);
151
203
  }
152
204
  logger_1.logger.info("outputLanguage: detection unreliable, using UI locale", {
153
205
  uiLocale: uiTag,
@@ -57,9 +57,25 @@ declare function translate(text: string, from: ELANGUAGE_CODE, to?: ELANGUAGE_CO
57
57
  * instead of treating the guess as fact.
58
58
  */
59
59
  declare function detectLanguage(text: string): Promise<IDetectLang>;
60
+ /**
61
+ * Choose between closely related languages the primary detector confuses.
62
+ *
63
+ * The primary detector is n-gram based and reliably mislabels casual
64
+ * Indonesian as Malay (measured 2026-10-10: "buat video tentang tips merawat
65
+ * kulit wajah untuk remaja" → ms/98%/reliable:true), and it still marks those
66
+ * verdicts reliable, so the flag can't catch it. An LLM limited to the
67
+ * candidate set separates the pair correctly. Same timeout/retry treatment
68
+ * as callLlmDetect; throws when both attempts fail so the caller can keep
69
+ * the detector's verdict.
70
+ */
71
+ declare function pickCloseLanguage(text: string, candidates: {
72
+ code: string;
73
+ name: string;
74
+ }[], hint?: string): Promise<string>;
60
75
  export declare const translationService: {
61
76
  translate: typeof translate;
62
77
  detectLanguage: typeof detectLanguage;
78
+ pickCloseLanguage: typeof pickCloseLanguage;
63
79
  };
64
80
  /** @deprecated use `translationService.translate` */
65
81
  export declare const getTranslationWrapper: typeof translate;
@@ -1 +1 @@
1
- {"version":3,"file":"translation.service.d.ts","sourceRoot":"","sources":["../../../src/services/translation/translation.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAiDvD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAkB,GAAG,MAAM,EAAE,CA8BjF;AA4ID;;;;;;GAMG;AACH,iBAAe,SAAS,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,EACpB,EAAE,GAAE,cAAkC,EACtC,OAAO,GAAE,IAAI,GAAG,IAAW,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AA+ID;;;;;;;;;;;;;;GAcG;AACH,iBAAe,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8ChE;AAOD,eAAO,MAAM,kBAAkB;;;CAG9B,CAAC;AAGF,qDAAqD;AACrD,eAAO,MAAM,qBAAqB,kBAAY,CAAC;AAC/C,0DAA0D;AAC1D,eAAO,MAAM,UAAU,uBAAiB,CAAC"}
1
+ {"version":3,"file":"translation.service.d.ts","sourceRoot":"","sources":["../../../src/services/translation/translation.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAiDvD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAkB,GAAG,MAAM,EAAE,CA8BjF;AA4ID;;;;;;GAMG;AACH,iBAAe,SAAS,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,EACpB,EAAE,GAAE,cAAkC,EACtC,OAAO,GAAE,IAAI,GAAG,IAAW,GAC1B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AA+ID;;;;;;;;;;;;;;GAcG;AACH,iBAAe,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8ChE;AA8BD;;;;;;;;;;GAUG;AACH,iBAAe,iBAAiB,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EAC5C,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAejB;AAOD,eAAO,MAAM,kBAAkB;;;;CAI9B,CAAC;AAGF,qDAAqD;AACrD,eAAO,MAAM,qBAAqB,kBAAY,CAAC;AAC/C,0DAA0D;AAC1D,eAAO,MAAM,UAAU,uBAAiB,CAAC"}
@@ -462,6 +462,52 @@ async function detectLanguage(text) {
462
462
  };
463
463
  }
464
464
  }
465
+ /** One un-retried constrained-choice LLM attempt (see pickCloseLanguage). */
466
+ async function callLlmPickOnce(text, candidates, hint) {
467
+ const service = await loadFallbackService();
468
+ const options = candidates.map((c) => `${c.code} (${c.name})`).join(", ");
469
+ const system = `Identify which of these closely related languages the user's text is ` +
470
+ `written in: ${options}. Decide from vocabulary, spelling and slang` +
471
+ (hint ? ` (${hint})` : "") +
472
+ `. Reply with ONLY the code, nothing else.`;
473
+ const { text: out } = await service.generateText({
474
+ input: [
475
+ { role: "system", content: system },
476
+ { role: "user", content: text.slice(0, 1000) },
477
+ ],
478
+ modelKey: FALLBACK_MODEL,
479
+ options: { temperature: 0 },
480
+ });
481
+ const code = (out ?? "").trim().toLowerCase().replace(/[^a-z-]/g, "");
482
+ if (!candidates.some((c) => c.code === code)) {
483
+ throw new Error(`LLM language pick returned an off-list reply: "${out}"`);
484
+ }
485
+ return code;
486
+ }
487
+ /**
488
+ * Choose between closely related languages the primary detector confuses.
489
+ *
490
+ * The primary detector is n-gram based and reliably mislabels casual
491
+ * Indonesian as Malay (measured 2026-10-10: "buat video tentang tips merawat
492
+ * kulit wajah untuk remaja" → ms/98%/reliable:true), and it still marks those
493
+ * verdicts reliable, so the flag can't catch it. An LLM limited to the
494
+ * candidate set separates the pair correctly. Same timeout/retry treatment
495
+ * as callLlmDetect; throws when both attempts fail so the caller can keep
496
+ * the detector's verdict.
497
+ */
498
+ async function pickCloseLanguage(text, candidates, hint) {
499
+ await loadFallbackService(); // outside the timer — see loadFallbackService
500
+ let lastErr;
501
+ for (let attempt = 1; attempt <= FALLBACK_MAX_ATTEMPTS; attempt++) {
502
+ try {
503
+ return await withTimeout(callLlmPickOnce(text, candidates, hint), FALLBACK_ATTEMPT_TIMEOUT_MS, "LLM language pick");
504
+ }
505
+ catch (err) {
506
+ lastErr = err;
507
+ }
508
+ }
509
+ throw lastErr;
510
+ }
465
511
  function errMsg(err) {
466
512
  if (err instanceof Error)
467
513
  return err.stack ?? err.message;
@@ -470,6 +516,7 @@ function errMsg(err) {
470
516
  exports.translationService = {
471
517
  translate,
472
518
  detectLanguage,
519
+ pickCloseLanguage,
473
520
  };
474
521
  // ── Legacy aliases (kept so existing callsites need no change) ──────────────
475
522
  /** @deprecated use `translationService.translate` */
@@ -51,6 +51,13 @@ export type UserFacingErrorCode = keyof typeof USER_FACING_ERROR_CODES;
51
51
  * the provider's, matching the credit-refund behaviour on failed jobs.
52
52
  */
53
53
  export declare const USER_FACING_ERROR_MESSAGES: Record<string, string>;
54
+ /**
55
+ * True for an expected, user-facing failure that should log at warn (Loki)
56
+ * rather than error (Slack): any UserFacingError except the operator-action
57
+ * codes. Duck-typed on `isUserFacingError` so it survives errors crossing a
58
+ * package-copy boundary (functions' npm shared vs the worker's workspace one).
59
+ */
60
+ export declare function isQuietUserFacingError(err: unknown): boolean;
54
61
  /** Friendly default for a code, or undefined if the code is unknown/unset. */
55
62
  export declare function friendlyMessageForCode(code: string | undefined): string | undefined;
56
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,iBAAiB,QAAQ;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAM1C,qEAAqE;IACrE,MAAM,IAAI;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAG7C;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;IAUlC,wFAAwF;;IAExF,qFAAqF;;IAErF,+FAA+F;;IAE/F,oGAAoG;;IAEpG,gGAAgG;;CAExF,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,uBAAuB,CAAC;AAEvE;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6B7D,CAAC;AAEF,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnF;AAqBD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAaR"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,iBAAiB,QAAQ;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAM1C,qEAAqE;IACrE,MAAM,IAAI;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAG7C;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;IAUlC,wFAAwF;;IAExF,qFAAqF;;IAErF,+FAA+F;;IAE/F,oGAAoG;;IAEpG,gGAAgG;;CAExF,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,uBAAuB,CAAC;AAEvE;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6B7D,CAAC;AAWF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAK5D;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnF;AAqBD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAaR"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.USER_FACING_ERROR_MESSAGES = exports.USER_FACING_ERROR_CODES = exports.UserFacingError = void 0;
4
+ exports.isQuietUserFacingError = isQuietUserFacingError;
4
5
  exports.friendlyMessageForCode = friendlyMessageForCode;
5
6
  exports.sanitizeUserFacingMessage = sanitizeUserFacingMessage;
6
7
  /**
@@ -73,6 +74,28 @@ exports.USER_FACING_ERROR_MESSAGES = {
73
74
  [exports.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH]: "This combination of settings isn't supported by the selected model. Please adjust your options and try again.",
74
75
  [exports.USER_FACING_ERROR_CODES.SCENES_NOT_READY]: "This video isn't fully generated yet — one or more scenes are still processing. Please wait for generation to finish and try rendering again.",
75
76
  };
77
+ /**
78
+ * UserFacingError codes an operator must act on (bad key, account out of
79
+ * credit). These still page even though the user sees a friendly message.
80
+ */
81
+ const OPERATOR_ACTION_CODES = new Set([
82
+ exports.USER_FACING_ERROR_CODES.PROVIDER_AUTH_ERROR,
83
+ exports.USER_FACING_ERROR_CODES.ACCOUNT_QUOTA_EXCEEDED,
84
+ ]);
85
+ /**
86
+ * True for an expected, user-facing failure that should log at warn (Loki)
87
+ * rather than error (Slack): any UserFacingError except the operator-action
88
+ * codes. Duck-typed on `isUserFacingError` so it survives errors crossing a
89
+ * package-copy boundary (functions' npm shared vs the worker's workspace one).
90
+ */
91
+ function isQuietUserFacingError(err) {
92
+ if (!err || typeof err !== "object")
93
+ return false;
94
+ const e = err;
95
+ if (e.isUserFacingError !== true)
96
+ return false;
97
+ return !(typeof e.code === "string" && OPERATOR_ACTION_CODES.has(e.code));
98
+ }
76
99
  /** Friendly default for a code, or undefined if the code is unknown/unset. */
77
100
  function friendlyMessageForCode(code) {
78
101
  return code ? exports.USER_FACING_ERROR_MESSAGES[code] : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vidspotai-shared",
3
- "version": "1.0.130",
3
+ "version": "1.0.131",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "exports": {