refactor: use shared PRINTER singleton
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled

This commit is contained in:
Greyson LaLonde
2026-04-08 07:17:22 +08:00
committed by GitHub
parent b23b2696fe
commit 0450d06a65
25 changed files with 161 additions and 221 deletions

View File

@@ -6,7 +6,6 @@ from pydantic import BaseModel, Field, PrivateAttr
from crewai.agents.parser import AgentFinish
from crewai.memory.utils import sanitize_scope_name
from crewai.utilities.printer import Printer
from crewai.utilities.string_utils import sanitize_tool_name
from crewai.utilities.types import LLMMessage
@@ -30,7 +29,6 @@ class BaseAgentExecutor(BaseModel):
messages: list[LLMMessage] = Field(default_factory=list)
_resuming: bool = PrivateAttr(default=False)
_i18n: I18N | None = PrivateAttr(default=None)
_printer: Printer = PrivateAttr(default_factory=Printer)
def _save_to_memory(self, output: AgentFinish) -> None:
"""Save task result to unified memory (memory or crew._memory)."""

View File

@@ -68,6 +68,7 @@ from crewai.utilities.agent_utils import (
from crewai.utilities.constants import TRAINING_DATA_FILE
from crewai.utilities.file_store import aget_all_files, get_all_files
from crewai.utilities.i18n import I18N, get_i18n
from crewai.utilities.printer import PRINTER
from crewai.utilities.string_utils import sanitize_tool_name
from crewai.utilities.token_counter_callback import TokenCalcHandler
from crewai.utilities.tool_utils import (
@@ -212,13 +213,13 @@ class CrewAgentExecutor(BaseAgentExecutor):
formatted_answer = self._invoke_loop()
except AssertionError:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
color="red",
)
raise
except Exception as e:
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise
if self.ask_for_human_input:
@@ -326,7 +327,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if has_reached_max_iterations(self.iterations, self.max_iter):
formatted_answer = handle_max_iterations_exceeded(
formatted_answer,
printer=self._printer,
printer=PRINTER,
i18n=self._i18n,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
@@ -341,7 +342,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
llm=cast("BaseLLM", self.llm),
messages=self.messages,
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
from_task=self.task,
from_agent=self.agent,
response_model=self.response_model,
@@ -422,7 +423,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
messages=self.messages,
iterations=self.iterations,
log_error_after=self.log_error_after,
printer=self._printer,
printer=PRINTER,
verbose=self.agent.verbose,
)
@@ -433,7 +434,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if is_context_length_exceeded(e):
handle_context_length(
respect_context_window=self.respect_context_window,
printer=self._printer,
printer=PRINTER,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
callbacks=self.callbacks,
@@ -441,7 +442,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
verbose=self.agent.verbose,
)
continue
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise e
finally:
self.iterations += 1
@@ -482,7 +483,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if has_reached_max_iterations(self.iterations, self.max_iter):
formatted_answer = handle_max_iterations_exceeded(
None,
printer=self._printer,
printer=PRINTER,
i18n=self._i18n,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
@@ -502,7 +503,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
llm=cast("BaseLLM", self.llm),
messages=self.messages,
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
tools=openai_tools,
available_functions=None,
from_task=self.task,
@@ -570,7 +571,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if is_context_length_exceeded(e):
handle_context_length(
respect_context_window=self.respect_context_window,
printer=self._printer,
printer=PRINTER,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
callbacks=self.callbacks,
@@ -578,7 +579,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
verbose=self.agent.verbose,
)
continue
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise e
finally:
self.iterations += 1
@@ -595,7 +596,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
llm=cast("BaseLLM", self.llm),
messages=self.messages,
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
from_task=self.task,
from_agent=self.agent,
response_model=self.response_model,
@@ -965,7 +966,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
break
except Exception as hook_error:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Error in before_tool_call hook: {hook_error}",
color="red",
)
@@ -1031,7 +1032,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
after_hook_context.tool_result = result
except Exception as hook_error:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Error in after_tool_call hook: {hook_error}",
color="red",
)
@@ -1078,7 +1079,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if self.agent and self.agent.verbose:
cache_info = " (from cache)" if from_cache else ""
self._printer.print(
PRINTER.print(
content=f"Tool {func_name} executed with result{cache_info}: {result[:200]}...",
color="green",
)
@@ -1118,13 +1119,13 @@ class CrewAgentExecutor(BaseAgentExecutor):
formatted_answer = await self._ainvoke_loop()
except AssertionError:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
color="red",
)
raise
except Exception as e:
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise
if self.ask_for_human_input:
@@ -1168,7 +1169,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if has_reached_max_iterations(self.iterations, self.max_iter):
formatted_answer = handle_max_iterations_exceeded(
formatted_answer,
printer=self._printer,
printer=PRINTER,
i18n=self._i18n,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
@@ -1183,7 +1184,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
llm=cast("BaseLLM", self.llm),
messages=self.messages,
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
from_task=self.task,
from_agent=self.agent,
response_model=self.response_model,
@@ -1263,7 +1264,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
messages=self.messages,
iterations=self.iterations,
log_error_after=self.log_error_after,
printer=self._printer,
printer=PRINTER,
verbose=self.agent.verbose,
)
@@ -1273,7 +1274,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if is_context_length_exceeded(e):
handle_context_length(
respect_context_window=self.respect_context_window,
printer=self._printer,
printer=PRINTER,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
callbacks=self.callbacks,
@@ -1281,7 +1282,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
verbose=self.agent.verbose,
)
continue
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise e
finally:
self.iterations += 1
@@ -1316,7 +1317,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if has_reached_max_iterations(self.iterations, self.max_iter):
formatted_answer = handle_max_iterations_exceeded(
None,
printer=self._printer,
printer=PRINTER,
i18n=self._i18n,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
@@ -1336,7 +1337,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
llm=cast("BaseLLM", self.llm),
messages=self.messages,
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
tools=openai_tools,
available_functions=None,
from_task=self.task,
@@ -1403,7 +1404,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if is_context_length_exceeded(e):
handle_context_length(
respect_context_window=self.respect_context_window,
printer=self._printer,
printer=PRINTER,
messages=self.messages,
llm=cast("BaseLLM", self.llm),
callbacks=self.callbacks,
@@ -1411,7 +1412,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
verbose=self.agent.verbose,
)
continue
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise e
finally:
self.iterations += 1
@@ -1428,7 +1429,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
llm=cast("BaseLLM", self.llm),
messages=self.messages,
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
from_task=self.task,
from_agent=self.agent,
response_model=self.response_model,
@@ -1576,7 +1577,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
if train_iteration is None or not isinstance(train_iteration, int):
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="Invalid or missing train iteration. Cannot save training data.",
color="red",
)
@@ -1600,7 +1601,7 @@ class CrewAgentExecutor(BaseAgentExecutor):
agent_training_data[train_iteration]["improved_output"] = result.output
else:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=(
f"No existing training data for agent {agent_id} and iteration "
f"{train_iteration}. Cannot save improved output."

View File

@@ -40,7 +40,7 @@ from crewai.utilities.agent_utils import (
)
from crewai.utilities.i18n import I18N, get_i18n
from crewai.utilities.planning_types import TodoItem
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
from crewai.utilities.step_execution_context import StepExecutionContext, StepResult
from crewai.utilities.string_utils import sanitize_tool_name
from crewai.utilities.tool_utils import execute_tool_and_check_finality
@@ -109,7 +109,6 @@ class StepExecutor:
self.request_within_rpm_limit = request_within_rpm_limit
self.callbacks = callbacks or []
self._i18n: I18N = i18n or get_i18n()
self._printer: Printer = Printer()
# Native tool support — set up once
self._use_native_tools = check_native_tool_support(
@@ -585,7 +584,7 @@ class StepExecutor:
task=self.task,
crew=self.crew,
event_source=self,
printer=self._printer,
printer=PRINTER,
verbose=bool(self.agent and self.agent.verbose),
)

View File

@@ -3,17 +3,14 @@ from pathlib import Path
import click
from crewai.cli.utils import copy_template
from crewai.utilities.printer import Printer
_printer = Printer()
from crewai.utilities.printer import PRINTER
def add_crew_to_flow(crew_name: str) -> None:
"""Add a new crew to the current flow."""
# Check if pyproject.toml exists in the current directory
if not Path("pyproject.toml").exists():
_printer.print(
PRINTER.print(
"This command must be run from the root of a flow project.", color="red"
)
raise click.ClickException(
@@ -25,7 +22,7 @@ def add_crew_to_flow(crew_name: str) -> None:
crews_folder = flow_folder / "src" / flow_folder.name / "crews"
if not crews_folder.exists():
_printer.print("Crews folder does not exist in the current flow.", color="red")
PRINTER.print("Crews folder does not exist in the current flow.", color="red")
raise click.ClickException("Crews folder does not exist in the current flow.")
# Create the crew within the flow's crews directory

View File

@@ -19,12 +19,10 @@ from crewai.llm import LLM
from crewai.llms.base_llm import BaseLLM
from crewai.types.crew_chat import ChatInputField, ChatInputs
from crewai.utilities.llm_utils import create_llm
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
from crewai.utilities.types import LLMMessage
_printer = Printer()
MIN_REQUIRED_VERSION: Final[Literal["0.98.0"]] = "0.98.0"
@@ -121,9 +119,9 @@ def run_chat() -> None:
def show_loading(event: threading.Event) -> None:
"""Display animated loading dots while processing."""
while not event.is_set():
_printer.print(".", end="")
PRINTER.print(".", end="")
time.sleep(1)
_printer.print("")
PRINTER.print("")
def initialize_chat_llm(crew: Crew) -> LLM | BaseLLM | None:

View File

@@ -98,7 +98,7 @@ from crewai.utilities.planning_types import (
TodoItem,
TodoList,
)
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
from crewai.utilities.step_execution_context import StepExecutionContext, StepResult
from crewai.utilities.string_utils import sanitize_tool_name
from crewai.utilities.tool_utils import execute_tool_and_check_finality
@@ -199,7 +199,6 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
)
_i18n: I18N = PrivateAttr(default_factory=get_i18n)
_printer: Printer = PrivateAttr(default_factory=Printer)
_console: Console = PrivateAttr(default_factory=Console)
_last_parser_error: OutputParserError | None = PrivateAttr(default=None)
_last_context_error: Exception | None = PrivateAttr(default=None)
@@ -503,7 +502,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=(
f"[Observe] Step {current_todo.step_number} "
f"(effort={effort}): "
@@ -553,7 +552,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
current_todo.step_number, result=current_todo.result
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=(
f"[Low] Step {current_todo.step_number} hard-failed "
f"— triggering replan: {observation.replan_reason}"
@@ -572,7 +571,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
completed = self.state.todos.completed_count
total = len(self.state.todos.items)
self._printer.print(
PRINTER.print(
content=f"[Low] Step {current_todo.step_number} done ({completed}/{total}) — continuing",
color="green",
)
@@ -605,7 +604,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
completed = self.state.todos.completed_count
total = len(self.state.todos.items)
self._printer.print(
PRINTER.print(
content=f"[Medium] Step {current_todo.step_number} succeeded ({completed}/{total}) — continuing",
color="green",
)
@@ -618,7 +617,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
current_todo.step_number, result=current_todo.result
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=(
f"[Medium] Step {current_todo.step_number} failed + replan required "
f"— triggering replan: {observation.replan_reason}"
@@ -638,7 +637,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
failed = len(self.state.todos.get_failed_todos())
total = len(self.state.todos.items)
self._printer.print(
PRINTER.print(
content=(
f"[Medium] Step {current_todo.step_number} failed but no replan needed "
f"({failed} failed/{total} total) — continuing"
@@ -680,7 +679,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
current_todo.step_number, result=current_todo.result
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="[Decide] Goal achieved early — finalizing",
color="green",
)
@@ -692,7 +691,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
current_todo.step_number, result=current_todo.result
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"[Decide] Full replan needed: {observation.replan_reason}",
color="yellow",
)
@@ -705,7 +704,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
current_todo.step_number, result=current_todo.result
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="[Decide] Step failed — triggering replan",
color="yellow",
)
@@ -718,7 +717,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
current_todo.step_number, result=current_todo.result
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="[Decide] Plan valid but refining upcoming steps",
color="cyan",
)
@@ -731,7 +730,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
completed = self.state.todos.completed_count
total = len(self.state.todos.items)
self._printer.print(
PRINTER.print(
content=f"[Decide] Continue plan ({completed}/{total} done)",
color="green",
)
@@ -776,7 +775,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"[Refine] Updated {len(remaining)} pending step(s)",
color="cyan",
)
@@ -811,7 +810,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content="Goal achieved early — skipping remaining steps",
color="green",
)
@@ -829,7 +828,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.state.replan_count >= max_replans:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Max replans ({max_replans}) reached — finalizing with current results",
color="yellow",
)
@@ -936,7 +935,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
# Plan-and-Execute path: use StepExecutor for isolated execution
if getattr(self.agent, "planning_enabled", False):
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=(
f"[Execute] Step {current.step_number}: "
f"{current.description[:60]}..."
@@ -971,7 +970,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
status = "success" if result.success else "failed"
self._printer.print(
PRINTER.print(
content=(
f"[Execute] Step {current.step_number} {status} "
f"({result.execution_time:.1f}s, "
@@ -1080,7 +1079,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
todo.result = error_msg
self.state.todos.mark_failed(todo.step_number, result=error_msg)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Todo {todo.step_number} failed: {error_msg}",
color="red",
)
@@ -1105,7 +1104,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
status = "success" if step_result.success else "failed"
self._printer.print(
PRINTER.print(
content=(
f"[Execute] Step {todo.step_number} {status} "
f"({step_result.execution_time:.1f}s, "
@@ -1152,7 +1151,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
self.state.todos.mark_failed(todo.step_number, result=todo.result)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=(
f"[Observe] Step {todo.step_number} "
f"(effort={effort}): "
@@ -1203,7 +1202,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
"""Force agent to provide final answer when max iterations exceeded."""
formatted_answer = handle_max_iterations_exceeded(
formatted_answer=None,
printer=self._printer,
printer=PRINTER,
i18n=self._i18n,
messages=list(self.state.messages),
llm=self.llm,
@@ -1232,7 +1231,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
llm=self.llm,
messages=list(self.state.messages),
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
from_task=self.task,
from_agent=self.agent,
response_model=self.response_model,
@@ -1282,7 +1281,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
return "context_error"
if e.__class__.__module__.startswith("litellm"):
raise e
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise
@router("continue_reasoning_native")
@@ -1318,7 +1317,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
llm=self.llm,
messages=list(self.state.messages),
callbacks=self.callbacks,
printer=self._printer,
printer=PRINTER,
tools=self._openai_tools,
available_functions=None,
from_task=self.task,
@@ -1373,7 +1372,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
return "context_error"
if e.__class__.__module__.startswith("litellm"):
raise e
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise
def _route_finish_with_todos(
@@ -1442,9 +1441,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
)
except Exception as e:
if self.agent and self.agent.verbose:
self._printer.print(
content=f"Error in tool execution: {e}", color="red"
)
PRINTER.print(content=f"Error in tool execution: {e}", color="red")
if self.task:
self.task.increment_tools_errors()
@@ -1598,7 +1595,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
# Log the tool execution
if self.agent and self.agent.verbose:
cache_info = " (from cache)" if from_cache else ""
self._printer.print(
PRINTER.print(
content=f"Tool {func_name} executed with result{cache_info}: {result[:200]}...",
color="green",
)
@@ -1636,7 +1633,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
# Log the tool execution
if self.agent and self.agent.verbose:
cache_info = " (from cache)" if from_cache else ""
self._printer.print(
PRINTER.print(
content=f"Tool {func_name} executed with result{cache_info}: {result[:200]}...",
color="green",
)
@@ -1800,7 +1797,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
break
except Exception as hook_error:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Error in before_tool_call hook: {hook_error}",
color="red",
)
@@ -1875,7 +1872,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
after_hook_context.tool_result = result
except Exception as hook_error:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Error in after_tool_call hook: {hook_error}",
color="red",
)
@@ -2033,7 +2030,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.agent.verbose:
completed = self.state.todos.completed_count
total = len(self.state.todos.items)
self._printer.print(
PRINTER.print(
content=f"✓ Todo {step_number} completed ({completed}/{total})",
color="green",
)
@@ -2100,7 +2097,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
self._finalize_called = True
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"[Finalize] todos_count={len(self.state.todos.items)}, todos_with_results={sum(1 for t in self.state.todos.items if t.result)}",
color="magenta",
)
@@ -2263,7 +2260,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
except Exception as e:
if self.agent and self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Synthesis LLM call failed ({e}), falling back to concatenation",
color="yellow",
)
@@ -2348,7 +2345,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
self.state.last_replan_reason = reason
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Triggering replan (attempt {self.state.replan_count}): {reason}",
color="yellow",
)
@@ -2408,7 +2405,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
self.state.todos.replace_pending_todos(new_todos)
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Replan: {len(new_todos)} new steps (completed history preserved)",
color="green",
)
@@ -2492,7 +2489,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
if self.state.replan_count >= max_replans:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Max replans ({max_replans}) reached — finalizing with current results",
color="yellow",
)
@@ -2518,7 +2515,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
messages=list(self.state.messages),
iterations=self.state.iterations,
log_error_after=self.log_error_after,
printer=self._printer,
printer=PRINTER,
verbose=self.agent.verbose,
)
@@ -2534,7 +2531,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
"""Recover from context length errors and retry."""
handle_context_length(
respect_context_window=self.respect_context_window,
printer=self._printer,
printer=PRINTER,
messages=self.state.messages,
llm=self.llm,
callbacks=self.callbacks,
@@ -2637,7 +2634,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
self._console.print(fail_text)
raise
except Exception as e:
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise
finally:
self._is_executing = False
@@ -2728,7 +2725,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
self._console.print(fail_text)
raise
except Exception as e:
handle_unknown_error(self._printer, e, verbose=self.agent.verbose)
handle_unknown_error(PRINTER, e, verbose=self.agent.verbose)
raise
finally:
self._is_executing = False
@@ -2793,7 +2790,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor
task.result()
except Exception as e:
if self.agent.verbose:
self._printer.print(
PRINTER.print(
content=f"Error in async step_callback task: {e!s}",
color="red",
)

View File

@@ -28,13 +28,13 @@ import asyncio
from collections.abc import Callable
import functools
import logging
from typing import TYPE_CHECKING, Any, ClassVar, Final, TypeVar, cast
from typing import TYPE_CHECKING, Any, Final, TypeVar, cast
from pydantic import BaseModel
from crewai.flow.persistence.base import FlowPersistence
from crewai.flow.persistence.sqlite import SQLiteFlowPersistence
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
if TYPE_CHECKING:
@@ -56,8 +56,6 @@ LOG_MESSAGES: Final[dict[str, str]] = {
class PersistenceDecorator:
"""Class to handle flow state persistence with consistent logging."""
_printer: ClassVar[Printer] = Printer()
@classmethod
def persist_state(
cls,
@@ -104,7 +102,7 @@ class PersistenceDecorator:
# Log state saving only if verbose is True
if verbose:
cls._printer.print(
PRINTER.print(
LOG_MESSAGES["save_state"].format(flow_uuid), color="cyan"
)
logger.info(LOG_MESSAGES["save_state"].format(flow_uuid))
@@ -119,19 +117,19 @@ class PersistenceDecorator:
except Exception as e:
error_msg = LOG_MESSAGES["save_error"].format(method_name, str(e))
if verbose:
cls._printer.print(error_msg, color="red")
PRINTER.print(error_msg, color="red")
logger.error(error_msg)
raise RuntimeError(f"State persistence failed: {e!s}") from e
except AttributeError as e:
error_msg = LOG_MESSAGES["state_missing"]
if verbose:
cls._printer.print(error_msg, color="red")
PRINTER.print(error_msg, color="red")
logger.error(error_msg)
raise ValueError(error_msg) from e
except (TypeError, ValueError) as e:
error_msg = LOG_MESSAGES["id_missing"]
if verbose:
cls._printer.print(error_msg, color="red")
PRINTER.print(error_msg, color="red")
logger.error(error_msg)
raise ValueError(error_msg) from e

View File

@@ -32,14 +32,12 @@ from crewai.flow.flow_wrappers import (
SimpleFlowCondition,
)
from crewai.flow.types import FlowMethodCallable, FlowMethodName
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
if TYPE_CHECKING:
from crewai.flow.flow import Flow
_printer = Printer()
def _extract_string_literals_from_type_annotation(
node: ast.expr,
@@ -181,7 +179,7 @@ def get_possible_return_constants(
return None
except Exception as e:
if verbose:
_printer.print(
PRINTER.print(
f"Error retrieving source code for function {function.__name__}: {e}",
color="red",
)
@@ -194,27 +192,27 @@ def get_possible_return_constants(
code_ast = ast.parse(source)
except IndentationError as e:
if verbose:
_printer.print(
PRINTER.print(
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
except SyntaxError as e:
if verbose:
_printer.print(
PRINTER.print(
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
except Exception as e:
if verbose:
_printer.print(
PRINTER.print(
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_values: set[str] = set()
@@ -395,13 +393,13 @@ def get_possible_return_constants(
StateAttributeVisitor().visit(class_ast)
except Exception as e:
if verbose:
_printer.print(
PRINTER.print(
f"Could not analyze class context for {function.__name__}: {e}",
color="yellow",
)
except Exception as e:
if verbose:
_printer.print(
PRINTER.print(
f"Could not introspect class for {function.__name__}: {e}",
color="yellow",
)

View File

@@ -9,7 +9,7 @@ from crewai.hooks.types import (
BeforeLLMCallHookCallable,
BeforeLLMCallHookType,
)
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
if TYPE_CHECKING:
@@ -138,16 +138,15 @@ class LLMCallHookContext:
... print("LLM call skipped by user")
"""
printer = Printer()
event_listener.formatter.pause_live_updates()
try:
printer.print(content=f"\n{prompt}", color="bold_yellow")
printer.print(content=default_message, color="cyan")
PRINTER.print(content=f"\n{prompt}", color="bold_yellow")
PRINTER.print(content=default_message, color="cyan")
response = input().strip()
if response:
printer.print(content="\nProcessing your input...", color="cyan")
PRINTER.print(content="\nProcessing your input...", color="cyan")
return response
finally:

View File

@@ -9,7 +9,7 @@ from crewai.hooks.types import (
BeforeToolCallHookCallable,
BeforeToolCallHookType,
)
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
if TYPE_CHECKING:
@@ -100,16 +100,15 @@ class ToolCallHookContext:
... return None # Allow execution
"""
printer = Printer()
event_listener.formatter.pause_live_updates()
try:
printer.print(content=f"\n{prompt}", color="bold_yellow")
printer.print(content=default_message, color="cyan")
PRINTER.print(content=f"\n{prompt}", color="bold_yellow")
PRINTER.print(content=default_message, color="cyan")
response = input().strip()
if response:
printer.print(content="\nProcessing your input...", color="cyan")
PRINTER.print(content="\nProcessing your input...", color="cyan")
return response
finally:

View File

@@ -91,7 +91,7 @@ from crewai.utilities.guardrail import process_guardrail
from crewai.utilities.guardrail_types import GuardrailCallable, GuardrailType
from crewai.utilities.i18n import I18N, get_i18n
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.tool_utils import execute_tool_and_check_finality
@@ -270,7 +270,6 @@ class LiteAgent(FlowTrackable, BaseModel):
_key: str = PrivateAttr(default_factory=lambda: str(uuid.uuid4()))
_messages: list[LLMMessage] = PrivateAttr(default_factory=list)
_iterations: int = PrivateAttr(default=0)
_printer: Printer = PrivateAttr(default_factory=Printer)
_guardrail: GuardrailCallable | None = PrivateAttr(default=None)
_guardrail_retry_count: int = PrivateAttr(default=0)
_callbacks: list[TokenCalcHandler] = PrivateAttr(default_factory=list)
@@ -528,11 +527,11 @@ class LiteAgent(FlowTrackable, BaseModel):
except Exception as e:
if self.verbose:
self._printer.print(
PRINTER.print(
content="Agent failed to reach a final answer. This is likely a bug - please report it.",
color="red",
)
handle_unknown_error(self._printer, e, verbose=self.verbose)
handle_unknown_error(PRINTER, e, verbose=self.verbose)
# Emit error event
crewai_event_bus.emit(
self,
@@ -609,7 +608,7 @@ class LiteAgent(FlowTrackable, BaseModel):
self._memory.remember_many(extracted, agent_role=self.role)
except Exception as e:
if self.verbose:
self._printer.print(
PRINTER.print(
content=f"Failed to save to memory: {e}",
color="yellow",
)
@@ -661,7 +660,7 @@ class LiteAgent(FlowTrackable, BaseModel):
formatted_result = result
except ConverterError as e:
if self.verbose:
self._printer.print(
PRINTER.print(
content=f"Failed to parse output into response format after retries: {e.message}",
color="yellow",
)
@@ -704,7 +703,7 @@ class LiteAgent(FlowTrackable, BaseModel):
)
self._guardrail_retry_count += 1
if self.verbose:
self._printer.print(
PRINTER.print(
f"Guardrail failed. Retrying ({self._guardrail_retry_count}/{self.guardrail_max_retries})..."
f"\n{guardrail_result.error}"
)
@@ -875,7 +874,7 @@ class LiteAgent(FlowTrackable, BaseModel):
if has_reached_max_iterations(self._iterations, self.max_iterations):
formatted_answer = handle_max_iterations_exceeded(
formatted_answer,
printer=self._printer,
printer=PRINTER,
i18n=self.i18n,
messages=self._messages,
llm=cast(LLM, self.llm),
@@ -890,7 +889,7 @@ class LiteAgent(FlowTrackable, BaseModel):
llm=cast(LLM, self.llm),
messages=self._messages,
callbacks=self._callbacks,
printer=self._printer,
printer=PRINTER,
from_agent=self, # type: ignore[arg-type]
executor_context=self,
response_model=response_model,
@@ -933,7 +932,7 @@ class LiteAgent(FlowTrackable, BaseModel):
self._append_message(formatted_answer.text, role="assistant")
except OutputParserError as e:
if self.verbose:
self._printer.print(
PRINTER.print(
content="Failed to parse LLM output. Retrying...",
color="yellow",
)
@@ -942,7 +941,7 @@ class LiteAgent(FlowTrackable, BaseModel):
messages=self._messages,
iterations=self._iterations,
log_error_after=3,
printer=self._printer,
printer=PRINTER,
verbose=self.verbose,
)
@@ -953,7 +952,7 @@ class LiteAgent(FlowTrackable, BaseModel):
if is_context_length_exceeded(e):
handle_context_length(
respect_context_window=self.respect_context_window,
printer=self._printer,
printer=PRINTER,
messages=self._messages,
llm=cast(LLM, self.llm),
callbacks=self._callbacks,
@@ -961,7 +960,7 @@ class LiteAgent(FlowTrackable, BaseModel):
verbose=self.verbose,
)
continue
handle_unknown_error(self._printer, e, verbose=self.verbose)
handle_unknown_error(PRINTER, e, verbose=self.verbose)
raise e
finally:

View File

@@ -857,7 +857,7 @@ class BaseLLM(BaseModel, ABC):
LLMCallHookContext,
get_before_llm_call_hooks,
)
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
before_hooks = get_before_llm_call_hooks()
if not before_hooks:
@@ -872,21 +872,20 @@ class BaseLLM(BaseModel, ABC):
crew=None,
)
verbose = getattr(from_agent, "verbose", True) if from_agent else True
printer = Printer()
try:
for hook in before_hooks:
result = hook(hook_context)
if result is False:
if verbose:
printer.print(
PRINTER.print(
content="LLM call blocked by before_llm_call hook",
color="yellow",
)
return False
except Exception as e:
if verbose:
printer.print(
PRINTER.print(
content=f"Error in before_llm_call hook: {e}",
color="yellow",
)
@@ -927,7 +926,7 @@ class BaseLLM(BaseModel, ABC):
LLMCallHookContext,
get_after_llm_call_hooks,
)
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
after_hooks = get_after_llm_call_hooks()
if not after_hooks:
@@ -943,7 +942,6 @@ class BaseLLM(BaseModel, ABC):
response=response,
)
verbose = getattr(from_agent, "verbose", True) if from_agent else True
printer = Printer()
modified_response = response
try:
@@ -954,7 +952,7 @@ class BaseLLM(BaseModel, ABC):
hook_context.response = modified_response
except Exception as e:
if verbose:
printer.print(
PRINTER.print(
content=f"Error in after_llm_call hook: {e}",
color="yellow",
)

View File

@@ -6,7 +6,6 @@ import sqlite3
from typing import Any
from crewai.task import Task
from crewai.utilities import Printer
from crewai.utilities.crew_json_encoder import CrewJSONEncoder
from crewai.utilities.errors import DatabaseError, DatabaseOperationError
from crewai.utilities.lock_store import lock as store_lock
@@ -27,7 +26,6 @@ class KickoffTaskOutputsSQLiteStorage:
db_path = str(Path(db_storage_path()) / "latest_kickoff_task_outputs.db")
self.db_path = db_path
self._lock_name = f"sqlite:{os.path.realpath(self.db_path)}"
self._printer: Printer = Printer()
self._initialize_db()
def _initialize_db(self) -> None:

View File

@@ -6,10 +6,7 @@ from chromadb.api.types import Documents, EmbeddingFunction, Embeddings
from typing_extensions import Unpack
from crewai.rag.embeddings.providers.ibm.types import WatsonXProviderConfig
from crewai.utilities.printer import Printer
_printer = Printer()
from crewai.utilities.printer import PRINTER
class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
@@ -164,5 +161,5 @@ class WatsonXEmbeddingFunction(EmbeddingFunction[Documents]):
return cast(Embeddings, embeddings)
except Exception as e:
if self._verbose:
_printer.print(f"Error during WatsonX embedding: {e}", color="red")
PRINTER.print(f"Error during WatsonX embedding: {e}", color="red")
raise

View File

@@ -81,13 +81,10 @@ from crewai.utilities.guardrail_types import (
GuardrailsType,
)
from crewai.utilities.i18n import I18N, get_i18n
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
from crewai.utilities.string_utils import interpolate_only
_printer = Printer()
class Task(BaseModel):
"""Class that represents a task to be executed.
@@ -981,7 +978,7 @@ Follow these guidelines:
crew_chat_messages = json.loads(crew_chat_messages_json)
except json.JSONDecodeError as e:
if self.agent and self.agent.verbose:
_printer.print(
PRINTER.print(
f"An error occurred while parsing crew chat messages: {e}",
color="red",
)
@@ -1227,8 +1224,7 @@ Follow these guidelines:
task_output=task_output.raw,
)
if agent and agent.verbose:
printer = Printer()
printer.print(
PRINTER.print(
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",
)
@@ -1325,8 +1321,7 @@ Follow these guidelines:
task_output=task_output.raw,
)
if agent and agent.verbose:
printer = Printer()
printer.print(
PRINTER.print(
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",
)

View File

@@ -38,13 +38,10 @@ from crewai.tools.structured_tool import (
build_schema_hint,
)
from crewai.types.callback import SerializableCallable, _resolve_dotted_path
from crewai.utilities.printer import Printer
from crewai.utilities.pydantic_schema_utils import generate_model_description
from crewai.utilities.string_utils import sanitize_tool_name
_printer = Printer()
P = ParamSpec("P")
R = TypeVar("R", covariant=True)

View File

@@ -29,7 +29,7 @@ from crewai.utilities.agent_utils import (
)
from crewai.utilities.converter import Converter
from crewai.utilities.i18n import I18N, get_i18n
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
from crewai.utilities.string_utils import sanitize_tool_name
@@ -94,7 +94,6 @@ class ToolUsage:
fingerprint_context: dict[str, str] | None = None,
) -> None:
self._i18n: I18N = agent.i18n if agent else get_i18n()
self._printer: Printer = Printer()
self._telemetry: Telemetry = Telemetry()
self._run_attempts: int = 1
self._max_parsing_attempts: int = 3
@@ -129,7 +128,7 @@ class ToolUsage:
if isinstance(calling, ToolUsageError):
error = calling.message
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{error}\n", color="red")
PRINTER.print(content=f"\n\n{error}\n", color="red")
if self.task:
self.task.increment_tools_errors()
return error
@@ -141,7 +140,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{error}\n", color="red")
PRINTER.print(content=f"\n\n{error}\n", color="red")
return error
if (
@@ -157,7 +156,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{error}\n", color="red")
PRINTER.print(content=f"\n\n{error}\n", color="red")
return error
return f"{self._use(tool_string=tool_string, tool=tool, calling=calling)}"
@@ -177,7 +176,7 @@ class ToolUsage:
if isinstance(calling, ToolUsageError):
error = calling.message
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{error}\n", color="red")
PRINTER.print(content=f"\n\n{error}\n", color="red")
if self.task:
self.task.increment_tools_errors()
return error
@@ -189,7 +188,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{error}\n", color="red")
PRINTER.print(content=f"\n\n{error}\n", color="red")
return error
if (
@@ -206,7 +205,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{error}\n", color="red")
PRINTER.print(content=f"\n\n{error}\n", color="red")
return error
return (
@@ -391,7 +390,7 @@ class ToolUsage:
and self.agent
and self.agent.verbose
):
self._printer.print(
PRINTER.print(
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
color="blue",
)
@@ -405,7 +404,7 @@ class ToolUsage:
and self.agent
and self.agent.verbose
):
self._printer.print(
PRINTER.print(
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
color="blue",
)
@@ -429,9 +428,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(
content=f"\n\n{error_message}\n", color="red"
)
PRINTER.print(content=f"\n\n{error_message}\n", color="red")
else:
if self.task:
self.task.increment_tools_errors()
@@ -626,7 +623,7 @@ class ToolUsage:
and self.agent
and self.agent.verbose
):
self._printer.print(
PRINTER.print(
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
color="blue",
)
@@ -640,7 +637,7 @@ class ToolUsage:
and self.agent
and self.agent.verbose
):
self._printer.print(
PRINTER.print(
content=f"Tool '{sanitize_tool_name(available_tool.name)}' usage: {available_tool.current_usage_count}/{available_tool.max_usage_count}",
color="blue",
)
@@ -664,9 +661,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(
content=f"\n\n{error_message}\n", color="red"
)
PRINTER.print(content=f"\n\n{error_message}\n", color="red")
else:
if self.task:
self.task.increment_tools_errors()
@@ -859,7 +854,7 @@ class ToolUsage:
if self.task:
self.task.increment_tools_errors()
if self.agent and self.agent.verbose:
self._printer.print(content=f"\n\n{e}\n", color="red")
PRINTER.print(content=f"\n\n{e}\n", color="red")
return ToolUsageError(
f"{self._i18n.errors('tool_usage_error').format(error=e)}\nMoving on then. {self._i18n.slice('format').format(tool_names=self.tools_names)}"
)
@@ -903,16 +898,14 @@ class ToolUsage:
try:
repaired_input = str(repair_json(tool_input, skip_json_loads=True))
if self.agent and self.agent.verbose:
self._printer.print(
content=f"Repaired JSON: {repaired_input}", color="blue"
)
PRINTER.print(content=f"Repaired JSON: {repaired_input}", color="blue")
arguments = json.loads(repaired_input)
if isinstance(arguments, dict):
return arguments
except Exception as e:
error = f"Failed to repair JSON: {e}"
if self.agent and self.agent.verbose:
self._printer.print(content=error, color="red")
PRINTER.print(content=error, color="red")
error_message = (
"Tool input must be a valid dictionary in JSON or Python literal format"

View File

@@ -32,7 +32,7 @@ from crewai.utilities.exceptions.context_window_exceeding_exception import (
LLMContextLengthExceededError,
)
from crewai.utilities.i18n import I18N
from crewai.utilities.printer import ColoredText, Printer
from crewai.utilities.printer import PRINTER, ColoredText, Printer
from crewai.utilities.pydantic_schema_utils import generate_model_description
from crewai.utilities.string_utils import sanitize_tool_name
from crewai.utilities.token_counter_callback import TokenCalcHandler
@@ -946,7 +946,7 @@ def summarize_messages(
summarized_contents: list[SummaryContent] = []
for idx, chunk in enumerate(chunks, 1):
if verbose:
Printer().print(
PRINTER.print(
content=f"Summarizing {idx}/{total_chunks}...",
color="yellow",
)
@@ -967,7 +967,7 @@ def summarize_messages(
else:
# Multiple chunks — summarize in parallel via asyncio
if verbose:
Printer().print(
PRINTER.print(
content=f"Summarizing {total_chunks} chunks in parallel...",
color="yellow",
)

View File

@@ -10,7 +10,7 @@ from typing_extensions import Unpack
from crewai.agents.agent_builder.utilities.base_output_converter import OutputConverter
from crewai.utilities.i18n import get_i18n
from crewai.utilities.internal_instructor import InternalInstructor
from crewai.utilities.printer import Printer
from crewai.utilities.printer import PRINTER
from crewai.utilities.pydantic_schema_utils import generate_model_description
@@ -209,7 +209,7 @@ def convert_to_model(
except Exception as e:
if agent and getattr(agent, "verbose", True):
Printer().print(
PRINTER.print(
content=f"Unexpected error during model conversion: {type(e).__name__}: {e}. Returning original result.",
color="red",
)
@@ -267,7 +267,7 @@ def handle_partial_json(
raise
except Exception as e:
if agent and getattr(agent, "verbose", True):
Printer().print(
PRINTER.print(
content=f"Unexpected error during partial JSON handling: {type(e).__name__}: {e}. Attempting alternative conversion method.",
color="red",
)
@@ -329,7 +329,7 @@ def convert_with_instructions(
if isinstance(exported_result, ConverterError):
if agent and getattr(agent, "verbose", True):
Printer().print(
PRINTER.print(
content=f"Failed to convert result to model: {exported_result}",
color="red",
)

View File

@@ -1,8 +1,8 @@
from datetime import datetime
from pydantic import BaseModel, Field, PrivateAttr
from pydantic import BaseModel, Field
from crewai.utilities.printer import ColoredText, Printer, PrinterColor
from crewai.utilities.printer import PRINTER, ColoredText, PrinterColor
class Logger(BaseModel):
@@ -14,7 +14,6 @@ class Logger(BaseModel):
default="bold_yellow",
description="Default color for log messages",
)
_printer: Printer = PrivateAttr(default_factory=Printer)
def log(self, level: str, message: str, color: PrinterColor | None = None) -> None:
"""Log a message with timestamp if verbose mode is enabled.
@@ -26,7 +25,7 @@ class Logger(BaseModel):
"""
if self.verbose:
timestamp: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self._printer.print(
PRINTER.print(
[
ColoredText(f"\n[{timestamp}]", "cyan"),
ColoredText(f"[{level.upper()}]: ", "yellow"),

View File

@@ -93,3 +93,6 @@ class Printer:
file=file,
flush=flush,
)
PRINTER: Printer = Printer()

View File

@@ -48,8 +48,6 @@ def _build_executor(**kwargs: Any) -> AgentExecutor:
executor._last_context_error = None
executor._step_executor = None
executor._planner_observer = None
from crewai.utilities.printer import Printer
executor._printer = Printer()
from crewai.utilities.i18n import get_i18n
executor._i18n = kwargs.get("i18n") or get_i18n()
return executor
@@ -1491,7 +1489,6 @@ class TestReasoningEffort:
executor.handle_step_observed_medium = (
AgentExecutor.handle_step_observed_medium.__get__(executor)
)
executor._printer = Mock()
# --- Case 1: step succeeded → should return "continue_plan" ---
success_todo = TodoItem(
@@ -1562,7 +1559,6 @@ class TestReasoningEffort:
executor.handle_step_observed_low = (
AgentExecutor.handle_step_observed_low.__get__(executor)
)
executor._printer = Mock()
todo = TodoItem(
step_number=1,

View File

@@ -1060,27 +1060,13 @@ def test_lite_agent_verbose_false_suppresses_printer_output():
verbose=False,
)
result = agent.kickoff("Say hello")
mock_printer = Mock()
with patch("crewai.lite_agent.PRINTER", mock_printer):
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")
# Verify the printer was never called when verbose=False
mock_printer.print.assert_not_called()

View File

@@ -529,9 +529,6 @@ def test_tool_validate_input_error_event():
mock_task = MagicMock()
mock_tools_handler = MagicMock()
# Mock printer
mock_printer = MagicMock()
# Create test tool
class TestTool(BaseTool):
name: str = "Test Tool"
@@ -551,8 +548,6 @@ def test_tool_validate_input_error_event():
agent=mock_agent,
action=MagicMock(tool="test_tool"),
)
tool_usage._printer = mock_printer
# Mock all parsing attempts to fail
with (
patch("json.loads", side_effect=json.JSONDecodeError("Test Error", "", 0)),

View File

@@ -207,10 +207,10 @@ def test_convert_with_instructions_failure(
mock_create_converter.return_value = mock_converter
result = "Some text to convert"
with patch("crewai.utilities.converter.Printer") as mock_printer:
with patch("crewai.utilities.converter.PRINTER") as mock_printer:
output = convert_with_instructions(result, SimpleModel, False, mock_agent)
assert output == result
mock_printer.return_value.print.assert_called_once()
mock_printer.print.assert_called_once()
# Tests for get_conversion_instructions