11
11
# See the License for the specific language governing permissions and
12
12
# limitations under the License.
13
13
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
14
- from typing import Any , Dict , List , Optional
14
+ from typing import Any , List , Optional
15
15
16
16
from colorama import Fore
17
17
18
- from camel .agents import BaseToolAgent , ChatAgent , HuggingFaceToolAgent
18
+ from camel .agents import BaseToolAgent , ChatAgent
19
+ from camel .interpreters import (
20
+ BaseInterpreter ,
21
+ InternalPythonInterpreter ,
22
+ SubprocessInterpreter ,
23
+ )
19
24
from camel .messages import BaseMessage
20
25
from camel .responses import ChatAgentResponse
21
26
from camel .types import ModelType
22
- from camel .utils import PythonInterpreter , print_text_animated
27
+ from camel .utils import print_text_animated
23
28
24
29
25
30
class EmbodiedAgent (ChatAgent ):
@@ -34,8 +39,13 @@ class EmbodiedAgent(ChatAgent):
34
39
message_window_size (int, optional): The maximum number of previous
35
40
messages to include in the context window. If `None`, no windowing
36
41
is performed. (default: :obj:`None`)
37
- action_space (List[Any], optional): The action space for the embodied
38
- agent. (default: :obj:`None`)
42
+ tool_agents (List[BaseToolAgent], optional): The tools agents to use in
43
+ the embodied agent. (default: :obj:`None`)
44
+ code_interpreter (BaseInterpreter, optional): The code interpreter to
45
+ execute codes. If `code_interpreter` and `tool_agent` are both
46
+ `None`, default to `SubProcessInterpreter`. If `code_interpreter`
47
+ is `None` and `tool_agents` is not `None`, default to
48
+ `InternalPythonInterpreter`. (default: :obj:`None`)
39
49
verbose (bool, optional): Whether to print the critic's messages.
40
50
logger_color (Any): The color of the logger displayed to the user.
41
51
(default: :obj:`Fore.MAGENTA`)
@@ -47,18 +57,22 @@ def __init__(
47
57
model_type : ModelType = ModelType .GPT_4 ,
48
58
model_config : Optional [Any ] = None ,
49
59
message_window_size : Optional [int ] = None ,
50
- action_space : Optional [List [BaseToolAgent ]] = None ,
60
+ tool_agents : Optional [List [BaseToolAgent ]] = None ,
61
+ code_interpreter : Optional [BaseInterpreter ] = None ,
51
62
verbose : bool = False ,
52
63
logger_color : Any = Fore .MAGENTA ,
53
64
) -> None :
54
- default_action_space = [
55
- HuggingFaceToolAgent ('hugging_face_tool_agent' ,
56
- model_type = model_type .value ),
57
- ]
58
- self .action_space = action_space or default_action_space
59
- action_space_prompt = self .get_action_space_prompt ()
60
- system_message .content = system_message .content .format (
61
- action_space = action_space_prompt )
65
+ self .tool_agents = tool_agents
66
+ self .code_interpreter : BaseInterpreter
67
+ if code_interpreter is not None :
68
+ self .code_interpreter = code_interpreter
69
+ elif self .tool_agents :
70
+ self .code_interpreter = InternalPythonInterpreter ()
71
+ else :
72
+ self .code_interpreter = SubprocessInterpreter ()
73
+
74
+ if self .tool_agents :
75
+ system_message = self ._set_tool_agents (system_message )
62
76
self .verbose = verbose
63
77
self .logger_color = logger_color
64
78
super ().__init__ (
@@ -68,16 +82,41 @@ def __init__(
68
82
message_window_size = message_window_size ,
69
83
)
70
84
71
- def get_action_space_prompt (self ) -> str :
85
+ def _set_tool_agents (self , system_message : BaseMessage ) -> BaseMessage :
86
+ action_space_prompt = self ._get_tool_agents_prompt ()
87
+ result_message = system_message .create_new_instance (
88
+ content = system_message .content .format (
89
+ action_space = action_space_prompt ))
90
+ if self .tool_agents is not None :
91
+ self .code_interpreter .update_action_space (
92
+ {tool .name : tool
93
+ for tool in self .tool_agents })
94
+ return result_message
95
+
96
+ def _get_tool_agents_prompt (self ) -> str :
72
97
r"""Returns the action space prompt.
73
98
74
99
Returns:
75
100
str: The action space prompt.
76
101
"""
77
- return "\n " .join ([
78
- f"*** { action .name } ***:\n { action .description } "
79
- for action in self .action_space
80
- ])
102
+ if self .tool_agents is not None :
103
+ return "\n " .join ([
104
+ f"*** { tool .name } ***:\n { tool .description } "
105
+ for tool in self .tool_agents
106
+ ])
107
+ else :
108
+ return ""
109
+
110
+ def get_tool_agent_names (self ) -> List [str ]:
111
+ r"""Returns the names of tool agents.
112
+
113
+ Returns:
114
+ List[str]: The names of tool agents.
115
+ """
116
+ if self .tool_agents is not None :
117
+ return [tool .name for tool in self .tool_agents ]
118
+ else :
119
+ return []
81
120
82
121
def step (
83
122
self ,
@@ -111,28 +150,24 @@ def step(
111
150
112
151
if len (explanations ) > len (codes ):
113
152
print_text_animated (self .logger_color +
114
- f"> Explanation:\n { explanations } " )
153
+ f"> Explanation:\n { explanations [ - 1 ] } " )
115
154
116
155
content = response .msg .content
117
156
118
157
if codes is not None :
119
- content = "\n > Executed Results:"
120
- action_space : Dict [str , Any ] = {
121
- action .name : action
122
- for action in self .action_space
123
- }
124
- action_space .update ({"print" : print , "enumerate" : enumerate })
125
- interpreter = PythonInterpreter (action_space = action_space )
126
- for block_idx , code in enumerate (codes ):
127
- executed_outputs , _ = code .execute (interpreter )
128
- content += (f"Executing code block { block_idx } :\n "
129
- f" - execution output:\n { executed_outputs } \n "
130
- f" - Local variables:\n { interpreter .state } \n " )
131
- content += "*" * 50 + "\n "
158
+ try :
159
+ content = "\n > Executed Results:\n "
160
+ for block_idx , code in enumerate (codes ):
161
+ executed_output = self .code_interpreter .run (
162
+ code , code .code_type )
163
+ content += (f"Executing code block { block_idx } : {{\n " +
164
+ executed_output + "}\n " )
165
+ except InterruptedError as e :
166
+ content = (f"\n > Running code fail: { e } \n "
167
+ "Please regenerate the code." )
132
168
133
169
# TODO: Handle errors
134
- content = input_message .content + (Fore .RESET +
135
- f"\n > Embodied Actions:\n { content } " )
170
+ content = input_message .content + f"\n > Embodied Actions:\n { content } "
136
171
message = BaseMessage (input_message .role_name , input_message .role_type ,
137
172
input_message .meta_dict , content )
138
173
return ChatAgentResponse ([message ], response .terminated , response .info )
0 commit comments