llama-flow
Version:
The Typescript-first prompt engineering toolkit for working with chat based LLMs.
109 lines (108 loc) • 4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.Chat = void 0;
const lodash_1 = require("lodash");
const config_1 = require("./config");
const errors_1 = require("./models/errors");
const persona_1 = require("./persona");
const text_splitter_1 = require("./text-splitter");
const utils_1 = require("./utils");
const DefaultChunkSize = 50_000;
const DefaultMinChunkSize = 1000;
class Chat {
persona;
config;
model;
messages;
constructor(persona, config, model) {
this.persona = persona;
this.config = config;
this.model = model;
this.messages = [];
this.reset();
}
async request(prompt, opt) {
utils_1.debug.log('⬆️ sending request:', prompt.message);
const newMessages = [
...(opt?.messages ? opt.messages : this.messages),
{
role: 'user',
content: prompt.message,
},
];
const mergedOpt = (0, lodash_1.defaults)(opt, this.config.options);
const response = await this.model.request(newMessages, this.persona.config, mergedOpt);
if (!response) {
throw new Error('Chat request failed');
}
!response.isStream && utils_1.debug.log('⬇️ received response:', response.content);
const messagesWithResponse = [
...newMessages,
{
role: 'assistant',
content: response.content,
},
];
if (prompt.parse) {
const res = await prompt.parse(response);
if (res.success) {
if (this.config.retainMemory) {
this.messages = messagesWithResponse;
}
return {
...response,
content: res.data,
};
}
else {
const promptRetries = prompt.promptRetries ?? config_1.PromptDefaultRetries;
if (promptRetries > 0 && res.retryPrompt) {
utils_1.debug.log(`⚠️ retrying request with prompt: ${res.retryPrompt}\nCurrent message stack:`, messagesWithResponse);
return this.request({
...prompt,
message: res.retryPrompt,
promptRetries: promptRetries - 1,
}, { ...opt, messages: messagesWithResponse });
}
else {
throw new Error('Response parsing failed');
}
}
}
if (this.config.retainMemory) {
this.messages = messagesWithResponse;
}
return response;
}
async requestWithSplit(originalText, requestFn, opt, chunkSize = DefaultChunkSize, minumChunkSize = DefaultMinChunkSize) {
if (chunkSize < minumChunkSize) {
throw new Error('Text chunk size is below the minumim required chunk size, cannot split anymore');
}
try {
const res = await this.request(requestFn(originalText, chunkSize), opt);
return res;
}
catch (e) {
if (e instanceof errors_1.TokenError) {
const textSplitter = new text_splitter_1.RecursiveCharacterTextSplitter({
chunkSize,
chunkOverlap: Math.floor(Math.min(chunkSize / 4, 200)),
});
utils_1.debug.log(`⚠️ Request prompt too long, splitting text with chunk size of ${chunkSize}`);
return this.requestWithSplit(textSplitter.splitText(originalText)[0], requestFn, opt, Math.floor(chunkSize / 2), minumChunkSize);
}
else {
throw e;
}
}
}
reset() {
this.messages = [
{
role: 'system',
content: (0, persona_1.buildMessage)(this.persona),
},
];
}
}
exports.Chat = Chat;
;