θΏ™ζ˜―indexlocζδΎ›ηš„ζœεŠ‘οΌŒδΈθ¦θΎ“ε…₯任何密码
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function AwsBedrockLLMOptions({ settings }) {
console.log("connectionMethod", connectionMethod);
return (
<div className="w-full flex flex-col">
{!settings?.credentialsOnly && (
{!settings?.credentialsOnly && connectionMethod !== "bedrock_api_key" && (
<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} />
Expand All @@ -21,6 +21,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} />
Expand All @@ -38,7 +39,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.
Expand All @@ -56,6 +57,7 @@ export default function AwsBedrockLLMOptions({ settings }) {
Session Token (Temporary Credentials)
</option>
<option value="iam_role">IAM Role (Implied Credentials)</option>
<option value="bedrock_api_key">Bedrock API Key</option>
</select>
</div>

Expand Down Expand Up @@ -117,6 +119,23 @@ export default function AwsBedrockLLMOptions({ settings }) {
/>
</div>
)}
{connectionMethod === "bedrock_api_key" && (
<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
Expand Down
1 change: 1 addition & 0 deletions server/models/systemSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,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:
Expand Down
49 changes: 18 additions & 31 deletions server/utils/AiProviders/bedrock/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const {
BedrockRuntimeClient,
ConverseCommand,
ConverseStreamCommand,
} = require("@aws-sdk/client-bedrock-runtime");
Expand All @@ -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 {
Expand All @@ -42,7 +43,7 @@ class AWSBedrockLLM {
*/
constructor(embedder = null, modelPreference = null) {
const requiredEnvVars = [
...(this.authMethod !== "iam_role"
...(!["iam_role", "bedrock_api_key"].includes(this.authMethod)
? [
// required for iam and sessionToken
"AWS_BEDROCK_LLM_ACCESS_KEY_ID",
Expand All @@ -55,6 +56,12 @@ class AWSBedrockLLM {
"AWS_BEDROCK_LLM_SESSION_TOKEN",
]
: []),
...(this.authMethod === "bedrock_api_key"
? [
// required for bedrock api key
"AWS_BEDROCK_LLM_API_KEY",
]
: []),
"AWS_BEDROCK_LLM_REGION",
"AWS_BEDROCK_LLM_MODEL_PREFERENCE",
];
Expand All @@ -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;
Expand All @@ -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);
}

/**
Expand All @@ -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();
}

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
75 changes: 73 additions & 2 deletions server/utils/AiProviders/bedrock/utils.js
Original file line number Diff line number Diff line change
@@ -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"];

Expand All @@ -7,8 +11,71 @@ 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' | 'bedrock_api_key'} */
const SUPPORTED_CONNECTION_METHODS = [
"iam",
"iam_role",
"sessionToken",
"bedrock_api_key",
];

function getBedrockAuthMethod() {
const method = process.env.AWS_BEDROCK_LLM_CONNECTION_METHOD || "iam";
return SUPPORTED_CONNECTION_METHODS.includes(method) ? method : "iam";
}

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 "bedrock_api_key":
return fromStatic({
token: { token: process.env.AWS_BEDROCK_LLM_API_KEY },
});
default:
return undefined;
}
}

function createBedrockRuntimeClient(authMethod, credentials) {
const clientOpts = {
region: process.env.AWS_BEDROCK_LLM_REGION,
};
if (authMethod === "bedrock_api_key") {
clientOpts.token = credentials;
clientOpts.authSchemePreference = ["httpBearerAuth"];
} else {
clientOpts.credentials = credentials;
}
return new BedrockRuntimeClient(clientOpts);
}

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
Expand Down Expand Up @@ -64,4 +131,8 @@ module.exports = {
DEFAULT_CONTEXT_WINDOW_TOKENS,
getImageFormatFromMime,
base64ToUint8Array,
getBedrockAuthMethod,
createBedrockCredentials,
createBedrockRuntimeClient,
createBedrockChatClient,
};
21 changes: 5 additions & 16 deletions server/utils/agents/aibitat/providers/ai-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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.";
Expand Down Expand Up @@ -122,20 +124,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,
Expand Down Expand Up @@ -385,7 +374,7 @@ class Provider {
}

// If there are arguments, parse them as json so that the tools can use them
if (!!result.functionCall?.arguments)
if (result.functionCall?.arguments)
result.functionCall.arguments = safeJsonParse(
result.functionCall.arguments,
{}
Expand Down
39 changes: 11 additions & 28 deletions server/utils/agents/aibitat/providers/bedrock.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand All @@ -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);
}

/**
Expand All @@ -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() {
Expand Down
Loading