Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "multi-agent-chat-platform",
"version": "0.1.0",
"scripts": {
"test": "jest",
"test:coverage": "jest --coverage",
"lint": "eslint . --ext .ts",
"validate-schema": "ajv validate -s src/interfaces/schemas.json"
},
"dependencies": {
"ajv": "^8.12.0",
"typescript": "^4.9.5"
},
"devDependencies": {
"@types/jest": "^29.5.1",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"eslint": "^8.40.0",
"@typescript-eslint/parser": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^5.59.2"
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"collectCoverage": true,
"coverageReporters": ["text", "lcov", "clover"],
"coverageThreshold": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": -10
}
}
}
}
58 changes: 58 additions & 0 deletions src/interfaces/chatbot-engine.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Custom error types for Chatbot Engine
*/
export class ChatbotEngineError extends Error {
constructor(
message: string,
public code?: string,
public retryAfter?: number
) {
super(message);
this.name = 'ChatbotEngineError';
}
}

export interface ChatContext {
conversationHistory: string[];
maxTokens?: number;
agentProfile?: string;
}

export interface ChatbotEngineAdapter {
/**
* Generate a response based on a given profile and conversation context
* @param profileId Identifier of the agent's personality
* @param context Current conversation context
* @returns Generated response string
* @throws {ChatbotEngineError} For generation failures
*/
generateResponse(
profileId: string,
context: ChatContext
): Promise<{
response: string;
tokenCount: number;
generationTime: number;
}>;

/**
* Check current backend availability and connection status
* @returns Detailed health check result
*/
healthCheck(): Promise<{
isHealthy: boolean;
backendVersion: string;
responseTime: number;
supportedProfiles: string[];
}>;

/**
* Estimate token usage for a given context
* @param context Conversation context
* @returns Token estimation details
*/
estimateTokenUsage(context: ChatContext): {
inputTokens: number;
estimatedResponseTokens: number;
};
}
78 changes: 78 additions & 0 deletions src/interfaces/conversation-orchestrator.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Custom error types for Conversation Orchestrator
*/
export class ConversationOrchestrationError extends Error {
constructor(
message: string,
public code?: string,
public retryContext?: any
) {
super(message);
this.name = 'ConversationOrchestrationError';
}
}

export interface AgentReply {
agentId: string;
message: string;
timestamp: number;
confidence?: number;
}

export interface ConversationSession {
sessionId: string;
agents: string[];
history: AgentReply[];
createdAt: number;
lastActivityAt: number;
}

export interface ConversationOrchestrator {
/**
* Initialize a new conversation session
* @param agents List of agent profile IDs to participate
* @param initialContext Optional starting context
* @returns Unique session identifier
* @throws {ConversationOrchestrationError} If session creation fails
*/
createSession(
agents: string[],
initialContext?: Record<string, any>
): Promise<{
sessionId: string;
initialState: ConversationSession;
}>;

/**
* Handle an incoming user message
* @param sessionId Active conversation session
* @param userMessage User's input message
* @returns Detailed agent replies
* @throws {ConversationOrchestrationError} For routing or generation failures
*/
handleMessage(
sessionId: string,
userMessage: string
): Promise<{
replies: AgentReply[];
sessionState: ConversationSession;
}>;

/**
* Retrieve current conversation session state
* @param sessionId Session to retrieve
* @returns Complete conversation session details
*/
getSessionState(sessionId: string): Promise<ConversationSession>;

/**
* Close an active conversation session
* @param sessionId Session to close
* @returns Closure summary
*/
closeSession(sessionId: string): Promise<{
sessionId: string;
duration: number;
messageCount: number;
}>;
}
51 changes: 51 additions & 0 deletions src/interfaces/personality-manager.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Custom error types for Personality Manager
*/
export class PersonalityProfileError extends Error {
constructor(message: string, public code?: string) {
super(message);
this.name = 'PersonalityProfileError';
}
}

export interface PersonalityProfile {
id: string;
name: string;
tone: string;
samplePrompts: string[];
version: string;
}

export interface PersonalityDataManager {
/**
* Load a personality profile by its unique identifier
* @param id Profile identifier
* @returns Loaded PersonalityProfile
* @throws {PersonalityProfileError} If profile cannot be loaded
*/
loadProfile(id: string): Promise<PersonalityProfile>;

/**
* Validate a personality profile thoroughly
* @param profile Profile to validate
* @returns Validation result with optional error details
*/
validateProfile(profile: PersonalityProfile): {
isValid: boolean;
errors?: string[];
};

/**
* Save a new or updated personality profile
* @param profile Profile to save
* @returns Version identifier of saved profile
* @throws {PersonalityProfileError} If save fails
*/
saveProfile(profile: PersonalityProfile): Promise<string>;

/**
* List all available personality profiles
* @returns Array of profile metadata
*/
listProfiles(): Promise<PersonalityProfile[]>;
}
69 changes: 69 additions & 0 deletions src/interfaces/schemas.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"PersonalityProfile": {
"type": "object",
"required": ["id", "name", "tone", "samplePrompts", "version"],
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the personality profile"
},
"name": {
"type": "string",
"description": "Name of the personality"
},
"tone": {
"type": "string",
"description": "Characterization of the personality's communication style"
},
"samplePrompts": {
"type": "array",
"items": {
"type": "string"
},
"description": "Example prompts for the personality"
},
"version": {
"type": "string",
"description": "Version identifier of the profile"
}
}
},
"ChatContext": {
"type": "object",
"required": ["conversationHistory"],
"properties": {
"conversationHistory": {
"type": "array",
"items": {
"type": "string"
},
"description": "Chronological conversation messages"
},
"maxTokens": {
"type": "number",
"description": "Maximum token limit for response generation"
}
}
},
"AgentReply": {
"type": "object",
"required": ["agentId", "message", "timestamp"],
"properties": {
"agentId": {
"type": "string",
"description": "Unique identifier of the responding agent"
},
"message": {
"type": "string",
"description": "Generated response message"
},
"timestamp": {
"type": "number",
"description": "Unix timestamp of the reply"
}
}
}
}
}
84 changes: 84 additions & 0 deletions src/tests/chatbot-engine.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
ChatbotEngineAdapter,
ChatContext,
ChatbotEngineError
} from '../interfaces/chatbot-engine.interface';
import { schemaValidator } from '../utils/schema-validator';

// Mock implementation for testing
class MockChatbotEngineAdapter implements ChatbotEngineAdapter {
async generateResponse(profileId: string, context: ChatContext) {
const validation = schemaValidator.validate('ChatContext', context);
if (!validation.isValid) {
throw new ChatbotEngineError('Invalid context', 'INVALID_CONTEXT');
}

return {
response: `Response for ${profileId}: ${context.conversationHistory.join(' ')}`,
tokenCount: context.conversationHistory.join(' ').length,
generationTime: 100
};
}

async healthCheck() {
return {
isHealthy: true,
backendVersion: '1.0.0',
responseTime: 50,
supportedProfiles: ['jesus', 'peter', 'john']
};
}

estimateTokenUsage(context: ChatContext) {
return {
inputTokens: context.conversationHistory.join(' ').length,
estimatedResponseTokens: 100
};
}
}

describe('ChatbotEngineAdapter', () => {
let engine: ChatbotEngineAdapter;

beforeEach(() => {
engine = new MockChatbotEngineAdapter();
});

test('should generate response with valid context', async () => {
const context: ChatContext = {
conversationHistory: ['Hello', 'How are you?'],
maxTokens: 100
};

const result = await engine.generateResponse('jesus', context);
expect(result.response).toContain('Response for jesus');
expect(result.tokenCount).toBeGreaterThan(0);
});

test('should perform health check', async () => {
const health = await engine.healthCheck();
expect(health.isHealthy).toBe(true);
expect(health.backendVersion).toBe('1.0.0');
});

test('should estimate token usage', () => {
const context: ChatContext = {
conversationHistory: ['Test message'],
maxTokens: 50
};

const tokenUsage = engine.estimateTokenUsage(context);
expect(tokenUsage.inputTokens).toBeGreaterThan(0);
expect(tokenUsage.estimatedResponseTokens).toBe(100);
});

test('should throw error for invalid context', async () => {
const invalidContext = {
conversationHistory: null // Invalid input
};

await expect(
engine.generateResponse('jesus', invalidContext as ChatContext)
).rejects.toThrow(ChatbotEngineError);
});
});
Loading