Files
SuperCharged-Claude-Code-Up…/dexto/packages/core/src/session/session-manager.integration.test.ts
admin b52318eeae feat: Add intelligent auto-router and enhanced integrations
- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-28 00:27:56 +04:00

220 lines
9.0 KiB
TypeScript

import { describe, test, expect, beforeEach, afterEach } from 'vitest';
import { DextoAgent } from '../agent/DextoAgent.js';
import type { AgentConfig } from '@core/agent/schemas.js';
import type { SessionData } from './session-manager.js';
/**
* Full end-to-end integration tests for chat history preservation.
* Tests the complete flow from DextoAgent -> SessionManager -> ChatSession -> Storage
*/
describe('Session Integration: Chat History Preservation', () => {
let agent: DextoAgent;
const testConfig: AgentConfig = {
systemPrompt: 'You are a helpful assistant.',
llm: {
provider: 'openai',
model: 'gpt-5-mini',
apiKey: 'test-key-123',
},
mcpServers: {},
sessions: {
maxSessions: 10,
sessionTTL: 100, // 100ms for fast testing
},
toolConfirmation: {
mode: 'auto-approve',
timeout: 120000,
},
elicitation: {
enabled: false,
timeout: 120000,
},
};
beforeEach(async () => {
agent = new DextoAgent(testConfig);
await agent.start();
});
afterEach(async () => {
if (agent.isStarted()) {
await agent.stop();
}
});
test('full integration: chat history survives session expiry through DextoAgent', async () => {
const sessionId = 'integration-test-session';
// Step 1: Create session through DextoAgent
const session = await agent.createSession(sessionId);
expect(session.id).toBe(sessionId);
// Step 2: Simulate adding messages to the session
// In a real scenario, this would happen through agent.run() calls
// For testing, we'll access the underlying storage directly
const storage = agent.services.storageManager;
const messagesKey = `messages:${sessionId}`;
const chatHistory = [
{ role: 'user', content: 'What is 2+2?' },
{ role: 'assistant', content: '2+2 equals 4.' },
{ role: 'user', content: 'Thank you!' },
{
role: 'assistant',
content: "You're welcome! Is there anything else I can help you with?",
},
];
await storage.getDatabase().set(messagesKey, chatHistory);
// Step 3: Verify session exists and has history
const activeSession = await agent.getSession(sessionId);
expect(activeSession).toBeDefined();
expect(activeSession!.id).toBe(sessionId);
const storedHistory = await storage.getDatabase().get(messagesKey);
expect(storedHistory).toEqual(chatHistory);
// Step 4: Force session expiry by manipulating lastActivity timestamp
await new Promise((resolve) => setTimeout(resolve, 150)); // Wait > TTL
const sessionKey = `session:${sessionId}`;
const sessionData = await storage.getDatabase().get<SessionData>(sessionKey);
if (sessionData) {
sessionData.lastActivity = Date.now() - 200; // Mark as expired
await storage.getDatabase().set(sessionKey, sessionData);
}
// Access private method to manually trigger cleanup for testing session expiry behavior
const sessionManager = agent.sessionManager;
await (sessionManager as any).cleanupExpiredSessions();
// Step 5: Verify session is removed from memory but preserved in storage
const sessionsMap = (sessionManager as any).sessions;
expect(sessionsMap.has(sessionId)).toBe(false);
// But storage should still have both session metadata and chat history
expect(await storage.getDatabase().get(sessionKey)).toBeDefined();
expect(await storage.getDatabase().get(messagesKey)).toEqual(chatHistory);
// Step 6: Access session again through DextoAgent - should restore seamlessly
const restoredSession = await agent.getSession(sessionId);
expect(restoredSession).toBeDefined();
expect(restoredSession!.id).toBe(sessionId);
// Session should be back in memory
expect(sessionsMap.has(sessionId)).toBe(true);
// Chat history should still be intact
const restoredHistory = await storage.getDatabase().get(messagesKey);
expect(restoredHistory).toEqual(chatHistory);
// Step 7: Verify we can continue the conversation
const newMessage = { role: 'user', content: 'One more question: what is 3+3?' };
await storage.getDatabase().set(messagesKey, [...chatHistory, newMessage]);
const finalHistory = await storage.getDatabase().get<any[]>(messagesKey);
expect(finalHistory).toBeDefined();
expect(finalHistory!).toHaveLength(5);
expect(finalHistory![4]).toEqual(newMessage);
});
test('full integration: explicit session deletion removes everything', async () => {
const sessionId = 'deletion-test-session';
// Create session and add history
await agent.createSession(sessionId);
const storage = agent.services.storageManager;
const messagesKey = `messages:${sessionId}`;
const sessionKey = `session:${sessionId}`;
const history = [{ role: 'user', content: 'Hello!' }];
await storage.getDatabase().set(messagesKey, history);
// Verify everything exists
expect(await agent.getSession(sessionId)).toBeDefined();
expect(await storage.getDatabase().get(sessionKey)).toBeDefined();
expect(await storage.getDatabase().get(messagesKey)).toEqual(history);
// Delete session through DextoAgent
await agent.deleteSession(sessionId);
// Everything should be gone including chat history
const deletedSession = await agent.getSession(sessionId);
expect(deletedSession).toBeUndefined();
expect(await storage.getDatabase().get(sessionKey)).toBeUndefined();
expect(await storage.getDatabase().get(messagesKey)).toBeUndefined();
});
test('full integration: multiple concurrent sessions with independent histories', async () => {
const sessionIds = ['concurrent-1', 'concurrent-2', 'concurrent-3'];
const histories = sessionIds.map((_, index) => [
{ role: 'user', content: `Message from session ${index + 1}` },
{ role: 'assistant', content: `Response to session ${index + 1}` },
]);
// Create multiple sessions with different histories
const storage = agent.services.storageManager;
for (let i = 0; i < sessionIds.length; i++) {
await agent.createSession(sessionIds[i]);
await storage.getDatabase().set(`messages:${sessionIds[i]}`, histories[i]);
}
// Verify all sessions exist and have correct histories
for (let i = 0; i < sessionIds.length; i++) {
const sessionId = sessionIds[i]!;
const session = await agent.getSession(sessionId);
expect(session).toBeDefined();
expect(session!.id).toBe(sessionId);
const history = await storage.getDatabase().get(`messages:${sessionId}`);
expect(history).toEqual(histories[i]);
}
// Force expiry and cleanup for all sessions
await new Promise((resolve) => setTimeout(resolve, 150));
for (const sessionId of sessionIds) {
const sessionData = await storage
.getDatabase()
.get<SessionData>(`session:${sessionId}`);
if (sessionData) {
sessionData.lastActivity = Date.now() - 200;
await storage.getDatabase().set(`session:${sessionId}`, sessionData);
}
}
const sessionManager = agent.sessionManager;
await (sessionManager as any).cleanupExpiredSessions();
// All should be removed from memory
const sessionsMap = (sessionManager as any).sessions;
sessionIds.forEach((id) => {
expect(sessionsMap.has(id)).toBe(false);
});
// But histories should be preserved in storage
for (let i = 0; i < sessionIds.length; i++) {
const history = await storage.getDatabase().get(`messages:${sessionIds[i]}`);
expect(history).toEqual(histories[i]);
}
// Restore sessions one by one and verify independent operation
for (let i = 0; i < sessionIds.length; i++) {
const sessionId = sessionIds[i]!;
const restoredSession = await agent.getSession(sessionId);
expect(restoredSession).toBeDefined();
expect(restoredSession!.id).toBe(sessionId);
// Verify the session is back in memory
expect(sessionsMap.has(sessionId)).toBe(true);
// Verify history is still intact and independent
const history = await storage.getDatabase().get(`messages:${sessionId}`);
expect(history).toEqual(histories[i]);
}
});
// Note: Activity-based expiry prevention test removed due to timing complexities
// The core functionality (chat history preservation) is thoroughly tested above
});