Documentation Index Fetch the complete documentation index at: https://docs.exulu.com/llms.txt
Use this file to discover all available pages before exploring further.
ExuluVariables object
ExuluVariables is exported as a utility object:
import { ExuluVariables } from "@exulu/backend" ;
// Access the get method
const value = await ExuluVariables . get ( "variable_name" );
Methods
Retrieves and decrypts a variable value from the database.
async get ( name : string ): Promise < string >
The unique name of the variable to retrieve
The decrypted variable value
import { ExuluVariables } from "@exulu/backend" ;
// Retrieve a variable
const apiKey = await ExuluVariables . get ( "openai_api_key" );
console . log ( apiKey ); // "sk-proj-..."
Behavior:
Queries the variables table for the specified name
Throws an error if the variable is not found
If encrypted: true, decrypts the value using AES with NEXTAUTH_SECRET
Returns the decrypted (or plain) value
Error handling:
try {
const apiKey = await ExuluVariables . get ( "my_variable" );
console . log ( "Retrieved:" , apiKey );
} catch ( error ) {
console . error ( "Error:" , error . message );
// Error: Variable my_variable not found.
}
Throws:
Error if variable name doesn’t exist
Error if database connection fails
Error if decryption fails (wrong NEXTAUTH_SECRET)
Variable type
Variables in the database follow this structure:
interface Variable {
name : string ; // Primary key, unique identifier
value : string ; // Encrypted or plain text value
encrypted : boolean ; // Whether value is encrypted
created_at ?: Date ; // When variable was created
updated_at ?: Date ; // When variable was last updated
}
Unique variable identifier
The variable value (encrypted if encrypted: true)
Whether the value is encrypted at rest
Timestamp when last updated
Usage examples
Basic retrieval
import { ExuluVariables } from "@exulu/backend" ;
async function getApiKey () {
const apiKey = await ExuluVariables . get ( "openai_api_key" );
return apiKey ;
}
const key = await getApiKey ();
console . log ( key ); // "sk-proj-..."
With error handling
import { ExuluVariables } from "@exulu/backend" ;
async function getVariableWithFallback ( name : string , fallback : string ) {
try {
return await ExuluVariables . get ( name );
} catch ( error ) {
console . warn ( `Variable ${ name } not found, using fallback` );
return fallback ;
}
}
// Use with fallback
const apiKey = await getVariableWithFallback (
"openai_api_key" ,
process . env . OPENAI_API_KEY || ""
);
Retrieving multiple variables
import { ExuluVariables } from "@exulu/backend" ;
async function getVariables ( names : string []) {
const values = await Promise . all (
names . map (( name ) => ExuluVariables . get ( name ))
);
return Object . fromEntries (
names . map (( name , i ) => [ name , values [ i ]])
);
}
// Retrieve multiple
const vars = await getVariables ([
"openai_api_key" ,
"anthropic_api_key" ,
"google_api_key"
]);
console . log ( vars . openai_api_key ); // "sk-..."
console . log ( vars . anthropic_api_key ); // "sk-ant-..."
console . log ( vars . google_api_key ); // "AIza..."
With ExuluAgent
import { ExuluAgent , ExuluVariables } from "@exulu/backend" ;
import { createOpenAI } from "@ai-sdk/openai" ;
// Retrieve API key
const openaiKey = await ExuluVariables . get ( "openai_api_key" );
// Use in agent
const agent = new ExuluAgent ({
id: "assistant" ,
name: "AI Assistant" ,
type: "agent" ,
description: "General AI assistant" ,
provider: "openai" ,
authenticationInformation: openaiKey , // Use retrieved variable
config: {
name: "gpt-4o" ,
model: {
create : ({ apiKey }) => createOpenAI ({ apiKey: apiKey || openaiKey })( "gpt-4o" )
},
instructions: "You are a helpful assistant."
},
capabilities: { text: true , images: [], files: [], audio: [], video: [] }
});
// Generate response
const response = await agent . generateSync ({
prompt: "Hello!" ,
agentInstance: await loadAgent ( "assistant" ),
statistics: { label: "assistant" , trigger: "api" }
});
With ExuluEmbedder
import { ExuluEmbedder , ExuluVariables } from "@exulu/backend" ;
// Retrieve API key
const openaiKey = await ExuluVariables . get ( "openai_api_key" );
// Create embedder
const embedder = new ExuluEmbedder ({
id: "openai_embedder" ,
name: "OpenAI Embeddings" ,
provider: "openai" ,
model: "text-embedding-3-small" ,
vectorDimensions: 1536 ,
authenticationInformation: openaiKey // Use retrieved variable
});
// Generate embeddings
const embeddings = await embedder . generate ([
"First text to embed" ,
"Second text to embed"
]);
import { ExuluTool , ExuluVariables } from "@exulu/backend" ;
import { z } from "zod" ;
// Create tool with variable reference
const githubTool = new ExuluTool ({
id: "github_search" ,
name: "search_github" ,
description: "Searches GitHub repositories" ,
type: "function" ,
inputSchema: z . object ({
query: z . string ()
}),
config: [
{
name: "github_token" ,
type: "variable" ,
value: "github_api_token" // Variable name
}
],
execute : async ({ query }, config ) => {
// Retrieve variable inside execute
const token = await ExuluVariables . get ( "github_api_token" );
const response = await fetch (
`https://api.github.com/search/repositories?q= ${ query } ` ,
{
headers: {
Authorization: `Bearer ${ token } ` ,
"Accept" : "application/vnd.github+json"
}
}
);
const data = await response . json ();
return {
result: JSON . stringify (
data . items . slice ( 0 , 5 ). map (( item : any ) => ({
name: item . full_name ,
description: item . description ,
stars: item . stargazers_count ,
url: item . html_url
}))
)
};
}
});
Environment-aware retrieval
import { ExuluVariables } from "@exulu/backend" ;
async function getEnvironmentVariable ( baseName : string ) {
const env = process . env . NODE_ENV || "dev" ;
const variableName = ` ${ env } _ ${ baseName } ` ;
return await ExuluVariables . get ( variableName );
}
// In development: retrieves "dev_openai_api_key"
// In production: retrieves "prod_openai_api_key"
const apiKey = await getEnvironmentVariable ( "openai_api_key" );
Tenant-specific retrieval
import { ExuluVariables } from "@exulu/backend" ;
async function getTenantVariable ( tenantId : string , variableName : string ) {
const fullName = `tenant_ ${ tenantId } _ ${ variableName } ` ;
return await ExuluVariables . get ( fullName );
}
// Retrieve tenant-specific API key
const tenantApiKey = await getTenantVariable ( "acme_corp" , "openai_api_key" );
// Retrieves "tenant_acme_corp_openai_api_key"
// Use with tenant agent
const tenantAgent = new ExuluAgent ({
id: `agent_ ${ tenantId } ` ,
name: `Agent for ${ tenantId } ` ,
type: "agent" ,
description: "Tenant-specific agent" ,
provider: "openai" ,
authenticationInformation: tenantApiKey ,
config: { /* ... */ },
capabilities: { text: true , images: [], files: [], audio: [], video: [] }
});
Caching variables
For performance, cache frequently accessed variables:
import { ExuluVariables } from "@exulu/backend" ;
class VariableCache {
private cache = new Map < string , { value : string ; expires : number }>();
private ttl : number ;
constructor ( ttlSeconds : number = 300 ) {
this . ttl = ttlSeconds * 1000 ;
}
async get ( name : string ) : Promise < string > {
const cached = this . cache . get ( name );
if ( cached && cached . expires > Date . now ()) {
return cached . value ;
}
const value = await ExuluVariables . get ( name );
this . cache . set ( name , {
value ,
expires: Date . now () + this . ttl
});
return value ;
}
invalidate ( name : string ) {
this . cache . delete ( name );
}
clear () {
this . cache . clear ();
}
}
// Use cache
const cache = new VariableCache ( 300 ); // 5 minute TTL
const apiKey = await cache . get ( "openai_api_key" ); // Fetches from DB
const apiKey2 = await cache . get ( "openai_api_key" ); // Returns cached value
Validating variables on startup
import { ExuluVariables } from "@exulu/backend" ;
const REQUIRED_VARIABLES = [
"openai_api_key" ,
"anthropic_api_key" ,
"database_url" ,
"redis_url"
];
async function validateRequiredVariables () {
const missing : string [] = [];
for ( const name of REQUIRED_VARIABLES ) {
try {
await ExuluVariables . get ( name );
console . log ( `✓ ${ name } ` );
} catch ( error ) {
console . error ( `✗ ${ name } ` );
missing . push ( name );
}
}
if ( missing . length > 0 ) {
throw new Error (
`Missing required variables: ${ missing . join ( ", " ) } \n ` +
`Please add them to the database via UI or SQL.`
);
}
console . log ( "All required variables present." );
}
// Run on application startup
validateRequiredVariables ()
. then (() => console . log ( "Starting application..." ))
. catch (( error ) => {
console . error ( "Startup failed:" , error . message );
process . exit ( 1 );
});
Dynamic configuration
import { ExuluVariables } from "@exulu/backend" ;
async function getDynamicConfig () {
const config = {
llm: {
provider: await ExuluVariables . get ( "llm_provider" ). catch (() => "openai" ),
apiKey: await ExuluVariables . get ( "llm_api_key" ),
model: await ExuluVariables . get ( "llm_model" ). catch (() => "gpt-4o" )
},
embeddings: {
provider: await ExuluVariables . get ( "embeddings_provider" ). catch (() => "openai" ),
apiKey: await ExuluVariables . get ( "embeddings_api_key" ),
model: await ExuluVariables . get ( "embeddings_model" ). catch (() => "text-embedding-3-small" )
},
features: {
analytics: await ExuluVariables . get ( "feature_analytics" ). catch (() => "false" ) === "true" ,
rateLimit: parseInt ( await ExuluVariables . get ( "rate_limit_per_minute" ). catch (() => "100" ))
}
};
return config ;
}
// Use dynamic config
const config = await getDynamicConfig ();
const agent = new ExuluAgent ({
id: "dynamic_agent" ,
name: "Dynamic Agent" ,
type: "agent" ,
provider: config . llm . provider ,
authenticationInformation: config . llm . apiKey ,
config: {
name: config . llm . model ,
// ...
},
capabilities: { text: true , images: [], files: [], audio: [], video: [] }
});
Secret rotation helper
import { ExuluVariables , postgresClient } from "@exulu/backend" ;
import CryptoJS from "crypto-js" ;
async function rotateSecret ( variableName : string , newValue : string ) {
const { db } = await postgresClient ();
// Verify old value works
try {
const oldValue = await ExuluVariables . get ( variableName );
console . log ( "Current value retrieved successfully" );
} catch ( error ) {
throw new Error ( `Cannot retrieve current value: ${ error . message } ` );
}
// Encrypt new value
const encrypted = CryptoJS . AES . encrypt (
newValue ,
process . env . NEXTAUTH_SECRET
). toString ();
// Update variable
await db ( "variables" )
. where ({ name: variableName })
. update ({
value: encrypted ,
updated_at: new Date ()
});
// Verify new value
const updated = await ExuluVariables . get ( variableName );
if ( updated !== newValue ) {
throw new Error ( "Verification failed after rotation" );
}
console . log ( `✓ Secret rotated successfully: ${ variableName } ` );
}
// Rotate API key
await rotateSecret ( "openai_api_key" , "sk-proj-NEW_KEY_HERE" );
Listing variables
import { postgresClient } from "@exulu/backend" ;
async function listVariables () {
const { db } = await postgresClient ();
const variables = await db
. from ( "variables" )
. select ( "name" , "encrypted" , "created_at" , "updated_at" )
. orderBy ( "name" );
console . log ( "Variables:" );
for ( const v of variables ) {
console . log ( ` ${ v . name } (encrypted: ${ v . encrypted } )` );
}
return variables ;
}
await listVariables ();
// Variables:
// anthropic_api_key (encrypted: true)
// app_name (encrypted: false)
// app_version (encrypted: false)
// openai_api_key (encrypted: true)
Integration patterns
Factory function with variables
import { ExuluAgent , ExuluVariables } from "@exulu/backend" ;
import { createOpenAI } from "@ai-sdk/openai" ;
async function createAgentWithVariables (
id : string ,
provider : string ,
variableName : string
) {
const apiKey = await ExuluVariables . get ( variableName );
return new ExuluAgent ({
id ,
name: `Agent ${ id } ` ,
type: "agent" ,
description: "Agent with variable-based auth" ,
provider ,
authenticationInformation: apiKey ,
config: {
name: "gpt-4o" ,
model: {
create : ({ apiKey : key }) => createOpenAI ({ apiKey: key || apiKey })( "gpt-4o" )
},
instructions: "You are a helpful assistant."
},
capabilities: { text: true , images: [], files: [], audio: [], video: [] }
});
}
// Create agents
const agent1 = await createAgentWithVariables ( "agent1" , "openai" , "openai_api_key" );
const agent2 = await createAgentWithVariables ( "agent2" , "anthropic" , "anthropic_api_key" );
Middleware for API authentication
import { ExuluVariables } from "@exulu/backend" ;
import express from "express" ;
const app = express ();
// Middleware to inject API keys
app . use ( async ( req , res , next ) => {
try {
req . apiKeys = {
openai: await ExuluVariables . get ( "openai_api_key" ),
anthropic: await ExuluVariables . get ( "anthropic_api_key" ),
google: await ExuluVariables . get ( "google_api_key" )
};
next ();
} catch ( error ) {
res . status ( 500 ). json ({ error: "Failed to load API keys" });
}
});
// Use in routes
app . post ( "/api/generate" , async ( req , res ) => {
const { provider } = req . body ;
const agent = new ExuluAgent ({
id: "api_agent" ,
provider ,
authenticationInformation: req . apiKeys [ provider ],
// ...
});
const response = await agent . generateSync ({
prompt: req . body . prompt ,
agentInstance: await loadAgent ( "api_agent" ),
statistics: { label: "api" , trigger: "http" }
});
res . json ({ response });
});
Best practices
Cache variables : For frequently accessed variables, implement caching to reduce database queries.
Handle errors gracefully : Always wrap ExuluVariables.get() in try/catch to handle missing variables.
Don’t expose values : Never return variable values through public APIs or logs. Only use them internally.
Validate on startup : Check that all required variables exist before starting your application.
Error reference
Variable not found
// Error: Variable my_variable not found.
Cause : Variable doesn’t exist in database
Solution : Create the variable:
INSERT INTO variables ( name , value , encrypted )
VALUES ( 'my_variable' , 'value' , true);
Decryption error
// Error: Malformed UTF-8 data
Cause : Wrong NEXTAUTH_SECRET or corrupted encrypted value
Solution : Re-encrypt with correct secret or verify NEXTAUTH_SECRET is correct
Database connection error
// Error: Connection refused / timeout
Cause : Database not accessible
Solution : Check database connection settings and ensure database is running
Type definitions
// Variable database record
interface Variable {
name : string ;
value : string ;
encrypted : boolean ;
created_at ?: Date ;
updated_at ?: Date ;
}
// ExuluVariables utility
interface ExuluVariables {
get ( name : string ) : Promise < string >;
}
Next steps
Configuration guide Learn about setup and management
Overview Understand variable concepts
ExuluAgent Use variables with agents
ExuluTool Use variables with tools