1
1
import { config } from "dotenv" ;
2
2
import fs from "fs" ;
3
3
import path from "path" ;
4
+ import * as dotenv from 'dotenv' ;
4
5
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
+ }
20
16
21
17
interface Settings {
22
18
[ key : string ] : string | undefined ;
@@ -26,84 +22,163 @@ let environmentSettings: Settings = {};
26
22
27
23
/**
28
24
* Determines if code is running in a browser environment
29
- * @returns {boolean } True if in browser environment
30
25
*/
31
26
const isBrowser = ( ) : boolean => {
32
- return (
33
- typeof window !== "undefined" && typeof window . document !== "undefined"
34
- ) ;
27
+ return typeof window !== "undefined" && typeof window . document !== "undefined" ;
35
28
} ;
36
29
37
30
/**
38
31
* 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
42
32
*/
43
33
export function findNearestEnvFile ( startDir = process . cwd ( ) ) {
44
34
if ( isBrowser ( ) ) return null ;
45
35
36
+ elizaLogger . info ( 'Starting search for .env file from directory:' , startDir ) ;
46
37
let currentDir = startDir ;
47
38
48
- // Continue searching until we reach the root directory
49
39
while ( currentDir !== path . parse ( currentDir ) . root ) {
50
40
const envPath = path . join ( currentDir , ".env" ) ;
41
+ elizaLogger . info ( 'Checking for .env file at:' , envPath ) ;
51
42
52
43
if ( fs . existsSync ( envPath ) ) {
44
+ elizaLogger . info ( 'Found .env file at:' , envPath ) ;
53
45
return envPath ;
54
46
}
55
47
56
- // Move up to parent directory
57
48
currentDir = path . dirname ( currentDir ) ;
49
+ elizaLogger . info ( 'Moving up to directory:' , currentDir ) ;
58
50
}
59
51
60
- // Check root directory as well
61
52
const rootEnvPath = path . join ( path . parse ( currentDir ) . root , ".env" ) ;
53
+ elizaLogger . info ( 'Checking root directory for .env file:' , rootEnvPath ) ;
62
54
return fs . existsSync ( rootEnvPath ) ? rootEnvPath : null ;
63
55
}
64
56
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
+
65
99
/**
66
100
* Configures environment settings for browser usage
67
- * @param {Settings } settings - Object containing environment variables
68
101
*/
69
102
export function configureSettings ( settings : Settings ) {
70
103
environmentSettings = { ...settings } ;
71
104
}
72
105
73
106
/**
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
78
108
*/
79
- export function loadEnvConfig ( ) : Settings {
109
+ export async function loadEnvConfig ( ) : Promise < Settings > {
80
110
// For browser environments, return the configured settings
81
111
if ( isBrowser ( ) ) {
82
112
return environmentSettings ;
83
113
}
84
114
85
- // Node.js environment: load from .env file
115
+ elizaLogger . info ( 'Starting loadEnvConfig' ) ;
86
116
const envPath = findNearestEnvFile ( ) ;
87
117
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
+ }
90
122
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 } ` ) ;
93
129
}
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
+
94
175
return process . env as Settings ;
95
176
}
96
177
97
178
/**
98
179
* 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
102
180
*/
103
- export function getEnvVariable (
104
- key : string ,
105
- defaultValue ?: string
106
- ) : string | undefined {
181
+ export function getEnvVariable ( key : string , defaultValue ?: string ) : string | undefined {
107
182
if ( isBrowser ( ) ) {
108
183
return environmentSettings [ key ] || defaultValue ;
109
184
}
@@ -112,8 +187,6 @@ export function getEnvVariable(
112
187
113
188
/**
114
189
* Checks if a specific environment variable exists
115
- * @param {string } key - The environment variable key
116
- * @returns {boolean } True if the environment variable exists
117
190
*/
118
191
export function hasEnvVariable ( key : string ) : boolean {
119
192
if ( isBrowser ( ) ) {
@@ -123,15 +196,14 @@ export function hasEnvVariable(key: string): boolean {
123
196
}
124
197
125
198
// Initialize settings based on environment
126
- export const settings = isBrowser ( ) ? environmentSettings : loadEnvConfig ( ) ;
199
+ export const settings = isBrowser ( ) ? environmentSettings : await loadEnvConfig ( ) ;
127
200
128
201
elizaLogger . info ( "Parsed settings:" , {
129
202
USE_OPENAI_EMBEDDING : settings . USE_OPENAI_EMBEDDING ,
130
203
USE_OPENAI_EMBEDDING_TYPE : typeof settings . USE_OPENAI_EMBEDDING ,
131
204
USE_OLLAMA_EMBEDDING : settings . USE_OLLAMA_EMBEDDING ,
132
205
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" ,
135
207
} ) ;
136
208
137
- export default settings ;
209
+ export default settings ;
0 commit comments