mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-22 11:01:22 +03:00
add babyagi
This commit is contained in:
@@ -1,15 +1,7 @@
|
||||
import { INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { Configuration, CreateChatCompletionRequest, CreateCompletionRequest, OpenAIApi } from 'openai'
|
||||
import { PineconeClient } from '@pinecone-database/pinecone'
|
||||
import { CreateIndexRequest } from '@pinecone-database/pinecone/dist/pinecone-generated-ts-fetch'
|
||||
import { VectorOperationsApi } from '@pinecone-database/pinecone/dist/pinecone-generated-ts-fetch'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
interface Task {
|
||||
id: string
|
||||
name: string
|
||||
priority: number // 1 is highest priority
|
||||
}
|
||||
import { BabyAGI } from './core'
|
||||
import { BaseChatModel } from 'langchain/chat_models'
|
||||
import { VectorStore } from 'langchain/vectorstores'
|
||||
|
||||
class BabyAGI_Agents implements INode {
|
||||
label: string
|
||||
@@ -26,351 +18,45 @@ class BabyAGI_Agents implements INode {
|
||||
this.name = 'babyAGI'
|
||||
this.type = 'BabyAGI'
|
||||
this.category = 'Agents'
|
||||
this.icon = 'babyagi.svg'
|
||||
this.icon = 'babyagi.jpg'
|
||||
this.description = 'Task Driven Autonomous Agent which creates new task and reprioritizes task list based on objective'
|
||||
this.baseClasses = ['BabyAGI']
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Chat Model',
|
||||
name: 'model',
|
||||
type: 'BaseChatModel'
|
||||
},
|
||||
{
|
||||
label: 'Vector Store',
|
||||
name: 'vectorStore',
|
||||
type: 'VectorStore'
|
||||
},
|
||||
{
|
||||
label: 'Task Loop',
|
||||
name: 'taskLoop',
|
||||
type: 'number',
|
||||
default: 3
|
||||
},
|
||||
{
|
||||
label: 'OpenAI Api Key',
|
||||
name: 'openAIApiKey',
|
||||
type: 'password'
|
||||
},
|
||||
{
|
||||
label: 'Pinecone Api Key',
|
||||
name: 'pineconeApiKey',
|
||||
type: 'password'
|
||||
},
|
||||
{
|
||||
label: 'Pinecone Environment',
|
||||
name: 'pineconeEnv',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
label: 'Pinecone Index',
|
||||
name: 'pineconeIndex',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
label: 'Model Name',
|
||||
name: 'modelName',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
label: 'gpt-4',
|
||||
name: 'gpt-4'
|
||||
},
|
||||
{
|
||||
label: 'gpt-4-0314',
|
||||
name: 'gpt-4-0314'
|
||||
},
|
||||
{
|
||||
label: 'gpt-4-32k-0314',
|
||||
name: 'gpt-4-32k-0314'
|
||||
},
|
||||
{
|
||||
label: 'gpt-3.5-turbo',
|
||||
name: 'gpt-3.5-turbo'
|
||||
},
|
||||
{
|
||||
label: 'gpt-3.5-turbo-0301',
|
||||
name: 'gpt-3.5-turbo-0301'
|
||||
}
|
||||
],
|
||||
default: 'gpt-3.5-turbo',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async getBaseClasses(): Promise<string[]> {
|
||||
return ['BabyAGI']
|
||||
}
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const model = nodeData.inputs?.model as BaseChatModel
|
||||
const vectorStore = nodeData.inputs?.vectorStore as VectorStore
|
||||
const taskLoop = nodeData.inputs?.taskLoop as string
|
||||
|
||||
async init(): Promise<any> {
|
||||
return null
|
||||
const babyAgi = BabyAGI.fromLLM(model, vectorStore, parseInt(taskLoop, 10))
|
||||
return babyAgi
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string): Promise<string> {
|
||||
const openAIApiKey = nodeData.inputs?.openAIApiKey as string
|
||||
const pineconeApiKey = nodeData.inputs?.pineconeApiKey as string
|
||||
const pineconeEnv = nodeData.inputs?.pineconeEnv as string
|
||||
const index = nodeData.inputs?.pineconeIndex as string
|
||||
const modelName = nodeData.inputs?.modelName as string
|
||||
const taskLoop = nodeData.inputs?.taskLoop as string
|
||||
const executor = nodeData.instance as BabyAGI
|
||||
const objective = input
|
||||
|
||||
const configuration = new Configuration({
|
||||
apiKey: openAIApiKey
|
||||
})
|
||||
const openai = new OpenAIApi(configuration)
|
||||
|
||||
const pinecone = new PineconeClient()
|
||||
await pinecone.init({
|
||||
apiKey: pineconeApiKey,
|
||||
environment: pineconeEnv
|
||||
})
|
||||
|
||||
const dimension = 1536
|
||||
const metric = 'cosine'
|
||||
const podType = 'p1'
|
||||
|
||||
const indexList = await pinecone.listIndexes()
|
||||
if (!indexList.includes(index)) {
|
||||
const createIndexOptions: CreateIndexRequest = {
|
||||
createRequest: {
|
||||
name: index,
|
||||
dimension,
|
||||
metric,
|
||||
podType
|
||||
}
|
||||
}
|
||||
await pinecone.createIndex(createIndexOptions)
|
||||
}
|
||||
|
||||
let vectorIndex: VectorOperationsApi = pinecone.Index(index)
|
||||
|
||||
let taskList: Task[] = []
|
||||
let embeddingList = new Map<string, number[]>()
|
||||
|
||||
taskList = [
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: 'Develop a task list',
|
||||
priority: 1
|
||||
}
|
||||
]
|
||||
|
||||
return await mainLoop(openai, pinecone, index, embeddingList, vectorIndex, taskList, objective, modelName, taskLoop)
|
||||
const res = await executor.call({ objective })
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
export const getADAEmbedding = async (openai: OpenAIApi, text: string, embeddingList: Map<string, number[]>): Promise<number[]> => {
|
||||
//console.log('\nGetting ADA embedding for: ', text)
|
||||
|
||||
if (embeddingList.has(text)) {
|
||||
//console.log('Embedding already exists for: ', text)
|
||||
const numbers = embeddingList.get(text)
|
||||
return numbers ?? []
|
||||
}
|
||||
|
||||
const embedding = (
|
||||
await openai.createEmbedding({
|
||||
input: [text],
|
||||
model: 'text-embedding-ada-002'
|
||||
})
|
||||
).data?.data[0].embedding
|
||||
|
||||
embeddingList.set(text, embedding)
|
||||
|
||||
return embedding
|
||||
}
|
||||
|
||||
export const openAICall = async (openai: OpenAIApi, prompt: string, gptVersion: string, temperature = 0.5, max_tokens = 100) => {
|
||||
if (gptVersion === 'gpt-3.5-turbo' || gptVersion === 'gpt-4' || gptVersion === 'gpt-4-32k') {
|
||||
// Chat completion
|
||||
const options: CreateChatCompletionRequest = {
|
||||
model: gptVersion,
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
temperature,
|
||||
max_tokens,
|
||||
n: 1
|
||||
}
|
||||
const data = (await openai.createChatCompletion(options)).data
|
||||
|
||||
return data?.choices[0]?.message?.content.trim() ?? ''
|
||||
} else {
|
||||
// Prompt completion
|
||||
const options: CreateCompletionRequest = {
|
||||
model: gptVersion,
|
||||
prompt,
|
||||
temperature,
|
||||
max_tokens,
|
||||
top_p: 1,
|
||||
frequency_penalty: 0,
|
||||
presence_penalty: 0
|
||||
}
|
||||
const data = (await openai.createCompletion(options)).data
|
||||
|
||||
return data?.choices[0]?.text?.trim() ?? ''
|
||||
}
|
||||
}
|
||||
|
||||
export const taskCreationAgent = async (
|
||||
openai: OpenAIApi,
|
||||
taskList: Task[],
|
||||
objective: string,
|
||||
result: string,
|
||||
taskDescription: string,
|
||||
gptVersion = 'gpt-3.5-turbo'
|
||||
): Promise<Task[]> => {
|
||||
const prompt = `You are an task creation AI that uses the result of an execution agent to create new tasks with the following objective: ${objective}, The last completed task has the result: ${result}. This result was based on this task description: ${taskDescription}. These are incomplete tasks: ${taskList.join(
|
||||
', '
|
||||
)}. Based on the result, create new tasks to be completed by the AI system that do not overlap with incomplete tasks. Return the tasks as an array.`
|
||||
const response = await openAICall(openai, prompt, gptVersion)
|
||||
const newTaskNames = response.split('\n')
|
||||
|
||||
return newTaskNames.map((name) => ({
|
||||
id: uuidv4(),
|
||||
name,
|
||||
priority: taskList.length + 1
|
||||
}))
|
||||
}
|
||||
|
||||
export const prioritizationAgent = async (
|
||||
openai: OpenAIApi,
|
||||
taskList: Task[],
|
||||
taskPriority: number,
|
||||
objective: string,
|
||||
gptVersion = 'gpt-3.5-turbo'
|
||||
): Promise<Task[]> => {
|
||||
const taskNames = taskList.map((t) => t.name)
|
||||
const startPriority = taskPriority + 1
|
||||
|
||||
const prompt = `You are an task prioritization AI tasked with cleaning the formatting of and reprioritizing the following tasks: ${taskNames}. Consider the ultimate objective of your team: ${objective}. Do not remove any tasks. Return the result as a list, like:
|
||||
#. First task
|
||||
#. Second task
|
||||
Start the task list with number ${startPriority}.`
|
||||
const response = await openAICall(openai, prompt, gptVersion)
|
||||
const newTasks = response.split('\n')
|
||||
|
||||
// Parse and add new tasks
|
||||
return (
|
||||
newTasks
|
||||
.map((taskString) => {
|
||||
const taskParts = taskString.trim().split('.', 2)
|
||||
|
||||
if (taskParts.length === 2) {
|
||||
const id = uuidv4()
|
||||
const name = taskParts[1].trim()
|
||||
const priority = parseInt(taskParts[0])
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
priority
|
||||
} as Task
|
||||
}
|
||||
})
|
||||
// Remove lines that don't have a task
|
||||
.filter((t) => t !== undefined)
|
||||
// Sort by priority
|
||||
.sort((a, b) => a!.priority - b!.priority) as Task[]
|
||||
)
|
||||
}
|
||||
|
||||
export const contextAgent = async (
|
||||
openai: OpenAIApi,
|
||||
pinecone: PineconeClient,
|
||||
indexName: string,
|
||||
embeddingList: Map<string, number[]>,
|
||||
objective: string,
|
||||
topK: number
|
||||
) => {
|
||||
const index = pinecone.Index(indexName)
|
||||
const queryEmbedding = await getADAEmbedding(openai, objective, embeddingList)
|
||||
|
||||
const results = await index.query({
|
||||
queryRequest: {
|
||||
vector: queryEmbedding,
|
||||
includeMetadata: true,
|
||||
topK
|
||||
}
|
||||
})
|
||||
const sortedResults = results.matches?.sort((a, b) => (b?.score ?? 0) - (a?.score ?? 0)) ?? []
|
||||
|
||||
return sortedResults.map((item) => (item.metadata as any)?.task ?? '')
|
||||
}
|
||||
|
||||
export const executionAgent = async (
|
||||
openai: OpenAIApi,
|
||||
pinecone: PineconeClient,
|
||||
indexName: string,
|
||||
embeddingList: Map<string, number[]>,
|
||||
objective: string,
|
||||
task: Task,
|
||||
gptVersion = 'gpt-3.5-turbo'
|
||||
) => {
|
||||
const context = await contextAgent(openai, pinecone, indexName, embeddingList, objective, 5)
|
||||
const prompt = `You are an AI who performs one task based on the following objective: ${objective}.\nTake into account these previously completed tasks: ${context}\nYour task: ${task.name}\nResponse:`
|
||||
|
||||
//console.log('\nexecution prompt: ', prompt, '\n')
|
||||
|
||||
return openAICall(openai, prompt, gptVersion, 0.7, 2000)
|
||||
}
|
||||
|
||||
export const mainLoop = async (
|
||||
openai: OpenAIApi,
|
||||
pinecone: PineconeClient,
|
||||
indexName: string,
|
||||
embeddingList: Map<string, number[]>,
|
||||
index: VectorOperationsApi,
|
||||
taskList: Task[],
|
||||
objective: string,
|
||||
modelName: string,
|
||||
taskLoop: string
|
||||
): Promise<string> => {
|
||||
const RUN_LIMIT = parseInt(taskLoop, 10) || 3
|
||||
let finalResult = ''
|
||||
|
||||
for (let run = 0; run < RUN_LIMIT; run++) {
|
||||
let enrichedResult: any
|
||||
let task: Task | undefined
|
||||
|
||||
if (taskList.length > 0) {
|
||||
// Step 1: Pull the task
|
||||
task = taskList.shift()
|
||||
|
||||
if (!task) {
|
||||
//console.log('No tasks left to complete. Exiting.')
|
||||
break
|
||||
}
|
||||
|
||||
console.log(`\x1b[95m\x1b[1m\n*****TASK LIST*****\n\x1b[0m\x1b[0m
|
||||
${taskList.map((t) => ` ${t?.priority}. ${t?.name}`).join('\n')}
|
||||
\x1b[92m\x1b[1m\n*****NEXT TASK*****\n\x1b[0m\x1b[0m
|
||||
${task.name}`)
|
||||
|
||||
// Step 2: Execute the task
|
||||
const result = await executionAgent(openai, pinecone, indexName, embeddingList, objective, task)
|
||||
console.log('\x1b[93m\x1b[1m\n*****TASK RESULT*****\n\x1b[0m\x1b[0m')
|
||||
console.log(result)
|
||||
finalResult = result
|
||||
|
||||
// Step 3: Enrich result and store in Pinecone
|
||||
enrichedResult = { data: result }
|
||||
const vector = enrichedResult.data // extract the actual result from the dictionary
|
||||
const embeddingResult = await getADAEmbedding(openai, vector, embeddingList)
|
||||
await index.upsert({
|
||||
upsertRequest: {
|
||||
vectors: [
|
||||
{
|
||||
id: task.id,
|
||||
values: embeddingResult,
|
||||
metadata: { task: task.name, result }
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Step 4: Create new tasks and reprioritize task list
|
||||
if (enrichedResult) {
|
||||
const newTasks = await taskCreationAgent(openai, taskList, objective, enrichedResult.data, task!.name)
|
||||
//console.log('newTasks', newTasks)
|
||||
taskList = [...taskList, ...newTasks]
|
||||
|
||||
taskList = await prioritizationAgent(openai, taskList, task!.priority, objective, modelName)
|
||||
//console.log(`Reprioritized task list: ${taskList.map((t) => `[${t?.priority}] ${t?.id}: ${t?.name}`).join(', ')}`)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return finalResult
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: BabyAGI_Agents }
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-robot" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M7 7h10a2 2 0 0 1 2 2v1l1 1v3l-1 1v3a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-3l-1 -1v-3l1 -1v-1a2 2 0 0 1 2 -2z"></path>
|
||||
<path d="M10 16h4"></path>
|
||||
<circle cx="8.5" cy="11.5" r=".5" fill="currentColor"></circle>
|
||||
<circle cx="15.5" cy="11.5" r=".5" fill="currentColor"></circle>
|
||||
<path d="M9 7l-1 -4"></path>
|
||||
<path d="M15 7l1 -4"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 650 B |
@@ -0,0 +1,262 @@
|
||||
import { LLMChain } from 'langchain/chains'
|
||||
import { BaseChatModel } from 'langchain/chat_models'
|
||||
import { VectorStore } from 'langchain/dist/vectorstores/base'
|
||||
import { Document } from 'langchain/document'
|
||||
import { PromptTemplate } from 'langchain/prompts'
|
||||
|
||||
class TaskCreationChain extends LLMChain {
|
||||
constructor(prompt: PromptTemplate, llm: BaseChatModel) {
|
||||
super({ prompt, llm })
|
||||
}
|
||||
|
||||
static from_llm(llm: BaseChatModel): LLMChain {
|
||||
const taskCreationTemplate: string =
|
||||
'You are a task creation AI that uses the result of an execution agent' +
|
||||
' to create new tasks with the following objective: {objective},' +
|
||||
' The last completed task has the result: {result}.' +
|
||||
' This result was based on this task description: {task_description}.' +
|
||||
' These are incomplete tasks list: {incomplete_tasks}.' +
|
||||
' Based on the result, create new tasks to be completed' +
|
||||
' by the AI system that do not overlap with incomplete tasks.' +
|
||||
' Return the tasks as an array.'
|
||||
|
||||
const prompt = new PromptTemplate({
|
||||
template: taskCreationTemplate,
|
||||
inputVariables: ['result', 'task_description', 'incomplete_tasks', 'objective']
|
||||
})
|
||||
|
||||
return new TaskCreationChain(prompt, llm)
|
||||
}
|
||||
}
|
||||
|
||||
class TaskPrioritizationChain extends LLMChain {
|
||||
constructor(prompt: PromptTemplate, llm: BaseChatModel) {
|
||||
super({ prompt, llm })
|
||||
}
|
||||
|
||||
static from_llm(llm: BaseChatModel): TaskPrioritizationChain {
|
||||
const taskPrioritizationTemplate: string =
|
||||
'You are a task prioritization AI tasked with cleaning the formatting of and reprioritizing' +
|
||||
' the following task list: {task_names}.' +
|
||||
' Consider the ultimate objective of your team: {objective}.' +
|
||||
' Do not remove any tasks. Return the result as a numbered list, like:' +
|
||||
' #. First task' +
|
||||
' #. Second task' +
|
||||
' Start the task list with number {next_task_id}.'
|
||||
const prompt = new PromptTemplate({
|
||||
template: taskPrioritizationTemplate,
|
||||
inputVariables: ['task_names', 'next_task_id', 'objective']
|
||||
})
|
||||
return new TaskPrioritizationChain(prompt, llm)
|
||||
}
|
||||
}
|
||||
|
||||
class ExecutionChain extends LLMChain {
|
||||
constructor(prompt: PromptTemplate, llm: BaseChatModel) {
|
||||
super({ prompt, llm })
|
||||
}
|
||||
|
||||
static from_llm(llm: BaseChatModel): LLMChain {
|
||||
const executionTemplate: string =
|
||||
'You are an AI who performs one task based on the following objective: {objective}.' +
|
||||
' Take into account these previously completed tasks: {context}.' +
|
||||
' Your task: {task}.' +
|
||||
' Response:'
|
||||
|
||||
const prompt = new PromptTemplate({
|
||||
template: executionTemplate,
|
||||
inputVariables: ['objective', 'context', 'task']
|
||||
})
|
||||
|
||||
return new ExecutionChain(prompt, llm)
|
||||
}
|
||||
}
|
||||
|
||||
async function getNextTask(
|
||||
taskCreationChain: LLMChain,
|
||||
result: string,
|
||||
taskDescription: string,
|
||||
taskList: string[],
|
||||
objective: string
|
||||
): Promise<any[]> {
|
||||
const incompleteTasks: string = taskList.join(', ')
|
||||
const response: string = await taskCreationChain.predict({
|
||||
result,
|
||||
task_description: taskDescription,
|
||||
incomplete_tasks: incompleteTasks,
|
||||
objective
|
||||
})
|
||||
|
||||
const newTasks: string[] = response.split('\n')
|
||||
|
||||
return newTasks.filter((taskName) => taskName.trim()).map((taskName) => ({ task_name: taskName }))
|
||||
}
|
||||
|
||||
interface Task {
|
||||
task_id: number
|
||||
task_name: string
|
||||
}
|
||||
|
||||
async function prioritizeTasks(
|
||||
taskPrioritizationChain: LLMChain,
|
||||
thisTaskId: number,
|
||||
taskList: Task[],
|
||||
objective: string
|
||||
): Promise<Task[]> {
|
||||
const next_task_id = thisTaskId + 1
|
||||
const task_names = taskList.map((t) => t.task_name).join(', ')
|
||||
const response = await taskPrioritizationChain.predict({ task_names, next_task_id, objective })
|
||||
const newTasks = response.split('\n')
|
||||
const prioritizedTaskList: Task[] = []
|
||||
|
||||
for (const taskString of newTasks) {
|
||||
if (!taskString.trim()) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue
|
||||
}
|
||||
const taskParts = taskString.trim().split('. ', 2)
|
||||
if (taskParts.length === 2) {
|
||||
const task_id = parseInt(taskParts[0].trim(), 10)
|
||||
const task_name = taskParts[1].trim()
|
||||
prioritizedTaskList.push({ task_id, task_name })
|
||||
}
|
||||
}
|
||||
|
||||
return prioritizedTaskList
|
||||
}
|
||||
|
||||
export async function get_top_tasks(vectorStore: VectorStore, query: string, k: number): Promise<string[]> {
|
||||
const docs = await vectorStore.similaritySearch(query, k)
|
||||
let returnDocs: string[] = []
|
||||
for (const doc of docs) {
|
||||
returnDocs.push(doc.metadata.task)
|
||||
}
|
||||
return returnDocs
|
||||
}
|
||||
|
||||
async function executeTask(vectorStore: VectorStore, executionChain: LLMChain, objective: string, task: string, k = 5): Promise<string> {
|
||||
const context = await get_top_tasks(vectorStore, objective, k)
|
||||
//const docContent = await retrieve_embeddings(table, task, 0.5);
|
||||
//console.log(docContent);
|
||||
return executionChain.predict({ objective, context, task })
|
||||
}
|
||||
|
||||
export class BabyAGI {
|
||||
taskList: Array<Task> = []
|
||||
|
||||
taskCreationChain: TaskCreationChain
|
||||
|
||||
taskPrioritizationChain: TaskPrioritizationChain
|
||||
|
||||
executionChain: ExecutionChain
|
||||
|
||||
taskIdCounter = 1
|
||||
|
||||
vectorStore: VectorStore
|
||||
|
||||
maxIterations = 3
|
||||
|
||||
constructor(
|
||||
taskCreationChain: TaskCreationChain,
|
||||
taskPrioritizationChain: TaskPrioritizationChain,
|
||||
executionChain: ExecutionChain,
|
||||
vectorStore: VectorStore,
|
||||
maxIterations: number
|
||||
) {
|
||||
this.taskCreationChain = taskCreationChain
|
||||
this.taskPrioritizationChain = taskPrioritizationChain
|
||||
this.executionChain = executionChain
|
||||
this.vectorStore = vectorStore
|
||||
this.maxIterations = maxIterations
|
||||
}
|
||||
|
||||
addTask(task: Task) {
|
||||
this.taskList.push(task)
|
||||
}
|
||||
|
||||
printTaskList() {
|
||||
console.log('\x1b[95m\x1b[1m\n*****TASK LIST*****\n\x1b[0m\x1b[0m')
|
||||
this.taskList.forEach((t) => console.log(`${t.task_id}: ${t.task_name}`))
|
||||
}
|
||||
|
||||
printNextTask(task: Task) {
|
||||
console.log('\x1b[92m\x1b[1m\n*****NEXT TASK*****\n\x1b[0m\x1b[0m')
|
||||
console.log(`${task.task_id}: ${task.task_name}`)
|
||||
}
|
||||
|
||||
printTaskResult(result: string) {
|
||||
console.log('\x1b[93m\x1b[1m\n*****TASK RESULT*****\n\x1b[0m\x1b[0m')
|
||||
console.log(result)
|
||||
}
|
||||
|
||||
getInputKeys(): string[] {
|
||||
return ['objective']
|
||||
}
|
||||
|
||||
getOutputKeys(): string[] {
|
||||
return []
|
||||
}
|
||||
|
||||
async call(inputs: Record<string, any>): Promise<string> {
|
||||
const { objective } = inputs
|
||||
const firstTask = inputs.first_task || 'Make a todo list'
|
||||
this.addTask({ task_id: 1, task_name: firstTask })
|
||||
let numIters = 0
|
||||
let loop = true
|
||||
let finalResult = ''
|
||||
|
||||
while (loop) {
|
||||
if (this.taskList.length) {
|
||||
this.printTaskList()
|
||||
|
||||
// Step 1: Pull the first task
|
||||
const task = this.taskList.shift()
|
||||
if (!task) break
|
||||
this.printNextTask(task)
|
||||
|
||||
// Step 2: Execute the task
|
||||
const result = await executeTask(this.vectorStore, this.executionChain, objective, task.task_name)
|
||||
const thisTaskId = task.task_id
|
||||
finalResult = result
|
||||
this.printTaskResult(result)
|
||||
|
||||
// Step 3: Store the result in Pinecone
|
||||
const docs = new Document({ pageContent: result, metadata: { task: task.task_name } })
|
||||
this.vectorStore.addDocuments([docs])
|
||||
|
||||
// Step 4: Create new tasks and reprioritize task list
|
||||
const newTasks = await getNextTask(
|
||||
this.taskCreationChain,
|
||||
result,
|
||||
task.task_name,
|
||||
this.taskList.map((t) => t.task_name),
|
||||
objective
|
||||
)
|
||||
newTasks.forEach((newTask) => {
|
||||
this.taskIdCounter += 1
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
newTask.task_id = this.taskIdCounter
|
||||
this.addTask(newTask)
|
||||
})
|
||||
this.taskList = await prioritizeTasks(this.taskPrioritizationChain, thisTaskId, this.taskList, objective)
|
||||
}
|
||||
|
||||
numIters += 1
|
||||
if (this.maxIterations !== null && numIters === this.maxIterations) {
|
||||
console.log('\x1b[91m\x1b[1m\n*****TASK ENDING*****\n\x1b[0m\x1b[0m')
|
||||
console.log(this.maxIterations)
|
||||
loop = false
|
||||
this.taskList = []
|
||||
}
|
||||
}
|
||||
|
||||
return finalResult
|
||||
}
|
||||
|
||||
static fromLLM(llm: BaseChatModel, vectorstore: VectorStore, maxIterations = 3): BabyAGI {
|
||||
const taskCreationChain = TaskCreationChain.from_llm(llm)
|
||||
const taskPrioritizationChain = TaskPrioritizationChain.from_llm(llm)
|
||||
const executionChain = ExecutionChain.from_llm(llm)
|
||||
return new BabyAGI(taskCreationChain, taskPrioritizationChain, executionChain, vectorstore, maxIterations)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user