ag-common 0.0.908 → 0.0.910
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/README.md +32 -0
- package/dist/api/helpers/ai/adapters/codex.d.ts +12 -0
- package/dist/api/helpers/ai/adapters/codex.js +573 -0
- package/dist/api/helpers/ai/adapters/google.d.ts +12 -0
- package/dist/api/helpers/ai/adapters/google.js +429 -0
- package/dist/api/helpers/ai/client.d.ts +11 -0
- package/dist/api/helpers/ai/client.js +191 -0
- package/dist/api/helpers/ai/index.d.ts +3 -0
- package/dist/api/helpers/ai/index.js +18 -0
- package/dist/api/helpers/ai/quota.d.ts +55 -0
- package/dist/api/helpers/ai/quota.js +148 -0
- package/dist/api/helpers/ai/types.d.ts +118 -0
- package/dist/api/helpers/ai/types.js +2 -0
- package/dist/api/helpers/google/index.d.ts +0 -1
- package/dist/api/helpers/google/index.js +0 -1
- package/dist/api/helpers/index.d.ts +1 -0
- package/dist/api/helpers/index.js +1 -0
- package/dist/api/helpers/retryOnError.d.ts +3 -3
- package/dist/api/helpers/retryOnError.js +60 -10
- package/package.json +1 -1
- package/dist/api/helpers/google/gemini.d.ts +0 -26
- package/dist/api/helpers/google/gemini.js +0 -239
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveGroundedUrl = exports.geminiPromptDirect = exports.geminiPromptImage = exports.isTextGenerationModel = void 0;
|
|
4
|
-
const genai_1 = require("@google/genai");
|
|
5
|
-
const array_1 = require("../../../common/helpers/array");
|
|
6
|
-
const async_1 = require("../../../common/helpers/async");
|
|
7
|
-
const fetch_1 = require("../../../common/helpers/fetch");
|
|
8
|
-
const log_1 = require("../../../common/helpers/log");
|
|
9
|
-
const node_cache_1 = require("../../../common/helpers/node-cache");
|
|
10
|
-
const retryOnError_1 = require("../retryOnError");
|
|
11
|
-
const apikey_1 = require("./apikey");
|
|
12
|
-
let genAIs = [];
|
|
13
|
-
const geminiModelsCache = new node_cache_1.TypedNodeCache({ stdTTL: 86400 });
|
|
14
|
-
const geminiModelsCacheKey = "gemini-models-v1";
|
|
15
|
-
const FALLBACK_GEMINI_MODELS = [
|
|
16
|
-
"gemini-3-flash-preview",
|
|
17
|
-
"gemini-3-pro-preview",
|
|
18
|
-
"gemini-2.5-pro",
|
|
19
|
-
"gemini-2.5-flash",
|
|
20
|
-
"gemini-2.5-flash-lite",
|
|
21
|
-
];
|
|
22
|
-
// Helper to sort models based on preference
|
|
23
|
-
const sortModelsByPreference = (models, prefer) => {
|
|
24
|
-
const modelArray = [...models];
|
|
25
|
-
if (prefer === "quality") {
|
|
26
|
-
// Sort pro models first
|
|
27
|
-
return modelArray.sort((a, b) => {
|
|
28
|
-
const aIsPro = a.includes("pro");
|
|
29
|
-
const bIsPro = b.includes("pro");
|
|
30
|
-
if (aIsPro && !bIsPro)
|
|
31
|
-
return -1;
|
|
32
|
-
if (!aIsPro && bIsPro)
|
|
33
|
-
return 1;
|
|
34
|
-
return 0;
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else if (prefer === "fast") {
|
|
38
|
-
// Sort flash models first
|
|
39
|
-
return modelArray.sort((a, b) => {
|
|
40
|
-
const aIsFlash = a.includes("flash");
|
|
41
|
-
const bIsFlash = b.includes("flash");
|
|
42
|
-
if (aIsFlash && !bIsFlash)
|
|
43
|
-
return -1;
|
|
44
|
-
if (!aIsFlash && bIsFlash)
|
|
45
|
-
return 1;
|
|
46
|
-
return 0;
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
// Default behavior - no sorting
|
|
50
|
-
return modelArray;
|
|
51
|
-
};
|
|
52
|
-
const normalizeModelName = (name) => name.replace(/^models\//, "");
|
|
53
|
-
const NON_TEXT_MODEL_CAPABILITIES = [
|
|
54
|
-
"audio",
|
|
55
|
-
"computer-use",
|
|
56
|
-
"embedding",
|
|
57
|
-
"image",
|
|
58
|
-
"live",
|
|
59
|
-
"robotics",
|
|
60
|
-
"tts",
|
|
61
|
-
];
|
|
62
|
-
const isTextGenerationModel = (name) => {
|
|
63
|
-
const normalizedName = name.toLowerCase();
|
|
64
|
-
return (normalizedName.startsWith("gemini") &&
|
|
65
|
-
!NON_TEXT_MODEL_CAPABILITIES.some((capability) => normalizedName.includes(capability)));
|
|
66
|
-
};
|
|
67
|
-
exports.isTextGenerationModel = isTextGenerationModel;
|
|
68
|
-
const getAvailableGeminiModels = async () => {
|
|
69
|
-
const cachedModels = geminiModelsCache.get(geminiModelsCacheKey);
|
|
70
|
-
if (cachedModels && cachedModels.length > 0) {
|
|
71
|
-
return cachedModels;
|
|
72
|
-
}
|
|
73
|
-
const keyServiceCombinations = (0, apikey_1.getAvailableCombinations)("gemini");
|
|
74
|
-
const key = keyServiceCombinations[0]?.key;
|
|
75
|
-
if (!key) {
|
|
76
|
-
(0, log_1.warn)("No GOOGLE_API_KEY available. Falling back to default Gemini models.");
|
|
77
|
-
return [...FALLBACK_GEMINI_MODELS];
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(key)}`);
|
|
81
|
-
if (!response.ok) {
|
|
82
|
-
throw new Error(`model list fetch failed with status ${response.status}`);
|
|
83
|
-
}
|
|
84
|
-
const payload = (await response.json());
|
|
85
|
-
const discoveredModels = [
|
|
86
|
-
...new Set((payload.models ?? [])
|
|
87
|
-
.filter((m) => (m.supportedGenerationMethods ?? []).includes("generateContent"))
|
|
88
|
-
.map((m) => normalizeModelName(m.name ?? ""))
|
|
89
|
-
.filter(exports.isTextGenerationModel)),
|
|
90
|
-
];
|
|
91
|
-
if (discoveredModels.length === 0) {
|
|
92
|
-
throw new Error("no gemini generateContent models discovered");
|
|
93
|
-
}
|
|
94
|
-
geminiModelsCache.set(geminiModelsCacheKey, discoveredModels);
|
|
95
|
-
(0, log_1.info)(`loaded ${discoveredModels.length} Gemini models from API`);
|
|
96
|
-
return discoveredModels;
|
|
97
|
-
}
|
|
98
|
-
catch (e) {
|
|
99
|
-
(0, log_1.warn)(`Failed to load Gemini models from API. Falling back to defaults. ${String(e)}`);
|
|
100
|
-
return [...FALLBACK_GEMINI_MODELS];
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
// Helper to get available key+model combinations
|
|
104
|
-
const getAvailableGeminiCombinations = async (prefer) => {
|
|
105
|
-
if (genAIs.length === 0) {
|
|
106
|
-
const keyServiceCombinations = (0, apikey_1.getAvailableCombinations)("gemini");
|
|
107
|
-
const keys = keyServiceCombinations.map((combo) => combo.key);
|
|
108
|
-
genAIs = keys.map((k) => [k, new genai_1.GoogleGenAI({ apiKey: k })]);
|
|
109
|
-
}
|
|
110
|
-
const availableModels = await getAvailableGeminiModels();
|
|
111
|
-
const sortedModels = sortModelsByPreference(availableModels, prefer);
|
|
112
|
-
const combinations = [];
|
|
113
|
-
for (const [key, ai] of genAIs) {
|
|
114
|
-
for (const model of sortedModels) {
|
|
115
|
-
const keyServiceCombinations = (0, apikey_1.getAvailableCombinations)(`gemini-${model}`, false);
|
|
116
|
-
const isAvailable = keyServiceCombinations.some((k) => k.key === key);
|
|
117
|
-
if (isAvailable) {
|
|
118
|
-
combinations.push([key, ai, model]);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return combinations;
|
|
123
|
-
};
|
|
124
|
-
const geminiPromptImage = async ({ prompt, urls, ident, prefer, onGenerated, }) => {
|
|
125
|
-
let images = [];
|
|
126
|
-
if (urls && urls.length > 0) {
|
|
127
|
-
images = await (0, async_1.asyncMap)(urls, (i) => (0, fetch_1.fetchToMemory)(i));
|
|
128
|
-
}
|
|
129
|
-
if (images.some((image) => image === undefined)) {
|
|
130
|
-
throw new Error("image not downloaded correctly");
|
|
131
|
-
}
|
|
132
|
-
const r = await (0, exports.geminiPromptDirect)({
|
|
133
|
-
prompt,
|
|
134
|
-
images: images.filter(array_1.notEmpty),
|
|
135
|
-
ident,
|
|
136
|
-
prefer,
|
|
137
|
-
onGenerated,
|
|
138
|
-
});
|
|
139
|
-
return r;
|
|
140
|
-
};
|
|
141
|
-
exports.geminiPromptImage = geminiPromptImage;
|
|
142
|
-
const geminiPromptDirect = async ({ prompt, images = [], ident, prefer, groundedSearch = false, onGenerated, }) => {
|
|
143
|
-
const parts = images.map((i) => ({
|
|
144
|
-
inlineData: {
|
|
145
|
-
data: Buffer.from(i.arraybuffer).toString("base64"),
|
|
146
|
-
mimeType: i.type,
|
|
147
|
-
},
|
|
148
|
-
}));
|
|
149
|
-
return (0, retryOnError_1.retryOnError)(`geminiPromptDirect:${ident ?? "unknown"}`, async () => {
|
|
150
|
-
const combinations = await getAvailableGeminiCombinations(prefer);
|
|
151
|
-
if (combinations.length === 0) {
|
|
152
|
-
throw new Error("No available API key and model combinations");
|
|
153
|
-
}
|
|
154
|
-
let lastFailure;
|
|
155
|
-
for (const [key, ai, selectedModel] of combinations) {
|
|
156
|
-
// Another concurrent prompt may have exhausted this combination already.
|
|
157
|
-
if (!(0, apikey_1.getAvailableCombinations)(`gemini-${selectedModel}`, false).some((entry) => entry.key === key))
|
|
158
|
-
continue;
|
|
159
|
-
// Prepare the request configuration
|
|
160
|
-
const requestConfig = {
|
|
161
|
-
model: selectedModel,
|
|
162
|
-
contents: [{ parts: [{ text: prompt }, ...parts] }],
|
|
163
|
-
config: {},
|
|
164
|
-
};
|
|
165
|
-
// Add grounded search configuration if enabled
|
|
166
|
-
if (groundedSearch) {
|
|
167
|
-
requestConfig.config.tools = [{ googleSearch: {} }];
|
|
168
|
-
}
|
|
169
|
-
(0, log_1.info)("gem query on:" + selectedModel, requestConfig);
|
|
170
|
-
try {
|
|
171
|
-
// oxlint-disable-next-line no-await-in-loop -- fallback depends on the previous model failing
|
|
172
|
-
const response = await ai.models.generateContent(requestConfig);
|
|
173
|
-
const rawtext = (response.text ?? "")
|
|
174
|
-
.replace(/```(json)?/gi, "")
|
|
175
|
-
.replace(/:[ ]+undefined/gim, ": null");
|
|
176
|
-
(0, log_1.info)("gem response");
|
|
177
|
-
(0, log_1.debug)("gem prompt:" + prompt, ident);
|
|
178
|
-
(0, log_1.debug)("gem response:" + rawtext);
|
|
179
|
-
(0, log_1.debug)("gem query usage:" + JSON.stringify(response.usageMetadata));
|
|
180
|
-
onGenerated?.({ model: response.modelVersion || selectedModel, generatedAt: Date.now() });
|
|
181
|
-
return rawtext;
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
const mod = `gemini-${selectedModel}`;
|
|
185
|
-
const status = e.status;
|
|
186
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
187
|
-
const unavailableModel = status === 404 && message.includes(selectedModel);
|
|
188
|
-
if (status === 429 || (0, retryOnError_1.isOverloadedApiKeyError)(e) || unavailableModel) {
|
|
189
|
-
(0, log_1.warn)("Gemini model attempt failed; trying next available combination", {
|
|
190
|
-
model: selectedModel,
|
|
191
|
-
status,
|
|
192
|
-
reason: unavailableModel ? "model unavailable" : "quota or capacity exhausted",
|
|
193
|
-
});
|
|
194
|
-
(0, apikey_1.blockKeyService)(key, mod);
|
|
195
|
-
lastFailure = e;
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
throw e;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
throw lastFailure ?? new Error("No available API key and model combinations");
|
|
202
|
-
}, 1, 5000);
|
|
203
|
-
};
|
|
204
|
-
exports.geminiPromptDirect = geminiPromptDirect;
|
|
205
|
-
const resolveGroundedUrl = async (url) => {
|
|
206
|
-
if (!url.includes("vertexaisearch.cloud.google.com")) {
|
|
207
|
-
(0, log_1.debug)("not a grounded url", url);
|
|
208
|
-
return url;
|
|
209
|
-
}
|
|
210
|
-
try {
|
|
211
|
-
(0, log_1.debug)("resolving grounded url", url);
|
|
212
|
-
// Fetch the grounded URL with redirect following disabled
|
|
213
|
-
const response = await fetch(url, {
|
|
214
|
-
method: "HEAD",
|
|
215
|
-
redirect: "manual",
|
|
216
|
-
});
|
|
217
|
-
// Check for redirect responses (301, 302, 307, 308)
|
|
218
|
-
if (response.status >= 300 && response.status < 400) {
|
|
219
|
-
const location = response.headers.get("location") || response.headers.get("Location");
|
|
220
|
-
if (location) {
|
|
221
|
-
(0, log_1.debug)("resolved grounded url to", location);
|
|
222
|
-
return location;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
// If no redirect, try a GET request to follow any JavaScript redirects
|
|
226
|
-
const fullResponse = await fetch(url, {
|
|
227
|
-
redirect: "follow",
|
|
228
|
-
});
|
|
229
|
-
const finalUrl = fullResponse.url;
|
|
230
|
-
(0, log_1.debug)("resolved grounded url via GET to", finalUrl);
|
|
231
|
-
return finalUrl;
|
|
232
|
-
}
|
|
233
|
-
catch (error) {
|
|
234
|
-
(0, log_1.debug)("error resolving grounded url", error);
|
|
235
|
-
// Return original URL if resolution fails
|
|
236
|
-
return url;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
exports.resolveGroundedUrl = resolveGroundedUrl;
|