UNPKG

auto-gpt-ts

Version:

my take of Auto-GPT in typescript

162 lines 9.51 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.chat_with_ai = exports.generateContext = exports.createChatMessage = void 0; const logging_1 = require("../logging"); const config_1 = require("../config/config"); const summary_memory_1 = require("../memory-managment/summary-memory"); const api_manages_1 = require("./api-manages"); const llm_utils_1 = require("./llm-utils"); const token_counter_1 = require("./token-counter"); const logger = (0, logging_1.getLogger)(); const config = new config_1.Config(); /** * Create a chat message with the given role and content. * * @param role {Role} - The role of the message sender, e.g., "system", "user", or "assistant". * @param content {string} - The content of the message. * * @returns {Message} - A dictionary containing the role and content of the message. */ function createChatMessage(role, content) { return { role, content }; } exports.createChatMessage = createChatMessage; /** * Generate context for the OpenAI API by adding messages to a prompt until * the token limit is reached. * * @param prompt {string} - The prompt to use. * @param relevant_memory {string[]} - The relevant memory to include in the context. * @param full_message_history {Message[]} - The full message history to use. * @param model {string} - The name of the OpenAI model to use. * * @returns {[number, number, number, Message[]]} - A tuple containing the index of the next message * to add, the current tokens used, the index at * which to insert new messages, and the current context. */ function generateContext(prompt, relevant_memory, full_message_history, model) { const current_context = [ createChatMessage("system", prompt), createChatMessage("system", `The current time and date is ${new Date().toLocaleString()}, Timezone: ${config.currentTimeZone}, Location: ${config.currentGeoLocation}.\n\n`), // createChatMessage( // "system", // `This reminds you of these events from your past:\n${relevant_memory}\n\n` // ), ]; // Add messages from the full message history until we reach the token limit let next_message_to_add_index = full_message_history.length - 1; let insertion_index = current_context.length; // Count the currently used tokens let current_tokens_used = (0, token_counter_1.countMessageTokens)(current_context, model); return [ next_message_to_add_index, current_tokens_used, insertion_index, current_context, ]; } exports.generateContext = generateContext; function chat_with_ai(agent, prompt, user_input, full_message_history, permanent_memory, token_limit) { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { const cfg = new config_1.Config(); while (true) { try { const model = cfg.fastLlmModel; // Reserve 1000 tokens for the response logger.debug(`Token limit: ${token_limit}`); const send_token_limit = token_limit - 1000; // const relevant_memory: any[] = []; logger.debug(`Memory Stats: ${permanent_memory.getStats()}`); const [next_message_to_add_index, current_tokens_used, insertion_index, currentContext,] = generateContext(prompt, '', full_message_history, model); let updated_tokens_used = current_tokens_used + (0, token_counter_1.countMessageTokens)([createChatMessage("user", user_input)], model); // Account for user input (appended later) updated_tokens_used += 1000; // Account for memory (appended later) TODO: The final memory may be less than 500 tokens // Add Messages until the token limit is reached or there are no more messages to add. let messageIndex = next_message_to_add_index; while (messageIndex >= 0) { // print (f"CURRENT TOKENS USED: {current_tokens_used}") const messageToAdd = full_message_history[messageIndex]; const tokens_to_add = (0, token_counter_1.countMessageTokens)([messageToAdd], model); if (updated_tokens_used + tokens_to_add > send_token_limit) { break; } // Add the most recent message to the start of the current context, // after the two system prompts. currentContext.splice(insertion_index, 0, full_message_history[messageIndex]); // Count the currently used tokens updated_tokens_used += tokens_to_add; // Move to the next most recent message in the full message history messageIndex -= 1; } // Insert Memories if (full_message_history.length > 0) { const [newlyTrimmedMessages] = (0, summary_memory_1.getNewlyTrimmedMessages)(full_message_history, currentContext, agent.lastMemoryIndex); agent.summaryMemory = yield (0, summary_memory_1.updateRunningSummary)(agent.summaryMemory, newlyTrimmedMessages); currentContext.splice(insertion_index, 0, { role: 'user', content: agent.summaryMemory }); } const api_manager = new api_manages_1.ApiManager(); // inform the AI about its remaining budget (if it has one) if (api_manager.getTotalBudget() > 0.0) { const remaining_budget = api_manager.getTotalBudget() - api_manager.getTotalCost(); const system_message = `Your remaining API budget is ${remaining_budget.toFixed(3)}` + (remaining_budget == 0 ? " BUDGET EXCEEDED! SHUT DOWN!\n\n" : remaining_budget < 0.005 ? " Budget very nearly exceeded! Shut down gracefully!\n\n" : remaining_budget < 0.01 ? " Budget nearly exceeded. Finish up.\n\n" : "\n\n"); logger.debug(system_message); // current_context.push(createChatMessage("system", system_message)); } // Append user input, the length of this is accounted for above // Append user input, the length of this is accounted for above currentContext.push(createChatMessage("user", user_input)); const tokensRemaining = token_limit - current_tokens_used; logger.debug(`Token limit: ${token_limit}`); logger.debug(`Send Token Count: ${current_tokens_used}`); logger.debug(`Tokens remaining for response: ${tokensRemaining}`); logger.debug("------------ CONTEXT SENT TO AI ---------------"); for (const message of currentContext) { // Skip printing the prompt if (message.role === "system" && message.content === prompt) { continue; } logger.debug(`${message.role.charAt(0).toUpperCase() + message.role.slice(1)}: ${message.content}`); logger.debug(""); } logger.debug(currentContext.map((message) => `Role: ${message.role}, Content: ${message.content}`).join("\n")); logger.debug("\n----------- END OF CONTEXT ----------------"); const assistant_reply = yield (0, llm_utils_1.createChatCompletion)(currentContext, model, cfg.temperature, tokensRemaining); full_message_history.push(createChatMessage("user", user_input)); full_message_history.push(createChatMessage("system", assistant_reply)); // logger.debug( // `Assistant reply: ${assistant_reply} (length: ${assistant_reply.length})` // ); return resolve(assistant_reply); } catch (error) { logger.debug('Error: ', error); if (/429/.test(error === null || error === void 0 ? void 0 : error.message)) { logger.warn("Error: API Rate Limit Reached. Waiting 10 seconds..."); yield new Promise((res) => setTimeout(res, 10 * 1000)); token_limit -= 300; } else { return reject(error); } } } })); } exports.chat_with_ai = chat_with_ai; //# sourceMappingURL=chat.js.map