Package Exports
- @memberjunction/ai-agents
- @memberjunction/ai-agents/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@memberjunction/ai-agents) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@memberjunction/ai-agents
The MemberJunction AI Agents package provides a comprehensive framework for creating, managing, and executing AI agents within the MemberJunction ecosystem. This package serves as the foundation for building sophisticated agentic AI applications with hierarchical composition, context management, and intelligent execution strategies.
Features
- 🤖 BaseAgent Class: Core foundation for all AI agent implementations
- 🏗️ Agent Composition: Hierarchical agent architecture with parent-child relationships
- 🧠 Context Management: Intelligent conversation context handling and compression
- 🔄 Execution Strategies: Sequential and parallel agent execution modes
- 📝 Learning System: Agent note-taking and knowledge retention capabilities
- 🎯 Action Framework: Extensible action system for agent capabilities
- 🔧 Subclassing Support: Easy extension and customization of agent behavior
- 🔐 Metadata-Driven: Database-driven configuration for agents and behaviors
- 📊 Analytics: Comprehensive execution logging and performance tracking
Installation
npm install @memberjunction/ai-agentsRequirements
- Node.js 16+
- MemberJunction Core libraries
- @memberjunction/ai-prompts for advanced prompt management
- @memberjunction/aiengine for AI model orchestration
Core Architecture
BaseAgent Class
The BaseAgent class is the central component of the AI Agents framework, providing:
- Standard Interface: Consistent API for all agent implementations
- Lifecycle Management: Initialization, execution, and cleanup workflows
- Context Handling: Automatic conversation context management
- Error Handling: Robust error recovery and logging
- Extensibility: Clean extension points for custom behavior
import { BaseAgent } from '@memberjunction/ai-agents';
import { AIAgentEntity } from '@memberjunction/core-entities';
// Create a custom agent by extending BaseAgent
class CustomerSupportAgent extends BaseAgent {
// Agent metadata from database
private agentEntity: AIAgentEntity;
constructor(agentEntity: AIAgentEntity) {
super();
this.agentEntity = agentEntity;
}
async initialize(): Promise<void> {
// Custom initialization logic
await super.initialize();
this.setupCustomCapabilities();
}
async execute(context: AgentContext): Promise<AgentResult> {
// Custom execution logic
const result = await super.execute(context);
return this.enhanceResult(result);
}
async handleAction(actionName: string, params: any): Promise<any> {
// Handle agent-specific actions
switch(actionName) {
case 'searchKnowledgeBase':
return this.searchKnowledgeBase(params);
case 'createTicket':
return this.createSupportTicket(params);
default:
return super.handleAction(actionName, params);
}
}
}Architecture Deep Dive
For comprehensive details about the AI Agents framework architecture, data models, workflows, and implementation guidelines, see the Agent Architecture.md document.
Key architectural concepts covered include:
- Hierarchical Agent Composition: How agents are organized and orchestrated
- Metadata-Driven Configuration: Database-driven agent and prompt management
- Execution Workflows: Detailed execution patterns and context management
- Performance Optimization: Caching, parallel execution, and resource management
- Extensibility Patterns: Guidelines for custom agent development
Usage Examples
Basic Agent Implementation
import { BaseAgent } from '@memberjunction/ai-agents';
import { Metadata } from '@memberjunction/core';
import { AIAgentEntity } from '@memberjunction/core-entities';
// Load agent metadata from database
const md = new Metadata();
const agentEntity = await md.GetEntityObject<AIAgentEntity>('AI Agents');
await agentEntity.Load('Customer Support Agent');
// Create agent instance
const agent = new CustomerSupportAgent(agentEntity);
await agent.initialize();
// Execute agent with context
const result = await agent.execute({
conversationId: 'conv-123',
messages: [
{ role: 'user', content: 'I need help with my order' }
],
metadata: {
userId: 'user-456',
sessionId: 'session-789'
}
});
console.log(result.response);Hierarchical Agent Composition
import { BaseAgent, ConductorAgent } from '@memberjunction/ai-agents';
// Create a conductor agent that manages other agents
class CustomerServiceConductor extends ConductorAgent {
async routeToSubAgent(context: AgentContext): Promise<string> {
// Analyze context to determine which sub-agent to use
const intent = await this.analyzeIntent(context);
switch(intent.category) {
case 'billing':
return 'BillingAgent';
case 'technical':
return 'TechnicalSupportAgent';
case 'general':
return 'GeneralInquiryAgent';
default:
return 'DefaultAgent';
}
}
}
// Use the conductor
const conductor = new CustomerServiceConductor(conductorEntity);
await conductor.initialize();
// Add child agents
await conductor.addChildAgent(billingAgent);
await conductor.addChildAgent(technicalAgent);
await conductor.addChildAgent(generalAgent);
// Execute - conductor will route to appropriate sub-agent
const result = await conductor.execute(context);Context Management and Compression
import { BaseAgent } from '@memberjunction/ai-agents';
class LongConversationAgent extends BaseAgent {
async execute(context: AgentContext): Promise<AgentResult> {
// Check if context needs compression
if (context.messages.length > this.agentEntity.ContextCompressionMessageThreshold) {
// Compress older messages while keeping recent ones
context = await this.compressContext(context);
}
// Continue with execution
return super.execute(context);
}
private async compressContext(context: AgentContext): Promise<AgentContext> {
// Use configured compression prompt
const compressionPrompt = await this.getCompressionPrompt();
const compressed = await compressionPrompt.execute({
messages: context.messages.slice(0, -this.agentEntity.ContextCompressionMessageRetentionCount)
});
// Return new context with compressed history
return {
...context,
messages: [
{ role: 'system', content: compressed.summary },
...context.messages.slice(-this.agentEntity.ContextCompressionMessageRetentionCount)
]
};
}
}API Reference
BaseAgent Class
The foundation class for all AI agents.
Constructor
constructor(agentEntity?: AIAgentEntity)Properties
| Property | Type | Description |
|---|---|---|
agentEntity |
AIAgentEntity |
The database entity containing agent configuration |
isInitialized |
boolean |
Whether the agent has been initialized |
actions |
AIAgentActionEntity[] |
Available actions for this agent |
notes |
AIAgentNoteEntity[] |
Learning notes accumulated by the agent |
Methods
initialize(): Promise<void>
Initializes the agent, loading configuration and preparing for execution.
execute(context: AgentContext): Promise<AgentResult>
Executes the agent with the provided context.
Parameters:
context: AgentContext- The execution context containing conversation history and metadata
Returns: Promise<AgentResult> - The agent's response and metadata
handleAction(actionName: string, params: any): Promise<any>
Handles agent-specific actions.
Parameters:
actionName: string- The name of the action to executeparams: any- Parameters for the action
Returns: Promise<any> - The action result
addNote(content: string, type: string): Promise<void>
Adds a learning note for the agent.
Parameters:
content: string- The note contenttype: string- The type of note (e.g., 'learning', 'error', 'improvement')
Types and Interfaces
AgentContext
interface AgentContext {
conversationId: string;
messages: Message[];
metadata?: Record<string, any>;
parentContext?: AgentContext;
}AgentResult
interface AgentResult {
response: string;
success: boolean;
metadata?: {
tokensUsed?: number;
executionTimeMs?: number;
modelUsed?: string;
childAgentResults?: AgentResult[];
};
error?: string;
}Message
interface Message {
role: 'system' | 'user' | 'assistant';
content: string;
timestamp?: Date;
metadata?: Record<string, any>;
}Configuration
Agents are configured through the MemberJunction metadata system. Key configuration options include:
Agent Configuration (AIAgent Entity)
| Field | Description | Default |
|---|---|---|
Name |
Unique agent identifier | Required |
Description |
Agent purpose and capabilities | Required |
ParentID |
Parent agent for hierarchical composition | null |
ExecutionMode |
How child agents execute (Sequential/Parallel) | Sequential |
EnableContextCompression |
Whether to compress long conversations | false |
ContextCompressionMessageThreshold |
Messages before compression triggers | 50 |
ContextCompressionMessageRetentionCount |
Recent messages to keep uncompressed | 10 |
Integration with Prompts
Agents use prompts through the AIAgentPrompt entity:
// Example: Associate a prompt with an agent
const agentPrompt = await md.GetEntityObject<AIAgentPromptEntity>('AI Agent Prompts');
agentPrompt.NewRecord();
agentPrompt.AgentID = agent.ID;
agentPrompt.PromptID = prompt.ID;
agentPrompt.Purpose = 'Main conversation handler';
agentPrompt.ExecutionOrder = 1;
agentPrompt.ContextBehavior = 'Recent'; // or 'Full', 'None'
agentPrompt.ContextMessageCount = 20;
await agentPrompt.Save();Dependencies
@memberjunction/core: ^2.43.0 - MemberJunction core library@memberjunction/global: ^2.43.0 - MemberJunction global utilities@memberjunction/core-entities: ^2.43.0 - MemberJunction entity definitions@memberjunction/ai: ^2.43.0 - Base AI functionality@memberjunction/aiengine: ^2.43.0 - AI model orchestration@memberjunction/ai-prompts: ^2.43.0 - Advanced prompt management@memberjunction/templates: ^2.43.0 - Template rendering supportrxjs: ^7.8.1 - Reactive programming supportdotenv: ^16.4.1 - Environment configuration
Related Packages
@memberjunction/aiengine: Core AI engine and model management@memberjunction/ai-prompts: Advanced prompt execution and management@memberjunction/templates: Template rendering for dynamic content
Advanced Features
Parallel Agent Execution
class ParallelAnalysisAgent extends BaseAgent {
async execute(context: AgentContext): Promise<AgentResult> {
// Execute multiple sub-agents in parallel
const [sentiment, intent, entities] = await Promise.all([
this.sentimentAgent.execute(context),
this.intentAgent.execute(context),
this.entityExtractorAgent.execute(context)
]);
// Combine results
return {
response: this.synthesizeResults(sentiment, intent, entities),
success: true,
metadata: {
childAgentResults: [sentiment, intent, entities]
}
};
}
}Agent Learning and Adaptation
class LearningAgent extends BaseAgent {
async execute(context: AgentContext): Promise<AgentResult> {
try {
const result = await super.execute(context);
// Learn from successful execution
if (result.success) {
await this.addNote(
`Successfully handled query type: ${this.classifyQuery(context)}`,
'learning'
);
}
return result;
} catch (error) {
// Learn from errors
await this.addNote(
`Error handling query: ${error.message}`,
'error'
);
throw error;
}
}
}Custom Action Implementation
class DataAnalysisAgent extends BaseAgent {
async initialize(): Promise<void> {
await super.initialize();
// Register custom actions
this.registerAction('analyzeData', this.analyzeData.bind(this));
this.registerAction('generateReport', this.generateReport.bind(this));
this.registerAction('exportResults', this.exportResults.bind(this));
}
private async analyzeData(params: { datasetId: string }): Promise<any> {
// Implementation for data analysis
const dataset = await this.loadDataset(params.datasetId);
return this.performAnalysis(dataset);
}
}Error Handling
The framework provides comprehensive error handling:
try {
const result = await agent.execute(context);
console.log('Success:', result);
} catch (error) {
if (error instanceof AgentExecutionError) {
console.error('Execution failed:', error.message);
console.error('Agent:', error.agentName);
console.error('Context:', error.context);
} else if (error instanceof AgentInitializationError) {
console.error('Failed to initialize agent:', error.message);
} else {
console.error('Unexpected error:', error);
}
}Performance Considerations
- Context Compression: Enable for long conversations to reduce token usage
- Caching: Leverage result caching for repeated queries
- Parallel Execution: Use parallel mode for independent sub-agents
- Resource Limits: Configure appropriate timeouts and token limits
Development Status
🚧 Under Active Development - This package is currently being built and will house all functionality for the MJ AI Agent framework. The BaseAgent class and core infrastructure are being implemented to provide the foundation for all agentic execution work in the MemberJunction ecosystem.
Current Implementation Status
- ✅ Package structure and configuration
- 🚧 BaseAgent class implementation (in progress)
- 📋 ConductorAgent for hierarchical composition (planned)
- 📋 Context management and compression (planned)
- 📋 Action framework integration (planned)
- 📋 Learning and note system (planned)
- 📋 Execution logging and analytics (planned)
Roadmap
- Phase 1: Core BaseAgent implementation with basic execution
- Phase 2: Hierarchical agent composition and conductor pattern
- Phase 3: Advanced context management and compression
- Phase 4: Action framework and extensibility
- Phase 5: Learning system and performance optimization
License
ISC
Testing
import { BaseAgent } from '@memberjunction/ai-agents';
import { MockAgentEntity } from './test-utils';
describe('CustomerSupportAgent', () => {
let agent: CustomerSupportAgent;
beforeEach(async () => {
const mockEntity = new MockAgentEntity({
Name: 'Test Agent',
EnableContextCompression: true,
ContextCompressionMessageThreshold: 10
});
agent = new CustomerSupportAgent(mockEntity);
await agent.initialize();
});
test('should handle customer query', async () => {
const result = await agent.execute({
conversationId: 'test-123',
messages: [
{ role: 'user', content: 'What is my order status?' }
]
});
expect(result.success).toBe(true);
expect(result.response).toContain('order');
});
test('should compress long conversations', async () => {
const longContext = {
conversationId: 'test-456',
messages: Array(15).fill(null).map((_, i) => ({
role: i % 2 === 0 ? 'user' : 'assistant',
content: `Message ${i}`
}))
};
const result = await agent.execute(longContext);
expect(result.metadata.contextCompressed).toBe(true);
});
});Troubleshooting
Common Issues
- Agent Not Found: Ensure the agent is properly registered in the database
- Initialization Failures: Check that all required prompts and configurations exist
- Context Overflow: Enable context compression for long conversations
- Performance Issues: Review parallel execution settings and caching configuration
Debug Mode
// Enable debug logging
process.env.MJ_AI_AGENT_DEBUG = 'true';
const agent = new MyAgent(entity);
agent.on('debug', (message) => {
console.log('[Agent Debug]:', message);
});Contributing
When developing agents using this framework:
- Always extend BaseAgent for consistency and built-in functionality
- Follow the lifecycle patterns defined in the base class
- Use meaningful names and descriptions for agents and actions
- Implement proper error handling in custom execution logic
- Leverage the note system for agent learning and improvement
- Test with various context scenarios to ensure robustness
- Document custom actions and behaviors in your agent implementations
- Follow TypeScript best practices and avoid
anytypes
For detailed development guidelines and best practices, refer to the Agent Architecture.md documentation.