mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
* feat: added PROXY support for AWS Bedrock endpoint * chore: explicit install of new packages required for bedrock proxy --------- Co-authored-by: Danny Avila <danny@librechat.ai>
150 lines
5 KiB
JavaScript
150 lines
5 KiB
JavaScript
/**
|
|
* Bedrock endpoint options configuration
|
|
*
|
|
* This module handles configuration for AWS Bedrock endpoints, including support for
|
|
* HTTP/HTTPS proxies and reverse proxies.
|
|
*
|
|
* Proxy Support:
|
|
* - When the PROXY environment variable is set, creates a custom BedrockRuntimeClient
|
|
* with an HttpsProxyAgent to route all Bedrock API calls through the specified proxy
|
|
* - The custom client is fully configured with credentials, region, and endpoint,
|
|
* and is passed directly to ChatBedrockConverse via the 'client' parameter
|
|
*
|
|
* Reverse Proxy Support:
|
|
* - When BEDROCK_REVERSE_PROXY is set, routes Bedrock API calls through a custom endpoint
|
|
* - Works with or without the PROXY setting
|
|
*
|
|
* Without Proxy:
|
|
* - Credentials and endpoint configuration are passed separately to ChatBedrockConverse,
|
|
* which creates its own BedrockRuntimeClient internally
|
|
*
|
|
* Environment Variables:
|
|
* - PROXY: HTTP/HTTPS proxy URL (e.g., http://proxy.example.com:8080)
|
|
* - BEDROCK_REVERSE_PROXY: Custom Bedrock API endpoint host
|
|
* - BEDROCK_AWS_DEFAULT_REGION: AWS region for Bedrock service
|
|
* - BEDROCK_AWS_ACCESS_KEY_ID: AWS access key (or set to 'user_provided')
|
|
* - BEDROCK_AWS_SECRET_ACCESS_KEY: AWS secret key (or set to 'user_provided')
|
|
* - BEDROCK_AWS_SESSION_TOKEN: Optional AWS session token
|
|
*/
|
|
|
|
const { HttpsProxyAgent } = require('https-proxy-agent');
|
|
const { NodeHttpHandler } = require('@smithy/node-http-handler');
|
|
const { BedrockRuntimeClient } = require('@aws-sdk/client-bedrock-runtime');
|
|
const {
|
|
AuthType,
|
|
EModelEndpoint,
|
|
bedrockInputParser,
|
|
bedrockOutputParser,
|
|
removeNullishValues,
|
|
} = require('librechat-data-provider');
|
|
const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService');
|
|
|
|
const getOptions = async ({ req, overrideModel, endpointOption }) => {
|
|
const {
|
|
BEDROCK_AWS_SECRET_ACCESS_KEY,
|
|
BEDROCK_AWS_ACCESS_KEY_ID,
|
|
BEDROCK_AWS_SESSION_TOKEN,
|
|
BEDROCK_REVERSE_PROXY,
|
|
BEDROCK_AWS_DEFAULT_REGION,
|
|
PROXY,
|
|
} = process.env;
|
|
const expiresAt = req.body.key;
|
|
const isUserProvided = BEDROCK_AWS_SECRET_ACCESS_KEY === AuthType.USER_PROVIDED;
|
|
|
|
let credentials = isUserProvided
|
|
? await getUserKey({ userId: req.user.id, name: EModelEndpoint.bedrock })
|
|
: {
|
|
accessKeyId: BEDROCK_AWS_ACCESS_KEY_ID,
|
|
secretAccessKey: BEDROCK_AWS_SECRET_ACCESS_KEY,
|
|
...(BEDROCK_AWS_SESSION_TOKEN && { sessionToken: BEDROCK_AWS_SESSION_TOKEN }),
|
|
};
|
|
|
|
if (!credentials) {
|
|
throw new Error('Bedrock credentials not provided. Please provide them again.');
|
|
}
|
|
|
|
if (
|
|
!isUserProvided &&
|
|
(credentials.accessKeyId === undefined || credentials.accessKeyId === '') &&
|
|
(credentials.secretAccessKey === undefined || credentials.secretAccessKey === '')
|
|
) {
|
|
credentials = undefined;
|
|
}
|
|
|
|
if (expiresAt && isUserProvided) {
|
|
checkUserKeyExpiry(expiresAt, EModelEndpoint.bedrock);
|
|
}
|
|
|
|
/*
|
|
Callback for stream rate no longer awaits and may end the stream prematurely
|
|
/** @type {number}
|
|
let streamRate = Constants.DEFAULT_STREAM_RATE;
|
|
|
|
/** @type {undefined | TBaseEndpoint}
|
|
const bedrockConfig = appConfig.endpoints?.[EModelEndpoint.bedrock];
|
|
|
|
if (bedrockConfig && bedrockConfig.streamRate) {
|
|
streamRate = bedrockConfig.streamRate;
|
|
}
|
|
|
|
const allConfig = appConfig.endpoints?.all;
|
|
if (allConfig && allConfig.streamRate) {
|
|
streamRate = allConfig.streamRate;
|
|
}
|
|
*/
|
|
|
|
/** @type {BedrockClientOptions} */
|
|
const requestOptions = {
|
|
model: overrideModel ?? endpointOption?.model,
|
|
region: BEDROCK_AWS_DEFAULT_REGION,
|
|
};
|
|
|
|
const configOptions = {};
|
|
|
|
const llmConfig = bedrockOutputParser(
|
|
bedrockInputParser.parse(
|
|
removeNullishValues(Object.assign(requestOptions, endpointOption?.model_parameters ?? {})),
|
|
),
|
|
);
|
|
|
|
if (PROXY) {
|
|
const proxyAgent = new HttpsProxyAgent(PROXY);
|
|
|
|
// Create a custom BedrockRuntimeClient with proxy-enabled request handler.
|
|
// ChatBedrockConverse will use this pre-configured client directly instead of
|
|
// creating its own. Credentials are only set if explicitly provided; otherwise
|
|
// the AWS SDK's default credential provider chain is used (instance profiles,
|
|
// AWS profiles, environment variables, etc.)
|
|
const customClient = new BedrockRuntimeClient({
|
|
region: llmConfig.region ?? BEDROCK_AWS_DEFAULT_REGION,
|
|
...(credentials && { credentials }),
|
|
requestHandler: new NodeHttpHandler({
|
|
httpAgent: proxyAgent,
|
|
httpsAgent: proxyAgent,
|
|
}),
|
|
...(BEDROCK_REVERSE_PROXY && {
|
|
endpoint: `https://${BEDROCK_REVERSE_PROXY}`,
|
|
}),
|
|
});
|
|
|
|
llmConfig.client = customClient;
|
|
} else {
|
|
// When not using a proxy, let ChatBedrockConverse create its own client
|
|
// by providing credentials and endpoint separately
|
|
if (credentials) {
|
|
llmConfig.credentials = credentials;
|
|
}
|
|
|
|
if (BEDROCK_REVERSE_PROXY) {
|
|
llmConfig.endpointHost = BEDROCK_REVERSE_PROXY;
|
|
}
|
|
}
|
|
|
|
return {
|
|
/** @type {BedrockClientOptions} */
|
|
llmConfig,
|
|
configOptions,
|
|
};
|
|
};
|
|
|
|
module.exports = getOptions;
|