vidspotai-shared 1.0.81 → 1.0.82

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 (44) hide show
  1. package/lib/globals/aiModels/providers/google.d.ts.map +1 -1
  2. package/lib/globals/aiModels/providers/google.js +39 -7
  3. package/lib/schemas/project.schema.d.ts +3 -3
  4. package/lib/schemas/videoPlan.schema.d.ts +3 -3
  5. package/lib/services/agent/editClassifier.d.ts +2 -2
  6. package/lib/services/agent/eval/recorder.d.ts +13 -1
  7. package/lib/services/agent/eval/recorder.d.ts.map +1 -1
  8. package/lib/services/agent/eval/recorder.js +59 -0
  9. package/lib/services/agent/tools/composeScene.tool.d.ts +2 -2
  10. package/lib/services/agent/tools/estimateCost.tool.d.ts +1 -1
  11. package/lib/services/agent/tools/planVideo.tool.d.ts +1 -1
  12. package/lib/services/agent/tools/render.tool.d.ts +1 -1
  13. package/lib/services/aiGen/helpers.d.ts +8 -0
  14. package/lib/services/aiGen/helpers.d.ts.map +1 -1
  15. package/lib/services/aiGen/helpers.js +12 -0
  16. package/lib/services/aiGen/providers/google/google.service.d.ts +1 -0
  17. package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
  18. package/lib/services/aiGen/providers/google/google.service.js +100 -8
  19. package/lib/services/aiGen/providers/google/googleApiKeys.d.ts +71 -0
  20. package/lib/services/aiGen/providers/google/googleApiKeys.d.ts.map +1 -0
  21. package/lib/services/aiGen/providers/google/googleApiKeys.js +137 -0
  22. package/lib/services/aiGen/providers/google/googleKeyPool.d.ts +52 -0
  23. package/lib/services/aiGen/providers/google/googleKeyPool.d.ts.map +1 -0
  24. package/lib/services/aiGen/providers/google/googleKeyPool.js +129 -0
  25. package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
  26. package/lib/services/aiGen/providers/pixverse/pixverse.service.js +7 -1
  27. package/lib/services/bullmq.service.d.ts.map +1 -1
  28. package/lib/services/bullmq.service.js +23 -1
  29. package/lib/services/index.d.ts +1 -0
  30. package/lib/services/index.d.ts.map +1 -1
  31. package/lib/services/index.js +1 -0
  32. package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts +60 -5
  33. package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts.map +1 -1
  34. package/lib/services/rateLimiter/distributedRateLimiter.service.js +184 -16
  35. package/lib/services/translation/index.d.ts +2 -0
  36. package/lib/services/translation/index.d.ts.map +1 -0
  37. package/lib/services/translation/index.js +9 -0
  38. package/lib/services/translation/translation.service.d.ts +50 -0
  39. package/lib/services/translation/translation.service.d.ts.map +1 -0
  40. package/lib/services/translation/translation.service.js +211 -0
  41. package/lib/utils/helpers.d.ts +2 -4
  42. package/lib/utils/helpers.d.ts.map +1 -1
  43. package/lib/utils/helpers.js +9 -63
  44. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../../src/globals/aiModels/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,eAAO,MAAM,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAqSpE,CAAC"}
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../../src/globals/aiModels/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,eAAO,MAAM,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAqUpE,CAAC"}
@@ -23,7 +23,16 @@ exports.googleConfigs = {
23
23
  inputVideoUrl: {},
24
24
  negative_prompt: {},
25
25
  audio: {},
26
- seed: {},
26
+ // REMOVED — `seed` is Vertex-AI-only. On the Gemini Developer API the SDK
27
+ // throws "seed parameter is not supported in Gemini API" client-side.
28
+ // Kept for reference; restore only under a Vertex (vertexai:true) client.
29
+ // seed: {},
30
+ // NOTE (applies to all Veo 3.x): on the Gemini API only "allow_all" is
31
+ // actually honored — "allow_adult"/"dont_allow" are Veo-2 legacy and
32
+ // return 400 "<value> for personGeneration is currently not supported".
33
+ // allowedValues is kept as the union so validateParams doesn't hard-throw
34
+ // on a planner-emitted value; google.service.ts forwards ONLY allow_all
35
+ // and silently drops the rest (allow_all is the API default anyway).
27
36
  personGeneration: { allowedValues: ["allow_all", "allow_adult", "dont_allow"] },
28
37
  promptOptimizer: {},
29
38
  },
@@ -37,7 +46,18 @@ exports.googleConfigs = {
37
46
  6: ["720p"],
38
47
  8: ["720p", "1080p", "4k"],
39
48
  },
40
- requestPerMin: 50,
49
+ // SINGLE-KEY Tier-2 baseline (verified 2026-06-09 via
50
+ // aistudio.google.com/rate-limit): 4 req/min, ~50/day per Veo model on the
51
+ // shared `predict_long_running_requests_per_model` quota. The DAILY cap is
52
+ // enforced (requestPerDay) — the limiter's day-gate fast-fails
53
+ // (VIDEO_PROVIDER_RATE_LIMITED) rather than blocking for hours, so a
54
+ // daily-exhausted job silently spills to another model in the tier chain.
55
+ // NOTE: these are per-key Tier-2 numbers. The multi-key pool (googleKeyPool)
56
+ // scales the model-level limiter to the SUM across keys (each tier-scaled) —
57
+ // e.g. a Tier-1 + Tier-2 pool → 6/min, 60/day. See googleApiKeys.ts for the
58
+ // decision record.
59
+ requestPerMin: 4,
60
+ requestPerDay: 50,
41
61
  cost: {
42
62
  // Vertex: $0.40/s @ 720p/1080p, $0.60/s @ 4k.
43
63
  perResolution: { "720p": 0.40, "1080p": 0.40, "4k": 0.60 },
@@ -63,7 +83,9 @@ exports.googleConfigs = {
63
83
  inputVideoUrl: {},
64
84
  negative_prompt: {},
65
85
  audio: {},
66
- seed: {},
86
+ // REMOVED — `seed` is Vertex-AI-only; the Gemini API SDK throws
87
+ // "seed parameter is not supported in Gemini API" client-side. See veo-3.1.
88
+ // seed: {},
67
89
  personGeneration: { allowedValues: ["allow_all", "allow_adult", "dont_allow"] },
68
90
  promptOptimizer: {},
69
91
  },
@@ -73,7 +95,9 @@ exports.googleConfigs = {
73
95
  6: ["720p"],
74
96
  8: ["720p", "1080p"],
75
97
  },
76
- requestPerMin: 50,
98
+ // Tier 2 ceiling: 4 RPM / ~50 RPD per model (see veo-3.1 note above).
99
+ requestPerMin: 4,
100
+ requestPerDay: 50,
77
101
  cost: {
78
102
  perResolution: { "720p": 0.10, "1080p": 0.12 },
79
103
  },
@@ -95,9 +119,15 @@ exports.googleConfigs = {
95
119
  // lastFrameImageUrl: {},
96
120
  // Lite also does NOT support reference images or video extension per the
97
121
  // Gemini API spec — only 3.1 and 3.1-fast do.
98
- negative_prompt: {},
122
+ // REMOVED — veo-3.1-lite returns 400 "negativePrompt isn't supported by
123
+ // this model" (unlike veo-3.1 / veo-3.1-fast, which accept it). The request
124
+ // builder gates negativePrompt on this field being declared, so leaving it
125
+ // out is what stops the param from being forwarded. Kept for reference.
126
+ // negative_prompt: {},
99
127
  audio: {},
100
- seed: {},
128
+ // REMOVED — `seed` is Vertex-AI-only; the Gemini API SDK throws
129
+ // "seed parameter is not supported in Gemini API" client-side. See veo-3.1.
130
+ // seed: {},
101
131
  personGeneration: { allowedValues: ["allow_all", "allow_adult", "dont_allow"] },
102
132
  promptOptimizer: {},
103
133
  },
@@ -107,7 +137,9 @@ exports.googleConfigs = {
107
137
  6: ["720p"],
108
138
  8: ["720p", "1080p"],
109
139
  },
110
- requestPerMin: 50,
140
+ // Tier 2 ceiling: 4 RPM / ~50 RPD per model (see veo-3.1 note above).
141
+ requestPerMin: 4,
142
+ requestPerDay: 50,
111
143
  cost: {
112
144
  perResolution: { "720p": 0.05, "1080p": 0.08 },
113
145
  },
@@ -641,18 +641,18 @@ export declare const ClipSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
641
641
  metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
642
642
  }, z.core.$strip>], "type">;
643
643
  export declare const TrackKindSchema: z.ZodEnum<{
644
- text: "text";
645
644
  audio: "audio";
646
645
  video: "video";
646
+ text: "text";
647
647
  caption: "caption";
648
648
  fx: "fx";
649
649
  }>;
650
650
  export declare const TrackSchema: z.ZodObject<{
651
651
  id: z.ZodString;
652
652
  kind: z.ZodEnum<{
653
- text: "text";
654
653
  audio: "audio";
655
654
  video: "video";
655
+ text: "text";
656
656
  caption: "caption";
657
657
  fx: "fx";
658
658
  }>;
@@ -700,9 +700,9 @@ export declare const ProjectSchema: z.ZodObject<{
700
700
  tracks: z.ZodArray<z.ZodObject<{
701
701
  id: z.ZodString;
702
702
  kind: z.ZodEnum<{
703
- text: "text";
704
703
  audio: "audio";
705
704
  video: "video";
705
+ text: "text";
706
706
  caption: "caption";
707
707
  fx: "fx";
708
708
  }>;
@@ -167,8 +167,8 @@ export declare const TextOverlaySchema: z.ZodObject<{
167
167
  fontSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>>;
168
168
  sizePct: z.ZodOptional<z.ZodNumber>;
169
169
  weight: z.ZodOptional<z.ZodEnum<{
170
- bold: "bold";
171
170
  regular: "regular";
171
+ bold: "bold";
172
172
  black: "black";
173
173
  medium: "medium";
174
174
  }>>;
@@ -290,8 +290,8 @@ export declare const PlannedSceneSchema: z.ZodObject<{
290
290
  fontSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>>;
291
291
  sizePct: z.ZodOptional<z.ZodNumber>;
292
292
  weight: z.ZodOptional<z.ZodEnum<{
293
- bold: "bold";
294
293
  regular: "regular";
294
+ bold: "bold";
295
295
  black: "black";
296
296
  medium: "medium";
297
297
  }>>;
@@ -453,8 +453,8 @@ export declare const VideoPlanSchema: z.ZodObject<{
453
453
  fontSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>>;
454
454
  sizePct: z.ZodOptional<z.ZodNumber>;
455
455
  weight: z.ZodOptional<z.ZodEnum<{
456
- bold: "bold";
457
456
  regular: "regular";
457
+ bold: "bold";
458
458
  black: "black";
459
459
  medium: "medium";
460
460
  }>>;
@@ -69,8 +69,8 @@ export declare const TextEditSchema: z.ZodObject<{
69
69
  fontSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>>;
70
70
  sizePct: z.ZodOptional<z.ZodNumber>;
71
71
  weight: z.ZodOptional<z.ZodEnum<{
72
- bold: "bold";
73
72
  regular: "regular";
73
+ bold: "bold";
74
74
  black: "black";
75
75
  medium: "medium";
76
76
  }>>;
@@ -164,8 +164,8 @@ export declare const EditRequestSchema: z.ZodObject<{
164
164
  fontSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>>;
165
165
  sizePct: z.ZodOptional<z.ZodNumber>;
166
166
  weight: z.ZodOptional<z.ZodEnum<{
167
- bold: "bold";
168
167
  regular: "regular";
168
+ bold: "bold";
169
169
  black: "black";
170
170
  medium: "medium";
171
171
  }>>;
@@ -1,5 +1,5 @@
1
1
  import { ToolContext, ToolOutcome } from "../toolRegistry";
2
- import { AgentRunTrace } from "./types";
2
+ import { AgentRunTrace, ToolCallTrace } from "./types";
3
3
  export declare function setTracePersistence(fn: (trace: AgentRunTrace) => Promise<void>): void;
4
4
  export declare function startTrace(opts: {
5
5
  agentRunId: string;
@@ -8,6 +8,18 @@ export declare function startTrace(opts: {
8
8
  rngSeed: string;
9
9
  }): AgentRunTrace;
10
10
  export declare function getTrace(agentRunId: string): AgentRunTrace | undefined;
11
+ /**
12
+ * Returns a size-bounded copy of `toolCalls` safe to persist in a Firestore
13
+ * doc, plus whether anything was dropped/summarized. Strategy:
14
+ * 1. Any individually-huge entry keeps its metadata (ts/tool/ok/durationMs +
15
+ * error) but its `input`/`output` payloads are replaced with a marker.
16
+ * 2. The array is then trimmed to the most RECENT entries that fit under the
17
+ * total byte budget (recent calls are the most useful for a post-mortem).
18
+ */
19
+ export declare function capToolCallsForFirestore(toolCalls: ToolCallTrace[]): {
20
+ toolCalls: ToolCallTrace[];
21
+ truncated: boolean;
22
+ };
11
23
  export declare function endTrace(agentRunId: string): Promise<AgentRunTrace | undefined>;
12
24
  /**
13
25
  * Drop-in replacement for runTool that records the call in the active trace.
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/eval/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAA8B,MAAM,SAAS,CAAC;AAcpE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAErF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,aAAa,CAWhB;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEtE;AAED,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAgBrF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,CAAC,GAAG,OAAO,EAC/C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CASzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GACxD,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/eval/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;AAcpE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAErF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,aAAa,CAWhB;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEtE;AAiBD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG;IACpE,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;CACpB,CAyCA;AAED,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAgBrF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,CAAC,GAAG,OAAO,EAC/C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CASzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GACxD,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setTracePersistence = setTracePersistence;
4
4
  exports.startTrace = startTrace;
5
5
  exports.getTrace = getTrace;
6
+ exports.capToolCallsForFirestore = capToolCallsForFirestore;
6
7
  exports.endTrace = endTrace;
7
8
  exports.runToolRecorded = runToolRecorded;
8
9
  exports.trackStage = trackStage;
@@ -36,6 +37,64 @@ function startTrace(opts) {
36
37
  function getTrace(agentRunId) {
37
38
  return traces.get(agentRunId);
38
39
  }
40
+ /** Approx serialized byte size of a JSON-able value (Firestore counts UTF-8 bytes). */
41
+ function jsonByteLen(value) {
42
+ return Buffer.byteLength(JSON.stringify(value ?? null), "utf8");
43
+ }
44
+ // Firestore rejects ANY document over 1,048,576 bytes. For multi-scene agent
45
+ // runs the serialized `toolCalls` array (full provider input/output payloads
46
+ // inline) routinely blows past that — which previously failed the whole trace
47
+ // persist with "trace persist failed" AND, on a {merge:true} write to the run
48
+ // doc, poisoned the terminal-status flip the frontend listener depends on. The
49
+ // FULL trace already ships to Loki + GCS via the recorder, so the Firestore
50
+ // copy only needs to stay queryable and under the cap.
51
+ const FIRESTORE_TOOLCALLS_BUDGET_BYTES = 800000; // headroom for the rest of the doc
52
+ const PER_TOOLCALL_MAX_BYTES = 100000; // any single entry larger than this is summarized
53
+ /**
54
+ * Returns a size-bounded copy of `toolCalls` safe to persist in a Firestore
55
+ * doc, plus whether anything was dropped/summarized. Strategy:
56
+ * 1. Any individually-huge entry keeps its metadata (ts/tool/ok/durationMs +
57
+ * error) but its `input`/`output` payloads are replaced with a marker.
58
+ * 2. The array is then trimmed to the most RECENT entries that fit under the
59
+ * total byte budget (recent calls are the most useful for a post-mortem).
60
+ */
61
+ function capToolCallsForFirestore(toolCalls) {
62
+ let truncated = false;
63
+ const summarizeOutcome = (outcome) => outcome.ok
64
+ ? {
65
+ ok: true,
66
+ output: `[truncated ${jsonByteLen(outcome.output)} bytes]`,
67
+ durationMs: outcome.durationMs,
68
+ }
69
+ : outcome; // failure outcomes carry only {code, message} — already small
70
+ const shrunk = toolCalls.map((call) => {
71
+ if (jsonByteLen(call) <= PER_TOOLCALL_MAX_BYTES)
72
+ return call;
73
+ truncated = true;
74
+ return {
75
+ ts: call.ts,
76
+ tool: call.tool,
77
+ input: `[truncated ${jsonByteLen(call.input)} bytes]`,
78
+ outcome: summarizeOutcome(call.outcome),
79
+ };
80
+ });
81
+ // Keep newest-first under the budget, then restore chronological order.
82
+ const kept = [];
83
+ let total = 0;
84
+ for (let i = shrunk.length - 1; i >= 0; i--) {
85
+ const entry = shrunk[i];
86
+ if (!entry)
87
+ continue;
88
+ const size = jsonByteLen(entry);
89
+ if (total + size > FIRESTORE_TOOLCALLS_BUDGET_BYTES) {
90
+ truncated = true;
91
+ break;
92
+ }
93
+ total += size;
94
+ kept.unshift(entry);
95
+ }
96
+ return { toolCalls: kept, truncated };
97
+ }
39
98
  async function endTrace(agentRunId) {
40
99
  const trace = traces.get(agentRunId);
41
100
  if (!trace)
@@ -29,9 +29,9 @@ declare const InputSchema: z.ZodObject<{
29
29
  tracks: z.ZodArray<z.ZodObject<{
30
30
  id: z.ZodString;
31
31
  kind: z.ZodEnum<{
32
- text: "text";
33
32
  audio: "audio";
34
33
  video: "video";
34
+ text: "text";
35
35
  caption: "caption";
36
36
  fx: "fx";
37
37
  }>;
@@ -662,9 +662,9 @@ declare const OutputSchema: z.ZodObject<{
662
662
  tracks: z.ZodArray<z.ZodObject<{
663
663
  id: z.ZodString;
664
664
  kind: z.ZodEnum<{
665
- text: "text";
666
665
  audio: "audio";
667
666
  video: "video";
667
+ text: "text";
668
668
  caption: "caption";
669
669
  fx: "fx";
670
670
  }>;
@@ -29,9 +29,9 @@ declare const InputSchema: z.ZodObject<{
29
29
  tracks: z.ZodArray<z.ZodObject<{
30
30
  id: z.ZodString;
31
31
  kind: z.ZodEnum<{
32
- text: "text";
33
32
  audio: "audio";
34
33
  video: "video";
34
+ text: "text";
35
35
  caption: "caption";
36
36
  fx: "fx";
37
37
  }>;
@@ -209,8 +209,8 @@ declare const OutputSchema: z.ZodObject<{
209
209
  fontSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>>;
210
210
  sizePct: z.ZodOptional<z.ZodNumber>;
211
211
  weight: z.ZodOptional<z.ZodEnum<{
212
- bold: "bold";
213
212
  regular: "regular";
213
+ bold: "bold";
214
214
  black: "black";
215
215
  medium: "medium";
216
216
  }>>;
@@ -44,9 +44,9 @@ declare const InputSchema: z.ZodObject<{
44
44
  tracks: z.ZodArray<z.ZodObject<{
45
45
  id: z.ZodString;
46
46
  kind: z.ZodEnum<{
47
- text: "text";
48
47
  audio: "audio";
49
48
  video: "video";
49
+ text: "text";
50
50
  caption: "caption";
51
51
  fx: "fx";
52
52
  }>;
@@ -14,5 +14,13 @@ export declare function modelSupportsLastFrame(modelKey: string): boolean;
14
14
  * a model that can't do it. Derived from the configs so it never drifts.
15
15
  */
16
16
  export declare function getModelsSupportingLastFrame(): string[];
17
+ /**
18
+ * Generic capability probe: does the model's config DECLARE this field? Source
19
+ * of truth for "should we send this optional param to the provider", so a model
20
+ * that doesn't list e.g. `negative_prompt` never has it forwarded (and never
21
+ * eats an opaque provider 400 like veo-3.1-lite's "negativePrompt isn't
22
+ * supported by this model"). Same pattern as modelSupportsLastFrame, generalized.
23
+ */
24
+ export declare function modelDeclaresField(modelKey: string, field: string): boolean;
17
25
  export declare function validateParams(params: VideoGenerationParams): boolean;
18
26
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/helpers.ts"],"names":[],"mappings":"AACA,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,wBAAgB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAqJrE"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/helpers.ts"],"names":[],"mappings":"AACA,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,wBAAgB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAqJrE"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.modelSupportsLastFrame = modelSupportsLastFrame;
4
4
  exports.getModelsSupportingLastFrame = getModelsSupportingLastFrame;
5
+ exports.modelDeclaresField = modelDeclaresField;
5
6
  exports.validateParams = validateParams;
6
7
  const aiModels_1 = require("../../globals/aiModels");
7
8
  /**
@@ -24,6 +25,17 @@ function modelSupportsLastFrame(modelKey) {
24
25
  function getModelsSupportingLastFrame() {
25
26
  return Object.keys(aiModels_1.aiModelConfigs).filter((key) => modelSupportsLastFrame(key));
26
27
  }
28
+ /**
29
+ * Generic capability probe: does the model's config DECLARE this field? Source
30
+ * of truth for "should we send this optional param to the provider", so a model
31
+ * that doesn't list e.g. `negative_prompt` never has it forwarded (and never
32
+ * eats an opaque provider 400 like veo-3.1-lite's "negativePrompt isn't
33
+ * supported by this model"). Same pattern as modelSupportsLastFrame, generalized.
34
+ */
35
+ function modelDeclaresField(modelKey, field) {
36
+ const cfg = aiModels_1.aiModelConfigs[modelKey];
37
+ return !!cfg?.fields && field in cfg.fields;
38
+ }
27
39
  function validateParams(params) {
28
40
  const modelConfig = aiModels_1.aiModelConfigs[params.modelKey];
29
41
  if (!modelConfig) {
@@ -2,6 +2,7 @@ import { BaseAiGenProviderService } from "../baseAiGenProvider.service";
2
2
  import { CreditUsageParams, ImageGenerationParams, ImageGenerationResult, MusicGenerationParams, MusicGenerationResult, VideoGenerationParams, VideoGenerationResult, VideoStatusParams, VideoStatusResult } from "../types";
3
3
  export declare class GoogleService extends BaseAiGenProviderService {
4
4
  private ai;
5
+ private keyPool;
5
6
  private static readonly MAX_RETRY_ATTEMPTS;
6
7
  constructor();
7
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"google.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/google/google.service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAmKlB,qBAAa,aAAc,SAAQ,wBAAwB;IACzD,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAK;;IAO/C;;;;OAIG;YACW,kBAAkB;IA+B1B,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAyG3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA0F3C,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;YAiBnB,cAAc;IAwG5B;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAqEjC,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAY,EAAE,UAAmB,EAAE,SAAiB,EAAE,SAAa,EAAE,SAAS,EAAE,EAAE,iBAAiB,GAAG,MAAM;CA8BvI"}
1
+ {"version":3,"file":"google.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/google/google.service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AA+NlB,qBAAa,aAAc,SAAQ,wBAAwB;IAKzD,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAK;;IAQ/C;;;;OAIG;YACW,kBAAkB;IA+B1B,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAiJ3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAyG3C,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;YAiBnB,cAAc;IAwG5B;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAqEjC,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAY,EAAE,UAAmB,EAAE,SAAiB,EAAE,SAAa,EAAE,SAAS,EAAE,EAAE,iBAAiB,GAAG,MAAM;CA8BvI"}
@@ -18,6 +18,8 @@ const baseAiGenProvider_service_1 = require("../baseAiGenProvider.service");
18
18
  const google_auth_library_1 = require("google-auth-library");
19
19
  const fs_1 = require("fs");
20
20
  const promises_2 = require("stream/promises");
21
+ const googleApiKeys_1 = require("./googleApiKeys");
22
+ const googleKeyPool_1 = require("./googleKeyPool");
21
23
  // Codes from undici / Node net layer that indicate a transient network failure
22
24
  // the request never reached the server, or the server hung up mid-flight.
23
25
  // Retrying these is safe (idempotent at the API layer for our use cases) and usually succeeds.
@@ -151,6 +153,46 @@ function classifyGoogleApiError(err) {
151
153
  /(filtered out because they violated|violated Google's (?:Responsible AI|content) (?:practices|policies))/i.test(msg)) {
152
154
  return new errors_1.UserFacingError("Your prompt was flagged by Google's safety filters. Please rephrase and try again.", errors_1.USER_FACING_ERROR_CODES.CONTENT_POLICY_VIOLATION);
153
155
  }
156
+ // Generic INVALID_ARGUMENT 400 on a provided string field. Veo echoes the
157
+ // offending value back ("The string value `<prompt>` ...") and the only
158
+ // large free-text field we send is the prompt, so attribute this to the
159
+ // prompt: it's either over the model's length limit or otherwise rejected
160
+ // by the validator. Either way it's user input, not a platform bug —
161
+ // surface a typed, actionable, non-retryable error (logged warn, no Slack
162
+ // page) instead of leaking the echoed prompt into the error channel.
163
+ if ((status === "INVALID_ARGUMENT" || httpCode === 400) &&
164
+ /string value/i.test(msg)) {
165
+ const tooLong = /(exceed|too long|maximum length|length limit|\blimit\b)/i.test(msg);
166
+ return tooLong
167
+ ? new errors_1.UserFacingError("Your prompt is too long for this model. Please shorten it and try again.", errors_1.USER_FACING_ERROR_CODES.PROMPT_TOO_LONG)
168
+ : new errors_1.UserFacingError("Your prompt was rejected by the model. Please simplify or rephrase it and try again.", errors_1.USER_FACING_ERROR_CODES.PROMPT_INVALID);
169
+ }
170
+ // gRPC code 13 = INTERNAL. Veo returns this for transient backend failures
171
+ // ("Video generation failed due to an internal server issue. Please try
172
+ // again in a few minutes."). It is NOT our bug and NOT moderation — a
173
+ // Google-side flake. Surface as a transient PROVIDER_UNAVAILABLE so the
174
+ // user gets a "try again" message and it logs warn (Loki) instead of
175
+ // paging Slack as a platform error. (Egregiously-blocked content that Veo
176
+ // masks as code 13 also lands here; we can't distinguish it from a real
177
+ // internal flake, and "try again" is an acceptable fallback message.)
178
+ if (httpCode === 13 ||
179
+ status === "INTERNAL" ||
180
+ /internal (server|error)/i.test(msg)) {
181
+ return new errors_1.UserFacingError("Google's video service had a temporary problem. Please try again in a few minutes.", errors_1.USER_FACING_ERROR_CODES.PROVIDER_UNAVAILABLE);
182
+ }
183
+ // HTTP 503 / status UNAVAILABLE — Google's video backend is temporarily
184
+ // overloaded or down ("The service is currently unavailable."). Same class
185
+ // as code 13 INTERNAL above: a transient provider outage, not our bug and
186
+ // not moderation. Without this branch it fell through to `return null` and
187
+ // got re-thrown as a raw ApiError → logged at `error` (paging Slack) with
188
+ // the raw provider JSON as the scene's errorMessage. Surface it as
189
+ // PROVIDER_UNAVAILABLE so the user gets a "try again" message and it logs
190
+ // warn (Loki) instead.
191
+ if (httpCode === 503 ||
192
+ status === "UNAVAILABLE" ||
193
+ /service is currently unavailable|temporarily unavailable/i.test(msg)) {
194
+ return new errors_1.UserFacingError("Google's video service is temporarily unavailable. Please try again in a few minutes.", errors_1.USER_FACING_ERROR_CODES.PROVIDER_UNAVAILABLE);
195
+ }
154
196
  }
155
197
  catch {
156
198
  // Not JSON — fall through to non-JSON checks.
@@ -164,6 +206,7 @@ class GoogleService extends baseAiGenProvider_service_1.BaseAiGenProviderService
164
206
  constructor() {
165
207
  super();
166
208
  this.ai = new genai_1.GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY });
209
+ this.keyPool = (0, googleKeyPool_1.getGoogleKeyPool)();
167
210
  }
168
211
  /**
169
212
  * Retries `fn` on transient network errors (undici "fetch failed", ECONNRESET, ETIMEDOUT,
@@ -229,9 +272,35 @@ class GoogleService extends baseAiGenProvider_service_1.BaseAiGenProviderService
229
272
  aspectRatio: params.aspectRatio,
230
273
  resolution: params.resolution,
231
274
  durationSeconds: params.duration,
232
- ...(params.seed !== undefined ? { seed: params.seed } : {}),
233
- ...(params.personGeneration ? { personGeneration: params.personGeneration } : {}),
234
- ...(params.negativePrompt ? { negativePrompt: params.negativePrompt } : {}),
275
+ // REMOVED for the Gemini Developer API backend kept for reference.
276
+ // `seed` is NOT supported by Veo on the Gemini API (Mldev): this client
277
+ // is `new GoogleGenAI({ apiKey })`, whose SDK transformer
278
+ // (generateVideosConfigToMldev) throws *client-side*
279
+ // "seed parameter is not supported in Gemini API" before any request is
280
+ // sent — so it can never reach Google and was failing every job that
281
+ // carried a seed. Like `generateAudio`, it is a Vertex-AI-only field.
282
+ // Restore this line if/when this client switches to Vertex (vertexai:true).
283
+ // ...(params.seed !== undefined ? { seed: params.seed } : {}),
284
+ // personGeneration on the Gemini API Veo backend: "allow_all" is the
285
+ // ONLY supported value for Veo 3.x (and it is also the default).
286
+ // "allow_adult" and "dont_allow" are Veo-2-only legacy values — sending
287
+ // either returns 400 "<value> for personGeneration is currently not
288
+ // supported", which is NOT matched by classifyGoogleApiError and so
289
+ // leaks to logger.error → Slack while failing the job. Since allow_all
290
+ // is the default, forward the param only when it's explicitly allow_all
291
+ // (a no-op that documents intent); drop any other requested value
292
+ // rather than hard-fail. Restoring allow_adult/dont_allow would require
293
+ // a Veo-2 model or an allowlisted Vertex project.
294
+ ...(params.personGeneration === "allow_all"
295
+ ? { personGeneration: "allow_all" }
296
+ : {}),
297
+ // negativePrompt support is MODEL-SPECIFIC on the Gemini API: veo-3.1 and
298
+ // veo-3.1-fast accept it, veo-3.1-lite returns 400 "negativePrompt isn't
299
+ // supported by this model". Gate on the model config declaring the field
300
+ // (negative_prompt) so we never forward it to a model that rejects it.
301
+ ...(params.negativePrompt && (0, helpers_2.modelDeclaresField)(params.modelKey, "negative_prompt")
302
+ ? { negativePrompt: params.negativePrompt }
303
+ : {}),
235
304
  // REMOVED for the Gemini Developer API backend — kept for reference.
236
305
  // `generateAudio` is a Vertex-AI-only config field. This client is
237
306
  // constructed with `new GoogleGenAI({ apiKey })` (the Mldev / Gemini
@@ -272,21 +341,44 @@ class GoogleService extends baseAiGenProvider_service_1.BaseAiGenProviderService
272
341
  }));
273
342
  }
274
343
  }
275
- const operation = await this.withTransientRetry("generateVideos", () => this.ai.models.generateVideos(request));
344
+ // Route this submit to a key with budget (priority order). The per-key
345
+ // caps are the single-key Tier-2 numbers in the model config; the
346
+ // model-level limiter already gated the aggregate (per-key × key count).
347
+ const keyEntry = await this.keyPool.pickForSubmit(modelId, modelConfig.requestPerMin ?? 0, modelConfig.requestPerDay ?? 0);
348
+ const operation = await this.withTransientRetry("generateVideos", () => keyEntry.client.models.generateVideos(request));
276
349
  if (!operation || !operation.name) {
277
350
  throw new Error("Failed to initiate video generation task");
278
351
  }
279
- return { task: operation.name, status: types_1.EVideoSceneStatus.TRIGGERED };
352
+ // Tag the task with the issuing key so poll + download re-select the same
353
+ // (project-scoped) client. Single-key pool → bare name (legacy format).
354
+ return {
355
+ task: (0, googleApiKeys_1.encodeVeoTask)(keyEntry.id, operation.name, this.keyPool.size),
356
+ status: types_1.EVideoSceneStatus.TRIGGERED,
357
+ };
280
358
  }
281
359
  async checkVideoStatus({ task, outputFilename, outputFilePath = "videos", }) {
360
+ // Re-select the key that submitted this task (Veo operations are
361
+ // project-scoped). Un-tagged / unknown ids fall back to the legacy client.
362
+ const { keyId, operationName } = (0, googleApiKeys_1.decodeVeoTask)(task);
363
+ const client = this.keyPool.clientById(keyId) ?? this.ai;
282
364
  const operation = new genai_1.GenerateVideosOperation();
283
- operation.name = task;
284
- const result = await this.withTransientRetry("getVideosOperation", () => this.ai.operations.getVideosOperation({ operation }));
365
+ operation.name = operationName;
366
+ const result = await this.withTransientRetry("getVideosOperation", () => client.operations.getVideosOperation({ operation }));
285
367
  if (result.done) {
286
368
  if (result.error) {
369
+ // A long-running operation can finish with an error (e.g. gRPC 13
370
+ // INTERNAL) instead of throwing. Route it through the same classifier
371
+ // as thrown API errors so transient INTERNAL and invalid-prompt
372
+ // failures get a typed `{code, message}` (which sceneMonitor demotes to
373
+ // warn) instead of leaking raw gRPC JSON that pages Slack as a bug.
374
+ const classified = classifyGoogleApiError({
375
+ message: JSON.stringify(result.error),
376
+ });
287
377
  return {
288
378
  status: types_1.EVideoSceneStatus.FAILED,
289
- errorMessage: JSON.stringify(result.error),
379
+ errorMessage: classified
380
+ ? JSON.stringify(classified.toJSON())
381
+ : JSON.stringify(result.error),
290
382
  };
291
383
  }
292
384
  const videoUri = result.response?.generatedVideos?.[0]?.video?.uri;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Pure (SDK-free, Redis-free) helpers for the Google AI Studio API key pool.
3
+ *
4
+ * ── DECISION RECORD (2026-06-15) ────────────────────────────────────────────
5
+ * Problem: Veo on a single Gemini Developer API key is quota-starved — Tier 2
6
+ * is ~4 req/min and ~50/day per Veo model — which serialized bursts of jobs
7
+ * into a multi-hour queue (~370 min observed avg latency).
8
+ *
9
+ * Chosen fix (today): a multi-key pool over TWO Google AI Studio keys that live
10
+ * in SEPARATE GCP projects / billing accounts, so their quotas are independent
11
+ * and ADD UP. Keys are used in PRIORITY order:
12
+ * - key[0] = the NEW key (vidspotai project), currently **Tier 1** (2/min,
13
+ * 10/day per Veo model). Used FIRST, deliberately, to drive usage and
14
+ * promote its billing account up the tier ladder.
15
+ * - key[1] = the CURRENT key, **Tier 2** (4/min, 50/day). Used once key[0]
16
+ * is out of per-minute / per-day budget.
17
+ * Aggregate Veo budget = T1 + T2 = 6/min, 60/day. When BOTH are exhausted, the
18
+ * job-start capacity selector (videoJobProcessor) spills to another provider.
19
+ *
20
+ * When key[1]'s account is billed it moves to Tier 3; bump its tier in
21
+ * GOOGLE_API_KEY_TIERS then (no code change — the ladder below handles it).
22
+ *
23
+ * Vertex AI (DEFERRED, on record for the future): Veo is also available via
24
+ * Vertex, where quota is **per-project** and the current billing account is
25
+ * Tier-2-per-project — so we could create multiple projects under one account
26
+ * to scale further. We are NOT doing Vertex now: the two AI-Studio keys across
27
+ * two billing accounts already cover our needed headroom, and the Vertex path
28
+ * needs a different output flow (GCS `gs://` URIs rather than the Files API)
29
+ * that we'd rather build + test deliberately when the extra capacity is needed.
30
+ *
31
+ * ── CONFIG ──────────────────────────────────────────────────────────────────
32
+ * GOOGLE_API_KEYS — comma-separated keys in PRIORITY order. Falls back
33
+ * to the single legacy GOOGLE_API_KEY when unset.
34
+ * GOOGLE_API_KEY_TIERS — comma-separated tier numbers (1/2/3) aligned to
35
+ * GOOGLE_API_KEYS. Missing/extra entries default to 2.
36
+ * GOOGLE_API_KEY — legacy single key; also the client used to poll
37
+ * tasks submitted before the pool existed (un-tagged).
38
+ *
39
+ * Per-key budget is derived from the model config's Tier-2 baseline
40
+ * (requestPerMin / requestPerDay) scaled by each key's tier (see TIER_FACTORS);
41
+ * the pool gives us the SUM across keys.
42
+ */
43
+ /** Parse the configured keys in priority order, de-duped, empties removed. */
44
+ export declare function parseGoogleApiKeys(): string[];
45
+ /** Tier per key (aligned to parseGoogleApiKeys order); defaults to 2. */
46
+ export declare function parseGoogleApiKeyTiers(): number[];
47
+ /** Number of configured Google keys (>= 1 so callers can multiply safely). */
48
+ export declare function googleApiKeyCount(): number;
49
+ /** Per-key rate cap for a given Tier-2 baseline and tier. */
50
+ export declare function scaleLimitForTier(baseline: number | undefined, tier: number, kind: "rpm" | "rpd"): number;
51
+ /**
52
+ * Aggregate multiplier across all configured keys, for scaling a Google
53
+ * model's Tier-2 baseline into the pool-wide budget. Returns 1 for a single
54
+ * default key (legacy behavior unchanged).
55
+ */
56
+ export declare function googleAggregateFactor(kind: "rpm" | "rpd"): number;
57
+ /** Stable id for the key at a given priority index. */
58
+ export declare function googleKeyId(index: number): string;
59
+ /**
60
+ * Tag a Veo operation name with the id of the key that created it, so polling
61
+ * + download can re-select the same project-scoped client. With a single key
62
+ * we return the bare operation name (no tag) — byte-for-byte the legacy format,
63
+ * so nothing changes until a real pool is configured.
64
+ */
65
+ export declare function encodeVeoTask(keyId: string, operationName: string, poolSize: number): string;
66
+ /** Reverse of encodeVeoTask. `keyId` is undefined for legacy/un-tagged tasks. */
67
+ export declare function decodeVeoTask(task: string): {
68
+ keyId?: string;
69
+ operationName: string;
70
+ };
71
+ //# sourceMappingURL=googleApiKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"googleApiKeys.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/google/googleApiKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAoBH,8EAA8E;AAC9E,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAa7C;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAUjD;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,KAAK,GAAG,KAAK,GAClB,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAIjE;AAED,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAIrF"}