mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-28 17:48:13 +00:00
Compare commits
3 Commits
1.9.1
...
gl/fix/goo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad2a9271f | ||
|
|
1e27cf3f0f | ||
|
|
cba6d2eb9b |
@@ -37,7 +37,8 @@ class CrewAgentExecutorMixin:
|
|||||||
self.crew
|
self.crew
|
||||||
and self.agent
|
and self.agent
|
||||||
and self.task
|
and self.task
|
||||||
and f"Action: {sanitize_tool_name('Delegate work to coworker')}" not in output.text
|
and f"Action: {sanitize_tool_name('Delegate work to coworker')}"
|
||||||
|
not in output.text
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
@@ -132,10 +133,11 @@ class CrewAgentExecutorMixin:
|
|||||||
and self.crew._long_term_memory
|
and self.crew._long_term_memory
|
||||||
and self.crew._entity_memory is None
|
and self.crew._entity_memory is None
|
||||||
):
|
):
|
||||||
self._printer.print(
|
if self.agent and self.agent.verbose:
|
||||||
content="Long term memory is enabled, but entity memory is not enabled. Please configure entity memory or set memory=True to automatically enable it.",
|
self._printer.print(
|
||||||
color="bold_yellow",
|
content="Long term memory is enabled, but entity memory is not enabled. Please configure entity memory or set memory=True to automatically enable it.",
|
||||||
)
|
color="bold_yellow",
|
||||||
|
)
|
||||||
|
|
||||||
def _ask_human_input(self, final_answer: str) -> str:
|
def _ask_human_input(self, final_answer: str) -> str:
|
||||||
"""Prompt human input with mode-appropriate messaging.
|
"""Prompt human input with mode-appropriate messaging.
|
||||||
|
|||||||
@@ -206,13 +206,14 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
try:
|
try:
|
||||||
formatted_answer = self._invoke_loop()
|
formatted_answer = self._invoke_loop()
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
|
self._printer.print(
|
||||||
color="red",
|
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.ask_for_human_input:
|
if self.ask_for_human_input:
|
||||||
@@ -327,6 +328,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
messages=self.messages,
|
messages=self.messages,
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -341,6 +343,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=self.response_model,
|
response_model=self.response_model,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
# breakpoint()
|
# breakpoint()
|
||||||
if self.response_model is not None:
|
if self.response_model is not None:
|
||||||
@@ -399,6 +402,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
iterations=self.iterations,
|
iterations=self.iterations,
|
||||||
log_error_after=self.log_error_after,
|
log_error_after=self.log_error_after,
|
||||||
printer=self._printer,
|
printer=self._printer,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -413,9 +417,10 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
i18n=self._i18n,
|
i18n=self._i18n,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
self.iterations += 1
|
self.iterations += 1
|
||||||
@@ -461,6 +466,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
messages=self.messages,
|
messages=self.messages,
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
self._show_logs(formatted_answer)
|
self._show_logs(formatted_answer)
|
||||||
return formatted_answer
|
return formatted_answer
|
||||||
@@ -482,6 +488,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=self.response_model,
|
response_model=self.response_model,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if the response is a list of tool calls
|
# Check if the response is a list of tool calls
|
||||||
@@ -535,9 +542,10 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
i18n=self._i18n,
|
i18n=self._i18n,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
self.iterations += 1
|
self.iterations += 1
|
||||||
@@ -559,6 +567,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=self.response_model,
|
response_model=self.response_model,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
formatted_answer = AgentFinish(
|
formatted_answer = AgentFinish(
|
||||||
@@ -755,10 +764,10 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
track_delegation_if_needed(func_name, args_dict, self.task)
|
track_delegation_if_needed(func_name, args_dict, self.task)
|
||||||
|
|
||||||
# Find the structured tool for hook context
|
# Find the structured tool for hook context
|
||||||
structured_tool = None
|
structured_tool: CrewStructuredTool | None = None
|
||||||
for tool in self.tools or []:
|
for structured in self.tools or []:
|
||||||
if sanitize_tool_name(tool.name) == func_name:
|
if sanitize_tool_name(structured.name) == func_name:
|
||||||
structured_tool = tool
|
structured_tool = structured
|
||||||
break
|
break
|
||||||
|
|
||||||
# Execute before_tool_call hooks
|
# Execute before_tool_call hooks
|
||||||
@@ -779,10 +788,11 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
hook_blocked = True
|
hook_blocked = True
|
||||||
break
|
break
|
||||||
except Exception as hook_error:
|
except Exception as hook_error:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content=f"Error in before_tool_call hook: {hook_error}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"Error in before_tool_call hook: {hook_error}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
# If hook blocked execution, set result and skip tool execution
|
# If hook blocked execution, set result and skip tool execution
|
||||||
if hook_blocked:
|
if hook_blocked:
|
||||||
@@ -848,15 +858,16 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
after_hooks = get_after_tool_call_hooks()
|
after_hooks = get_after_tool_call_hooks()
|
||||||
try:
|
try:
|
||||||
for after_hook in after_hooks:
|
for after_hook in after_hooks:
|
||||||
hook_result = after_hook(after_hook_context)
|
after_hook_result = after_hook(after_hook_context)
|
||||||
if hook_result is not None:
|
if after_hook_result is not None:
|
||||||
result = hook_result
|
result = after_hook_result
|
||||||
after_hook_context.tool_result = result
|
after_hook_context.tool_result = result
|
||||||
except Exception as hook_error:
|
except Exception as hook_error:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content=f"Error in after_tool_call hook: {hook_error}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"Error in after_tool_call hook: {hook_error}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
# Emit tool usage finished event
|
# Emit tool usage finished event
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
@@ -942,13 +953,14 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
try:
|
try:
|
||||||
formatted_answer = await self._ainvoke_loop()
|
formatted_answer = await self._ainvoke_loop()
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
|
self._printer.print(
|
||||||
color="red",
|
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.ask_for_human_input:
|
if self.ask_for_human_input:
|
||||||
@@ -999,6 +1011,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
messages=self.messages,
|
messages=self.messages,
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -1013,6 +1026,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=self.response_model,
|
response_model=self.response_model,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.response_model is not None:
|
if self.response_model is not None:
|
||||||
@@ -1070,6 +1084,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
iterations=self.iterations,
|
iterations=self.iterations,
|
||||||
log_error_after=self.log_error_after,
|
log_error_after=self.log_error_after,
|
||||||
printer=self._printer,
|
printer=self._printer,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1083,9 +1098,10 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
i18n=self._i18n,
|
i18n=self._i18n,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
self.iterations += 1
|
self.iterations += 1
|
||||||
@@ -1125,6 +1141,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
messages=self.messages,
|
messages=self.messages,
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
self._show_logs(formatted_answer)
|
self._show_logs(formatted_answer)
|
||||||
return formatted_answer
|
return formatted_answer
|
||||||
@@ -1146,6 +1163,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=self.response_model,
|
response_model=self.response_model,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
# Check if the response is a list of tool calls
|
# Check if the response is a list of tool calls
|
||||||
if (
|
if (
|
||||||
@@ -1198,9 +1216,10 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
i18n=self._i18n,
|
i18n=self._i18n,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
self.iterations += 1
|
self.iterations += 1
|
||||||
@@ -1222,6 +1241,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=self.response_model,
|
response_model=self.response_model,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
formatted_answer = AgentFinish(
|
formatted_answer = AgentFinish(
|
||||||
@@ -1339,10 +1359,11 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if train_iteration is None or not isinstance(train_iteration, int):
|
if train_iteration is None or not isinstance(train_iteration, int):
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content="Invalid or missing train iteration. Cannot save training data.",
|
self._printer.print(
|
||||||
color="red",
|
content="Invalid or missing train iteration. Cannot save training data.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
training_handler = CrewTrainingHandler(TRAINING_DATA_FILE)
|
training_handler = CrewTrainingHandler(TRAINING_DATA_FILE)
|
||||||
@@ -1362,13 +1383,14 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
if train_iteration in agent_training_data:
|
if train_iteration in agent_training_data:
|
||||||
agent_training_data[train_iteration]["improved_output"] = result.output
|
agent_training_data[train_iteration]["improved_output"] = result.output
|
||||||
else:
|
else:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content=(
|
self._printer.print(
|
||||||
f"No existing training data for agent {agent_id} and iteration "
|
content=(
|
||||||
f"{train_iteration}. Cannot save improved output."
|
f"No existing training data for agent {agent_id} and iteration "
|
||||||
),
|
f"{train_iteration}. Cannot save improved output."
|
||||||
color="red",
|
),
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Update the training data and save
|
# Update the training data and save
|
||||||
|
|||||||
@@ -341,6 +341,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
messages=list(self.state.messages),
|
messages=list(self.state.messages),
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.state.current_answer = formatted_answer
|
self.state.current_answer = formatted_answer
|
||||||
@@ -366,6 +367,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=None,
|
response_model=None,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Parse the LLM response
|
# Parse the LLM response
|
||||||
@@ -401,7 +403,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
return "context_error"
|
return "context_error"
|
||||||
if e.__class__.__module__.startswith("litellm"):
|
if e.__class__.__module__.startswith("litellm"):
|
||||||
raise e
|
raise e
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@listen("continue_reasoning_native")
|
@listen("continue_reasoning_native")
|
||||||
@@ -436,6 +438,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
from_agent=self.agent,
|
from_agent=self.agent,
|
||||||
response_model=None,
|
response_model=None,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if the response is a list of tool calls
|
# Check if the response is a list of tool calls
|
||||||
@@ -474,7 +477,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
return "context_error"
|
return "context_error"
|
||||||
if e.__class__.__module__.startswith("litellm"):
|
if e.__class__.__module__.startswith("litellm"):
|
||||||
raise e
|
raise e
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@router(call_llm_and_parse)
|
@router(call_llm_and_parse)
|
||||||
@@ -670,10 +673,10 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
|
|
||||||
track_delegation_if_needed(func_name, args_dict, self.task)
|
track_delegation_if_needed(func_name, args_dict, self.task)
|
||||||
|
|
||||||
structured_tool = None
|
structured_tool: CrewStructuredTool | None = None
|
||||||
for tool in self.tools or []:
|
for structured in self.tools or []:
|
||||||
if sanitize_tool_name(tool.name) == func_name:
|
if sanitize_tool_name(structured.name) == func_name:
|
||||||
structured_tool = tool
|
structured_tool = structured
|
||||||
break
|
break
|
||||||
|
|
||||||
hook_blocked = False
|
hook_blocked = False
|
||||||
@@ -693,10 +696,11 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
hook_blocked = True
|
hook_blocked = True
|
||||||
break
|
break
|
||||||
except Exception as hook_error:
|
except Exception as hook_error:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content=f"Error in before_tool_call hook: {hook_error}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"Error in before_tool_call hook: {hook_error}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
if hook_blocked:
|
if hook_blocked:
|
||||||
result = f"Tool execution blocked by hook. Tool: {func_name}"
|
result = f"Tool execution blocked by hook. Tool: {func_name}"
|
||||||
@@ -758,15 +762,16 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
after_hooks = get_after_tool_call_hooks()
|
after_hooks = get_after_tool_call_hooks()
|
||||||
try:
|
try:
|
||||||
for after_hook in after_hooks:
|
for after_hook in after_hooks:
|
||||||
hook_result = after_hook(after_hook_context)
|
after_hook_result = after_hook(after_hook_context)
|
||||||
if hook_result is not None:
|
if after_hook_result is not None:
|
||||||
result = hook_result
|
result = after_hook_result
|
||||||
after_hook_context.tool_result = result
|
after_hook_context.tool_result = result
|
||||||
except Exception as hook_error:
|
except Exception as hook_error:
|
||||||
self._printer.print(
|
if self.agent.verbose:
|
||||||
content=f"Error in after_tool_call hook: {hook_error}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"Error in after_tool_call hook: {hook_error}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
# Emit tool usage finished event
|
# Emit tool usage finished event
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
@@ -911,6 +916,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
iterations=self.state.iterations,
|
iterations=self.state.iterations,
|
||||||
log_error_after=self.log_error_after,
|
log_error_after=self.log_error_after,
|
||||||
printer=self._printer,
|
printer=self._printer,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
if formatted_answer:
|
if formatted_answer:
|
||||||
@@ -930,6 +936,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
callbacks=self.callbacks,
|
callbacks=self.callbacks,
|
||||||
i18n=self._i18n,
|
i18n=self._i18n,
|
||||||
|
verbose=self.agent.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.state.iterations += 1
|
self.state.iterations += 1
|
||||||
@@ -1021,7 +1028,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
self._console.print(fail_text)
|
self._console.print(fail_text)
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
self._is_executing = False
|
self._is_executing = False
|
||||||
@@ -1106,7 +1113,7 @@ class AgentExecutor(Flow[AgentReActState], CrewAgentExecutorMixin):
|
|||||||
self._console.print(fail_text)
|
self._console.print(fail_text)
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
self._is_executing = False
|
self._is_executing = False
|
||||||
|
|||||||
@@ -118,17 +118,20 @@ class PersistenceDecorator:
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = LOG_MESSAGES["save_error"].format(method_name, str(e))
|
error_msg = LOG_MESSAGES["save_error"].format(method_name, str(e))
|
||||||
cls._printer.print(error_msg, color="red")
|
if verbose:
|
||||||
|
cls._printer.print(error_msg, color="red")
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
raise RuntimeError(f"State persistence failed: {e!s}") from e
|
raise RuntimeError(f"State persistence failed: {e!s}") from e
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
error_msg = LOG_MESSAGES["state_missing"]
|
error_msg = LOG_MESSAGES["state_missing"]
|
||||||
cls._printer.print(error_msg, color="red")
|
if verbose:
|
||||||
|
cls._printer.print(error_msg, color="red")
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
raise ValueError(error_msg) from e
|
raise ValueError(error_msg) from e
|
||||||
except (TypeError, ValueError) as e:
|
except (TypeError, ValueError) as e:
|
||||||
error_msg = LOG_MESSAGES["id_missing"]
|
error_msg = LOG_MESSAGES["id_missing"]
|
||||||
cls._printer.print(error_msg, color="red")
|
if verbose:
|
||||||
|
cls._printer.print(error_msg, color="red")
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
raise ValueError(error_msg) from e
|
raise ValueError(error_msg) from e
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ def _unwrap_function(function: Any) -> Any:
|
|||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
||||||
def get_possible_return_constants(function: Any) -> list[str] | None:
|
def get_possible_return_constants(
|
||||||
|
function: Any, verbose: bool = True
|
||||||
|
) -> list[str] | None:
|
||||||
"""Extract possible string return values from a function using AST parsing.
|
"""Extract possible string return values from a function using AST parsing.
|
||||||
|
|
||||||
This function analyzes the source code of a router method to identify
|
This function analyzes the source code of a router method to identify
|
||||||
@@ -178,10 +180,11 @@ def get_possible_return_constants(function: Any) -> list[str] | None:
|
|||||||
# Can't get source code
|
# Can't get source code
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_printer.print(
|
if verbose:
|
||||||
f"Error retrieving source code for function {function.__name__}: {e}",
|
_printer.print(
|
||||||
color="red",
|
f"Error retrieving source code for function {function.__name__}: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -190,25 +193,28 @@ def get_possible_return_constants(function: Any) -> list[str] | None:
|
|||||||
# Parse the source code into an AST
|
# Parse the source code into an AST
|
||||||
code_ast = ast.parse(source)
|
code_ast = ast.parse(source)
|
||||||
except IndentationError as e:
|
except IndentationError as e:
|
||||||
_printer.print(
|
if verbose:
|
||||||
f"IndentationError while parsing source code of {function.__name__}: {e}",
|
_printer.print(
|
||||||
color="red",
|
f"IndentationError while parsing source code of {function.__name__}: {e}",
|
||||||
)
|
color="red",
|
||||||
_printer.print(f"Source code:\n{source}", color="yellow")
|
)
|
||||||
|
_printer.print(f"Source code:\n{source}", color="yellow")
|
||||||
return None
|
return None
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
_printer.print(
|
if verbose:
|
||||||
f"SyntaxError while parsing source code of {function.__name__}: {e}",
|
_printer.print(
|
||||||
color="red",
|
f"SyntaxError while parsing source code of {function.__name__}: {e}",
|
||||||
)
|
color="red",
|
||||||
_printer.print(f"Source code:\n{source}", color="yellow")
|
)
|
||||||
|
_printer.print(f"Source code:\n{source}", color="yellow")
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_printer.print(
|
if verbose:
|
||||||
f"Unexpected error while parsing source code of {function.__name__}: {e}",
|
_printer.print(
|
||||||
color="red",
|
f"Unexpected error while parsing source code of {function.__name__}: {e}",
|
||||||
)
|
color="red",
|
||||||
_printer.print(f"Source code:\n{source}", color="yellow")
|
)
|
||||||
|
_printer.print(f"Source code:\n{source}", color="yellow")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return_values: set[str] = set()
|
return_values: set[str] = set()
|
||||||
@@ -388,15 +394,17 @@ def get_possible_return_constants(function: Any) -> list[str] | None:
|
|||||||
|
|
||||||
StateAttributeVisitor().visit(class_ast)
|
StateAttributeVisitor().visit(class_ast)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_printer.print(
|
if verbose:
|
||||||
f"Could not analyze class context for {function.__name__}: {e}",
|
_printer.print(
|
||||||
color="yellow",
|
f"Could not analyze class context for {function.__name__}: {e}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_printer.print(
|
if verbose:
|
||||||
f"Could not introspect class for {function.__name__}: {e}",
|
_printer.print(
|
||||||
color="yellow",
|
f"Could not introspect class for {function.__name__}: {e}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
VariableAssignmentVisitor().visit(code_ast)
|
VariableAssignmentVisitor().visit(code_ast)
|
||||||
ReturnVisitor().visit(code_ast)
|
ReturnVisitor().visit(code_ast)
|
||||||
|
|||||||
@@ -72,13 +72,13 @@ from crewai.utilities.agent_utils import (
|
|||||||
from crewai.utilities.converter import (
|
from crewai.utilities.converter import (
|
||||||
Converter,
|
Converter,
|
||||||
ConverterError,
|
ConverterError,
|
||||||
generate_model_description,
|
|
||||||
)
|
)
|
||||||
from crewai.utilities.guardrail import process_guardrail
|
from crewai.utilities.guardrail import process_guardrail
|
||||||
from crewai.utilities.guardrail_types import GuardrailCallable, GuardrailType
|
from crewai.utilities.guardrail_types import GuardrailCallable, GuardrailType
|
||||||
from crewai.utilities.i18n import I18N, get_i18n
|
from crewai.utilities.i18n import I18N, get_i18n
|
||||||
from crewai.utilities.llm_utils import create_llm
|
from crewai.utilities.llm_utils import create_llm
|
||||||
from crewai.utilities.printer import Printer
|
from crewai.utilities.printer import Printer
|
||||||
|
from crewai.utilities.pydantic_schema_utils import generate_model_description
|
||||||
from crewai.utilities.token_counter_callback import TokenCalcHandler
|
from crewai.utilities.token_counter_callback import TokenCalcHandler
|
||||||
from crewai.utilities.tool_utils import execute_tool_and_check_finality
|
from crewai.utilities.tool_utils import execute_tool_and_check_finality
|
||||||
from crewai.utilities.types import LLMMessage
|
from crewai.utilities.types import LLMMessage
|
||||||
@@ -344,11 +344,12 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._printer.print(
|
if self.verbose:
|
||||||
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
|
self._printer.print(
|
||||||
color="red",
|
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
|
||||||
)
|
color="red",
|
||||||
handle_unknown_error(self._printer, e)
|
)
|
||||||
|
handle_unknown_error(self._printer, e, verbose=self.verbose)
|
||||||
# Emit error event
|
# Emit error event
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
@@ -396,10 +397,11 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
if isinstance(result, BaseModel):
|
if isinstance(result, BaseModel):
|
||||||
formatted_result = result
|
formatted_result = result
|
||||||
except ConverterError as e:
|
except ConverterError as e:
|
||||||
self._printer.print(
|
if self.verbose:
|
||||||
content=f"Failed to parse output into response format after retries: {e.message}",
|
self._printer.print(
|
||||||
color="yellow",
|
content=f"Failed to parse output into response format after retries: {e.message}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
# Calculate token usage metrics
|
# Calculate token usage metrics
|
||||||
if isinstance(self.llm, BaseLLM):
|
if isinstance(self.llm, BaseLLM):
|
||||||
@@ -605,6 +607,7 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
messages=self._messages,
|
messages=self._messages,
|
||||||
llm=cast(LLM, self.llm),
|
llm=cast(LLM, self.llm),
|
||||||
callbacks=self._callbacks,
|
callbacks=self._callbacks,
|
||||||
|
verbose=self.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
enforce_rpm_limit(self.request_within_rpm_limit)
|
enforce_rpm_limit(self.request_within_rpm_limit)
|
||||||
@@ -617,6 +620,7 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
printer=self._printer,
|
printer=self._printer,
|
||||||
from_agent=self,
|
from_agent=self,
|
||||||
executor_context=self,
|
executor_context=self,
|
||||||
|
verbose=self.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -646,16 +650,18 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
|
|
||||||
self._append_message(formatted_answer.text, role="assistant")
|
self._append_message(formatted_answer.text, role="assistant")
|
||||||
except OutputParserError as e: # noqa: PERF203
|
except OutputParserError as e: # noqa: PERF203
|
||||||
self._printer.print(
|
if self.verbose:
|
||||||
content="Failed to parse LLM output. Retrying...",
|
self._printer.print(
|
||||||
color="yellow",
|
content="Failed to parse LLM output. Retrying...",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
formatted_answer = handle_output_parser_exception(
|
formatted_answer = handle_output_parser_exception(
|
||||||
e=e,
|
e=e,
|
||||||
messages=self._messages,
|
messages=self._messages,
|
||||||
iterations=self._iterations,
|
iterations=self._iterations,
|
||||||
log_error_after=3,
|
log_error_after=3,
|
||||||
printer=self._printer,
|
printer=self._printer,
|
||||||
|
verbose=self.verbose,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -670,9 +676,10 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
llm=cast(LLM, self.llm),
|
llm=cast(LLM, self.llm),
|
||||||
callbacks=self._callbacks,
|
callbacks=self._callbacks,
|
||||||
i18n=self.i18n,
|
i18n=self.i18n,
|
||||||
|
verbose=self.verbose,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
handle_unknown_error(self._printer, e)
|
handle_unknown_error(self._printer, e, verbose=self.verbose)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ class BaseLLM(ABC):
|
|||||||
from_agent: Agent | None = None,
|
from_agent: Agent | None = None,
|
||||||
tool_call: dict[str, Any] | None = None,
|
tool_call: dict[str, Any] | None = None,
|
||||||
call_type: LLMCallType | None = None,
|
call_type: LLMCallType | None = None,
|
||||||
response_id: str | None = None
|
response_id: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Emit stream chunk event.
|
"""Emit stream chunk event.
|
||||||
|
|
||||||
@@ -427,7 +427,7 @@ class BaseLLM(ABC):
|
|||||||
from_task=from_task,
|
from_task=from_task,
|
||||||
from_agent=from_agent,
|
from_agent=from_agent,
|
||||||
call_type=call_type,
|
call_type=call_type,
|
||||||
response_id=response_id
|
response_id=response_id,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -497,7 +497,7 @@ class BaseLLM(ABC):
|
|||||||
from_agent=from_agent,
|
from_agent=from_agent,
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return str(result) if not isinstance(result, str) else result
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Error executing function '{function_name}': {e!s}"
|
error_msg = f"Error executing function '{function_name}': {e!s}"
|
||||||
@@ -737,22 +737,25 @@ class BaseLLM(ABC):
|
|||||||
task=None,
|
task=None,
|
||||||
crew=None,
|
crew=None,
|
||||||
)
|
)
|
||||||
|
verbose = getattr(from_agent, "verbose", True) if from_agent else True
|
||||||
printer = Printer()
|
printer = Printer()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for hook in before_hooks:
|
for hook in before_hooks:
|
||||||
result = hook(hook_context)
|
result = hook(hook_context)
|
||||||
if result is False:
|
if result is False:
|
||||||
printer.print(
|
if verbose:
|
||||||
content="LLM call blocked by before_llm_call hook",
|
printer.print(
|
||||||
color="yellow",
|
content="LLM call blocked by before_llm_call hook",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printer.print(
|
if verbose:
|
||||||
content=f"Error in before_llm_call hook: {e}",
|
printer.print(
|
||||||
color="yellow",
|
content=f"Error in before_llm_call hook: {e}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -805,6 +808,7 @@ class BaseLLM(ABC):
|
|||||||
crew=None,
|
crew=None,
|
||||||
response=response,
|
response=response,
|
||||||
)
|
)
|
||||||
|
verbose = getattr(from_agent, "verbose", True) if from_agent else True
|
||||||
printer = Printer()
|
printer = Printer()
|
||||||
modified_response = response
|
modified_response = response
|
||||||
|
|
||||||
@@ -815,9 +819,10 @@ class BaseLLM(ABC):
|
|||||||
modified_response = result
|
modified_response = result
|
||||||
hook_context.response = modified_response
|
hook_context.response = modified_response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printer.print(
|
if verbose:
|
||||||
content=f"Error in after_llm_call hook: {e}",
|
printer.print(
|
||||||
color="yellow",
|
content=f"Error in after_llm_call hook: {e}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
return modified_response
|
return modified_response
|
||||||
|
|||||||
@@ -466,9 +466,9 @@ class GeminiCompletion(BaseLLM):
|
|||||||
if response_model:
|
if response_model:
|
||||||
config_params["response_mime_type"] = "application/json"
|
config_params["response_mime_type"] = "application/json"
|
||||||
schema_output = generate_model_description(response_model)
|
schema_output = generate_model_description(response_model)
|
||||||
config_params["response_schema"] = schema_output.get("json_schema", {}).get(
|
config_params["response_json_schema"] = schema_output.get(
|
||||||
"schema", {}
|
"json_schema", {}
|
||||||
)
|
).get("schema", {})
|
||||||
|
|
||||||
# Handle tools for supported models
|
# Handle tools for supported models
|
||||||
if tools and self.supports_tools:
|
if tools and self.supports_tools:
|
||||||
|
|||||||
@@ -12,15 +12,17 @@ from crewai.utilities.paths import db_storage_path
|
|||||||
class LTMSQLiteStorage:
|
class LTMSQLiteStorage:
|
||||||
"""SQLite storage class for long-term memory data."""
|
"""SQLite storage class for long-term memory data."""
|
||||||
|
|
||||||
def __init__(self, db_path: str | None = None) -> None:
|
def __init__(self, db_path: str | None = None, verbose: bool = True) -> None:
|
||||||
"""Initialize the SQLite storage.
|
"""Initialize the SQLite storage.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
db_path: Optional path to the database file.
|
db_path: Optional path to the database file.
|
||||||
|
verbose: Whether to print error messages.
|
||||||
"""
|
"""
|
||||||
if db_path is None:
|
if db_path is None:
|
||||||
db_path = str(Path(db_storage_path()) / "long_term_memory_storage.db")
|
db_path = str(Path(db_storage_path()) / "long_term_memory_storage.db")
|
||||||
self.db_path = db_path
|
self.db_path = db_path
|
||||||
|
self._verbose = verbose
|
||||||
self._printer: Printer = Printer()
|
self._printer: Printer = Printer()
|
||||||
Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)
|
Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
self._initialize_db()
|
self._initialize_db()
|
||||||
@@ -44,10 +46,11 @@ class LTMSQLiteStorage:
|
|||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred during database initialization: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred during database initialization: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
def save(
|
def save(
|
||||||
self,
|
self,
|
||||||
@@ -69,10 +72,11 @@ class LTMSQLiteStorage:
|
|||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred while saving to LTM: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred while saving to LTM: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
def load(self, task_description: str, latest_n: int) -> list[dict[str, Any]] | None:
|
def load(self, task_description: str, latest_n: int) -> list[dict[str, Any]] | None:
|
||||||
"""Queries the LTM table by task description with error handling."""
|
"""Queries the LTM table by task description with error handling."""
|
||||||
@@ -101,10 +105,11 @@ class LTMSQLiteStorage:
|
|||||||
]
|
]
|
||||||
|
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred while querying LTM: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred while querying LTM: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
@@ -116,10 +121,11 @@ class LTMSQLiteStorage:
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred while deleting all rows in LTM: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred while deleting all rows in LTM: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
async def asave(
|
async def asave(
|
||||||
self,
|
self,
|
||||||
@@ -147,10 +153,11 @@ class LTMSQLiteStorage:
|
|||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiosqlite.Error as e:
|
except aiosqlite.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred while saving to LTM: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred while saving to LTM: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
async def aload(
|
async def aload(
|
||||||
self, task_description: str, latest_n: int
|
self, task_description: str, latest_n: int
|
||||||
@@ -187,10 +194,11 @@ class LTMSQLiteStorage:
|
|||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
except aiosqlite.Error as e:
|
except aiosqlite.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred while querying LTM: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred while querying LTM: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def areset(self) -> None:
|
async def areset(self) -> None:
|
||||||
@@ -200,7 +208,8 @@ class LTMSQLiteStorage:
|
|||||||
await conn.execute("DELETE FROM long_term_memories")
|
await conn.execute("DELETE FROM long_term_memories")
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiosqlite.Error as e:
|
except aiosqlite.Error as e:
|
||||||
self._printer.print(
|
if self._verbose:
|
||||||
content=f"MEMORY ERROR: An error occurred while deleting all rows in LTM: {e}",
|
self._printer.print(
|
||||||
color="red",
|
content=f"MEMORY ERROR: An error occurred while deleting all rows in LTM: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"""IBM WatsonX embedding function implementation."""
|
"""IBM WatsonX embedding function implementation."""
|
||||||
|
|
||||||
from typing import cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from chromadb.api.types import Documents, EmbeddingFunction, Embeddings
|
from chromadb.api.types import Documents, EmbeddingFunction, Embeddings
|
||||||
from typing_extensions import Unpack
|
from typing_extensions import Unpack
|
||||||
@@ -15,14 +15,18 @@ _printer = Printer()
|
|||||||
class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
|
class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
|
||||||
"""Embedding function for IBM WatsonX models."""
|
"""Embedding function for IBM WatsonX models."""
|
||||||
|
|
||||||
def __init__(self, **kwargs: Unpack[WatsonXProviderConfig]) -> None:
|
def __init__(
|
||||||
|
self, *, verbose: bool = True, **kwargs: Unpack[WatsonXProviderConfig]
|
||||||
|
) -> None:
|
||||||
"""Initialize WatsonX embedding function.
|
"""Initialize WatsonX embedding function.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
verbose: Whether to print error messages.
|
||||||
**kwargs: Configuration parameters for WatsonX Embeddings and Credentials.
|
**kwargs: Configuration parameters for WatsonX Embeddings and Credentials.
|
||||||
"""
|
"""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self._config = kwargs
|
self._config = kwargs
|
||||||
|
self._verbose = verbose
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def name() -> str:
|
def name() -> str:
|
||||||
@@ -56,7 +60,7 @@ class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
|
|||||||
if isinstance(input, str):
|
if isinstance(input, str):
|
||||||
input = [input]
|
input = [input]
|
||||||
|
|
||||||
embeddings_config: dict = {
|
embeddings_config: dict[str, Any] = {
|
||||||
"model_id": self._config["model_id"],
|
"model_id": self._config["model_id"],
|
||||||
}
|
}
|
||||||
if "params" in self._config and self._config["params"] is not None:
|
if "params" in self._config and self._config["params"] is not None:
|
||||||
@@ -90,7 +94,7 @@ class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
|
|||||||
if "credentials" in self._config and self._config["credentials"] is not None:
|
if "credentials" in self._config and self._config["credentials"] is not None:
|
||||||
embeddings_config["credentials"] = self._config["credentials"]
|
embeddings_config["credentials"] = self._config["credentials"]
|
||||||
else:
|
else:
|
||||||
cred_config: dict = {}
|
cred_config: dict[str, Any] = {}
|
||||||
if "url" in self._config and self._config["url"] is not None:
|
if "url" in self._config and self._config["url"] is not None:
|
||||||
cred_config["url"] = self._config["url"]
|
cred_config["url"] = self._config["url"]
|
||||||
if "api_key" in self._config and self._config["api_key"] is not None:
|
if "api_key" in self._config and self._config["api_key"] is not None:
|
||||||
@@ -159,5 +163,6 @@ class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
|
|||||||
embeddings = embedding.embed_documents(input)
|
embeddings = embedding.embed_documents(input)
|
||||||
return cast(Embeddings, embeddings)
|
return cast(Embeddings, embeddings)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_printer.print(f"Error during WatsonX embedding: {e}", color="red")
|
if self._verbose:
|
||||||
|
_printer.print(f"Error during WatsonX embedding: {e}", color="red")
|
||||||
raise
|
raise
|
||||||
|
|||||||
@@ -767,10 +767,11 @@ class Task(BaseModel):
|
|||||||
if files:
|
if files:
|
||||||
supported_types: list[str] = []
|
supported_types: list[str] = []
|
||||||
if self.agent.llm and self.agent.llm.supports_multimodal():
|
if self.agent.llm and self.agent.llm.supports_multimodal():
|
||||||
provider = getattr(self.agent.llm, "provider", None) or getattr(
|
provider: str = str(
|
||||||
self.agent.llm, "model", "openai"
|
getattr(self.agent.llm, "provider", None)
|
||||||
|
or getattr(self.agent.llm, "model", "openai")
|
||||||
)
|
)
|
||||||
api = getattr(self.agent.llm, "api", None)
|
api: str | None = getattr(self.agent.llm, "api", None)
|
||||||
supported_types = get_supported_content_types(provider, api)
|
supported_types = get_supported_content_types(provider, api)
|
||||||
|
|
||||||
def is_auto_injected(content_type: str) -> bool:
|
def is_auto_injected(content_type: str) -> bool:
|
||||||
@@ -887,10 +888,11 @@ Follow these guidelines:
|
|||||||
try:
|
try:
|
||||||
crew_chat_messages = json.loads(crew_chat_messages_json)
|
crew_chat_messages = json.loads(crew_chat_messages_json)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
_printer.print(
|
if self.agent and self.agent.verbose:
|
||||||
f"An error occurred while parsing crew chat messages: {e}",
|
_printer.print(
|
||||||
color="red",
|
f"An error occurred while parsing crew chat messages: {e}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
conversation_history = "\n".join(
|
conversation_history = "\n".join(
|
||||||
@@ -1132,11 +1134,12 @@ Follow these guidelines:
|
|||||||
guardrail_result_error=guardrail_result.error,
|
guardrail_result_error=guardrail_result.error,
|
||||||
task_output=task_output.raw,
|
task_output=task_output.raw,
|
||||||
)
|
)
|
||||||
printer = Printer()
|
if agent and agent.verbose:
|
||||||
printer.print(
|
printer = Printer()
|
||||||
content=f"Guardrail {guardrail_index if guardrail_index is not None else ''} blocked (attempt {attempt + 1}/{max_attempts}), retrying due to: {guardrail_result.error}\n",
|
printer.print(
|
||||||
color="yellow",
|
content=f"Guardrail {guardrail_index if guardrail_index is not None else ''} blocked (attempt {attempt + 1}/{max_attempts}), retrying due to: {guardrail_result.error}\n",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
# Regenerate output from agent
|
# Regenerate output from agent
|
||||||
result = agent.execute_task(
|
result = agent.execute_task(
|
||||||
@@ -1229,11 +1232,12 @@ Follow these guidelines:
|
|||||||
guardrail_result_error=guardrail_result.error,
|
guardrail_result_error=guardrail_result.error,
|
||||||
task_output=task_output.raw,
|
task_output=task_output.raw,
|
||||||
)
|
)
|
||||||
printer = Printer()
|
if agent and agent.verbose:
|
||||||
printer.print(
|
printer = Printer()
|
||||||
content=f"Guardrail {guardrail_index if guardrail_index is not None else ''} blocked (attempt {attempt + 1}/{max_attempts}), retrying due to: {guardrail_result.error}\n",
|
printer.print(
|
||||||
color="yellow",
|
content=f"Guardrail {guardrail_index if guardrail_index is not None else ''} blocked (attempt {attempt + 1}/{max_attempts}), retrying due to: {guardrail_result.error}\n",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
result = await agent.aexecute_task(
|
result = await agent.aexecute_task(
|
||||||
task=self,
|
task=self,
|
||||||
|
|||||||
@@ -384,6 +384,8 @@ class ToolUsage:
|
|||||||
if (
|
if (
|
||||||
hasattr(available_tool, "max_usage_count")
|
hasattr(available_tool, "max_usage_count")
|
||||||
and available_tool.max_usage_count is not None
|
and available_tool.max_usage_count is not None
|
||||||
|
and self.agent
|
||||||
|
and self.agent.verbose
|
||||||
):
|
):
|
||||||
self._printer.print(
|
self._printer.print(
|
||||||
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
||||||
@@ -396,6 +398,8 @@ class ToolUsage:
|
|||||||
if (
|
if (
|
||||||
hasattr(available_tool, "max_usage_count")
|
hasattr(available_tool, "max_usage_count")
|
||||||
and available_tool.max_usage_count is not None
|
and available_tool.max_usage_count is not None
|
||||||
|
and self.agent
|
||||||
|
and self.agent.verbose
|
||||||
):
|
):
|
||||||
self._printer.print(
|
self._printer.print(
|
||||||
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
||||||
@@ -610,6 +614,8 @@ class ToolUsage:
|
|||||||
if (
|
if (
|
||||||
hasattr(available_tool, "max_usage_count")
|
hasattr(available_tool, "max_usage_count")
|
||||||
and available_tool.max_usage_count is not None
|
and available_tool.max_usage_count is not None
|
||||||
|
and self.agent
|
||||||
|
and self.agent.verbose
|
||||||
):
|
):
|
||||||
self._printer.print(
|
self._printer.print(
|
||||||
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
||||||
@@ -622,6 +628,8 @@ class ToolUsage:
|
|||||||
if (
|
if (
|
||||||
hasattr(available_tool, "max_usage_count")
|
hasattr(available_tool, "max_usage_count")
|
||||||
and available_tool.max_usage_count is not None
|
and available_tool.max_usage_count is not None
|
||||||
|
and self.agent
|
||||||
|
and self.agent.verbose
|
||||||
):
|
):
|
||||||
self._printer.print(
|
self._printer.print(
|
||||||
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
|
||||||
@@ -884,15 +892,17 @@ class ToolUsage:
|
|||||||
# Attempt 4: Repair JSON
|
# Attempt 4: Repair JSON
|
||||||
try:
|
try:
|
||||||
repaired_input = str(repair_json(tool_input, skip_json_loads=True))
|
repaired_input = str(repair_json(tool_input, skip_json_loads=True))
|
||||||
self._printer.print(
|
if self.agent and self.agent.verbose:
|
||||||
content=f"Repaired JSON: {repaired_input}", color="blue"
|
self._printer.print(
|
||||||
)
|
content=f"Repaired JSON: {repaired_input}", color="blue"
|
||||||
|
)
|
||||||
arguments = json.loads(repaired_input)
|
arguments = json.loads(repaired_input)
|
||||||
if isinstance(arguments, dict):
|
if isinstance(arguments, dict):
|
||||||
return arguments
|
return arguments
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error = f"Failed to repair JSON: {e}"
|
error = f"Failed to repair JSON: {e}"
|
||||||
self._printer.print(content=error, color="red")
|
if self.agent and self.agent.verbose:
|
||||||
|
self._printer.print(content=error, color="red")
|
||||||
|
|
||||||
error_message = (
|
error_message = (
|
||||||
"Tool input must be a valid dictionary in JSON or Python literal format"
|
"Tool input must be a valid dictionary in JSON or Python literal format"
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ def handle_max_iterations_exceeded(
|
|||||||
messages: list[LLMMessage],
|
messages: list[LLMMessage],
|
||||||
llm: LLM | BaseLLM,
|
llm: LLM | BaseLLM,
|
||||||
callbacks: list[TokenCalcHandler],
|
callbacks: list[TokenCalcHandler],
|
||||||
|
verbose: bool = True,
|
||||||
) -> AgentFinish:
|
) -> AgentFinish:
|
||||||
"""Handles the case when the maximum number of iterations is exceeded. Performs one more LLM call to get the final answer.
|
"""Handles the case when the maximum number of iterations is exceeded. Performs one more LLM call to get the final answer.
|
||||||
|
|
||||||
@@ -220,14 +221,16 @@ def handle_max_iterations_exceeded(
|
|||||||
messages: List of messages to send to the LLM.
|
messages: List of messages to send to the LLM.
|
||||||
llm: The LLM instance to call.
|
llm: The LLM instance to call.
|
||||||
callbacks: List of callbacks for the LLM call.
|
callbacks: List of callbacks for the LLM call.
|
||||||
|
verbose: Whether to print output.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AgentFinish with the final answer after exceeding max iterations.
|
AgentFinish with the final answer after exceeding max iterations.
|
||||||
"""
|
"""
|
||||||
printer.print(
|
if verbose:
|
||||||
content="Maximum iterations reached. Requesting final answer.",
|
printer.print(
|
||||||
color="yellow",
|
content="Maximum iterations reached. Requesting final answer.",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
if formatted_answer and hasattr(formatted_answer, "text"):
|
if formatted_answer and hasattr(formatted_answer, "text"):
|
||||||
assistant_message = (
|
assistant_message = (
|
||||||
@@ -245,10 +248,11 @@ def handle_max_iterations_exceeded(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if answer is None or answer == "":
|
if answer is None or answer == "":
|
||||||
printer.print(
|
if verbose:
|
||||||
content="Received None or empty response from LLM call.",
|
printer.print(
|
||||||
color="red",
|
content="Received None or empty response from LLM call.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise ValueError("Invalid response from LLM call - None or empty.")
|
raise ValueError("Invalid response from LLM call - None or empty.")
|
||||||
|
|
||||||
formatted = format_answer(answer=answer)
|
formatted = format_answer(answer=answer)
|
||||||
@@ -322,6 +326,7 @@ def get_llm_response(
|
|||||||
from_agent: Agent | LiteAgent | None = None,
|
from_agent: Agent | LiteAgent | None = None,
|
||||||
response_model: type[BaseModel] | None = None,
|
response_model: type[BaseModel] | None = None,
|
||||||
executor_context: CrewAgentExecutor | AgentExecutor | LiteAgent | None = None,
|
executor_context: CrewAgentExecutor | AgentExecutor | LiteAgent | None = None,
|
||||||
|
verbose: bool = True,
|
||||||
) -> str | Any:
|
) -> str | Any:
|
||||||
"""Call the LLM and return the response, handling any invalid responses.
|
"""Call the LLM and return the response, handling any invalid responses.
|
||||||
|
|
||||||
@@ -347,7 +352,7 @@ def get_llm_response(
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if executor_context is not None:
|
if executor_context is not None:
|
||||||
if not _setup_before_llm_call_hooks(executor_context, printer):
|
if not _setup_before_llm_call_hooks(executor_context, printer, verbose=verbose):
|
||||||
raise ValueError("LLM call blocked by before_llm_call hook")
|
raise ValueError("LLM call blocked by before_llm_call hook")
|
||||||
messages = executor_context.messages
|
messages = executor_context.messages
|
||||||
|
|
||||||
@@ -364,13 +369,16 @@ def get_llm_response(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
if not answer:
|
if not answer:
|
||||||
printer.print(
|
if verbose:
|
||||||
content="Received None or empty response from LLM call.",
|
printer.print(
|
||||||
color="red",
|
content="Received None or empty response from LLM call.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise ValueError("Invalid response from LLM call - None or empty.")
|
raise ValueError("Invalid response from LLM call - None or empty.")
|
||||||
|
|
||||||
return _setup_after_llm_call_hooks(executor_context, answer, printer)
|
return _setup_after_llm_call_hooks(
|
||||||
|
executor_context, answer, printer, verbose=verbose
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def aget_llm_response(
|
async def aget_llm_response(
|
||||||
@@ -384,6 +392,7 @@ async def aget_llm_response(
|
|||||||
from_agent: Agent | LiteAgent | None = None,
|
from_agent: Agent | LiteAgent | None = None,
|
||||||
response_model: type[BaseModel] | None = None,
|
response_model: type[BaseModel] | None = None,
|
||||||
executor_context: CrewAgentExecutor | AgentExecutor | None = None,
|
executor_context: CrewAgentExecutor | AgentExecutor | None = None,
|
||||||
|
verbose: bool = True,
|
||||||
) -> str | Any:
|
) -> str | Any:
|
||||||
"""Call the LLM asynchronously and return the response.
|
"""Call the LLM asynchronously and return the response.
|
||||||
|
|
||||||
@@ -408,7 +417,7 @@ async def aget_llm_response(
|
|||||||
ValueError: If the response is None or empty.
|
ValueError: If the response is None or empty.
|
||||||
"""
|
"""
|
||||||
if executor_context is not None:
|
if executor_context is not None:
|
||||||
if not _setup_before_llm_call_hooks(executor_context, printer):
|
if not _setup_before_llm_call_hooks(executor_context, printer, verbose=verbose):
|
||||||
raise ValueError("LLM call blocked by before_llm_call hook")
|
raise ValueError("LLM call blocked by before_llm_call hook")
|
||||||
messages = executor_context.messages
|
messages = executor_context.messages
|
||||||
|
|
||||||
@@ -425,13 +434,16 @@ async def aget_llm_response(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
if not answer:
|
if not answer:
|
||||||
printer.print(
|
if verbose:
|
||||||
content="Received None or empty response from LLM call.",
|
printer.print(
|
||||||
color="red",
|
content="Received None or empty response from LLM call.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise ValueError("Invalid response from LLM call - None or empty.")
|
raise ValueError("Invalid response from LLM call - None or empty.")
|
||||||
|
|
||||||
return _setup_after_llm_call_hooks(executor_context, answer, printer)
|
return _setup_after_llm_call_hooks(
|
||||||
|
executor_context, answer, printer, verbose=verbose
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def process_llm_response(
|
def process_llm_response(
|
||||||
@@ -498,13 +510,19 @@ def handle_agent_action_core(
|
|||||||
return formatted_answer
|
return formatted_answer
|
||||||
|
|
||||||
|
|
||||||
def handle_unknown_error(printer: Printer, exception: Exception) -> None:
|
def handle_unknown_error(
|
||||||
|
printer: Printer, exception: Exception, verbose: bool = True
|
||||||
|
) -> None:
|
||||||
"""Handle unknown errors by informing the user.
|
"""Handle unknown errors by informing the user.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
printer: Printer instance for output
|
printer: Printer instance for output
|
||||||
exception: The exception that occurred
|
exception: The exception that occurred
|
||||||
|
verbose: Whether to print output.
|
||||||
"""
|
"""
|
||||||
|
if not verbose:
|
||||||
|
return
|
||||||
|
|
||||||
error_message = str(exception)
|
error_message = str(exception)
|
||||||
|
|
||||||
if "litellm" in error_message:
|
if "litellm" in error_message:
|
||||||
@@ -526,6 +544,7 @@ def handle_output_parser_exception(
|
|||||||
iterations: int,
|
iterations: int,
|
||||||
log_error_after: int = 3,
|
log_error_after: int = 3,
|
||||||
printer: Printer | None = None,
|
printer: Printer | None = None,
|
||||||
|
verbose: bool = True,
|
||||||
) -> AgentAction:
|
) -> AgentAction:
|
||||||
"""Handle OutputParserError by updating messages and formatted_answer.
|
"""Handle OutputParserError by updating messages and formatted_answer.
|
||||||
|
|
||||||
@@ -548,7 +567,7 @@ def handle_output_parser_exception(
|
|||||||
thought="",
|
thought="",
|
||||||
)
|
)
|
||||||
|
|
||||||
if iterations > log_error_after and printer:
|
if verbose and iterations > log_error_after and printer:
|
||||||
printer.print(
|
printer.print(
|
||||||
content=f"Error parsing LLM output, agent will retry: {e.error}",
|
content=f"Error parsing LLM output, agent will retry: {e.error}",
|
||||||
color="red",
|
color="red",
|
||||||
@@ -578,6 +597,7 @@ def handle_context_length(
|
|||||||
llm: LLM | BaseLLM,
|
llm: LLM | BaseLLM,
|
||||||
callbacks: list[TokenCalcHandler],
|
callbacks: list[TokenCalcHandler],
|
||||||
i18n: I18N,
|
i18n: I18N,
|
||||||
|
verbose: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle context length exceeded by either summarizing or raising an error.
|
"""Handle context length exceeded by either summarizing or raising an error.
|
||||||
|
|
||||||
@@ -593,16 +613,20 @@ def handle_context_length(
|
|||||||
SystemExit: If context length is exceeded and user opts not to summarize
|
SystemExit: If context length is exceeded and user opts not to summarize
|
||||||
"""
|
"""
|
||||||
if respect_context_window:
|
if respect_context_window:
|
||||||
printer.print(
|
if verbose:
|
||||||
content="Context length exceeded. Summarizing content to fit the model context window. Might take a while...",
|
printer.print(
|
||||||
color="yellow",
|
content="Context length exceeded. Summarizing content to fit the model context window. Might take a while...",
|
||||||
|
color="yellow",
|
||||||
|
)
|
||||||
|
summarize_messages(
|
||||||
|
messages=messages, llm=llm, callbacks=callbacks, i18n=i18n, verbose=verbose
|
||||||
)
|
)
|
||||||
summarize_messages(messages=messages, llm=llm, callbacks=callbacks, i18n=i18n)
|
|
||||||
else:
|
else:
|
||||||
printer.print(
|
if verbose:
|
||||||
content="Context length exceeded. Consider using smaller text or RAG tools from crewai_tools.",
|
printer.print(
|
||||||
color="red",
|
content="Context length exceeded. Consider using smaller text or RAG tools from crewai_tools.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
raise SystemExit(
|
raise SystemExit(
|
||||||
"Context length exceeded and user opted not to summarize. Consider using smaller text or RAG tools from crewai_tools."
|
"Context length exceeded and user opted not to summarize. Consider using smaller text or RAG tools from crewai_tools."
|
||||||
)
|
)
|
||||||
@@ -613,6 +637,7 @@ def summarize_messages(
|
|||||||
llm: LLM | BaseLLM,
|
llm: LLM | BaseLLM,
|
||||||
callbacks: list[TokenCalcHandler],
|
callbacks: list[TokenCalcHandler],
|
||||||
i18n: I18N,
|
i18n: I18N,
|
||||||
|
verbose: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Summarize messages to fit within context window.
|
"""Summarize messages to fit within context window.
|
||||||
|
|
||||||
@@ -644,10 +669,11 @@ def summarize_messages(
|
|||||||
|
|
||||||
total_groups = len(messages_groups)
|
total_groups = len(messages_groups)
|
||||||
for idx, group in enumerate(messages_groups, 1):
|
for idx, group in enumerate(messages_groups, 1):
|
||||||
Printer().print(
|
if verbose:
|
||||||
content=f"Summarizing {idx}/{total_groups}...",
|
Printer().print(
|
||||||
color="yellow",
|
content=f"Summarizing {idx}/{total_groups}...",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
summarization_messages = [
|
summarization_messages = [
|
||||||
format_message_for_llm(
|
format_message_for_llm(
|
||||||
@@ -905,12 +931,14 @@ def extract_tool_call_info(
|
|||||||
def _setup_before_llm_call_hooks(
|
def _setup_before_llm_call_hooks(
|
||||||
executor_context: CrewAgentExecutor | AgentExecutor | LiteAgent | None,
|
executor_context: CrewAgentExecutor | AgentExecutor | LiteAgent | None,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
|
verbose: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Setup and invoke before_llm_call hooks for the executor context.
|
"""Setup and invoke before_llm_call hooks for the executor context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
executor_context: The executor context to setup the hooks for.
|
executor_context: The executor context to setup the hooks for.
|
||||||
printer: Printer instance for error logging.
|
printer: Printer instance for error logging.
|
||||||
|
verbose: Whether to print output.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if LLM execution should proceed, False if blocked by a hook.
|
True if LLM execution should proceed, False if blocked by a hook.
|
||||||
@@ -925,26 +953,29 @@ def _setup_before_llm_call_hooks(
|
|||||||
for hook in executor_context.before_llm_call_hooks:
|
for hook in executor_context.before_llm_call_hooks:
|
||||||
result = hook(hook_context)
|
result = hook(hook_context)
|
||||||
if result is False:
|
if result is False:
|
||||||
printer.print(
|
if verbose:
|
||||||
content="LLM call blocked by before_llm_call hook",
|
printer.print(
|
||||||
color="yellow",
|
content="LLM call blocked by before_llm_call hook",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printer.print(
|
if verbose:
|
||||||
content=f"Error in before_llm_call hook: {e}",
|
printer.print(
|
||||||
color="yellow",
|
content=f"Error in before_llm_call hook: {e}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
if not isinstance(executor_context.messages, list):
|
if not isinstance(executor_context.messages, list):
|
||||||
printer.print(
|
if verbose:
|
||||||
content=(
|
printer.print(
|
||||||
"Warning: before_llm_call hook replaced messages with non-list. "
|
content=(
|
||||||
"Restoring original messages list. Hooks should modify messages in-place, "
|
"Warning: before_llm_call hook replaced messages with non-list. "
|
||||||
"not replace the list (e.g., use context.messages.append() not context.messages = [])."
|
"Restoring original messages list. Hooks should modify messages in-place, "
|
||||||
),
|
"not replace the list (e.g., use context.messages.append() not context.messages = [])."
|
||||||
color="yellow",
|
),
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
if isinstance(original_messages, list):
|
if isinstance(original_messages, list):
|
||||||
executor_context.messages = original_messages
|
executor_context.messages = original_messages
|
||||||
else:
|
else:
|
||||||
@@ -957,6 +988,7 @@ def _setup_after_llm_call_hooks(
|
|||||||
executor_context: CrewAgentExecutor | AgentExecutor | LiteAgent | None,
|
executor_context: CrewAgentExecutor | AgentExecutor | LiteAgent | None,
|
||||||
answer: str,
|
answer: str,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
|
verbose: bool = True,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Setup and invoke after_llm_call hooks for the executor context.
|
"""Setup and invoke after_llm_call hooks for the executor context.
|
||||||
|
|
||||||
@@ -964,6 +996,7 @@ def _setup_after_llm_call_hooks(
|
|||||||
executor_context: The executor context to setup the hooks for.
|
executor_context: The executor context to setup the hooks for.
|
||||||
answer: The LLM response string.
|
answer: The LLM response string.
|
||||||
printer: Printer instance for error logging.
|
printer: Printer instance for error logging.
|
||||||
|
verbose: Whether to print output.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The potentially modified response string.
|
The potentially modified response string.
|
||||||
@@ -981,20 +1014,22 @@ def _setup_after_llm_call_hooks(
|
|||||||
answer = modified_response
|
answer = modified_response
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printer.print(
|
if verbose:
|
||||||
content=f"Error in after_llm_call hook: {e}",
|
printer.print(
|
||||||
color="yellow",
|
content=f"Error in after_llm_call hook: {e}",
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
if not isinstance(executor_context.messages, list):
|
if not isinstance(executor_context.messages, list):
|
||||||
printer.print(
|
if verbose:
|
||||||
content=(
|
printer.print(
|
||||||
"Warning: after_llm_call hook replaced messages with non-list. "
|
content=(
|
||||||
"Restoring original messages list. Hooks should modify messages in-place, "
|
"Warning: after_llm_call hook replaced messages with non-list. "
|
||||||
"not replace the list (e.g., use context.messages.append() not context.messages = [])."
|
"Restoring original messages list. Hooks should modify messages in-place, "
|
||||||
),
|
"not replace the list (e.g., use context.messages.append() not context.messages = [])."
|
||||||
color="yellow",
|
),
|
||||||
)
|
color="yellow",
|
||||||
|
)
|
||||||
if isinstance(original_messages, list):
|
if isinstance(original_messages, list):
|
||||||
executor_context.messages = original_messages
|
executor_context.messages = original_messages
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -205,10 +205,11 @@ def convert_to_model(
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Printer().print(
|
if agent and getattr(agent, "verbose", True):
|
||||||
content=f"Unexpected error during model conversion: {type(e).__name__}: {e}. Returning original result.",
|
Printer().print(
|
||||||
color="red",
|
content=f"Unexpected error during model conversion: {type(e).__name__}: {e}. Returning original result.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -262,10 +263,11 @@ def handle_partial_json(
|
|||||||
except ValidationError:
|
except ValidationError:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Printer().print(
|
if agent and getattr(agent, "verbose", True):
|
||||||
content=f"Unexpected error during partial JSON handling: {type(e).__name__}: {e}. Attempting alternative conversion method.",
|
Printer().print(
|
||||||
color="red",
|
content=f"Unexpected error during partial JSON handling: {type(e).__name__}: {e}. Attempting alternative conversion method.",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
|
|
||||||
return convert_with_instructions(
|
return convert_with_instructions(
|
||||||
result=result,
|
result=result,
|
||||||
@@ -323,10 +325,11 @@ def convert_with_instructions(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(exported_result, ConverterError):
|
if isinstance(exported_result, ConverterError):
|
||||||
Printer().print(
|
if agent and getattr(agent, "verbose", True):
|
||||||
content=f"Failed to convert result to model: {exported_result}",
|
Printer().print(
|
||||||
color="red",
|
content=f"Failed to convert result to model: {exported_result}",
|
||||||
)
|
color="red",
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return exported_result
|
return exported_result
|
||||||
|
|||||||
@@ -1004,3 +1004,53 @@ def test_prepare_kickoff_param_files_override_message_files():
|
|||||||
|
|
||||||
assert "files" in inputs
|
assert "files" in inputs
|
||||||
assert inputs["files"]["same.png"] is param_file # param takes precedence
|
assert inputs["files"]["same.png"] is param_file # param takes precedence
|
||||||
|
|
||||||
|
|
||||||
|
def test_lite_agent_verbose_false_suppresses_printer_output():
|
||||||
|
"""Test that setting verbose=False suppresses all printer output."""
|
||||||
|
from crewai.agents.parser import AgentFinish
|
||||||
|
from crewai.types.usage_metrics import UsageMetrics
|
||||||
|
|
||||||
|
mock_llm = Mock(spec=LLM)
|
||||||
|
mock_llm.call.return_value = "Final Answer: Hello!"
|
||||||
|
mock_llm.stop = []
|
||||||
|
mock_llm.supports_stop_words.return_value = False
|
||||||
|
mock_llm.get_token_usage_summary.return_value = UsageMetrics(
|
||||||
|
total_tokens=100,
|
||||||
|
prompt_tokens=50,
|
||||||
|
completion_tokens=50,
|
||||||
|
cached_prompt_tokens=0,
|
||||||
|
successful_requests=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
agent = LiteAgent(
|
||||||
|
role="Test Agent",
|
||||||
|
goal="Test goal",
|
||||||
|
backstory="Test backstory",
|
||||||
|
llm=mock_llm,
|
||||||
|
verbose=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = agent.kickoff("Say hello")
|
||||||
|
|
||||||
|
assert result is not None
|
||||||
|
assert isinstance(result, LiteAgentOutput)
|
||||||
|
# Verify the printer was never called
|
||||||
|
agent._printer.print = Mock()
|
||||||
|
# For a clean verification, patch printer before execution
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
agent2 = LiteAgent(
|
||||||
|
role="Test Agent",
|
||||||
|
goal="Test goal",
|
||||||
|
backstory="Test backstory",
|
||||||
|
llm=mock_llm,
|
||||||
|
verbose=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_printer = Mock()
|
||||||
|
agent2._printer = mock_printer
|
||||||
|
|
||||||
|
agent2.kickoff("Say hello")
|
||||||
|
|
||||||
|
mock_printer.print.assert_not_called()
|
||||||
|
|||||||
@@ -2585,6 +2585,7 @@ def test_warning_long_term_memory_without_entity_memory():
|
|||||||
goal="You research about math.",
|
goal="You research about math.",
|
||||||
backstory="You're an expert in research and you love to learn new things.",
|
backstory="You're an expert in research and you love to learn new things.",
|
||||||
allow_delegation=False,
|
allow_delegation=False,
|
||||||
|
verbose=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
task1 = Task(
|
task1 = Task(
|
||||||
|
|||||||
Reference in New Issue
Block a user