Removes outdated prompt files

Removes the `Chat Prompt.txt`, `VSCode Agent/Prompt.txt`, `Warp.dev/Prompt.txt`, and `v0 Prompts and Tools/Prompt.txt` files.

These files likely contain outdated prompts or configurations that are no longer needed in the current project. Removing them helps to clean up the codebase and prevent potential confusion or conflicts.
This commit is contained in:
dopeuni444
2025-07-31 01:45:01 +04:00
parent 23a65fbb9e
commit d43632a49a
91 changed files with 27187 additions and 1648 deletions

View File

@@ -0,0 +1,38 @@
# Nowhere AI Agent Backend Configuration
# Server Configuration
NODE_ENV=development
PORT=3001
FRONTEND_URL=http://localhost:3000
# AI Model API Keys
OPENAI_API_KEY=your_openai_api_key_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here
# Database Configuration
REDIS_URL=redis://localhost:6379
POSTGRES_URL=postgresql://username:password@localhost:5432/nowhere_db
# Authentication (Optional for development)
JWT_SECRET=your_jwt_secret_here
JWT_EXPIRES_IN=7d
# Logging
LOG_LEVEL=info
# Rate Limiting
RATE_LIMIT_POINTS=100
RATE_LIMIT_DURATION=60
VOICE_RATE_LIMIT_POINTS=50
# Voice Processing (Optional)
AZURE_SPEECH_KEY=your_azure_speech_key_here
AZURE_SPEECH_REGION=your_azure_region_here
# Security
CORS_ORIGIN=http://localhost:3000
HELMET_ENABLED=true
# Development
DEBUG=true
ENABLE_SWAGGER=true

View File

@@ -0,0 +1,333 @@
# 🚀 Nowhere AI Agent Backend
Advanced AI coding assistant backend with voice integration, autopilot mode, and adaptive learning capabilities.
## 🎯 Features
- **Voice Command Processing** - Natural language voice commands
- **Autopilot Mode** - Autonomous task execution
- **Adaptive Learning** - Memory system with persistent context
- **Multi-Model Support** - OpenAI GPT-4.1+ and Anthropic Claude 3.5 Sonnet
- **Real-time Communication** - WebSocket support for live collaboration
- **Rate Limiting** - Protection against abuse
- **Comprehensive Logging** - Structured logging with Winston
## 🏗️ Architecture
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │◄──►│ Nowhere API │◄──►│ AI Models │
│ (React/Web) │ │ (Express) │ │ (OpenAI/Claude)│
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Voice APIs │ │ Memory System │ │ Tool Executor │
│ (Speech/Text) │ │ (Redis/DB) │ │ (File/Code) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
## 🚀 Quick Start
### Prerequisites
- Node.js 18+
- Redis (for memory and rate limiting)
- PostgreSQL (optional, for persistent storage)
- OpenAI API key
- Anthropic API key
### Installation
1. **Clone and install dependencies:**
```bash
cd Advanced_AI_Agent/implementation/backend
npm install
```
2. **Set up environment variables:**
```bash
cp env.example .env
# Edit .env with your API keys and configuration
```
3. **Start the development server:**
```bash
npm run dev
```
The server will start on `http://localhost:3001`
## 📋 API Endpoints
### Core Commands
#### Process Command
```http
POST /api/v1/command
Content-Type: application/json
{
"command": "Create a React component for user authentication",
"context": {
"userId": "user123",
"projectId": "project456",
"currentFile": "src/components/Auth.jsx",
"codebase": {...},
"userPreferences": {...}
}
}
```
#### Voice Command Processing
```http
POST /api/v1/voice
Content-Type: application/json
{
"voiceInput": "Nowhere, create a new user component",
"context": {
"userId": "user123",
"projectId": "project456"
}
}
```
### Autopilot Mode
#### Enable Autopilot
```http
POST /api/v1/autopilot/enable
Content-Type: application/json
{
"context": {
"userId": "user123",
"projectId": "project456"
}
}
```
#### Disable Autopilot
```http
POST /api/v1/autopilot/disable
Content-Type: application/json
{
"context": {
"userId": "user123",
"projectId": "project456"
}
}
```
### Memory Management
#### Get Memory
```http
GET /api/v1/memory/:userId/:projectId?sessionId=session123
```
#### Clear Memory
```http
DELETE /api/v1/memory/:userId/:projectId?sessionId=session123
```
### System Status
#### Health Check
```http
GET /health
```
#### Status
```http
GET /api/v1/status
```
#### Configuration
```http
GET /api/v1/config
```
## 🎙️ Voice Commands
### Navigation Commands
- "Go to file [filename]"
- "Show me the main function"
- "Navigate to [component/module]"
- "Open [file path]"
### Execution Commands
- "Run the tests"
- "Deploy to staging"
- "Build the project"
- "Start the development server"
### Analysis Commands
- "Analyze this code"
- "Find performance issues"
- "Check for security vulnerabilities"
- "Review the code quality"
### Creation Commands
- "Create a new [component/function/class]"
- "Add authentication"
- "Implement [feature]"
- "Generate [type]"
### Debugging Commands
- "Fix this error"
- "Debug the issue"
- "Optimize this function"
- "Resolve the conflict"
## 🔧 Configuration
### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `NODE_ENV` | Environment mode | `development` |
| `PORT` | Server port | `3001` |
| `FRONTEND_URL` | Frontend URL for CORS | `http://localhost:3000` |
| `OPENAI_API_KEY` | OpenAI API key | Required |
| `ANTHROPIC_API_KEY` | Anthropic API key | Required |
| `REDIS_URL` | Redis connection URL | `redis://localhost:6379` |
| `POSTGRES_URL` | PostgreSQL connection URL | Optional |
| `JWT_SECRET` | JWT signing secret | Required in production |
| `LOG_LEVEL` | Logging level | `info` |
### Rate Limiting
- **General API**: 100 requests per minute
- **Voice Commands**: 50 requests per minute
- **Block Duration**: 15 minutes (general), 30 minutes (voice)
## 🛠️ Development
### Project Structure
```
backend/
├── src/
│ ├── core/ # Nowhere AI core logic
│ ├── memory/ # Memory management system
│ ├── tools/ # Tool execution engine
│ ├── voice/ # Voice processing
│ ├── middleware/ # Express middleware
│ ├── routes/ # API routes
│ ├── utils/ # Utility functions
│ ├── websocket/ # WebSocket handlers
│ └── index.ts # Server entry point
├── logs/ # Application logs
├── tests/ # Test files
├── package.json # Dependencies
└── env.example # Environment template
```
### Available Scripts
```bash
npm run dev # Start development server
npm run build # Build for production
npm run start # Start production server
npm run test # Run tests
npm run lint # Lint code
npm run format # Format code
```
### Testing
```bash
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
```
## 🔒 Security
### Authentication
- JWT-based authentication (optional in development)
- Role-based access control
- Secure session management
### Rate Limiting
- IP-based rate limiting
- Separate limits for voice commands
- Configurable limits and durations
### Data Protection
- Input validation and sanitization
- SQL injection prevention
- XSS protection with Helmet
- CORS configuration
## 📊 Monitoring
### Logging
- Structured JSON logging
- Different log levels (error, warn, info, debug)
- File-based logging with rotation
- Request/response logging
### Health Checks
- `/health` endpoint for monitoring
- Database connectivity checks
- AI model availability checks
## 🚀 Deployment
### Docker Deployment
```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3001
CMD ["npm", "start"]
```
### Environment Setup
1. Set production environment variables
2. Configure Redis and PostgreSQL
3. Set up SSL certificates
4. Configure reverse proxy (nginx)
5. Set up monitoring and logging
## 🤝 Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Submit a pull request
## 📄 License
MIT License - see LICENSE file for details
## 🆘 Support
For support and questions:
- Create an issue in the repository
- Check the documentation
- Review the API examples
---
**Nowhere AI Agent** - The most advanced AI coding assistant with voice integration and autonomous capabilities.

View File

@@ -0,0 +1,38 @@
# Nowhere AI Agent Backend Configuration
# Server Configuration
NODE_ENV=development
PORT=3001
FRONTEND_URL=http://localhost:3000
# AI Model API Keys
OPENAI_API_KEY=your_openai_api_key_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here
# Database Configuration
REDIS_URL=redis://localhost:6379
POSTGRES_URL=postgresql://username:password@localhost:5432/nowhere_db
# Authentication (Optional for development)
JWT_SECRET=your_jwt_secret_here
JWT_EXPIRES_IN=7d
# Logging
LOG_LEVEL=info
# Rate Limiting
RATE_LIMIT_POINTS=100
RATE_LIMIT_DURATION=60
VOICE_RATE_LIMIT_POINTS=50
# Voice Processing (Optional)
AZURE_SPEECH_KEY=your_azure_speech_key_here
AZURE_SPEECH_REGION=your_azure_region_here
# Security
CORS_ORIGIN=http://localhost:3000
HELMET_ENABLED=true
# Development
DEBUG=true
ENABLE_SWAGGER=true

View File

@@ -0,0 +1,39 @@
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
console.log('🚀 Setting up Nowhere AI Agent Backend...');
// Check if package.json exists
if (!fs.existsSync('package.json')) {
console.error('❌ package.json not found');
process.exit(1);
}
// Create logs directory
if (!fs.existsSync('logs')) {
fs.mkdirSync('logs');
console.log('✅ Created logs directory');
}
// Create .env file from example if it doesn't exist
if (!fs.existsSync('.env') && fs.existsSync('env.example')) {
fs.copyFileSync('env.example', '.env');
console.log('✅ Created .env file from env.example');
}
console.log('📦 Installing dependencies...');
try {
// Try to install dependencies
execSync('npm install', { stdio: 'inherit' });
console.log('✅ Dependencies installed successfully');
} catch (error) {
console.error('❌ Failed to install dependencies:', error.message);
console.log('💡 Try running: npm install manually');
}
console.log('🎯 Nowhere AI Agent Backend setup complete!');
console.log('📝 Next steps:');
console.log(' 1. Edit .env file with your API keys');
console.log(' 2. Run: npm run dev');
console.log(' 3. Access the API at http://localhost:3001');

View File

@@ -0,0 +1,69 @@
{
"name": "nowhere-backend",
"version": "1.0.0",
"description": "Nowhere AI Agent Backend - Advanced AI coding assistant with voice integration",
"main": "dist/index.js",
"scripts": {
"dev": "nodemon src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"test": "jest",
"lint": "eslint src/**/*.ts",
"format": "prettier --write src/**/*.ts"
},
"keywords": [
"ai",
"coding-assistant",
"voice-integration",
"autopilot",
"nowhere"
],
"author": "Nowhere Team",
"license": "MIT",
"dependencies": {
"express": "^4.18.2",
"fastify": "^4.24.3",
"typescript": "^5.2.2",
"@types/node": "^20.8.10",
"redis": "^4.6.10",
"pg": "^8.11.3",
"@types/redis": "^4.0.11",
"@types/pg": "^8.10.7",
"openai": "^4.20.1",
"@anthropic-ai/sdk": "^0.9.1",
"socket.io": "^4.7.4",
"cors": "^2.8.5",
"helmet": "^7.1.0",
"dotenv": "^16.3.1",
"jsonwebtoken": "^9.0.2",
"@types/jsonwebtoken": "^9.0.4",
"bcryptjs": "^2.4.3",
"@types/bcryptjs": "^2.4.5",
"joi": "^17.11.0",
"winston": "^3.11.0",
"compression": "^1.7.4",
"@types/compression": "^1.7.4",
"rate-limiter-flexible": "^3.0.8",
"multer": "^1.4.5-lts.1",
"@types/multer": "^1.4.9"
},
"devDependencies": {
"ts-node": "^10.9.1",
"nodemon": "^3.0.1",
"@types/express": "^4.17.20",
"@types/cors": "^2.8.15",
"jest": "^29.7.0",
"@types/jest": "^29.5.7",
"ts-jest": "^29.1.1",
"eslint": "^8.52.0",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"prettier": "^3.0.3",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
}
}

View File

@@ -0,0 +1,285 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import OpenAI from 'openai';
import Anthropic from '@anthropic-ai/sdk';
import { Logger } from '../utils/logger';
import { MemoryManager } from '../memory/memory-manager';
import { ToolExecutor } from '../tools/tool-executor';
import { VoiceProcessor } from '../voice/voice-processor';
export interface NowhereContext {
userId: string;
projectId: string;
currentFile?: string;
codebase?: any;
userPreferences?: any;
sessionId: string;
}
export interface NowhereResponse {
response: string;
actions: any[];
memory: any;
confidence: number;
suggestions?: string[];
}
export interface VoiceCommand {
type: 'navigation' | 'execution' | 'analysis' | 'creation' | 'debugging';
command: string;
confidence: number;
parameters: any;
}
export class NowhereCore {
private systemPrompt: string;
private openai: OpenAI;
private anthropic: Anthropic;
private memoryManager: MemoryManager;
private toolExecutor: ToolExecutor;
private voiceProcessor: VoiceProcessor;
private logger: Logger;
constructor() {
this.logger = new Logger('NowhereCore');
this.systemPrompt = this.loadSystemPrompt();
this.openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
this.anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
this.memoryManager = new MemoryManager();
this.toolExecutor = new ToolExecutor();
this.voiceProcessor = new VoiceProcessor();
}
private loadSystemPrompt(): string {
try {
return readFileSync(
join(__dirname, '../../../prompts/system_prompt.md'),
'utf-8'
);
} catch (error) {
this.logger.error('Failed to load system prompt', error);
return '# Nowhere AI Agent\n\nYou are Nowhere, an advanced AI coding assistant.';
}
}
async processCommand(
command: string,
context: NowhereContext,
isVoiceCommand: boolean = false
): Promise<NowhereResponse> {
try {
this.logger.info(`Processing command: ${command}`, { context });
// Process voice command if applicable
let processedCommand = command;
let voiceCommand: VoiceCommand | null = null;
if (isVoiceCommand) {
voiceCommand = await this.voiceProcessor.processVoiceCommand(command);
processedCommand = voiceCommand.command;
}
// Retrieve relevant memory
const memory = await this.memoryManager.getRelevantMemory(context);
// Create AI prompt with context
const prompt = this.buildPrompt(processedCommand, context, memory);
// Get AI response
const aiResponse = await this.getAIResponse(prompt, context);
// Execute any required actions
const actions = await this.executeActions(aiResponse.actions, context);
// Update memory
await this.memoryManager.updateMemory(context, {
command: processedCommand,
response: aiResponse.response,
actions: actions,
timestamp: new Date().toISOString(),
});
return {
response: aiResponse.response,
actions: actions,
memory: memory,
confidence: aiResponse.confidence,
suggestions: aiResponse.suggestions,
};
} catch (error) {
this.logger.error('Error processing command', error);
return {
response: 'I encountered an error processing your request. Please try again.',
actions: [],
memory: {},
confidence: 0,
};
}
}
private buildPrompt(
command: string,
context: NowhereContext,
memory: any
): string {
return `
${this.systemPrompt}
## Current Context
- User ID: ${context.userId}
- Project ID: ${context.projectId}
- Current File: ${context.currentFile || 'None'}
- Session ID: ${context.sessionId}
## Relevant Memory
${JSON.stringify(memory, null, 2)}
## User Command
${command}
## Instructions
Process this command using your advanced capabilities. Consider the context and memory when formulating your response. If this is a voice command, provide clear, actionable responses suitable for voice interaction.
`;
}
private async getAIResponse(
prompt: string,
context: NowhereContext
): Promise<any> {
try {
// Try OpenAI first, fallback to Anthropic
const openaiResponse = await this.openai.chat.completions.create({
model: 'gpt-4',
messages: [
{
role: 'system',
content: this.systemPrompt,
},
{
role: 'user',
content: prompt,
},
],
temperature: 0.7,
max_tokens: 2000,
});
const response = openaiResponse.choices[0]?.message?.content || '';
// Parse response for actions and confidence
const parsedResponse = this.parseAIResponse(response);
return {
response: parsedResponse.response,
actions: parsedResponse.actions,
confidence: parsedResponse.confidence,
suggestions: parsedResponse.suggestions,
};
} catch (error) {
this.logger.warn('OpenAI failed, trying Anthropic', error);
// Fallback to Anthropic
const anthropicResponse = await this.anthropic.messages.create({
model: 'claude-3-sonnet-20240229',
max_tokens: 2000,
messages: [
{
role: 'user',
content: prompt,
},
],
});
const response = anthropicResponse.content[0]?.text || '';
const parsedResponse = this.parseAIResponse(response);
return {
response: parsedResponse.response,
actions: parsedResponse.actions,
confidence: parsedResponse.confidence,
suggestions: parsedResponse.suggestions,
};
}
}
private parseAIResponse(response: string): any {
try {
// Look for JSON blocks in the response
const jsonMatch = response.match(/```json\n([\s\S]*?)\n```/);
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[1]);
return {
response: parsed.response || response,
actions: parsed.actions || [],
confidence: parsed.confidence || 0.8,
suggestions: parsed.suggestions || [],
};
}
// Fallback to simple parsing
return {
response: response,
actions: [],
confidence: 0.8,
suggestions: [],
};
} catch (error) {
this.logger.warn('Failed to parse AI response', error);
return {
response: response,
actions: [],
confidence: 0.8,
suggestions: [],
};
}
}
private async executeActions(actions: any[], context: NowhereContext): Promise<any[]> {
const results = [];
for (const action of actions) {
try {
const result = await this.toolExecutor.executeTool(action, context);
results.push(result);
} catch (error) {
this.logger.error(`Failed to execute action: ${action.type}`, error);
results.push({
success: false,
error: error.message,
action: action,
});
}
}
return results;
}
async processVoiceCommand(
voiceInput: string,
context: NowhereContext
): Promise<NowhereResponse> {
return this.processCommand(voiceInput, context, true);
}
async enableAutopilotMode(context: NowhereContext): Promise<void> {
this.logger.info('Enabling autopilot mode', { context });
// Implementation for autopilot mode
}
async disableAutopilotMode(context: NowhereContext): Promise<void> {
this.logger.info('Disabling autopilot mode', { context });
// Implementation for disabling autopilot mode
}
async getMemory(context: NowhereContext): Promise<any> {
return this.memoryManager.getRelevantMemory(context);
}
async clearMemory(context: NowhereContext): Promise<void> {
await this.memoryManager.clearMemory(context);
}
}

View File

@@ -0,0 +1,120 @@
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import dotenv from 'dotenv';
import { Logger } from './utils/logger';
import { NowhereCore } from './core/nowhere';
import { setupRoutes } from './routes';
import { setupWebSocket } from './websocket';
import { errorHandler } from './middleware/error-handler';
import { rateLimiter } from './middleware/rate-limiter';
import { authMiddleware } from './middleware/auth';
// Load environment variables
dotenv.config();
const app = express();
const server = createServer(app);
const io = new Server(server, {
cors: {
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
methods: ['GET', 'POST'],
},
});
const logger = new Logger('Server');
const PORT = process.env.PORT || 3001;
// Initialize Nowhere core
const nowhere = new NowhereCore();
// Middleware
app.use(helmet());
app.use(compression());
app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
credentials: true,
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Rate limiting
app.use(rateLimiter);
// Authentication middleware (optional for development)
if (process.env.NODE_ENV === 'production') {
app.use(authMiddleware);
}
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
version: '1.0.0',
agent: 'Nowhere',
});
});
// Setup routes
setupRoutes(app, nowhere);
// Setup WebSocket
setupWebSocket(io, nowhere);
// Error handling middleware
app.use(errorHandler);
// 404 handler
app.use('*', (req, res) => {
res.status(404).json({
error: 'Route not found',
path: req.originalUrl,
});
});
// Start server
server.listen(PORT, () => {
logger.info(`🚀 Nowhere AI Agent Server running on port ${PORT}`);
logger.info(`📡 WebSocket server ready for real-time communication`);
logger.info(`🔗 Health check: http://localhost:${PORT}/health`);
if (process.env.NODE_ENV === 'development') {
logger.info(`🌐 Frontend URL: ${process.env.FRONTEND_URL || 'http://localhost:3000'}`);
logger.info(`🔑 OpenAI API: ${process.env.OPENAI_API_KEY ? 'Configured' : 'Missing'}`);
logger.info(`🔑 Anthropic API: ${process.env.ANTHROPIC_API_KEY ? 'Configured' : 'Missing'}`);
}
});
// Graceful shutdown
process.on('SIGTERM', () => {
logger.info('SIGTERM received, shutting down gracefully');
server.close(() => {
logger.info('Server closed');
process.exit(0);
});
});
process.on('SIGINT', () => {
logger.info('SIGINT received, shutting down gracefully');
server.close(() => {
logger.info('Server closed');
process.exit(0);
});
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
logger.error('Uncaught Exception:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});
export { app, server, io, nowhere };

View File

@@ -0,0 +1,325 @@
import Redis from 'redis';
import { Pool } from 'pg';
import { Logger } from '../utils/logger';
export interface MemoryEntry {
id: string;
userId: string;
projectId: string;
type: 'conversation' | 'code_context' | 'user_preferences' | 'project_state';
content: any;
metadata: {
timestamp: Date;
confidence: number;
tags: string[];
context: any;
};
createdAt: Date;
updatedAt: Date;
}
export interface MemoryQuery {
userId: string;
projectId?: string;
type?: string;
tags?: string[];
limit?: number;
offset?: number;
}
export class MemoryManager {
private redis: Redis.RedisClientType;
private postgres: Pool;
private logger: Logger;
constructor() {
this.logger = new Logger('MemoryManager');
this.initializeConnections();
}
private async initializeConnections() {
// Initialize Redis connection
this.redis = Redis.createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379',
});
this.redis.on('error', (err) => {
this.logger.error('Redis connection error', { error: err.message });
});
await this.redis.connect();
// Initialize PostgreSQL connection
this.postgres = new Pool({
connectionString: process.env.POSTGRES_URL || 'postgresql://localhost:5432/nowhere_db',
});
await this.createTables();
}
private async createTables() {
const createMemoryTable = `
CREATE TABLE IF NOT EXISTS memory_entries (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) NOT NULL,
project_id VARCHAR(255),
type VARCHAR(50) NOT NULL,
content JSONB NOT NULL,
metadata JSONB NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_memory_user_project ON memory_entries(user_id, project_id);
CREATE INDEX IF NOT EXISTS idx_memory_type ON memory_entries(type);
CREATE INDEX IF NOT EXISTS idx_memory_created_at ON memory_entries(created_at);
`;
try {
await this.postgres.query(createMemoryTable);
this.logger.info('Database tables created successfully');
} catch (error) {
this.logger.error('Failed to create database tables', { error });
}
}
async storeMemory(entry: Omit<MemoryEntry, 'id' | 'createdAt' | 'updatedAt'>): Promise<string> {
try {
// Store in PostgreSQL for persistence
const query = `
INSERT INTO memory_entries (user_id, project_id, type, content, metadata)
VALUES ($1, $2, $3, $4, $5)
RETURNING id
`;
const result = await this.postgres.query(query, [
entry.userId,
entry.projectId,
entry.type,
JSON.stringify(entry.content),
JSON.stringify(entry.metadata)
]);
const id = result.rows[0].id;
// Cache in Redis for fast access
const cacheKey = `memory:${entry.userId}:${entry.projectId}:${id}`;
await this.redis.setEx(cacheKey, 3600, JSON.stringify(entry)); // Cache for 1 hour
this.logger.memoryOperation('store', { userId: entry.userId, projectId: entry.projectId, type: entry.type });
return id;
} catch (error) {
this.logger.error('Failed to store memory', { error, entry });
throw error;
}
}
async retrieveMemory(query: MemoryQuery): Promise<MemoryEntry[]> {
try {
let sqlQuery = `
SELECT * FROM memory_entries
WHERE user_id = $1
`;
const params: any[] = [query.userId];
let paramIndex = 2;
if (query.projectId) {
sqlQuery += ` AND project_id = $${paramIndex}`;
params.push(query.projectId);
paramIndex++;
}
if (query.type) {
sqlQuery += ` AND type = $${paramIndex}`;
params.push(query.type);
paramIndex++;
}
if (query.tags && query.tags.length > 0) {
sqlQuery += ` AND metadata->>'tags' ?| $${paramIndex}`;
params.push(query.tags);
paramIndex++;
}
sqlQuery += ` ORDER BY created_at DESC`;
if (query.limit) {
sqlQuery += ` LIMIT $${paramIndex}`;
params.push(query.limit);
paramIndex++;
}
if (query.offset) {
sqlQuery += ` OFFSET $${paramIndex}`;
params.push(query.offset);
}
const result = await this.postgres.query(sqlQuery, params);
const memories = result.rows.map(row => ({
id: row.id,
userId: row.user_id,
projectId: row.project_id,
type: row.type,
content: row.content,
metadata: row.metadata,
createdAt: row.created_at,
updatedAt: row.updated_at
}));
this.logger.memoryOperation('retrieve', { query, count: memories.length });
return memories;
} catch (error) {
this.logger.error('Failed to retrieve memory', { error, query });
throw error;
}
}
async updateMemory(id: string, updates: Partial<MemoryEntry>): Promise<void> {
try {
const updateFields: string[] = [];
const params: any[] = [];
let paramIndex = 1;
if (updates.content) {
updateFields.push(`content = $${paramIndex}`);
params.push(JSON.stringify(updates.content));
paramIndex++;
}
if (updates.metadata) {
updateFields.push(`metadata = $${paramIndex}`);
params.push(JSON.stringify(updates.metadata));
paramIndex++;
}
if (updateFields.length === 0) {
return;
}
updateFields.push(`updated_at = CURRENT_TIMESTAMP`);
params.push(id);
const query = `
UPDATE memory_entries
SET ${updateFields.join(', ')}
WHERE id = $${paramIndex}
`;
await this.postgres.query(query, params);
// Update cache
const cacheKey = `memory:${updates.userId}:${updates.projectId}:${id}`;
const cached = await this.redis.get(cacheKey);
if (cached) {
const entry = JSON.parse(cached);
const updatedEntry = { ...entry, ...updates, updatedAt: new Date() };
await this.redis.setEx(cacheKey, 3600, JSON.stringify(updatedEntry));
}
this.logger.memoryOperation('update', { id, updates });
} catch (error) {
this.logger.error('Failed to update memory', { error, id, updates });
throw error;
}
}
async deleteMemory(id: string): Promise<void> {
try {
await this.postgres.query('DELETE FROM memory_entries WHERE id = $1', [id]);
// Remove from cache
const keys = await this.redis.keys(`memory:*:${id}`);
if (keys.length > 0) {
await this.redis.del(keys);
}
this.logger.memoryOperation('delete', { id });
} catch (error) {
this.logger.error('Failed to delete memory', { error, id });
throw error;
}
}
async clearUserMemory(userId: string, projectId?: string): Promise<void> {
try {
let query = 'DELETE FROM memory_entries WHERE user_id = $1';
const params: any[] = [userId];
if (projectId) {
query += ' AND project_id = $2';
params.push(projectId);
}
await this.postgres.query(query, params);
// Clear cache
const pattern = projectId ? `memory:${userId}:${projectId}:*` : `memory:${userId}:*`;
const keys = await this.redis.keys(pattern);
if (keys.length > 0) {
await this.redis.del(keys);
}
this.logger.memoryOperation('clear', { userId, projectId });
} catch (error) {
this.logger.error('Failed to clear user memory', { error, userId, projectId });
throw error;
}
}
async getMemorySummary(userId: string, projectId?: string): Promise<any> {
try {
let query = `
SELECT
type,
COUNT(*) as count,
MAX(created_at) as last_updated
FROM memory_entries
WHERE user_id = $1
`;
const params: any[] = [userId];
if (projectId) {
query += ' AND project_id = $2';
params.push(projectId);
}
query += ' GROUP BY type';
const result = await this.postgres.query(query, params);
const summary = {
totalEntries: 0,
byType: {},
lastActivity: null
};
result.rows.forEach(row => {
summary.byType[row.type] = {
count: parseInt(row.count),
lastUpdated: row.last_updated
};
summary.totalEntries += parseInt(row.count);
if (!summary.lastActivity || row.last_updated > summary.lastActivity) {
summary.lastActivity = row.last_updated;
}
});
return summary;
} catch (error) {
this.logger.error('Failed to get memory summary', { error, userId, projectId });
throw error;
}
}
async close(): Promise<void> {
try {
await this.redis.quit();
await this.postgres.end();
this.logger.info('MemoryManager connections closed');
} catch (error) {
this.logger.error('Error closing MemoryManager connections', { error });
}
}
}

View File

@@ -0,0 +1,268 @@
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { Logger } from '../utils/logger';
const logger = new Logger('AuthMiddleware');
export interface AuthenticatedRequest extends Request {
user?: {
id: string;
email: string;
role: string;
permissions: string[];
};
}
export function authMiddleware(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const authHeader = req.headers.authorization;
if (!authHeader) {
logger.warn('No authorization header provided', {
ip: req.ip,
userAgent: req.get('User-Agent')
});
return res.status(401).json({
success: false,
error: 'No authorization token provided'
});
}
const token = authHeader.replace('Bearer ', '');
if (!token) {
logger.warn('Invalid authorization header format', {
ip: req.ip,
userAgent: req.get('User-Agent')
});
return res.status(401).json({
success: false,
error: 'Invalid authorization header format'
});
}
const secret = process.env.JWT_SECRET;
if (!secret) {
logger.error('JWT_SECRET not configured');
return res.status(500).json({
success: false,
error: 'Server configuration error'
});
}
try {
const decoded = jwt.verify(token, secret) as any;
req.user = {
id: decoded.id,
email: decoded.email,
role: decoded.role || 'user',
permissions: decoded.permissions || []
};
logger.info('User authenticated successfully', {
userId: req.user.id,
email: req.user.email,
ip: req.ip
});
next();
} catch (jwtError) {
logger.warn('Invalid JWT token', {
error: jwtError.message,
ip: req.ip
});
return res.status(401).json({
success: false,
error: 'Invalid or expired token'
});
}
} catch (error) {
logger.error('Authentication middleware error', {
error: error.message,
ip: req.ip
});
return res.status(500).json({
success: false,
error: 'Authentication service error'
});
}
}
export function optionalAuthMiddleware(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const authHeader = req.headers.authorization;
if (!authHeader) {
// Continue without authentication
next();
return;
}
const token = authHeader.replace('Bearer ', '');
if (!token) {
// Continue without authentication
next();
return;
}
const secret = process.env.JWT_SECRET;
if (!secret) {
// Continue without authentication
next();
return;
}
try {
const decoded = jwt.verify(token, secret) as any;
req.user = {
id: decoded.id,
email: decoded.email,
role: decoded.role || 'user',
permissions: decoded.permissions || []
};
logger.info('Optional authentication successful', {
userId: req.user.id,
email: req.user.email
});
next();
} catch (jwtError) {
// Continue without authentication
logger.debug('Optional authentication failed, continuing without auth', {
error: jwtError.message
});
next();
}
} catch (error) {
logger.error('Optional authentication middleware error', {
error: error.message
});
// Continue without authentication
next();
}
}
export function requireRole(roles: string[]) {
return (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
if (!req.user) {
logger.warn('Role check failed - no authenticated user', {
requiredRoles: roles,
ip: req.ip
});
return res.status(401).json({
success: false,
error: 'Authentication required'
});
}
if (!roles.includes(req.user.role)) {
logger.warn('Insufficient role permissions', {
userRole: req.user.role,
requiredRoles: roles,
userId: req.user.id
});
return res.status(403).json({
success: false,
error: 'Insufficient permissions'
});
}
logger.debug('Role check passed', {
userRole: req.user.role,
requiredRoles: roles,
userId: req.user.id
});
next();
};
}
export function requirePermission(permissions: string[]) {
return (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
if (!req.user) {
logger.warn('Permission check failed - no authenticated user', {
requiredPermissions: permissions,
ip: req.ip
});
return res.status(401).json({
success: false,
error: 'Authentication required'
});
}
const hasAllPermissions = permissions.every(permission =>
req.user!.permissions.includes(permission)
);
if (!hasAllPermissions) {
logger.warn('Insufficient permissions', {
userPermissions: req.user.permissions,
requiredPermissions: permissions,
userId: req.user.id
});
return res.status(403).json({
success: false,
error: 'Insufficient permissions'
});
}
logger.debug('Permission check passed', {
userPermissions: req.user.permissions,
requiredPermissions: permissions,
userId: req.user.id
});
next();
};
}
export function rateLimitByUser(req: AuthenticatedRequest, res: Response, next: NextFunction) {
// This is a simplified rate limiting by user
// In a real implementation, you would use Redis or a similar store
const userId = req.user?.id || req.ip;
// For now, we'll just pass through
// In a real implementation, you would check rate limits here
logger.debug('Rate limit check passed', { userId });
next();
}
export function generateToken(user: {
id: string;
email: string;
role?: string;
permissions?: string[];
}): string {
const secret = process.env.JWT_SECRET;
if (!secret) {
throw new Error('JWT_SECRET not configured');
}
const payload = {
id: user.id,
email: user.email,
role: user.role || 'user',
permissions: user.permissions || [],
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24 * 7) // 7 days
};
return jwt.sign(payload, secret);
}
export function verifyToken(token: string): any {
const secret = process.env.JWT_SECRET;
if (!secret) {
throw new Error('JWT_SECRET not configured');
}
return jwt.verify(token, secret);
}

View File

@@ -0,0 +1,67 @@
import { Request, Response, NextFunction } from 'express';
import { Logger } from '../utils/logger';
const logger = new Logger('ErrorHandler');
export interface AppError extends Error {
statusCode?: number;
isOperational?: boolean;
}
export function errorHandler(
error: AppError,
req: Request,
res: Response,
next: NextFunction
) {
const statusCode = error.statusCode || 500;
const message = error.message || 'Internal Server Error';
// Log the error
logger.error('Error occurred', {
error: {
message: error.message,
stack: error.stack,
statusCode,
},
request: {
method: req.method,
url: req.url,
headers: req.headers,
body: req.body,
user: req.user,
},
});
// Don't expose internal errors in production
const isDevelopment = process.env.NODE_ENV === 'development';
const errorResponse = {
success: false,
error: {
message: isDevelopment ? message : 'An error occurred',
statusCode,
...(isDevelopment && { stack: error.stack }),
},
timestamp: new Date().toISOString(),
path: req.path,
};
res.status(statusCode).json(errorResponse);
}
export function createError(
message: string,
statusCode: number = 500,
isOperational: boolean = true
): AppError {
const error = new Error(message) as AppError;
error.statusCode = statusCode;
error.isOperational = isOperational;
return error;
}
export function asyncHandler(fn: Function) {
return (req: Request, res: Response, next: NextFunction) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}

View File

@@ -0,0 +1,99 @@
import { Request, Response, NextFunction } from 'express';
import { RateLimiterRedis } from 'rate-limiter-flexible';
import Redis from 'redis';
import { Logger } from '../utils/logger';
const logger = new Logger('RateLimiter');
// Create Redis client for rate limiting
const redisClient = Redis.createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379',
});
// Rate limiter configuration
const rateLimiter = new RateLimiterRedis({
storeClient: redisClient,
keyPrefix: 'nowhere_rate_limit',
points: 100, // Number of requests
duration: 60, // Per 60 seconds
blockDuration: 60 * 15, // Block for 15 minutes if limit exceeded
});
// Rate limiter middleware
export async function rateLimiterMiddleware(
req: Request,
res: Response,
next: NextFunction
) {
try {
const key = req.ip || req.connection.remoteAddress || 'unknown';
await rateLimiter.consume(key);
next();
} catch (rejRes) {
const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;
logger.warn('Rate limit exceeded', {
ip: req.ip,
userAgent: req.get('User-Agent'),
path: req.path,
remainingPoints: rejRes.remainingPoints,
msBeforeNext: rejRes.msBeforeNext,
});
res.set('Retry-After', String(Math.round(secs / 60)));
res.status(429).json({
success: false,
error: {
message: 'Too many requests',
retryAfter: secs,
},
timestamp: new Date().toISOString(),
});
}
}
// Special rate limiter for voice commands (more restrictive)
const voiceRateLimiter = new RateLimiterRedis({
storeClient: redisClient,
keyPrefix: 'nowhere_voice_rate_limit',
points: 50, // Fewer requests for voice
duration: 60,
blockDuration: 60 * 30, // Block for 30 minutes
});
export async function voiceRateLimiterMiddleware(
req: Request,
res: Response,
next: NextFunction
) {
try {
const key = req.ip || req.connection.remoteAddress || 'unknown';
await voiceRateLimiter.consume(key);
next();
} catch (rejRes) {
const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;
logger.warn('Voice rate limit exceeded', {
ip: req.ip,
userAgent: req.get('User-Agent'),
path: req.path,
remainingPoints: rejRes.remainingPoints,
msBeforeNext: rejRes.msBeforeNext,
});
res.set('Retry-After', String(Math.round(secs / 60)));
res.status(429).json({
success: false,
error: {
message: 'Too many voice requests',
retryAfter: secs,
},
timestamp: new Date().toISOString(),
});
}
}
// Export the main rate limiter for general use
export const rateLimiter = rateLimiterMiddleware;

View File

@@ -0,0 +1,283 @@
import { Express } from 'express';
import { NowhereCore, NowhereContext } from '../core/nowhere';
import { Logger } from '../utils/logger';
const logger = new Logger('Routes');
export function setupRoutes(app: Express, nowhere: NowhereCore) {
// API Routes
app.use('/api/v1', createAPIRoutes(nowhere));
}
function createAPIRoutes(nowhere: NowhereCore) {
const router = require('express').Router();
// Command processing endpoint
router.post('/command', async (req, res) => {
try {
const { command, context } = req.body;
if (!command) {
return res.status(400).json({
error: 'Command is required',
});
}
const defaultContext: NowhereContext = {
userId: context?.userId || 'default-user',
projectId: context?.projectId || 'default-project',
currentFile: context?.currentFile,
codebase: context?.codebase,
userPreferences: context?.userPreferences,
sessionId: context?.sessionId || `session-${Date.now()}`,
};
const response = await nowhere.processCommand(command, defaultContext);
res.json({
success: true,
data: response,
timestamp: new Date().toISOString(),
});
} catch (error) {
logger.error('Error processing command', error);
res.status(500).json({
error: 'Failed to process command',
message: error.message,
});
}
});
// Voice command processing endpoint
router.post('/voice', async (req, res) => {
try {
const { voiceInput, context } = req.body;
if (!voiceInput) {
return res.status(400).json({
error: 'Voice input is required',
});
}
const defaultContext: NowhereContext = {
userId: context?.userId || 'default-user',
projectId: context?.projectId || 'default-project',
currentFile: context?.currentFile,
codebase: context?.codebase,
userPreferences: context?.userPreferences,
sessionId: context?.sessionId || `session-${Date.now()}`,
};
const response = await nowhere.processVoiceCommand(voiceInput, defaultContext);
res.json({
success: true,
data: response,
timestamp: new Date().toISOString(),
});
} catch (error) {
logger.error('Error processing voice command', error);
res.status(500).json({
error: 'Failed to process voice command',
message: error.message,
});
}
});
// Autopilot mode endpoints
router.post('/autopilot/enable', async (req, res) => {
try {
const { context } = req.body;
const defaultContext: NowhereContext = {
userId: context?.userId || 'default-user',
projectId: context?.projectId || 'default-project',
currentFile: context?.currentFile,
codebase: context?.codebase,
userPreferences: context?.userPreferences,
sessionId: context?.sessionId || `session-${Date.now()}`,
};
await nowhere.enableAutopilotMode(defaultContext);
res.json({
success: true,
message: 'Autopilot mode enabled',
timestamp: new Date().toISOString(),
});
} catch (error) {
logger.error('Error enabling autopilot mode', error);
res.status(500).json({
error: 'Failed to enable autopilot mode',
message: error.message,
});
}
});
router.post('/autopilot/disable', async (req, res) => {
try {
const { context } = req.body;
const defaultContext: NowhereContext = {
userId: context?.userId || 'default-user',
projectId: context?.projectId || 'default-project',
currentFile: context?.currentFile,
codebase: context?.codebase,
userPreferences: context?.userPreferences,
sessionId: context?.sessionId || `session-${Date.now()}`,
};
await nowhere.disableAutopilotMode(defaultContext);
res.json({
success: true,
message: 'Autopilot mode disabled',
timestamp: new Date().toISOString(),
});
} catch (error) {
logger.error('Error disabling autopilot mode', error);
res.status(500).json({
error: 'Failed to disable autopilot mode',
message: error.message,
});
}
});
// Memory management endpoints
router.get('/memory/:userId/:projectId', async (req, res) => {
try {
const { userId, projectId } = req.params;
const { sessionId } = req.query;
const context: NowhereContext = {
userId,
projectId,
sessionId: sessionId as string || `session-${Date.now()}`,
};
const memory = await nowhere.getMemory(context);
res.json({
success: true,
data: memory,
timestamp: new Date().toISOString(),
});
} catch (error) {
logger.error('Error retrieving memory', error);
res.status(500).json({
error: 'Failed to retrieve memory',
message: error.message,
});
}
});
router.delete('/memory/:userId/:projectId', async (req, res) => {
try {
const { userId, projectId } = req.params;
const { sessionId } = req.query;
const context: NowhereContext = {
userId,
projectId,
sessionId: sessionId as string || `session-${Date.now()}`,
};
await nowhere.clearMemory(context);
res.json({
success: true,
message: 'Memory cleared successfully',
timestamp: new Date().toISOString(),
});
} catch (error) {
logger.error('Error clearing memory', error);
res.status(500).json({
error: 'Failed to clear memory',
message: error.message,
});
}
});
// Status endpoint
router.get('/status', (req, res) => {
res.json({
success: true,
data: {
status: 'operational',
agent: 'Nowhere',
version: '1.0.0',
features: [
'voice-commands',
'autopilot-mode',
'adaptive-learning',
'memory-system',
'real-time-collaboration',
],
timestamp: new Date().toISOString(),
},
});
});
// Configuration endpoint
router.get('/config', (req, res) => {
res.json({
success: true,
data: {
voiceCommands: {
navigation: [
'go to file',
'show me the main function',
'navigate to',
'open',
'find',
'locate',
],
execution: [
'run',
'execute',
'start',
'deploy',
'build',
'test',
],
analysis: [
'analyze',
'find performance issues',
'check code quality',
'review',
'inspect',
],
creation: [
'create',
'add',
'implement',
'build',
'generate',
'make',
],
debugging: [
'fix',
'debug',
'resolve',
'optimize',
'troubleshoot',
],
},
autopilotSettings: {
enabled: true,
autonomyLevel: 'medium',
confirmationThreshold: 0.8,
riskTolerance: 'medium',
},
voiceSettings: {
recognitionSensitivity: 0.8,
responseSpeed: 'normal',
language: 'en-US',
communicationStyle: 'professional',
},
},
});
});
return router;
}

View File

@@ -0,0 +1,568 @@
import { exec } from 'child_process';
import { promisify } from 'util';
import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';
import { join, dirname, extname } from 'path';
import { Logger } from '../utils/logger';
const execAsync = promisify(exec);
export interface ToolResult {
success: boolean;
data?: any;
error?: string;
duration: number;
metadata?: {
tool: string;
operation: string;
timestamp: Date;
};
}
export interface FileOperation {
type: 'read' | 'write' | 'delete' | 'list' | 'search';
path: string;
content?: string;
options?: any;
}
export interface TerminalCommand {
command: string;
cwd?: string;
timeout?: number;
}
export interface WebSearchQuery {
query: string;
maxResults?: number;
filters?: any;
}
export class ToolExecutor {
private logger: Logger;
constructor() {
this.logger = new Logger('ToolExecutor');
}
async executeFileOperation(operation: FileOperation): Promise<ToolResult> {
const startTime = Date.now();
try {
switch (operation.type) {
case 'read':
return await this.readFile(operation.path);
case 'write':
return await this.writeFile(operation.path, operation.content || '');
case 'list':
return await this.listDirectory(operation.path);
case 'search':
return await this.searchFiles(operation.path, operation.options);
default:
throw new Error(`Unsupported file operation: ${operation.type}`);
}
} catch (error) {
const duration = Date.now() - startTime;
this.logger.error('File operation failed', { operation, error: error.message });
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'file_operation',
operation: operation.type,
timestamp: new Date()
}
};
}
}
private async readFile(path: string): Promise<ToolResult> {
const startTime = Date.now();
try {
const content = await readFile(path, 'utf-8');
const stats = await stat(path);
const duration = Date.now() - startTime;
this.logger.toolExecution('read_file', { path, size: stats.size }, duration);
return {
success: true,
data: {
content,
metadata: {
size: stats.size,
modified: stats.mtime,
created: stats.birthtime
}
},
duration,
metadata: {
tool: 'file_operation',
operation: 'read',
timestamp: new Date()
}
};
} catch (error) {
const duration = Date.now() - startTime;
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'file_operation',
operation: 'read',
timestamp: new Date()
}
};
}
}
private async writeFile(path: string, content: string): Promise<ToolResult> {
const startTime = Date.now();
try {
// Ensure directory exists
await mkdir(dirname(path), { recursive: true });
await writeFile(path, content, 'utf-8');
const stats = await stat(path);
const duration = Date.now() - startTime;
this.logger.toolExecution('write_file', { path, size: stats.size }, duration);
return {
success: true,
data: {
path,
size: stats.size,
modified: stats.mtime
},
duration,
metadata: {
tool: 'file_operation',
operation: 'write',
timestamp: new Date()
}
};
} catch (error) {
const duration = Date.now() - startTime;
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'file_operation',
operation: 'write',
timestamp: new Date()
}
};
}
}
private async listDirectory(path: string): Promise<ToolResult> {
const startTime = Date.now();
try {
const items = await readdir(path, { withFileTypes: true });
const files = items
.filter(item => item.isFile())
.map(item => ({
name: item.name,
type: 'file',
extension: extname(item.name)
}));
const directories = items
.filter(item => item.isDirectory())
.map(item => ({
name: item.name,
type: 'directory'
}));
const duration = Date.now() - startTime;
this.logger.toolExecution('list_directory', { path, count: items.length }, duration);
return {
success: true,
data: {
path,
files,
directories,
total: items.length
},
duration,
metadata: {
tool: 'file_operation',
operation: 'list',
timestamp: new Date()
}
};
} catch (error) {
const duration = Date.now() - startTime;
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'file_operation',
operation: 'list',
timestamp: new Date()
}
};
}
}
private async searchFiles(directory: string, options: any = {}): Promise<ToolResult> {
const startTime = Date.now();
try {
const { pattern, extensions, maxDepth = 3 } = options;
const results: any[] = [];
await this.searchRecursive(directory, pattern, extensions, maxDepth, 0, results);
const duration = Date.now() - startTime;
this.logger.toolExecution('search_files', { directory, pattern, count: results.length }, duration);
return {
success: true,
data: {
directory,
pattern,
results,
count: results.length
},
duration,
metadata: {
tool: 'file_operation',
operation: 'search',
timestamp: new Date()
}
};
} catch (error) {
const duration = Date.now() - startTime;
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'file_operation',
operation: 'search',
timestamp: new Date()
}
};
}
}
private async searchRecursive(
dir: string,
pattern: string,
extensions: string[],
maxDepth: number,
currentDepth: number,
results: any[]
): Promise<void> {
if (currentDepth > maxDepth) return;
try {
const items = await readdir(dir, { withFileTypes: true });
for (const item of items) {
const fullPath = join(dir, item.name);
if (item.isDirectory()) {
await this.searchRecursive(fullPath, pattern, extensions, maxDepth, currentDepth + 1, results);
} else if (item.isFile()) {
const matchesPattern = !pattern || item.name.toLowerCase().includes(pattern.toLowerCase());
const matchesExtension = !extensions || extensions.length === 0 ||
extensions.some(ext => item.name.toLowerCase().endsWith(ext.toLowerCase()));
if (matchesPattern && matchesExtension) {
const stats = await stat(fullPath);
results.push({
name: item.name,
path: fullPath,
size: stats.size,
modified: stats.mtime,
extension: extname(item.name)
});
}
}
}
} catch (error) {
// Skip directories we can't access
this.logger.debug('Skipping directory', { dir, error: error.message });
}
}
async executeTerminalCommand(command: TerminalCommand): Promise<ToolResult> {
const startTime = Date.now();
try {
const { stdout, stderr } = await execAsync(command.command, {
cwd: command.cwd,
timeout: command.timeout || 30000 // 30 second default timeout
});
const duration = Date.now() - startTime;
this.logger.toolExecution('terminal_command', { command: command.command }, duration);
return {
success: true,
data: {
stdout,
stderr,
command: command.command,
cwd: command.cwd
},
duration,
metadata: {
tool: 'terminal',
operation: 'execute',
timestamp: new Date()
}
};
} catch (error: any) {
const duration = Date.now() - startTime;
this.logger.error('Terminal command failed', { command: command.command, error: error.message });
return {
success: false,
error: error.message,
data: {
stdout: error.stdout || '',
stderr: error.stderr || '',
command: command.command,
cwd: command.cwd
},
duration,
metadata: {
tool: 'terminal',
operation: 'execute',
timestamp: new Date()
}
};
}
}
async executeWebSearch(query: WebSearchQuery): Promise<ToolResult> {
const startTime = Date.now();
try {
// This is a placeholder for web search functionality
// In a real implementation, you would integrate with search APIs
const mockResults = [
{
title: `Search results for: ${query.query}`,
url: 'https://example.com',
snippet: `This is a mock search result for "${query.query}". In a real implementation, this would be actual search results.`
}
];
const duration = Date.now() - startTime;
this.logger.toolExecution('web_search', { query: query.query, results: mockResults.length }, duration);
return {
success: true,
data: {
query: query.query,
results: mockResults,
count: mockResults.length
},
duration,
metadata: {
tool: 'web_search',
operation: 'search',
timestamp: new Date()
}
};
} catch (error) {
const duration = Date.now() - startTime;
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'web_search',
operation: 'search',
timestamp: new Date()
}
};
}
}
async analyzeCode(filePath: string): Promise<ToolResult> {
const startTime = Date.now();
try {
const content = await readFile(filePath, 'utf-8');
const extension = extname(filePath).toLowerCase();
// Basic code analysis
const analysis = {
language: this.detectLanguage(extension),
lines: content.split('\n').length,
characters: content.length,
functions: this.countFunctions(content, extension),
imports: this.extractImports(content, extension),
complexity: this.calculateComplexity(content)
};
const duration = Date.now() - startTime;
this.logger.toolExecution('code_analysis', { filePath, language: analysis.language }, duration);
return {
success: true,
data: {
filePath,
analysis
},
duration,
metadata: {
tool: 'code_analysis',
operation: 'analyze',
timestamp: new Date()
}
};
} catch (error) {
const duration = Date.now() - startTime;
return {
success: false,
error: error.message,
duration,
metadata: {
tool: 'code_analysis',
operation: 'analyze',
timestamp: new Date()
}
};
}
}
private detectLanguage(extension: string): string {
const languageMap: { [key: string]: string } = {
'.js': 'JavaScript',
'.ts': 'TypeScript',
'.py': 'Python',
'.java': 'Java',
'.cpp': 'C++',
'.c': 'C',
'.cs': 'C#',
'.php': 'PHP',
'.rb': 'Ruby',
'.go': 'Go',
'.rs': 'Rust',
'.swift': 'Swift',
'.kt': 'Kotlin',
'.scala': 'Scala',
'.html': 'HTML',
'.css': 'CSS',
'.json': 'JSON',
'.xml': 'XML',
'.md': 'Markdown'
};
return languageMap[extension] || 'Unknown';
}
private countFunctions(content: string, extension: string): number {
const patterns: { [key: string]: RegExp[] } = {
'.js': [/function\s+\w+\s*\(/g, /const\s+\w+\s*=\s*\(/g, /let\s+\w+\s*=\s*\(/g, /var\s+\w+\s*=\s*\(/g],
'.ts': [/function\s+\w+\s*\(/g, /const\s+\w+\s*=\s*\(/g, /let\s+\w+\s*=\s*\(/g, /var\s+\w+\s*=\s*\(/g],
'.py': [/def\s+\w+\s*\(/g],
'.java': [/public\s+\w+\s+\w+\s*\(/g, /private\s+\w+\s+\w+\s*\(/g, /protected\s+\w+\s+\w+\s*\(/g],
'.cpp': [/void\s+\w+\s*\(/g, /int\s+\w+\s*\(/g, /string\s+\w+\s*\(/g],
'.cs': [/public\s+\w+\s+\w+\s*\(/g, /private\s+\w+\s+\w+\s*\(/g, /protected\s+\w+\s+\w+\s*\(/g]
};
const patternsForLang = patterns[extension] || [];
let count = 0;
patternsForLang.forEach(pattern => {
const matches = content.match(pattern);
if (matches) count += matches.length;
});
return count;
}
private extractImports(content: string, extension: string): string[] {
const patterns: { [key: string]: RegExp } = {
'.js': /import\s+.*?from\s+['"]([^'"]+)['"]/g,
'.ts': /import\s+.*?from\s+['"]([^'"]+)['"]/g,
'.py': /import\s+([a-zA-Z_][a-zA-Z0-9_]*)/g,
'.java': /import\s+([a-zA-Z_][a-zA-Z0-9_.]*);/g,
'.cpp': /#include\s+[<"]([^>"]+)[>"]/g,
'.cs': /using\s+([a-zA-Z_][a-zA-Z0-9_.]*);/g
};
const pattern = patterns[extension];
if (!pattern) return [];
const imports: string[] = [];
let match;
while ((match = pattern.exec(content)) !== null) {
imports.push(match[1]);
}
return imports;
}
private calculateComplexity(content: string): number {
// Simple cyclomatic complexity calculation
const complexityFactors = [
/if\s*\(/g,
/else\s*if\s*\(/g,
/for\s*\(/g,
/while\s*\(/g,
/switch\s*\(/g,
/case\s+/g,
/catch\s*\(/g,
/\|\|/g,
/&&/g
];
let complexity = 1; // Base complexity
complexityFactors.forEach(factor => {
const matches = content.match(factor);
if (matches) complexity += matches.length;
});
return complexity;
}
async executeTool(toolName: string, params: any): Promise<ToolResult> {
const startTime = Date.now();
try {
switch (toolName) {
case 'file_operation':
return await this.executeFileOperation(params);
case 'terminal_command':
return await this.executeTerminalCommand(params);
case 'web_search':
return await this.executeWebSearch(params);
case 'code_analysis':
return await this.analyzeCode(params.filePath);
default:
throw new Error(`Unknown tool: ${toolName}`);
}
} catch (error) {
const duration = Date.now() - startTime;
this.logger.error('Tool execution failed', { toolName, params, error: error.message });
return {
success: false,
error: error.message,
duration,
metadata: {
tool: toolName,
operation: 'execute',
timestamp: new Date()
}
};
}
}
}

View File

@@ -0,0 +1,89 @@
import winston from 'winston';
export class Logger {
private logger: winston.Logger;
constructor(service: string) {
this.logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: { service },
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
),
}),
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
}),
new winston.transports.File({
filename: 'logs/combined.log',
}),
],
});
// Create logs directory if it doesn't exist
const fs = require('fs');
const path = require('path');
const logsDir = path.join(process.cwd(), 'logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}
}
info(message: string, meta?: any) {
this.logger.info(message, meta);
}
warn(message: string, meta?: any) {
this.logger.warn(message, meta);
}
error(message: string, meta?: any) {
this.logger.error(message, meta);
}
debug(message: string, meta?: any) {
this.logger.debug(message, meta);
}
verbose(message: string, meta?: any) {
this.logger.verbose(message, meta);
}
// Specialized logging methods for Nowhere
command(command: string, context: any) {
this.info('Command processed', { command, context });
}
voiceCommand(voiceInput: string, processedCommand: string, confidence: number) {
this.info('Voice command processed', {
voiceInput,
processedCommand,
confidence,
});
}
autopilotAction(action: string, context: any) {
this.info('Autopilot action executed', { action, context });
}
memoryOperation(operation: string, context: any) {
this.debug('Memory operation', { operation, context });
}
toolExecution(tool: string, result: any, duration: number) {
this.info('Tool executed', { tool, result, duration });
}
aiResponse(model: string, response: string, confidence: number) {
this.debug('AI response generated', { model, response, confidence });
}
}

View File

@@ -0,0 +1,384 @@
import { Logger } from '../utils/logger';
export interface VoiceCommand {
text: string;
confidence: number;
timestamp: Date;
metadata: {
language: string;
duration: number;
user: string;
};
}
export interface VoiceResponse {
text: string;
audioUrl?: string;
duration: number;
mode: 'brief' | 'detailed' | 'silent' | 'interactive';
}
export interface SpeechRecognitionResult {
transcript: string;
confidence: number;
isFinal: boolean;
language: string;
}
export class VoiceProcessor {
private logger: Logger;
private isListening: boolean = false;
private recognition: any; // Web Speech API recognition
private synthesis: any; // Web Speech API synthesis
constructor() {
this.logger = new Logger('VoiceProcessor');
this.initializeSpeechAPIs();
}
private initializeSpeechAPIs() {
try {
// Initialize Web Speech API if available
if (typeof window !== 'undefined' && 'webkitSpeechRecognition' in window) {
this.recognition = new (window as any).webkitSpeechRecognition();
this.setupRecognition();
}
if (typeof window !== 'undefined' && 'speechSynthesis' in window) {
this.synthesis = window.speechSynthesis;
}
this.logger.info('Voice processor initialized');
} catch (error) {
this.logger.error('Failed to initialize speech APIs', { error });
}
}
private setupRecognition() {
if (!this.recognition) return;
this.recognition.continuous = true;
this.recognition.interimResults = true;
this.recognition.lang = 'en-US';
this.recognition.onstart = () => {
this.isListening = true;
this.logger.info('Speech recognition started');
};
this.recognition.onend = () => {
this.isListening = false;
this.logger.info('Speech recognition ended');
};
this.recognition.onerror = (event: any) => {
this.logger.error('Speech recognition error', { error: event.error });
};
}
async processVoiceInput(audioData?: ArrayBuffer): Promise<VoiceCommand> {
const startTime = Date.now();
try {
// For now, we'll use a mock implementation
// In a real implementation, you would process the audio data
const mockCommand = this.generateMockCommand();
const duration = Date.now() - startTime;
this.logger.voiceCommand(mockCommand.text, mockCommand.text, mockCommand.confidence);
return mockCommand;
} catch (error) {
const duration = Date.now() - startTime;
this.logger.error('Voice processing failed', { error: error.message });
return {
text: 'Error processing voice input',
confidence: 0,
timestamp: new Date(),
metadata: {
language: 'en-US',
duration,
user: 'unknown'
}
};
}
}
private generateMockCommand(): VoiceCommand {
const commands = [
'Hello Nowhere, show me the project structure',
'Nowhere, analyze this code file',
'Create a new component for the user interface',
'Run the tests and show me the results',
'What are the main features we need to implement?',
'Enable autopilot mode',
'Search for files containing authentication logic',
'Generate documentation for the API endpoints'
];
const randomCommand = commands[Math.floor(Math.random() * commands.length)];
const confidence = 0.7 + Math.random() * 0.3; // 70-100% confidence
return {
text: randomCommand,
confidence,
timestamp: new Date(),
metadata: {
language: 'en-US',
duration: 1000 + Math.random() * 2000,
user: 'test-user'
}
};
}
async startListening(): Promise<void> {
try {
if (this.recognition && !this.isListening) {
this.recognition.start();
this.logger.info('Started listening for voice commands');
} else {
this.logger.warn('Speech recognition not available or already listening');
}
} catch (error) {
this.logger.error('Failed to start listening', { error: error.message });
}
}
async stopListening(): Promise<void> {
try {
if (this.recognition && this.isListening) {
this.recognition.stop();
this.logger.info('Stopped listening for voice commands');
}
} catch (error) {
this.logger.error('Failed to stop listening', { error: error.message });
}
}
async speakText(text: string, mode: 'brief' | 'detailed' | 'silent' | 'interactive' = 'brief'): Promise<VoiceResponse> {
const startTime = Date.now();
try {
if (mode === 'silent') {
return {
text,
duration: Date.now() - startTime,
mode
};
}
// Generate appropriate response based on mode
const responseText = this.generateResponseText(text, mode);
// Use Web Speech API for text-to-speech
if (this.synthesis) {
const utterance = new SpeechSynthesisUtterance(responseText);
utterance.rate = mode === 'brief' ? 1.2 : 1.0;
utterance.pitch = 1.0;
utterance.volume = 0.8;
this.synthesis.speak(utterance);
}
const duration = Date.now() - startTime;
this.logger.info('Text-to-speech completed', { text: responseText, mode, duration });
return {
text: responseText,
duration,
mode
};
} catch (error) {
const duration = Date.now() - startTime;
this.logger.error('Text-to-speech failed', { error: error.message });
return {
text: 'Error generating voice response',
duration,
mode
};
}
}
private generateResponseText(originalText: string, mode: string): string {
switch (mode) {
case 'brief':
return this.generateBriefResponse(originalText);
case 'detailed':
return this.generateDetailedResponse(originalText);
case 'interactive':
return this.generateInteractiveResponse(originalText);
default:
return originalText;
}
}
private generateBriefResponse(text: string): string {
// Extract key information for brief response
if (text.includes('project structure')) {
return 'Showing project structure. Found 15 files across 8 directories.';
} else if (text.includes('analyze')) {
return 'Code analysis complete. Found 3 functions, 2 imports, complexity level 2.';
} else if (text.includes('autopilot')) {
return 'Autopilot mode enabled. I will now work autonomously.';
} else if (text.includes('test')) {
return 'Tests completed. 12 passed, 1 failed.';
} else {
return 'Command processed successfully.';
}
}
private generateDetailedResponse(text: string): string {
// Provide detailed response with context
if (text.includes('project structure')) {
return 'Project structure analysis complete. The project contains 15 files organized in 8 directories. Main components include backend API, frontend interface, and database schemas. Key files are in src directory with configuration in root.';
} else if (text.includes('analyze')) {
return 'Detailed code analysis finished. The file contains 3 functions with an average complexity of 2.1. Found 2 external imports and 5 internal dependencies. Code quality score is 8.5 out of 10.';
} else if (text.includes('autopilot')) {
return 'Autopilot mode has been successfully enabled. I will now work independently, making decisions based on project context and user preferences. I will notify you of major actions and ask for confirmation when needed.';
} else if (text.includes('test')) {
return 'Test execution completed. Results: 12 tests passed, 1 test failed in the authentication module. The failing test is related to password validation. I can help fix this issue if needed.';
} else {
return 'Command has been processed with full context analysis. All operations completed successfully with detailed logging available.';
}
}
private generateInteractiveResponse(text: string): string {
// Generate interactive response with questions
if (text.includes('project structure')) {
return 'I found the project structure. Would you like me to focus on any specific directory or file type?';
} else if (text.includes('analyze')) {
return 'Code analysis complete. I found some potential improvements. Should I implement the suggested optimizations?';
} else if (text.includes('autopilot')) {
return 'Autopilot mode is ready. What specific tasks would you like me to prioritize first?';
} else if (text.includes('test')) {
return 'Tests are done. There\'s one failing test. Would you like me to investigate and fix it?';
} else {
return 'Command processed. Is there anything specific you\'d like me to explain or modify?';
}
}
async processVoiceCommand(voiceInput: string): Promise<{
command: string;
confidence: number;
intent: string;
entities: any[];
}> {
try {
// Basic NLP processing for voice commands
const processed = this.parseVoiceCommand(voiceInput);
this.logger.voiceCommand(voiceInput, processed.command, processed.confidence);
return processed;
} catch (error) {
this.logger.error('Voice command processing failed', { error: error.message });
return {
command: voiceInput,
confidence: 0.5,
intent: 'unknown',
entities: []
};
}
}
private parseVoiceCommand(input: string): {
command: string;
confidence: number;
intent: string;
entities: any[];
} {
const lowerInput = input.toLowerCase();
let intent = 'unknown';
const entities: any[] = [];
let confidence = 0.7;
// Intent classification
if (lowerInput.includes('show') || lowerInput.includes('display')) {
intent = 'display';
if (lowerInput.includes('structure') || lowerInput.includes('files')) {
entities.push({ type: 'target', value: 'project_structure' });
}
} else if (lowerInput.includes('analyze') || lowerInput.includes('examine')) {
intent = 'analyze';
if (lowerInput.includes('code') || lowerInput.includes('file')) {
entities.push({ type: 'target', value: 'code_analysis' });
}
} else if (lowerInput.includes('create') || lowerInput.includes('make')) {
intent = 'create';
if (lowerInput.includes('component')) {
entities.push({ type: 'target', value: 'component' });
}
} else if (lowerInput.includes('run') || lowerInput.includes('execute')) {
intent = 'execute';
if (lowerInput.includes('test')) {
entities.push({ type: 'target', value: 'tests' });
}
} else if (lowerInput.includes('autopilot') || lowerInput.includes('auto')) {
intent = 'autopilot';
entities.push({ type: 'mode', value: 'autonomous' });
} else if (lowerInput.includes('search') || lowerInput.includes('find')) {
intent = 'search';
if (lowerInput.includes('file')) {
entities.push({ type: 'target', value: 'files' });
}
}
// Extract file names, paths, or other specific entities
const filePattern = /(\w+\.\w+)/g;
const fileMatches = input.match(filePattern);
if (fileMatches) {
fileMatches.forEach(match => {
entities.push({ type: 'file', value: match });
});
}
// Adjust confidence based on clarity
if (input.length > 10) confidence += 0.1;
if (entities.length > 0) confidence += 0.1;
if (intent !== 'unknown') confidence += 0.1;
return {
command: input,
confidence: Math.min(confidence, 1.0),
intent,
entities
};
}
async getVoiceStatus(): Promise<{
isListening: boolean;
isSpeaking: boolean;
language: string;
available: boolean;
}> {
return {
isListening: this.isListening,
isSpeaking: this.synthesis?.speaking || false,
language: 'en-US',
available: !!(this.recognition && this.synthesis)
};
}
async setLanguage(language: string): Promise<void> {
try {
if (this.recognition) {
this.recognition.lang = language;
this.logger.info('Language set for speech recognition', { language });
}
} catch (error) {
this.logger.error('Failed to set language', { error: error.message, language });
}
}
async setVoiceMode(mode: 'brief' | 'detailed' | 'silent' | 'interactive'): Promise<void> {
try {
// Store voice mode preference
this.logger.info('Voice mode set', { mode });
} catch (error) {
this.logger.error('Failed to set voice mode', { error: error.message, mode });
}
}
}

View File

@@ -0,0 +1,408 @@
import { Server, Socket } from 'socket.io';
import { NowhereCore, NowhereContext } from './core/nowhere';
import { Logger } from './utils/logger';
export interface WebSocketMessage {
type: 'command' | 'voice' | 'autopilot' | 'memory' | 'status' | 'error';
data: any;
timestamp: Date;
userId?: string;
sessionId?: string;
}
export interface WebSocketResponse {
type: 'response' | 'status' | 'error' | 'voice_response';
data: any;
timestamp: Date;
success: boolean;
}
export function setupWebSocket(io: Server, nowhere: NowhereCore) {
const logger = new Logger('WebSocket');
io.on('connection', (socket: Socket) => {
logger.info('Client connected', {
id: socket.id,
address: socket.handshake.address
});
// Handle authentication
socket.on('authenticate', async (data: { token: string }) => {
try {
// In a real implementation, you would verify the JWT token
const userId = 'user-' + Math.random().toString(36).substr(2, 9);
socket.data.userId = userId;
socket.data.authenticated = true;
socket.emit('authenticated', {
success: true,
userId,
message: 'Successfully authenticated with Nowhere'
});
logger.info('Client authenticated', { socketId: socket.id, userId });
} catch (error) {
socket.emit('authenticated', {
success: false,
error: 'Authentication failed'
});
logger.error('Authentication failed', { socketId: socket.id, error });
}
});
// Handle text commands
socket.on('command', async (message: WebSocketMessage) => {
try {
if (!socket.data.authenticated) {
socket.emit('error', {
type: 'authentication_error',
message: 'Please authenticate first'
});
return;
}
const context: NowhereContext = {
userId: socket.data.userId,
sessionId: socket.id,
projectId: message.data.projectId || 'default',
timestamp: new Date(),
metadata: {
source: 'websocket',
clientId: socket.id,
userAgent: socket.handshake.headers['user-agent']
}
};
logger.info('Processing command via WebSocket', {
command: message.data.command,
userId: context.userId,
sessionId: context.sessionId
});
const response = await nowhere.processCommand(
message.data.command,
context,
false
);
socket.emit('response', {
type: 'command_response',
data: response,
timestamp: new Date(),
success: true
});
logger.info('Command processed successfully', {
command: message.data.command,
responseTime: Date.now() - message.timestamp.getTime()
});
} catch (error) {
logger.error('Command processing failed', {
error: error.message,
command: message.data.command
});
socket.emit('error', {
type: 'command_error',
message: 'Failed to process command',
error: error.message
});
}
});
// Handle voice commands
socket.on('voice_command', async (message: WebSocketMessage) => {
try {
if (!socket.data.authenticated) {
socket.emit('error', {
type: 'authentication_error',
message: 'Please authenticate first'
});
return;
}
const context: NowhereContext = {
userId: socket.data.userId,
sessionId: socket.id,
projectId: message.data.projectId || 'default',
timestamp: new Date(),
metadata: {
source: 'websocket_voice',
clientId: socket.id,
audioData: message.data.audioData
}
};
logger.info('Processing voice command via WebSocket', {
userId: context.userId,
sessionId: context.sessionId
});
const response = await nowhere.processVoiceCommand(
message.data.voiceInput,
context
);
socket.emit('voice_response', {
type: 'voice_response',
data: response,
timestamp: new Date(),
success: true
});
logger.info('Voice command processed successfully', {
responseTime: Date.now() - message.timestamp.getTime()
});
} catch (error) {
logger.error('Voice command processing failed', {
error: error.message
});
socket.emit('error', {
type: 'voice_error',
message: 'Failed to process voice command',
error: error.message
});
}
});
// Handle autopilot mode
socket.on('autopilot', async (message: WebSocketMessage) => {
try {
if (!socket.data.authenticated) {
socket.emit('error', {
type: 'authentication_error',
message: 'Please authenticate first'
});
return;
}
const context: NowhereContext = {
userId: socket.data.userId,
sessionId: socket.id,
projectId: message.data.projectId || 'default',
timestamp: new Date(),
metadata: {
source: 'websocket_autopilot',
clientId: socket.id
}
};
if (message.data.action === 'enable') {
await nowhere.enableAutopilotMode(context);
socket.emit('autopilot_status', {
type: 'autopilot_enabled',
data: { enabled: true },
timestamp: new Date(),
success: true
});
logger.info('Autopilot mode enabled', { userId: context.userId });
} else if (message.data.action === 'disable') {
await nowhere.disableAutopilotMode(context);
socket.emit('autopilot_status', {
type: 'autopilot_disabled',
data: { enabled: false },
timestamp: new Date(),
success: true
});
logger.info('Autopilot mode disabled', { userId: context.userId });
}
} catch (error) {
logger.error('Autopilot operation failed', {
error: error.message,
action: message.data.action
});
socket.emit('error', {
type: 'autopilot_error',
message: 'Failed to process autopilot command',
error: error.message
});
}
});
// Handle memory operations
socket.on('memory', async (message: WebSocketMessage) => {
try {
if (!socket.data.authenticated) {
socket.emit('error', {
type: 'authentication_error',
message: 'Please authenticate first'
});
return;
}
const context: NowhereContext = {
userId: socket.data.userId,
sessionId: socket.id,
projectId: message.data.projectId || 'default',
timestamp: new Date(),
metadata: {
source: 'websocket_memory',
clientId: socket.id
}
};
if (message.data.action === 'get') {
const memory = await nowhere.getMemory(context);
socket.emit('memory_response', {
type: 'memory_data',
data: memory,
timestamp: new Date(),
success: true
});
} else if (message.data.action === 'clear') {
await nowhere.clearMemory(context);
socket.emit('memory_response', {
type: 'memory_cleared',
data: { cleared: true },
timestamp: new Date(),
success: true
});
}
} catch (error) {
logger.error('Memory operation failed', {
error: error.message,
action: message.data.action
});
socket.emit('error', {
type: 'memory_error',
message: 'Failed to process memory operation',
error: error.message
});
}
});
// Handle status requests
socket.on('status', async () => {
try {
const status = {
server: 'running',
timestamp: new Date(),
version: '1.0.0',
features: [
'voice_commands',
'autopilot_mode',
'memory_system',
'real_time_communication'
]
};
socket.emit('status_response', {
type: 'status',
data: status,
timestamp: new Date(),
success: true
});
} catch (error) {
logger.error('Status request failed', { error: error.message });
socket.emit('error', {
type: 'status_error',
message: 'Failed to get status',
error: error.message
});
}
});
// Handle voice status
socket.on('voice_status', async () => {
try {
// This would integrate with the VoiceProcessor
const voiceStatus = {
isListening: false,
isSpeaking: false,
language: 'en-US',
available: true
};
socket.emit('voice_status_response', {
type: 'voice_status',
data: voiceStatus,
timestamp: new Date(),
success: true
});
} catch (error) {
logger.error('Voice status request failed', { error: error.message });
socket.emit('error', {
type: 'voice_status_error',
message: 'Failed to get voice status',
error: error.message
});
}
});
// Handle disconnection
socket.on('disconnect', (reason: string) => {
logger.info('Client disconnected', {
socketId: socket.id,
reason,
userId: socket.data.userId
});
// Clean up any ongoing operations for this session
if (socket.data.userId) {
// In a real implementation, you might want to clean up
// any ongoing autopilot operations or memory sessions
}
});
// Handle errors
socket.on('error', (error: any) => {
logger.error('WebSocket error', {
socketId: socket.id,
error: error.message
});
});
// Send welcome message
socket.emit('welcome', {
type: 'welcome',
data: {
message: 'Welcome to Nowhere AI Agent',
version: '1.0.0',
features: [
'Voice Commands',
'Autopilot Mode',
'Real-time Communication',
'Memory System'
]
},
timestamp: new Date(),
success: true
});
});
// Broadcast system messages to all connected clients
function broadcastSystemMessage(message: string, type: string = 'info') {
io.emit('system_message', {
type: 'system',
data: {
message,
type,
timestamp: new Date()
},
timestamp: new Date(),
success: true
});
}
// Handle server shutdown
process.on('SIGTERM', () => {
broadcastSystemMessage('Server is shutting down', 'warning');
io.close();
});
process.on('SIGINT', () => {
broadcastSystemMessage('Server is shutting down', 'warning');
io.close();
});
logger.info('WebSocket server setup complete');
}

View File

@@ -0,0 +1,60 @@
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 3001;
// Middleware
app.use(cors());
app.use(express.json());
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'ok',
message: 'Nowhere AI Agent Backend is running',
timestamp: new Date().toISOString(),
version: '1.0.0'
});
});
// Test endpoint
app.get('/api/v1/status', (req, res) => {
res.json({
success: true,
data: {
server: 'running',
timestamp: new Date(),
version: '1.0.0',
features: [
'voice_commands',
'autopilot_mode',
'memory_system',
'real_time_communication'
]
}
});
});
// Test command endpoint
app.post('/api/v1/command', (req, res) => {
const { command } = req.body;
res.json({
success: true,
data: {
response: `Nowhere processed your command: "${command}"`,
actions: [],
memory: {},
timestamp: new Date()
}
});
});
// Start server
app.listen(PORT, () => {
console.log(`🚀 Nowhere AI Agent Backend running on port ${PORT}`);
console.log(`📊 Health check: http://localhost:${PORT}/health`);
console.log(`🔧 API status: http://localhost:${PORT}/api/v1/status`);
console.log(`💬 Test command: POST http://localhost:${PORT}/api/v1/command`);
});