UNPKG

llama-flow

Version:

The Typescript-first prompt engineering toolkit for working with chat based LLMs.

109 lines (108 loc) 4 kB
"use strict"; 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;