274 lines
10 KiB
JavaScript
274 lines
10 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.BabyAGI = void 0;
|
|
const documents_1 = require("@langchain/core/documents");
|
|
const base_js_1 = require("../../chains/base.cjs");
|
|
const task_creation_js_1 = require("./task_creation.cjs");
|
|
const task_execution_js_1 = require("./task_execution.cjs");
|
|
const task_prioritization_js_1 = require("./task_prioritization.cjs");
|
|
/**
|
|
* Class responsible for managing tasks, including their creation,
|
|
* prioritization, and execution. It uses three chains for these
|
|
* operations: `creationChain`, `prioritizationChain`, and
|
|
* `executionChain`.
|
|
* @example
|
|
* ```typescript
|
|
* const babyAGI = BabyAGI.fromLLM({
|
|
* llm: new OpenAI({ temperature: 0 }),
|
|
* vectorstore: new MemoryVectorStore(new OpenAIEmbeddings()),
|
|
* maxIterations: 3,
|
|
* });
|
|
*
|
|
* const result = await babyAGI.call({
|
|
* objective: "Write a weather report for SF today",
|
|
* });
|
|
* ```
|
|
*/
|
|
class BabyAGI extends base_js_1.BaseChain {
|
|
static lc_name() {
|
|
return "BabyAGI";
|
|
}
|
|
constructor({ creationChain, prioritizationChain, executionChain, vectorstore, maxIterations = 100, verbose, callbacks, }) {
|
|
super(undefined, verbose, callbacks);
|
|
Object.defineProperty(this, "taskList", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "creationChain", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "prioritizationChain", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "executionChain", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "taskIDCounter", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "vectorstore", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
Object.defineProperty(this, "maxIterations", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: void 0
|
|
});
|
|
this.taskList = [];
|
|
this.creationChain = creationChain;
|
|
this.prioritizationChain = prioritizationChain;
|
|
this.executionChain = executionChain;
|
|
this.taskIDCounter = 1;
|
|
this.vectorstore = vectorstore;
|
|
this.maxIterations = maxIterations;
|
|
}
|
|
_chainType() {
|
|
return "BabyAGI";
|
|
}
|
|
get inputKeys() {
|
|
return ["objective", "firstTask"];
|
|
}
|
|
get outputKeys() {
|
|
return [];
|
|
}
|
|
/**
|
|
* Adds a task to the task list.
|
|
* @param task The task to be added.
|
|
* @returns Promise resolving to void.
|
|
*/
|
|
async addTask(task) {
|
|
this.taskList.push(task);
|
|
}
|
|
/**
|
|
* Prints the current task list to the console.
|
|
* @returns void
|
|
*/
|
|
printTaskList() {
|
|
console.log("\x1b[95m\x1b[1m\n*****TASK LIST*****\n\x1b[0m\x1b[0m");
|
|
for (const t of this.taskList) {
|
|
console.log(`${t.taskID}: ${t.taskName}`);
|
|
}
|
|
}
|
|
/**
|
|
* Prints the next task to the console.
|
|
* @param task The next task to be printed.
|
|
* @returns void
|
|
*/
|
|
printNextTask(task) {
|
|
console.log("\x1b[92m\x1b[1m\n*****NEXT TASK*****\n\x1b[0m\x1b[0m");
|
|
console.log(`${task.taskID}: ${task.taskName}`);
|
|
}
|
|
/**
|
|
* Prints the result of a task to the console.
|
|
* @param result The result of the task.
|
|
* @returns void
|
|
*/
|
|
printTaskResult(result) {
|
|
console.log("\x1b[93m\x1b[1m\n*****TASK RESULT*****\n\x1b[0m\x1b[0m");
|
|
console.log(result.trim());
|
|
}
|
|
/**
|
|
* Generates the next tasks based on the result of the previous task, the
|
|
* task description, and the objective.
|
|
* @param result The result of the previous task.
|
|
* @param task_description The description of the task.
|
|
* @param objective The objective of the task.
|
|
* @param runManager Optional CallbackManagerForChainRun instance.
|
|
* @returns Promise resolving to an array of tasks without taskID.
|
|
*/
|
|
async getNextTasks(result, task_description, objective, runManager) {
|
|
const taskNames = this.taskList.map((t) => t.taskName);
|
|
const incomplete_tasks = taskNames.join(", ");
|
|
const { [this.creationChain.outputKeys[0]]: text } = await this.creationChain.call({
|
|
result,
|
|
task_description,
|
|
incomplete_tasks,
|
|
objective,
|
|
}, runManager?.getChild());
|
|
const newTasks = text.split("\n");
|
|
return newTasks
|
|
.filter((taskName) => taskName.trim())
|
|
.map((taskName) => ({ taskName }));
|
|
}
|
|
/**
|
|
* Prioritizes the tasks based on the current task ID and the objective.
|
|
* @param thisTaskID The ID of the current task.
|
|
* @param objective The objective of the task.
|
|
* @param runManager Optional CallbackManagerForChainRun instance.
|
|
* @returns Promise resolving to an array of prioritized tasks.
|
|
*/
|
|
async prioritizeTasks(thisTaskID, objective, runManager) {
|
|
const taskNames = this.taskList.map((t) => t.taskName);
|
|
const nextTaskID = thisTaskID + 1;
|
|
const { [this.prioritizationChain.outputKeys[0]]: text } = await this.prioritizationChain.call({
|
|
task_names: taskNames.join(", "),
|
|
next_task_id: String(nextTaskID),
|
|
objective,
|
|
}, runManager?.getChild());
|
|
const newTasks = text.trim().split("\n");
|
|
const prioritizedTaskList = [];
|
|
for (const taskString of newTasks) {
|
|
const taskParts = taskString.trim().split(".", 2);
|
|
if (taskParts.length === 2) {
|
|
const taskID = taskParts[0].trim();
|
|
const taskName = taskParts[1].trim();
|
|
prioritizedTaskList.push({ taskID, taskName });
|
|
}
|
|
}
|
|
return prioritizedTaskList;
|
|
}
|
|
/**
|
|
* Retrieves the top tasks that are most similar to the given query.
|
|
* @param query The query to search for.
|
|
* @param k The number of top tasks to retrieve.
|
|
* @returns Promise resolving to an array of top tasks.
|
|
*/
|
|
async getTopTasks(query, k = 5) {
|
|
const results = await this.vectorstore.similaritySearch(query, k);
|
|
if (!results) {
|
|
return [];
|
|
}
|
|
return results.map((item) => String(item.metadata.task));
|
|
}
|
|
/**
|
|
* Executes a task based on the objective and the task description.
|
|
* @param objective The objective of the task.
|
|
* @param task The task to be executed.
|
|
* @param runManager Optional CallbackManagerForChainRun instance.
|
|
* @returns Promise resolving to the result of the task execution as a string.
|
|
*/
|
|
async executeTask(objective, task, runManager) {
|
|
const context = await this.getTopTasks(objective);
|
|
const { [this.executionChain.outputKeys[0]]: text } = await this.executionChain.call({
|
|
objective,
|
|
context: context.join("\n"),
|
|
task,
|
|
}, runManager?.getChild());
|
|
return text;
|
|
}
|
|
async _call({ objective, firstTask = "Make a todo list" }, runManager) {
|
|
this.taskList = [];
|
|
this.taskIDCounter = 1;
|
|
await this.addTask({ taskID: "1", taskName: firstTask });
|
|
let numIters = 0;
|
|
while (numIters < this.maxIterations && this.taskList.length > 0) {
|
|
this.printTaskList();
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
const task = this.taskList.shift();
|
|
this.printNextTask(task);
|
|
const result = await this.executeTask(objective, task.taskName, runManager);
|
|
const thisTaskID = parseInt(task.taskID, 10);
|
|
this.printTaskResult(result);
|
|
await this.vectorstore.addDocuments([
|
|
new documents_1.Document({
|
|
pageContent: result,
|
|
metadata: { task: task.taskName },
|
|
}),
|
|
]);
|
|
const newTasks = await this.getNextTasks(result, task.taskName, objective, runManager);
|
|
for (const newTask of newTasks) {
|
|
this.taskIDCounter += 1;
|
|
newTask.taskID = this.taskIDCounter.toFixed();
|
|
await this.addTask(newTask);
|
|
}
|
|
this.taskList = await this.prioritizeTasks(thisTaskID, objective, runManager);
|
|
numIters += 1;
|
|
}
|
|
return {};
|
|
}
|
|
serialize() {
|
|
throw new Error("Method not implemented.");
|
|
}
|
|
/**
|
|
* Static method to create a new BabyAGI instance from a
|
|
* BaseLanguageModel.
|
|
* @param llm BaseLanguageModel instance used to generate a new BabyAGI instance.
|
|
* @param vectorstore VectorStore instance used to store and retrieve vectors.
|
|
* @param executionChain Optional BaseChain instance used to execute tasks.
|
|
* @param verbose Optional boolean indicating whether to log verbose output.
|
|
* @param callbacks Optional callbacks to be used during the execution of tasks.
|
|
* @param rest Optional additional parameters.
|
|
* @returns A new instance of BabyAGI.
|
|
*/
|
|
static fromLLM({ llm, vectorstore, executionChain, verbose, callbacks, ...rest }) {
|
|
const creationChain = task_creation_js_1.TaskCreationChain.fromLLM({
|
|
llm,
|
|
verbose,
|
|
callbacks,
|
|
});
|
|
const prioritizationChain = task_prioritization_js_1.TaskPrioritizationChain.fromLLM({
|
|
llm,
|
|
verbose,
|
|
callbacks,
|
|
});
|
|
return new BabyAGI({
|
|
creationChain,
|
|
prioritizationChain,
|
|
executionChain: executionChain ||
|
|
task_execution_js_1.TaskExecutionChain.fromLLM({ llm, verbose, callbacks }),
|
|
vectorstore,
|
|
verbose,
|
|
callbacks,
|
|
...rest,
|
|
});
|
|
}
|
|
}
|
|
exports.BabyAGI = BabyAGI;
|