92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
/**
|
|
* E2E Tests for LettaBot
|
|
*
|
|
* These tests use a real Letta API agent to verify the full message flow.
|
|
* Requires LETTA_API_KEY and LETTA_E2E_AGENT_ID environment variables.
|
|
*
|
|
* Run with: npm run test:e2e
|
|
*/
|
|
|
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
import { LettaBot } from '../src/core/bot.js';
|
|
import { MockChannelAdapter } from '../src/test/mock-channel.js';
|
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
|
|
// Skip if no API key (local dev without secrets)
|
|
const SKIP_E2E = !process.env.LETTA_API_KEY || !process.env.LETTA_E2E_AGENT_ID;
|
|
|
|
describe.skipIf(SKIP_E2E)('e2e: LettaBot with Letta API', () => {
|
|
let bot: LettaBot;
|
|
let mockAdapter: MockChannelAdapter;
|
|
let tempDir: string;
|
|
|
|
beforeAll(async () => {
|
|
// Create temp directory for test data
|
|
tempDir = mkdtempSync(join(tmpdir(), 'lettabot-e2e-'));
|
|
|
|
// Set agent ID from secrets
|
|
process.env.LETTA_AGENT_ID = process.env.LETTA_E2E_AGENT_ID;
|
|
|
|
// Initialize bot with test config
|
|
bot = new LettaBot({
|
|
workingDir: tempDir,
|
|
agentName: 'e2e-test',
|
|
});
|
|
|
|
// Register mock channel
|
|
mockAdapter = new MockChannelAdapter();
|
|
bot.registerChannel(mockAdapter);
|
|
|
|
console.log('[E2E] Bot initialized with agent:', process.env.LETTA_E2E_AGENT_ID);
|
|
}, 30000); // 30s timeout for setup
|
|
|
|
afterAll(async () => {
|
|
// Cleanup temp directory
|
|
try {
|
|
rmSync(tempDir, { recursive: true, force: true });
|
|
} catch {
|
|
// Ignore cleanup errors
|
|
}
|
|
});
|
|
|
|
it('responds to a simple message', async () => {
|
|
const response = await mockAdapter.simulateMessage('Say "E2E TEST OK" and nothing else.');
|
|
|
|
expect(response).toBeTruthy();
|
|
expect(response.length).toBeGreaterThan(0);
|
|
// The agent should respond with something containing our test phrase
|
|
expect(response.toUpperCase()).toContain('E2E TEST OK');
|
|
}, 60000); // 60s timeout
|
|
|
|
it('handles /status command', async () => {
|
|
const response = await mockAdapter.simulateMessage('/status');
|
|
|
|
expect(response).toBeTruthy();
|
|
// Status should contain agent info
|
|
expect(response).toMatch(/agent|status/i);
|
|
}, 30000);
|
|
|
|
it('handles /help command', async () => {
|
|
const response = await mockAdapter.simulateMessage('/help');
|
|
|
|
expect(response).toBeTruthy();
|
|
expect(response).toContain('LettaBot');
|
|
expect(response).toContain('/status');
|
|
}, 10000);
|
|
|
|
it('maintains conversation context', async () => {
|
|
// First message - set context
|
|
await mockAdapter.simulateMessage('Remember this number: 42424242');
|
|
|
|
// Clear messages but keep session
|
|
mockAdapter.clearMessages();
|
|
|
|
// Second message - recall context
|
|
const response = await mockAdapter.simulateMessage('What number did I just tell you to remember?');
|
|
|
|
expect(response).toContain('42424242');
|
|
}, 120000); // 2 min timeout for multi-turn
|
|
});
|