-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathac-agi.js
267 lines (232 loc) · 6.85 KB
/
ac-agi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
Pardon the mess this was put together in half a day for the [lablab.ai](https://lablab.ai/event/autonomous-gpt-agents-hackathon) hackathon.
More updates to come
# AC AGI
An autonomous general intelligence that accomplishes a task for you.
Uses human in the loop to provide feedback to the agent.
How to use:
- Enter your task
- Wait for the agent to complete the task
- Assign max-iterations for the agent to loop: 0 for infinite (probably not a good idea ¯\_(ツ)_/¯)
- Profit
Known issues:
- The agent will sometimes get stuck in a loop and not complete the task
- Human feedback is not always helpful
Upcoming features:
- More tools
- Refined prompts
- Better human feedback system
- Better memory system
Possible thanks to the fine folks at [Langchain](https://js.langchain.com/docs/use_cases/autonomous_agents/baby_agi#example-with-tools)
and all the other giants whose shoulders we stand on.
*/
// Name: AC AGI
// Description: An AGI task manager inspired by BabyAGI
// Author: Josh Mabry
// Twitter: @AI_Citizen
import "@johnlindquist/kit";
let { BabyAGI } = await import("langchain/experimental/babyagi");
let { MemoryVectorStore } = await import("langchain/vectorstores/memory");
let { OpenAIEmbeddings } = await import("langchain/embeddings/openai");
let { OpenAI } = await import("langchain/llms/openai");
let { PromptTemplate } = await import("langchain/prompts");
let { LLMChain } = await import("langchain/chains");
let { ChainTool } = await import("langchain/tools");
let { initializeAgentExecutorWithOptions } = await import("langchain/agents");
let { DynamicTool } = await import("langchain/tools");
let { ChatOpenAI } = await import("langchain/chat_models");
let { WebBrowser } = await import("langchain/tools/webbrowser");
let GOOGLE_API_KEY = await env("GOOGLE_API_KEY", {
shortcuts: [
{
name: "Google API Key",
key: `${cmd}+o`,
bar: "right",
onPress: () => {
open("https://developers.google.com/custom-search/v1/introduction");
},
},
],
ignoreBlur: true,
secret: true,
height: PROMPT.HEIGHT.INPUT_ONLY,
});
let GOOGLE_CSE_KEY = await env("GOOGLE_CSE_KEY", {
shortcuts: [
{
name: "Google Custom Search Engine Key",
key: `${cmd}+o`,
bar: "right",
onPress: () => {
open("https://programmablesearchengine.google.com/");
},
},
],
ignoreBlur: true,
secret: true,
height: PROMPT.HEIGHT.INPUT_ONLY,
});
await env("OPENAI_API_KEY", {
hint: `Grab a key from <a href="https://platform.openai.com/account/api-keys">here</a>`,
});
const task = await arg({
placeholder: "Task",
description: "Enter a task for AC AGI to complete",
ignoreBlur: true,
height: PROMPT.HEIGHT.INPUT_ONLY,
});
let maxIterations = await arg({
placeholder: "How many times should AC AGI loop?",
hint: "Leave empty for infinite iterations *use with caution*",
ignoreBlur: true,
height: PROMPT.HEIGHT.INPUT_ONLY,
});
if (maxIterations === "" || maxIterations === "0") {
maxIterations = undefined;
}
//#########################
// BabyAGI method overrides
//#########################
function printTaskList() {
let result = "";
for (const t of this.taskList) {
result += `${t.taskID}: ${t.taskName}\n`;
}
const msg = `### Task List
${result}
`;
let html = md(msg);
log(html);
div({
html,
ignoreBlur: true,
});
}
function printNextTask(task) {
const msg = `### Next Task
${task.taskID}: ${task.taskName}
`;
let html = md(msg);
log(html);
div({
html,
ignoreBlur: true,
});
}
function printTaskResult(result) {
const msg = `### Task Result
${result.trim()}
`;
let html = md(msg);
log(html);
div({
html,
ignoreBlur: true,
});
}
//#############
// Custom Tools
//#############
let html = (str) => str.replace(/ /g, "+");
let fetch = (q) =>
`https://www.googleapis.com/customsearch/v1?key=${GOOGLE_API_KEY}&cx=${GOOGLE_CSE_KEY}&q=${html(
q
)}&sort=date`;
async function search(query) {
let response = await get(fetch(query));
let items = response?.data?.items;
if (items) {
let choices = items.map((item) => ({
name: item.title,
value: item.link,
}));
return JSON.stringify(choices);
}
}
async function humanInput(question) {
const response = await arg({
placeholder: "Human, I need help!",
hint: question,
ignoreBlur: true,
ignoreAbandon: true,
height: PROMPT.HEIGHT.INPUT_ONLY,
});
return response;
}
async function processThought(thought) {
let html = md(`## Thought
${thought.trim()}`);
log(html);
div({
html,
ignoreBlur: true,
});
return thought;
}
const todoPrompt = PromptTemplate.fromTemplate(
"You are a planner/expert todo list creator. Generate a markdown formatted todo list for: {objective}"
);
const tools = [
new ChainTool({
name: "TODO",
chain: new LLMChain({
llm: new ChatOpenAI({ temperature: 0 }),
prompt: todoPrompt,
}),
description:
"Use to make a todo list. Input: users query. Output: the todo list",
}),
new DynamicTool({
name: "Search",
description: "Search web for information",
func: search,
}),
new DynamicTool({
name: "Human Input",
description:
"(Use only as last resort) Ask a human for specific input that you don't know, like a persons name, or DOB, location, etc. Input is question to ask human, output is answer",
func: humanInput,
}),
// I've found that sometimes the agent just needs a dumping ground to rework its thoughts
// this seems to help minimize LLM parsing errors
new DynamicTool({
name: "Thought Processing",
description: `This is useful for when you have a thought that you want to use in a task,
but you want to make sure it's formatted correctly.
Input is your thought and self-critique and output is the processed thought.`,
func: processThought,
}),
];
//##################
// AC AGI is Born
//##################
const taskBeginMsg = md(`
### Executing Task Manager
Goal: ${task}
`);
div({ html: taskBeginMsg, ignoreBlur: true });
const agentExecutor = await initializeAgentExecutorWithOptions(
tools,
new ChatOpenAI({ modelName: "gpt-4", temperature: 0 }),
{
agentType: "zero-shot-react-description",
agentArgs: {
prefix: `You are an AI who performs one task based on the following objective: {objective}.
Take into account these previously completed tasks: {context}.`,
suffix: `Question: {task}
{agent_scratchpad}`,
inputVariables: ["objective", "task", "context", "agent_scratchpad"],
},
}
);
const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());
const babyAGI = BabyAGI.fromLLM({
llm: new ChatOpenAI({ temperature: 0 }),
executionChain: agentExecutor,
vectorstore: vectorStore,
maxIterations: maxIterations,
});
babyAGI.printNextTask = printNextTask;
babyAGI.printTaskList = printTaskList;
babyAGI.printTaskResult = printTaskResult;
await babyAGI.call({ objective: task });