Skip to content

Commit bb3a06d

Browse files
authored
Release v0.4.7 (#5094)
2 parents ec47a31 + f26ccda commit bb3a06d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1202
-864
lines changed

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,10 @@ openai/
160160

161161
# news
162162
CURRENT_BULLETIN.md
163+
164+
# AgBenchmark
165+
agbenchmark/reports/
166+
167+
# Nodejs
168+
package-lock.json
169+
package.json

BULLETIN.md

+9-15
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,18 @@
44
📖 *User Guide*: https://docs.agpt.co.
55
👩 *Contributors Wiki*: https://github.com/Significant-Gravitas/Auto-GPT/wiki/Contributing.
66

7-
# v0.4.6 RELEASE HIGHLIGHTS! 🚀
7+
# v0.4.7 RELEASE HIGHLIGHTS! 🚀
88
# -----------------------------
9-
This release includes under-the-hood improvements and bug fixes, including better UTF-8
10-
special character support, workspace write access for sandboxed Python execution,
11-
more robust path resolution for config files and the workspace, and a full restructure
12-
of the Agent class, the "brain" of Auto-GPT, to make it more extensible.
9+
This release introduces initial REST API support, powered by e2b's agent
10+
protocol SDK (https://github.com/e2b-dev/agent-protocol#sdk).
1311

14-
We have also released some documentation updates, including:
12+
It also includes improvements to prompt generation and support
13+
for our new benchmarking tool, Auto-GPT-Benchmarks
14+
(https://github.com/Significant-Gravitas/Auto-GPT-Benchmarks).
1515

16-
- *How to share your system logs*
17-
Visit [docs/share-your-logs.md] to learn how to how to share logs with us
18-
via a log analyzer graciously contributed by https://www.e2b.dev/
16+
We've also moved our documentation to Material Theme, at https://docs.agpt.co.
1917

20-
- *Auto-GPT re-architecture documentation*
21-
You can learn more about the inner-workings of the Auto-GPT re-architecture
22-
released last cycle, via these links:
23-
* [autogpt/core/README.md]
24-
* [autogpt/core/ARCHITECTURE_NOTES.md]
18+
As usual, we've squashed a few bugs and made some under-the-hood improvements.
2519

26-
Take a look at the Release Notes on Github for the full changelog!
20+
Take a look at the Release Notes on Github for the full changelog:
2721
https://github.com/Significant-Gravitas/Auto-GPT/releases.

agbenchmark/benchmarks.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import os
2+
import sys
3+
from pathlib import Path
4+
from typing import Tuple
5+
6+
from autogpt.agents import Agent
7+
from autogpt.app.main import run_interaction_loop
8+
from autogpt.commands import COMMAND_CATEGORIES
9+
from autogpt.config import AIConfig, Config, ConfigBuilder
10+
from autogpt.memory.vector import get_memory
11+
from autogpt.models.command_registry import CommandRegistry
12+
from autogpt.prompts.prompt import DEFAULT_TRIGGERING_PROMPT
13+
from autogpt.workspace import Workspace
14+
15+
PROJECT_DIR = Path().resolve()
16+
17+
18+
def run_specific_agent(task, continuous_mode=False) -> Tuple[str, int]:
19+
agent = bootstrap_agent(task, continuous_mode)
20+
run_interaction_loop(agent)
21+
22+
23+
def bootstrap_agent(task, continuous_mode) -> Agent:
24+
config = ConfigBuilder.build_config_from_env(workdir=PROJECT_DIR)
25+
config.debug_mode = True
26+
config.continuous_mode = continuous_mode
27+
config.temperature = 0
28+
config.plain_output = True
29+
command_registry = CommandRegistry.with_command_modules(COMMAND_CATEGORIES, config)
30+
config.memory_backend = "no_memory"
31+
config.workspace_path = Workspace.init_workspace_directory(config)
32+
config.file_logger_path = Workspace.build_file_logger_path(config.workspace_path)
33+
ai_config = AIConfig(
34+
ai_name="Auto-GPT",
35+
ai_role="a multi-purpose AI assistant.",
36+
ai_goals=[task],
37+
)
38+
ai_config.command_registry = command_registry
39+
return Agent(
40+
memory=get_memory(config),
41+
command_registry=command_registry,
42+
ai_config=ai_config,
43+
config=config,
44+
triggering_prompt=DEFAULT_TRIGGERING_PROMPT,
45+
)
46+
47+
48+
if __name__ == "__main__":
49+
# The first argument is the script name itself, second is the task
50+
if len(sys.argv) != 2:
51+
print("Usage: python script.py <task>")
52+
sys.exit(1)
53+
task = sys.argv[1]
54+
run_specific_agent(task, continuous_mode=True)

agbenchmark/config.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"workspace": "auto_gpt_workspace",
3+
"entry_path": "agbenchmark.benchmarks"
4+
}

agbenchmark/regression_tests.json

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"TestBasicCodeGeneration": {
3+
"difficulty": "basic",
4+
"dependencies": [
5+
"TestWriteFile"
6+
],
7+
"data_path": "agbenchmark/challenges/code/d3"
8+
},
9+
"TestBasicMemory": {
10+
"difficulty": "basic",
11+
"data_path": "agbenchmark/challenges/memory/m1"
12+
},
13+
"TestReadFile": {
14+
"difficulty": "basic",
15+
"dependencies": [
16+
"TestWriteFile"
17+
],
18+
"data_path": "agbenchmark/challenges/interface/read_file"
19+
},
20+
"TestWriteFile": {
21+
"dependencies": [],
22+
"data_path": "agbenchmark/challenges/interface/write_file"
23+
}
24+
}

autogpt/agents/agent.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from autogpt.llm.utils import count_string_tokens
1818
from autogpt.logs import logger
1919
from autogpt.logs.log_cycle import (
20+
CURRENT_CONTEXT_FILE_NAME,
2021
FULL_MESSAGE_HISTORY_FILE_NAME,
2122
NEXT_ACTION_FILE_NAME,
2223
USER_INPUT_FILE_NAME,
@@ -109,6 +110,13 @@ def on_before_think(self, *args, **kwargs) -> ChatSequence:
109110
self.history.raw(),
110111
FULL_MESSAGE_HISTORY_FILE_NAME,
111112
)
113+
self.log_cycle_handler.log_cycle(
114+
self.ai_config.ai_name,
115+
self.created_at,
116+
self.cycle_count,
117+
prompt.raw(),
118+
CURRENT_CONTEXT_FILE_NAME,
119+
)
112120
return prompt
113121

114122
def execute(
@@ -285,10 +293,10 @@ def execute_command(
285293
# Handle non-native commands (e.g. from plugins)
286294
for command in agent.ai_config.prompt_generator.commands:
287295
if (
288-
command_name == command["label"].lower()
289-
or command_name == command["name"].lower()
296+
command_name == command.label.lower()
297+
or command_name == command.name.lower()
290298
):
291-
return command["function"](**arguments)
299+
return command.function(**arguments)
292300

293301
raise RuntimeError(
294302
f"Cannot execute '{command_name}': unknown command."

autogpt/agents/base.py

+101-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

3+
import re
34
from abc import ABCMeta, abstractmethod
4-
from typing import TYPE_CHECKING, Any, Optional
5+
from typing import TYPE_CHECKING, Any, Literal, Optional
56

67
if TYPE_CHECKING:
78
from autogpt.config import AIConfig, Config
@@ -23,6 +24,8 @@
2324
class BaseAgent(metaclass=ABCMeta):
2425
"""Base class for all Auto-GPT agents."""
2526

27+
ThoughtProcessID = Literal["one-shot"]
28+
2629
def __init__(
2730
self,
2831
ai_config: AIConfig,
@@ -91,6 +94,7 @@ def __init__(
9194
def think(
9295
self,
9396
instruction: Optional[str] = None,
97+
thought_process_id: ThoughtProcessID = "one-shot",
9498
) -> tuple[CommandName | None, CommandArgs | None, AgentThoughts]:
9599
"""Runs the agent for one cycle.
96100
@@ -103,9 +107,8 @@ def think(
103107

104108
instruction = instruction or self.default_cycle_instruction
105109

106-
prompt: ChatSequence = self.construct_prompt(instruction)
107-
prompt = self.on_before_think(prompt, instruction)
108-
110+
prompt: ChatSequence = self.construct_prompt(instruction, thought_process_id)
111+
prompt = self.on_before_think(prompt, thought_process_id, instruction)
109112
raw_response = create_chat_completion(
110113
prompt,
111114
self.config,
@@ -115,7 +118,7 @@ def think(
115118
)
116119
self.cycle_count += 1
117120

118-
return self.on_response(raw_response, prompt, instruction)
121+
return self.on_response(raw_response, thought_process_id, prompt, instruction)
119122

120123
@abstractmethod
121124
def execute(
@@ -138,6 +141,7 @@ def execute(
138141

139142
def construct_base_prompt(
140143
self,
144+
thought_process_id: ThoughtProcessID,
141145
prepend_messages: list[Message] = [],
142146
append_messages: list[Message] = [],
143147
reserve_tokens: int = 0,
@@ -179,7 +183,11 @@ def construct_base_prompt(
179183

180184
return prompt
181185

182-
def construct_prompt(self, cycle_instruction: str) -> ChatSequence:
186+
def construct_prompt(
187+
self,
188+
cycle_instruction: str,
189+
thought_process_id: ThoughtProcessID,
190+
) -> ChatSequence:
183191
"""Constructs and returns a prompt with the following structure:
184192
1. System prompt
185193
2. Message history of the agent, truncated & prepended with running summary as needed
@@ -196,14 +204,86 @@ def construct_prompt(self, cycle_instruction: str) -> ChatSequence:
196204
cycle_instruction_tlength = count_message_tokens(
197205
cycle_instruction_msg, self.llm.name
198206
)
199-
prompt = self.construct_base_prompt(reserve_tokens=cycle_instruction_tlength)
207+
208+
append_messages: list[Message] = []
209+
210+
response_format_instr = self.response_format_instruction(thought_process_id)
211+
if response_format_instr:
212+
append_messages.append(Message("system", response_format_instr))
213+
214+
prompt = self.construct_base_prompt(
215+
thought_process_id,
216+
append_messages=append_messages,
217+
reserve_tokens=cycle_instruction_tlength,
218+
)
200219

201220
# ADD user input message ("triggering prompt")
202221
prompt.append(cycle_instruction_msg)
203222

204223
return prompt
205224

206-
def on_before_think(self, prompt: ChatSequence, instruction: str) -> ChatSequence:
225+
# This can be expanded to support multiple types of (inter)actions within an agent
226+
def response_format_instruction(self, thought_process_id: ThoughtProcessID) -> str:
227+
if thought_process_id != "one-shot":
228+
raise NotImplementedError(f"Unknown thought process '{thought_process_id}'")
229+
230+
RESPONSE_FORMAT_WITH_COMMAND = """```ts
231+
interface Response {
232+
thoughts: {
233+
// Thoughts
234+
text: string;
235+
reasoning: string;
236+
// Short markdown-style bullet list that conveys the long-term plan
237+
plan: string;
238+
// Constructive self-criticism
239+
criticism: string;
240+
// Summary of thoughts to say to the user
241+
speak: string;
242+
};
243+
command: {
244+
name: string;
245+
args: Record<string, any>;
246+
};
247+
}
248+
```"""
249+
250+
RESPONSE_FORMAT_WITHOUT_COMMAND = """```ts
251+
interface Response {
252+
thoughts: {
253+
// Thoughts
254+
text: string;
255+
reasoning: string;
256+
// Short markdown-style bullet list that conveys the long-term plan
257+
plan: string;
258+
// Constructive self-criticism
259+
criticism: string;
260+
// Summary of thoughts to say to the user
261+
speak: string;
262+
};
263+
}
264+
```"""
265+
266+
response_format = re.sub(
267+
r"\n\s+",
268+
"\n",
269+
RESPONSE_FORMAT_WITHOUT_COMMAND
270+
if self.config.openai_functions
271+
else RESPONSE_FORMAT_WITH_COMMAND,
272+
)
273+
274+
use_functions = self.config.openai_functions and self.command_registry.commands
275+
return (
276+
f"Respond strictly with JSON{', and also specify a command to use through a function_call' if use_functions else ''}. "
277+
"The JSON should be compatible with the TypeScript type `Response` from the following:\n"
278+
f"{response_format}\n"
279+
)
280+
281+
def on_before_think(
282+
self,
283+
prompt: ChatSequence,
284+
thought_process_id: ThoughtProcessID,
285+
instruction: str,
286+
) -> ChatSequence:
207287
"""Called after constructing the prompt but before executing it.
208288
209289
Calls the `on_planning` hook of any enabled and capable plugins, adding their
@@ -238,7 +318,11 @@ def on_before_think(self, prompt: ChatSequence, instruction: str) -> ChatSequenc
238318
return prompt
239319

240320
def on_response(
241-
self, llm_response: ChatModelResponse, prompt: ChatSequence, instruction: str
321+
self,
322+
llm_response: ChatModelResponse,
323+
thought_process_id: ThoughtProcessID,
324+
prompt: ChatSequence,
325+
instruction: str,
242326
) -> tuple[CommandName | None, CommandArgs | None, AgentThoughts]:
243327
"""Called upon receiving a response from the chat model.
244328
@@ -261,7 +345,9 @@ def on_response(
261345
) # FIXME: support function calls
262346

263347
try:
264-
return self.parse_and_process_response(llm_response, prompt, instruction)
348+
return self.parse_and_process_response(
349+
llm_response, thought_process_id, prompt, instruction
350+
)
265351
except SyntaxError as e:
266352
logger.error(f"Response could not be parsed: {e}")
267353
# TODO: tune this message
@@ -276,7 +362,11 @@ def on_response(
276362

277363
@abstractmethod
278364
def parse_and_process_response(
279-
self, llm_response: ChatModelResponse, prompt: ChatSequence, instruction: str
365+
self,
366+
llm_response: ChatModelResponse,
367+
thought_process_id: ThoughtProcessID,
368+
prompt: ChatSequence,
369+
instruction: str,
280370
) -> tuple[CommandName | None, CommandArgs | None, AgentThoughts]:
281371
"""Validate, parse & process the LLM's response.
282372

0 commit comments

Comments
 (0)