diff --git a/src/crewai/flow/flow.py b/src/crewai/flow/flow.py index 83d76f8a7..b2fcee961 100644 --- a/src/crewai/flow/flow.py +++ b/src/crewai/flow/flow.py @@ -29,6 +29,7 @@ from crewai.utilities.events import ( FlowStartedEvent, MethodExecutionFinishedEvent, MethodExecutionStartedEvent, + FlowCreatedEvent, ) from crewai.utilities.events.event_bus import event_bus from crewai.utilities.printer import Printer @@ -428,7 +429,6 @@ class Flow(Generic[T], metaclass=FlowMeta): Type parameter T must be either Dict[str, Any] or a subclass of BaseModel.""" - _telemetry = Telemetry() _printer = Printer() _start_methods: List[str] = [] @@ -469,7 +469,13 @@ class Flow(Generic[T], metaclass=FlowMeta): if kwargs: self._initialize_state(kwargs) - self._telemetry.flow_creation_span(self.__class__.__name__) + event_bus.emit( + self, + FlowCreatedEvent( + type="flow_created", + flow_name=self.__class__.__name__, + ), + ) # Register all flow-related methods for method_name in dir(self): @@ -759,19 +765,13 @@ class Flow(Generic[T], metaclass=FlowMeta): if not self._start_methods: raise ValueError("No start method defined") - self._telemetry.flow_execution_span( - self.__class__.__name__, list(self._methods.keys()) - ) - tasks = [ self._execute_start_method(start_method) for start_method in self._start_methods ] await asyncio.gather(*tasks) - print(f"All method outputs: {self._method_outputs}") # Debug log final_output = self._method_outputs[-1] if self._method_outputs else None - print("final_output", final_output) event_bus.emit( self, @@ -1029,8 +1029,8 @@ class Flow(Generic[T], metaclass=FlowMeta): elif level == "warning": logger.warning(message) - def plot(self, filename: str = "crewai_flow") -> None: - self._telemetry.flow_plotting_span( + def plot(self, filename: str = "crewai_flow") -> None: + Telemetry().flow_plotting_span( self.__class__.__name__, list(self._methods.keys()) ) plot_flow(self, filename) diff --git a/src/crewai/task.py b/src/crewai/task.py index e723fb0e3..32fbdd1d3 100644 --- a/src/crewai/task.py +++ b/src/crewai/task.py @@ -21,7 +21,6 @@ from typing import ( Union, ) -from opentelemetry.trace import Span from pydantic import ( UUID4, BaseModel, @@ -36,7 +35,6 @@ from crewai.agents.agent_builder.base_agent import BaseAgent from crewai.tasks.guardrail_result import GuardrailResult from crewai.tasks.output_format import OutputFormat from crewai.tasks.task_output import TaskOutput -from crewai.telemetry.telemetry import Telemetry from crewai.tools.base_tool import BaseTool from crewai.utilities.config import process_config from crewai.utilities.converter import Converter, convert_to_model @@ -189,8 +187,6 @@ class Task(BaseModel): ) return v - _telemetry: Telemetry = PrivateAttr(default_factory=Telemetry) - _execution_span: Optional[Span] = PrivateAttr(default=None) _original_description: Optional[str] = PrivateAttr(default=None) _original_expected_output: Optional[str] = PrivateAttr(default=None) _original_output_file: Optional[str] = PrivateAttr(default=None) @@ -363,9 +359,6 @@ class Task(BaseModel): ) self.start_time = datetime.datetime.now() - self._execution_span = self._telemetry.task_started( - crew=agent.crew, task=self - ) self.prompt_context = context tools = tools or self.tools or [] @@ -438,29 +431,20 @@ class Task(BaseModel): if crew and crew.task_callback and crew.task_callback != self.callback: crew.task_callback(self.output) - if self._execution_span: - self._telemetry.task_ended(self._execution_span, self, agent.crew) - self._execution_span = None - - if self.output_file: - content = ( - json_output - if json_output - else pydantic_output.model_dump_json() - if pydantic_output - else result - ) - self._save_file(content) + if self.output_file: + content = ( + json_output + if json_output + else pydantic_output.model_dump_json() + if pydantic_output + else result + ) + self._save_file(content) event_bus.emit(self, TaskCompletedEvent(output=task_output)) return task_output except Exception as e: self.end_time = datetime.datetime.now() - if self._execution_span: - if agent and agent.crew: - self._telemetry.task_ended(self._execution_span, self, agent.crew) - self._execution_span = None - - event_bus.emit(self, TaskFailedEvent(task=self, error=str(e))) + event_bus.emit(self, TaskFailedEvent(error=str(e))) raise e # Re-raise the exception after emitting the event def prompt(self) -> str: diff --git a/src/crewai/utilities/events/__init__.py b/src/crewai/utilities/events/__init__.py index a19502e54..3756d64f8 100644 --- a/src/crewai/utilities/events/__init__.py +++ b/src/crewai/utilities/events/__init__.py @@ -16,6 +16,7 @@ from .agent_events import ( ) from .task_events import TaskStartedEvent, TaskCompletedEvent, TaskFailedEvent from .flow_events import ( + FlowCreatedEvent, FlowStartedEvent, FlowFinishedEvent, MethodExecutionStartedEvent, diff --git a/src/crewai/utilities/events/crew_events.py b/src/crewai/utilities/events/crew_events.py index 229d5d53a..d5b12a196 100644 --- a/src/crewai/utilities/events/crew_events.py +++ b/src/crewai/utilities/events/crew_events.py @@ -92,4 +92,3 @@ class CrewTestFailedEvent(CrewEvent): error: str crew_name: Optional[str] type: str = "crew_test_failed" - diff --git a/src/crewai/utilities/events/event_listener.py b/src/crewai/utilities/events/event_listener.py index d34dd33de..d796889e1 100644 --- a/src/crewai/utilities/events/event_listener.py +++ b/src/crewai/utilities/events/event_listener.py @@ -1,9 +1,7 @@ -from re import S from pydantic import PrivateAttr from crewai.telemetry.telemetry import Telemetry from crewai.utilities import Logger -from crewai.utilities.evaluators.task_evaluator import TaskEvaluator from crewai.utilities.events.base_event_listener import BaseEventListener from .agent_events import AgentExecutionCompletedEvent, AgentExecutionStartedEvent @@ -19,12 +17,13 @@ from .crew_events import ( CrewTrainStartedEvent, ) from .flow_events import ( + FlowCreatedEvent, FlowFinishedEvent, FlowStartedEvent, MethodExecutionFinishedEvent, MethodExecutionStartedEvent, ) -from .task_events import TaskCompletedEvent, TaskStartedEvent +from .task_events import TaskCompletedEvent, TaskFailedEvent, TaskStartedEvent class EventListener(BaseEventListener): @@ -120,15 +119,44 @@ class EventListener(BaseEventListener): event.timestamp, color=self.color, ) - + + @event_bus.on(TaskStartedEvent) + def on_task_started(source, event: TaskStartedEvent): + source._execution_span = self._telemetry.task_started( + crew=source.agent.crew, task=source + ) + context = event.context + self.logger.log( + f"📋 Task started: {source.description} Context: {context}", + event.timestamp, + color=self.color, + ) + + + @event_bus.on(TaskCompletedEvent) def on_task_completed(source, event: TaskCompletedEvent): - self._telemetry.task_ended(source._execution_span, source, source) + if source._execution_span: + self._telemetry.task_ended(source._execution_span, source, source.agent.crew) self.logger.log( f"📋 Task completed: {source.description}", event.timestamp, color=self.color, ) + source._execution_span = None + + @event_bus.on(TaskFailedEvent) + def on_task_failed(source, event: TaskFailedEvent): + if source._execution_span: + if source.agent and source.agent.crew: + self._telemetry.task_ended(source._execution_span, source, source.agent.crew) + source._execution_span = None + self.logger.log( + f"❌ Task failed: {source.description}", + event.timestamp, + color=self.color, + ) + @event_bus.on(AgentExecutionStartedEvent) def on_agent_execution_started(source, event: AgentExecutionStartedEvent): @@ -147,8 +175,21 @@ class EventListener(BaseEventListener): ) # Flow Events + + @event_bus.on(FlowCreatedEvent) + def on_flow_created(source, event: FlowCreatedEvent): + self._telemetry.flow_creation_span(self.__class__.__name__) + self.logger.log( + f"🌊 Flow Created: '{event.flow_name}'", + event.timestamp, + color=self.color, + ) + @event_bus.on(FlowStartedEvent) def on_flow_started(source, event: FlowStartedEvent): + self._telemetry.flow_execution_span( + source.__class__.__name__, list(source._methods.keys()) + ) self.logger.log( f"🤖 Flow Started: '{event.flow_name}'", event.timestamp, diff --git a/src/crewai/utilities/events/flow_events.py b/src/crewai/utilities/events/flow_events.py index 1eb988413..ac0fbeea1 100644 --- a/src/crewai/utilities/events/flow_events.py +++ b/src/crewai/utilities/events/flow_events.py @@ -20,6 +20,13 @@ class FlowStartedEvent(FlowEvent): type: str = "flow_started" + +class FlowCreatedEvent(FlowEvent): + """Event emitted when a flow is created""" + + flow_name: str + type: str = "flow_created" + class MethodExecutionStartedEvent(FlowEvent): """Event emitted when a flow method starts execution""" diff --git a/src/crewai/utilities/events/task_events.py b/src/crewai/utilities/events/task_events.py index f1de7a8df..a48f0b69d 100644 --- a/src/crewai/utilities/events/task_events.py +++ b/src/crewai/utilities/events/task_events.py @@ -1,5 +1,4 @@ from typing import Any, Optional - from crewai.utilities.events.crew_events import CrewEvent @@ -8,7 +7,6 @@ class TaskStartedEvent(CrewEvent): type: str = "task_started" context: Optional[str] - model_config = {"arbitrary_types_allowed": True} @@ -18,12 +16,11 @@ class TaskCompletedEvent(CrewEvent): output: Any type: str = "task_completed" - model_config = {"arbitrary_types_allowed": True} class TaskFailedEvent(CrewEvent): """Event emitted when a task fails""" - task: Any error: str type: str = "task_failed" + diff --git a/tests/utilities/cassettes/test_task_emits_failed_event_on_execution_error.yaml b/tests/utilities/cassettes/test_task_emits_failed_event_on_execution_error.yaml index 389c74eba..9c87bddaa 100644 --- a/tests/utilities/cassettes/test_task_emits_failed_event_on_execution_error.yaml +++ b/tests/utilities/cassettes/test_task_emits_failed_event_on_execution_error.yaml @@ -1,13 +1,19 @@ interactions: - request: body: '{"messages": [{"role": "system", "content": "You are base_agent. You are - a helpful assistant that just says hi\nYour personal goal is: Just say hi\nTo - give my best complete final answer to the task respond using the exact following - format:\n\nThought: I now can give a great answer\nFinal Answer: Your final - answer must be the great and the most complete as possible, it must be outcome - described.\n\nI MUST use these formats, my job depends on it!"}, {"role": "user", - "content": "\nCurrent Task: Just say hi\n\nThis is the expect criteria for your - final answer: hi\nyou MUST return the actual complete content as the final answer, + a helpful assistant that just says hi\nYour personal goal is: Just say hi\nYou + ONLY have access to the following tools, and should NEVER make up tools that + are not listed here:\n\nTool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error\n\nIMPORTANT: Use the following format in your + response:\n\n```\nThought: you should always think about what to do\nAction: + the action to take, only one name of [Say Hi], just the name, exactly as it''s + written.\nAction Input: the input to the action, just a simple JSON object, + enclosed in curly braces, using \" to wrap keys and values.\nObservation: the + result of the action\n```\n\nOnce all necessary information is gathered, return + the following format:\n\n```\nThought: I now know the final answer\nFinal Answer: + the final answer to the original input question\n```"}, {"role": "user", "content": + "\nCurrent Task: Just say hi\n\nThis is the expected criteria for your final + answer: hi\nyou MUST return the actual complete content as the final answer, not a summary.\n\nBegin! This is VERY important to you, use the tools available and give your best Final Answer, your job depends on it!\n\nThought:"}], "model": "gpt-4o-mini", "stop": ["\nObservation:"]}' @@ -19,9 +25,11 @@ interactions: connection: - keep-alive content-length: - - '836' + - '1303' content-type: - application/json + cookie: + - _cfuvid=Cl48aI8.jSRja0Pqr6Jrh3mAnigd4rDn6lhGicyjMPY-1738698987673-0.0.1.1-604800000 host: - api.openai.com user-agent: @@ -47,20 +55,23 @@ interactions: method: POST uri: https://api.openai.com/v1/chat/completions response: - content: "{\n \"id\": \"chatcmpl-Azq6WJmBZbITt0acwjRonlLua3QxT\",\n \"object\": - \"chat.completion\",\n \"created\": 1739301660,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + content: "{\n \"id\": \"chatcmpl-B0ceNVvGO3iTja3ZJM0GHPp7fptc6\",\n \"object\": + \"chat.completion\",\n \"created\": 1739488271,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": - \"assistant\",\n \"content\": \"I now can give a great answer \\nFinal - Answer: hi\",\n \"refusal\": null\n },\n \"logprobs\": null,\n - \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": - 161,\n \"completion_tokens\": 12,\n \"total_tokens\": 173,\n \"prompt_tokens_details\": - {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": - {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + \"assistant\",\n \"content\": \"```\\nThought: you should always think + about what to do\\nAction: Say Hi\\nAction Input: {}\",\n \"refusal\": + null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 261,\n \"completion_tokens\": + 22,\n \"total_tokens\": 283,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n + \ \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": - \"default\",\n \"system_fingerprint\": \"fp_72ed7ab54c\"\n}\n" + \"default\",\n \"system_fingerprint\": \"fp_bd83329f63\"\n}\n" headers: + CF-Cache-Status: + - DYNAMIC CF-RAY: - - 9106b311e8c07e25-SJC + - 91187efd98829e74-SJC Connection: - keep-alive Content-Encoding: @@ -68,14 +79,14 @@ interactions: Content-Type: - application/json Date: - - Tue, 11 Feb 2025 19:21:01 GMT + - Thu, 13 Feb 2025 23:11:12 GMT Server: - cloudflare Set-Cookie: - - __cf_bm=BkEp5CX4ww8Vwy5oYVZjMyXHy_c9tXdEJGfsQ51m67c-1739301661-1.0.1.1-BUtQpsmDPsq5ZBEmUB.Zw8aq8D3MvPz5U8rR4oa.gsns9S9ve3SPfP8hmpYpSWYYYJPg1KJIBG0OTJwjC9lWkg; - path=/; expires=Tue, 11-Feb-25 19:51:01 GMT; domain=.api.openai.com; HttpOnly; + - __cf_bm=XgZ48Kh_Np19KQZFMcdhitEO1hYoQQZmGISmqGQyAew-1739488272-1.0.1.1-71ljflXRwwgMFHqNdbWAIPe5U0Svfer60TB92nqmufsvx_NnPNO.ShrjIwdWBpJ6cQIh6szfk6FrIoioemqHgg; + path=/; expires=Thu, 13-Feb-25 23:41:12 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None - - _cfuvid=4fxBBkCchurossCvL6LwAzMBGrP47yMs0bo0ZMKGz0I-1739301661039-0.0.1.1-604800000; + - _cfuvid=eFYG1.FIv9a4z_Uqb0svvrE60EPh73_2qTAnZyFX9lA-1739488272138-0.0.1.1-604800000; path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None Transfer-Encoding: - chunked @@ -85,12 +96,139 @@ interactions: - X-Request-ID alt-svc: - h3=":443"; ma=86400 + openai-organization: + - crewai-iuxna1 + openai-processing-ms: + - '782' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999697' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_67df2b150e90b637ec98ad5796dfe71d + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "system", "content": "You are base_agent. You are + a helpful assistant that just says hi\nYour personal goal is: Just say hi\nYou + ONLY have access to the following tools, and should NEVER make up tools that + are not listed here:\n\nTool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error\n\nIMPORTANT: Use the following format in your + response:\n\n```\nThought: you should always think about what to do\nAction: + the action to take, only one name of [Say Hi], just the name, exactly as it''s + written.\nAction Input: the input to the action, just a simple JSON object, + enclosed in curly braces, using \" to wrap keys and values.\nObservation: the + result of the action\n```\n\nOnce all necessary information is gathered, return + the following format:\n\n```\nThought: I now know the final answer\nFinal Answer: + the final answer to the original input question\n```"}, {"role": "user", "content": + "\nCurrent Task: Just say hi\n\nThis is the expected criteria for your final + answer: hi\nyou MUST return the actual complete content as the final answer, + not a summary.\n\nBegin! This is VERY important to you, use the tools available + and give your best Final Answer, your job depends on it!\n\nThought:"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}], "model": + "gpt-4o-mini", "stop": ["\nObservation:"]}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '2362' + content-type: + - application/json + cookie: + - _cfuvid=eFYG1.FIv9a4z_Uqb0svvrE60EPh73_2qTAnZyFX9lA-1739488272138-0.0.1.1-604800000; + __cf_bm=XgZ48Kh_Np19KQZFMcdhitEO1hYoQQZmGISmqGQyAew-1739488272-1.0.1.1-71ljflXRwwgMFHqNdbWAIPe5U0Svfer60TB92nqmufsvx_NnPNO.ShrjIwdWBpJ6cQIh6szfk6FrIoioemqHgg + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.61.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.61.0 + x-stainless-raw-response: + - 'true' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.8 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-B0ceOtrUJ80V8Li7rmZaP56XCp37M\",\n \"object\": + \"chat.completion\",\n \"created\": 1739488272,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"```\\nThought: you should always think + about what to do\\nAction: Say Hi\\nAction Input: {}\",\n \"refusal\": + null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 494,\n \"completion_tokens\": + 22,\n \"total_tokens\": 516,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n + \ \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_bd83329f63\"\n}\n" + headers: + CF-RAY: + - 91187f05197b9e74-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 13 Feb 2025 23:11:12 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 cf-cache-status: - DYNAMIC openai-organization: - crewai-iuxna1 openai-processing-ms: - - '499' + - '545' openai-version: - '2020-10-01' strict-transport-security: @@ -102,13 +240,765 @@ interactions: x-ratelimit-remaining-requests: - '29999' x-ratelimit-remaining-tokens: - - '149999810' + - '149999447' x-ratelimit-reset-requests: - 2ms x-ratelimit-reset-tokens: - 0s x-request-id: - - req_92c40fec00fb98496f76bdaa7b0842a2 + - req_d7c1f2c3bae845e5083c5092852e051f + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "system", "content": "You are base_agent. You are + a helpful assistant that just says hi\nYour personal goal is: Just say hi\nYou + ONLY have access to the following tools, and should NEVER make up tools that + are not listed here:\n\nTool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error\n\nIMPORTANT: Use the following format in your + response:\n\n```\nThought: you should always think about what to do\nAction: + the action to take, only one name of [Say Hi], just the name, exactly as it''s + written.\nAction Input: the input to the action, just a simple JSON object, + enclosed in curly braces, using \" to wrap keys and values.\nObservation: the + result of the action\n```\n\nOnce all necessary information is gathered, return + the following format:\n\n```\nThought: I now know the final answer\nFinal Answer: + the final answer to the original input question\n```"}, {"role": "user", "content": + "\nCurrent Task: Just say hi\n\nThis is the expected criteria for your final + answer: hi\nyou MUST return the actual complete content as the final answer, + not a summary.\n\nBegin! This is VERY important to you, use the tools available + and give your best Final Answer, your job depends on it!\n\nThought:"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}], "model": + "gpt-4o-mini", "stop": ["\nObservation:"]}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '3421' + content-type: + - application/json + cookie: + - _cfuvid=eFYG1.FIv9a4z_Uqb0svvrE60EPh73_2qTAnZyFX9lA-1739488272138-0.0.1.1-604800000; + __cf_bm=XgZ48Kh_Np19KQZFMcdhitEO1hYoQQZmGISmqGQyAew-1739488272-1.0.1.1-71ljflXRwwgMFHqNdbWAIPe5U0Svfer60TB92nqmufsvx_NnPNO.ShrjIwdWBpJ6cQIh6szfk6FrIoioemqHgg + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.61.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.61.0 + x-stainless-raw-response: + - 'true' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.8 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-B0cePLitBGIhHl5SUU1C8s7cmjIEX\",\n \"object\": + \"chat.completion\",\n \"created\": 1739488273,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"```\\nThought: you should always think + about what to do\\nAction: Say Hi\\nAction Input: {}\",\n \"refusal\": + null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 727,\n \"completion_tokens\": + 22,\n \"total_tokens\": 749,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n + \ \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_bd83329f63\"\n}\n" + headers: + CF-RAY: + - 91187f098ead9e74-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 13 Feb 2025 23:11:13 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + openai-organization: + - crewai-iuxna1 + openai-processing-ms: + - '632' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149999196' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_6c82a00bbf8ab599a6a6cf521cb4bf52 + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "system", "content": "You are base_agent. You are + a helpful assistant that just says hi\nYour personal goal is: Just say hi\nYou + ONLY have access to the following tools, and should NEVER make up tools that + are not listed here:\n\nTool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error\n\nIMPORTANT: Use the following format in your + response:\n\n```\nThought: you should always think about what to do\nAction: + the action to take, only one name of [Say Hi], just the name, exactly as it''s + written.\nAction Input: the input to the action, just a simple JSON object, + enclosed in curly braces, using \" to wrap keys and values.\nObservation: the + result of the action\n```\n\nOnce all necessary information is gathered, return + the following format:\n\n```\nThought: I now know the final answer\nFinal Answer: + the final answer to the original input question\n```"}, {"role": "user", "content": + "\nCurrent Task: Just say hi\n\nThis is the expected criteria for your final + answer: hi\nyou MUST return the actual complete content as the final answer, + not a summary.\n\nBegin! This is VERY important to you, use the tools available + and give your best Final Answer, your job depends on it!\n\nThought:"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}], "model": + "gpt-4o-mini", "stop": ["\nObservation:"]}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '4480' + content-type: + - application/json + cookie: + - _cfuvid=eFYG1.FIv9a4z_Uqb0svvrE60EPh73_2qTAnZyFX9lA-1739488272138-0.0.1.1-604800000; + __cf_bm=XgZ48Kh_Np19KQZFMcdhitEO1hYoQQZmGISmqGQyAew-1739488272-1.0.1.1-71ljflXRwwgMFHqNdbWAIPe5U0Svfer60TB92nqmufsvx_NnPNO.ShrjIwdWBpJ6cQIh6szfk6FrIoioemqHgg + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.61.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.61.0 + x-stainless-raw-response: + - 'true' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.8 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-B0cePDnVjWCsyTlSfvSmP1uUWVqJV\",\n \"object\": + \"chat.completion\",\n \"created\": 1739488273,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"```\\nThought: you should always think + about what to do\\nAction: Say Hi\\nAction Input: {}\",\n \"refusal\": + null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 960,\n \"completion_tokens\": + 22,\n \"total_tokens\": 982,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n + \ \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_bd83329f63\"\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 91187f0e0bd19e74-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 13 Feb 2025 23:11:14 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-organization: + - crewai-iuxna1 + openai-processing-ms: + - '757' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149998945' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_83956b8df7f7137fec9ae6450f3c9a7b + http_version: HTTP/1.1 + status_code: 200 +- request: + body: !!binary | + CqIiCiQKIgoMc2VydmljZS5uYW1lEhIKEGNyZXdBSS10ZWxlbWV0cnkS+SEKEgoQY3Jld2FpLnRl + bGVtZXRyeRKkBwoQy3yskK/xR1Awm7D0OKZhbxIIH0xxCLM8S5cqDENyZXcgQ3JlYXRlZDABOXBZ + LLZd5yMYQYCpOrZd5yMYShsKDmNyZXdhaV92ZXJzaW9uEgkKBzAuMTAwLjFKGgoOcHl0aG9uX3Zl + cnNpb24SCAoGMy4xMi44Si4KCGNyZXdfa2V5EiIKIGU1ODA3MDFkNTJlYjY1YWZmMjRlZWZlNzhj + NzQ2MjhjSjEKB2NyZXdfaWQSJgokOGQ4NDY3OGYtMDU0NC00MWFiLWIwMjQtMTFkYTRhMTgxNzhj + ShwKDGNyZXdfcHJvY2VzcxIMCgpzZXF1ZW50aWFsShEKC2NyZXdfbWVtb3J5EgIQAEoaChRjcmV3 + X251bWJlcl9vZl90YXNrcxICGAFKGwoVY3Jld19udW1iZXJfb2ZfYWdlbnRzEgIYAUrRAgoLY3Jl + d19hZ2VudHMSwQIKvgJbeyJrZXkiOiAiYWQxNTMxNjFjNWM1YTg1NmFhMGQwNmIyNDljNGM2NGEi + LCAiaWQiOiAiYWQ5OTg5ZTEtNDY5YS00YmQxLTg0ZjQtZWVlNjZhYTBiMjk3IiwgInJvbGUiOiAi + YmFzZV9hZ2VudCIsICJ2ZXJib3NlPyI6IGZhbHNlLCAibWF4X2l0ZXIiOiAyNSwgIm1heF9ycG0i + OiBudWxsLCAiZnVuY3Rpb25fY2FsbGluZ19sbG0iOiAiIiwgImxsbSI6ICJncHQtNG8tbWluaSIs + ICJkZWxlZ2F0aW9uX2VuYWJsZWQ/IjogZmFsc2UsICJhbGxvd19jb2RlX2V4ZWN1dGlvbj8iOiBm + YWxzZSwgIm1heF9yZXRyeV9saW1pdCI6IDIsICJ0b29sc19uYW1lcyI6IFtdfV1K/wEKCmNyZXdf + dGFza3MS8AEK7QFbeyJrZXkiOiAiMWIxNWVmMjM5MTViMjc1NWU4OWEwZWMzYjI2YTEzZDIiLCAi + aWQiOiAiNWUyMWIxOTQtMzE5Ni00NDBhLTg3ZTAtMWEyOGJkZjUxMGUzIiwgImFzeW5jX2V4ZWN1 + dGlvbj8iOiBmYWxzZSwgImh1bWFuX2lucHV0PyI6IGZhbHNlLCAiYWdlbnRfcm9sZSI6ICJiYXNl + X2FnZW50IiwgImFnZW50X2tleSI6ICJhZDE1MzE2MWM1YzVhODU2YWEwZDA2YjI0OWM0YzY0YSIs + ICJ0b29sc19uYW1lcyI6IFtdfV16AhgBhQEAAQAAEo4CChCvtNCi6SXalRPxb+3e9KHyEggbtBZr + f+eAqioMVGFzayBDcmVhdGVkMAE5oJFLtl3nIxhBkOdLtl3nIxhKLgoIY3Jld19rZXkSIgogZTU4 + MDcwMWQ1MmViNjVhZmYyNGVlZmU3OGM3NDYyOGNKMQoHY3Jld19pZBImCiQ4ZDg0Njc4Zi0wNTQ0 + LTQxYWItYjAyNC0xMWRhNGExODE3OGNKLgoIdGFza19rZXkSIgogMWIxNWVmMjM5MTViMjc1NWU4 + OWEwZWMzYjI2YTEzZDJKMQoHdGFza19pZBImCiQ1ZTIxYjE5NC0zMTk2LTQ0MGEtODdlMC0xYTI4 + YmRmNTEwZTN6AhgBhQEAAQAAEqQHChBgHAng7xhBnfS2/GYvkdYbEggsqqZdYq4kICoMQ3JldyBD + cmVhdGVkMAE5MC09t13nIxhBMPdFt13nIxhKGwoOY3Jld2FpX3ZlcnNpb24SCQoHMC4xMDAuMUoa + Cg5weXRob25fdmVyc2lvbhIICgYzLjEyLjhKLgoIY3Jld19rZXkSIgogZTU4MDcwMWQ1MmViNjVh + ZmYyNGVlZmU3OGM3NDYyOGNKMQoHY3Jld19pZBImCiRiMDQ0Njk5NC1jNzMxLTQ4MTQtYjQ0Zi04 + MGUzNmY0NmVlNjdKHAoMY3Jld19wcm9jZXNzEgwKCnNlcXVlbnRpYWxKEQoLY3Jld19tZW1vcnkS + AhAAShoKFGNyZXdfbnVtYmVyX29mX3Rhc2tzEgIYAUobChVjcmV3X251bWJlcl9vZl9hZ2VudHMS + AhgBStECCgtjcmV3X2FnZW50cxLBAgq+Alt7ImtleSI6ICJhZDE1MzE2MWM1YzVhODU2YWEwZDA2 + YjI0OWM0YzY0YSIsICJpZCI6ICJhZDk5ODllMS00NjlhLTRiZDEtODRmNC1lZWU2NmFhMGIyOTci + LCAicm9sZSI6ICJiYXNlX2FnZW50IiwgInZlcmJvc2U/IjogZmFsc2UsICJtYXhfaXRlciI6IDI1 + LCAibWF4X3JwbSI6IG51bGwsICJmdW5jdGlvbl9jYWxsaW5nX2xsbSI6ICIiLCAibGxtIjogImdw + dC00by1taW5pIiwgImRlbGVnYXRpb25fZW5hYmxlZD8iOiBmYWxzZSwgImFsbG93X2NvZGVfZXhl + Y3V0aW9uPyI6IGZhbHNlLCAibWF4X3JldHJ5X2xpbWl0IjogMiwgInRvb2xzX25hbWVzIjogW119 + XUr/AQoKY3Jld190YXNrcxLwAQrtAVt7ImtleSI6ICIxYjE1ZWYyMzkxNWIyNzU1ZTg5YTBlYzNi + MjZhMTNkMiIsICJpZCI6ICI1ZTIxYjE5NC0zMTk2LTQ0MGEtODdlMC0xYTI4YmRmNTEwZTMiLCAi + YXN5bmNfZXhlY3V0aW9uPyI6IGZhbHNlLCAiaHVtYW5faW5wdXQ/IjogZmFsc2UsICJhZ2VudF9y + b2xlIjogImJhc2VfYWdlbnQiLCAiYWdlbnRfa2V5IjogImFkMTUzMTYxYzVjNWE4NTZhYTBkMDZi + MjQ5YzRjNjRhIiwgInRvb2xzX25hbWVzIjogW119XXoCGAGFAQABAAASjgIKEPPkDbccpJ9jDuUl + rzqUoqQSCL6irICbXoxyKgxUYXNrIENyZWF0ZWQwATn4sVm3XecjGEGIF1q3XecjGEouCghjcmV3 + X2tleRIiCiBlNTgwNzAxZDUyZWI2NWFmZjI0ZWVmZTc4Yzc0NjI4Y0oxCgdjcmV3X2lkEiYKJGIw + NDQ2OTk0LWM3MzEtNDgxNC1iNDRmLTgwZTM2ZjQ2ZWU2N0ouCgh0YXNrX2tleRIiCiAxYjE1ZWYy + MzkxNWIyNzU1ZTg5YTBlYzNiMjZhMTNkMkoxCgd0YXNrX2lkEiYKJDVlMjFiMTk0LTMxOTYtNDQw + YS04N2UwLTFhMjhiZGY1MTBlM3oCGAGFAQABAAASpAcKEOZUZG2c1vI5V6bNLpPk3ygSCIKZQpuE + HMQfKgxDcmV3IENyZWF0ZWQwATlwnAC4XecjGEGQMQq4XecjGEobCg5jcmV3YWlfdmVyc2lvbhIJ + CgcwLjEwMC4xShoKDnB5dGhvbl92ZXJzaW9uEggKBjMuMTIuOEouCghjcmV3X2tleRIiCiBlNTgw + NzAxZDUyZWI2NWFmZjI0ZWVmZTc4Yzc0NjI4Y0oxCgdjcmV3X2lkEiYKJGM2ZGQ0OTYwLTU3ZTMt + NGQ5Mi1iZTQzLTg3OTQ0N2NmZjJjNEocCgxjcmV3X3Byb2Nlc3MSDAoKc2VxdWVudGlhbEoRCgtj + cmV3X21lbW9yeRICEABKGgoUY3Jld19udW1iZXJfb2ZfdGFza3MSAhgBShsKFWNyZXdfbnVtYmVy + X29mX2FnZW50cxICGAFK0QIKC2NyZXdfYWdlbnRzEsECCr4CW3sia2V5IjogImFkMTUzMTYxYzVj + NWE4NTZhYTBkMDZiMjQ5YzRjNjRhIiwgImlkIjogImFkOTk4OWUxLTQ2OWEtNGJkMS04NGY0LWVl + ZTY2YWEwYjI5NyIsICJyb2xlIjogImJhc2VfYWdlbnQiLCAidmVyYm9zZT8iOiBmYWxzZSwgIm1h + eF9pdGVyIjogMjUsICJtYXhfcnBtIjogbnVsbCwgImZ1bmN0aW9uX2NhbGxpbmdfbGxtIjogIiIs + ICJsbG0iOiAiZ3B0LTRvLW1pbmkiLCAiZGVsZWdhdGlvbl9lbmFibGVkPyI6IGZhbHNlLCAiYWxs + b3dfY29kZV9leGVjdXRpb24/IjogZmFsc2UsICJtYXhfcmV0cnlfbGltaXQiOiAyLCAidG9vbHNf + bmFtZXMiOiBbXX1dSv8BCgpjcmV3X3Rhc2tzEvABCu0BW3sia2V5IjogIjFiMTVlZjIzOTE1YjI3 + NTVlODlhMGVjM2IyNmExM2QyIiwgImlkIjogIjVlMjFiMTk0LTMxOTYtNDQwYS04N2UwLTFhMjhi + ZGY1MTBlMyIsICJhc3luY19leGVjdXRpb24/IjogZmFsc2UsICJodW1hbl9pbnB1dD8iOiBmYWxz + ZSwgImFnZW50X3JvbGUiOiAiYmFzZV9hZ2VudCIsICJhZ2VudF9rZXkiOiAiYWQxNTMxNjFjNWM1 + YTg1NmFhMGQwNmIyNDljNGM2NGEiLCAidG9vbHNfbmFtZXMiOiBbXX1degIYAYUBAAEAABKOAgoQ + vhlU4CgyTyrgPRf0wlb8eRIIqtS4lWPuJuYqDFRhc2sgQ3JlYXRlZDABOSA9Gbhd5yMYQWiuGbhd + 5yMYSi4KCGNyZXdfa2V5EiIKIGU1ODA3MDFkNTJlYjY1YWZmMjRlZWZlNzhjNzQ2MjhjSjEKB2Ny + ZXdfaWQSJgokYzZkZDQ5NjAtNTdlMy00ZDkyLWJlNDMtODc5NDQ3Y2ZmMmM0Si4KCHRhc2tfa2V5 + EiIKIDFiMTVlZjIzOTE1YjI3NTVlODlhMGVjM2IyNmExM2QySjEKB3Rhc2tfaWQSJgokNWUyMWIx + OTQtMzE5Ni00NDBhLTg3ZTAtMWEyOGJkZjUxMGUzegIYAYUBAAEAABKOAgoQr7izSc/LzkAmDVE4 + TCRtVxIIlEdWL3gr4vAqDFRhc2sgQ3JlYXRlZDABOajMq7hd5yMYQUCErLhd5yMYSi4KCGNyZXdf + a2V5EiIKIGU1ODA3MDFkNTJlYjY1YWZmMjRlZWZlNzhjNzQ2MjhjSjEKB2NyZXdfaWQSJgokYzZk + ZDQ5NjAtNTdlMy00ZDkyLWJlNDMtODc5NDQ3Y2ZmMmM0Si4KCHRhc2tfa2V5EiIKIDFiMTVlZjIz + OTE1YjI3NTVlODlhMGVjM2IyNmExM2QySjEKB3Rhc2tfaWQSJgokYmNhMmRkYmMtZmM4MC00ZTM4 + LWE2ZTAtNTU0MmM2OTIzYTE5egIYAYUBAAEAABJpChAW++bDmEo222QymLgbmnOnEggC9Fj1KYqp + iCoQVG9vbCBVc2FnZSBFcnJvcjABOQja5wRe5yMYQdjm+wRe5yMYShsKDmNyZXdhaV92ZXJzaW9u + EgkKBzAuMTAwLjF6AhgBhQEAAQAAEmkKEOeYSHtVxHT42vgh6qJWipASCG4YjIxTPsQrKhBUb29s + IFVzYWdlIEVycm9yMAE58JKtL17nIxhBeEy8L17nIxhKGwoOY3Jld2FpX3ZlcnNpb24SCQoHMC4x + MDAuMXoCGAGFAQABAAASaQoQd2xGQ0N0fRjEAZb3m591vhII9yEmZE84dukqEFRvb2wgVXNhZ2Ug + RXJyb3IwATkIXzBaXucjGEHgTEJaXucjGEobCg5jcmV3YWlfdmVyc2lvbhIJCgcwLjEwMC4xegIY + AYUBAAEAABJpChCuKrUoVTHcaqSma3csnzpOEgjdvJJFFn7JYioQVG9vbCBVc2FnZSBFcnJvcjAB + OVjIbJFe5yMYQTgIf5Fe5yMYShsKDmNyZXdhaV92ZXJzaW9uEgkKBzAuMTAwLjF6AhgBhQEAAQAA + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '4389' + Content-Type: + - application/x-protobuf + User-Agent: + - OTel-OTLP-Exporter-Python/1.27.0 + method: POST + uri: https://telemetry.crewai.com:4319/v1/traces + response: + body: + string: "\n\0" + headers: + Content-Length: + - '2' + Content-Type: + - application/x-protobuf + Date: + - Thu, 13 Feb 2025 23:11:15 GMT + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"role": "system", "content": "You are base_agent. You are + a helpful assistant that just says hi\nYour personal goal is: Just say hi\nYou + ONLY have access to the following tools, and should NEVER make up tools that + are not listed here:\n\nTool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error\n\nIMPORTANT: Use the following format in your + response:\n\n```\nThought: you should always think about what to do\nAction: + the action to take, only one name of [Say Hi], just the name, exactly as it''s + written.\nAction Input: the input to the action, just a simple JSON object, + enclosed in curly braces, using \" to wrap keys and values.\nObservation: the + result of the action\n```\n\nOnce all necessary information is gathered, return + the following format:\n\n```\nThought: I now know the final answer\nFinal Answer: + the final answer to the original input question\n```"}, {"role": "user", "content": + "\nCurrent Task: Just say hi\n\nThis is the expected criteria for your final + answer: hi\nyou MUST return the actual complete content as the final answer, + not a summary.\n\nBegin! This is VERY important to you, use the tools available + and give your best Final Answer, your job depends on it!\n\nThought:"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}], "model": + "gpt-4o-mini", "stop": ["\nObservation:"]}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '5539' + content-type: + - application/json + cookie: + - _cfuvid=eFYG1.FIv9a4z_Uqb0svvrE60EPh73_2qTAnZyFX9lA-1739488272138-0.0.1.1-604800000; + __cf_bm=XgZ48Kh_Np19KQZFMcdhitEO1hYoQQZmGISmqGQyAew-1739488272-1.0.1.1-71ljflXRwwgMFHqNdbWAIPe5U0Svfer60TB92nqmufsvx_NnPNO.ShrjIwdWBpJ6cQIh6szfk6FrIoioemqHgg + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.61.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.61.0 + x-stainless-raw-response: + - 'true' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.8 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-B0ceQN5mVVSLXPfYhoXL7kYKYC7js\",\n \"object\": + \"chat.completion\",\n \"created\": 1739488274,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"```\\nThought: you should always think + about what to do\\nAction: Say Hi\\nAction Input: {}\",\n \"refusal\": + null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 1193,\n \"completion_tokens\": + 22,\n \"total_tokens\": 1215,\n \"prompt_tokens_details\": {\n \"cached_tokens\": + 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n + \ \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_bd83329f63\"\n}\n" + headers: + CF-RAY: + - 91187f13fb279e74-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 13 Feb 2025 23:11:15 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + cf-cache-status: + - DYNAMIC + openai-organization: + - crewai-iuxna1 + openai-processing-ms: + - '615' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149998695' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_732a192814669f7e2fce3f349a4b1b8d + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "system", "content": "You are base_agent. You are + a helpful assistant that just says hi\nYour personal goal is: Just say hi\nYou + ONLY have access to the following tools, and should NEVER make up tools that + are not listed here:\n\nTool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error\n\nIMPORTANT: Use the following format in your + response:\n\n```\nThought: you should always think about what to do\nAction: + the action to take, only one name of [Say Hi], just the name, exactly as it''s + written.\nAction Input: the input to the action, just a simple JSON object, + enclosed in curly braces, using \" to wrap keys and values.\nObservation: the + result of the action\n```\n\nOnce all necessary information is gathered, return + the following format:\n\n```\nThought: I now know the final answer\nFinal Answer: + the final answer to the original input question\n```"}, {"role": "user", "content": + "\nCurrent Task: Just say hi\n\nThis is the expected criteria for your final + answer: hi\nyou MUST return the actual complete content as the final answer, + not a summary.\n\nBegin! This is VERY important to you, use the tools available + and give your best Final Answer, your job depends on it!\n\nThought:"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}, {"role": + "assistant", "content": "```\nThought: you should always think about what to + do\nAction: Say Hi\nAction Input: {}\nObservation: \nI encountered an error + while trying to use the tool. This was the error: Simulated tool error.\n Tool + Say Hi accepts these inputs: Tool Name: Say Hi\nTool Arguments: {}\nTool Description: + This tool always raises an error.\nMoving on then. I MUST either use a tool + (use one at time) OR give my best final answer not both at the same time. When + responding, I must use the following format:\n\n```\nThought: you should always + think about what to do\nAction: the action to take, should be one of [Say Hi]\nAction + Input: the input to the action, dictionary enclosed in curly braces\nObservation: + the result of the action\n```\nThis Thought/Action/Action Input/Result can repeat + N times. Once I know the final answer, I must return the following format:\n\n```\nThought: + I now can give a great answer\nFinal Answer: Your final answer must be the great + and the most complete as possible, it must be outcome described\n\n```"}], "model": + "gpt-4o-mini", "stop": ["\nObservation:"]}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '6598' + content-type: + - application/json + cookie: + - _cfuvid=eFYG1.FIv9a4z_Uqb0svvrE60EPh73_2qTAnZyFX9lA-1739488272138-0.0.1.1-604800000; + __cf_bm=XgZ48Kh_Np19KQZFMcdhitEO1hYoQQZmGISmqGQyAew-1739488272-1.0.1.1-71ljflXRwwgMFHqNdbWAIPe5U0Svfer60TB92nqmufsvx_NnPNO.ShrjIwdWBpJ6cQIh6szfk6FrIoioemqHgg + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.61.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.61.0 + x-stainless-raw-response: + - 'true' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.8 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-B0ceRVoFzoUPmiO0sOZVNpLbXD41f\",\n \"object\": + \"chat.completion\",\n \"created\": 1739488275,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"```\\nThought: I now know the final answer\\nFinal + Answer: hi\\n```\",\n \"refusal\": null\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 1426,\n \"completion_tokens\": 17,\n \"total_tokens\": 1443,\n \"prompt_tokens_details\": + {\n \"cached_tokens\": 1024,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": + {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": + 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": + \"default\",\n \"system_fingerprint\": \"fp_bd83329f63\"\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 91187f1b3b1e9e74-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 13 Feb 2025 23:11:16 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-organization: + - crewai-iuxna1 + openai-processing-ms: + - '618' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - '30000' + x-ratelimit-limit-tokens: + - '150000000' + x-ratelimit-remaining-requests: + - '29999' + x-ratelimit-remaining-tokens: + - '149998444' + x-ratelimit-reset-requests: + - 2ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_b12d08242d920f524028f18e6eb2ef1a http_version: HTTP/1.1 status_code: 200 version: 1 diff --git a/tests/utilities/test_events.py b/tests/utilities/test_events.py index 5688112be..ed47a32c4 100644 --- a/tests/utilities/test_events.py +++ b/tests/utilities/test_events.py @@ -23,6 +23,7 @@ from crewai.utilities.events.crew_events import ( from crewai.utilities.events.event_bus import event_bus from crewai.utilities.events.event_types import ToolUsageFinishedEvent from crewai.utilities.events.flow_events import ( + FlowCreatedEvent, FlowFinishedEvent, FlowStartedEvent, MethodExecutionStartedEvent, @@ -33,6 +34,7 @@ from crewai.utilities.events.task_events import ( TaskStartedEvent, ) from crewai.utilities.events.tool_usage_events import ToolUsageErrorEvent +from requests.exceptions import RequestException base_agent = Agent( role="base_agent", @@ -148,27 +150,35 @@ def test_crew_emits_end_task_event(): @pytest.mark.vcr(filter_headers=["authorization"]) def test_task_emits_failed_event_on_execution_error(): received_events = [] + received_sources = [] @event_bus.on(TaskFailedEvent) def handle_task_failed(source, event): received_events.append(event) + received_sources.append(source) + + with patch.object(Task, "_execute_core",) as mock_execute: + error_message = "Simulated task failure" + mock_execute.side_effect = Exception(error_message) + agent = Agent( + role="base_agent", + goal="Just say hi", + backstory="You are a helpful assistant that just says hi", + ) + task = Task( + description="Just say hi", + expected_output="hi", + agent=agent, + ) + + with pytest.raises(Exception): + agent.execute_task(task=task) - task = Task( - description="Just say hi", - expected_output="hi", - agent=None, - ) - - with pytest.raises(Exception) as exc_info: - task._execute_core(agent=None, context=None, tools=None) - - assert "has no agent assigned" in str(exc_info.value) - - assert len(received_events) == 1 - assert received_events[0].task == task - assert "has no agent assigned" in received_events[0].error - assert isinstance(received_events[0].timestamp, datetime) - assert received_events[0].type == "task_failed" + assert len(received_events) == 1 + assert received_sources[0] == task + assert received_events[0].error == error_message + assert isinstance(received_events[0].timestamp, datetime) + assert received_events[0].type == "task_failed" @pytest.mark.vcr(filter_headers=["authorization"]) @@ -439,3 +449,23 @@ def test_multiple_handlers_for_same_event(): assert len(received_events_2) == 1 assert received_events_1[0].type == "crew_kickoff_started" assert received_events_2[0].type == "crew_kickoff_started" + + +def test_flow_emits_created_event(): + received_events = [] + + @event_bus.on(FlowCreatedEvent) + def handle_flow_created(source, event): + received_events.append(event) + + class TestFlow(Flow[dict]): + @start() + def begin(self): + return "started" + + flow = TestFlow() + flow.kickoff() + + assert len(received_events) == 1 + assert received_events[0].flow_name == "TestFlow" + assert received_events[0].type == "flow_created"