@sahan-sac/ai-core 0.3.0 → 0.4.0
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/CHANGELOG.md +21 -0
- package/README.md +123 -120
- package/dist/adapters.d.ts +1 -1
- package/dist/adapters.js +17 -609
- package/dist/availability.js +9 -458
- package/dist/chunk-BK4B76LD.js +621 -0
- package/dist/chunk-BL4J2JNX.js +48 -0
- package/dist/chunk-MRNQPHWI.js +194 -0
- package/dist/chunk-PMC3UWQ2.js +10 -0
- package/dist/chunk-RBSLNDFW.js +61 -0
- package/dist/chunk-SI7JE5BG.js +126 -0
- package/dist/env.d.ts +13 -0
- package/dist/env.js +6 -102
- package/dist/image.js +14 -236
- package/dist/index.js +5 -102
- package/dist/log.js +3 -6
- package/dist/models.js +9 -51
- package/dist/providers.d.ts +31 -1
- package/dist/providers.js +22 -582
- package/dist/vertex.js +4 -43
- package/package.json +2 -2
package/dist/image.js
CHANGED
|
@@ -1,240 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
gemini: pick(env.IMAGE_GEMINI_MODEL, DEFAULT_IMAGE_MODELS.gemini),
|
|
15
|
-
vertex: pick(env.IMAGE_VERTEX_MODEL, env.IMAGEN_MODEL, DEFAULT_IMAGE_MODELS.vertex)
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
var paidAllowed = (env) => env.AI_ALLOW_PAID === true;
|
|
19
|
-
function vertexConfigured(env) {
|
|
20
|
-
return Boolean(env.GOOGLE_CLIENT_EMAIL && env.GOOGLE_PRIVATE_KEY && env.GOOGLE_CLOUD_PROJECT);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// src/vertex.ts
|
|
24
|
-
import "server-only";
|
|
25
|
-
var cachedToken = null;
|
|
26
|
-
function base64UrlEncode(input) {
|
|
27
|
-
return Buffer.from(input).toString("base64url");
|
|
28
|
-
}
|
|
29
|
-
async function getVertexAccessToken(account, fetchImpl = fetch) {
|
|
30
|
-
const now = Date.now();
|
|
31
|
-
if (cachedToken && cachedToken.expiresAt - 6e4 > now) return cachedToken.accessToken;
|
|
32
|
-
const { createSign } = await import("crypto");
|
|
33
|
-
const issuedAt = Math.floor(now / 1e3);
|
|
34
|
-
const expiresIn = 3600;
|
|
35
|
-
const header = base64UrlEncode(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
36
|
-
const claims = base64UrlEncode(
|
|
37
|
-
JSON.stringify({
|
|
38
|
-
iss: account.clientEmail,
|
|
39
|
-
scope: "https://www.googleapis.com/auth/cloud-platform",
|
|
40
|
-
aud: account.tokenUri,
|
|
41
|
-
iat: issuedAt,
|
|
42
|
-
exp: issuedAt + expiresIn
|
|
43
|
-
})
|
|
44
|
-
);
|
|
45
|
-
const signingInput = `${header}.${claims}`;
|
|
46
|
-
const signature = createSign("RSA-SHA256").update(signingInput).sign(account.privateKey);
|
|
47
|
-
const jwt = `${signingInput}.${base64UrlEncode(signature)}`;
|
|
48
|
-
const response = await fetchImpl(account.tokenUri, {
|
|
49
|
-
method: "POST",
|
|
50
|
-
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
51
|
-
body: new URLSearchParams({
|
|
52
|
-
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
53
|
-
assertion: jwt
|
|
54
|
-
})
|
|
55
|
-
});
|
|
56
|
-
if (!response.ok) {
|
|
57
|
-
throw new Error(`Vertex token exchange failed: HTTP ${response.status}`);
|
|
58
|
-
}
|
|
59
|
-
const data = await response.json();
|
|
60
|
-
cachedToken = { accessToken: data.access_token, expiresAt: now + data.expires_in * 1e3 };
|
|
61
|
-
return data.access_token;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// src/image.ts
|
|
65
|
-
var DEFAULT_IMAGE_MODELS2 = [
|
|
66
|
-
{ model: "gemini-3.1-flash-image", location: "global" },
|
|
67
|
-
{ model: "gemini-2.5-flash-image", location: "us-central1" }
|
|
68
|
-
];
|
|
69
|
-
function defaultLocation(model) {
|
|
70
|
-
return /^gemini-3/.test(model) ? "global" : "us-central1";
|
|
71
|
-
}
|
|
72
|
-
function imageModelChain(config) {
|
|
73
|
-
const chain = config.model ? [{ model: config.model, location: config.location ?? defaultLocation(config.model) }] : [];
|
|
74
|
-
for (const candidate of DEFAULT_IMAGE_MODELS2) {
|
|
75
|
-
if (!chain.some((entry) => entry.model === candidate.model)) chain.push(candidate);
|
|
76
|
-
}
|
|
77
|
-
return chain;
|
|
78
|
-
}
|
|
79
|
-
function endpoint(project, target, method) {
|
|
80
|
-
const host = target.location === "global" ? "aiplatform.googleapis.com" : `${target.location}-aiplatform.googleapis.com`;
|
|
81
|
-
return `https://${host}/v1/projects/${project}/locations/${target.location}/publishers/google/models/${target.model}:${method}`;
|
|
82
|
-
}
|
|
83
|
-
function requestFor(target, prompt, aspectRatio) {
|
|
84
|
-
if (target.model.startsWith("imagen-")) {
|
|
85
|
-
return {
|
|
86
|
-
method: "predict",
|
|
87
|
-
body: {
|
|
88
|
-
instances: [{ prompt }],
|
|
89
|
-
parameters: { sampleCount: 1, aspectRatio, safetySetting: "block_medium_and_above", personGeneration: "allow_adult" }
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
method: "generateContent",
|
|
95
|
-
body: {
|
|
96
|
-
contents: [{ role: "user", parts: [{ text: prompt }] }],
|
|
97
|
-
generationConfig: { responseModalities: ["IMAGE"], imageConfig: { aspectRatio } }
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function extractImage(data) {
|
|
102
|
-
const prediction = data?.predictions?.[0];
|
|
103
|
-
if (prediction?.bytesBase64Encoded) return { base64: prediction.bytesBase64Encoded, mimeType: prediction.mimeType || "image/png" };
|
|
104
|
-
const parts = data?.candidates?.[0]?.content?.parts;
|
|
105
|
-
const inline = parts?.find((part) => part.inlineData?.data)?.inlineData;
|
|
106
|
-
return inline?.data ? { base64: inline.data, mimeType: inline.mimeType || "image/png" } : null;
|
|
107
|
-
}
|
|
108
|
-
async function generateImageVertex(prompt, config, options = {}) {
|
|
109
|
-
const fetchImpl = options.fetchImpl ?? fetch;
|
|
110
|
-
const aspectRatio = options.aspectRatio ?? "16:9";
|
|
111
|
-
let accessToken;
|
|
112
|
-
try {
|
|
113
|
-
accessToken = await getVertexAccessToken(
|
|
114
|
-
{ clientEmail: config.clientEmail, privateKey: config.privateKey, tokenUri: config.tokenUri },
|
|
115
|
-
fetchImpl
|
|
116
|
-
);
|
|
117
|
-
} catch (error) {
|
|
118
|
-
return { ok: false, error: `Image generation failed: ${error instanceof Error ? error.message : "authentication error"}` };
|
|
119
|
-
}
|
|
120
|
-
const failures = [];
|
|
121
|
-
for (const target of imageModelChain(config)) {
|
|
122
|
-
if (options.signal?.aborted) return { ok: false, error: "Image generation timed out." };
|
|
123
|
-
const { method, body } = requestFor(target, prompt, aspectRatio);
|
|
124
|
-
try {
|
|
125
|
-
const response = await fetchImpl(endpoint(config.project, target, method), {
|
|
126
|
-
method: "POST",
|
|
127
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${accessToken}` },
|
|
128
|
-
signal: options.signal,
|
|
129
|
-
body: JSON.stringify(body)
|
|
130
|
-
});
|
|
131
|
-
if (!response.ok) {
|
|
132
|
-
failures.push(`${target.model}: HTTP ${response.status}`);
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
const image = extractImage(await response.json());
|
|
136
|
-
if (image) return { ok: true, ...image };
|
|
137
|
-
failures.push(`${target.model}: no image data`);
|
|
138
|
-
} catch (error) {
|
|
139
|
-
if (options.signal?.aborted) return { ok: false, error: "Image generation timed out." };
|
|
140
|
-
failures.push(`${target.model}: ${error instanceof Error ? error.message : "transport error"}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return { ok: false, error: `Image generation failed (${failures.join("; ")}).` };
|
|
144
|
-
}
|
|
145
|
-
function vertexImageAvailable(env) {
|
|
146
|
-
return vertexConfigured(env);
|
|
147
|
-
}
|
|
148
|
-
var FLUX_SIZE = {
|
|
149
|
-
"16:9": { width: 1344, height: 768 },
|
|
150
|
-
"4:3": { width: 1024, height: 768 },
|
|
151
|
-
"1:1": { width: 1024, height: 1024 }
|
|
152
|
-
};
|
|
153
|
-
function nvidiaImageRequest(model, prompt, aspectRatio, seed) {
|
|
154
|
-
const size = FLUX_SIZE[aspectRatio];
|
|
155
|
-
if (/schnell/.test(model)) return { prompt, ...size, steps: 4, seed };
|
|
156
|
-
return { prompt, ...size, steps: 30, cfg_scale: 3.5, mode: "base", seed };
|
|
157
|
-
}
|
|
158
|
-
function extractNvidiaImage(data) {
|
|
159
|
-
const artifact = data?.artifacts?.[0];
|
|
160
|
-
if (!artifact?.base64 || artifact.finishReason && artifact.finishReason !== "SUCCESS") return null;
|
|
161
|
-
const mimeType = artifact.base64.startsWith("/9j/") ? "image/jpeg" : artifact.base64.startsWith("UklG") ? "image/webp" : "image/png";
|
|
162
|
-
return { base64: artifact.base64, mimeType };
|
|
163
|
-
}
|
|
164
|
-
async function postForImage(model, url, init, extract, options) {
|
|
165
|
-
try {
|
|
166
|
-
const response = await (options.fetchImpl ?? fetch)(url, {
|
|
167
|
-
method: "POST",
|
|
168
|
-
headers: { "content-type": "application/json", ...init.headers },
|
|
169
|
-
signal: options.signal,
|
|
170
|
-
body: JSON.stringify(init.body)
|
|
171
|
-
});
|
|
172
|
-
if (!response.ok) return { ok: false, error: `${model}: HTTP ${response.status}` };
|
|
173
|
-
const image = extract(await response.json());
|
|
174
|
-
return image ? { ok: true, ...image } : { ok: false, error: `${model}: no image (filtered or empty)` };
|
|
175
|
-
} catch (error) {
|
|
176
|
-
if (options.signal?.aborted) return { ok: false, error: "Image generation timed out." };
|
|
177
|
-
return { ok: false, error: `${model}: ${error instanceof Error ? error.message : "transport error"}` };
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
function generateImageNvidia(prompt, config, aspectRatio, options) {
|
|
181
|
-
return postForImage(
|
|
182
|
-
config.model,
|
|
183
|
-
`https://ai.api.nvidia.com/v1/genai/${config.model}`,
|
|
184
|
-
{
|
|
185
|
-
headers: { authorization: `Bearer ${config.apiKey}`, accept: "application/json" },
|
|
186
|
-
body: nvidiaImageRequest(config.model, prompt, aspectRatio, Math.floor(Math.random() * 2 ** 31))
|
|
187
|
-
},
|
|
188
|
-
extractNvidiaImage,
|
|
189
|
-
options
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
function generateImageGemini(prompt, config, aspectRatio, options) {
|
|
193
|
-
return postForImage(
|
|
194
|
-
config.model,
|
|
195
|
-
`https://generativelanguage.googleapis.com/v1beta/models/${config.model}:generateContent`,
|
|
196
|
-
{
|
|
197
|
-
headers: { "x-goog-api-key": config.apiKey },
|
|
198
|
-
body: { contents: [{ role: "user", parts: [{ text: prompt }] }], generationConfig: { responseModalities: ["IMAGE"], imageConfig: { aspectRatio } } }
|
|
199
|
-
},
|
|
200
|
-
extractImage,
|
|
201
|
-
options
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
function imageConfigFromEnv(env) {
|
|
205
|
-
const models = imageModels(env);
|
|
206
|
-
const paid = paidAllowed(env);
|
|
207
|
-
const config = {};
|
|
208
|
-
if (env.NVIDIA_API_KEY) config.nvidia = { apiKey: env.NVIDIA_API_KEY, model: models.nvidia };
|
|
209
|
-
if (paid && env.GEMINI_API_KEY) config.gemini = { apiKey: env.GEMINI_API_KEY, model: models.gemini };
|
|
210
|
-
if (paid && vertexImageAvailable(env)) {
|
|
211
|
-
config.vertex = {
|
|
212
|
-
clientEmail: env.GOOGLE_CLIENT_EMAIL,
|
|
213
|
-
privateKey: env.GOOGLE_PRIVATE_KEY,
|
|
214
|
-
tokenUri: env.GOOGLE_TOKEN_URI,
|
|
215
|
-
project: env.GOOGLE_CLOUD_PROJECT,
|
|
216
|
-
model: models.vertex
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return config.nvidia || config.gemini || config.vertex ? config : null;
|
|
220
|
-
}
|
|
221
|
-
async function generateImage(prompt, config, options = {}) {
|
|
222
|
-
const aspectRatio = options.aspectRatio ?? "16:9";
|
|
223
|
-
const attempts = [];
|
|
224
|
-
if (config.nvidia) attempts.push(() => generateImageNvidia(prompt, config.nvidia, aspectRatio, options));
|
|
225
|
-
if (config.gemini) attempts.push(() => generateImageGemini(prompt, config.gemini, aspectRatio, options));
|
|
226
|
-
if (config.vertex) attempts.push(() => generateImageVertex(prompt, config.vertex, options));
|
|
227
|
-
const failures = [];
|
|
228
|
-
for (const run of attempts) {
|
|
229
|
-
if (options.signal?.aborted) return { ok: false, error: "Image generation timed out." };
|
|
230
|
-
const outcome = await run();
|
|
231
|
-
if (outcome.ok) return outcome;
|
|
232
|
-
failures.push(outcome.error);
|
|
233
|
-
}
|
|
234
|
-
return { ok: false, error: failures.length ? `Image generation failed (${failures.join("; ")}).` : "No image provider is configured." };
|
|
235
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_IMAGE_MODELS,
|
|
3
|
+
extractImage,
|
|
4
|
+
extractNvidiaImage,
|
|
5
|
+
generateImage,
|
|
6
|
+
generateImageVertex,
|
|
7
|
+
imageConfigFromEnv,
|
|
8
|
+
imageModelChain,
|
|
9
|
+
nvidiaImageRequest,
|
|
10
|
+
vertexImageAvailable
|
|
11
|
+
} from "./chunk-MRNQPHWI.js";
|
|
12
|
+
import "./chunk-BL4J2JNX.js";
|
|
13
|
+
import "./chunk-RBSLNDFW.js";
|
|
236
14
|
export {
|
|
237
|
-
|
|
15
|
+
DEFAULT_IMAGE_MODELS,
|
|
238
16
|
extractImage,
|
|
239
17
|
extractNvidiaImage,
|
|
240
18
|
generateImage,
|
package/dist/index.js
CHANGED
|
@@ -1,105 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
});
|
|
7
|
-
var ON = ["1", "true", "yes", "on"];
|
|
8
|
-
var flag = z.string().optional().transform((value) => ON.includes((value ?? "").trim().toLowerCase()));
|
|
9
|
-
var flagDefaultOn = z.string().optional().transform((value) => {
|
|
10
|
-
const normalized = (value ?? "").trim().toLowerCase();
|
|
11
|
-
return normalized === "" || ON.includes(normalized);
|
|
12
|
-
});
|
|
13
|
-
var privateKey = text.transform((value) => value?.replace(/\\n/g, "\n"));
|
|
14
|
-
var DEFAULT_GOOGLE_TOKEN_URI = "https://oauth2.googleapis.com/token";
|
|
15
|
-
var aiEnvSchema = z.object({
|
|
16
|
-
// Paid providers (Vertex text and images, Gemini images) join the chains
|
|
17
|
-
// only with AI_ALLOW_PAID; off by default, so AI costs $0.
|
|
18
|
-
AI_ALLOW_PAID: flag,
|
|
19
|
-
// Feature switches. The blog assistant is off until turned on; the chatbot
|
|
20
|
-
// is on unless turned off. Each also needs a text provider key.
|
|
21
|
-
ENABLE_BLOG_AI: flag,
|
|
22
|
-
ENABLE_CHATBOT: flagDefaultOn,
|
|
23
|
-
OPENROUTER_BASE_URL: text,
|
|
24
|
-
OPENROUTER_API_KEY: text,
|
|
25
|
-
OPENROUTER_API_KEY_2: text,
|
|
26
|
-
OPENROUTER_ALLOW_PAID_MODELS: flag,
|
|
27
|
-
GEMINI_API_KEY: text,
|
|
28
|
-
NVIDIA_API_KEY: text,
|
|
29
|
-
// Model overrides, all optional (models.ts): purpose variable, then the
|
|
30
|
-
// provider-wide *_MODEL, then a verified free default.
|
|
31
|
-
OPENROUTER_MODEL: text,
|
|
32
|
-
GEMINI_MODEL: text,
|
|
33
|
-
NVIDIA_MODEL: text,
|
|
34
|
-
VERTEX_MODEL: text,
|
|
35
|
-
IMAGEN_MODEL: text,
|
|
36
|
-
BLOG_GEMINI_MODEL: text,
|
|
37
|
-
BLOG_OPENROUTER_MODEL: text,
|
|
38
|
-
BLOG_NVIDIA_MODEL: text,
|
|
39
|
-
BLOG_VERTEX_MODEL: text,
|
|
40
|
-
CHAT_GEMINI_MODEL: text,
|
|
41
|
-
CHAT_OPENROUTER_MODEL: text,
|
|
42
|
-
CHAT_NVIDIA_MODEL: text,
|
|
43
|
-
CHAT_VERTEX_MODEL: text,
|
|
44
|
-
IMAGE_NVIDIA_MODEL: text,
|
|
45
|
-
IMAGE_GEMINI_MODEL: text,
|
|
46
|
-
IMAGE_VERTEX_MODEL: text,
|
|
47
|
-
// Provider order (./adapters). Comma-separated adapter ids; only the listed
|
|
48
|
-
// ones run, in that order. Per purpose first, then the global one; unset =
|
|
49
|
-
// the built-in order (free tiers first, paid last).
|
|
50
|
-
AI_PROVIDER_ORDER: text,
|
|
51
|
-
AI_PROVIDER_ORDER_BLOG: text,
|
|
52
|
-
AI_PROVIDER_ORDER_CHAT: text,
|
|
53
|
-
// Paid OpenAI-compatible and Anthropic providers: each joins a chain only
|
|
54
|
-
// with its key set and AI_ALLOW_PAID on. Models: purpose variable, then the
|
|
55
|
-
// provider-wide one, then the default in ./adapters.
|
|
56
|
-
OPENAI_API_KEY: text,
|
|
57
|
-
OPENAI_BASE_URL: text,
|
|
58
|
-
OPENAI_MODEL: text,
|
|
59
|
-
BLOG_OPENAI_MODEL: text,
|
|
60
|
-
CHAT_OPENAI_MODEL: text,
|
|
61
|
-
ANTHROPIC_API_KEY: text,
|
|
62
|
-
ANTHROPIC_BASE_URL: text,
|
|
63
|
-
ANTHROPIC_MODEL: text,
|
|
64
|
-
BLOG_ANTHROPIC_MODEL: text,
|
|
65
|
-
CHAT_ANTHROPIC_MODEL: text,
|
|
66
|
-
DEEPSEEK_API_KEY: text,
|
|
67
|
-
DEEPSEEK_MODEL: text,
|
|
68
|
-
BLOG_DEEPSEEK_MODEL: text,
|
|
69
|
-
CHAT_DEEPSEEK_MODEL: text,
|
|
70
|
-
XAI_API_KEY: text,
|
|
71
|
-
XAI_MODEL: text,
|
|
72
|
-
BLOG_XAI_MODEL: text,
|
|
73
|
-
CHAT_XAI_MODEL: text,
|
|
74
|
-
PERPLEXITY_API_KEY: text,
|
|
75
|
-
PERPLEXITY_MODEL: text,
|
|
76
|
-
BLOG_PERPLEXITY_MODEL: text,
|
|
77
|
-
CHAT_PERPLEXITY_MODEL: text,
|
|
78
|
-
// One custom OpenAI-compatible endpoint (a gateway, vLLM, Ollama, LiteLLM).
|
|
79
|
-
// Treated as paid unless AI_CUSTOM_FREE is on; the key is optional for a
|
|
80
|
-
// local server.
|
|
81
|
-
AI_CUSTOM_BASE_URL: text,
|
|
82
|
-
AI_CUSTOM_API_KEY: text,
|
|
83
|
-
AI_CUSTOM_MODEL: text,
|
|
84
|
-
AI_CUSTOM_NAME: text,
|
|
85
|
-
AI_CUSTOM_FREE: flag,
|
|
86
|
-
// Google Vertex service account (paid).
|
|
87
|
-
GOOGLE_CLIENT_EMAIL: text,
|
|
88
|
-
GOOGLE_PRIVATE_KEY: privateKey,
|
|
89
|
-
GOOGLE_CLOUD_PROJECT: text,
|
|
90
|
-
GOOGLE_TOKEN_URI: text.transform((value) => value ?? DEFAULT_GOOGLE_TOKEN_URI)
|
|
91
|
-
});
|
|
92
|
-
function parseAiEnv(source) {
|
|
93
|
-
const result = aiEnvSchema.safeParse(source);
|
|
94
|
-
if (!result.success) {
|
|
95
|
-
const names = [...new Set(result.error.issues.map((issue) => String(issue.path[0] ?? "?")))];
|
|
96
|
-
throw new Error(`Invalid AI environment variables: ${names.join(", ")}`);
|
|
97
|
-
}
|
|
98
|
-
return result.data;
|
|
99
|
-
}
|
|
100
|
-
function aiEnvFromProcess() {
|
|
101
|
-
return parseAiEnv(process.env);
|
|
102
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
aiEnvFromProcess,
|
|
3
|
+
aiEnvSchema,
|
|
4
|
+
parseAiEnv
|
|
5
|
+
} from "./chunk-SI7JE5BG.js";
|
|
103
6
|
export {
|
|
104
7
|
aiEnvFromProcess,
|
|
105
8
|
aiEnvSchema,
|
package/dist/log.js
CHANGED
package/dist/models.js
CHANGED
|
@@ -1,54 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Short, latency-sensitive replies: the fastest free model first.
|
|
11
|
-
chat: {
|
|
12
|
-
gemini: "gemini-3.1-flash-lite",
|
|
13
|
-
openrouter: "nvidia/nemotron-3-super-120b-a12b:free",
|
|
14
|
-
nvidia: "nvidia/nemotron-3-super-120b-a12b",
|
|
15
|
-
vertex: "gemini-2.5-flash"
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var DEFAULT_IMAGE_MODELS = {
|
|
19
|
-
nvidia: "black-forest-labs/flux.1-dev",
|
|
20
|
-
gemini: "gemini-3.1-flash-image",
|
|
21
|
-
vertex: "gemini-3.1-flash-image"
|
|
22
|
-
};
|
|
23
|
-
var pick = (...values) => values.find((value) => value && value.trim()).trim();
|
|
24
|
-
function textModels(env, purpose) {
|
|
25
|
-
const defaults = DEFAULT_TEXT_MODELS[purpose];
|
|
26
|
-
const own = purpose === "blog" ? { gemini: env.BLOG_GEMINI_MODEL, openrouter: env.BLOG_OPENROUTER_MODEL, nvidia: env.BLOG_NVIDIA_MODEL, vertex: env.BLOG_VERTEX_MODEL } : { gemini: env.CHAT_GEMINI_MODEL, openrouter: env.CHAT_OPENROUTER_MODEL, nvidia: env.CHAT_NVIDIA_MODEL, vertex: env.CHAT_VERTEX_MODEL };
|
|
27
|
-
return {
|
|
28
|
-
gemini: pick(own.gemini, env.GEMINI_MODEL, defaults.gemini),
|
|
29
|
-
openrouter: pick(own.openrouter, env.OPENROUTER_MODEL, defaults.openrouter),
|
|
30
|
-
nvidia: pick(own.nvidia, env.NVIDIA_MODEL, defaults.nvidia),
|
|
31
|
-
vertex: pick(own.vertex, env.VERTEX_MODEL, defaults.vertex)
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function imageModels(env) {
|
|
35
|
-
return {
|
|
36
|
-
nvidia: pick(env.IMAGE_NVIDIA_MODEL, DEFAULT_IMAGE_MODELS.nvidia),
|
|
37
|
-
gemini: pick(env.IMAGE_GEMINI_MODEL, DEFAULT_IMAGE_MODELS.gemini),
|
|
38
|
-
vertex: pick(env.IMAGE_VERTEX_MODEL, env.IMAGEN_MODEL, DEFAULT_IMAGE_MODELS.vertex)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
var paidAllowed = (env) => env.AI_ALLOW_PAID === true;
|
|
42
|
-
function vertexConfigured(env) {
|
|
43
|
-
return Boolean(env.GOOGLE_CLIENT_EMAIL && env.GOOGLE_PRIVATE_KEY && env.GOOGLE_CLOUD_PROJECT);
|
|
44
|
-
}
|
|
45
|
-
function thinkingConfigFor(model, maxOutputTokens) {
|
|
46
|
-
const long = maxOutputTokens >= 2e3;
|
|
47
|
-
if (/^gemini-[3-9]/.test(model)) {
|
|
48
|
-
return { thinkingLevel: long ? "low" : /flash/.test(model) ? "minimal" : "low" };
|
|
49
|
-
}
|
|
50
|
-
return { thinkingBudget: long ? Math.min(800, Math.floor(maxOutputTokens / 5)) : 0 };
|
|
51
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_IMAGE_MODELS,
|
|
3
|
+
DEFAULT_TEXT_MODELS,
|
|
4
|
+
imageModels,
|
|
5
|
+
paidAllowed,
|
|
6
|
+
textModels,
|
|
7
|
+
thinkingConfigFor,
|
|
8
|
+
vertexConfigured
|
|
9
|
+
} from "./chunk-RBSLNDFW.js";
|
|
52
10
|
export {
|
|
53
11
|
DEFAULT_IMAGE_MODELS,
|
|
54
12
|
DEFAULT_TEXT_MODELS,
|
package/dist/providers.d.ts
CHANGED
|
@@ -70,6 +70,13 @@ interface AiHealth {
|
|
|
70
70
|
declare const createAiHealth: () => AiHealth;
|
|
71
71
|
/** One per server instance, for request handlers; tests and scripts get a fresh one by default. */
|
|
72
72
|
declare const sharedAiHealth: AiHealth;
|
|
73
|
+
/**
|
|
74
|
+
* Quota and slowness pass quickly; a wrong key or a retired model needs an
|
|
75
|
+
* operator, so it cools longer; an empty prepaid wallet (402) needs someone to
|
|
76
|
+
* add funds, so it cools longest and costs one probe per half hour instead of
|
|
77
|
+
* a failed round trip on every request.
|
|
78
|
+
*/
|
|
79
|
+
declare function cooldownFor(outcome: AiOutcome): number;
|
|
73
80
|
interface AiServiceDeps {
|
|
74
81
|
providers: readonly AiProvider[];
|
|
75
82
|
/** Per-provider attempt budget. */
|
|
@@ -188,12 +195,35 @@ interface ProviderAdapter {
|
|
|
188
195
|
/** Lowercase id used in AI_PROVIDER_ORDER. */
|
|
189
196
|
readonly id: string;
|
|
190
197
|
readonly label: string;
|
|
198
|
+
/**
|
|
199
|
+
* Purposes it joins under the default order; unset means all. An explicit
|
|
200
|
+
* AI_PROVIDER_ORDER(_BLOG|_CHAT) still adds it anywhere it is listed.
|
|
201
|
+
*/
|
|
202
|
+
readonly defaultPurposes?: readonly TextPurpose[];
|
|
191
203
|
/** Costs money: runs only with AI_ALLOW_PAID. */
|
|
192
204
|
paid(env: AiEnv): boolean;
|
|
193
205
|
/** Env variable names still missing; empty means configured. Never values. */
|
|
194
206
|
missing(env: AiEnv): string[];
|
|
195
207
|
create(context: AdapterContext): AiProvider;
|
|
196
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Defaults for the free-tier adapters that take an id per purpose. The blog
|
|
211
|
+
* writes long JSON, so it gets the larger model; chat gets the faster one.
|
|
212
|
+
*/
|
|
213
|
+
declare const FREE_TEXT_MODELS: {
|
|
214
|
+
readonly groq: {
|
|
215
|
+
readonly blog: "openai/gpt-oss-120b";
|
|
216
|
+
readonly chat: "openai/gpt-oss-20b";
|
|
217
|
+
};
|
|
218
|
+
readonly mistral: {
|
|
219
|
+
readonly blog: "mistral-medium-latest";
|
|
220
|
+
readonly chat: "mistral-small-latest";
|
|
221
|
+
};
|
|
222
|
+
readonly cloudflare: {
|
|
223
|
+
readonly blog: "@cf/openai/gpt-oss-120b";
|
|
224
|
+
readonly chat: "@cf/openai/gpt-oss-20b";
|
|
225
|
+
};
|
|
226
|
+
};
|
|
197
227
|
/**
|
|
198
228
|
* Defaults for the paid adapters. Model names change often: set the
|
|
199
229
|
* provider's *_MODEL variable rather than relying on these.
|
|
@@ -290,4 +320,4 @@ declare function checkChain(env: AiEnv, purpose: TextPurpose, options?: {
|
|
|
290
320
|
*/
|
|
291
321
|
declare function realProviders(env: AiEnv, purpose: TextPurpose, fetchImpl?: typeof fetch, adapters?: readonly ProviderAdapter[]): AiProvider[];
|
|
292
322
|
|
|
293
|
-
export { type AdapterContext as A, AI_COOLDOWN_MS, AI_TIMEOUT_MS, type AiAttempt, type AiAttemptStatus, type AiGenerateOptions, type AiHealth, type AiOutcome, type AiProvider, type AiResult, type AiServiceDeps, BUILTIN_ADAPTERS as B, CHECK_PROMPT as C, DEFAULT_ORDER as D, HEDGE, type JsonMode, PAID_TEXT_MODELS as P, type AdapterState as a, anthropicOutcome, anthropicProvider, type AdapterStatus as b, type ProviderAdapter as c, createAiHealth, createAiService, type ProviderCheck as d, chainPlan as e, checkChain as f, checkProvider as g, geminiOutcome, geminiProvider, configuredOrder as h, nvidiaProvider, openAiCompatibleProvider, openRouterProvider, providerStatuses as p, realProviders, sharedAiHealth, vertexProvider };
|
|
323
|
+
export { type AdapterContext as A, AI_COOLDOWN_MS, AI_TIMEOUT_MS, type AiAttempt, type AiAttemptStatus, type AiGenerateOptions, type AiHealth, type AiOutcome, type AiProvider, type AiResult, type AiServiceDeps, BUILTIN_ADAPTERS as B, CHECK_PROMPT as C, DEFAULT_ORDER as D, FREE_TEXT_MODELS as F, HEDGE, type JsonMode, PAID_TEXT_MODELS as P, type AdapterState as a, anthropicOutcome, anthropicProvider, type AdapterStatus as b, type ProviderAdapter as c, cooldownFor, createAiHealth, createAiService, type ProviderCheck as d, chainPlan as e, checkChain as f, checkProvider as g, geminiOutcome, geminiProvider, configuredOrder as h, nvidiaProvider, openAiCompatibleProvider, openRouterProvider, providerStatuses as p, realProviders, sharedAiHealth, vertexProvider };
|