Merge PR #7080: fix(ai): add authenticated Bedrock Mantle routing (@anatoli-tsinovoy)

# Conflicts:
#	packages/ai/src/registry/registry.ts
#	packages/catalog/scripts/generated-policies.ts
#	packages/catalog/src/models.json
This commit is contained in:
can1357
2026-08-03 14:36:52 +02:00
27 changed files with 1705 additions and 289 deletions
+11 -1
View File
@@ -14,6 +14,7 @@ import { discoverAuthStorage } from "@oh-my-pi/pi-ai/auth-broker/discover";
import type { OAuthAccess } from "@oh-my-pi/pi-ai/auth-storage";
import type { OAuthProvider } from "@oh-my-pi/pi-ai/oauth/types";
import { getGitLabDuoModels } from "@oh-my-pi/pi-ai/providers/gitlab-duo";
import { getProviderDefinition } from "@oh-my-pi/pi-ai/registry";
import { $env } from "@oh-my-pi/pi-utils";
import { ANTIGRAVITY_PRIMARY_ENDPOINT, fetchAntigravityDiscoveryModels } from "../src/discovery/antigravity";
import { buildGitLabDuoWorkflowFallbackModel } from "../src/discovery/gitlab-duo-workflow";
@@ -31,6 +32,7 @@ import {
AIAND_STATIC_MODELS,
ALIBABA_TOKEN_PLAN_STATIC_MODELS,
ANTHROPIC_CURATED_FALLBACK_MODELS,
BEDROCK_MANTLE_STATIC_MODELS,
buildFireworksFastSeed,
buildXaiOAuthStaticSeed,
clampFireworksKimiMaxTokens,
@@ -57,6 +59,7 @@ import {
applyGeneratedModelPolicies,
applyOllamaCloudOutputCap,
CLOUDFLARE_FALLBACK_MODEL,
dropBedrockMantleOpenAIModels,
dropUnsupportedBedrockGeoIds,
hasBillableCost,
linkOpenAIPromotionTargets,
@@ -126,7 +129,10 @@ async function fetchProviderModelsFromCatalog(
try {
console.log(`Fetching models from ${descriptor.catalogDiscovery.label} model manager...`);
const managerOptions = descriptor.createModelManagerOptions({ apiKey });
const discoveryConfig = { apiKey };
const preparedConfig =
getProviderDefinition(descriptor.providerId)?.prepareModelDiscovery?.(discoveryConfig) ?? discoveryConfig;
const managerOptions = descriptor.createModelManagerOptions(preparedConfig);
const manager = createModelManager(managerOptions);
const result = await manager.refresh("online");
// `stale: true` means the dynamic fetch failed and the manager fell back
@@ -554,6 +560,9 @@ async function generateModels() {
// Seed Meta's documented Muse model so first-run selection does not depend on
// credentials or live discovery.
allModels.push(...META_MUSE_STATIC_MODELS);
// Mantle's catalog endpoint is account/API-key scoped. Keep the generated
// bundle deterministic; authenticated runtime discovery may replace this seed.
allModels.push(...BEDROCK_MANTLE_STATIC_MODELS);
// Seed Sakana's documented Fugu models so the provider is usable when
// catalog generation has no live API key. If live `/v1/models` succeeds,
// Sakana is authoritative and stale seed IDs must stay out.
@@ -657,6 +666,7 @@ async function generateModels() {
allModels = dropUnusableZaiContextTierIds(allModels);
allModels = dropXiaomiAudioOnlyIds(allModels);
allModels = dropUnsupportedBedrockGeoIds(allModels);
allModels = dropBedrockMantleOpenAIModels(allModels);
allModels = normalizeAntigravityEndpoint(allModels);
// Normalize display names: gateway author prefixes ("OpenAI: …"), alias
// markers ("(latest)"), provider attribution ("(Antigravity)"), and
@@ -66,6 +66,22 @@ export function dropUnsupportedBedrockGeoIds(models: readonly ModelSpec[]): Mode
return models.filter(model => !(model.provider === "amazon-bedrock" && model.id === "jp.anthropic.claude-opus-5"));
}
const BEDROCK_MANTLE_OPENAI_MODEL_IDS: Record<string, true> = {
"openai.gpt-5.4": true,
"openai.gpt-5.5": true,
"openai.gpt-5.6-luna": true,
"openai.gpt-5.6-sol": true,
"openai.gpt-5.6-terra": true,
};
/**
* models.dev exposes these Responses-only models under amazon-bedrock, whose
* descriptor uses Converse. The working Mantle rows come from the static seed.
*/
export function dropBedrockMantleOpenAIModels(models: readonly ModelSpec[]): ModelSpec[] {
return models.filter(model => !(model.provider === "amazon-bedrock" && BEDROCK_MANTLE_OPENAI_MODEL_IDS[model.id]));
}
/** True when any component of a model's per-million-token cost is nonzero. */
export function hasBillableCost(cost: ModelSpec["cost"]): boolean {
return cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0;