my-webapp-hf / public /ARCHITECTURE.md
Deminiko
feat(ai-agent): complete modular AI agent system for HF Spaces
5071059

AI Agent Architecture & Microservices Design

Overview

The AI Agent is built as a modular microservices system with clear separation of concerns. Each component is independently testable and can be extended without affecting others.

Core Components

1. Services Layer (src/services/)

Services are stateless, reusable modules that handle specific functionality.

Gemini Service (gemini.js)

  • Purpose: Handle all Google Generative AI interactions
  • Methods:
    • generate(prompt, options) - Single-turn generation
    • chat(message) - Multi-turn conversation
    • analyzeCode(code, language) - Code analysis with structured output
    • generateCommitMessage(changes) - Create semantic commit messages
    • clearHistory() - Reset conversation state

Example:

import { geminiService } from './services/gemini.js';

const analysis = await geminiService.analyzeCode(code, 'javascript');
const response = await geminiService.chat("What does this function do?");

GitHub Service (github.js)

  • Purpose: GitHub API integration
  • Methods:
    • createIssue(issue) - Create GitHub issue
    • createPullRequest(pr) - Create PR
    • getFileContents(path) - Read file from repo
    • listFiles(path) - List directory contents
    • triggerWorkflow(workflowId, inputs) - Trigger GitHub Actions
    • getRepoInfo() - Repository metadata
    • listIssues(state) - Get open/closed issues
    • addIssueComment(issueNumber, body) - Comment on issue

Example:

import { githubService } from './services/github.js';

const issue = await githubService.createIssue({
  title: "Bug: Login fails",
  body: "Steps to reproduce...",
  labels: ['bug', 'critical']
});

Project Service (project.js)

  • Purpose: Project analysis and exploration
  • Methods:
    • getProjectStructure() - Files and directories
    • getFileContent(path) - Read specific file
    • scanForIssues() - Automated issue detection
    • getReadme() - README.md content
    • getDockerfile() - Dockerfile content
    • getSourceFiles() - List programming files

Example:

import { projectService } from './services/project.js';

const issues = await projectService.scanForIssues();
const readme = await projectService.getReadme();

2. Agents Layer (src/agents/)

Agents orchestrate multiple services to accomplish complex tasks.

Scanner Agent (scanner.js)

  • Purpose: Periodic project analysis and remediation
  • Workflow:
    1. Get project structure
    2. Scan for issues
    3. Analyze critical files with AI
    4. Generate recommendations
    5. Create GitHub issues if enabled

Key Methods:

scannerAgent.startPeriodicScanning()  // Begin hourly scans
scannerAgent.performScan()            // One-time full scan
scannerAgent.getLastScan()            // Get last report

Example Flow:

[Scan Triggered]
  ↓
[Get Project Structure] β†’ GitHub Service
  ↓
[Detect Issues] β†’ Project Service
  ↓
[AI Analysis] β†’ Gemini Service
  ↓
[Generate Recommendations] β†’ Gemini Service
  ↓
[Create Issue] β†’ GitHub Service (if enabled)

Chat Agent (chat.js)

  • Purpose: Multi-turn conversation management
  • Workflow:
    1. Start conversation session
    2. Maintain context about project
    3. Process commands or queries
    4. Generate AI responses
    5. Track conversation history

Key Methods:

chatAgent.startConversation(sessionId)    // Initialize session
chatAgent.processMessage(sessionId, msg)  // Handle user input
chatAgent.getHistory(sessionId)           // Get conversation
chatAgent.clearConversation(sessionId)    // End session

Commands:

/scan      β†’ Trigger project scan
/status    β†’ Get repository status
/issues    β†’ List open issues
/help      β†’ Show available commands

3. API Routes (src/api/)

Express routes that expose services and agents via HTTP.

Chat Routes (chat.js)

POST   /api/chat/start                      # Initialize session
POST   /api/chat/message                    # Send message
GET    /api/chat/history/:sessionId         # Get conversation
DELETE /api/chat/clear/:sessionId           # Clear conversation
GET    /api/chat/stats                      # Chat statistics

Scanner Routes (scanner.js)

POST /api/scanner/scan                      # Manual scan
GET  /api/scanner/last-report               # Last report
GET  /api/scanner/issues                    # Current issues
POST /api/scanner/start-continuous          # Start auto-scanning
POST /api/scanner/stop-continuous           # Stop auto-scanning

Project Routes (project.js)

GET /api/project/structure                  # Project layout
GET /api/project/file?path=...             # File content
GET /api/project/readme                     # README.md
GET /api/project/dockerfile                 # Dockerfile
GET /api/project/source-files               # Source files list

4. Configuration & Utilities

Environment Config (config/env.js)

  • Centralized configuration management
  • Validates required variables at startup
  • Type-safe environment access
import { config, validateConfig } from './config/env.js';

console.log(config.GEMINI_API_KEY);
validateConfig();  // Throws if missing required vars

Logger (config/logger.js)

  • Structured logging with levels
  • Timestamp and context support
  • Configurable verbosity
import { logger } from './config/logger.js';

logger.info('Something happened', { details: {...} });
logger.error('Failed', { error: err.message });
logger.debug('Debug info', { data });

Task Runner (utils/taskRunner.js)

  • Task queue execution with retry logic
  • Priority-based ordering
  • Timeout management
  • Execution history
import { taskRunner } from './utils/taskRunner.js';

taskRunner.addTask({
  id: 'analyze-code',
  name: 'Analyze codebase',
  priority: 10,
  execute: async () => { /* task code */ },
  retries: 3,
  timeout: 30000
});

const results = await taskRunner.runAll();

Data Flow Diagrams

Chat Flow

User Input
    ↓
[Chat API] POST /api/chat/message
    ↓
[Chat Agent] processMessage()
    ↓
Load Project Context? β†’ [Project Service] getProjectStructure()
    ↓
Is Command? (/scan, /status, etc)
    β”œβ”€ Yes β†’ Execute specific handler
    β”‚         └─ May call GitHub Service
    β”‚
    └─ No β†’ [Gemini Service] chat()
            └─ Multi-turn conversation
    ↓
[Chat Agent] Store in history
    ↓
Return Response to Client
    ↓
Update Chat UI

Scanner Flow

[Timer] Every SCAN_INTERVAL
    ↓
[Scanner Agent] performScan()
    ↓
[Project Service] getProjectStructure()
    ↓
[Project Service] scanForIssues()
    ↓
[Gemini Service] analyzeCode() (per file)
    ↓
[Gemini Service] generateRecommendations()
    ↓
[Create Report]
    ↓
Issues Found + AUTO_FIX enabled?
    β”œβ”€ Yes β†’ [GitHub Service] createIssue()
    └─ No  β†’ [Store Report]
    ↓
Return Report to Client

Request Flow

Browser Client
    ↓
JavaScript fetch() β†’ API Request
    ↓
[Express Router]
    β”œβ”€ Parse request
    β”œβ”€ Call service/agent
    β”œβ”€ Handle errors
    └─ Return JSON response
    ↓
Client Updates UI

Extension Points

Adding a New Scanner

  1. Create analyzer in src/agents/scanner.js:
async analyzeProject() {
  const sourceFiles = await projectService.getSourceFiles();
  const analysis = {
    files: [],
    overallHealth: 'unknown',
  };

  for (const file of sourceFiles.slice(0, 5)) {
    try {
      const content = await projectService.getFileContent(file.path);
      // YOUR CUSTOM ANALYSIS HERE
      const customAnalysis = await your_analysis(content);
      analysis.files.push({
        name: file.name,
        analysis: customAnalysis,
      });
    } catch (e) {
      logger.warn(`Failed to analyze ${file.name}`);
    }
  }

  return analysis;
}
  1. Results appear in scan reports and recommendations.

Adding a New Command

  1. Extend src/agents/chat.js:
async handleMessage(message, context) {
  if (message.startsWith('/mycommand')) {
    return this.handleMyCommand(context);
  }
  // ... existing code
}

async handleMyCommand(context) {
  // Your command logic
  return "Command result";
}
  1. Add to /help text:
getHelpText() {
  return `
    /mycommand - Description of what it does
    ...existing commands...
  `;
}

Adding a New API Endpoint

  1. Create route in src/api/newfeature.js:
import express from 'express';
import { someService } from '../services/some.js';

const router = express.Router();

router.get('/endpoint', async (req, res) => {
  try {
    const result = await someService.doSomething();
    res.json({ success: true, result });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

export default router;
  1. Mount in src/server.js:
import newFeatureRoutes from './api/newfeature.js';

app.use('/api/newfeature', newFeatureRoutes);

Performance Considerations

Caching

  • Project structure: 5-minute cache
  • File contents: On-demand (no cache)
  • API responses: Browser cache (Cache-Control headers)

Optimization

  • Analyze only first 5 source files
  • Limit file size for AI analysis
  • Use pagination for large lists
  • Compress API responses

Scaling

  • Separate scanner into background job
  • Use message queue for long-running tasks
  • Cache expensive computations
  • Add rate limiting for API endpoints

Testing

Each component can be tested independently:

// Test Gemini Service
const response = await geminiService.analyzeCode(code, 'javascript');
assert(response.issues !== undefined);

// Test GitHub Service
const issue = await githubService.createIssue({
  title: 'Test',
  body: 'Test body'
});
assert(issue.number !== undefined);

// Test Project Service
const structure = await projectService.getProjectStructure();
assert(structure.files.length > 0);

// Test Chat Agent
const session = chatAgent.startConversation('test-session');
assert(session.sessionId === 'test-session');

Deployment Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Hugging Face Space (Docker)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚    Express Server (Port 7860)     β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Static Files (HTML/CSS/JS)       β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  API Routes                       β”‚  β”‚
β”‚  β”‚  β”œβ”€ /api/chat                     β”‚  β”‚
β”‚  β”‚  β”œβ”€ /api/scanner                  β”‚  β”‚
β”‚  β”‚  └─ /api/project                  β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Agents                           β”‚  β”‚
β”‚  β”‚  β”œβ”€ Chat Agent (sessions)         β”‚  β”‚
β”‚  β”‚  └─ Scanner Agent (periodic)      β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Services                         β”‚  β”‚
β”‚  β”‚  β”œβ”€ Gemini Service                β”‚  β”‚
β”‚  β”‚  β”œβ”€ GitHub Service                β”‚  β”‚
β”‚  β”‚  └─ Project Service               β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”œβ”€β†’ [Google Gemini API]
         β”œβ”€β†’ [GitHub API]
         └─→ [Hugging Face API]

Security Best Practices

  1. Environment Variables: Never log or expose API keys
  2. Input Validation: Sanitize all user inputs
  3. Error Handling: Don't expose stack traces in production
  4. Rate Limiting: Add per-IP or per-session limits
  5. Token Rotation: Regularly refresh API tokens
  6. Logging: Log security-relevant events

Architecture Version: 1.0.0 Last Updated: November 17, 2024