diff --git a/src/proxy/anthropic.ts b/src/proxy/anthropic.ts index d2eec0e..8d8965e 100644 --- a/src/proxy/anthropic.ts +++ b/src/proxy/anthropic.ts @@ -9,6 +9,7 @@ import { import { ProxyResHandlerWithBody } from "./middleware/response"; import { createQueuedProxyMiddleware } from "./middleware/request/proxy-middleware-factory"; import { ProxyReqManager } from "./middleware/request/proxy-req-manager"; +import { claudeModels } from "../shared/claude-models"; let modelsCache: any = null; let modelsCacheTime = 0; @@ -20,30 +21,14 @@ const getModelsResponse = () => { if (!config.anthropicKey) return { object: "list", data: [], has_more: false, first_id: null, last_id: null }; - const claudeVariants = [ - ["claude-2", "Claude 2"], - ["claude-2.0", "Claude 2.0"], - ["claude-2.1", "Claude 2.1"], - ["claude-3-haiku-20240307", "Claude 3 Haiku"], - ["claude-3-5-haiku-20241022", "Claude 3.5 Haiku"], - ["claude-3-opus-20240229", "Claude 3 Opus"], - ["claude-3-opus-latest", "Claude 3 Opus (latest)"], - ["claude-3-sonnet-20240229", "Claude 3 Sonnet"], - ["claude-3-5-sonnet-20240620", "Claude 3.5 Sonnet (Old)"], - ["claude-3-5-sonnet-20241022", "Claude 3.5 Sonnet (New)"], - ["claude-3-5-sonnet-latest", "Claude 3.5 Sonnet (Latest)"], - ["claude-3-7-sonnet-20250219", "Claude 3.7 Sonnet"], - ["claude-3-7-sonnet-latest", "Claude 3.7 Sonnet (Latest)"] - ]; - const date = new Date() - const models = claudeVariants.map(([id, display_name]) => ({ + const models = claudeModels.map(model => ({ // Common - id, + id: model.anthropicId, owned_by: "anthropic", // Anthropic type: "model", - display_name, + display_name: model.displayName, created_at: date.toISOString(), // OpenAI object: "model", @@ -56,8 +41,8 @@ const getModelsResponse = () => { data: models, // Anthropic has_more: false, - first_id: claudeVariants[0][0], - last_id: claudeVariants.at(-1)![0], + first_id: models[0]?.id, + last_id: models[models.length - 1]?.id, }; modelsCacheTime = date.getTime(); diff --git a/src/proxy/aws.ts b/src/proxy/aws.ts index c214d55..7febbed 100644 --- a/src/proxy/aws.ts +++ b/src/proxy/aws.ts @@ -6,6 +6,7 @@ import { addV1 } from "./add-v1"; import { awsClaude } from "./aws-claude"; import { awsMistral } from "./aws-mistral"; import { AwsBedrockKey, keyPool } from "../shared/key-management"; +import { claudeModels, findByAwsId } from "../shared/claude-models"; const awsRouter = Router(); awsRouter.get(["/:vendor?/v1/models", "/:vendor?/models"], handleModelsRequest); @@ -29,22 +30,13 @@ function handleModelsRequest(req: Request, res: Response) { return res.json(modelsCache[vendor]); } - const availableModelIds = new Set(); + const availableAwsModelIds = new Set(); for (const key of keyPool.list()) { if (key.isDisabled || key.service !== "aws") continue; - (key as AwsBedrockKey).modelIds.forEach((id) => availableModelIds.add(id)); + (key as AwsBedrockKey).modelIds.forEach((id) => availableAwsModelIds.add(id)); } - const modelDisplayNames = new Map([ - ["anthropic.claude-v2", "Claude 2"], - ["anthropic.claude-v2:1", "Claude 2.1"], - ["anthropic.claude-3-haiku-20240307-v1:0", "Claude 3 Haiku"], - ["anthropic.claude-3-5-haiku-20241022-v1:0", "Claude 3.5 Haiku"], - ["anthropic.claude-3-sonnet-20240229-v1:0", "Claude 3 Sonnet"], - ["anthropic.claude-3-5-sonnet-20240620-v1:0", "Claude 3.5 Sonnet (Old)"], - ["anthropic.claude-3-5-sonnet-20241022-v2:0", "Claude 3.5 Sonnet (New)"], - ["anthropic.claude-3-7-sonnet-20250219-v1:0", "Claude 3.7 Sonnet"], - ["anthropic.claude-3-opus-20240229-v1:0", "Claude 3 Opus"], + const mistralMappings = new Map([ ["mistral.mistral-7b-instruct-v0:2", "Mistral 7B Instruct"], ["mistral.mixtral-8x7b-instruct-v0:1", "Mixtral 8x7B Instruct"], ["mistral.mistral-large-2402-v1:0", "Mistral Large 2402"], @@ -52,39 +44,53 @@ function handleModelsRequest(req: Request, res: Response) { ["mistral.mistral-small-2402-v1:0", "Mistral Small 2402"], ]); - // https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html - const models = Array.from(modelDisplayNames.keys()) - .filter((id) => availableModelIds.has(id)) - .map((id) => { - const vendor = id.match(/^(.*)\./)?.[1]; - const date = new Date(); + const date = new Date(); + + const claudeModelsList = claudeModels + .filter(model => availableAwsModelIds.has(model.awsId)) + .map(model => ({ + id: model.anthropicId, + owned_by: "anthropic", + type: "model", + display_name: model.displayName, + created_at: date.toISOString(), + object: "model", + created: date.getTime(), + permission: [], + root: "anthropic", + parent: null, + })); + + const mistralModelsList = Array.from(mistralMappings.keys()) + .filter(id => availableAwsModelIds.has(id)) + .map(id => { return { - // Common id, - owned_by: vendor, - // Anthropic + owned_by: "mistral", type: "model", - display_name: modelDisplayNames.get(id) || id.split('.')[1], + display_name: mistralMappings.get(id) || id.split('.')[1], created_at: date.toISOString(), - // OpenAI object: "model", created: date.getTime(), permission: [], - root: vendor, + root: "mistral", parent: null, }; }); + const allModels = [...claudeModelsList, ...mistralModelsList]; + const filteredModels = vendor === "all" + ? allModels + : allModels.filter(m => m.root === vendor); + modelsCache[vendor] = { - // Common object: "list", - data: models.filter((m) => vendor === "all" || m.root === vendor), - // Anthropic + data: filteredModels, has_more: false, - first_id: models[0]?.id, - last_id: models[models.length - 1]?.id, + first_id: filteredModels[0]?.id, + last_id: filteredModels[filteredModels.length - 1]?.id, }; - modelsCacheTime[vendor] = new Date().getTime(); + modelsCacheTime[vendor] = date.getTime(); return res.json(modelsCache[vendor]); } diff --git a/src/shared/claude-models.ts b/src/shared/claude-models.ts new file mode 100644 index 0000000..a714437 --- /dev/null +++ b/src/shared/claude-models.ts @@ -0,0 +1,28 @@ +export interface ClaudeModelMapping { + awsId: string; + anthropicId: string; + displayName: string; +} + +export const claudeModels: ClaudeModelMapping[] = [ + { awsId: "anthropic.claude-v2", anthropicId: "claude-2", displayName: "Claude 2" }, + { awsId: "anthropic.claude-v2:1", anthropicId: "claude-2.1", displayName: "Claude 2.1" }, + { awsId: "anthropic.claude-3-haiku-20240307-v1:0", anthropicId: "claude-3-haiku-20240307", displayName: "Claude 3 Haiku" }, + { awsId: "anthropic.claude-3-5-haiku-20241022-v1:0", anthropicId: "claude-3-5-haiku-20241022", displayName: "Claude 3.5 Haiku" }, + { awsId: "anthropic.claude-3-sonnet-20240229-v1:0", anthropicId: "claude-3-sonnet-20240229", displayName: "Claude 3 Sonnet" }, + { awsId: "anthropic.claude-3-5-sonnet-20240620-v1:0", anthropicId: "claude-3-5-sonnet-20240620", displayName: "Claude 3.5 Sonnet (Old)" }, + { awsId: "anthropic.claude-3-5-sonnet-20241022-v2:0", anthropicId: "claude-3-5-sonnet-20241022", displayName: "Claude 3.5 Sonnet (New)" }, + { awsId: "anthropic.claude-3-5-sonnet-20241022-v2:0", anthropicId: "claude-3-5-sonnet-latest", displayName: "Claude 3.5 Sonnet (Latest)" }, + { awsId: "anthropic.claude-3-7-sonnet-20250219-v1:0", anthropicId: "claude-3-7-sonnet-20250219", displayName: "Claude 3.7 Sonnet" }, + { awsId: "anthropic.claude-3-7-sonnet-20250219-v1:0", anthropicId: "claude-3-7-sonnet-latest", displayName: "Claude 3.7 Sonnet (Latest)" }, + { awsId: "anthropic.claude-3-opus-20240229-v1:0", anthropicId: "claude-3-opus-20240229", displayName: "Claude 3 Opus" }, + { awsId: "anthropic.claude-3-opus-20240229-v1:0", anthropicId: "claude-3-opus-latest", displayName: "Claude 3 Opus (Latest)" }, +]; + +export function findByAwsId(awsId: string): ClaudeModelMapping | undefined { + return claudeModels.find(model => model.awsId === awsId); +} + +export function getAllClaudeModels(): ClaudeModelMapping[] { + return claudeModels; +} \ No newline at end of file