Files
wifi-densepose/vendor/ruvector/npm/packages/ruvllm/src/session.ts

239 lines
5.8 KiB
TypeScript

/**
* Session Management for multi-turn conversations
*/
import {
ConversationSession,
ConversationMessage,
QueryResponse,
GenerationConfig,
} from './types';
/**
* Session Manager for multi-turn conversations
*
* @example
* ```typescript
* import { RuvLLM, SessionManager } from '@ruvector/ruvllm';
*
* const llm = new RuvLLM();
* const sessions = new SessionManager(llm);
*
* // Create a new session
* const session = sessions.create();
*
* // Chat with context
* const response1 = sessions.chat(session.id, 'What is Python?');
* const response2 = sessions.chat(session.id, 'How do I install it?');
* // Second query automatically has context from first
* ```
*/
export class SessionManager {
private sessions: Map<string, ConversationSession> = new Map();
private llm: { query: (text: string, config?: GenerationConfig) => QueryResponse; addMemory: (content: string, metadata?: Record<string, unknown>) => number };
constructor(llm: { query: (text: string, config?: GenerationConfig) => QueryResponse; addMemory: (content: string, metadata?: Record<string, unknown>) => number }) {
this.llm = llm;
}
/**
* Create a new conversation session
*/
create(metadata?: Record<string, unknown>): ConversationSession {
const id = `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
const session: ConversationSession = {
id,
createdAt: new Date(),
messageCount: 0,
messages: [],
context: [],
activeMemoryIds: [],
metadata: metadata ?? {},
};
this.sessions.set(id, session);
return session;
}
/**
* Get session by ID
*/
get(sessionId: string): ConversationSession | undefined {
return this.sessions.get(sessionId);
}
/**
* Chat within a session (maintains context)
*/
chat(sessionId: string, message: string, config?: GenerationConfig): QueryResponse {
const session = this.sessions.get(sessionId);
if (!session) {
throw new Error(`Session not found: ${sessionId}`);
}
// Add user message
session.messages.push({
role: 'user',
content: message,
timestamp: new Date(),
});
// Build context from recent messages
const contextWindow = this.buildContext(session);
// Query with context
const prompt = contextWindow ? `${contextWindow}\n\nUser: ${message}` : message;
const response = this.llm.query(prompt, config);
// Add assistant response
session.messages.push({
role: 'assistant',
content: response.text,
timestamp: new Date(),
requestId: response.requestId,
});
session.messageCount = session.messages.length;
return response;
}
/**
* Add system message to session
*/
addSystemMessage(sessionId: string, content: string): void {
const session = this.sessions.get(sessionId);
if (!session) {
throw new Error(`Session not found: ${sessionId}`);
}
session.messages.push({
role: 'system',
content,
timestamp: new Date(),
});
session.messageCount = session.messages.length;
}
/**
* Add context to session (persisted to memory)
*/
addContext(sessionId: string, context: string): number {
const session = this.sessions.get(sessionId);
if (!session) {
throw new Error(`Session not found: ${sessionId}`);
}
session.context.push(context);
// Also store in memory for retrieval
const memoryId = this.llm.addMemory(context, {
sessionId,
type: 'context',
timestamp: new Date().toISOString(),
});
session.activeMemoryIds.push(memoryId);
return memoryId;
}
/**
* Get conversation history
*/
getHistory(sessionId: string, limit?: number): ConversationMessage[] {
const session = this.sessions.get(sessionId);
if (!session) {
return [];
}
const messages = session.messages;
return limit ? messages.slice(-limit) : messages;
}
/**
* Clear session history (keep session active)
*/
clearHistory(sessionId: string): void {
const session = this.sessions.get(sessionId);
if (session) {
session.messages = [];
session.context = [];
session.messageCount = 0;
}
}
/**
* End and delete session
*/
end(sessionId: string): boolean {
return this.sessions.delete(sessionId);
}
/**
* List all active sessions
*/
list(): ConversationSession[] {
return Array.from(this.sessions.values());
}
/**
* Export session as JSON
*/
export(sessionId: string): string | null {
const session = this.sessions.get(sessionId);
if (!session) {
return null;
}
return JSON.stringify(session, null, 2);
}
/**
* Import session from JSON
*/
import(json: string): ConversationSession {
const data = JSON.parse(json);
const session: ConversationSession = {
...data,
createdAt: new Date(data.createdAt),
messages: data.messages.map((m: ConversationMessage) => ({
...m,
timestamp: new Date(m.timestamp),
})),
};
this.sessions.set(session.id, session);
return session;
}
/**
* Build context string from recent messages
*/
private buildContext(session: ConversationSession, maxMessages = 10): string {
const recent = session.messages.slice(-maxMessages);
if (recent.length === 0) {
return '';
}
const contextParts: string[] = [];
// Add persistent context
if (session.context.length > 0) {
contextParts.push('Context:\n' + session.context.join('\n'));
}
// Add conversation history
const history = recent
.map(m => {
const role = m.role === 'user' ? 'User' : m.role === 'assistant' ? 'Assistant' : 'System';
return `${role}: ${m.content}`;
})
.join('\n');
if (history) {
contextParts.push('Conversation:\n' + history);
}
return contextParts.join('\n\n');
}
}