File size: 3,811 Bytes
5fc68b0 5c221d7 5fc68b0 136f9cf 5fc68b0 136f9cf 5fc68b0 136f9cf 5fc68b0 5c221d7 5fc68b0 136f9cf 5fc68b0 136f9cf 5fc68b0 136f9cf 5fc68b0 620331c 136f9cf 5fc68b0 620331c 5fc68b0 5c221d7 5fc68b0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
import { BaseChatMessageHistory } from "@langchain/core/chat_history";
import Dexie from "dexie";
import { IChatSession } from "./types";
import { ConfigManager } from "@/lib/config/manager";
import {
mapStoredMessageToChatMessage,
mapChatMessagesToStoredMessages,
BaseMessage,
AIMessage,
HumanMessage,
} from "@langchain/core/messages";
import { IConfig, CHAT_MODELS, EMBEDDING_MODELS } from "@/lib/config/types";
import { ChatCompletionReasoningEffort } from "openai/resources/chat/completions";
import { PROVIDERS } from "@/lib/config/types";
// Create a singleton instance of ChatHistoryDB
export class ChatHistoryDB extends Dexie {
sessions!: Dexie.Table<IChatSession, string>;
private static instance: ChatHistoryDB | null = null;
private constructor() {
super("chat_history");
this.version(1).stores({
sessions: "id, title, createdAt, updatedAt, model, embedding_model, enabled_tools, messages, reasoningEffort",
});
}
public static getInstance(): ChatHistoryDB {
if (!ChatHistoryDB.instance) {
ChatHistoryDB.instance = new ChatHistoryDB();
}
return ChatHistoryDB.instance;
}
}
export class DexieChatMemory extends BaseChatMessageHistory {
db: ChatHistoryDB;
lc_namespace = ["langchain", "stores", "message", "dexie"];
sessionId: string;
chatHistory!: IChatSession | undefined;
config!: IConfig;
configManager: ConfigManager;
initialized: boolean = false;
constructor(sessionId: string) {
super();
this.sessionId = sessionId;
this.db = ChatHistoryDB.getInstance();
this.configManager = ConfigManager.getInstance();
}
async initialize() {
if (this.initialized) return;
this.config = await this.configManager.getConfig();
this.chatHistory = await this.db.sessions.get(this.sessionId);
if (!this.chatHistory) {
const chatModel = CHAT_MODELS.find((m) => m.model === this.config.default_chat_model);
const embeddingModel = EMBEDDING_MODELS.find((m) => m.model === this.config.default_embedding_model);
if (!chatModel) {
throw new Error("Chat or embedding models are not configured.");
}
this.chatHistory = {
id: this.sessionId,
name: "New Chat",
createdAt: Date.now(),
updatedAt: Date.now(),
model: chatModel.model,
embedding_model: embeddingModel?.model || '',
enabled_tools: [],
messages: [],
reasoningEffort: chatModel.isReasoning
? (chatModel.provider === PROVIDERS.anthropic
? "disabled" as ChatCompletionReasoningEffort
: "low" as ChatCompletionReasoningEffort)
: null as ChatCompletionReasoningEffort,
};
await this.db.sessions.put(this.chatHistory);
}
this.initialized = true;
}
private async updateSession() {
if (!this.chatHistory) return;
this.chatHistory.updatedAt = Date.now();
await this.db.sessions.put(this.chatHistory);
}
async getMessages(): Promise<BaseMessage[]> {
await this.initialize();
return this.chatHistory?.messages.map(mapStoredMessageToChatMessage) || [];
}
async addMessage(message: BaseMessage): Promise<void> {
await this.initialize();
if (!this.chatHistory) return;
const storedMessage = mapChatMessagesToStoredMessages([message]);
this.chatHistory.messages.push(storedMessage[0]);
await this.updateSession();
}
async addUserMessage(message: string): Promise<void> {
await this.addMessage(new HumanMessage(message));
}
async addAIChatMessage(message: string): Promise<void> {
await this.addMessage(new AIMessage(message));
}
async clear(): Promise<void> {
this.chatHistory = undefined;
this.initialized = false;
await this.db.sessions.delete(this.sessionId);
}
} |