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.
- package/lib/globals/aiModels/providers/google.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/google.js +39 -7
- package/lib/schemas/project.schema.d.ts +3 -3
- package/lib/schemas/videoPlan.schema.d.ts +3 -3
- package/lib/services/agent/editClassifier.d.ts +2 -2
- package/lib/services/agent/eval/recorder.d.ts +13 -1
- package/lib/services/agent/eval/recorder.d.ts.map +1 -1
- package/lib/services/agent/eval/recorder.js +59 -0
- package/lib/services/agent/tools/composeScene.tool.d.ts +2 -2
- package/lib/services/agent/tools/estimateCost.tool.d.ts +1 -1
- package/lib/services/agent/tools/planVideo.tool.d.ts +1 -1
- package/lib/services/agent/tools/render.tool.d.ts +1 -1
- package/lib/services/aiGen/helpers.d.ts +8 -0
- package/lib/services/aiGen/helpers.d.ts.map +1 -1
- package/lib/services/aiGen/helpers.js +12 -0
- package/lib/services/aiGen/providers/google/google.service.d.ts +1 -0
- package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/google/google.service.js +100 -8
- package/lib/services/aiGen/providers/google/googleApiKeys.d.ts +71 -0
- package/lib/services/aiGen/providers/google/googleApiKeys.d.ts.map +1 -0
- package/lib/services/aiGen/providers/google/googleApiKeys.js +137 -0
- package/lib/services/aiGen/providers/google/googleKeyPool.d.ts +52 -0
- package/lib/services/aiGen/providers/google/googleKeyPool.d.ts.map +1 -0
- package/lib/services/aiGen/providers/google/googleKeyPool.js +129 -0
- package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/pixverse/pixverse.service.js +7 -1
- package/lib/services/bullmq.service.d.ts.map +1 -1
- package/lib/services/bullmq.service.js +23 -1
- package/lib/services/index.d.ts +1 -0
- package/lib/services/index.d.ts.map +1 -1
- package/lib/services/index.js +1 -0
- package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts +60 -5
- package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts.map +1 -1
- package/lib/services/rateLimiter/distributedRateLimiter.service.js +184 -16
- package/lib/services/translation/index.d.ts +2 -0
- package/lib/services/translation/index.d.ts.map +1 -0
- package/lib/services/translation/index.js +9 -0
- package/lib/services/translation/translation.service.d.ts +50 -0
- package/lib/services/translation/translation.service.d.ts.map +1 -0
- package/lib/services/translation/translation.service.js +211 -0
- package/lib/utils/helpers.d.ts +2 -4
- package/lib/utils/helpers.d.ts.map +1 -1
- package/lib/utils/helpers.js +9 -63
- 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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
}>;
|
|
@@ -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
|
}>>;
|
|
@@ -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;
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
284
|
-
const result = await this.withTransientRetry("getVideosOperation", () =>
|
|
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:
|
|
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"}
|