Skip to content

Commit c0c85c1

Browse files
committed
test suite
1 parent a7f4697 commit c0c85c1

22 files changed

+2148
-608
lines changed

README.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -615,4 +615,11 @@ const agent = new Agent({
615615

616616
## License
617617

618-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
618+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
619+
620+
## Documentation
621+
622+
- [API Reference](./API.md) - Detailed API documentation
623+
- [Creating Integrations](./docs/creating-integrations.md) - Guide for creating new integrations
624+
- [Contributing Guidelines](./CONTRIBUTING.md) - How to contribute to the project
625+
- [Changelog](./CHANGELOG.md) - Version history and changes

docs/creating-integrations.md

+345
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
# Creating New Integrations
2+
3+
This guide will walk you through the process of creating new integrations for the Replicant framework. Whether you're adding support for a new platform, AI provider, or custom functionality, this guide will help you understand the integration process.
4+
5+
## Table of Contents
6+
- [Overview](#overview)
7+
- [Types of Integrations](#types-of-integrations)
8+
- [Basic Integration Structure](#basic-integration-structure)
9+
- [Step-by-Step Guide](#step-by-step-guide)
10+
- [Best Practices](#best-practices)
11+
- [Examples](#examples)
12+
13+
## Overview
14+
15+
Replicant uses a plugin-based architecture where each integration implements the `Plugin` interface and can optionally extend additional base classes or interfaces based on its functionality.
16+
17+
## Types of Integrations
18+
19+
1. **Platform Integrations**
20+
- Messaging platforms (Discord, Telegram, etc.)
21+
- Social media platforms (Twitter, etc.)
22+
- Custom communication channels
23+
24+
2. **AI Provider Integrations**
25+
- Language model providers
26+
- Specialized AI services
27+
- Custom AI implementations
28+
29+
3. **State Provider Integrations**
30+
- Database integrations
31+
- Memory management systems
32+
- Custom state handlers
33+
34+
## Basic Integration Structure
35+
36+
Every integration must implement the `Plugin` interface:
37+
38+
```typescript
39+
interface Plugin {
40+
readonly name: string; // Unique identifier for the plugin
41+
readonly version: string; // Plugin version number
42+
readonly type: string; // Plugin type (e.g., 'messaging', 'ai', 'storage')
43+
44+
initialize(): Promise<void>; // Setup code
45+
shutdown(): Promise<void>; // Cleanup code
46+
setAgent(agent: Agent): void; // Reference to main agent
47+
}
48+
```
49+
50+
## Step-by-Step Guide
51+
52+
### 1. Create the Integration Class
53+
54+
Start by creating a new class that implements the `Plugin` interface:
55+
56+
```typescript
57+
import { Plugin, ReplicantConfig } from '../../core/interfaces';
58+
import { EventEmitter } from 'events';
59+
import { Message } from '../../core/types';
60+
61+
// Define configuration interface
62+
export interface MyIntegrationConfig extends ReplicantConfig {
63+
apiKey: string;
64+
endpoint?: string;
65+
// Add other configuration options
66+
}
67+
68+
export class MyIntegration extends EventEmitter implements Plugin {
69+
private agent?: Agent;
70+
71+
public readonly name = 'my-integration';
72+
public readonly version = '1.0.0';
73+
public readonly type = 'custom';
74+
75+
constructor(config: MyIntegrationConfig) {
76+
super();
77+
// Initialize your integration
78+
}
79+
80+
setAgent(agent: Agent): void {
81+
this.agent = agent;
82+
}
83+
84+
async initialize(): Promise<void> {
85+
// Setup code
86+
}
87+
88+
async shutdown(): Promise<void> {
89+
// Cleanup code
90+
}
91+
}
92+
```
93+
94+
### 2. Add Message Handling
95+
96+
If your integration deals with messages, implement message handling:
97+
98+
```typescript
99+
export class MyIntegration extends EventEmitter implements Plugin {
100+
// ... previous code ...
101+
102+
async processMessage(message: Message): Promise<void> {
103+
// Handle outgoing messages
104+
try {
105+
await this.sendToExternalService(message);
106+
} catch (error) {
107+
console.error('Error processing message:', error);
108+
throw error;
109+
}
110+
}
111+
112+
private async handleIncomingMessage(rawMessage: any): Promise<void> {
113+
// Convert external message format to Replicant Message type
114+
const message: Message = {
115+
role: 'user',
116+
content: rawMessage.text,
117+
metadata: {
118+
platform: this.name,
119+
messageId: rawMessage.id,
120+
userId: rawMessage.sender,
121+
timestamp: new Date().toISOString()
122+
}
123+
};
124+
125+
// Emit message event for the agent to handle
126+
this.emit('message', message);
127+
}
128+
}
129+
```
130+
131+
### 3. Implement Error Handling
132+
133+
Add proper error handling and logging:
134+
135+
```typescript
136+
export class MyIntegration extends EventEmitter implements Plugin {
137+
// ... previous code ...
138+
139+
private async handleError(error: Error, context: string): Promise<void> {
140+
console.error(`[${this.name}] Error in ${context}:`, error);
141+
142+
// Emit error event
143+
this.emit('error', {
144+
integration: this.name,
145+
context,
146+
error,
147+
timestamp: new Date().toISOString()
148+
});
149+
150+
// Optionally attempt recovery
151+
await this.attemptRecovery(context);
152+
}
153+
154+
private async attemptRecovery(context: string): Promise<void> {
155+
// Implement recovery logic
156+
try {
157+
// Example: Reconnect to service
158+
await this.reconnect();
159+
} catch (error) {
160+
console.error(`[${this.name}] Recovery failed:`, error);
161+
}
162+
}
163+
}
164+
```
165+
166+
### 4. Add State Management
167+
168+
If your integration needs to maintain state:
169+
170+
```typescript
171+
export class MyIntegration extends EventEmitter implements Plugin {
172+
private state: Map<string, any> = new Map();
173+
174+
// ... previous code ...
175+
176+
async saveState(key: string, value: any): Promise<void> {
177+
this.state.set(key, value);
178+
// Optionally persist to external storage
179+
}
180+
181+
async loadState(key: string): Promise<any> {
182+
return this.state.get(key);
183+
}
184+
185+
async clearState(): Promise<void> {
186+
this.state.clear();
187+
}
188+
}
189+
```
190+
191+
### 5. Register Event Handlers
192+
193+
Set up event handling in the initialize method:
194+
195+
```typescript
196+
export class MyIntegration extends EventEmitter implements Plugin {
197+
// ... previous code ...
198+
199+
async initialize(): Promise<void> {
200+
// Set up event listeners
201+
this.on('message', this.handleMessage.bind(this));
202+
this.on('error', this.handleError.bind(this));
203+
204+
// Initialize external service connection
205+
await this.connect();
206+
207+
// Start any necessary background tasks
208+
this.startBackgroundTasks();
209+
}
210+
211+
private startBackgroundTasks(): void {
212+
// Example: Set up periodic checks
213+
setInterval(() => {
214+
this.checkForUpdates();
215+
}, 60000);
216+
}
217+
}
218+
```
219+
220+
## Best Practices
221+
222+
1. **Error Handling**
223+
- Always implement proper error handling
224+
- Use typed errors for different failure modes
225+
- Provide meaningful error messages
226+
- Implement recovery mechanisms
227+
228+
2. **Event Management**
229+
- Use TypeScript for event type safety
230+
- Document all emitted events
231+
- Clean up event listeners in shutdown
232+
233+
3. **State Management**
234+
- Keep state isolated and encapsulated
235+
- Implement proper cleanup
236+
- Handle state persistence if needed
237+
238+
4. **Testing**
239+
- Write unit tests for your integration
240+
- Implement mock services for testing
241+
- Test error conditions and recovery
242+
243+
Example test structure:
244+
245+
```typescript
246+
describe('MyIntegration', () => {
247+
let integration: MyIntegration;
248+
let mockAgent: Agent;
249+
250+
beforeEach(() => {
251+
mockAgent = TestUtils.createMockAgent();
252+
integration = new MyIntegration({
253+
domain: 'test',
254+
userId: 'test-user',
255+
platform: 'test',
256+
apiKey: 'test-key'
257+
});
258+
integration.setAgent(mockAgent);
259+
});
260+
261+
it('should handle messages correctly', async () => {
262+
const message: Message = {
263+
role: 'user',
264+
content: 'test message'
265+
};
266+
267+
await integration.processMessage(message);
268+
// Add assertions
269+
});
270+
271+
it('should recover from errors', async () => {
272+
// Test error recovery
273+
});
274+
});
275+
```
276+
277+
## Examples
278+
279+
### Messaging Platform Integration
280+
281+
```typescript
282+
import { Plugin, Message } from '../../core/interfaces';
283+
import { EventEmitter } from 'events';
284+
285+
export class MessagingIntegration extends EventEmitter implements Plugin {
286+
public readonly type = 'messaging';
287+
288+
async initialize(): Promise<void> {
289+
// Connect to messaging platform
290+
await this.connect();
291+
292+
// Set up message handlers
293+
this.platform.on('message', async (rawMessage) => {
294+
const message = this.convertMessage(rawMessage);
295+
this.emit('message', message);
296+
});
297+
}
298+
299+
async processMessage(message: Message): Promise<void> {
300+
// Send message to platform
301+
await this.platform.send(message);
302+
}
303+
}
304+
```
305+
306+
### AI Provider Integration
307+
308+
```typescript
309+
import { Plugin, AIProvider } from '../../core/interfaces';
310+
311+
export class CustomAIProvider implements Plugin, AIProvider {
312+
public readonly type = 'ai';
313+
314+
async processMessage(message: Message, context: ModelContextProtocol): Promise<AIResponse> {
315+
// Process message with AI service
316+
const response = await this.ai.generate(message, context);
317+
318+
return {
319+
role: 'assistant',
320+
content: response.text,
321+
metadata: response.metadata
322+
};
323+
}
324+
}
325+
```
326+
327+
### Storage Integration
328+
329+
```typescript
330+
import { Plugin, StorageProvider } from '../../core/interfaces';
331+
332+
export class CustomStorageProvider implements Plugin, StorageProvider {
333+
public readonly type = 'storage';
334+
335+
async saveState(state: ConversationStateData): Promise<void> {
336+
// Save state to storage
337+
await this.storage.save(state);
338+
}
339+
340+
async loadState(id: string): Promise<ConversationStateData | null> {
341+
// Load state from storage
342+
return await this.storage.load(id);
343+
}
344+
}
345+
```

package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)