AI Agent Implementation Guide
Getting Started with Axiom Genesis AI Agents
This guide provides technical steps to implement the AI Agent Architecture in Axiom Genesis.
Part 1: SETUP & INFRASTRUCTURE
1.1 Prerequisites
# Node.js and npm
node --version # >= v16.0.0
npm --version # >= 7.0.0
# Install core dependencies
npm install express dotenv
npm install bull redis # Message queue
npm install axios openai anthropic # AI providers
npm install winston # Logging
npm install socket.io # Real-time updates
1.2 Environment Configuration
# .env
AI_PROVIDER=openai # openai | anthropic | vertex_ai | local
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4
# Optional: Anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-3-sonnet
# Message Queue
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# Database (for state storage)
DB_HOST=localhost
DB_USER=admin
DB_PASSWORD=
# Logging
LOG_LEVEL=info
LOG_FILE=/var/log/ai-agents.log
1.3 Database Tables for State Management
-- Agent task tracking
CREATE TABLE agent_tasks (
task_id UUID PRIMARY KEY,
project_id UUID,
agent_id VARCHAR(255),
task_type VARCHAR(255),
status VARCHAR(50), -- queued, in_progress, completed, failed
input JSONB,
output JSONB,
error_message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP,
duration_ms INT,
INDEX idx_project_status (project_id, status),
INDEX idx_agent_id (agent_id),
INDEX idx_created_at (created_at)
);
-- Project state tracking
CREATE TABLE ai_projects (
project_id UUID PRIMARY KEY,
user_id UUID,
tenant_id UUID,
title VARCHAR(255),
status VARCHAR(50), -- planning, in_progress, completed, failed
requirements JSONB,
artifacts JSONB, -- {"entities": [...], "workflows": [...], ...}
progress_percent INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP,
INDEX idx_user_created (user_id, created_at),
INDEX idx_tenant_id (tenant_id)
);
-- Conversation history
CREATE TABLE ai_conversations (
conversation_id UUID PRIMARY KEY,
session_id VARCHAR(255),
user_id UUID,
messages JSONB, -- Array of {role, content, timestamp}
context JSONB, -- Current context snapshot
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_session_id (session_id),
INDEX idx_user_id (user_id)
);
1.4 Redis Setup for State Caching
// config/redis.js
const redis = require('redis');
const client = redis.createClient({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
db: 0
});
module.exports = {
// Store conversation with TTL
async saveConversation(sessionId, messages) {
await client.setex(
`conv:${sessionId}`,
86400, // 24 hours
JSON.stringify(messages)
);
},
// Retrieve conversation
async getConversation(sessionId) {
const data = await client.get(`conv:${sessionId}`);
return JSON.parse(data);
},
// Cache agent response
async cacheAgentResponse(key, response) {
await client.setex(
`agent_resp:${key}`,
3600, // 1 hour
JSON.stringify(response)
);
}
};
1.5 Message Queue Setup
// config/queue.js
const Queue = require('bull');
const redis = require('redis');
const redisConfig = {
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD
};
// Create queues for different agent types
const queues = {
orchestration: new Queue('orchestration', redisConfig),
entity_design: new Queue('entity_design', redisConfig),
workflow_design: new Queue('workflow_design', redisConfig),
form_design: new Queue('form_design', redisConfig),
report_design: new Queue('report_design', redisConfig),
security_setup: new Queue('security_setup', redisConfig),
integration_setup: new Queue('integration_setup', redisConfig)
};
// Setup queue processors
Object.entries(queues).forEach(([name, queue]) => {
queue.process(10); // 10 concurrent jobs
queue.on('completed', (job) => {
console.log(`✅ ${name} completed:`, job.id);
});
queue.on('failed', (job, err) => {
console.error(`❌ ${name} failed:`, job.id, err.message);
});
});
module.exports = queues;
Part 2: BASE AGENT FRAMEWORK
2.1 Abstract Agent Class
// agents/BaseAgent.js
const { LLM } = require('../services/llm');
const logger = require('../services/logger');
class BaseAgent {
constructor(name, config = {}) {
this.name = name;
this.config = config;
this.llm = new LLM(process.env.AI_PROVIDER);
this.tools = config.tools || [];
this.systemPrompt = this.buildSystemPrompt();
this.conversationHistory = [];
}
buildSystemPrompt() {
return `You are ${this.name}, a specialized AI agent in the Axiom Genesis RAD platform.
Your role: ${this.config.role || 'undefined'}
Your domain: ${this.config.domain || 'general'}
Your responsibilities:
${(this.config.responsibilities || []).map(r => `- ${r}`).join('\n')}
Guidelines:
- Be precise and technical
- Always validate outputs against constraints
- Ask for clarification if requirements are ambiguous
- Provide reasoning for your design decisions
- Consider best practices and industry standards`;
}
// Main execution method
async execute(task) {
logger.info(`[${this.name}] Executing task:`, task.task_id);
try {
// 1. Prepare context
const context = await this.prepareContext(task);
// 2. Build prompt
const prompt = this.buildPrompt(task, context);
// 3. Call LLM (potentially multiple times)
const result = await this.think(prompt, context);
// 4. Validate output
await this.validateOutput(result);
// 5. Execute action if needed
if (result.action) {
await this.executeAction(result.action);
}
logger.info(`[${this.name}] Task completed:`, task.task_id);
return result;
} catch (error) {
logger.error(`[${this.name}] Task failed:`, task.task_id, error);
throw error;
}
}
// ReAct pattern: Thought → Action → Observation
async think(prompt, context) {
let thought = null;
let action = null;
let observation = null;
let iterations = 0;
const maxIterations = 5;
while (iterations < maxIterations) {
iterations++;
// Thought step
thought = await this.llm.chat({
system: this.systemPrompt,
messages: [
...this.conversationHistory,
{ role: "user", content: prompt }
]
});
this.conversationHistory.push({
role: "assistant",
content: thought
});
// Check if we need to take action
action = this.parseAction(thought);
if (action.type === 'complete') {
return thought;
}
// Execute action and get observation
observation = await this.executeTool(action.tool, action.params);
this.conversationHistory.push({
role: "user",
content: `Observation: ${JSON.stringify(observation)}`
});
prompt = `Based on this observation, continue your thinking and either take another action or complete the task.`;
}
throw new Error(`Agent did not complete within ${maxIterations} iterations`);
}
async executeTool(toolName, params) {
const tool = this.tools.find(t => t.name === toolName);
if (!tool) {
throw new Error(`Tool not found: ${toolName}`);
}
return await tool.execute(params);
}
parseAction(thought) {
// Parse agent's thought to extract action
// e.g., "I will <ACTION>create_entity</ACTION> with <PARAMS>...</PARAMS>"
const actionMatch = thought.match(/<ACTION>(.*?)<\/ACTION>/);
const paramsMatch = thought.match(/<PARAMS>(.*?)<\/PARAMS>/);
if (!actionMatch) {
return { type: 'complete', content: thought };
}
return {
type: 'action',
tool: actionMatch[1],
params: paramsMatch ? JSON.parse(paramsMatch[1]) : {}
};
}
async prepareContext(task) {
// Override in subclasses to provide domain-specific context
return {
task,
timestamp: Date.now()
};
}
buildPrompt(task, context) {
// Override in subclasses
return `Task: ${task.description}\nContext: ${JSON.stringify(context, null, 2)}`;
}
async validateOutput(result) {
// Override in subclasses for validation
return true;
}
async executeAction(action) {
// Override in subclasses for specific actions
}
}
module.exports = BaseAgent;
2.2 LLM Service
// services/llm.js
const OpenAI = require('openai');
const Anthropic = require('@anthropic-ai/sdk');
class LLM {
constructor(provider = 'openai') {
this.provider = provider;
switch(provider) {
case 'openai':
this.client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
this.model = process.env.OPENAI_MODEL || 'gpt-4';
break;
case 'anthropic':
this.client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
this.model = process.env.ANTHROPIC_MODEL || 'claude-3-sonnet';
break;
default:
throw new Error(`Unsupported provider: ${provider}`);
}
}
async chat(options) {
const { system, messages } = options;
try {
if (this.provider === 'openai') {
const response = await this.client.chat.completions.create({
model: this.model,
system,
messages,
temperature: 0.7,
max_tokens: 2000
});
return response.choices[0].message.content;
} else if (this.provider === 'anthropic') {
const response = await this.client.messages.create({
model: this.model,
system,
messages,
temperature: 0.7,
max_tokens: 2000
});
return response.content[0].text;
}
} catch (error) {
console.error('LLM error:', error);
throw error;
}
}
async embeddings(text) {
if (this.provider !== 'openai') {
throw new Error('Embeddings only supported in OpenAI');
}
const response = await this.client.embeddings.create({
model: 'text-embedding-3-small',
input: text
});
return response.data[0].embedding;
}
}
module.exports = LLM;
Part 3: SPECIALIZED AGENTS
3.1 Entity Architect Agent
// agents/EntityArchitectAgent.js
const BaseAgent = require('./BaseAgent');
const { createEntityTool, validateEntityTool } = require('../tools');
class EntityArchitectAgent extends BaseAgent {
constructor() {
super('EntityArchitectAgent', {
role: 'Design optimal data entities',
domain: 'data_modeling',
responsibilities: [
'Analyze requirements to determine needed entities',
'Design entity structures with fields and types',
'Define relationships between entities',
'Plan indexes and performance optimizations',
'Configure access controls and permissions'
],
tools: [
createEntityTool,
validateEntityTool,
queryExistingEntityTool
]
});
}
async prepareContext(task) {
const { requirements, knowledgeContext } = task;
return {
...await super.prepareContext(task),
domain_knowledge: knowledgeContext.invoice_standards,
similar_entities: await this.findSimilarEntities(requirements),
database_constraints: await this.getDatabaseConstraints(),
naming_conventions: this.getNamingConventions()
};
}
buildPrompt(task, context) {
return `
TASK: Design entity configurations for the following requirements:
${task.requirements}
DOMAIN KNOWLEDGE:
${JSON.stringify(context.domain_knowledge, null, 2)}
SIMILAR ENTITIES (for reference):
${JSON.stringify(context.similar_entities, null, 2)}
DATABASE CONSTRAINTS:
${JSON.stringify(context.database_constraints, null, 2)}
NAMING CONVENTIONS:
${JSON.stringify(context.naming_conventions, null, 2)}
OUTPUT FORMAT:
Provide the entity design in JSON format with:
{
"entity_name": "...",
"fields": [...],
"relationships": [...],
"indexes": [...],
"permissions": {...}
}
After designing, validate the entity using the validate_entity tool.
`;
}
async validateOutput(result) {
// Validate JSON structure
try {
JSON.parse(result);
} catch (e) {
throw new Error('Output is not valid JSON');
}
// Validate entity structure
const entity = JSON.parse(result);
if (!entity.entity_name || !entity.fields) {
throw new Error('Entity missing required fields: entity_name, fields');
}
// Validate against database constraints
await validateEntityTool.execute({ entity });
return true;
}
async findSimilarEntities(requirements) {
// Query knowledge base for similar entity patterns
// This would typically search a template library
return [];
}
async getDatabaseConstraints() {
// Get current database constraints
// e.g., max field length, reserved names, etc.
return {
max_field_name_length: 255,
reserved_words: [...],
supported_types: [...]
};
}
getNamingConventions() {
return {
entity_name_case: 'PascalCase',
field_name_case: 'snake_case',
primary_key_suffix: '_id',
foreign_key_prefix: 'fk_'
};
}
}
module.exports = EntityArchitectAgent;
3.2 Orchestrator Agent
// agents/OrchestratorAgent.js
const BaseAgent = require('./BaseAgent');
const EventEmitter = require('events');
const queues = require('../config/queue');
class OrchestratorAgent extends BaseAgent {
constructor() {
super('OrchestratorAgent', {
role: 'Coordinate all other agents',
domain: 'orchestration',
responsibilities: [
'Decompose requirements into tasks',
'Plan agent execution sequence',
'Handle dependencies',
'Aggregate results',
'Manage overall project state'
]
});
this.eventBus = new EventEmitter();
}
async orchestrate(requirements) {
// 1. Create project context
const project = {
project_id: generateUUID(),
status: 'in_progress',
artifacts: {},
agents_completed: [],
created_at: Date.now()
};
try {
// 2. Decompose requirements
const executionPlan = await this.planExecution(requirements);
// 3. Execute agents in sequence/parallel
for (const phase of executionPlan.phases) {
if (phase.parallel) {
await this.executePhaseParallel(phase, project);
} else {
await this.executePhasSequential(phase, project);
}
}
// 4. Deploy generated configs
project.status = 'deploying';
await this.deployConfigs(project.artifacts);
project.status = 'completed';
return project;
} catch (error) {
project.status = 'failed';
project.error = error.message;
throw error;
}
}
async planExecution(requirements) {
const prompt = `
Based on these requirements, create an execution plan:
${requirements}
Return a JSON plan with phases, each containing:
{
"phases": [
{
"phase": 1,
"parallel": true,
"tasks": [
{"agent": "EntityArchitectAgent", "task": "..."},
{"agent": "KnowledgeAgent", "task": "..."}
]
},
...
]
}
`;
const planJson = await this.llm.chat({
system: this.systemPrompt,
messages: [{ role: 'user', content: prompt }]
});
return JSON.parse(planJson);
}
async executePhaseParallel(phase, project) {
const taskPromises = phase.tasks.map(taskDef =>
this.queueTask(taskDef, project)
);
await Promise.all(taskPromises);
}
async executePhaseSequential(phase, project) {
for (const taskDef of phase.tasks) {
await this.queueTask(taskDef, project);
}
}
async queueTask(taskDef, project) {
const queue = queues[taskDef.agent];
const job = await queue.add({
task_id: generateUUID(),
project_id: project.project_id,
agent: taskDef.agent,
task: taskDef.task,
project_context: project
});
// Wait for completion
return new Promise((resolve, reject) => {
job.on('completed', (result) => {
project.artifacts[taskDef.agent] = result;
project.agents_completed.push(taskDef.agent);
resolve(result);
});
job.on('failed', reject);
});
}
async deployConfigs(artifacts) {
// Call Axiom Genesis APIs to deploy configs
const deployment = {
entities: await deployEntities(artifacts.entities),
workflows: await deployWorkflows(artifacts.workflows),
forms: await deployForms(artifacts.forms),
reports: await deployReports(artifacts.reports),
roles: await deployRoles(artifacts.roles)
};
return deployment;
}
}
module.exports = OrchestratorAgent;
Part 4: API ENDPOINTS
4.1 Chat Endpoint
// routes/ai.routes.js
const express = require('express');
const router = express.Router();
const { CommunicationAgent } = require('../agents');
const db = require('../config/database');
// POST /api/ai/chat
router.post('/chat', async (req, res) => {
try {
const { message, session_id } = req.body;
const user_id = req.user.id;
// Get or create conversation session
let conversation = await db.getConversation(session_id);
if (!conversation) {
conversation = { messages: [], session_id, user_id };
}
// Add user message
conversation.messages.push({
role: 'user',
content: message,
timestamp: Date.now()
});
// Get Communication Agent response
const communicationAgent = new CommunicationAgent();
const response = await communicationAgent.respond(message, conversation);
// Add assistant response
conversation.messages.push({
role: 'assistant',
content: response,
timestamp: Date.now()
});
// Save conversation
await db.saveConversation(session_id, conversation);
res.json({
message: response,
session_id,
message_count: conversation.messages.length
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// POST /api/ai/build
router.post('/build', async (req, res) => {
try {
const { requirements, session_id } = req.body;
const user_id = req.user.id;
const tenant_id = req.tenant.id;
// Create project
const project = {
project_id: generateUUID(),
user_id,
tenant_id,
requirements,
status: 'planning',
created_at: Date.now()
};
await db.saveProject(project);
// Queue orchestration task
const orchestrator = new OrchestratorAgent();
orchestrator.eventBus.on('progress', (event) => {
// Send progress updates via WebSocket
io.to(session_id).emit('ai:progress', event);
});
// Execute async
orchestrator.orchestrate(requirements)
.then(result => {
io.to(session_id).emit('ai:completed', result);
})
.catch(error => {
io.to(session_id).emit('ai:failed', { error: error.message });
});
res.json({
project_id: project.project_id,
status: 'building',
message: 'Solution generation in progress...'
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// GET /api/ai/project/:project_id
router.get('/project/:project_id', async (req, res) => {
try {
const project = await db.getProject(req.params.project_id);
res.json(project);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
module.exports = router;
4.2 WebSocket for Real-Time Updates
// services/websocket.js
const socketIO = require('socket.io');
module.exports = (server) => {
const io = socketIO(server, {
cors: { origin: '*' }
});
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
socket.on('join_session', (session_id) => {
socket.join(session_id);
});
socket.on('ai:start_build', async (data) => {
const { session_id, requirements } = data;
// Broadcast to all in session
const orchestrator = new OrchestratorAgent();
orchestrator.eventBus.on('progress', (event) => {
io.to(session_id).emit('ai:progress', event);
});
try {
const result = await orchestrator.orchestrate(requirements);
io.to(session_id).emit('ai:completed', result);
} catch (error) {
io.to(session_id).emit('ai:failed', { error: error.message });
}
});
socket.on('disconnect', () => {
console.log('User disconnected:', socket.id);
});
});
return io;
};
Part 5: FRONTEND INTEGRATION
5.1 Vue.js Component Example
<!-- components/AIAssistant.vue -->
<template>
<div class="ai-assistant">
<div class="chat-messages">
<div v-for="msg in messages" :key="msg.id" :class="`message ${msg.role}`">
<p>{{ msg.content }}</p>
</div>
<div v-if="building" class="progress">
<div class="progress-bar" :style="{width: progress + '%'}"></div>
<p>{{ progressMessage }}</p>
</div>
</div>
<div class="chat-input">
<textarea v-model="input" @keyup.enter="sendMessage"
placeholder="Describe what you want to build..."></textarea>
<button @click="sendMessage" :disabled="building">
{{ building ? 'Building...' : 'Build' }}
</button>
</div>
</div>
</template>
<script>
import axios from 'axios';
import io from 'socket.io-client';
export default {
name: 'AIAssistant',
data() {
return {
messages: [],
input: '',
building: false,
progress: 0,
progressMessage: '',
session_id: this.generateSessionId(),
socket: null
};
},
mounted() {
// Connect to WebSocket
this.socket = io('http://localhost:3000');
this.socket.on('connect', () => {
this.socket.emit('join_session', this.session_id);
});
this.socket.on('ai:progress', (event) => {
this.progress = event.progress;
this.progressMessage = event.message;
});
this.socket.on('ai:completed', (result) => {
this.building = false;
this.messages.push({
role: 'assistant',
content: `✅ Solution created! ${result.summary}`,
id: Date.now()
});
});
this.socket.on('ai:failed', (event) => {
this.building = false;
this.messages.push({
role: 'assistant',
content: `❌ Error: ${event.error}`,
id: Date.now()
});
});
},
methods: {
async sendMessage() {
if (!this.input.trim()) return;
// Add user message
this.messages.push({
role: 'user',
content: this.input,
id: Date.now()
});
const userMessage = this.input;
this.input = '';
try {
// Check if this is a build request
if (userMessage.includes('build') || userMessage.includes('create')) {
this.building = true;
this.socket.emit('ai:start_build', {
session_id: this.session_id,
requirements: userMessage
});
} else {
// Regular chat
const response = await axios.post('/api/ai/chat', {
message: userMessage,
session_id: this.session_id
});
this.messages.push({
role: 'assistant',
content: response.data.message,
id: Date.now()
});
}
} catch (error) {
this.messages.push({
role: 'assistant',
content: `Error: ${error.message}`,
id: Date.now()
});
}
},
generateSessionId() {
return `session_${Date.now()}_${Math.random()}`;
}
}
};
</script>
DEPLOYMENT CHECKLIST
- Environment variables configured
- Redis server running
- Database migrations completed
- LLM API keys configured
- Base Agent framework implemented
- All specialized agents coded
- API endpoints tested
- WebSocket connected
- Frontend components integrated
- Error handling and logging
- Performance optimization
- Security hardened
- Documentation complete
NEXT STEPS
- Start with EntityArchitectAgent implementation
- Test with simple requirement (e.g., "Create a customer entity")
- Add Workflow Designer Agent
- Integrate Orchestrator Agent
- Build full end-to-end flow
- Load test and optimize
- Deploy to staging
- Gather feedback and iterate