@juspay/zephyr-mind
Version:
AI toolkit extracted from lighthouse with multi-provider support
230 lines (229 loc) • 9.28 kB
JavaScript
import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
import { streamText, generateText, Output } from 'ai';
// Default system context
const DEFAULT_SYSTEM_CONTEXT = {
systemPrompt: 'You are a helpful AI assistant.'
};
// Configuration helpers
const getBedrockModelId = () => {
return process.env.BEDROCK_MODEL_ID || 'arn:aws:bedrock:us-east-2:account:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0';
};
const getAWSAccessKeyId = () => {
const keyId = process.env.AWS_ACCESS_KEY_ID;
if (!keyId) {
throw new Error('AWS_ACCESS_KEY_ID environment variable is not set');
}
return keyId;
};
const getAWSSecretAccessKey = () => {
const secretKey = process.env.AWS_SECRET_ACCESS_KEY;
if (!secretKey) {
throw new Error('AWS_SECRET_ACCESS_KEY environment variable is not set');
}
return secretKey;
};
const getAWSRegion = () => {
return process.env.AWS_REGION || 'us-east-2';
};
const getAWSSessionToken = () => {
return process.env.AWS_SESSION_TOKEN;
};
const getAppEnvironment = () => {
return process.env.PUBLIC_APP_ENVIRONMENT || 'dev';
};
// Amazon Bedrock class with enhanced error handling using createAmazonBedrock
export class AmazonBedrock {
modelName;
model;
bedrock;
constructor(modelName) {
const functionTag = 'AmazonBedrock.constructor';
this.modelName = modelName || getBedrockModelId();
try {
console.log(`[${functionTag}] Function called`, { modelName: this.modelName });
// Configure AWS credentials for custom Bedrock instance
const awsConfig = {
accessKeyId: getAWSAccessKeyId(),
secretAccessKey: getAWSSecretAccessKey(),
region: getAWSRegion()
};
console.log(`[${functionTag}] AWS config validation`, {
hasAccessKeyId: !!awsConfig.accessKeyId,
hasSecretAccessKey: !!awsConfig.secretAccessKey,
region: awsConfig.region || 'MISSING'
});
// Add session token for development environment
if (getAppEnvironment() === 'dev') {
const sessionToken = getAWSSessionToken();
if (sessionToken) {
awsConfig.sessionToken = sessionToken;
console.log(`[${functionTag}] Session token added`, {
environment: 'dev'
});
}
else {
console.warn(`[${functionTag}] Session token missing`, {
environment: 'dev'
});
}
}
console.log(`[${functionTag}] AWS config created`, {
region: awsConfig.region,
hasSessionToken: !!awsConfig.sessionToken
});
console.log(`[${functionTag}] Bedrock provider creating`, {
modelName: this.modelName
});
// Create custom Bedrock provider instance with environment-based configuration
this.bedrock = createAmazonBedrock(awsConfig);
console.log(`[${functionTag}] Bedrock provider initialized`, {
modelName: this.modelName
});
console.log(`[${functionTag}] Model instance creating`, {
modelName: this.modelName
});
this.model = this.bedrock(this.modelName);
console.log(`[${functionTag}] Model instance created`, {
modelName: this.modelName
});
console.log(`[${functionTag}] Function result`, {
modelName: this.modelName,
region: awsConfig.region,
hasSessionToken: !!awsConfig.sessionToken,
success: true
});
console.log(`[${functionTag}] Initialization completed`, {
modelName: this.modelName,
region: awsConfig.region,
hasSessionToken: !!awsConfig.sessionToken
});
}
catch (err) {
console.error(`[${functionTag}] Initialization failed`, {
message: 'Error in initializing Amazon Bedrock',
modelName: this.modelName,
region: getAWSRegion(),
error: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined
});
throw err;
}
}
async streamText(prompt, analysisSchema) {
const functionTag = 'AmazonBedrock.streamText';
const provider = 'bedrock';
let chunkCount = 0;
try {
console.log(`[${functionTag}] Stream request started`, {
provider,
modelName: this.modelName,
promptLength: prompt.length
});
const streamOptions = {
model: this.model,
prompt: prompt,
system: DEFAULT_SYSTEM_CONTEXT.systemPrompt,
onError: (event) => {
const error = event.error;
const errorMessage = error instanceof Error ? error.message : String(error);
const errorStack = error instanceof Error ? error.stack : undefined;
console.error(`[${functionTag}] Stream text error`, {
provider,
modelName: this.modelName,
region: getAWSRegion(),
error: errorMessage,
stack: errorStack,
promptLength: prompt.length,
chunkCount
});
},
onFinish: (event) => {
console.log(`[${functionTag}] Stream text finished`, {
provider,
modelName: this.modelName,
region: getAWSRegion(),
finishReason: event.finishReason,
usage: event.usage,
totalChunks: chunkCount,
promptLength: prompt.length,
responseLength: event.text?.length || 0
});
},
onChunk: (event) => {
chunkCount++;
console.debug(`[${functionTag}] Stream text chunk`, {
provider,
modelName: this.modelName,
chunkNumber: chunkCount,
chunkLength: event.chunk.text?.length || 0,
chunkType: event.chunk.type
});
}
};
if (analysisSchema) {
streamOptions.experimental_output = Output.object({ schema: analysisSchema });
}
console.log(`[${functionTag}] Stream text started`, {
provider,
modelName: this.modelName,
region: getAWSRegion(),
promptLength: prompt.length
});
// Direct streamText call - let the real error bubble up
const result = streamText(streamOptions);
console.log(`[${functionTag}] Stream text call successful`, {
provider,
modelName: this.modelName,
promptLength: prompt.length
});
return result;
}
catch (err) {
console.error(`[${functionTag}] Exception`, {
provider,
modelName: this.modelName,
region: getAWSRegion(),
message: 'Error in streaming text',
err: String(err)
});
throw err; // Re-throw error to trigger fallback
}
}
async generateText(prompt, analysisSchema) {
const functionTag = 'AmazonBedrock.generateText';
const provider = 'bedrock';
try {
const generateOptions = {
model: this.model,
prompt: prompt,
system: DEFAULT_SYSTEM_CONTEXT.systemPrompt
};
if (analysisSchema) {
generateOptions.experimental_output = Output.object({ schema: analysisSchema });
}
console.log(`[${functionTag}] Generate text started`, {
provider,
modelName: this.modelName,
region: getAWSRegion(),
promptLength: prompt.length
});
const result = await generateText(generateOptions);
console.log(`[${functionTag}] Generate text completed`, {
provider,
modelName: this.modelName,
usage: result.usage,
finishReason: result.finishReason
});
return result;
}
catch (err) {
console.error(`[${functionTag}] Exception`, {
provider,
modelName: this.modelName,
message: 'Error in generating text',
err: String(err)
});
throw err; // Re-throw error to trigger fallback instead of returning null
}
}
}