// --------------------------------------------------------------------------- // Known model context windows (Bedrock API does not expose token limits) // ---------------------------------------------------------------------------
function resolveDefaultContextWindow(config?: BedrockDiscoveryConfig): number { const value = Math.floor(config?.defaultContextWindow ?? DEFAULT_CONTEXT_WINDOW); return value > 0 ? value : DEFAULT_CONTEXT_WINDOW;
}
function resolveDefaultMaxTokens(config?: BedrockDiscoveryConfig): number { const value = Math.floor(config?.defaultMaxTokens ?? DEFAULT_MAX_TOKENS); return value > 0 ? value : DEFAULT_MAX_TOKENS;
}
// --------------------------------------------------------------------------- // Foundation model helpers // ---------------------------------------------------------------------------
/** *Convertrawinferenceprofilesummariesintomodeldefinitions. * *Eachprofileinheritscapabilities(modalities,reasoning,contextwindow, *cost)fromitsunderlyingfoundationmodel.Thisensuresthat *"us.anthropic.claude-sonnet-4-6"hasthesamecapabilitiesas *"anthropic.claude-sonnet-4-6"—includingimageinput,reasoningsupport, *andtokenlimits. * *Whenthefoundationmodelisn'tfoundinthemap(e.g.themodelisonly *availableviainferenceprofilesinthisregion),safedefaultsareused.
*/ function resolveInferenceProfiles(
profiles: InferenceProfileSummary[],
defaults: { contextWindow: number; maxTokens: number },
providerFilter: string[],
foundationModels: Map<string, ModelDefinitionConfig>,
): ModelDefinitionConfig[] { const discovered: ModelDefinitionConfig[] = []; for (const profile of profiles) { if (!profile.inferenceProfileId?.trim()) { continue;
} if (profile.status !== "ACTIVE") { continue;
}
// Apply provider filter: check if any of the underlying models match. if (providerFilter.length > 0) { const models = profile.models ?? []; const matchesFilter = models.some((m) => { const provider = m.modelArn?.split("/")?.[1]?.split(".")?.[0]; return provider
? providerFilter.includes(normalizeOptionalLowercaseString(provider) ?? "")
: false;
}); if (!matchesFilter) { continue;
}
}
// Look up the underlying foundation model to inherit its capabilities. const baseModelId = resolveBaseModelId(profile); const baseModel = baseModelId
? foundationModels.get(normalizeLowercaseStringOrEmpty(baseModelId))
: undefined;
// --------------------------------------------------------------------------- // Public API // ---------------------------------------------------------------------------
export function resetBedrockDiscoveryCacheForTest(): void {
discoveryCache.clear();
hasLoggedBedrockError = false;
}
export function resolveBedrockConfigApiKey(
env: NodeJS.ProcessEnv = process.env,
): string | undefined { // When no AWS auth env marker is present, Bedrock should fall back to the // AWS SDK default credential chain instead of persisting a fake apiKey marker. return resolveAwsSdkEnvVarName(env);
}
if (refreshIntervalSeconds > 0) { const cached = discoveryCache.get(cacheKey); if (cached?.value && cached.expiresAt > now) { return cached.value;
} if (cached?.inFlight) { return cached.inFlight;
}
}
const clientFactory = params.clientFactory ?? ((region: string) => new BedrockClient({ region })); const client = clientFactory(params.region);
const discoveryPromise = (async () => { // Discover foundation models and inference profiles in parallel. // Both API calls are independent, but we need the foundation model data // to resolve inference profile capabilities — so we fetch in parallel, // then build the lookup map before processing profiles. const [foundationResponse, profileSummaries] = await Promise.all([
client.send(new ListFoundationModelsCommand({})),
fetchInferenceProfileSummaries(client),
]);
const discovered: ModelDefinitionConfig[] = []; const seenIds = new Set<string>(); const foundationModels = new Map<string, ModelDefinitionConfig>();
// Foundation models first — build both the results list and the lookup map. for (const summary of foundationResponse.modelSummaries ?? []) { if (!shouldIncludeSummary(summary, providerFilter)) { continue;
} const def = toModelDefinition(summary, {
contextWindow: defaultContextWindow,
maxTokens: defaultMaxTokens,
});
discovered.push(def); const normalizedId = normalizeLowercaseStringOrEmpty(def.id);
seenIds.add(normalizedId);
foundationModels.set(normalizedId, def);
}
// Merge inference profiles — inherit capabilities from foundation models. const inferenceProfiles = resolveInferenceProfiles(
profileSummaries,
{ contextWindow: defaultContextWindow, maxTokens: defaultMaxTokens },
providerFilter,
foundationModels,
); for (const profile of inferenceProfiles) { const normalizedId = normalizeLowercaseStringOrEmpty(profile.id); if (!seenIds.has(normalizedId)) {
discovered.push(profile);
seenIds.add(normalizedId);
}
}
// Sort: global cross-region profiles first (recommended for most users — // better capacity, automatic failover, no data sovereignty constraints), // then remaining profiles/models alphabetically. return discovered.toSorted((a, b) => { const aGlobal = a.id.startsWith("global.") ? 0 : 1; const bGlobal = b.id.startsWith("global.") ? 0 : 1; if (aGlobal !== bGlobal) { return aGlobal - bGlobal;
} return a.name.localeCompare(b.name);
});
})();
if (refreshIntervalSeconds > 0) {
discoveryCache.set(cacheKey, {
expiresAt: now + refreshIntervalSeconds * 1000,
inFlight: discoveryPromise,
});
}
try { const value = await discoveryPromise; if (refreshIntervalSeconds > 0) {
discoveryCache.set(cacheKey, {
expiresAt: now + refreshIntervalSeconds * 1000,
value,
});
} return value;
} catch (error) { if (refreshIntervalSeconds > 0) {
discoveryCache.delete(cacheKey);
} if (!hasLoggedBedrockError) {
hasLoggedBedrockError = true;
log.warn("Failed to discover Bedrock models", {
error: formatErrorMessage(error),
});
} return [];
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.