eaglelandsonce commited on
Commit
a3dac62
1 Parent(s): e7e1a5c

Upload 4 files

Browse files
crewai/agents/exceptions.py CHANGED
@@ -5,15 +5,19 @@ class TaskRepeatedUsageException(OutputParserException):
5
  """Exception raised when a task is used twice in a roll."""
6
 
7
  error: str = "TaskRepeatedUsageException"
8
- message: str = "\nI just used the {tool} tool with input {tool_input}. So I already know the result of that.\n"
9
 
10
- def __init__(self, tool: str, tool_input: str):
 
11
  self.tool = tool
12
  self.tool_input = tool_input
13
  self.message = self.message.format(tool=tool, tool_input=tool_input)
14
 
15
  super().__init__(
16
- error=self.error, observation=self.message, send_to_llm=True, llm_output=""
 
 
 
17
  )
18
 
19
  def __str__(self):
 
5
  """Exception raised when a task is used twice in a roll."""
6
 
7
  error: str = "TaskRepeatedUsageException"
8
+ message: str = "I just used the {tool} tool with input {tool_input}. So I already know the result of that and don't need to use it now.\n"
9
 
10
+ def __init__(self, tool: str, tool_input: str, text: str):
11
+ self.text = text
12
  self.tool = tool
13
  self.tool_input = tool_input
14
  self.message = self.message.format(tool=tool, tool_input=tool_input)
15
 
16
  super().__init__(
17
+ error=self.error,
18
+ observation=self.message,
19
+ send_to_llm=True,
20
+ llm_output=self.text,
21
  )
22
 
23
  def __str__(self):
crewai/agents/executor.py CHANGED
@@ -1,4 +1,6 @@
1
- from typing import Dict, Iterator, List, Optional, Tuple, Union
 
 
2
 
3
  from langchain.agents import AgentExecutor
4
  from langchain.agents.agent import ExceptionTool
@@ -6,13 +8,85 @@ from langchain.agents.tools import InvalidTool
6
  from langchain.callbacks.manager import CallbackManagerForChainRun
7
  from langchain_core.agents import AgentAction, AgentFinish, AgentStep
8
  from langchain_core.exceptions import OutputParserException
 
9
  from langchain_core.tools import BaseTool
 
10
 
11
  from ..tools.cache_tools import CacheTools
12
  from .cache.cache_hit import CacheHit
13
 
14
 
15
  class CrewAgentExecutor(AgentExecutor):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def _iter_next_step(
17
  self,
18
  name_to_tool_map: Dict[str, BaseTool],
@@ -34,6 +108,14 @@ class CrewAgentExecutor(AgentExecutor):
34
  callbacks=run_manager.get_child() if run_manager else None,
35
  **inputs,
36
  )
 
 
 
 
 
 
 
 
37
  except OutputParserException as e:
38
  if isinstance(self.handle_parsing_errors, bool):
39
  raise_error = not self.handle_parsing_errors
@@ -70,6 +152,11 @@ class CrewAgentExecutor(AgentExecutor):
70
  callbacks=run_manager.get_child() if run_manager else None,
71
  **tool_run_kwargs,
72
  )
 
 
 
 
 
73
  yield AgentStep(action=output, observation=observation)
74
  return
75
 
@@ -90,12 +177,8 @@ class CrewAgentExecutor(AgentExecutor):
90
  color_mapping[tool.name] = color_mapping[action.tool]
91
 
92
  actions: List[AgentAction]
93
- if isinstance(output, AgentAction):
94
- actions = [output]
95
- else:
96
- actions = output
97
- for agent_action in actions:
98
- yield agent_action
99
  for agent_action in actions:
100
  if run_manager:
101
  run_manager.on_agent_action(agent_action, color="green")
 
1
+ import time
2
+ from textwrap import dedent
3
+ from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
4
 
5
  from langchain.agents import AgentExecutor
6
  from langchain.agents.agent import ExceptionTool
 
8
  from langchain.callbacks.manager import CallbackManagerForChainRun
9
  from langchain_core.agents import AgentAction, AgentFinish, AgentStep
10
  from langchain_core.exceptions import OutputParserException
11
+ from langchain_core.pydantic_v1 import root_validator
12
  from langchain_core.tools import BaseTool
13
+ from langchain_core.utils.input import get_color_mapping
14
 
15
  from ..tools.cache_tools import CacheTools
16
  from .cache.cache_hit import CacheHit
17
 
18
 
19
  class CrewAgentExecutor(AgentExecutor):
20
+ iterations: int = 0
21
+ max_iterations: Optional[int] = 15
22
+ force_answer_max_iterations: Optional[int] = None
23
+
24
+ @root_validator()
25
+ def set_force_answer_max_iterations(cls, values: Dict) -> Dict:
26
+ values["force_answer_max_iterations"] = values["max_iterations"] - 2
27
+ return values
28
+
29
+ def _should_force_answer(self) -> bool:
30
+ return True if self.iterations == self.force_answer_max_iterations else False
31
+
32
+ def _force_answer(self, output: AgentAction):
33
+ return AgentStep(
34
+ action=output,
35
+ observation=dedent(
36
+ """\
37
+ I've used too many tools for this task.
38
+ I'm going to give you my absolute BEST Final answer now and
39
+ not use any more tools."""
40
+ ),
41
+ )
42
+
43
+ def _call(
44
+ self,
45
+ inputs: Dict[str, str],
46
+ run_manager: Optional[CallbackManagerForChainRun] = None,
47
+ ) -> Dict[str, Any]:
48
+ """Run text through and get agent response."""
49
+ # Construct a mapping of tool name to tool for easy lookup
50
+ name_to_tool_map = {tool.name: tool for tool in self.tools}
51
+ # We construct a mapping from each tool to a color, used for logging.
52
+ color_mapping = get_color_mapping(
53
+ [tool.name for tool in self.tools], excluded_colors=["green", "red"]
54
+ )
55
+ intermediate_steps: List[Tuple[AgentAction, str]] = []
56
+ # Let's start tracking the number of iterations and time elapsed
57
+ self.iterations = 0
58
+ time_elapsed = 0.0
59
+ start_time = time.time()
60
+ # We now enter the agent loop (until it returns something).
61
+ while self._should_continue(self.iterations, time_elapsed):
62
+ next_step_output = self._take_next_step(
63
+ name_to_tool_map,
64
+ color_mapping,
65
+ inputs,
66
+ intermediate_steps,
67
+ run_manager=run_manager,
68
+ )
69
+ if isinstance(next_step_output, AgentFinish):
70
+ return self._return(
71
+ next_step_output, intermediate_steps, run_manager=run_manager
72
+ )
73
+
74
+ intermediate_steps.extend(next_step_output)
75
+ if len(next_step_output) == 1:
76
+ next_step_action = next_step_output[0]
77
+ # See if tool should return directly
78
+ tool_return = self._get_tool_return(next_step_action)
79
+ if tool_return is not None:
80
+ return self._return(
81
+ tool_return, intermediate_steps, run_manager=run_manager
82
+ )
83
+ self.iterations += 1
84
+ time_elapsed = time.time() - start_time
85
+ output = self.agent.return_stopped_response(
86
+ self.early_stopping_method, intermediate_steps, **inputs
87
+ )
88
+ return self._return(output, intermediate_steps, run_manager=run_manager)
89
+
90
  def _iter_next_step(
91
  self,
92
  name_to_tool_map: Dict[str, BaseTool],
 
108
  callbacks=run_manager.get_child() if run_manager else None,
109
  **inputs,
110
  )
111
+ if self._should_force_answer():
112
+ if isinstance(output, AgentAction):
113
+ output = output
114
+ else:
115
+ output = output.action
116
+ yield self._force_answer(output)
117
+ return
118
+
119
  except OutputParserException as e:
120
  if isinstance(self.handle_parsing_errors, bool):
121
  raise_error = not self.handle_parsing_errors
 
152
  callbacks=run_manager.get_child() if run_manager else None,
153
  **tool_run_kwargs,
154
  )
155
+
156
+ if self._should_force_answer():
157
+ yield self._force_answer(output)
158
+ return
159
+
160
  yield AgentStep(action=output, observation=observation)
161
  return
162
 
 
177
  color_mapping[tool.name] = color_mapping[action.tool]
178
 
179
  actions: List[AgentAction]
180
+ actions = [output] if isinstance(output, AgentAction) else output
181
+ yield from actions
 
 
 
 
182
  for agent_action in actions:
183
  if run_manager:
184
  run_manager.on_agent_action(agent_action, color="green")
crewai/agents/output_parser.py CHANGED
@@ -52,24 +52,23 @@ class CrewAgentOutputParser(ReActSingleInputOutputParser):
52
  regex = (
53
  r"Action\s*\d*\s*:[\s]*(.*?)[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
54
  )
55
- action_match = re.search(regex, text, re.DOTALL)
56
- if action_match:
57
  action = action_match.group(1).strip()
58
  action_input = action_match.group(2)
59
  tool_input = action_input.strip(" ")
60
  tool_input = tool_input.strip('"')
61
 
62
- last_tool_usage = self.tools_handler.last_used_tool
63
- if last_tool_usage:
64
  usage = {
65
  "tool": action,
66
  "input": tool_input,
67
  }
68
  if usage == last_tool_usage:
69
- raise TaskRepeatedUsageException(tool=action, tool_input=tool_input)
 
 
70
 
71
- result = self.cache.read(action, tool_input)
72
- if result:
73
  action = AgentAction(action, tool_input, text)
74
  return CacheHit(action=action, cache=self.cache)
75
 
 
52
  regex = (
53
  r"Action\s*\d*\s*:[\s]*(.*?)[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
54
  )
55
+ if action_match := re.search(regex, text, re.DOTALL):
 
56
  action = action_match.group(1).strip()
57
  action_input = action_match.group(2)
58
  tool_input = action_input.strip(" ")
59
  tool_input = tool_input.strip('"')
60
 
61
+ if last_tool_usage := self.tools_handler.last_used_tool:
 
62
  usage = {
63
  "tool": action,
64
  "input": tool_input,
65
  }
66
  if usage == last_tool_usage:
67
+ raise TaskRepeatedUsageException(
68
+ tool=action, tool_input=tool_input, text=text
69
+ )
70
 
71
+ if result := self.cache.read(action, tool_input):
 
72
  action = AgentAction(action, tool_input, text)
73
  return CacheHit(action=action, cache=self.cache)
74