@shop-os/modelkit 0.2.10 → 0.2.11
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 +11 -0
- package/README.md +61 -0
- package/dist/catalog.cjs +12 -1
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +23 -4
- package/dist/catalog.d.ts +23 -4
- package/dist/catalog.js +12 -1
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +199 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -5
- package/dist/index.d.ts +29 -5
- package/dist/index.js +196 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ __export(index_exports, {
|
|
|
63
63
|
generateVideo: () => generateVideo,
|
|
64
64
|
googleGenaiAdapter: () => googleGenaiAdapter,
|
|
65
65
|
googleImageAdapter: () => googleImageAdapter,
|
|
66
|
+
hasAwsCredentials: () => hasAwsCredentials,
|
|
66
67
|
higgsfieldAdapter: () => higgsfieldAdapter,
|
|
67
68
|
isListed: () => isListed,
|
|
68
69
|
isListedOn: () => isListedOn,
|
|
@@ -100,6 +101,14 @@ __export(index_exports, {
|
|
|
100
101
|
module.exports = __toCommonJS(index_exports);
|
|
101
102
|
__reExport(index_exports, require("ai"), module.exports);
|
|
102
103
|
|
|
104
|
+
// src/types.ts
|
|
105
|
+
function hasAwsCredentials(aws) {
|
|
106
|
+
if (!aws || !aws.region) return false;
|
|
107
|
+
if (aws.apiKey) return true;
|
|
108
|
+
if (aws.credentialProvider) return true;
|
|
109
|
+
return Boolean(aws.accessKeyId && aws.secretAccessKey);
|
|
110
|
+
}
|
|
111
|
+
|
|
103
112
|
// src/errors.ts
|
|
104
113
|
var ModelKitError = class extends Error {
|
|
105
114
|
code;
|
|
@@ -2136,7 +2145,18 @@ var CatalogModelSchemaBase = import_zod.z.looseObject({
|
|
|
2136
2145
|
});
|
|
2137
2146
|
}
|
|
2138
2147
|
});
|
|
2139
|
-
var CatalogModelSchema = CatalogModelSchemaBase
|
|
2148
|
+
var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
|
|
2149
|
+
(row, ctx) => {
|
|
2150
|
+
const transport = row.providerOptions?.["modelkit"]?.["transport"];
|
|
2151
|
+
if (transport !== void 0 && transport !== "direct" && transport !== "bedrock") {
|
|
2152
|
+
ctx.addIssue({
|
|
2153
|
+
code: "custom",
|
|
2154
|
+
path: ["providerOptions", "modelkit", "transport"],
|
|
2155
|
+
message: 'transport must be "direct" or "bedrock"'
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
);
|
|
2140
2160
|
var CatalogSchema = import_zod.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
|
|
2141
2161
|
const seenIds = /* @__PURE__ */ new Map();
|
|
2142
2162
|
rows.forEach((row, index) => {
|
|
@@ -2741,9 +2761,12 @@ var ADAPTER_KEYS = {
|
|
|
2741
2761
|
function hasAll(keys, names) {
|
|
2742
2762
|
if (!keys) return false;
|
|
2743
2763
|
return names.every(
|
|
2744
|
-
(n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
|
|
2764
|
+
(n) => n === "aws" ? hasAwsCredentials(keys.aws) : Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
|
|
2745
2765
|
);
|
|
2746
2766
|
}
|
|
2767
|
+
function hasKey(keys, name) {
|
|
2768
|
+
return hasAll(keys, [name]);
|
|
2769
|
+
}
|
|
2747
2770
|
function missingEnterpriseKeys(config, names) {
|
|
2748
2771
|
return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
|
|
2749
2772
|
}
|
|
@@ -2780,6 +2803,22 @@ function keysFromEnv(env, prefix = "") {
|
|
|
2780
2803
|
set("higgsfield", pick("HIGGSFIELD_API_KEY"));
|
|
2781
2804
|
set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
|
|
2782
2805
|
set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
2806
|
+
const bearer = pick("AWS_BEARER_TOKEN_BEDROCK");
|
|
2807
|
+
const accessKeyId = pick("AWS_ACCESS_KEY_ID");
|
|
2808
|
+
const secretAccessKey = pick("AWS_SECRET_ACCESS_KEY");
|
|
2809
|
+
if (bearer || accessKeyId && secretAccessKey) {
|
|
2810
|
+
const aws = {
|
|
2811
|
+
region: env[`${prefix}BEDROCK_REGION`] || "us-east-1"
|
|
2812
|
+
};
|
|
2813
|
+
if (accessKeyId && secretAccessKey) {
|
|
2814
|
+
aws.accessKeyId = accessKeyId;
|
|
2815
|
+
aws.secretAccessKey = secretAccessKey;
|
|
2816
|
+
}
|
|
2817
|
+
const sessionToken = pick("AWS_SESSION_TOKEN");
|
|
2818
|
+
if (sessionToken) aws.sessionToken = sessionToken;
|
|
2819
|
+
if (bearer) aws.apiKey = bearer;
|
|
2820
|
+
keys.aws = aws;
|
|
2821
|
+
}
|
|
2783
2822
|
return keys;
|
|
2784
2823
|
}
|
|
2785
2824
|
|
|
@@ -3108,7 +3147,8 @@ function toGeneratedImage(image) {
|
|
|
3108
3147
|
}
|
|
3109
3148
|
|
|
3110
3149
|
// src/adapters/ai-sdk-text.ts
|
|
3111
|
-
var import_anthropic = require("@ai-sdk/anthropic");
|
|
3150
|
+
var import_anthropic = require("@ai-sdk/amazon-bedrock/anthropic");
|
|
3151
|
+
var import_anthropic2 = require("@ai-sdk/anthropic");
|
|
3112
3152
|
var import_google = require("@ai-sdk/google");
|
|
3113
3153
|
var import_openai = require("@ai-sdk/openai");
|
|
3114
3154
|
var import_openai_compatible = require("@ai-sdk/openai-compatible");
|
|
@@ -3159,16 +3199,47 @@ function detectTextProvider(modelId) {
|
|
|
3159
3199
|
message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
|
|
3160
3200
|
});
|
|
3161
3201
|
}
|
|
3162
|
-
function textKeyName(model,
|
|
3163
|
-
|
|
3202
|
+
function textKeyName(model, transport) {
|
|
3203
|
+
const provider = textProviderOf(model);
|
|
3204
|
+
return provider === "anthropic" && transport === "bedrock" ? "aws" : provider;
|
|
3164
3205
|
}
|
|
3165
3206
|
function textProviderOf(model) {
|
|
3166
3207
|
const explicit = model.providerOptions?.["modelkit"]?.["provider"];
|
|
3167
3208
|
return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
|
|
3168
3209
|
}
|
|
3169
|
-
function textUsesCloudflareGateway(model, routing) {
|
|
3210
|
+
function textUsesCloudflareGateway(model, routing, transport) {
|
|
3170
3211
|
if (routing.text !== "cloudflare") return false;
|
|
3171
|
-
|
|
3212
|
+
const provider = textProviderOf(model);
|
|
3213
|
+
if (provider === "anthropic" && transport === "bedrock") return false;
|
|
3214
|
+
return GATEWAY_SLUGS[provider] !== void 0;
|
|
3215
|
+
}
|
|
3216
|
+
var BEDROCK_DATED_MODEL_IDS = {
|
|
3217
|
+
"claude-haiku-4-5": "anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
3218
|
+
"claude-haiku-4-5-20251001": "anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
3219
|
+
"claude-sonnet-4-5": "anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
3220
|
+
"claude-sonnet-4-5-20250929": "anthropic.claude-sonnet-4-5-20250929-v1:0"
|
|
3221
|
+
};
|
|
3222
|
+
var BEDROCK_PROFILE_PREFIXES = ["us.", "global.", "eu.", "jp.", "au.", "apac."];
|
|
3223
|
+
function toBedrockModelId(model, routing) {
|
|
3224
|
+
const profile = routing.bedrockProfile ?? "us";
|
|
3225
|
+
const override = model.providerOptions?.["modelkit"]?.["bedrockModelId"];
|
|
3226
|
+
if (typeof override === "string" && override.length > 0) {
|
|
3227
|
+
if (BEDROCK_PROFILE_PREFIXES.some((prefix) => override.startsWith(prefix))) return override;
|
|
3228
|
+
if (override.startsWith("anthropic.")) return `${profile}.${override}`;
|
|
3229
|
+
return override;
|
|
3230
|
+
}
|
|
3231
|
+
const id = model.providerModelId;
|
|
3232
|
+
if (BEDROCK_PROFILE_PREFIXES.some((prefix) => id.startsWith(prefix))) return id;
|
|
3233
|
+
const dated = BEDROCK_DATED_MODEL_IDS[id];
|
|
3234
|
+
if (dated) return `${profile}.${dated}`;
|
|
3235
|
+
if (id.startsWith("claude-")) return `${profile}.anthropic.${id}`;
|
|
3236
|
+
throw new ModelKitError({
|
|
3237
|
+
code: "unsupported_option",
|
|
3238
|
+
message: `No Bedrock model id for "${id}". Set providerOptions.modelkit.bedrockModelId on the catalog row.`,
|
|
3239
|
+
provider: "ai-sdk-text",
|
|
3240
|
+
model: model.id,
|
|
3241
|
+
retryable: false
|
|
3242
|
+
});
|
|
3172
3243
|
}
|
|
3173
3244
|
function nativeClientFor(provider) {
|
|
3174
3245
|
switch (provider) {
|
|
@@ -3193,14 +3264,14 @@ function nativeClientFor(provider) {
|
|
|
3193
3264
|
function resolveTextRoute(ctx) {
|
|
3194
3265
|
const provider = textProviderOf(ctx.model);
|
|
3195
3266
|
const mode = ctx.routing.text ?? "direct";
|
|
3196
|
-
if (provider === "anthropic" && ctx.
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
}
|
|
3267
|
+
if (provider === "anthropic" && ctx.anthropicTransport === "bedrock") {
|
|
3268
|
+
return {
|
|
3269
|
+
provider,
|
|
3270
|
+
client: "bedrock-anthropic",
|
|
3271
|
+
modelId: toBedrockModelId(ctx.model, ctx.routing),
|
|
3272
|
+
keyName: "aws",
|
|
3273
|
+
canonicalModelId: ctx.model.id
|
|
3274
|
+
};
|
|
3204
3275
|
}
|
|
3205
3276
|
const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
|
|
3206
3277
|
const route2 = {
|
|
@@ -3244,6 +3315,70 @@ function missingKey(ctx, name) {
|
|
|
3244
3315
|
retryable: false
|
|
3245
3316
|
});
|
|
3246
3317
|
}
|
|
3318
|
+
function bedrockMiddleware(ctx, canonicalModelId) {
|
|
3319
|
+
let warned = false;
|
|
3320
|
+
return {
|
|
3321
|
+
specificationVersion: "v3",
|
|
3322
|
+
transformParams: async ({ params }) => {
|
|
3323
|
+
const anthropic = params.providerOptions?.["anthropic"];
|
|
3324
|
+
if (typeof anthropic !== "object" || anthropic === null || !("cacheControl" in anthropic))
|
|
3325
|
+
return params;
|
|
3326
|
+
if (!warned) {
|
|
3327
|
+
warned = true;
|
|
3328
|
+
ctx.logger.warn(
|
|
3329
|
+
`[modelkit] ${canonicalModelId} drops call-level providerOptions.anthropic.cacheControl: not supported on Bedrock, use message-level cacheControl`
|
|
3330
|
+
);
|
|
3331
|
+
}
|
|
3332
|
+
const { cacheControl: _dropped, ...rest } = anthropic;
|
|
3333
|
+
return {
|
|
3334
|
+
...params,
|
|
3335
|
+
providerOptions: { ...params.providerOptions, anthropic: rest }
|
|
3336
|
+
};
|
|
3337
|
+
},
|
|
3338
|
+
// Bedrock echoes its own id for dated models (anthropic.claude-haiku-4-5-20251001-v1:0),
|
|
3339
|
+
// and consumers bill on response.modelId.
|
|
3340
|
+
wrapGenerate: async ({ doGenerate }) => {
|
|
3341
|
+
const result = await doGenerate();
|
|
3342
|
+
if (!result.response) return result;
|
|
3343
|
+
return { ...result, response: { ...result.response, modelId: canonicalModelId } };
|
|
3344
|
+
},
|
|
3345
|
+
wrapStream: async ({ doStream }) => {
|
|
3346
|
+
const result = await doStream();
|
|
3347
|
+
return {
|
|
3348
|
+
...result,
|
|
3349
|
+
stream: result.stream.pipeThrough(
|
|
3350
|
+
new TransformStream({
|
|
3351
|
+
transform(part, controller) {
|
|
3352
|
+
controller.enqueue(
|
|
3353
|
+
part.type === "response-metadata" && part.modelId !== void 0 ? { ...part, modelId: canonicalModelId } : part
|
|
3354
|
+
);
|
|
3355
|
+
}
|
|
3356
|
+
})
|
|
3357
|
+
)
|
|
3358
|
+
};
|
|
3359
|
+
}
|
|
3360
|
+
};
|
|
3361
|
+
}
|
|
3362
|
+
function bedrockLanguageModel(ctx, route2) {
|
|
3363
|
+
const aws = ctx.keys.aws;
|
|
3364
|
+
if (!hasAwsCredentials(aws)) throw missingKey(ctx, "aws");
|
|
3365
|
+
const canonical = route2.canonicalModelId ?? ctx.model.id;
|
|
3366
|
+
const inner = (0, import_anthropic.createBedrockAnthropic)({
|
|
3367
|
+
region: aws.region,
|
|
3368
|
+
fetch: ctx.fetch,
|
|
3369
|
+
...aws.apiKey ? { apiKey: aws.apiKey } : aws.credentialProvider ? { credentialProvider: aws.credentialProvider } : aws.accessKeyId !== void 0 && aws.secretAccessKey !== void 0 ? {
|
|
3370
|
+
accessKeyId: aws.accessKeyId,
|
|
3371
|
+
secretAccessKey: aws.secretAccessKey,
|
|
3372
|
+
...aws.sessionToken !== void 0 ? { sessionToken: aws.sessionToken } : {}
|
|
3373
|
+
} : {}
|
|
3374
|
+
})(route2.modelId);
|
|
3375
|
+
return (0, import_ai2.wrapLanguageModel)({
|
|
3376
|
+
model: inner,
|
|
3377
|
+
middleware: bedrockMiddleware(ctx, canonical),
|
|
3378
|
+
modelId: canonical,
|
|
3379
|
+
providerId: "anthropic.messages"
|
|
3380
|
+
});
|
|
3381
|
+
}
|
|
3247
3382
|
function minimaxDefaults(params) {
|
|
3248
3383
|
return params.responseFormat?.type === "json" ? { reasoning_split: true, thinking: { type: "disabled" } } : { reasoning_split: true };
|
|
3249
3384
|
}
|
|
@@ -3282,14 +3417,17 @@ var aiSdkTextAdapter = {
|
|
|
3282
3417
|
id: "ai-sdk-text",
|
|
3283
3418
|
languageModel(ctx) {
|
|
3284
3419
|
const route2 = resolveTextRoute(ctx);
|
|
3285
|
-
|
|
3286
|
-
|
|
3420
|
+
if (route2.client === "bedrock-anthropic") return bedrockLanguageModel(ctx, route2);
|
|
3421
|
+
const { keyName } = route2;
|
|
3422
|
+
if (keyName === "aws") throw missingKey(ctx, keyName);
|
|
3423
|
+
const apiKey = ctx.keys[keyName];
|
|
3424
|
+
if (!apiKey) throw missingKey(ctx, keyName);
|
|
3287
3425
|
const settings = { apiKey, fetch: ctx.fetch };
|
|
3288
3426
|
if (route2.baseURL !== void 0) settings.baseURL = route2.baseURL;
|
|
3289
3427
|
if (route2.headers !== void 0) settings.headers = route2.headers;
|
|
3290
3428
|
switch (route2.client) {
|
|
3291
3429
|
case "anthropic":
|
|
3292
|
-
return (0,
|
|
3430
|
+
return (0, import_anthropic2.createAnthropic)(settings)(route2.modelId);
|
|
3293
3431
|
case "google":
|
|
3294
3432
|
return (0, import_google.createGoogleGenerativeAI)(settings)(route2.modelId);
|
|
3295
3433
|
case "xai":
|
|
@@ -3322,14 +3460,43 @@ var aiSdkTextAdapter = {
|
|
|
3322
3460
|
}
|
|
3323
3461
|
};
|
|
3324
3462
|
|
|
3463
|
+
// src/anthropic-transport.ts
|
|
3464
|
+
var ANTHROPIC_TRANSPORTS = ["direct", "bedrock"];
|
|
3465
|
+
function isAnthropicTransport(value) {
|
|
3466
|
+
return ANTHROPIC_TRANSPORTS.some((transport) => transport === value);
|
|
3467
|
+
}
|
|
3468
|
+
function preferredAnthropicTransport(model, routing) {
|
|
3469
|
+
const row = model.providerOptions?.["modelkit"]?.["transport"];
|
|
3470
|
+
if (isAnthropicTransport(row)) return row;
|
|
3471
|
+
return routing.anthropic ?? "direct";
|
|
3472
|
+
}
|
|
3473
|
+
function resolveAnthropicTransport(model, config, tier, warn) {
|
|
3474
|
+
if (model.adapter !== "ai-sdk-text" || textProviderOf(model) !== "anthropic") return void 0;
|
|
3475
|
+
const rowValue = model.providerOptions?.["modelkit"]?.["transport"];
|
|
3476
|
+
if (rowValue !== void 0 && !isAnthropicTransport(rowValue))
|
|
3477
|
+
warn(
|
|
3478
|
+
`[modelkit] ${model.id} has an unknown providerOptions.modelkit.transport "${String(rowValue)}"; ignoring it`
|
|
3479
|
+
);
|
|
3480
|
+
const preferred = preferredAnthropicTransport(model, config.routing ?? {});
|
|
3481
|
+
const usable = (transport) => {
|
|
3482
|
+
const name = transport === "bedrock" ? "aws" : "anthropic";
|
|
3483
|
+
return hasKey(config.keys.pro, name) || tier === "enterprise" && hasKey(config.keys.enterprise, name);
|
|
3484
|
+
};
|
|
3485
|
+
if (usable(preferred)) return preferred;
|
|
3486
|
+
const other = preferred === "bedrock" ? "direct" : "bedrock";
|
|
3487
|
+
if (!usable(other)) return preferred;
|
|
3488
|
+
warn(`[modelkit] ${model.id}: no credentials for the ${preferred} transport; using ${other}`);
|
|
3489
|
+
return other;
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3325
3492
|
// src/client.ts
|
|
3326
|
-
function requiredKeys(model, config) {
|
|
3493
|
+
function requiredKeys(model, config, transport) {
|
|
3327
3494
|
if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
|
|
3328
3495
|
return ["cloudflare"];
|
|
3329
3496
|
if (model.adapter === "ai-sdk-text") {
|
|
3330
3497
|
const routing = config.routing ?? {};
|
|
3331
|
-
const names = [textKeyName(model,
|
|
3332
|
-
if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
|
|
3498
|
+
const names = [textKeyName(model, transport)];
|
|
3499
|
+
if (textUsesCloudflareGateway(model, routing, transport)) names.push("cloudflare");
|
|
3333
3500
|
return names;
|
|
3334
3501
|
}
|
|
3335
3502
|
return ADAPTER_KEYS[model.adapter];
|
|
@@ -3416,6 +3583,12 @@ function createModelKit(config, adapters) {
|
|
|
3416
3583
|
const catalog = config.catalogOverride ? liveCatalog.withOverrides(config.catalogOverride) : liveCatalog;
|
|
3417
3584
|
const logger = config.logger ?? console;
|
|
3418
3585
|
const fetchImpl = config.fetch ?? globalThis.fetch;
|
|
3586
|
+
const transportWarnings = /* @__PURE__ */ new Set();
|
|
3587
|
+
function warnOnce(message) {
|
|
3588
|
+
if (transportWarnings.has(message)) return;
|
|
3589
|
+
transportWarnings.add(message);
|
|
3590
|
+
logger.warn(message);
|
|
3591
|
+
}
|
|
3419
3592
|
function context(model, call, warnings) {
|
|
3420
3593
|
const adapter = adapters[model.adapter];
|
|
3421
3594
|
if (!adapter)
|
|
@@ -3424,7 +3597,8 @@ function createModelKit(config, adapters) {
|
|
|
3424
3597
|
message: `No adapter registered for ${model.adapter}`,
|
|
3425
3598
|
model: model.id
|
|
3426
3599
|
});
|
|
3427
|
-
const
|
|
3600
|
+
const transport = resolveAnthropicTransport(model, config, call.tier, warnOnce);
|
|
3601
|
+
const names = requiredKeys(model, config, transport);
|
|
3428
3602
|
if (call.tier === "enterprise") {
|
|
3429
3603
|
const missing = missingEnterpriseKeys(config, names);
|
|
3430
3604
|
if (missing.length > 0)
|
|
@@ -3443,6 +3617,7 @@ function createModelKit(config, adapters) {
|
|
|
3443
3617
|
call,
|
|
3444
3618
|
warnings
|
|
3445
3619
|
};
|
|
3620
|
+
if (transport) ctx.anthropicTransport = transport;
|
|
3446
3621
|
if (config.endpoints) ctx.endpoints = config.endpoints;
|
|
3447
3622
|
if (call.signal) ctx.signal = call.signal;
|
|
3448
3623
|
return { adapter, ctx };
|
|
@@ -3777,7 +3952,7 @@ function createModelKit(config, adapters) {
|
|
|
3777
3952
|
async prepareMediaPart(modelId, ref, mediaType, call = {}) {
|
|
3778
3953
|
const model = catalog.require(modelId);
|
|
3779
3954
|
const { adapter, ctx } = context(model, call, []);
|
|
3780
|
-
const fileStore = model.adapter === "ai-sdk-text" && textKeyName(model
|
|
3955
|
+
const fileStore = model.adapter === "ai-sdk-text" && textKeyName(model) === "google" ? adapters["google-genai"] : adapter;
|
|
3781
3956
|
if (fileStore?.prepareMediaPart) return fileStore.prepareMediaPart(ref, mediaType, ctx);
|
|
3782
3957
|
return "url" in ref ? { type: "file", data: ref.url, mediaType } : { type: "file", data: ref.bytes, mediaType };
|
|
3783
3958
|
},
|
|
@@ -7569,6 +7744,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
|
|
|
7569
7744
|
generateVideo,
|
|
7570
7745
|
googleGenaiAdapter,
|
|
7571
7746
|
googleImageAdapter,
|
|
7747
|
+
hasAwsCredentials,
|
|
7572
7748
|
higgsfieldAdapter,
|
|
7573
7749
|
isListed,
|
|
7574
7750
|
isListedOn,
|