@vfarcic/dot-ai
Version:
AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance
189 lines (188 loc) • 8.19 kB
JavaScript
;
/**
* Resource Capability Discovery & Inference Engine
*
* PRD #48: Resource Capabilities Discovery & Integration
*
* This module provides capability inference for Kubernetes resources through
* AI-powered analysis of schemas and metadata.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CapabilityInferenceEngine = void 0;
const shared_prompt_loader_1 = require("./shared-prompt-loader");
const crypto_1 = __importDefault(require("crypto"));
/**
* Generic Capability Inference Engine
*
* Analyzes any Kubernetes CRD using AI to extract semantic capabilities
* for improved AI recommendations and resource matching.
*/
class CapabilityInferenceEngine {
logger;
aiProvider;
constructor(aiProvider, logger) {
this.aiProvider = aiProvider;
this.logger = logger;
}
/**
* Main entry point: analyze resource to infer complete capabilities
*
* @param resourceName - Full resource name (e.g., "resourcegroups.azure.upbound.io")
* @param resourceDefinition - kubectl explain output for the resource
* @param interaction_id - Optional interaction ID for tracing
* @param apiVersion - Full apiVersion from kubectl (e.g., "apps/v1", "azure.upbound.io/v1beta1")
* @param version - Just the version part (e.g., "v1beta1")
* @param group - API group (e.g., "azure.upbound.io")
* @throws Error if capability inference fails for any reason
*/
async inferCapabilities(resourceName, resourceDefinition, interaction_id, apiVersion, version, group) {
const requestId = `capability-inference-${Date.now()}`;
this.logger.info('Starting capability inference', {
requestId,
resource: resourceName,
hasDefinition: !!resourceDefinition,
apiVersion,
version,
group,
});
// Use AI to analyze all available information
const aiResult = await this.inferWithAI(resourceName, resourceDefinition, requestId, interaction_id);
// Convert AI result to final capability structure
const finalCapability = this.buildResourceCapability(resourceName, aiResult, apiVersion, version, group);
this.logger.info('Capability inference completed', {
requestId,
resource: resourceName,
capabilitiesFound: finalCapability.capabilities.length,
providersFound: finalCapability.providers.length,
complexity: finalCapability.complexity,
confidence: finalCapability.confidence,
apiVersion,
version,
});
return finalCapability;
}
/**
* Use AI to infer capabilities from all available resource context
*
* @throws Error if AI inference fails
*/
async inferWithAI(resourceName, resourceDefinition, requestId, interaction_id) {
try {
const prompt = await this.buildInferencePrompt(resourceName, resourceDefinition);
const response = await this.aiProvider.sendMessage(prompt, 'capability-inference', {
user_intent: `Analyze capabilities of Kubernetes resource: ${resourceName}`,
interaction_id: interaction_id || 'inference',
});
return this.parseCapabilitiesFromAI(response.content);
}
catch (error) {
this.logger.error('AI capability inference failed', error, {
requestId,
resource: resourceName,
});
throw error; // Re-throw to maintain fail-fast behavior
}
}
/**
* Build AI inference prompt using standard prompt loading pattern
*
* @throws Error if prompt template cannot be loaded
*/
async buildInferencePrompt(resourceName, resourceDefinition) {
// Load prompt template using shared prompt loader
const finalPrompt = (0, shared_prompt_loader_1.loadPrompt)('capability-inference', {
resourceName,
resourceDefinition: resourceDefinition || 'No resource definition provided',
});
return finalPrompt;
}
/**
* Parse AI response into structured capability data
*
* @throws Error if AI response cannot be parsed or is invalid
*/
parseCapabilitiesFromAI(response) {
// Look for JSON in the response using standard pattern
const jsonMatch = response.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
throw new Error(`No JSON found in AI response. Response: ${response.substring(0, 200)}...`);
}
let parsed;
try {
parsed = JSON.parse(jsonMatch[0]);
}
catch (parseError) {
throw new Error(`Invalid JSON in AI response: ${parseError instanceof Error ? parseError.message : String(parseError)}. JSON: ${jsonMatch[0].substring(0, 200)}...`, { cause: parseError });
}
// Validate required fields with detailed error messages
if (!Array.isArray(parsed.capabilities)) {
throw new Error(`AI response missing or invalid capabilities array. Got: ${typeof parsed.capabilities}`);
}
if (!Array.isArray(parsed.providers)) {
throw new Error(`AI response missing or invalid providers array. Got: ${typeof parsed.providers}`);
}
if (!Array.isArray(parsed.abstractions)) {
throw new Error(`AI response missing or invalid abstractions array. Got: ${typeof parsed.abstractions}`);
}
if (!['low', 'medium', 'high'].includes(parsed.complexity)) {
throw new Error(`AI response invalid complexity: ${parsed.complexity}. Must be low, medium, or high`);
}
if (typeof parsed.description !== 'string' ||
parsed.description.trim() === '') {
throw new Error(`AI response missing or invalid description. Got: ${typeof parsed.description}`);
}
if (typeof parsed.useCase !== 'string' || parsed.useCase.trim() === '') {
throw new Error(`AI response missing or invalid useCase. Got: ${typeof parsed.useCase}`);
}
if (typeof parsed.confidence !== 'number' ||
parsed.confidence < 0 ||
parsed.confidence > 1) {
throw new Error(`AI response invalid confidence score: ${parsed.confidence}. Must be number between 0-1`);
}
return {
capabilities: parsed.capabilities,
providers: parsed.providers,
abstractions: parsed.abstractions,
complexity: parsed.complexity,
description: parsed.description.trim(),
useCase: parsed.useCase.trim(),
confidence: parsed.confidence,
};
}
/**
* Build final ResourceCapability from AI analysis result
*/
buildResourceCapability(resourceName, aiResult, apiVersion, version, group) {
return {
resourceName,
apiVersion,
version,
group,
capabilities: aiResult.capabilities,
providers: aiResult.providers,
abstractions: aiResult.abstractions,
complexity: aiResult.complexity,
description: aiResult.description,
useCase: aiResult.useCase,
confidence: aiResult.confidence,
analyzedAt: new Date().toISOString(),
};
}
/**
* Generate Vector DB ID for capability storage
* Creates deterministic UUID from resource name for Qdrant compatibility
*/
static generateCapabilityId(resourceName) {
// Create deterministic UUID from resource name hash
const hash = crypto_1.default
.createHash('sha256')
.update(`capability-${resourceName}`)
.digest('hex');
// Convert to UUID format: 8-4-4-4-12
return `${hash.substring(0, 8)}-${hash.substring(8, 12)}-${hash.substring(12, 16)}-${hash.substring(16, 20)}-${hash.substring(20, 32)}`;
}
}
exports.CapabilityInferenceEngine = CapabilityInferenceEngine;