Devlog Jan 8: Module System Refinement
This week we focused on refining the module system with significant improvements to module management, error handling, and AI tools integration. The system is becoming more robust and developer-friendly.
Major Enhancements
AI Chat Workspace
We implemented a comprehensive AI chat workspace with enhanced UI and server-side improvements (cebd4e1):
New Components:
// AI Chat Workspace Component
import { useState } from 'react';
import { AiChatMessage } from './AiChatMessage';
import { AiChatInput } from './AiChatInput';
import { AiToolSelector } from './AiToolSelector';
export function AiChatWorkspace({ module }: { module: Module }) {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [selectedTools, setSelectedTools] = useState<AITool[]>([]);
const [isStreaming, setIsStreaming] = useState(false);
const handleSendMessage = async (content: string) => {
const newMessage: ChatMessage = {
id: generateId(),
role: 'user',
content,
timestamp: new Date()
};
setMessages(prev => [...prev, newMessage]);
setIsStreaming(true);
try {
const response = await invokeAI(
content,
selectedTools.map(t => t.name)
);
// Stream response
for await (const chunk of response) {
setMessages(prev => {
const lastMessage = prev[prev.length - 1];
if (lastMessage.role === 'assistant') {
return [
...prev.slice(0, -1),
{ ...lastMessage, content: lastMessage.content + chunk }
];
}
return prev;
});
}
} catch (error) {
console.error('AI invocation error:', error);
} finally {
setIsStreaming(false);
}
};
return (
<div className="ai-chat-workspace">
<div className="messages-container">
{messages.map(message => (
<AiChatMessage key={message.id} message={message} />
))}
</div>
<AiToolSelector
availableTools={module.aiTools}
selected={selectedTools}
onChange={setSelectedTools}
/>
<AiChatInput
onSend={handleSendMessage}
disabled={isStreaming}
/>
</div>
);
}
Server-Side Improvements:
// AI Invocation Server Handler
export async function invokeAI(
prompt: string,
tools: string[]
): AsyncGenerator<string> {
const config = await getAIConfig();
const client = new OpenAI({ apiKey: config.apiKey });
const response = await client.chat.completions.create({
model: config.model,
messages: [{ role: 'user', content: prompt }],
tools: tools.map(toolName => ({
type: 'function',
function: {
name: toolName,
description: await getToolDescription(toolName),
parameters: await getToolParameters(toolName)
}
})),
stream: true
});
for await (const chunk of response) {
const content = chunk.choices[0]?.delta?.content;
if (content) {
yield content;
}
}
}
Enhanced Module TUI
The Terminal User Interface received significant improvements for module management (9a16235):
New Features:
- Create new modules interactively
- View module dependencies
- Install modules from Git repositories
- Manage module versions
// TUI Module Creation
export async function createModuleViaTUI() {
const screen = blessed.screen();
// Module name input
const nameBox = blessed.textbox({
parent: screen,
label: 'Module Name:',
input: true,
keys: true,
mouse: true
});
// Module description input
const descBox = blessed.textbox({
parent: screen,
label: 'Description:',
input: true,
keys: true,
mouse: true
});
// Confirm button
const confirmBtn = blessed.button({
parent: screen,
content: 'Create Module',
mouse: true,
keys: true,
style: {
bg: 'green',
fg: 'white'
}
});
confirmBtn.on('press', async () => {
const name = nameBox.getValue();
const description = descBox.getValue();
await createModule({
name,
description,
version: '0.1.0',
author: 'MoLOS'
});
screen.destroy();
});
screen.render();
}
Module Error API
We introduced a comprehensive error handling system for modules (78da76f):
Error Types:
// Module Error Types
export enum ModuleErrorType {
INSTALLATION_FAILED = 'INSTALLATION_FAILED',
DEPENDENCY_MISSING = 'DEPENDENCY_MISSING',
CONFIGURATION_ERROR = 'CONFIGURATION_ERROR',
RUNTIME_ERROR = 'RUNTIME_ERROR',
SECURITY_VIOLATION = 'SECURITY_VIOLATION'
}
export interface ModuleError {
id: string;
moduleId: string;
type: ModuleErrorType;
message: string;
stack?: string;
timestamp: Date;
resolved: boolean;
}
API Endpoints:
// Module Error API Routes
app.get('/api/modules/:moduleId/errors', async (req, res) => {
const { moduleId } = req.params;
const { resolved } = req.query;
const errors = await prisma.moduleError.findMany({
where: {
moduleId,
resolved: resolved === 'true'
},
orderBy: {
timestamp: 'desc'
}
});
res.json(errors);
});
app.post('/api/modules/:moduleId/errors', async (req, res) => {
const { moduleId } = req.params;
const { type, message, stack } = req.body;
const error = await prisma.moduleError.create({
data: {
moduleId,
type,
message,
stack,
timestamp: new Date(),
resolved: false
}
});
res.status(201).json(error);
});
app.patch('/api/modules/:moduleId/errors/:errorId', async (req, res) => {
const { errorId } = req.params;
const { resolved } = req.body;
const error = await prisma.moduleError.update({
where: { id: errorId },
data: { resolved }
});
res.json(error);
});
Module Migration Improvements
Fixed module migration errors and improved database migration handling (b772f36):
// Improved Module Migration
export async function migrateModule(module: Module) {
const migrationDir = path.join(module.path, 'prisma', 'migrations');
if (!fs.existsSync(migrationDir)) {
return; // No migrations to run
}
const migrations = await fs.readdir(migrationDir);
const appliedMigrations = await prisma._migration.findMany({
where: { module_id: module.id }
});
const pendingMigrations = migrations.filter(
m => !appliedMigrations.some(am => am.name === m)
);
for (const migration of pendingMigrations) {
const migrationPath = path.join(migrationDir, migration);
const sql = await fs.readFile(migrationPath, 'utf-8');
try {
await prisma.$executeRawUnsafe(sql);
await prisma._migration.create({
data: {
name: migration,
module_id: module.id,
applied_at: new Date()
}
});
console.log(`✓ Applied migration: ${migration}`);
} catch (error) {
console.error(`✗ Failed to apply migration: ${migration}`, error);
throw new ModuleMigrationError(
module,
migration,
error.message
);
}
}
}
AI Tools Management
Enhanced AI tools management with better error handling and logging (f96938e):
// AI Tools Manager
export class AIToolsManager {
private tools: Map<string, AITool> = new Map();
async registerTool(tool: AITool): Promise<void> {
// Validate tool configuration
await this.validateTool(tool);
// Check for name conflicts
if (this.tools.has(tool.name)) {
throw new Error(`Tool with name "${tool.name}" already exists`);
}
// Register in database
await prisma.aITool.create({
data: {
name: tool.name,
description: tool.description,
moduleId: tool.moduleId,
config: tool.config
}
});
this.tools.set(tool.name, tool);
}
async invokeTool(name: string, params: any): Promise<any> {
const tool = this.tools.get(name);
if (!tool) {
throw new Error(`Tool "${name}" not found`);
}
try {
const result = await tool.execute(params);
this.logToolExecution(name, params, result);
return result;
} catch (error) {
this.logToolError(name, params, error);
throw error;
}
}
private async validateTool(tool: AITool): Promise<void> {
if (!tool.name || tool.name.trim().length === 0) {
throw new Error('Tool name is required');
}
if (!tool.description) {
throw new Error('Tool description is required');
}
if (!tool.execute || typeof tool.execute !== 'function') {
throw new Error('Tool must have an execute function');
}
}
private logToolExecution(name: string, params: any, result: any): void {
console.log(`[AI Tool] ${name}`, {
params: JSON.stringify(params, null, 2),
result: typeof result === 'object' ? JSON.stringify(result, null, 2) : result
});
}
private logToolError(name: string, params: any, error: Error): void {
console.error(`[AI Tool Error] ${name}`, {
params: JSON.stringify(params, null, 2),
error: error.message,
stack: error.stack
});
}
}
Database Schema Updates
Updated database schema to support new features (9edb72b):
// New Database Tables
model ModuleError {
id String @id @default(uuid())
moduleId String
type ModuleErrorType
message String
stack String?
timestamp DateTime @default(now())
resolved Boolean @default(false)
module Module @relation(fields: [moduleId], references: [id])
@@index([moduleId])
@@index([resolved])
}
model _Migration {
id String @id @default(uuid())
name String @unique
module_id String
applied_at DateTime @default(now())
checksum String?
module Module @relation(fields: [module_id], references: [id])
@@index([module_id])
}
model AITool {
id String @id @default(uuid())
name String @unique
description String
moduleId String
config Json?
enabled Boolean @default(true)
module Module @relation(fields: [moduleId], references: [id])
@@index([moduleId])
}
Bug Fixes
- Fixed unique name constraints for AI tools (
f96938e) - Resolved module installation error recognition (
78da76f) - Fixed SQL migration issues with new tables (
9edb72b)
Documentation Updates
- Added implementation guide for database changes (
a39ca04) - Updated module development documentation
What's Next
Next week we'll focus on:
- AI Integration: Further enhancements to AI capabilities in modules
- Module Development: Improvements to module development workflow
- Dynamic Module Addition: Better support for dynamically adding modules
- Standalone App: Enhancements to standalone application launch
The module system is becoming more robust with each passing week. Stay tuned for more updates!
Related Commits:
