@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
206 lines (204 loc) • 7.23 kB
JavaScript
class ConversationContextManager {
constructor(config = {}) {
this.conversations = new Map();
this.config = {
maxMessages: 20,
maxTokens: 4000,
retainSystemMessages: true,
contextTimeoutMs: 30 * 60 * 1000, // 30 minutes
...config,
};
}
createConversation(id, systemPrompt) {
const context = {
id,
messages: [],
createdAt: new Date(),
updatedAt: new Date(),
metadata: {},
};
if (systemPrompt) {
context.messages.push({
id: this.generateMessageId(),
role: "system",
content: systemPrompt,
timestamp: new Date(),
});
}
this.conversations.set(id, context);
return context;
}
getConversation(id) {
const conversation = this.conversations.get(id);
if (!conversation) {
return null;
}
// Check if conversation has expired
if (this.config.contextTimeoutMs) {
const now = Date.now();
const lastUpdate = conversation.updatedAt.getTime();
if (now - lastUpdate > this.config.contextTimeoutMs) {
this.conversations.delete(id);
return null;
}
}
return conversation;
}
addMessage(conversationId, message) {
let conversation = this.getConversation(conversationId);
if (!conversation) {
// Create new conversation if it doesn't exist
conversation = this.createConversation(conversationId);
}
const chatMessage = {
...message,
id: this.generateMessageId(),
timestamp: new Date(),
};
conversation.messages.push(chatMessage);
conversation.updatedAt = new Date();
// Trim conversation if it exceeds limits
this.trimConversation(conversation);
return chatMessage;
}
updateMessage(conversationId, messageId, updates) {
const conversation = this.getConversation(conversationId);
if (!conversation) {
return false;
}
const messageIndex = conversation.messages.findIndex((msg) => msg.id === messageId);
if (messageIndex === -1) {
return false;
}
conversation.messages[messageIndex] = {
...conversation.messages[messageIndex],
...updates,
updatedAt: new Date(),
};
conversation.updatedAt = new Date();
return true;
}
getConversationHistory(conversationId, lastN) {
const conversation = this.getConversation(conversationId);
if (!conversation) {
return [];
}
const messages = conversation.messages;
if (lastN && lastN > 0) {
return messages.slice(-lastN);
}
return messages;
}
getConversationSummary(conversationId) {
const conversation = this.getConversation(conversationId);
if (!conversation) {
return null;
}
const summary = {
totalMessages: conversation.messages.length,
userMessages: 0,
assistantMessages: 0,
systemMessages: 0,
totalTokens: 0,
};
for (const message of conversation.messages) {
switch (message.role) {
case "user":
summary.userMessages++;
break;
case "assistant":
summary.assistantMessages++;
break;
case "system":
summary.systemMessages++;
break;
}
// Simple token estimation (4 chars ≈ 1 token)
summary.totalTokens += Math.ceil(message.content.length / 4);
}
return summary;
}
clearConversation(conversationId) {
return this.conversations.delete(conversationId);
}
getAllConversations() {
return Array.from(this.conversations.values());
}
cleanupExpiredConversations() {
if (!this.config.contextTimeoutMs) {
return 0;
}
const now = Date.now();
let cleaned = 0;
for (const [id, conversation] of this.conversations) {
const lastUpdate = conversation.updatedAt.getTime();
if (now - lastUpdate > this.config.contextTimeoutMs) {
this.conversations.delete(id);
cleaned++;
}
}
return cleaned;
}
trimConversation(conversation) {
const messages = conversation.messages;
// Separate system messages from conversation messages
const systemMessages = messages.filter((msg) => msg.role === "system");
const conversationMessages = messages.filter((msg) => msg.role !== "system");
// Trim by message count
if (conversationMessages.length > this.config.maxMessages) {
const keepCount = this.config.maxMessages;
conversationMessages.splice(0, conversationMessages.length - keepCount);
}
// Trim by token count if specified
if (this.config.maxTokens) {
let totalTokens = 0;
const trimmedMessages = [];
// Count tokens from the end (most recent messages)
for (let i = conversationMessages.length - 1; i >= 0; i--) {
const messageTokens = Math.ceil(conversationMessages[i].content.length / 4);
if (totalTokens + messageTokens <= this.config.maxTokens) {
trimmedMessages.unshift(conversationMessages[i]);
totalTokens += messageTokens;
}
else {
break;
}
}
conversationMessages.splice(0, conversationMessages.length, ...trimmedMessages);
}
// Reconstruct conversation with system messages
if (this.config.retainSystemMessages) {
conversation.messages = [...systemMessages, ...conversationMessages];
}
else {
conversation.messages = conversationMessages;
}
}
generateMessageId() {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// Update conversation metadata
updateConversationMetadata(conversationId, metadata) {
const conversation = this.getConversation(conversationId);
if (!conversation) {
return false;
}
conversation.metadata = { ...conversation.metadata, ...metadata };
conversation.updatedAt = new Date();
return true;
}
// Get statistics
getManagerStats() {
let totalMessages = 0;
for (const conversation of this.conversations.values()) {
totalMessages += conversation.messages.length;
}
return {
totalConversations: this.conversations.size,
totalMessages,
config: this.config,
};
}
}
export { ConversationContextManager };
//# sourceMappingURL=context-manager.js.map