@broberg/ai-sdk 0.36.5 → 0.36.7
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/dist/index.d.ts +11 -5
- package/dist/index.js +26 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export { AvailabilitySource, AvailabilityStatus, ModelStatus, ModelUnavailableEr
|
|
|
17
17
|
type Region = "eu" | "us" | "cn" | "unknown";
|
|
18
18
|
/** Region of the endpoint a call will actually hit. Never throws — a residency
|
|
19
19
|
* reading must not be able to break a call that already succeeded. */
|
|
20
|
-
declare function regionOfHost(
|
|
20
|
+
declare function regionOfHost(hostOrUrl: string | undefined): Region;
|
|
21
21
|
/** Classify a provider REGION STRING — a Vertex/GCP location like `europe-west1`, or
|
|
22
22
|
* an Azure region like `westeurope`. Anything unrecognised is `"unknown"`: a region
|
|
23
23
|
* name we have never seen is exactly the case where guessing is most tempting and
|
|
@@ -273,7 +273,9 @@ interface ImageResult {
|
|
|
273
273
|
}
|
|
274
274
|
/** Image-to-video generation (F024) — animate a still into a short clip. */
|
|
275
275
|
interface AnimateRequest {
|
|
276
|
-
/** Input image: a URL (passed through) or raw bytes
|
|
276
|
+
/** Input image: a URL (passed through) or raw bytes. Where bytes are uploaded is
|
|
277
|
+
* the ADAPTER's business — fal uses fal storage, the Gemini/Veo default inlines
|
|
278
|
+
* them — so do not read a storage provider out of this field. */
|
|
277
279
|
image: string | Uint8Array;
|
|
278
280
|
/** Motion/scene prompt, e.g. "the subject turns and smiles". */
|
|
279
281
|
prompt?: string;
|
|
@@ -446,7 +448,11 @@ interface ProviderAdapter {
|
|
|
446
448
|
translate?(req: TranslateRequest): Promise<TranslateResult>;
|
|
447
449
|
vision?(req: ChatRequest): Promise<ChatResult>;
|
|
448
450
|
image?(req: ImageRequest): Promise<ImageResult>;
|
|
449
|
-
/** Image-to-video generation (F024) — animate a still into a short clip.
|
|
451
|
+
/** Image-to-video generation (F024) — animate a still into a short clip. gemini
|
|
452
|
+
* (Veo 3.1) by default; override to fal for Kling/Seedance. Name only the DEFAULT
|
|
453
|
+
* route here — provider-doc-drift.test.ts fails if this and DEFAULT_ANIMATE_SPEC
|
|
454
|
+
* disagree, because this sentence is the editor tooltip a consumer reads when
|
|
455
|
+
* deciding which API key to buy. */
|
|
450
456
|
animate?(req: AnimateRequest): Promise<AnimateResult>;
|
|
451
457
|
/** Train a style/brand LoRA from images (F021). fal. */
|
|
452
458
|
trainStyle?(req: TrainStyleRequest): Promise<TrainStyleResult>;
|
|
@@ -2200,8 +2206,8 @@ declare const falStubAdapter: ProviderAdapter;
|
|
|
2200
2206
|
* wires the live adapters. */
|
|
2201
2207
|
declare const stubProviders: Record<string, ProviderAdapter>;
|
|
2202
2208
|
|
|
2203
|
-
declare const VERSION: "0.36.
|
|
2204
|
-
declare const SDK_TAG: "@broberg/ai-sdk@0.36.
|
|
2209
|
+
declare const VERSION: "0.36.7";
|
|
2210
|
+
declare const SDK_TAG: "@broberg/ai-sdk@0.36.7";
|
|
2205
2211
|
|
|
2206
2212
|
/** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
|
|
2207
2213
|
* per-call override.
|
package/dist/index.js
CHANGED
|
@@ -241,14 +241,20 @@ var HOST_REGION = {
|
|
|
241
241
|
"openrouter.ai": "unknown",
|
|
242
242
|
"router.requesty.ai": "unknown"
|
|
243
243
|
};
|
|
244
|
-
function regionOfHost(
|
|
245
|
-
if (!
|
|
244
|
+
function regionOfHost(hostOrUrl) {
|
|
245
|
+
if (!hostOrUrl) return "unknown";
|
|
246
|
+
const trimmed = hostOrUrl.trim();
|
|
247
|
+
if (!trimmed) return "unknown";
|
|
248
|
+
let host = "";
|
|
246
249
|
try {
|
|
247
|
-
|
|
248
|
-
return Object.hasOwn(HOST_REGION, host) ? HOST_REGION[host] : "unknown";
|
|
250
|
+
host = new URL(trimmed).host;
|
|
249
251
|
} catch {
|
|
250
|
-
return "unknown";
|
|
251
252
|
}
|
|
253
|
+
if (!host) {
|
|
254
|
+
host = trimmed.split("/")[0].split("@").pop().split(":")[0];
|
|
255
|
+
}
|
|
256
|
+
host = host.toLowerCase();
|
|
257
|
+
return Object.hasOwn(HOST_REGION, host) ? HOST_REGION[host] : "unknown";
|
|
252
258
|
}
|
|
253
259
|
var FIXED_PROVIDER_REGION = {
|
|
254
260
|
// NB: mistral and deepl are deliberately ABSENT — both take a config.baseUrl, so
|
|
@@ -303,6 +309,7 @@ function classifyRegionName(name) {
|
|
|
303
309
|
if (!name) return "unknown";
|
|
304
310
|
const n = name.trim().toLowerCase();
|
|
305
311
|
if (!n) return "unknown";
|
|
312
|
+
if (n === "eu" || n === "us" || n === "cn" || n === "unknown") return n;
|
|
306
313
|
if (n.startsWith("europe-")) return "eu";
|
|
307
314
|
if (n.startsWith("us-")) return "us";
|
|
308
315
|
if (EU_REGION_NAMES.has(n)) return "eu";
|
|
@@ -952,7 +959,7 @@ function geminiAdapter(config = {}) {
|
|
|
952
959
|
const baseUrl = config.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta";
|
|
953
960
|
function resolveKey() {
|
|
954
961
|
const apiKey = config.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
955
|
-
if (!apiKey) throw new Error("gemini adapter: API key not set (env GOOGLE_API_KEY)");
|
|
962
|
+
if (!apiKey) throw new Error("gemini adapter: API key not set (env GOOGLE_API_KEY or GEMINI_API_KEY)");
|
|
956
963
|
return apiKey;
|
|
957
964
|
}
|
|
958
965
|
function buildBody(req) {
|
|
@@ -1991,7 +1998,7 @@ function falAdapter(config = {}) {
|
|
|
1991
1998
|
});
|
|
1992
1999
|
async function image(req) {
|
|
1993
2000
|
const apiKey = resolveKey();
|
|
1994
|
-
if (!apiKey) throw new Error("fal adapter:
|
|
2001
|
+
if (!apiKey) throw new Error("fal adapter: API key not set (env FAL_KEY or FAL_API_KEY)");
|
|
1995
2002
|
const headers = authHeaders(apiKey);
|
|
1996
2003
|
const body = { prompt: req.prompt };
|
|
1997
2004
|
if (req.width !== void 0 && req.height !== void 0) {
|
|
@@ -2021,7 +2028,7 @@ function falAdapter(config = {}) {
|
|
|
2021
2028
|
}
|
|
2022
2029
|
async function animate(req) {
|
|
2023
2030
|
const apiKey = resolveKey();
|
|
2024
|
-
if (!apiKey) throw new Error("fal adapter:
|
|
2031
|
+
if (!apiKey) throw new Error("fal adapter: API key not set (env FAL_KEY or FAL_API_KEY)");
|
|
2025
2032
|
const headers = authHeaders(apiKey);
|
|
2026
2033
|
const imageUrl = typeof req.image === "string" && /^https?:\/\//i.test(req.image) ? req.image : await uploadToFalStorage(toBytes(req.image), sniffImageType(req.image), "input", apiKey);
|
|
2027
2034
|
const body = { image_url: imageUrl };
|
|
@@ -2051,7 +2058,7 @@ function falAdapter(config = {}) {
|
|
|
2051
2058
|
}
|
|
2052
2059
|
async function trainStyle(req) {
|
|
2053
2060
|
const apiKey = resolveKey();
|
|
2054
|
-
if (!apiKey) throw new Error("fal adapter:
|
|
2061
|
+
if (!apiKey) throw new Error("fal adapter: API key not set (env FAL_KEY or FAL_API_KEY)");
|
|
2055
2062
|
const headers = authHeaders(apiKey);
|
|
2056
2063
|
const body = {
|
|
2057
2064
|
images_data_url: await resolveImagesUrl(req.images, apiKey),
|
|
@@ -2986,8 +2993,8 @@ var aiConfigSchema = z.object({
|
|
|
2986
2993
|
});
|
|
2987
2994
|
|
|
2988
2995
|
// src/version.ts
|
|
2989
|
-
var VERSION = "0.36.
|
|
2990
|
-
var SDK_TAG = "@broberg/ai-sdk@0.36.
|
|
2996
|
+
var VERSION = "0.36.7";
|
|
2997
|
+
var SDK_TAG = "@broberg/ai-sdk@0.36.7";
|
|
2991
2998
|
|
|
2992
2999
|
// src/cost/sinks/upmetrics.ts
|
|
2993
3000
|
function upmetricsSink(config) {
|
|
@@ -3083,6 +3090,11 @@ var DEFAULT_ANIMATE_SPEC = {
|
|
|
3083
3090
|
transport: "http"
|
|
3084
3091
|
};
|
|
3085
3092
|
var ANIMATE_AUDIO_DIRECTIVE = "No spoken dialogue, no talking, no voiceover. Include natural ambient background sounds that match the environment.";
|
|
3093
|
+
function routeHasAudio(spec) {
|
|
3094
|
+
const m = spec.model.toLowerCase();
|
|
3095
|
+
if (m.includes("kling") || m.includes("seedance") || m.includes("wan-")) return false;
|
|
3096
|
+
return true;
|
|
3097
|
+
}
|
|
3086
3098
|
var DEFAULT_BFL_FINETUNE_SPEC = {
|
|
3087
3099
|
provider: "bfl",
|
|
3088
3100
|
model: "flux-pro-1.1-ultra-finetuned",
|
|
@@ -3398,7 +3410,7 @@ function createAI(config = {}) {
|
|
|
3398
3410
|
},
|
|
3399
3411
|
async animate(input) {
|
|
3400
3412
|
input = animateInputSchema.parse(input);
|
|
3401
|
-
const
|
|
3413
|
+
const basePrompt = input.prompt?.trim() ?? "";
|
|
3402
3414
|
return runCapability({
|
|
3403
3415
|
primary: withOverride(DEFAULT_ANIMATE_SPEC, input.override, "animate"),
|
|
3404
3416
|
fallback: input.fallback,
|
|
@@ -3411,9 +3423,10 @@ function createAI(config = {}) {
|
|
|
3411
3423
|
invoke: async (spec) => {
|
|
3412
3424
|
const adapter = pickProvider(spec.provider);
|
|
3413
3425
|
if (!adapter.animate) throw new Error(`createAI: provider "${spec.provider}" does not support animate`);
|
|
3426
|
+
const prompt = routeHasAudio(spec) ? `${basePrompt} ${ANIMATE_AUDIO_DIRECTIVE}`.trim() : basePrompt;
|
|
3414
3427
|
return adapter.animate({
|
|
3415
3428
|
image: input.image,
|
|
3416
|
-
prompt,
|
|
3429
|
+
prompt: prompt || void 0,
|
|
3417
3430
|
durationSec: input.durationSec,
|
|
3418
3431
|
resolution: input.resolution,
|
|
3419
3432
|
spec
|