Skip to content

Commit ace2546

Browse files
committed
AWS secrets manager integration in settings
1 parent 81d0273 commit ace2546

File tree

2 files changed

+123
-49
lines changed

2 files changed

+123
-49
lines changed

packages/core/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
"@ai-sdk/groq": "0.0.3",
5757
"@ai-sdk/openai": "1.0.5",
5858
"@anthropic-ai/sdk": "0.30.1",
59+
"@aws-sdk/client-secrets-manager": "*",
60+
"@aws-sdk/client-sts": "*",
5961
"@fal-ai/client": "1.2.0",
6062
"@types/uuid": "10.0.0",
6163
"ai": "3.4.33",

packages/core/src/settings.ts

+121-49
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import { config } from "dotenv";
22
import fs from "fs";
33
import path from "path";
4+
import * as dotenv from 'dotenv';
45
import elizaLogger from "./logger.ts";
5-
6-
elizaLogger.info("Loading embedding settings:", {
7-
USE_OPENAI_EMBEDDING: process.env.USE_OPENAI_EMBEDDING,
8-
USE_OLLAMA_EMBEDDING: process.env.USE_OLLAMA_EMBEDDING,
9-
OLLAMA_EMBEDDING_MODEL:
10-
process.env.OLLAMA_EMBEDDING_MODEL || "mxbai-embed-large",
11-
});
12-
13-
// Add this logging block
14-
elizaLogger.info("Loading character settings:", {
15-
CHARACTER_PATH: process.env.CHARACTER_PATH,
16-
ARGV: process.argv,
17-
CHARACTER_ARG: process.argv.find((arg) => arg.startsWith("--character=")),
18-
CWD: process.cwd(),
19-
});
6+
import {
7+
SecretsManagerClient,
8+
GetSecretValueCommand
9+
} from "@aws-sdk/client-secrets-manager";
10+
11+
interface SecretConfig {
12+
secretNames: string[];
13+
region: string;
14+
roleArn?: string;
15+
}
2016

2117
interface Settings {
2218
[key: string]: string | undefined;
@@ -26,84 +22,163 @@ let environmentSettings: Settings = {};
2622

2723
/**
2824
* Determines if code is running in a browser environment
29-
* @returns {boolean} True if in browser environment
3025
*/
3126
const isBrowser = (): boolean => {
32-
return (
33-
typeof window !== "undefined" && typeof window.document !== "undefined"
34-
);
27+
return typeof window !== "undefined" && typeof window.document !== "undefined";
3528
};
3629

3730
/**
3831
* Recursively searches for a .env file starting from the current directory
39-
* and moving up through parent directories (Node.js only)
40-
* @param {string} [startDir=process.cwd()] - Starting directory for the search
41-
* @returns {string|null} Path to the nearest .env file or null if not found
4232
*/
4333
export function findNearestEnvFile(startDir = process.cwd()) {
4434
if (isBrowser()) return null;
4535

36+
elizaLogger.info('Starting search for .env file from directory:', startDir);
4637
let currentDir = startDir;
4738

48-
// Continue searching until we reach the root directory
4939
while (currentDir !== path.parse(currentDir).root) {
5040
const envPath = path.join(currentDir, ".env");
41+
elizaLogger.info('Checking for .env file at:', envPath);
5142

5243
if (fs.existsSync(envPath)) {
44+
elizaLogger.info('Found .env file at:', envPath);
5345
return envPath;
5446
}
5547

56-
// Move up to parent directory
5748
currentDir = path.dirname(currentDir);
49+
elizaLogger.info('Moving up to directory:', currentDir);
5850
}
5951

60-
// Check root directory as well
6152
const rootEnvPath = path.join(path.parse(currentDir).root, ".env");
53+
elizaLogger.info('Checking root directory for .env file:', rootEnvPath);
6254
return fs.existsSync(rootEnvPath) ? rootEnvPath : null;
6355
}
6456

57+
/**
58+
* Fetches secrets from AWS Secrets Manager
59+
*/
60+
async function getSecretsManagerValues(secretConfig: SecretConfig): Promise<Record<string, string>> {
61+
elizaLogger.info('Starting to fetch secrets with config:', secretConfig);
62+
const { secretNames, region } = secretConfig;
63+
64+
const client = new SecretsManagerClient({ region });
65+
const secrets: Record<string, string> = {};
66+
67+
elizaLogger.info('Starting to fetch secrets for:', secretNames);
68+
const secretPromises = secretNames.map(async (secretName) => {
69+
elizaLogger.info('Fetching secret:', secretName);
70+
try {
71+
const response = await client.send(
72+
new GetSecretValueCommand({ SecretId: secretName })
73+
);
74+
elizaLogger.info(`Received response for secret ${secretName}`);
75+
76+
if (response.SecretString) {
77+
try {
78+
elizaLogger.info(`Attempting to parse secret ${secretName} as JSON`);
79+
const secretJson = JSON.parse(response.SecretString);
80+
elizaLogger.info(`Successfully parsed secret ${secretName}, found keys:`, Object.keys(secretJson));
81+
Object.entries(secretJson).forEach(([key, value]) => {
82+
secrets[key] = value as string;
83+
});
84+
} catch (parseError) {
85+
elizaLogger.info(`Secret ${secretName} is not JSON, storing as plain string`);
86+
secrets[secretName] = response.SecretString;
87+
}
88+
}
89+
} catch (error) {
90+
elizaLogger.error(`Failed to fetch secret ${secretName}:`, error);
91+
throw error;
92+
}
93+
});
94+
95+
await Promise.all(secretPromises);
96+
return secrets;
97+
}
98+
6599
/**
66100
* Configures environment settings for browser usage
67-
* @param {Settings} settings - Object containing environment variables
68101
*/
69102
export function configureSettings(settings: Settings) {
70103
environmentSettings = { ...settings };
71104
}
72105

73106
/**
74-
* Loads environment variables from the nearest .env file in Node.js
75-
* or returns configured settings in browser
76-
* @returns {Settings} Environment variables object
77-
* @throws {Error} If no .env file is found in Node.js environment
107+
* Loads environment variables from .env and AWS Secrets Manager
78108
*/
79-
export function loadEnvConfig(): Settings {
109+
export async function loadEnvConfig(): Promise<Settings> {
80110
// For browser environments, return the configured settings
81111
if (isBrowser()) {
82112
return environmentSettings;
83113
}
84114

85-
// Node.js environment: load from .env file
115+
elizaLogger.info('Starting loadEnvConfig');
86116
const envPath = findNearestEnvFile();
87117

88-
// attempt to Load the .env file into process.env
89-
const result = config(envPath ? { path: envPath } : {});
118+
if (!envPath) {
119+
elizaLogger.error('No .env file found in directory hierarchy');
120+
throw new Error("No .env file found in current or parent directories.");
121+
}
90122

91-
if (!result.error) {
92-
console.log(`Loaded .env file from: ${envPath}`);
123+
elizaLogger.info('Loading .env file from:', envPath);
124+
const result = config({ path: envPath });
125+
126+
if (result.error) {
127+
elizaLogger.error('Error loading .env file:', result.error);
128+
throw new Error(`Error loading .env file: ${result.error}`);
93129
}
130+
131+
// Read directly from the .env file
132+
const envConfig = dotenv.parse(fs.readFileSync(envPath));
133+
elizaLogger.info('Direct .env file contents:', envConfig);
134+
135+
// Create secretConfig using the direct .env contents
136+
const secretConfig = {
137+
secretNames: envConfig.SECRET_NAMES?.split(',') || [],
138+
region: envConfig.AWS_REGION || 'us-east-1',
139+
roleArn: envConfig.AWS_ROLE_ARN?.trim()
140+
};
141+
142+
// Load secrets from AWS if configured
143+
if (secretConfig.secretNames.length > 0) {
144+
try {
145+
const secrets = await getSecretsManagerValues(secretConfig);
146+
elizaLogger.info('Successfully fetched secrets, found keys:', Object.keys(secrets));
147+
148+
Object.entries(secrets).forEach(([key, value]) => {
149+
process.env[key] = value;
150+
});
151+
elizaLogger.info(`Loaded all secrets from AWS Secrets Manager: ${secretConfig.secretNames.join(', ')}`);
152+
} catch (error) {
153+
elizaLogger.error('Failed to load secrets from AWS Secrets Manager:', error);
154+
throw new Error(`Failed to load secrets from AWS Secrets Manager: ${error}`);
155+
}
156+
} else {
157+
elizaLogger.info('No secret names provided, skipping AWS Secrets Manager');
158+
}
159+
160+
// Log embedding settings
161+
elizaLogger.info("Loading embedding settings:", {
162+
USE_OPENAI_EMBEDDING: process.env.USE_OPENAI_EMBEDDING,
163+
USE_OLLAMA_EMBEDDING: process.env.USE_OLLAMA_EMBEDDING,
164+
OLLAMA_EMBEDDING_MODEL: process.env.OLLAMA_EMBEDDING_MODEL || "mxbai-embed-large",
165+
});
166+
167+
// Log character settings
168+
elizaLogger.info("Loading character settings:", {
169+
CHARACTER_PATH: process.env.CHARACTER_PATH,
170+
ARGV: process.argv,
171+
CHARACTER_ARG: process.argv.find((arg) => arg.startsWith("--character=")),
172+
CWD: process.cwd(),
173+
});
174+
94175
return process.env as Settings;
95176
}
96177

97178
/**
98179
* Gets a specific environment variable
99-
* @param {string} key - The environment variable key
100-
* @param {string} [defaultValue] - Optional default value if key doesn't exist
101-
* @returns {string|undefined} The environment variable value or default value
102180
*/
103-
export function getEnvVariable(
104-
key: string,
105-
defaultValue?: string
106-
): string | undefined {
181+
export function getEnvVariable(key: string, defaultValue?: string): string | undefined {
107182
if (isBrowser()) {
108183
return environmentSettings[key] || defaultValue;
109184
}
@@ -112,8 +187,6 @@ export function getEnvVariable(
112187

113188
/**
114189
* Checks if a specific environment variable exists
115-
* @param {string} key - The environment variable key
116-
* @returns {boolean} True if the environment variable exists
117190
*/
118191
export function hasEnvVariable(key: string): boolean {
119192
if (isBrowser()) {
@@ -123,15 +196,14 @@ export function hasEnvVariable(key: string): boolean {
123196
}
124197

125198
// Initialize settings based on environment
126-
export const settings = isBrowser() ? environmentSettings : loadEnvConfig();
199+
export const settings = isBrowser() ? environmentSettings : await loadEnvConfig();
127200

128201
elizaLogger.info("Parsed settings:", {
129202
USE_OPENAI_EMBEDDING: settings.USE_OPENAI_EMBEDDING,
130203
USE_OPENAI_EMBEDDING_TYPE: typeof settings.USE_OPENAI_EMBEDDING,
131204
USE_OLLAMA_EMBEDDING: settings.USE_OLLAMA_EMBEDDING,
132205
USE_OLLAMA_EMBEDDING_TYPE: typeof settings.USE_OLLAMA_EMBEDDING,
133-
OLLAMA_EMBEDDING_MODEL:
134-
settings.OLLAMA_EMBEDDING_MODEL || "mxbai-embed-large",
206+
OLLAMA_EMBEDDING_MODEL: settings.OLLAMA_EMBEDDING_MODEL || "mxbai-embed-large",
135207
});
136208

137-
export default settings;
209+
export default settings;

0 commit comments

Comments
 (0)