-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
Copy pathsummary_buffer.ts
167 lines (153 loc) Β· 5.39 KB
/
summary_buffer.ts
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import { getBufferString } from "@langchain/core/messages";
import {
InputValues,
MemoryVariables,
OutputValues,
} from "@langchain/core/memory";
import {
BaseConversationSummaryMemory,
BaseConversationSummaryMemoryInput,
} from "./summary.js";
/**
* Interface for the input parameters of the
* ConversationSummaryBufferMemory class.
*/
export interface ConversationSummaryBufferMemoryInput
extends BaseConversationSummaryMemoryInput {
maxTokenLimit?: number;
}
/**
* Class that extends BaseConversationSummaryMemory and implements
* ConversationSummaryBufferMemoryInput. It manages the conversation
* history in a LangChain application by maintaining a buffer of chat
* messages and providing methods to load, save, prune, and clear the
* memory.
* @example
* ```typescript
* // Initialize the memory with a specific model and token limit
* const memory = new ConversationSummaryBufferMemory({
* llm: new ChatOpenAI({ modelName: "gpt-3.5-turbo-instruct", temperature: 0 }),
* maxTokenLimit: 10,
* });
*
* // Save conversation context to memory
* await memory.saveContext({ input: "hi" }, { output: "whats up" });
* await memory.saveContext({ input: "not much you" }, { output: "not much" });
*
* // Load the conversation history from memory
* const history = await memory.loadMemoryVariables({});
* console.log({ history });
*
* // Create a chat prompt using the conversation history
* const chatPrompt = ChatPromptTemplate.fromMessages([
* SystemMessagePromptTemplate.fromTemplate(
* "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.",
* ),
* new MessagesPlaceholder("history"),
* HumanMessagePromptTemplate.fromTemplate("{input}"),
* ]);
*
* // Initialize the conversation chain with the model, memory, and prompt
* const chain = new ConversationChain({
* llm: new ChatOpenAI({ temperature: 0.9, verbose: true }),
* memory: memory,
* prompt: chatPrompt,
* });
* ```
*/
export class ConversationSummaryBufferMemory
extends BaseConversationSummaryMemory
implements ConversationSummaryBufferMemoryInput
{
movingSummaryBuffer = "";
maxTokenLimit = 2000;
constructor(fields: ConversationSummaryBufferMemoryInput) {
super(fields);
this.maxTokenLimit = fields?.maxTokenLimit ?? this.maxTokenLimit;
}
get memoryKeys() {
return [this.memoryKey];
}
/**
* Method that loads the chat messages from the memory and returns them as
* a string or as a list of messages, depending on the returnMessages
* property.
* @param _ InputValues object, not used in this method.
* @returns Promise that resolves with MemoryVariables object containing the loaded chat messages.
*/
async loadMemoryVariables(_?: InputValues): Promise<MemoryVariables> {
let buffer = await this.chatHistory.getMessages();
if (this.movingSummaryBuffer) {
buffer = [
new this.summaryChatMessageClass(this.movingSummaryBuffer),
...buffer,
];
}
let finalBuffer;
if (this.returnMessages) {
finalBuffer = buffer;
} else {
finalBuffer = getBufferString(buffer, this.humanPrefix, this.aiPrefix);
}
return { [this.memoryKey]: finalBuffer };
}
/**
* Method that saves the context of the conversation, including the input
* and output values, and prunes the memory if it exceeds the maximum
* token limit.
* @param inputValues InputValues object containing the input values of the conversation.
* @param outputValues OutputValues object containing the output values of the conversation.
* @returns Promise that resolves when the context is saved and the memory is pruned.
*/
async saveContext(
inputValues: InputValues,
outputValues: OutputValues
): Promise<void> {
await super.saveContext(inputValues, outputValues);
await this.prune();
}
/**
* Method that prunes the memory if the total number of tokens in the
* buffer exceeds the maxTokenLimit. It removes messages from the
* beginning of the buffer until the total number of tokens is within the
* limit.
* @returns Promise that resolves when the memory is pruned.
*/
async prune() {
// Prune buffer if it exceeds max token limit
let buffer = await this.chatHistory.getMessages();
if (this.movingSummaryBuffer) {
buffer = [
new this.summaryChatMessageClass(this.movingSummaryBuffer),
...buffer,
];
}
let currBufferLength = await this.llm.getNumTokens(
getBufferString(buffer, this.humanPrefix, this.aiPrefix)
);
if (currBufferLength > this.maxTokenLimit) {
const prunedMemory = [];
while (currBufferLength > this.maxTokenLimit) {
const poppedMessage = buffer.shift();
if (poppedMessage) {
prunedMemory.push(poppedMessage);
currBufferLength = await this.llm.getNumTokens(
getBufferString(buffer, this.humanPrefix, this.aiPrefix)
);
}
}
this.movingSummaryBuffer = await this.predictNewSummary(
prunedMemory,
this.movingSummaryBuffer
);
}
}
/**
* Method that clears the memory and resets the movingSummaryBuffer.
* @returns Promise that resolves when the memory is cleared.
*/
async clear() {
await super.clear();
this.movingSummaryBuffer = "";
}
}