@langchain/community
Version:
Third-party integrations for LangChain.js
151 lines (150 loc) • 5.7 kB
JavaScript
import { v4 } from "uuid";
import { BaseListChatMessageHistory } from "@langchain/core/chat_history";
import { mapChatMessagesToStoredMessages, mapStoredMessagesToChatMessages, } from "@langchain/core/messages";
/**
* @deprecated Install and import from "@langchain/cloudflare" instead.
*
* Class for storing and retrieving chat message history from a
* Cloudflare D1 database. Extends the BaseListChatMessageHistory class.
* @example
* ```typescript
* const memory = new BufferMemory({
* returnMessages: true,
* chatHistory: new CloudflareD1MessageHistory({
* tableName: "stored_message",
* sessionId: "example",
* database: env.DB,
* }),
* });
*
* const chainInput = { input };
*
* const res = await memory.chatHistory.invoke(chainInput);
* await memory.saveContext(chainInput, {
* output: res,
* });
* ```
*/
export class CloudflareD1MessageHistory extends BaseListChatMessageHistory {
constructor(fields) {
super(fields);
Object.defineProperty(this, "lc_namespace", {
enumerable: true,
configurable: true,
writable: true,
value: ["langchain", "stores", "message", "cloudflare_d1"]
});
Object.defineProperty(this, "database", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "tableName", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "sessionId", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "tableInitialized", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
const { sessionId, database, tableName } = fields;
if (database) {
this.database = database;
}
else {
throw new Error("Either a client or config must be provided to CloudflareD1MessageHistory");
}
this.tableName = tableName || "langchain_chat_histories";
this.tableInitialized = false;
this.sessionId = sessionId;
}
/**
* Private method to ensure that the necessary table exists in the
* Cloudflare D1 database before performing any operations. If the table
* does not exist, it is created.
* @returns Promise that resolves to void.
*/
async ensureTable() {
if (this.tableInitialized) {
return;
}
const query = `CREATE TABLE IF NOT EXISTS ${this.tableName} (id TEXT PRIMARY KEY, session_id TEXT, type TEXT, content TEXT, role TEXT, name TEXT, additional_kwargs TEXT);`;
await this.database.prepare(query).bind().all();
const idIndexQuery = `CREATE INDEX IF NOT EXISTS id_index ON ${this.tableName} (id);`;
await this.database.prepare(idIndexQuery).bind().all();
const sessionIdIndexQuery = `CREATE INDEX IF NOT EXISTS session_id_index ON ${this.tableName} (session_id);`;
await this.database.prepare(sessionIdIndexQuery).bind().all();
this.tableInitialized = true;
}
/**
* Method to retrieve all messages from the Cloudflare D1 database for the
* current session.
* @returns Promise that resolves to an array of BaseMessage objects.
*/
async getMessages() {
await this.ensureTable();
const query = `SELECT * FROM ${this.tableName} WHERE session_id = ?`;
const rawStoredMessages = await this.database
.prepare(query)
.bind(this.sessionId)
.all();
const storedMessagesObject = rawStoredMessages.results;
const orderedMessages = storedMessagesObject.map((message) => {
const data = {
content: message.content,
additional_kwargs: JSON.parse(message.additional_kwargs),
};
if (message.role) {
data.role = message.role;
}
if (message.name) {
data.name = message.name;
}
return {
type: message.type,
data,
};
});
return mapStoredMessagesToChatMessages(orderedMessages);
}
/**
* Method to add a new message to the Cloudflare D1 database for the current
* session.
* @param message The BaseMessage object to be added to the database.
* @returns Promise that resolves to void.
*/
async addMessage(message) {
await this.ensureTable();
const messageToAdd = mapChatMessagesToStoredMessages([message]);
const query = `INSERT INTO ${this.tableName} (id, session_id, type, content, role, name, additional_kwargs) VALUES(?, ?, ?, ?, ?, ?, ?)`;
const id = v4();
await this.database
.prepare(query)
.bind(id, this.sessionId, messageToAdd[0].type || null, messageToAdd[0].data.content || null, messageToAdd[0].data.role || null, messageToAdd[0].data.name || null, JSON.stringify(messageToAdd[0].data.additional_kwargs))
.all();
}
/**
* Method to delete all messages from the Cloudflare D1 database for the
* current session.
* @returns Promise that resolves to void.
*/
async clear() {
await this.ensureTable();
const query = `DELETE FROM ? WHERE session_id = ? `;
await this.database
.prepare(query)
.bind(this.tableName, this.sessionId)
.all();
}
}