Skip to main content

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

  1. Start with EntityArchitectAgent implementation
  2. Test with simple requirement (e.g., "Create a customer entity")
  3. Add Workflow Designer Agent
  4. Integrate Orchestrator Agent
  5. Build full end-to-end flow
  6. Load test and optimize
  7. Deploy to staging
  8. Gather feedback and iterate