feature: Support for AWS Bedrock API Keys (#4651)
* feat: add AWS Bedrock API Key option to settings panel * feat: Bedrock API key auth method * fix: hide IAM note when using bedrock api key * move to camcelCase identifier for bedrock api key use linting --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
2eb5384e27
commit
c169193fc4
@ -115,6 +115,9 @@ GID='1000'
|
||||
# AWS_BEDROCK_LLM_CONNECTION_METHOD=iam
|
||||
# AWS_BEDROCK_LLM_MAX_OUTPUT_TOKENS=4096
|
||||
# AWS_BEDROCK_LLM_SESSION_TOKEN= # Only required if CONNECTION_METHOD is 'sessionToken'
|
||||
# or even use Short and Long Term API keys
|
||||
# AWS_BEDROCK_LLM_CONNECTION_METHOD="apiKey"
|
||||
# AWS_BEDROCK_LLM_API_KEY=
|
||||
|
||||
# LLM_PROVIDER='fireworksai'
|
||||
# FIREWORKS_AI_LLM_API_KEY='my-fireworks-ai-key'
|
||||
|
||||
@ -7,10 +7,9 @@ export default function AwsBedrockLLMOptions({ settings }) {
|
||||
settings?.AwsBedrockLLMConnectionMethod ?? "iam"
|
||||
);
|
||||
|
||||
console.log("connectionMethod", connectionMethod);
|
||||
return (
|
||||
<div className="w-full flex flex-col">
|
||||
{!settings?.credentialsOnly && (
|
||||
{!settings?.credentialsOnly && connectionMethod !== "apiKey" && (
|
||||
<div className="flex flex-col md:flex-row md:items-center gap-x-2 text-white mb-4 bg-blue-800/30 w-fit rounded-lg px-4 py-2">
|
||||
<div className="gap-x-2 flex items-center">
|
||||
<Info size={40} />
|
||||
@ -21,6 +20,7 @@ export default function AwsBedrockLLMOptions({ settings }) {
|
||||
href="https://docs.anythingllm.com/setup/llm-configuration/cloud/aws-bedrock"
|
||||
target="_blank"
|
||||
className="underline flex gap-x-1 items-center"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Read more on how to use AWS Bedrock in AnythingLLM
|
||||
<ArrowSquareOut size={14} />
|
||||
@ -38,7 +38,7 @@ export default function AwsBedrockLLMOptions({ settings }) {
|
||||
/>
|
||||
<div className="flex flex-col w-full">
|
||||
<label className="text-theme-text-primary text-sm font-semibold block mb-3">
|
||||
Use session token
|
||||
Authentication Method
|
||||
</label>
|
||||
<p className="text-theme-text-secondary text-sm">
|
||||
Select the method to authenticate with AWS Bedrock.
|
||||
@ -56,6 +56,7 @@ export default function AwsBedrockLLMOptions({ settings }) {
|
||||
Session Token (Temporary Credentials)
|
||||
</option>
|
||||
<option value="iam_role">IAM Role (Implied Credentials)</option>
|
||||
<option value="apiKey">Bedrock API Key</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -117,6 +118,23 @@ export default function AwsBedrockLLMOptions({ settings }) {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{connectionMethod === "apiKey" && (
|
||||
<div className="flex flex-col w-60">
|
||||
<label className="text-theme-text-primary text-sm font-semibold block mb-3">
|
||||
AWS Bedrock API Key
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name="AwsBedrockLLMAPIKey"
|
||||
className="border-none bg-theme-settings-input-bg text-theme-text-primary placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
|
||||
placeholder="AWS Bedrock API Key"
|
||||
defaultValue={settings?.AwsBedrockLLMAPIKey ? "*".repeat(20) : ""}
|
||||
required={true}
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col w-60">
|
||||
<label className="text-white text-sm font-semibold block mb-3">
|
||||
AWS region
|
||||
|
||||
@ -122,6 +122,9 @@ SIG_SALT='salt' # Please generate random string at least 32 chars long.
|
||||
# AWS_BEDROCK_LLM_CONNECTION_METHOD=iam
|
||||
# AWS_BEDROCK_LLM_MAX_OUTPUT_TOKENS=4096
|
||||
# AWS_BEDROCK_LLM_SESSION_TOKEN= # Only required if CONNECTION_METHOD is 'sessionToken'
|
||||
# or even use Short and Long Term API keys
|
||||
# AWS_BEDROCK_LLM_CONNECTION_METHOD="apiKey"
|
||||
# AWS_BEDROCK_LLM_API_KEY=
|
||||
|
||||
# LLM_PROVIDER='apipie'
|
||||
# APIPIE_LLM_API_KEY='sk-123abc'
|
||||
|
||||
@ -582,6 +582,7 @@ const SystemSettings = {
|
||||
AwsBedrockLLMAccessKeyId: !!process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
AwsBedrockLLMAccessKey: !!process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
AwsBedrockLLMSessionToken: !!process.env.AWS_BEDROCK_LLM_SESSION_TOKEN,
|
||||
AwsBedrockLLMAPIKey: !!process.env.AWS_BEDROCK_LLM_API_KEY,
|
||||
AwsBedrockLLMRegion: process.env.AWS_BEDROCK_LLM_REGION,
|
||||
AwsBedrockLLMModel: process.env.AWS_BEDROCK_LLM_MODEL_PREFERENCE,
|
||||
AwsBedrockLLMTokenLimit:
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
const {
|
||||
BedrockRuntimeClient,
|
||||
ConverseCommand,
|
||||
ConverseStreamCommand,
|
||||
} = require("@aws-sdk/client-bedrock-runtime");
|
||||
@ -15,9 +14,11 @@ const { v4: uuidv4 } = require("uuid");
|
||||
const {
|
||||
DEFAULT_MAX_OUTPUT_TOKENS,
|
||||
DEFAULT_CONTEXT_WINDOW_TOKENS,
|
||||
SUPPORTED_CONNECTION_METHODS,
|
||||
getImageFormatFromMime,
|
||||
base64ToUint8Array,
|
||||
createBedrockCredentials,
|
||||
createBedrockRuntimeClient,
|
||||
getBedrockAuthMethod,
|
||||
} = require("./utils");
|
||||
|
||||
class AWSBedrockLLM {
|
||||
@ -42,7 +43,7 @@ class AWSBedrockLLM {
|
||||
*/
|
||||
constructor(embedder = null, modelPreference = null) {
|
||||
const requiredEnvVars = [
|
||||
...(this.authMethod !== "iam_role"
|
||||
...(!["iam_role", "apiKey"].includes(this.authMethod)
|
||||
? [
|
||||
// required for iam and sessionToken
|
||||
"AWS_BEDROCK_LLM_ACCESS_KEY_ID",
|
||||
@ -55,6 +56,12 @@ class AWSBedrockLLM {
|
||||
"AWS_BEDROCK_LLM_SESSION_TOKEN",
|
||||
]
|
||||
: []),
|
||||
...(this.authMethod === "apiKey"
|
||||
? [
|
||||
// required for bedrock api key
|
||||
"AWS_BEDROCK_LLM_API_KEY",
|
||||
]
|
||||
: []),
|
||||
"AWS_BEDROCK_LLM_REGION",
|
||||
"AWS_BEDROCK_LLM_MODEL_PREFERENCE",
|
||||
];
|
||||
@ -75,10 +82,10 @@ class AWSBedrockLLM {
|
||||
user: Math.floor(contextWindowLimit * 0.7),
|
||||
};
|
||||
|
||||
this.bedrockClient = new BedrockRuntimeClient({
|
||||
region: process.env.AWS_BEDROCK_LLM_REGION,
|
||||
credentials: this.credentials,
|
||||
});
|
||||
this.bedrockClient = createBedrockRuntimeClient(
|
||||
this.authMethod,
|
||||
this.credentials
|
||||
);
|
||||
|
||||
this.embedder = embedder ?? new NativeEmbedder();
|
||||
this.defaultTemp = 0.7;
|
||||
@ -92,26 +99,7 @@ class AWSBedrockLLM {
|
||||
* @returns {object} The credentials object.
|
||||
*/
|
||||
get credentials() {
|
||||
switch (this.authMethod) {
|
||||
case "iam": // explicit credentials
|
||||
return {
|
||||
accessKeyId: process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
};
|
||||
case "sessionToken": // Session token is used for temporary credentials
|
||||
return {
|
||||
accessKeyId: process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
sessionToken: process.env.AWS_BEDROCK_LLM_SESSION_TOKEN,
|
||||
};
|
||||
// IAM role is used for long-term credentials implied by system process
|
||||
// is filled by the AWS SDK automatically if we pass in no credentials
|
||||
// returning undefined will allow this to happen
|
||||
case "iam_role":
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
return createBedrockCredentials(this.authMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,8 +108,7 @@ class AWSBedrockLLM {
|
||||
* @returns {"iam" | "iam_role" | "sessionToken"} The authentication method.
|
||||
*/
|
||||
get authMethod() {
|
||||
const method = process.env.AWS_BEDROCK_LLM_CONNECTION_METHOD || "iam";
|
||||
return SUPPORTED_CONNECTION_METHODS.includes(method) ? method : "iam";
|
||||
return getBedrockAuthMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -287,7 +274,7 @@ class AWSBedrockLLM {
|
||||
#generateContent({ userPrompt = "", attachments = [] }) {
|
||||
const content = [];
|
||||
// Add text block if prompt is not empty
|
||||
if (!!userPrompt?.trim()?.length) content.push({ text: userPrompt });
|
||||
if (userPrompt?.trim()?.length) content.push({ text: userPrompt });
|
||||
|
||||
// Validate attachments and add valid attachments to content
|
||||
const validAttachments = this.#validateAttachments(attachments);
|
||||
@ -384,7 +371,7 @@ class AWSBedrockLLM {
|
||||
if (reasoningBlock) {
|
||||
const reasoningText =
|
||||
reasoningBlock.reasoningContent.reasoningText.text.trim();
|
||||
if (!!reasoningText?.length)
|
||||
if (reasoningText?.length)
|
||||
textResponse = `<think>${reasoningText}</think>${textResponse}`;
|
||||
}
|
||||
return textResponse;
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
const { BedrockRuntimeClient } = require("@aws-sdk/client-bedrock-runtime");
|
||||
const { fromStatic } = require("@aws-sdk/token-providers");
|
||||
const { ChatBedrockConverse } = require("@langchain/aws");
|
||||
|
||||
/** @typedef {'jpeg' | 'png' | 'gif' | 'webp'} */
|
||||
const SUPPORTED_BEDROCK_IMAGE_FORMATS = ["jpeg", "png", "gif", "webp"];
|
||||
|
||||
@ -7,8 +11,95 @@ const DEFAULT_MAX_OUTPUT_TOKENS = 4096;
|
||||
/** @type {number} */
|
||||
const DEFAULT_CONTEXT_WINDOW_TOKENS = 8191;
|
||||
|
||||
/** @type {'iam' | 'iam_role' | 'sessionToken'} */
|
||||
const SUPPORTED_CONNECTION_METHODS = ["iam", "iam_role", "sessionToken"];
|
||||
/** @type {'iam' | 'iam_role' | 'sessionToken' | 'apiKey'} */
|
||||
const SUPPORTED_CONNECTION_METHODS = [
|
||||
"iam",
|
||||
"iam_role",
|
||||
"sessionToken",
|
||||
"apiKey",
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets the AWS Bedrock authentication method from the environment variables.
|
||||
* @returns {"iam" | "iam_role" | "sessionToken" | "apiKey"} The authentication method.
|
||||
*/
|
||||
function getBedrockAuthMethod() {
|
||||
const method = process.env.AWS_BEDROCK_LLM_CONNECTION_METHOD || "iam";
|
||||
return SUPPORTED_CONNECTION_METHODS.includes(method) ? method : "iam";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the AWS Bedrock credentials object based on the authentication method.
|
||||
* @param {"iam" | "iam_role" | "sessionToken" | "apiKey"} authMethod - The authentication method.
|
||||
* @returns {object | undefined} The credentials object.
|
||||
*/
|
||||
function createBedrockCredentials(authMethod) {
|
||||
switch (authMethod) {
|
||||
case "iam": // explicit credentials
|
||||
return {
|
||||
accessKeyId: process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
};
|
||||
case "sessionToken": // Session token is used for temporary credentials
|
||||
return {
|
||||
accessKeyId: process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
sessionToken: process.env.AWS_BEDROCK_LLM_SESSION_TOKEN,
|
||||
};
|
||||
// IAM role is used for long-term credentials implied by system process
|
||||
// is filled by the AWS SDK automatically if we pass in no credentials
|
||||
// returning undefined will allow this to happen
|
||||
case "iam_role":
|
||||
return undefined;
|
||||
case "apiKey":
|
||||
return fromStatic({
|
||||
token: { token: process.env.AWS_BEDROCK_LLM_API_KEY },
|
||||
});
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the AWS Bedrock runtime client based on the authentication method.
|
||||
* @param {"iam" | "iam_role" | "sessionToken" | "apiKey"} authMethod - The authentication method.
|
||||
* @param {object | undefined} credentials - The credentials object.
|
||||
* @returns {BedrockRuntimeClient} The runtime client.
|
||||
*/
|
||||
function createBedrockRuntimeClient(authMethod, credentials) {
|
||||
const clientOpts = {
|
||||
region: process.env.AWS_BEDROCK_LLM_REGION,
|
||||
};
|
||||
if (authMethod === "apiKey") {
|
||||
clientOpts.token = credentials;
|
||||
clientOpts.authSchemePreference = ["httpBearerAuth"];
|
||||
} else {
|
||||
clientOpts.credentials = credentials;
|
||||
}
|
||||
return new BedrockRuntimeClient(clientOpts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the AWS Bedrock chat client based on the authentication method.
|
||||
* Used explicitly by the agent provider for the AWS Bedrock provider.
|
||||
* @param {object} config - The configuration object.
|
||||
* @param {"iam" | "iam_role" | "sessionToken" | "apiKey"} authMethod - The authentication method.
|
||||
* @param {object | undefined} credentials - The credentials object.
|
||||
* @param {string | null} model - The model to use.
|
||||
* @returns {ChatBedrockConverse} The chat client.
|
||||
*/
|
||||
function createBedrockChatClient(config = {}, authMethod, credentials, model) {
|
||||
authMethod ||= getBedrockAuthMethod();
|
||||
credentials ||= createBedrockCredentials(authMethod);
|
||||
model ||= process.env.AWS_BEDROCK_LLM_MODEL_PREFERENCE ?? null;
|
||||
const client = createBedrockRuntimeClient(authMethod, credentials);
|
||||
return new ChatBedrockConverse({
|
||||
region: process.env.AWS_BEDROCK_LLM_REGION,
|
||||
client,
|
||||
model,
|
||||
...config,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a MIME type string (e.g., "image/jpeg") to extract and validate the image format
|
||||
@ -64,4 +155,8 @@ module.exports = {
|
||||
DEFAULT_CONTEXT_WINDOW_TOKENS,
|
||||
getImageFormatFromMime,
|
||||
base64ToUint8Array,
|
||||
getBedrockAuthMethod,
|
||||
createBedrockCredentials,
|
||||
createBedrockRuntimeClient,
|
||||
createBedrockChatClient,
|
||||
};
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
const { v4 } = require("uuid");
|
||||
const { ChatOpenAI } = require("@langchain/openai");
|
||||
const { ChatAnthropic } = require("@langchain/anthropic");
|
||||
const { ChatBedrockConverse } = require("@langchain/aws");
|
||||
const { ChatOllama } = require("@langchain/community/chat_models/ollama");
|
||||
const { toValidNumber, safeJsonParse } = require("../../../http");
|
||||
const { getLLMProviderClass } = require("../../../helpers");
|
||||
@ -22,6 +21,9 @@ const { parseFoundryBasePath } = require("../../../AiProviders/foundry");
|
||||
const {
|
||||
SystemPromptVariables,
|
||||
} = require("../../../../models/systemPromptVariables");
|
||||
const {
|
||||
createBedrockChatClient,
|
||||
} = require("../../../AiProviders/bedrock/utils");
|
||||
|
||||
const DEFAULT_WORKSPACE_PROMPT =
|
||||
"You are a helpful ai assistant who can assist the user and use tools available to help answer the users prompts and questions.";
|
||||
@ -151,20 +153,7 @@ class Provider {
|
||||
...config,
|
||||
});
|
||||
case "bedrock":
|
||||
// Grab just the credentials from the bedrock provider
|
||||
// using a closure to avoid circular dependency + to avoid instantiating the provider
|
||||
const credentials = (() => {
|
||||
const AWSBedrockProvider = require("./bedrock");
|
||||
const bedrockProvider = new AWSBedrockProvider();
|
||||
return bedrockProvider.credentials;
|
||||
})();
|
||||
|
||||
return new ChatBedrockConverse({
|
||||
model: process.env.AWS_BEDROCK_LLM_MODEL_PREFERENCE,
|
||||
region: process.env.AWS_BEDROCK_LLM_REGION,
|
||||
credentials: credentials,
|
||||
...config,
|
||||
});
|
||||
return createBedrockChatClient(config);
|
||||
case "fireworksai":
|
||||
return new ChatOpenAI({
|
||||
apiKey: process.env.FIREWORKS_AI_LLM_API_KEY,
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
const {
|
||||
SUPPORTED_CONNECTION_METHODS,
|
||||
createBedrockCredentials,
|
||||
getBedrockAuthMethod,
|
||||
createBedrockChatClient,
|
||||
} = require("../../../AiProviders/bedrock/utils.js");
|
||||
const Provider = require("./ai-provider.js");
|
||||
const InheritMultiple = require("./helpers/classes.js");
|
||||
const UnTooled = require("./helpers/untooled.js");
|
||||
const { ChatBedrockConverse } = require("@langchain/aws");
|
||||
const {
|
||||
HumanMessage,
|
||||
SystemMessage,
|
||||
@ -20,11 +21,12 @@ class AWSBedrockProvider extends InheritMultiple([Provider, UnTooled]) {
|
||||
constructor(_config = {}) {
|
||||
super();
|
||||
const model = process.env.AWS_BEDROCK_LLM_MODEL_PREFERENCE ?? null;
|
||||
const client = new ChatBedrockConverse({
|
||||
region: process.env.AWS_BEDROCK_LLM_REGION,
|
||||
credentials: this.credentials,
|
||||
model,
|
||||
});
|
||||
const client = createBedrockChatClient(
|
||||
{},
|
||||
this.authMethod,
|
||||
this.credentials,
|
||||
model
|
||||
);
|
||||
|
||||
this._client = client;
|
||||
this.model = model;
|
||||
@ -36,25 +38,7 @@ class AWSBedrockProvider extends InheritMultiple([Provider, UnTooled]) {
|
||||
* @returns {object} The credentials object.
|
||||
*/
|
||||
get credentials() {
|
||||
switch (this.authMethod) {
|
||||
case "iam": // explicit credentials
|
||||
return {
|
||||
accessKeyId: process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
};
|
||||
case "sessionToken": // Session token is used for temporary credentials
|
||||
return {
|
||||
accessKeyId: process.env.AWS_BEDROCK_LLM_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_BEDROCK_LLM_ACCESS_KEY,
|
||||
sessionToken: process.env.AWS_BEDROCK_LLM_SESSION_TOKEN,
|
||||
};
|
||||
// IAM role is used for long-term credentials implied by system process
|
||||
// is filled by the AWS SDK automatically if we pass in no credentials
|
||||
case "iam_role":
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
return createBedrockCredentials(this.authMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,8 +47,7 @@ class AWSBedrockProvider extends InheritMultiple([Provider, UnTooled]) {
|
||||
* @returns {"iam" | "iam_role" | "sessionToken"} The authentication method.
|
||||
*/
|
||||
get authMethod() {
|
||||
const method = process.env.AWS_BEDROCK_LLM_CONNECTION_METHOD || "iam";
|
||||
return SUPPORTED_CONNECTION_METHODS.includes(method) ? method : "iam";
|
||||
return getBedrockAuthMethod();
|
||||
}
|
||||
|
||||
get client() {
|
||||
|
||||
@ -235,16 +235,20 @@ const KEY_MAPPING = {
|
||||
},
|
||||
AwsBedrockLLMAccessKeyId: {
|
||||
envKey: "AWS_BEDROCK_LLM_ACCESS_KEY_ID",
|
||||
checks: [isNotEmpty],
|
||||
checks: [],
|
||||
},
|
||||
AwsBedrockLLMAccessKey: {
|
||||
envKey: "AWS_BEDROCK_LLM_ACCESS_KEY",
|
||||
checks: [isNotEmpty],
|
||||
checks: [],
|
||||
},
|
||||
AwsBedrockLLMSessionToken: {
|
||||
envKey: "AWS_BEDROCK_LLM_SESSION_TOKEN",
|
||||
checks: [],
|
||||
},
|
||||
AwsBedrockLLMAPIKey: {
|
||||
envKey: "AWS_BEDROCK_LLM_API_KEY",
|
||||
checks: [],
|
||||
},
|
||||
AwsBedrockLLMRegion: {
|
||||
envKey: "AWS_BEDROCK_LLM_REGION",
|
||||
checks: [isNotEmpty],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user