|
|
import { AnthropicChatMessage } from "../../../../shared/api-schemas"; |
|
|
import { containsImageContent } from "../../../../shared/api-schemas/anthropic"; |
|
|
import { Key, OpenAIKey, keyPool } from "../../../../shared/key-management"; |
|
|
import { isEmbeddingsRequest } from "../../common"; |
|
|
import { assertNever } from "../../../../shared/utils"; |
|
|
import { ProxyReqMutator } from "../index"; |
|
|
|
|
|
export const addKey: ProxyReqMutator = (manager) => { |
|
|
const req = manager.request; |
|
|
|
|
|
let assignedKey: Key; |
|
|
const { service, inboundApi, outboundApi, body } = req; |
|
|
|
|
|
if (!inboundApi || !outboundApi) { |
|
|
const err = new Error( |
|
|
"Request API format missing. Did you forget to add the request preprocessor to your router?" |
|
|
); |
|
|
req.log.error({ inboundApi, outboundApi, path: req.path }, err.message); |
|
|
throw err; |
|
|
} |
|
|
|
|
|
if (!body?.model) { |
|
|
throw new Error("You must specify a model with your request."); |
|
|
} |
|
|
|
|
|
let needsMultimodal = false; |
|
|
if (outboundApi === "anthropic-chat") { |
|
|
needsMultimodal = containsImageContent( |
|
|
body.messages as AnthropicChatMessage[] |
|
|
); |
|
|
} |
|
|
|
|
|
if (inboundApi === outboundApi) { |
|
|
assignedKey = keyPool.get(body.model, service, needsMultimodal); |
|
|
} else { |
|
|
switch (outboundApi) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "anthropic-text": |
|
|
case "anthropic-chat": |
|
|
case "mistral-ai": |
|
|
case "mistral-text": |
|
|
case "google-ai": |
|
|
assignedKey = keyPool.get(body.model, service); |
|
|
break; |
|
|
case "openai-text": |
|
|
assignedKey = keyPool.get("gpt-3.5-turbo-instruct", service); |
|
|
break; |
|
|
case "openai-image": |
|
|
|
|
|
|
|
|
assignedKey = keyPool.get(body.model, service); |
|
|
break; |
|
|
case "openai-responses": |
|
|
assignedKey = keyPool.get(body.model, service); |
|
|
break; |
|
|
case "openai": |
|
|
throw new Error( |
|
|
`Outbound API ${outboundApi} is not supported for ${inboundApi}` |
|
|
); |
|
|
default: |
|
|
assertNever(outboundApi); |
|
|
} |
|
|
} |
|
|
|
|
|
manager.setKey(assignedKey); |
|
|
req.log.info( |
|
|
{ key: assignedKey.hash, model: body.model, inboundApi, outboundApi }, |
|
|
"Assigned key to request" |
|
|
); |
|
|
|
|
|
|
|
|
switch (assignedKey.service) { |
|
|
case "anthropic": |
|
|
manager.setHeader("X-API-Key", assignedKey.key); |
|
|
if (!manager.request.headers["anthropic-version"]) { |
|
|
manager.setHeader("anthropic-version", "2023-06-01"); |
|
|
} |
|
|
break; |
|
|
case "openai": |
|
|
const key: OpenAIKey = assignedKey as OpenAIKey; |
|
|
if (key.organizationId && !key.key.includes("svcacct")) { |
|
|
manager.setHeader("OpenAI-Organization", key.organizationId); |
|
|
} |
|
|
manager.setHeader("Authorization", `Bearer ${assignedKey.key}`); |
|
|
break; |
|
|
case "mistral-ai": |
|
|
manager.setHeader("Authorization", `Bearer ${assignedKey.key}`); |
|
|
break; |
|
|
case "azure": |
|
|
const azureKey = assignedKey.key; |
|
|
manager.setHeader("api-key", azureKey); |
|
|
break; |
|
|
case "deepseek": |
|
|
manager.setHeader("Authorization", `Bearer ${assignedKey.key}`); |
|
|
break; |
|
|
case "xai": |
|
|
manager.setHeader("Authorization", `Bearer ${assignedKey.key}`); |
|
|
break; |
|
|
case "cohere": |
|
|
manager.setHeader("Authorization", `Bearer ${assignedKey.key}`); |
|
|
break; |
|
|
case "qwen": |
|
|
manager.setHeader("Authorization", `Bearer ${assignedKey.key}`); |
|
|
break; |
|
|
case "aws": |
|
|
case "gcp": |
|
|
case "google-ai": |
|
|
throw new Error("add-key should not be used for this service."); |
|
|
default: |
|
|
assertNever(assignedKey.service); |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const addKeyForEmbeddingsRequest: ProxyReqMutator = (manager) => { |
|
|
const req = manager.request; |
|
|
if (!isEmbeddingsRequest(req)) { |
|
|
throw new Error( |
|
|
"addKeyForEmbeddingsRequest called on non-embeddings request" |
|
|
); |
|
|
} |
|
|
|
|
|
if (req.inboundApi !== "openai") { |
|
|
throw new Error("Embeddings requests must be from OpenAI"); |
|
|
} |
|
|
|
|
|
manager.setBody({ input: req.body.input, model: "text-embedding-ada-002" }); |
|
|
|
|
|
const key = keyPool.get("text-embedding-ada-002", "openai") as OpenAIKey; |
|
|
|
|
|
manager.setKey(key); |
|
|
req.log.info( |
|
|
{ key: key.hash, toApi: req.outboundApi }, |
|
|
"Assigned Turbo key to embeddings request" |
|
|
); |
|
|
|
|
|
manager.setHeader("Authorization", `Bearer ${key.key}`); |
|
|
if (key.organizationId) { |
|
|
manager.setHeader("OpenAI-Organization", key.organizationId); |
|
|
} |
|
|
}; |
|
|
|