218 lines
7.3 KiB
JavaScript
218 lines
7.3 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.XataChatMessageHistory = void 0;
|
|
const client_1 = require("@xata.io/client");
|
|
const chat_history_1 = require("@langchain/core/chat_history");
|
|
const messages_1 = require("@langchain/core/messages");
|
|
const chatMemoryColumns = [
|
|
{ name: "sessionId", type: "string" },
|
|
{ name: "type", type: "string" },
|
|
{ name: "role", type: "string" },
|
|
{ name: "content", type: "text" },
|
|
{ name: "name", type: "string" },
|
|
{ name: "additionalKwargs", type: "text" },
|
|
];
|
|
/**
|
|
* A class for managing chat message history using Xata.io client. It
|
|
* extends the BaseListChatMessageHistory class and provides methods to
|
|
* get, add, and clear messages. It also ensures the existence of a table
|
|
* where the chat messages are stored.
|
|
* @example
|
|
* ```typescript
|
|
* const chatHistory = new XataChatMessageHistory({
|
|
* table: "messages",
|
|
* sessionId: new Date().toISOString(),
|
|
* client: new BaseClient({
|
|
* databaseURL: process.env.XATA_DB_URL,
|
|
* apiKey: process.env.XATA_API_KEY,
|
|
* branch: "main",
|
|
* }),
|
|
* apiKey: process.env.XATA_API_KEY,
|
|
* });
|
|
*
|
|
* const chain = new ConversationChain({
|
|
* llm: new ChatOpenAI(),
|
|
* memory: new BufferMemory({ chatHistory }),
|
|
* });
|
|
*
|
|
* const response = await chain.invoke({
|
|
* input: "What did I just say my name was?",
|
|
* });
|
|
* console.log({ response });
|
|
* ```
|
|
*/
|
|
class XataChatMessageHistory extends chat_history_1.BaseListChatMessageHistory {
|
|
constructor(fields) {
|
|
super(fields);
|
|
Object.defineProperty(this, "lc_namespace", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: ["langchain", "stores", "message", "xata"]
|
|
});
|
|
Object.defineProperty(this, "client", {
|
|
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, "table", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "tableInitialized", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "createTable", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "apiClient", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
const { sessionId, config, client, table } = fields;
|
|
this.sessionId = sessionId;
|
|
this.table = table || "memory";
|
|
if (client) {
|
|
this.client = client;
|
|
}
|
|
else if (config) {
|
|
this.client = new client_1.BaseClient(config);
|
|
}
|
|
else {
|
|
throw new Error("Either a client or a config must be provided to XataChatMessageHistoryInput");
|
|
}
|
|
if (fields.createTable !== false) {
|
|
this.createTable = true;
|
|
const apiKey = fields.apiKey || fields.config?.apiKey;
|
|
if (!apiKey) {
|
|
throw new Error("If createTable is set, an apiKey must be provided to XataChatMessageHistoryInput, either directly or through the config object");
|
|
}
|
|
this.apiClient = new client_1.XataApiClient({ apiKey });
|
|
}
|
|
else {
|
|
this.createTable = false;
|
|
}
|
|
this.tableInitialized = false;
|
|
}
|
|
/**
|
|
* Retrieves all messages associated with the session ID, ordered by
|
|
* creation time.
|
|
* @returns A promise that resolves to an array of BaseMessage instances.
|
|
*/
|
|
async getMessages() {
|
|
await this.ensureTable();
|
|
const records = await this.client.db[this.table]
|
|
.filter({ sessionId: this.sessionId })
|
|
.sort("xata.createdAt", "asc")
|
|
.getAll();
|
|
const rawStoredMessages = records;
|
|
const orderedMessages = rawStoredMessages.map((message) => {
|
|
const data = {
|
|
content: message.content,
|
|
additional_kwargs: JSON.parse(message.additionalKwargs),
|
|
};
|
|
if (message.role) {
|
|
data.role = message.role;
|
|
}
|
|
if (message.name) {
|
|
data.name = message.name;
|
|
}
|
|
return {
|
|
type: message.type,
|
|
data,
|
|
};
|
|
});
|
|
return (0, messages_1.mapStoredMessagesToChatMessages)(orderedMessages);
|
|
}
|
|
/**
|
|
* Adds a new message to the database.
|
|
* @param message The BaseMessage instance to be added.
|
|
* @returns A promise that resolves when the message has been added.
|
|
*/
|
|
async addMessage(message) {
|
|
await this.ensureTable();
|
|
const messageToAdd = (0, messages_1.mapChatMessagesToStoredMessages)([message]);
|
|
await this.client.db[this.table].create({
|
|
sessionId: this.sessionId,
|
|
type: messageToAdd[0].type,
|
|
content: messageToAdd[0].data.content,
|
|
role: messageToAdd[0].data.role,
|
|
name: messageToAdd[0].data.name,
|
|
additionalKwargs: JSON.stringify(messageToAdd[0].data.additional_kwargs),
|
|
});
|
|
}
|
|
/**
|
|
* Deletes all messages associated with the session ID.
|
|
* @returns A promise that resolves when the messages have been deleted.
|
|
*/
|
|
async clear() {
|
|
await this.ensureTable();
|
|
const records = await this.client.db[this.table]
|
|
.select(["id"])
|
|
.filter({ sessionId: this.sessionId })
|
|
.getAll();
|
|
const ids = records.map((m) => m.id);
|
|
await this.client.db[this.table].delete(ids);
|
|
}
|
|
/**
|
|
* Checks if the table exists and creates it if it doesn't. This method is
|
|
* called before any operation on the table.
|
|
* @returns A promise that resolves when the table has been ensured.
|
|
*/
|
|
async ensureTable() {
|
|
if (!this.createTable) {
|
|
return;
|
|
}
|
|
if (this.tableInitialized) {
|
|
return;
|
|
}
|
|
const { databaseURL, branch } = await this.client.getConfig();
|
|
const [, , host, , database] = databaseURL.split("/");
|
|
const urlParts = (0, client_1.parseWorkspacesUrlParts)(host);
|
|
if (urlParts == null) {
|
|
throw new Error("Invalid databaseURL");
|
|
}
|
|
const { workspace, region } = urlParts;
|
|
const tableParams = {
|
|
workspace,
|
|
region,
|
|
database,
|
|
branch,
|
|
table: this.table,
|
|
};
|
|
let schema = null;
|
|
try {
|
|
schema = await this.apiClient.tables.getTableSchema(tableParams);
|
|
}
|
|
catch (e) {
|
|
// pass
|
|
}
|
|
if (schema == null) {
|
|
await this.apiClient.tables.createTable(tableParams);
|
|
await this.apiClient.tables.setTableSchema({
|
|
...tableParams,
|
|
schema: {
|
|
columns: chatMemoryColumns,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
exports.XataChatMessageHistory = XataChatMessageHistory;
|