@ddegtyarev/aws-tools
Version:
This project contains AWS API integration tools for use in Vertex AI SDK.
127 lines (126 loc) • 6.14 kB
JavaScript
// src/tools/awsCostOptimizationHubListRecommendations.ts
import { CostOptimizationHubClient, ListRecommendationsCommand } from '@aws-sdk/client-cost-optimization-hub';
import { validateParameters } from '../utils/validation.js';
function generateRecommendationsSummary(recommendations, totalFetched, totalSavings) {
if (!recommendations || recommendations.length === 0) {
return 'No cost optimization recommendations found.';
}
const totalRecommendations = recommendations.length;
const totalMonthlySavings = parseFloat(totalSavings.amount);
// Get top 30 recommendations
const topRecommendations = recommendations.slice(0, 30);
// Create summary with one recommendation per line
const recommendationsList = topRecommendations
.map(rec => {
const savings = parseFloat(rec.estimatedMonthlySavings || '0');
return `${rec.type}: ${rec.title} ($${savings.toFixed(2)}/month savings)`;
})
.join('\n');
return `Found ${totalRecommendations} cost optimization recommendations out of ${totalFetched} total. ` +
`Total potential monthly savings: $${totalMonthlySavings.toFixed(2)}.\n\n` +
`Top recommendations:\n${recommendationsList}`;
}
export const awsCostOptimizationHubListRecommendations = {
name: 'awsCostOptimizationHubListRecommendations',
description: 'Retrieve cost optimization recommendations from AWS Cost Optimization Hub. Fetches all available recommendations, sorts them by estimated monthly savings in decreasing order, and returns the top N recommendations with the highest potential savings.',
inputSchema: {
type: 'object',
properties: {
maxResults: { type: 'number', description: 'Maximum number of recommendations to return (default: 50)' },
},
},
outputSchema: {
type: 'object',
properties: {
summary: { type: 'string', description: 'Text summary of the cost optimization recommendations' },
datapoints: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'string' },
type: { type: 'string' },
title: { type: 'string' },
description: { type: 'string' },
estimatedMonthlySavings: { type: 'string' },
estimatedAnnualSavings: { type: 'string' },
resourceId: { type: 'string' },
resourceType: { type: 'string' },
region: { type: 'string' },
service: { type: 'string' },
action: { type: 'string' },
reason: { type: 'string' },
},
},
},
},
},
configSchema: {
type: 'object',
properties: {
credentials: {
type: 'object',
properties: {
accessKeyId: { type: 'string' },
secretAccessKey: { type: 'string' },
sessionToken: { type: 'string' },
},
required: ['accessKeyId', 'secretAccessKey'],
},
region: { type: 'string', description: 'AWS region' },
logger: { type: 'object' },
},
required: ['credentials', 'region'],
},
defaultConfig: {},
async invoke(input, config) {
const { logger } = config;
// Validate input and config against schemas
validateParameters(input, this.inputSchema, config, this.configSchema, logger);
const { maxResults } = input;
const { region } = config;
logger?.debug('awsCostOptimizationHubListRecommendations input:', input);
const client = new CostOptimizationHubClient({ region, credentials: config.credentials });
const command = new ListRecommendationsCommand({
maxResults: maxResults || 50,
});
try {
const data = await client.send(command);
logger?.debug('awsCostOptimizationHubListRecommendations raw data:', data);
const recommendations = data.items?.map(item => ({
id: item.recommendationId,
type: item.actionType,
title: item.recommendedResourceSummary || item.actionType,
description: item.recommendedResourceSummary,
estimatedMonthlySavings: item.estimatedMonthlySavings?.toString(),
estimatedAnnualSavings: ((item.estimatedMonthlySavings || 0) * 12)?.toString(),
resourceId: item.resourceId,
resourceType: item.currentResourceType,
region: item.region,
service: item.source,
action: item.actionType,
reason: `Estimated ${item.estimatedSavingsPercentage}% savings`,
})) || [];
const totalEstimatedMonthlySavings = recommendations?.reduce((acc, r) => acc + parseFloat(r.estimatedMonthlySavings || '0'), 0) || 0;
const savings = recommendations?.map((r) => parseFloat(r.estimatedMonthlySavings || '0')) || [];
const highestSavings = Math.max(...savings);
const lowestSavings = Math.min(...savings);
const totalSavings = {
amount: totalEstimatedMonthlySavings.toFixed(2),
unit: 'USD',
};
const summary = generateRecommendationsSummary(recommendations, data.items?.length || 0, totalSavings);
const output = {
summary,
datapoints: recommendations,
};
logger?.debug('awsCostOptimizationHubListRecommendations summary:\n', output.summary);
logger?.debug('awsCostOptimizationHubListRecommendations datapoints:\n', output.datapoints);
return output;
}
catch (error) {
logger?.error('Error listing cost optimization hub recommendations:', error);
throw error;
}
},
};