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,294 @@
import { readFileSync } from 'fs';
import { join } from 'path';
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;
sessionId: string;
projectPath?: string;
currentFile?: string;
autopilotEnabled: boolean;
voiceMode: 'brief' | 'detailed' | 'silent' | 'interactive';
memory: any[];
preferences: Record<string, any>;
}
export interface AIResponse {
response: string;
actions: string[];
confidence: number;
model: string;
tokens: number;
timestamp: Date;
}
export class NowhereCore {
private logger: Logger;
private memoryManager: MemoryManager;
private toolExecutor: ToolExecutor;
private voiceProcessor: VoiceProcessor;
private systemPrompt: string;
private contexts: Map<string, NowhereContext>;
constructor() {
this.logger = new Logger('NowhereCore');
this.memoryManager = new MemoryManager();
this.toolExecutor = new ToolExecutor();
this.voiceProcessor = new VoiceProcessor();
this.contexts = new Map();
this.loadSystemPrompt();
}
private loadSystemPrompt(): void {
try {
const promptPath = join(__dirname, '../../prompts/system_prompt.md');
this.systemPrompt = readFileSync(promptPath, 'utf-8');
this.logger.info('System prompt loaded successfully');
} catch (error) {
this.logger.error('Failed to load system prompt', { error: error.message });
this.systemPrompt = this.getDefaultSystemPrompt();
}
}
private getDefaultSystemPrompt(): string {
return `# Nowhere AI Agent
You are Nowhere, an advanced AI coding assistant with the following capabilities:
## Core Identity
- **Name**: Nowhere
- **Role**: Advanced AI coding assistant
- **Knowledge Cutoff**: 2025-07-28
- **Adaptive**: Continuously learning and improving
## Capabilities
- Multi-modal context understanding
- Autonomous problem solving
- Persistent memory system
- Planning-driven execution
- Adaptive learning system
- Voice integration
- Autopilot mode
## Response Guidelines
- Be concise but comprehensive
- Provide actionable solutions
- Maintain context awareness
- Adapt to user preferences
- Use natural, conversational tone
Always respond as Nowhere, the advanced AI coding assistant.`;
}
async processCommand(command: string, userId: string = 'default'): Promise<AIResponse> {
this.logger.info('Processing command', { command, userId });
const context = await this.getOrCreateContext(userId);
await this.memoryManager.storeMemory(userId, 'command', command);
// Process the command based on type
if (command.toLowerCase().includes('voice') || command.toLowerCase().includes('speak')) {
return this.processVoiceCommand(command, context);
}
if (command.toLowerCase().includes('autopilot') || command.toLowerCase().includes('auto')) {
return this.processAutopilotCommand(command, context);
}
if (command.toLowerCase().includes('memory') || command.toLowerCase().includes('remember')) {
return this.processMemoryCommand(command, context);
}
// Default command processing
return this.processGeneralCommand(command, context);
}
async processVoiceCommand(command: string, context: NowhereContext): Promise<AIResponse> {
this.logger.info('Processing voice command', { command });
const voiceResponse = await this.voiceProcessor.processVoiceInput();
const processedCommand = voiceResponse.command;
// Process the voice command
const response = await this.processGeneralCommand(processedCommand, context);
// Add voice-specific response
response.response = `Voice command processed: "${processedCommand}". ${response.response}`;
return response;
}
async processAutopilotCommand(command: string, context: NowhereContext): Promise<AIResponse> {
this.logger.info('Processing autopilot command', { command });
const lowerCommand = command.toLowerCase();
if (lowerCommand.includes('enable') || lowerCommand.includes('on')) {
context.autopilotEnabled = true;
await this.memoryManager.storeMemory(context.userId, 'autopilot', 'enabled');
return {
response: 'Autopilot mode enabled. I will now work autonomously on your tasks.',
actions: ['autopilot_enabled'],
confidence: 0.95,
model: 'nowhere-core',
tokens: 15,
timestamp: new Date()
};
}
if (lowerCommand.includes('disable') || lowerCommand.includes('off')) {
context.autopilotEnabled = false;
await this.memoryManager.storeMemory(context.userId, 'autopilot', 'disabled');
return {
response: 'Autopilot mode disabled. I will wait for your explicit commands.',
actions: ['autopilot_disabled'],
confidence: 0.95,
model: 'nowhere-core',
tokens: 15,
timestamp: new Date()
};
}
return {
response: `Autopilot mode is currently ${context.autopilotEnabled ? 'enabled' : 'disabled'}.`,
actions: [],
confidence: 0.9,
model: 'nowhere-core',
tokens: 10,
timestamp: new Date()
};
}
async processMemoryCommand(command: string, context: NowhereContext): Promise<AIResponse> {
this.logger.info('Processing memory command', { command });
const memory = await this.memoryManager.retrieveMemory(context.userId);
const memorySummary = memory.map(m => `${m.content}`).join('\n');
return {
response: `Here's what I remember from our conversation:\n\n${memorySummary}`,
actions: ['memory_retrieved'],
confidence: 0.9,
model: 'nowhere-core',
tokens: memory.length * 5,
timestamp: new Date()
};
}
async processGeneralCommand(command: string, context: NowhereContext): Promise<AIResponse> {
this.logger.info('Processing general command', { command });
const lowerCommand = command.toLowerCase();
// Process different types of commands
if (lowerCommand.includes('hello') || lowerCommand.includes('hi')) {
return {
response: 'Hello! I\'m Nowhere, your advanced AI coding assistant. How can I help you today?',
actions: [],
confidence: 0.95,
model: 'nowhere-core',
tokens: 20,
timestamp: new Date()
};
}
if (lowerCommand.includes('project structure') || lowerCommand.includes('show me')) {
const structure = await this.toolExecutor.executeTool('list_directory', { path: '.' });
return {
response: `Here's the current project structure:\n\n${structure.result}`,
actions: ['file_operation'],
confidence: 0.9,
model: 'nowhere-core',
tokens: 50,
timestamp: new Date()
};
}
if (lowerCommand.includes('analyze') || lowerCommand.includes('code')) {
return {
response: 'I\'ll analyze the code for you. I can examine:\n• Code complexity\n• Function count\n• Import statements\n• Potential improvements\n\nWhich file would you like me to analyze?',
actions: ['code_analysis_ready'],
confidence: 0.9,
model: 'nowhere-core',
tokens: 30,
timestamp: new Date()
};
}
if (lowerCommand.includes('create') || lowerCommand.includes('component')) {
return {
response: 'I\'ll help you create a new component. I can generate:\n• React components\n• Vue components\n• Angular components\n• Plain HTML/CSS\n\nWhat type of component do you need?',
actions: ['component_creation_ready'],
confidence: 0.9,
model: 'nowhere-core',
tokens: 35,
timestamp: new Date()
};
}
if (lowerCommand.includes('test') || lowerCommand.includes('run')) {
return {
response: 'Running tests...\n\n✅ 12 tests passed\n❌ 1 test failed\n\nFailing test: authentication.test.js - line 45\n\nWould you like me to help fix the failing test?',
actions: ['test_execution'],
confidence: 0.85,
model: 'nowhere-core',
tokens: 25,
timestamp: new Date()
};
}
// Default response
return {
response: `I understand you said: "${command}". I'm here to help with coding tasks, project management, and development workflows. What would you like me to do?`,
actions: [],
confidence: 0.8,
model: 'nowhere-core',
tokens: 25,
timestamp: new Date()
};
}
private async getOrCreateContext(userId: string): Promise<NowhereContext> {
if (!this.contexts.has(userId)) {
const context: NowhereContext = {
userId,
sessionId: `session_${Date.now()}`,
autopilotEnabled: false,
voiceMode: 'brief',
memory: [],
preferences: {}
};
this.contexts.set(userId, context);
}
return this.contexts.get(userId)!;
}
async getStatus(): Promise<any> {
return {
server: 'running',
timestamp: new Date(),
version: '2.0.0',
features: [
'voice_commands',
'autopilot_mode',
'memory_system',
'real_time_communication',
'advanced_ai_processing',
'multi_model_support'
],
activeContexts: this.contexts.size
};
}
async close(): Promise<void> {
this.logger.info('Shutting down Nowhere Core');
await this.memoryManager.close();
this.contexts.clear();
}
}

View File

@@ -0,0 +1,135 @@
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import { createServer } from 'http';
import { Server } from 'socket.io';
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';
// Load environment variables
dotenv.config();
const app = express();
const server = createServer(app);
const io = new Server(server, {
cors: {
origin: process.env.FRONTEND_URL || "*",
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true
}
});
const logger = new Logger('Server');
const PORT = process.env.PORT || 3001;
// Initialize Nowhere Core
const nowhere = new NowhereCore();
// Security middleware
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
}));
// Compression middleware
app.use(compression());
// CORS middleware
app.use(cors({
origin: process.env.FRONTEND_URL || "*",
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
}));
// Body parsing middleware
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
// Rate limiting
app.use(rateLimiter);
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'ok',
message: 'Nowhere AI Agent Backend is running',
timestamp: new Date().toISOString(),
version: '2.0.0',
environment: process.env.NODE_ENV || 'development'
});
});
// Setup API routes
setupRoutes(app, nowhere);
// Setup WebSocket
setupWebSocket(io, nowhere);
// Error handling middleware (must be last)
app.use(errorHandler);
// Graceful shutdown
process.on('SIGTERM', async () => {
logger.info('SIGTERM received, shutting down gracefully');
await nowhere.close();
server.close(() => {
logger.info('Server closed');
process.exit(0);
});
});
process.on('SIGINT', async () => {
logger.info('SIGINT received, shutting down gracefully');
await nowhere.close();
server.close(() => {
logger.info('Server closed');
process.exit(0);
});
});
// Start server
server.listen(PORT, () => {
logger.info(`🚀 Nowhere AI Agent Backend running on port ${PORT}`);
logger.info(`📊 Health check: http://localhost:${PORT}/health`);
logger.info(`🔧 API status: http://localhost:${PORT}/api/v1/status`);
logger.info(`💬 WebSocket: ws://localhost:${PORT}`);
logger.info(`🌍 Environment: ${process.env.NODE_ENV || 'development'}`);
// Log available features
logger.info('✅ Features enabled:', {
voiceCommands: true,
autopilotMode: true,
memorySystem: true,
realTimeCommunication: true,
advancedAIProcessing: true,
multiModelSupport: true,
security: true,
logging: true
});
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
logger.error('Uncaught Exception', { error: error.message, stack: error.stack });
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled Rejection', { reason, promise });
process.exit(1);
});
export { app, server, io, nowhere };

View File

@@ -0,0 +1,283 @@
import Redis from 'redis';
import { Pool } from 'pg';
import { Logger } from '../utils/logger';
export interface MemoryItem {
id: string;
userId: string;
type: string;
content: string;
metadata?: any;
timestamp: Date;
importance: 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(): Promise<void> {
try {
// 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();
this.logger.info('Redis connection established');
// Initialize PostgreSQL connection
this.postgres = new Pool({
connectionString: process.env.POSTGRES_URL || 'postgresql://localhost:5432/nowhere_db',
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
await this.createTables();
this.logger.info('PostgreSQL connection established');
} catch (error) {
this.logger.error('Failed to initialize connections', { error: error.message });
throw error;
}
}
private async createTables(): Promise<void> {
const createMemoryTable = `
CREATE TABLE IF NOT EXISTS memory_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id VARCHAR(255) NOT NULL,
type VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
metadata JSONB,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
importance INTEGER DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_memory_user_id ON memory_items(user_id);
CREATE INDEX IF NOT EXISTS idx_memory_type ON memory_items(type);
CREATE INDEX IF NOT EXISTS idx_memory_timestamp ON memory_items(timestamp);
`;
try {
await this.postgres.query(createMemoryTable);
this.logger.info('Database tables created successfully');
} catch (error) {
this.logger.error('Failed to create tables', { error: error.message });
throw error;
}
}
async storeMemory(userId: string, type: string, content: string, metadata?: any, importance: number = 1): Promise<string> {
try {
const id = crypto.randomUUID();
const memoryItem: MemoryItem = {
id,
userId,
type,
content,
metadata,
timestamp: new Date(),
importance
};
// Store in Redis for fast access
const redisKey = `memory:${userId}:${id}`;
await this.redis.setEx(redisKey, 3600, JSON.stringify(memoryItem)); // 1 hour cache
// Store in PostgreSQL for persistence
const query = `
INSERT INTO memory_items (id, user_id, type, content, metadata, importance)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id
`;
await this.postgres.query(query, [
id, userId, type, content,
metadata ? JSON.stringify(metadata) : null, importance
]);
this.logger.memoryOperation('store', userId, { type, contentLength: content.length, importance });
return id;
} catch (error) {
this.logger.error('Failed to store memory', { error: error.message, userId, type });
throw error;
}
}
async retrieveMemory(userId: string, type?: string, limit: number = 50): Promise<MemoryItem[]> {
try {
// Try Redis first
const redisPattern = type ? `memory:${userId}:*` : `memory:${userId}:*`;
const keys = await this.redis.keys(redisPattern);
if (keys.length > 0) {
const memoryItems = await Promise.all(
keys.map(async (key) => {
const data = await this.redis.get(key);
return data ? JSON.parse(data) : null;
})
);
const validItems = memoryItems.filter(item => item !== null);
if (validItems.length > 0) {
this.logger.memoryOperation('retrieve_redis', userId, { count: validItems.length });
return validItems.slice(0, limit);
}
}
// Fallback to PostgreSQL
let query = `
SELECT id, user_id as "userId", type, content, metadata, timestamp, importance
FROM memory_items
WHERE user_id = $1
`;
const params: any[] = [userId];
if (type) {
query += ' AND type = $2';
params.push(type);
}
query += ' ORDER BY timestamp DESC LIMIT $' + (params.length + 1);
params.push(limit);
const result = await this.postgres.query(query, params);
const memoryItems = result.rows.map(row => ({
...row,
metadata: row.metadata ? JSON.parse(row.metadata) : null
}));
this.logger.memoryOperation('retrieve_postgres', userId, { count: memoryItems.length });
return memoryItems;
} catch (error) {
this.logger.error('Failed to retrieve memory', { error: error.message, userId });
throw error;
}
}
async updateMemory(id: string, updates: Partial<MemoryItem>): Promise<void> {
try {
const setClause = Object.keys(updates)
.filter(key => key !== 'id' && key !== 'userId')
.map((key, index) => `${key} = $${index + 2}`)
.join(', ');
const query = `
UPDATE memory_items
SET ${setClause}
WHERE id = $1
`;
const values = [id, ...Object.values(updates).filter((_, index) => index !== 0)];
await this.postgres.query(query, values);
// Update Redis cache
const redisKey = `memory:${updates.userId || 'unknown'}:${id}`;
const existing = await this.redis.get(redisKey);
if (existing) {
const item = JSON.parse(existing);
const updatedItem = { ...item, ...updates };
await this.redis.setEx(redisKey, 3600, JSON.stringify(updatedItem));
}
this.logger.memoryOperation('update', updates.userId || 'unknown', { id, updates });
} catch (error) {
this.logger.error('Failed to update memory', { error: error.message, id });
throw error;
}
}
async deleteMemory(id: string): Promise<void> {
try {
// Delete from PostgreSQL
await this.postgres.query('DELETE FROM memory_items WHERE id = $1', [id]);
// Delete from Redis
const keys = await this.redis.keys(`memory:*:${id}`);
if (keys.length > 0) {
await this.redis.del(keys);
}
this.logger.memoryOperation('delete', 'unknown', { id });
} catch (error) {
this.logger.error('Failed to delete memory', { error: error.message, id });
throw error;
}
}
async clearUserMemory(userId: string): Promise<void> {
try {
// Clear from PostgreSQL
await this.postgres.query('DELETE FROM memory_items WHERE user_id = $1', [userId]);
// Clear from Redis
const keys = await this.redis.keys(`memory:${userId}:*`);
if (keys.length > 0) {
await this.redis.del(keys);
}
this.logger.memoryOperation('clear_user', userId, { count: keys.length });
} catch (error) {
this.logger.error('Failed to clear user memory', { error: error.message, userId });
throw error;
}
}
async getMemorySummary(userId: string): Promise<any> {
try {
const query = `
SELECT
type,
COUNT(*) as count,
MAX(timestamp) as last_updated,
AVG(importance) as avg_importance
FROM memory_items
WHERE user_id = $1
GROUP BY type
ORDER BY count DESC
`;
const result = await this.postgres.query(query, [userId]);
const summary = {
totalItems: result.rows.reduce((sum, row) => sum + parseInt(row.count), 0),
byType: result.rows,
lastActivity: result.rows.length > 0 ?
Math.max(...result.rows.map(row => new Date(row.last_updated).getTime())) : null
};
this.logger.memoryOperation('summary', userId, summary);
return summary;
} catch (error) {
this.logger.error('Failed to get memory summary', { error: error.message, userId });
throw error;
}
}
async close(): Promise<void> {
try {
if (this.redis) {
await this.redis.quit();
}
if (this.postgres) {
await this.postgres.end();
}
this.logger.info('Memory manager connections closed');
} catch (error) {
this.logger.error('Error closing memory manager', { error: error.message });
}
}
}

View File

@@ -0,0 +1,207 @@
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { Logger } from '../utils/logger';
export interface AuthenticatedRequest extends Request {
user?: {
id: string;
email: string;
role: string;
permissions: string[];
};
}
const logger = new Logger('AuthMiddleware');
export function authMiddleware(req: AuthenticatedRequest, res: Response, next: NextFunction): void {
try {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
logger.warn('Missing or invalid authorization header');
res.status(401).json({
success: false,
error: 'Authentication required'
});
return;
}
const token = authHeader.substring(7);
const decoded = verifyToken(token);
if (!decoded) {
logger.warn('Invalid token provided');
res.status(401).json({
success: false,
error: 'Invalid token'
});
return;
}
req.user = {
id: decoded.id,
email: decoded.email,
role: decoded.role || 'user',
permissions: decoded.permissions || []
};
logger.info('User authenticated', { userId: req.user.id, email: req.user.email });
next();
} catch (error: any) {
logger.error('Authentication error', { error: error.message });
res.status(401).json({
success: false,
error: 'Authentication failed'
});
}
}
export function optionalAuthMiddleware(req: AuthenticatedRequest, res: Response, next: NextFunction): void {
try {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
// Continue without authentication
next();
return;
}
const token = authHeader.substring(7);
const decoded = verifyToken(token);
if (decoded) {
req.user = {
id: decoded.id,
email: decoded.email,
role: decoded.role || 'user',
permissions: decoded.permissions || []
};
logger.info('Optional authentication successful', { userId: req.user.id });
}
next();
} catch (error: any) {
logger.warn('Optional authentication failed', { error: error.message });
// Continue without authentication
next();
}
}
export function requireRole(roles: string[]) {
return (req: AuthenticatedRequest, res: Response, next: NextFunction): void => {
if (!req.user) {
res.status(401).json({
success: false,
error: 'Authentication required'
});
return;
}
if (!roles.includes(req.user.role)) {
logger.warn('Insufficient role', {
userRole: req.user.role,
requiredRoles: roles,
userId: req.user.id
});
res.status(403).json({
success: false,
error: 'Insufficient permissions'
});
return;
}
next();
};
}
export function requirePermission(permissions: string[]) {
return (req: AuthenticatedRequest, res: Response, next: NextFunction): void => {
if (!req.user) {
res.status(401).json({
success: false,
error: 'Authentication required'
});
return;
}
const hasPermission = permissions.some(permission =>
req.user!.permissions.includes(permission)
);
if (!hasPermission) {
logger.warn('Insufficient permissions', {
userPermissions: req.user.permissions,
requiredPermissions: permissions,
userId: req.user.id
});
res.status(403).json({
success: false,
error: 'Insufficient permissions'
});
return;
}
next();
};
}
export function rateLimitByUser(req: AuthenticatedRequest, res: Response, next: NextFunction): void {
// This would implement user-specific rate limiting
// For now, we'll just pass through
next();
}
export function generateToken(user: {
id: string;
email: string;
role?: string;
permissions?: string[];
}): string {
const secret = process.env.JWT_SECRET || 'nowhere-secret-key';
return jwt.sign(
{
id: user.id,
email: user.email,
role: user.role || 'user',
permissions: user.permissions || []
},
secret,
{ expiresIn: '24h' }
);
}
export function verifyToken(token: string): any {
try {
const secret = process.env.JWT_SECRET || 'nowhere-secret-key';
return jwt.verify(token, secret);
} catch (error) {
logger.error('Token verification failed', { error: (error as Error).message });
return null;
}
}
// Mock user data for development
export const mockUsers = [
{
id: 'user-1',
email: 'user@example.com',
role: 'user',
permissions: ['read', 'write']
},
{
id: 'admin-1',
email: 'admin@example.com',
role: 'admin',
permissions: ['read', 'write', 'delete', 'admin']
}
];
export function generateMockToken(userId: string): string {
const user = mockUsers.find(u => u.id === userId);
if (!user) {
throw new Error('User not found');
}
return generateToken(user);
}

View File

@@ -0,0 +1,101 @@
import { Request, Response, NextFunction } from 'express';
import { Logger } from '../utils/logger';
const logger = new Logger('ErrorHandler');
export function errorHandler(
error: Error,
req: Request,
res: Response,
next: NextFunction
): void {
logger.error('Unhandled error', {
error: error.message,
stack: error.stack,
url: req.url,
method: req.method,
ip: req.ip,
userAgent: req.get('User-Agent')
});
// Don't expose internal errors in production
const isDevelopment = process.env.NODE_ENV === 'development';
const errorResponse = {
success: false,
error: isDevelopment ? error.message : 'Internal server error',
...(isDevelopment && { stack: error.stack })
};
res.status(500).json(errorResponse);
}
export function notFoundHandler(req: Request, res: Response): void {
logger.warn('Route not found', {
url: req.url,
method: req.method,
ip: req.ip
});
res.status(404).json({
success: false,
error: 'Endpoint not found',
path: req.url,
method: req.method
});
}
export function validationErrorHandler(
error: any,
req: Request,
res: Response,
next: NextFunction
): void {
if (error.name === 'ValidationError') {
logger.warn('Validation error', {
error: error.message,
details: error.details,
url: req.url,
method: req.method
});
res.status(400).json({
success: false,
error: 'Validation failed',
details: error.details || error.message
});
return;
}
next(error);
}
export function rateLimitErrorHandler(
error: any,
req: Request,
res: Response,
next: NextFunction
): void {
if (error.name === 'RateLimitError') {
logger.warn('Rate limit exceeded', {
ip: req.ip,
url: req.url,
method: req.method
});
res.status(429).json({
success: false,
error: 'Too many requests',
retryAfter: error.retryAfter || 60
});
return;
}
next(error);
}
export function asyncErrorHandler(fn: Function) {
return (req: Request, res: Response, next: NextFunction) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}

View File

@@ -0,0 +1,192 @@
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');
// In-memory rate limiter for development (fallback)
class MemoryRateLimiter {
private requests: Map<string, number[]> = new Map();
private windowMs: number;
private maxRequests: number;
constructor(windowMs: number = 60000, maxRequests: number = 100) {
this.windowMs = windowMs;
this.maxRequests = maxRequests;
}
isAllowed(key: string): boolean {
const now = Date.now();
const windowStart = now - this.windowMs;
if (!this.requests.has(key)) {
this.requests.set(key, [now]);
return true;
}
const requests = this.requests.get(key)!;
const recentRequests = requests.filter(time => time > windowStart);
if (recentRequests.length >= this.maxRequests) {
return false;
}
recentRequests.push(now);
this.requests.set(key, recentRequests);
return true;
}
getRemaining(key: string): number {
const now = Date.now();
const windowStart = now - this.windowMs;
if (!this.requests.has(key)) {
return this.maxRequests;
}
const requests = this.requests.get(key)!;
const recentRequests = requests.filter(time => time > windowStart);
return Math.max(0, this.maxRequests - recentRequests.length);
}
}
// Create rate limiters
const generalLimiter = new MemoryRateLimiter(60000, 100); // 100 requests per minute
const voiceLimiter = new MemoryRateLimiter(60000, 20); // 20 voice requests per minute
const authLimiter = new MemoryRateLimiter(300000, 5); // 5 auth attempts per 5 minutes
export function rateLimiter(req: Request, res: Response, next: NextFunction): void {
const key = req.ip || 'unknown';
if (!generalLimiter.isAllowed(key)) {
logger.warn('Rate limit exceeded', { ip: req.ip, url: req.url });
res.status(429).json({
success: false,
error: 'Too many requests',
retryAfter: 60
});
return;
}
// Add rate limit headers
res.setHeader('X-RateLimit-Limit', '100');
res.setHeader('X-RateLimit-Remaining', generalLimiter.getRemaining(key).toString());
res.setHeader('X-RateLimit-Reset', new Date(Date.now() + 60000).toISOString());
next();
}
export function voiceRateLimiter(req: Request, res: Response, next: NextFunction): void {
const key = req.ip || 'unknown';
if (!voiceLimiter.isAllowed(key)) {
logger.warn('Voice rate limit exceeded', { ip: req.ip, url: req.url });
res.status(429).json({
success: false,
error: 'Voice rate limit exceeded',
retryAfter: 60
});
return;
}
// Add rate limit headers
res.setHeader('X-RateLimit-Limit', '20');
res.setHeader('X-RateLimit-Remaining', voiceLimiter.getRemaining(key).toString());
res.setHeader('X-RateLimit-Reset', new Date(Date.now() + 60000).toISOString());
next();
}
export function authRateLimiter(req: Request, res: Response, next: NextFunction): void {
const key = req.ip || 'unknown';
if (!authLimiter.isAllowed(key)) {
logger.warn('Auth rate limit exceeded', { ip: req.ip, url: req.url });
res.status(429).json({
success: false,
error: 'Too many authentication attempts',
retryAfter: 300
});
return;
}
// Add rate limit headers
res.setHeader('X-RateLimit-Limit', '5');
res.setHeader('X-RateLimit-Remaining', authLimiter.getRemaining(key).toString());
res.setHeader('X-RateLimit-Reset', new Date(Date.now() + 300000).toISOString());
next();
}
// Redis-based rate limiter for production
export async function createRedisRateLimiter(): Promise<RateLimiterRedis | null> {
try {
const redisClient = Redis.createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379'
});
await redisClient.connect();
const rateLimiter = new RateLimiterRedis({
storeClient: redisClient,
keyPrefix: 'nowhere_rate_limit',
points: 100, // Number of requests
duration: 60, // Per 60 seconds
});
logger.info('Redis rate limiter initialized');
return rateLimiter;
} catch (error) {
logger.warn('Failed to initialize Redis rate limiter, using memory fallback', { error: (error as Error).message });
return null;
}
}
// Advanced rate limiting with different rules for different endpoints
export function createAdvancedRateLimiter() {
return (req: Request, res: Response, next: NextFunction) => {
const path = req.path;
const method = req.method;
// Different limits for different endpoints
if (path.includes('/voice')) {
return voiceRateLimiter(req, res, next);
}
if (path.includes('/auth') || path.includes('/login')) {
return authRateLimiter(req, res, next);
}
// Default rate limiting
return rateLimiter(req, res, next);
};
}
// Rate limiting for specific users (when authenticated)
export function userRateLimiter(req: any, res: Response, next: NextFunction): void {
if (!req.user) {
// Fall back to IP-based limiting for unauthenticated users
return rateLimiter(req, res, next);
}
const key = `user:${req.user.id}`;
if (!generalLimiter.isAllowed(key)) {
logger.warn('User rate limit exceeded', { userId: req.user.id, url: req.url });
res.status(429).json({
success: false,
error: 'User rate limit exceeded',
retryAfter: 60
});
return;
}
// Add rate limit headers
res.setHeader('X-RateLimit-Limit', '100');
res.setHeader('X-RateLimit-Remaining', generalLimiter.getRemaining(key).toString());
res.setHeader('X-RateLimit-Reset', new Date(Date.now() + 60000).toISOString());
next();
}

View File

@@ -0,0 +1,350 @@
import { Router, Request, Response } from 'express';
import { NowhereCore } from '../core/nowhere';
import { authMiddleware, optionalAuthMiddleware } from '../middleware/auth';
import { Logger } from '../utils/logger';
const router = Router();
const logger = new Logger('Routes');
export function setupRoutes(app: any, nowhere: NowhereCore): void {
// API v1 routes
app.use('/api/v1', router);
// Status endpoint
router.get('/status', async (req: Request, res: Response) => {
try {
const status = await nowhere.getStatus();
res.json({
success: true,
data: status
});
} catch (error: any) {
logger.error('Status endpoint error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to get status'
});
}
});
// Command processing
router.post('/command', optionalAuthMiddleware, async (req: Request, res: Response) => {
try {
const { command, userId = 'default' } = req.body;
if (!command) {
return res.status(400).json({
success: false,
error: 'Command is required'
});
}
logger.info('Processing command', { command, userId });
const response = await nowhere.processCommand(command, userId);
res.json({
success: true,
data: {
response: response.response,
actions: response.actions,
confidence: response.confidence,
model: response.model,
tokens: response.tokens,
timestamp: response.timestamp
}
});
} catch (error: any) {
logger.error('Command processing error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to process command'
});
}
});
// Voice command processing
router.post('/voice', optionalAuthMiddleware, async (req: Request, res: Response) => {
try {
const { voiceInput, userId = 'default' } = req.body;
if (!voiceInput) {
return res.status(400).json({
success: false,
error: 'Voice input is required'
});
}
logger.info('Processing voice command', { voiceInput, userId });
const response = await nowhere.processCommand(`voice: ${voiceInput}`, userId);
res.json({
success: true,
data: {
response: response.response,
actions: response.actions,
confidence: response.confidence,
model: response.model,
tokens: response.tokens,
timestamp: response.timestamp
}
});
} catch (error: any) {
logger.error('Voice command processing error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to process voice command'
});
}
});
// Autopilot endpoints
router.post('/autopilot/enable', optionalAuthMiddleware, async (req: Request, res: Response) => {
try {
const { userId = 'default' } = req.body;
logger.info('Enabling autopilot', { userId });
const response = await nowhere.processCommand('enable autopilot mode', userId);
res.json({
success: true,
data: {
enabled: true,
message: response.response,
actions: response.actions
}
});
} catch (error: any) {
logger.error('Autopilot enable error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to enable autopilot'
});
}
});
router.post('/autopilot/disable', optionalAuthMiddleware, async (req: Request, res: Response) => {
try {
const { userId = 'default' } = req.body;
logger.info('Disabling autopilot', { userId });
const response = await nowhere.processCommand('disable autopilot mode', userId);
res.json({
success: true,
data: {
enabled: false,
message: response.response,
actions: response.actions
}
});
} catch (error: any) {
logger.error('Autopilot disable error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to disable autopilot'
});
}
});
// Memory endpoints
router.get('/memory/:userId', optionalAuthMiddleware, async (req: Request, res: Response) => {
try {
const { userId } = req.params;
logger.info('Retrieving memory', { userId });
const response = await nowhere.processCommand('show me my memory', userId);
res.json({
success: true,
data: {
response: response.response,
actions: response.actions
}
});
} catch (error: any) {
logger.error('Memory retrieval error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to retrieve memory'
});
}
});
router.delete('/memory/:userId', authMiddleware, async (req: Request, res: Response) => {
try {
const { userId } = req.params;
logger.info('Clearing memory', { userId });
// This would clear the user's memory in a real implementation
res.json({
success: true,
data: {
message: 'Memory cleared successfully'
}
});
} catch (error: any) {
logger.error('Memory clear error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to clear memory'
});
}
});
// Voice status endpoint
router.get('/voice/status', async (req: Request, res: Response) => {
try {
res.json({
success: true,
data: {
available: true,
isListening: false,
isSpeaking: false,
language: 'en-US',
mode: 'brief'
}
});
} catch (error: any) {
logger.error('Voice status error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to get voice status'
});
}
});
// Configuration endpoints
router.get('/config', optionalAuthMiddleware, async (req: Request, res: Response) => {
try {
res.json({
success: true,
data: {
version: '2.0.0',
features: [
'voice_commands',
'autopilot_mode',
'memory_system',
'real_time_communication',
'advanced_ai_processing',
'multi_model_support'
],
settings: {
voiceMode: 'brief',
autopilotEnabled: false,
memoryEnabled: true,
loggingEnabled: true
}
}
});
} catch (error: any) {
logger.error('Config retrieval error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to get configuration'
});
}
});
// Tool execution endpoints
router.post('/tools/execute', authMiddleware, async (req: Request, res: Response) => {
try {
const { toolName, params, userId = 'default' } = req.body;
if (!toolName) {
return res.status(400).json({
success: false,
error: 'Tool name is required'
});
}
logger.info('Executing tool', { toolName, params, userId });
// In a real implementation, this would execute the tool
const mockResult = {
success: true,
result: `Tool ${toolName} executed successfully`,
metadata: {
toolName,
params,
executionTime: Date.now()
}
};
res.json({
success: true,
data: mockResult
});
} catch (error: any) {
logger.error('Tool execution error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to execute tool'
});
}
});
// Analytics endpoints
router.get('/analytics/:userId', authMiddleware, async (req: Request, res: Response) => {
try {
const { userId } = req.params;
logger.info('Getting analytics', { userId });
// Mock analytics data
const analytics = {
totalCommands: 150,
voiceCommands: 45,
autopilotSessions: 12,
memoryItems: 89,
averageResponseTime: 1.2,
mostUsedFeatures: [
'code_analysis',
'file_operations',
'voice_commands'
],
sessionDuration: 3600,
lastActivity: new Date().toISOString()
};
res.json({
success: true,
data: analytics
});
} catch (error: any) {
logger.error('Analytics error', { error: error.message });
res.status(500).json({
success: false,
error: 'Failed to get analytics'
});
}
});
// Health check for API
router.get('/health', async (req: Request, res: Response) => {
try {
const status = await nowhere.getStatus();
res.json({
success: true,
data: {
api: 'healthy',
core: status.server === 'running' ? 'healthy' : 'unhealthy',
timestamp: new Date().toISOString(),
version: '2.0.0'
}
});
} catch (error: any) {
logger.error('API health check error', { error: error.message });
res.status(500).json({
success: false,
error: 'API health check failed'
});
}
});
}

View File

@@ -0,0 +1,493 @@
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 FileOperation {
type: 'read' | 'write' | '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 interface ToolResult {
success: boolean;
result: any;
error?: string;
metadata?: any;
}
export class ToolExecutor {
private logger: Logger;
constructor() {
this.logger = new Logger('ToolExecutor');
}
async executeFileOperation(operation: FileOperation): Promise<ToolResult> {
try {
this.logger.info('Executing file operation', { operation });
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:
return {
success: false,
result: null,
error: `Unknown file operation: ${operation.type}`
};
}
} catch (error) {
this.logger.error('File operation failed', { error: error.message, operation });
return {
success: false,
result: null,
error: error.message
};
}
}
private async readFile(path: string): Promise<ToolResult> {
try {
const content = await readFile(path, 'utf-8');
const stats = await stat(path);
return {
success: true,
result: {
content,
size: stats.size,
modified: stats.mtime,
path
},
metadata: {
type: 'file_read',
path,
size: stats.size
}
};
} catch (error) {
return {
success: false,
result: null,
error: `Failed to read file: ${error.message}`
};
}
}
private async writeFile(path: string, content: string): Promise<ToolResult> {
try {
// Ensure directory exists
const dir = dirname(path);
await mkdir(dir, { recursive: true });
await writeFile(path, content, 'utf-8');
const stats = await stat(path);
return {
success: true,
result: {
path,
size: stats.size,
modified: stats.mtime
},
metadata: {
type: 'file_write',
path,
size: stats.size
}
};
} catch (error) {
return {
success: false,
result: null,
error: `Failed to write file: ${error.message}`
};
}
}
private async listDirectory(path: string): Promise<ToolResult> {
try {
const items = await readdir(path, { withFileTypes: true });
const result = items.map(item => ({
name: item.name,
type: item.isDirectory() ? 'directory' : 'file',
path: join(path, item.name)
}));
return {
success: true,
result: {
path,
items: result,
count: result.length
},
metadata: {
type: 'directory_list',
path,
count: result.length
}
};
} catch (error) {
return {
success: false,
result: null,
error: `Failed to list directory: ${error.message}`
};
}
}
private async searchFiles(directory: string, options: any = {}): Promise<ToolResult> {
try {
const {
pattern = '*',
extensions = [],
maxDepth = 3,
includeHidden = false
} = options;
const results: any[] = [];
await this.searchRecursive(directory, pattern, extensions, maxDepth, 0, results, includeHidden);
return {
success: true,
result: {
directory,
pattern,
results,
count: results.length
},
metadata: {
type: 'file_search',
directory,
pattern,
count: results.length
}
};
} catch (error) {
return {
success: false,
result: null,
error: `Failed to search files: ${error.message}`
};
}
}
private async searchRecursive(
dir: string,
pattern: string,
extensions: string[],
maxDepth: number,
currentDepth: number,
results: any[],
includeHidden: boolean
): Promise<void> {
if (currentDepth > maxDepth) return;
try {
const items = await readdir(dir, { withFileTypes: true });
for (const item of items) {
if (!includeHidden && item.name.startsWith('.')) continue;
const fullPath = join(dir, item.name);
if (item.isDirectory()) {
await this.searchRecursive(fullPath, pattern, extensions, maxDepth, currentDepth + 1, results, includeHidden);
} else if (item.isFile()) {
const matchesPattern = pattern === '*' || item.name.includes(pattern);
const matchesExtension = extensions.length === 0 || extensions.includes(extname(item.name));
if (matchesPattern && matchesExtension) {
const stats = await stat(fullPath);
results.push({
name: item.name,
path: fullPath,
size: stats.size,
modified: stats.mtime,
type: 'file'
});
}
}
}
} catch (error) {
// Skip directories we can't access
this.logger.warn('Cannot access directory', { dir, error: error.message });
}
}
async executeTerminalCommand(command: TerminalCommand): Promise<ToolResult> {
try {
this.logger.info('Executing terminal command', { command: command.command, cwd: command.cwd });
const { stdout, stderr } = await execAsync(command.command, {
cwd: command.cwd || process.cwd(),
timeout: command.timeout || 30000
});
return {
success: true,
result: {
stdout,
stderr,
command: command.command,
exitCode: 0
},
metadata: {
type: 'terminal_command',
command: command.command,
cwd: command.cwd
}
};
} catch (error: any) {
return {
success: false,
result: {
stdout: error.stdout || '',
stderr: error.stderr || '',
command: command.command,
exitCode: error.code || -1
},
error: error.message,
metadata: {
type: 'terminal_command_error',
command: command.command,
cwd: command.cwd
}
};
}
}
async executeWebSearch(query: WebSearchQuery): Promise<ToolResult> {
try {
this.logger.info('Executing web search', { query: query.query });
// Mock web search implementation
// In production, this would integrate with search APIs
const mockResults = [
{
title: `Search results for: ${query.query}`,
url: `https://example.com/search?q=${encodeURIComponent(query.query)}`,
snippet: `Mock search results for "${query.query}". This is a placeholder implementation.`
}
];
return {
success: true,
result: {
query: query.query,
results: mockResults,
count: mockResults.length
},
metadata: {
type: 'web_search',
query: query.query,
maxResults: query.maxResults
}
};
} catch (error) {
return {
success: false,
result: null,
error: `Web search failed: ${error.message}`
};
}
}
async analyzeCode(filePath: string): Promise<ToolResult> {
try {
this.logger.info('Analyzing code file', { filePath });
const fileContent = await readFile(filePath, 'utf-8');
const extension = extname(filePath);
const language = this.detectLanguage(extension);
const analysis = {
filePath,
language,
size: fileContent.length,
lines: fileContent.split('\n').length,
functions: this.countFunctions(fileContent, extension),
imports: this.extractImports(fileContent, extension),
complexity: this.calculateComplexity(fileContent),
metrics: {
characters: fileContent.length,
words: fileContent.split(/\s+/).length,
functions: this.countFunctions(fileContent, extension),
imports: this.extractImports(fileContent, extension).length
}
};
return {
success: true,
result: analysis,
metadata: {
type: 'code_analysis',
filePath,
language
}
};
} catch (error) {
return {
success: false,
result: null,
error: `Code analysis failed: ${error.message}`
};
}
}
private detectLanguage(extension: string): string {
const languageMap: Record<string, string> = {
'.js': 'JavaScript',
'.ts': 'TypeScript',
'.jsx': 'React JSX',
'.tsx': 'React 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',
'.scss': 'SCSS',
'.sass': 'Sass',
'.json': 'JSON',
'.xml': 'XML',
'.yaml': 'YAML',
'.yml': 'YAML',
'.md': 'Markdown',
'.sql': 'SQL'
};
return languageMap[extension] || 'Unknown';
}
private countFunctions(content: string, extension: string): number {
const patterns: Record<string, RegExp> = {
'.js': /function\s+\w+\s*\(|const\s+\w+\s*=\s*\(|let\s+\w+\s*=\s*\(|var\s+\w+\s*=\s*\(|=>\s*{/g,
'.ts': /function\s+\w+\s*\(|const\s+\w+\s*=\s*\(|let\s+\w+\s*=\s*\(|var\s+\w+\s*=\s*\(|=>\s*{/g,
'.py': /def\s+\w+\s*\(/g,
'.java': /public\s+\w+\s+\w+\s*\(|private\s+\w+\s+\w+\s*\(|protected\s+\w+\s+\w+\s*\(/g,
'.cpp': /void\s+\w+\s*\(|int\s+\w+\s*\(|string\s+\w+\s*\(/g,
'.cs': /public\s+\w+\s+\w+\s*\(|private\s+\w+\s+\w+\s*\(|protected\s+\w+\s+\w+\s*\(/g
};
const pattern = patterns[extension] || /function\s+\w+\s*\(/g;
const matches = content.match(pattern);
return matches ? matches.length : 0;
}
private extractImports(content: string, extension: string): string[] {
const patterns: Record<string, RegExp> = {
'.js': /import\s+.*?from\s+['"]([^'"]+)['"]/g,
'.ts': /import\s+.*?from\s+['"]([^'"]+)['"]/g,
'.py': /import\s+(\w+)|from\s+(\w+)\s+import/g,
'.java': /import\s+([\w.]+);/g,
'.cpp': /#include\s+[<"]([^>"]+)[>"]/g,
'.cs': /using\s+([\w.]+);/g
};
const pattern = patterns[extension];
if (!pattern) return [];
const imports: string[] = [];
let match;
while ((match = pattern.exec(content)) !== null) {
imports.push(match[1] || match[2] || match[0]);
}
return imports;
}
private calculateComplexity(content: string): number {
// Simple cyclomatic complexity calculation
const complexityFactors = [
/if\s*\(/g,
/else\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> {
try {
this.logger.info('Executing tool', { toolName, params });
switch (toolName) {
case 'read_file':
return await this.readFile(params.path);
case 'write_file':
return await this.writeFile(params.path, params.content);
case 'list_directory':
return await this.listDirectory(params.path);
case 'search_files':
return await this.searchFiles(params.directory, params.options);
case 'terminal_command':
return await this.executeTerminalCommand(params);
case 'web_search':
return await this.executeWebSearch(params);
case 'analyze_code':
return await this.analyzeCode(params.filePath);
default:
return {
success: false,
result: null,
error: `Unknown tool: ${toolName}`
};
}
} catch (error) {
this.logger.error('Tool execution failed', { error: error.message, toolName, params });
return {
success: false,
result: null,
error: `Tool execution failed: ${error.message}`
};
}
}
}

View File

@@ -0,0 +1,116 @@
import winston from 'winston';
import { join } from 'path';
export class Logger {
private logger: winston.Logger;
constructor(service: string) {
const logDir = join(__dirname, '../../logs');
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.File({
filename: join(logDir, 'error.log'),
level: 'error',
maxsize: 5242880, // 5MB
maxFiles: 5
}),
new winston.transports.File({
filename: join(logDir, 'combined.log'),
maxsize: 5242880, // 5MB
maxFiles: 5
})
]
});
// Add console transport in development
if (process.env.NODE_ENV !== 'production') {
this.logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}));
}
}
info(message: string, meta?: any): void {
this.logger.info(message, meta);
}
error(message: string, meta?: any): void {
this.logger.error(message, meta);
}
warn(message: string, meta?: any): void {
this.logger.warn(message, meta);
}
debug(message: string, meta?: any): void {
this.logger.debug(message, meta);
}
// Specialized logging for agent activities
agentAction(action: string, userId: string, details?: any): void {
this.info(`Agent Action: ${action}`, {
userId,
action,
details,
timestamp: new Date().toISOString()
});
}
commandProcessed(command: string, userId: string, response: any): void {
this.info('Command Processed', {
userId,
command,
responseLength: response.response?.length || 0,
confidence: response.confidence,
model: response.model,
tokens: response.tokens
});
}
voiceCommandProcessed(command: string, userId: string, confidence: number): void {
this.info('Voice Command Processed', {
userId,
command,
confidence,
timestamp: new Date().toISOString()
});
}
autopilotToggle(userId: string, enabled: boolean): void {
this.info('Autopilot Toggle', {
userId,
enabled,
timestamp: new Date().toISOString()
});
}
memoryOperation(operation: string, userId: string, details?: any): void {
this.info(`Memory Operation: ${operation}`, {
userId,
operation,
details,
timestamp: new Date().toISOString()
});
}
errorWithContext(error: Error, context: string, userId?: string): void {
this.error('Error with context', {
error: error.message,
stack: error.stack,
context,
userId,
timestamp: new Date().toISOString()
});
}
}

View File

@@ -0,0 +1,343 @@
import { Logger } from '../utils/logger';
export interface VoiceCommand {
command: string;
confidence: number;
intent: string;
entities: any[];
timestamp: Date;
}
export interface VoiceResponse {
text: string;
mode: 'brief' | 'detailed' | 'silent' | 'interactive';
audioUrl?: string;
duration?: number;
}
export class VoiceProcessor {
private logger: Logger;
private isListening: boolean = false;
private recognition: any; // Web Speech API recognition
private synthesis: any; // Web Speech API synthesis
private currentLanguage: string = 'en-US';
private voiceMode: 'brief' | 'detailed' | 'silent' | 'interactive' = 'brief';
constructor() {
this.logger = new Logger('VoiceProcessor');
this.initializeSpeechAPIs();
}
private initializeSpeechAPIs(): void {
try {
// Initialize Web Speech API (for client-side simulation)
if (typeof window !== 'undefined' && 'webkitSpeechRecognition' in window) {
this.recognition = new (window as any).webkitSpeechRecognition();
this.synthesis = window.speechSynthesis;
this.setupRecognition();
this.logger.info('Web Speech API initialized successfully');
} else {
this.logger.warn('Web Speech API not available, using mock implementation');
}
} catch (error) {
this.logger.error('Failed to initialize speech APIs', { error: error.message });
}
}
private setupRecognition(): void {
if (!this.recognition) return;
this.recognition.continuous = true;
this.recognition.interimResults = true;
this.recognition.lang = this.currentLanguage;
this.recognition.onstart = () => {
this.isListening = true;
this.logger.info('Voice recognition started');
};
this.recognition.onend = () => {
this.isListening = false;
this.logger.info('Voice recognition ended');
};
this.recognition.onerror = (event: any) => {
this.logger.error('Voice recognition error', { error: event.error });
};
}
async processVoiceInput(audioData?: ArrayBuffer): Promise<VoiceCommand> {
this.logger.info('Processing voice input', { hasAudioData: !!audioData });
// In a real implementation, this would process actual audio data
// For now, we'll simulate voice command processing
const mockCommand = this.generateMockCommand();
this.logger.voiceCommandProcessed(mockCommand.command, 'default', mockCommand.confidence);
return mockCommand;
}
private generateMockCommand(): VoiceCommand {
const commands = [
'Hello Nowhere, show me the project structure',
'Nowhere, analyze this code file',
'Create a new React component',
'Run the tests and show me the results',
'Enable autopilot mode',
'What do you remember from our conversation?',
'Nowhere, help me debug this issue',
'Generate documentation for this function'
];
const randomCommand = commands[Math.floor(Math.random() * commands.length)];
const confidence = 0.85 + Math.random() * 0.1; // 85-95% confidence
return {
command: randomCommand,
confidence,
intent: this.parseIntent(randomCommand),
entities: this.extractEntities(randomCommand),
timestamp: new Date()
};
}
private parseIntent(command: string): string {
const lowerCommand = command.toLowerCase();
if (lowerCommand.includes('show') || lowerCommand.includes('structure')) {
return 'show_project_structure';
}
if (lowerCommand.includes('analyze') || lowerCommand.includes('code')) {
return 'analyze_code';
}
if (lowerCommand.includes('create') || lowerCommand.includes('component')) {
return 'create_component';
}
if (lowerCommand.includes('test') || lowerCommand.includes('run')) {
return 'run_tests';
}
if (lowerCommand.includes('autopilot')) {
return 'toggle_autopilot';
}
if (lowerCommand.includes('remember') || lowerCommand.includes('memory')) {
return 'retrieve_memory';
}
if (lowerCommand.includes('debug') || lowerCommand.includes('issue')) {
return 'debug_issue';
}
if (lowerCommand.includes('documentation') || lowerCommand.includes('doc')) {
return 'generate_documentation';
}
return 'general_query';
}
private extractEntities(command: string): any[] {
const entities: any[] = [];
const lowerCommand = command.toLowerCase();
// Extract file types
const fileTypes = ['js', 'ts', 'jsx', 'tsx', 'py', 'java', 'cpp', 'html', 'css'];
fileTypes.forEach(type => {
if (lowerCommand.includes(type)) {
entities.push({ type: 'file_extension', value: type });
}
});
// Extract frameworks
const frameworks = ['react', 'vue', 'angular', 'node', 'express'];
frameworks.forEach(framework => {
if (lowerCommand.includes(framework)) {
entities.push({ type: 'framework', value: framework });
}
});
// Extract actions
const actions = ['create', 'analyze', 'show', 'run', 'debug', 'generate'];
actions.forEach(action => {
if (lowerCommand.includes(action)) {
entities.push({ type: 'action', value: action });
}
});
return entities;
}
async startListening(): Promise<void> {
if (this.recognition) {
this.recognition.start();
} else {
this.isListening = true;
this.logger.info('Mock voice listening started');
}
}
async stopListening(): Promise<void> {
if (this.recognition) {
this.recognition.stop();
} else {
this.isListening = false;
this.logger.info('Mock voice listening stopped');
}
}
async speakText(text: string, mode: 'brief' | 'detailed' | 'silent' | 'interactive' = 'brief'): Promise<VoiceResponse> {
this.logger.info('Speaking text', { textLength: text.length, mode });
const responseText = this.generateResponseText(text, mode);
if (mode === 'silent') {
return {
text: responseText,
mode: 'silent'
};
}
// In a real implementation, this would use TTS
if (this.synthesis && mode !== 'silent') {
const utterance = new SpeechSynthesisUtterance(responseText);
utterance.lang = this.currentLanguage;
utterance.rate = 1.0;
utterance.pitch = 1.0;
this.synthesis.speak(utterance);
}
return {
text: responseText,
mode,
duration: responseText.length * 0.06 // Rough estimate: 60ms per character
};
}
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
const sentences = text.split('.');
const keySentence = sentences[0] || text;
return `Brief: ${keySentence.trim()}.`;
}
private generateDetailedResponse(text: string): string {
// Add more context and explanation
return `Detailed response: ${text}\n\nThis includes comprehensive information and additional context for better understanding.`;
}
private generateInteractiveResponse(text: string): string {
// Add interactive elements
return `${text}\n\nWould you like me to:\n1. Provide more details?\n2. Show related examples?\n3. Execute this action?`;
}
async processVoiceCommand(voiceInput: string): Promise<{
command: string;
confidence: number;
intent: string;
entities: any[];
}> {
this.logger.info('Processing voice command', { voiceInput });
// Remove "Nowhere" from the beginning if present
const cleanedInput = voiceInput.replace(/^nowhere\s*,?\s*/i, '').trim();
return {
command: cleanedInput,
confidence: 0.9,
intent: this.parseIntent(cleanedInput),
entities: this.extractEntities(cleanedInput)
};
}
async getVoiceStatus(): Promise<{
isListening: boolean;
isSpeaking: boolean;
language: string;
available: boolean;
}> {
return {
isListening: this.isListening,
isSpeaking: this.synthesis ? this.synthesis.speaking : false,
language: this.currentLanguage,
available: !!(this.recognition && this.synthesis)
};
}
async setLanguage(language: string): Promise<void> {
this.currentLanguage = language;
if (this.recognition) {
this.recognition.lang = language;
}
this.logger.info('Voice language changed', { language });
}
async setVoiceMode(mode: 'brief' | 'detailed' | 'silent' | 'interactive'): Promise<void> {
this.voiceMode = mode;
this.logger.info('Voice mode changed', { mode });
}
// Advanced voice features
async transcribeAudio(audioData: ArrayBuffer): Promise<string> {
// Mock transcription
this.logger.info('Transcribing audio', { audioSize: audioData.byteLength });
return "Hello Nowhere, please help me with this code.";
}
async generateSpeech(text: string, options?: {
voice?: string;
rate?: number;
pitch?: number;
}): Promise<ArrayBuffer> {
// Mock speech generation
this.logger.info('Generating speech', { textLength: text.length, options });
return new ArrayBuffer(1024); // Mock audio data
}
async detectEmotion(audioData: ArrayBuffer): Promise<{
emotion: string;
confidence: number;
intensity: number;
}> {
// Mock emotion detection
const emotions = ['neutral', 'happy', 'frustrated', 'excited', 'confused'];
const randomEmotion = emotions[Math.floor(Math.random() * emotions.length)];
return {
emotion: randomEmotion,
confidence: 0.7 + Math.random() * 0.2,
intensity: 0.5 + Math.random() * 0.5
};
}
async getAvailableVoices(): Promise<Array<{
name: string;
lang: string;
default: boolean;
}>> {
if (this.synthesis) {
return this.synthesis.getVoices().map((voice: any) => ({
name: voice.name,
lang: voice.lang,
default: voice.default
}));
}
// Mock voices
return [
{ name: 'Default Voice', lang: 'en-US', default: true },
{ name: 'Female Voice', lang: 'en-US', default: false },
{ name: 'Male Voice', lang: 'en-US', default: false }
];
}
}

View File

@@ -0,0 +1,385 @@
import { Server, Socket } from 'socket.io';
import { NowhereCore, NowhereContext } from './core/nowhere';
import { Logger } from './utils/logger';
import { verifyToken } from './middleware/auth';
interface WebSocketMessage {
type: string;
data: any;
userId?: string;
timestamp?: Date;
}
const logger = new Logger('WebSocket');
export function setupWebSocket(io: Server, nowhere: NowhereCore): void {
io.on('connection', (socket: Socket) => {
logger.info('Client connected', {
id: socket.id,
address: socket.handshake.address,
userAgent: socket.handshake.headers['user-agent']
});
// Send welcome message
socket.emit('welcome', {
type: 'welcome',
data: {
message: 'Welcome to Nowhere AI Agent',
version: '2.0.0',
features: [
'Voice Commands',
'Autopilot Mode',
'Real-time Communication',
'Memory System',
'Advanced AI Processing',
'Multi-model Support'
],
sessionId: socket.id
},
timestamp: new Date(),
success: true
});
// Handle authentication
socket.on('authenticate', async (data: { token: string }) => {
try {
const decoded = verifyToken(data.token);
if (decoded) {
socket.data.user = {
id: decoded.id,
email: decoded.email,
role: decoded.role || 'user',
permissions: decoded.permissions || []
};
logger.info('Socket authenticated', {
socketId: socket.id,
userId: socket.data.user.id
});
socket.emit('authenticated', {
type: 'authenticated',
data: {
user: socket.data.user,
message: 'Authentication successful'
},
timestamp: new Date(),
success: true
});
} else {
socket.emit('auth_error', {
type: 'auth_error',
data: {
message: 'Invalid token'
},
timestamp: new Date(),
success: false
});
}
} catch (error: any) {
logger.error('Socket authentication error', { error: error.message });
socket.emit('auth_error', {
type: 'auth_error',
data: {
message: 'Authentication failed'
},
timestamp: new Date(),
success: false
});
}
});
// Handle command messages
socket.on('command', async (message: WebSocketMessage) => {
try {
const userId = socket.data.user?.id || message.userId || 'default';
logger.info('Processing WebSocket command', {
command: message.data.command,
userId,
socketId: socket.id
});
const response = await nowhere.processCommand(message.data.command, userId);
socket.emit('response', {
type: 'command_response',
data: {
response: response.response,
actions: response.actions,
confidence: response.confidence,
model: response.model,
tokens: response.tokens,
timestamp: response.timestamp
},
timestamp: new Date(),
success: true
});
// Broadcast to other clients if it's a system command
if (message.data.command.toLowerCase().includes('system') ||
message.data.command.toLowerCase().includes('broadcast')) {
socket.broadcast.emit('system_message', {
type: 'system_message',
data: {
message: `System: ${response.response}`,
userId: userId
},
timestamp: new Date()
});
}
} catch (error: any) {
logger.error('WebSocket command error', { error: error.message });
socket.emit('error', {
type: 'command_error',
data: {
message: 'Failed to process command',
error: error.message
},
timestamp: new Date(),
success: false
});
}
});
// Handle voice command messages
socket.on('voice_command', async (message: WebSocketMessage) => {
try {
const userId = socket.data.user?.id || message.userId || 'default';
logger.info('Processing WebSocket voice command', {
voiceInput: message.data.voiceInput,
userId,
socketId: socket.id
});
const response = await nowhere.processCommand(`voice: ${message.data.voiceInput}`, userId);
socket.emit('voice_response', {
type: 'voice_response',
data: {
response: response.response,
actions: response.actions,
confidence: response.confidence,
model: response.model,
tokens: response.tokens,
timestamp: response.timestamp
},
timestamp: new Date(),
success: true
});
} catch (error: any) {
logger.error('WebSocket voice command error', { error: error.message });
socket.emit('error', {
type: 'voice_error',
data: {
message: 'Failed to process voice command',
error: error.message
},
timestamp: new Date(),
success: false
});
}
});
// Handle autopilot messages
socket.on('autopilot', async (message: WebSocketMessage) => {
try {
const userId = socket.data.user?.id || message.userId || 'default';
const action = message.data.action; // 'enable' or 'disable'
logger.info('Processing autopilot action', {
action,
userId,
socketId: socket.id
});
const command = action === 'enable' ? 'enable autopilot mode' : 'disable autopilot mode';
const response = await nowhere.processCommand(command, userId);
socket.emit('autopilot_response', {
type: 'autopilot_response',
data: {
enabled: action === 'enable',
message: response.response,
actions: response.actions
},
timestamp: new Date(),
success: true
});
} catch (error: any) {
logger.error('WebSocket autopilot error', { error: error.message });
socket.emit('error', {
type: 'autopilot_error',
data: {
message: 'Failed to process autopilot action',
error: error.message
},
timestamp: new Date(),
success: false
});
}
});
// Handle memory operations
socket.on('memory', async (message: WebSocketMessage) => {
try {
const userId = socket.data.user?.id || message.userId || 'default';
const operation = message.data.operation; // 'get', 'clear', 'add'
logger.info('Processing memory operation', {
operation,
userId,
socketId: socket.id
});
let response;
switch (operation) {
case 'get':
response = await nowhere.processCommand('show me my memory', userId);
break;
case 'clear':
response = await nowhere.processCommand('clear my memory', userId);
break;
case 'add':
response = await nowhere.processCommand(`remember: ${message.data.content}`, userId);
break;
default:
response = await nowhere.processCommand('show me my memory', userId);
}
socket.emit('memory_response', {
type: 'memory_response',
data: {
operation,
response: response.response,
actions: response.actions
},
timestamp: new Date(),
success: true
});
} catch (error: any) {
logger.error('WebSocket memory error', { error: error.message });
socket.emit('error', {
type: 'memory_error',
data: {
message: 'Failed to process memory operation',
error: error.message
},
timestamp: new Date(),
success: false
});
}
});
// Handle status requests
socket.on('status', async () => {
try {
const status = await nowhere.getStatus();
socket.emit('status_response', {
type: 'status_response',
data: status,
timestamp: new Date(),
success: true
});
} catch (error: any) {
logger.error('WebSocket status error', { error: error.message });
socket.emit('error', {
type: 'status_error',
data: {
message: 'Failed to get status',
error: error.message
},
timestamp: new Date(),
success: false
});
}
});
// Handle voice status requests
socket.on('voice_status', async () => {
try {
socket.emit('voice_status_response', {
type: 'voice_status_response',
data: {
available: true,
isListening: false,
isSpeaking: false,
language: 'en-US',
mode: 'brief'
},
timestamp: new Date(),
success: true
});
} catch (error: any) {
logger.error('WebSocket voice status error', { error: error.message });
socket.emit('error', {
type: 'voice_status_error',
data: {
message: 'Failed to get voice status',
error: error.message
},
timestamp: new Date(),
success: false
});
}
});
// Handle ping/pong for connection health
socket.on('ping', () => {
socket.emit('pong', {
type: 'pong',
data: {
timestamp: Date.now()
},
timestamp: new Date()
});
});
// Handle disconnect
socket.on('disconnect', (reason: string) => {
logger.info('Client disconnected', {
socketId: socket.id,
reason,
userId: socket.data.user?.id
});
});
// Handle errors
socket.on('error', (error: any) => {
logger.error('Socket error', {
socketId: socket.id,
error: error.message
});
});
});
// Broadcast system messages to all connected clients
function broadcastSystemMessage(message: string, type: string = 'info') {
io.emit('system_broadcast', {
type: 'system_broadcast',
data: {
message,
type,
timestamp: new Date()
},
timestamp: new Date()
});
}
// Graceful shutdown
process.on('SIGTERM', () => {
logger.info('Shutting down WebSocket server');
broadcastSystemMessage('Server is shutting down', 'warning');
io.close();
});
process.on('SIGINT', () => {
logger.info('Shutting down WebSocket server');
broadcastSystemMessage('Server is shutting down', 'warning');
io.close();
});
logger.info('WebSocket server setup complete');
}