contaigents
Version:
Modular AI Content Ecosystem with Audio Generation
620 lines (611 loc) • 23.8 kB
JavaScript
import { ConversationManager } from "../services/conversationManager.js";
import { AgentService } from "../services/agentService.js";
import { FileService } from "../services/fileService.js";
import { IntelligentFileService } from "../services/IntelligentFileService.js";
import { ProjectContextService } from "../services/ProjectContextService.js";
import { LLMFactory } from "../services/llm/LLMFactory.js";
import { AnalyzeFileTool } from "../tools/file/AnalyzeFileTool.js";
import { SummarizeFileTool } from "../tools/file/SummarizeFileTool.js";
import { ClassifyFileTool } from "../tools/file/ClassifyFileTool.js";
import { PartialFileOperationTool } from "../tools/file/PartialFileOperationTool.js";
import { DependencyTrackingTool } from "../tools/project/DependencyTrackingTool.js";
import { SemanticRelationshipTool } from "../tools/project/SemanticRelationshipTool.js";
export class AgentCLI {
constructor() {
this.conversationManager = new ConversationManager();
this.agentService = new AgentService();
this.fileService = new FileService();
this.intelligentFileService = new IntelligentFileService();
this.projectContextService = new ProjectContextService();
this.defaultAgent = this.createDefaultAgent();
this.initializeToolContext();
}
async initializeToolContext() {
const llm = await LLMFactory.getConfiguredProvider();
this.toolContext = {
workingDirectory: process.cwd(),
llm: llm || undefined
};
}
/**
* Start an interactive chat session
*/
async startChat(agentName) {
let agentConfig;
if (agentName) {
try {
agentConfig = await this.loadAgentConfig(agentName);
}
catch (error) {
console.warn(`Failed to load agent ${agentName}, using default agent`);
agentConfig = this.defaultAgent;
}
}
else {
agentConfig = this.defaultAgent;
}
const conversationId = await this.conversationManager.startConversation(agentConfig);
console.log(`Started conversation with ${agentConfig.name} (ID: ${conversationId})`);
return conversationId;
}
/**
* Send a message in a conversation
*/
async sendMessage(conversationId, message) {
try {
const response = await this.conversationManager.continueConversation(conversationId, message);
const conversation = this.conversationManager.getConversation(conversationId);
if (!conversation) {
throw new Error('Conversation not found');
}
return {
response,
conversationId,
context: conversation.context,
suggestions: this.generateSuggestions(message, response),
actions: this.extractActions(response)
};
}
catch (error) {
throw new Error(`Failed to send message: ${error.message}`);
}
}
/**
* Process a conversation request (unified API)
*/
async processConversationRequest(request) {
let conversationId = request.conversationId;
// Start new conversation if none provided
if (!conversationId) {
const agentConfig = request.agentConfig ? { ...this.defaultAgent, ...request.agentConfig } : this.defaultAgent;
conversationId = await this.conversationManager.startConversation(agentConfig);
}
// Update context if provided
if (request.context) {
await this.updateConversationContext(conversationId, request.context);
}
return await this.sendMessage(conversationId, request.message);
}
/**
* List all active conversations
*/
listConversations() {
const conversations = this.conversationManager.listConversations();
return conversations.map(conv => ({
id: conv.id,
agent: conv.agent.name,
lastMessage: conv.messages.length > 0
? conv.messages[conv.messages.length - 1].content.substring(0, 100) + '...'
: 'No messages yet',
updatedAt: conv.updatedAt
}));
}
/**
* Get conversation details
*/
getConversationDetails(conversationId) {
const conversation = this.conversationManager.getConversation(conversationId);
if (!conversation) {
throw new Error('Conversation not found');
}
return {
id: conversation.id,
agent: conversation.agent,
messageCount: conversation.messages.length,
createdAt: conversation.createdAt,
updatedAt: conversation.updatedAt,
context: conversation.context,
recentMessages: conversation.messages.slice(-5) // Last 5 messages
};
}
/**
* Delete a conversation
*/
async deleteConversation(conversationId) {
return await this.conversationManager.deleteConversation(conversationId);
}
/**
* Analyze files using intelligent file operations
*/
async analyzeFiles(files, analysisType = 'general') {
const results = [];
for (const file of files) {
try {
const analyzeTool = new AnalyzeFileTool(this.toolContext);
const analysisDepth = analysisType === 'comprehensive' ? 'comprehensive' : 'detailed';
const result = await analyzeTool.execute({
filePath: file,
analysisDepth,
includeContent: false
});
if (result.success) {
results.push({
file,
analysis: result.data,
success: true
});
}
else {
results.push({
file,
error: result.error,
success: false
});
}
}
catch (error) {
results.push({
file,
error: error.message,
success: false
});
}
}
return results;
}
/**
* Classify files using intelligent classification
*/
async classifyFiles(files, includeRelationships = false) {
const results = [];
for (const file of files) {
try {
const classifyTool = new ClassifyFileTool(this.toolContext);
const result = await classifyTool.execute({
filePath: file,
includeRelationships,
includeConfidence: true
});
if (result.success) {
results.push({
file,
classification: result.data,
success: true
});
}
else {
results.push({
file,
error: result.error,
success: false
});
}
}
catch (error) {
results.push({
file,
error: error.message,
success: false
});
}
}
return results;
}
/**
* Summarize files using intelligent summarization
*/
async summarizeFiles(files, summaryType = 'detailed', maxLength = 300) {
const results = [];
for (const file of files) {
try {
const summarizeTool = new SummarizeFileTool(this.toolContext);
const result = await summarizeTool.execute({
filePath: file,
summaryType,
maxLength
});
if (result.success) {
results.push({
file,
summary: result.data,
success: true
});
}
else {
results.push({
file,
error: result.error,
success: false
});
}
}
catch (error) {
results.push({
file,
error: error.message,
success: false
});
}
}
return results;
}
/**
* Perform partial file operations
*/
async performPartialFileOperation(filePath, operation, content, mode = 'read') {
try {
const partialTool = new PartialFileOperationTool(this.toolContext);
if (mode === 'read') {
const result = await partialTool.execute({
filePath,
operation,
contextLines: 2
});
return result;
}
else {
if (!content) {
throw new Error('Content is required for write operations');
}
const result = await partialTool.execute({
filePath,
content,
operation,
mode: 'replace',
backup: true
});
return result;
}
}
catch (error) {
return {
success: false,
error: error.message
};
}
}
/**
* Get intelligent project overview with enhanced context
*/
async getProjectOverview() {
try {
// Get comprehensive project context
const projectContext = await this.projectContextService.buildProjectContext();
// Get file tree (legacy support)
const fileTree = await this.fileService.getFileTree();
// Analyze key files
const keyFiles = this.extractKeyFiles(fileTree);
const analyses = await this.analyzeFiles(keyFiles, 'detailed');
const classifications = await this.classifyFiles(keyFiles, true);
// Generate project summary with enhanced context
const projectSummary = await this.generateProjectSummary(analyses, classifications, projectContext);
return {
fileTree,
keyFiles,
analyses,
classifications,
projectSummary,
projectContext,
timestamp: Date.now()
};
}
catch (error) {
return {
error: error.message,
success: false
};
}
}
/**
* Build comprehensive project context
*/
async buildProjectContext(forceRefresh = false) {
return await this.projectContextService.buildProjectContext(forceRefresh);
}
/**
* Get project context summary
*/
async getProjectContextSummary() {
return await this.projectContextService.getContextSummary();
}
/**
* Get files related to a specific file
*/
async getRelatedFiles(filePath, maxResults = 10) {
return await this.projectContextService.getRelatedFiles(filePath, maxResults);
}
/**
* Analyze project dependencies
*/
async analyzeProjectDependencies(options = {}) {
try {
const dependencyTool = new DependencyTrackingTool(this.toolContext);
const result = await dependencyTool.execute(options);
if (result.success) {
return {
success: true,
data: result.data,
metadata: result.metadata
};
}
else {
return {
success: false,
error: result.error
};
}
}
catch (error) {
return {
success: false,
error: error.message
};
}
}
/**
* Analyze semantic relationships between files
*/
async analyzeSemanticRelationships(options = {}) {
try {
const semanticTool = new SemanticRelationshipTool(this.toolContext);
const result = await semanticTool.execute(options);
if (result.success) {
return {
success: true,
data: result.data,
metadata: result.metadata
};
}
else {
return {
success: false,
error: result.error
};
}
}
catch (error) {
return {
success: false,
error: error.message
};
}
}
/**
* Clear project context cache
*/
async clearProjectContextCache() {
await this.projectContextService.clearCache();
}
/**
* Enhanced analyze files with conversational context
*/
async analyzeFilesWithConversation(files, analysisType = 'general') {
// Get intelligent analysis first
const intelligentAnalysis = await this.analyzeFiles(files, analysisType);
// Create conversational summary
const agentConfig = this.createAnalysisAgent(analysisType);
const conversationId = await this.conversationManager.startConversation(agentConfig);
const analysisPrompt = `I've performed intelligent analysis on the following files. Please provide a conversational summary and insights:
${JSON.stringify(intelligentAnalysis, null, 2)}
Please provide:
1. A clear summary of what these files do
2. Key insights and patterns
3. Recommendations for improvement
4. Any potential issues or concerns`;
const response = await this.conversationManager.continueConversation(conversationId, analysisPrompt);
// Clean up the temporary conversation
await this.conversationManager.deleteConversation(conversationId);
return response;
}
/**
* Generate content using the agent system
*/
async generateContent(contentType, requirements, context) {
const agentConfig = this.createContentGenerationAgent(contentType);
const conversationId = await this.conversationManager.startConversation(agentConfig);
// Update context if provided
if (context) {
await this.updateConversationContext(conversationId, context);
}
const generationPrompt = `Please generate ${contentType} content with the following requirements:\n${requirements}`;
const response = await this.conversationManager.continueConversation(conversationId, generationPrompt);
return response;
}
/**
* Load agent configuration from file
*/
async loadAgentConfig(agentName) {
try {
const configPath = `${agentName}-config.json`;
const configStr = await this.fileService.readFile(configPath);
return JSON.parse(configStr);
}
catch (error) {
throw new Error(`Failed to load agent configuration for ${agentName}`);
}
}
/**
* Create default agent configuration
*/
createDefaultAgent() {
return {
name: "ContenSpace Assistant",
llm: "default",
systemPrompt: "You are ContenSpace Assistant, an AI agent specialized in content creation, file analysis, and project management. You help users with writing, editing, analyzing files, and managing their content projects. You are knowledgeable, helpful, and provide clear, actionable responses.",
expertise: ["content creation", "file analysis", "project management", "writing assistance"],
writingStyle: "professional",
tone: "neutral",
language: "en"
};
}
/**
* Create specialized analysis agent
*/
createAnalysisAgent(analysisType) {
const specializations = {
code: "You are a code analysis expert. Analyze code for quality, structure, potential issues, and improvements.",
content: "You are a content analysis expert. Analyze text for clarity, structure, tone, and effectiveness.",
project: "You are a project analysis expert. Analyze project structure, organization, and provide strategic insights."
};
return {
name: `${analysisType.charAt(0).toUpperCase() + analysisType.slice(1)} Analyzer`,
llm: "default",
systemPrompt: specializations[analysisType] || specializations.content,
expertise: [analysisType, "analysis", "review"],
writingStyle: "technical",
tone: "authoritative",
language: "en"
};
}
/**
* Create specialized content generation agent
*/
createContentGenerationAgent(contentType) {
return {
name: `${contentType.charAt(0).toUpperCase() + contentType.slice(1)} Writer`,
llm: "default",
systemPrompt: `You are a specialized ${contentType} writer. Create high-quality, engaging ${contentType} content that meets the specified requirements and maintains consistency with the project context.`,
expertise: [contentType, "writing", "content creation"],
writingStyle: "professional",
tone: "enthusiastic",
language: "en"
};
}
/**
* Update conversation context
*/
async updateConversationContext(conversationId, contextUpdate) {
const conversation = this.conversationManager.getConversation(conversationId);
if (conversation) {
conversation.context = { ...conversation.context, ...contextUpdate };
conversation.updatedAt = Date.now();
}
}
/**
* Generate follow-up suggestions based on the conversation
*/
generateSuggestions(userMessage, agentResponse) {
const suggestions = [];
// Simple heuristics for generating suggestions
if (userMessage.toLowerCase().includes('analyze')) {
suggestions.push('Would you like me to analyze additional files?');
suggestions.push('Should I provide more detailed analysis?');
}
if (userMessage.toLowerCase().includes('write') || userMessage.toLowerCase().includes('create')) {
suggestions.push('Would you like me to refine this content?');
suggestions.push('Should I create additional sections?');
}
if (agentResponse.toLowerCase().includes('file') || agentResponse.toLowerCase().includes('project')) {
suggestions.push('Would you like me to examine the project structure?');
suggestions.push('Should I analyze related files?');
}
return suggestions.slice(0, 3); // Limit to 3 suggestions
}
/**
* Extract actionable items from agent response
*/
extractActions(response) {
const actions = [];
// Simple pattern matching for common actions
if (response.includes('create') || response.includes('write')) {
actions.push({
type: 'suggestion',
payload: { action: 'create_content' },
description: 'Create or write content'
});
}
if (response.includes('analyze') || response.includes('review')) {
actions.push({
type: 'suggestion',
payload: { action: 'analyze_files' },
description: 'Analyze files or content'
});
}
return actions;
}
/**
* Extract key files from file tree for analysis
*/
extractKeyFiles(fileTree) {
const keyFiles = [];
const traverse = (nodes) => {
for (const node of nodes) {
if (node.type === 'file') {
const fileName = node.name.toLowerCase();
// Prioritize important files
if (fileName.includes('readme') ||
fileName.includes('package.json') ||
fileName.includes('index') ||
fileName.includes('main') ||
fileName.includes('config') ||
fileName.endsWith('.md')) {
keyFiles.push(node.path);
}
}
else if (node.children) {
traverse(node.children);
}
}
};
traverse(fileTree);
return keyFiles.slice(0, 10); // Limit to 10 key files
}
/**
* Generate project summary from analyses, classifications, and enhanced context
*/
async generateProjectSummary(analyses, classifications, projectContext) {
const agentConfig = this.createAnalysisAgent('project');
const conversationId = await this.conversationManager.startConversation(agentConfig);
let summaryPrompt = `Based on the following file analyses and classifications, provide a comprehensive project summary:
ANALYSES:
${JSON.stringify(analyses, null, 2)}
CLASSIFICATIONS:
${JSON.stringify(classifications, null, 2)}`;
// Add enhanced project context if available
if (projectContext) {
summaryPrompt += `
ENHANCED PROJECT CONTEXT:
- Total Files: ${projectContext.relevantFiles.length}
- Project Structure: ${projectContext.projectStructure ?
`${projectContext.projectStructure.totalDirectories} directories, ${projectContext.projectStructure.totalFiles} files` : 'Not analyzed'}
- Semantic Relationships: ${projectContext.semanticRelationships?.length || 0} relationships found
- Dependency Clusters: ${projectContext.dependencyGraph?.clusters.length || 0} clusters identified
- Last Analyzed: ${projectContext.lastAnalyzed ? new Date(projectContext.lastAnalyzed).toLocaleString() : 'Never'}`;
if (projectContext.semanticRelationships && projectContext.semanticRelationships.length > 0) {
const topRelationships = projectContext.semanticRelationships
.sort((a, b) => b.strength - a.strength)
.slice(0, 5);
summaryPrompt += `
TOP SEMANTIC RELATIONSHIPS:
${topRelationships.map(rel => `- ${rel.sourceFile} → ${rel.targetFile} (${rel.relationshipType}, strength: ${rel.strength.toFixed(2)}): ${rel.description}`).join('\n')}`;
}
if (projectContext.dependencyGraph?.clusters && projectContext.dependencyGraph.clusters.length > 0) {
summaryPrompt += `
DEPENDENCY CLUSTERS:
${projectContext.dependencyGraph.clusters.map(cluster => `- ${cluster.name}: ${cluster.files.length} files, cohesion: ${cluster.cohesion.toFixed(2)} - ${cluster.purpose}`).join('\n')}`;
}
}
summaryPrompt += `
Please provide:
1. Project purpose and type
2. Technology stack and frameworks
3. Project structure and organization
4. Key features and capabilities
5. Code quality assessment
6. File relationships and dependencies
7. Recommendations for improvement`;
const response = await this.conversationManager.continueConversation(conversationId, summaryPrompt);
await this.conversationManager.deleteConversation(conversationId);
return response;
}
}