Compare commits

...

17 Commits

Author SHA1 Message Date
rajib
106b0df42e The suggestions were getting split at character level and not at sentence level (#436)
* fix the issue where the suggestions were split at character level

* Update contextual_memory.py

---------

Co-authored-by: rajib76 <rajib76@yahoo.com>
Co-authored-by: João Moura <joaomdmoura@gmail.com>
2024-04-07 02:57:23 -03:00
João Moura
c31ac4cf7e Updating tool dependency 2024-04-05 22:46:32 -03:00
João Moura
7b309df0c5 preparing new version 2024-04-05 19:52:13 -03:00
shivam singh
326f524e7c doc: Add documentation to Task model. (#363) 2024-04-05 19:49:36 -03:00
高璟琦
315ad20111 add solar example (#373)
Co-authored-by: João Moura <joaomdmoura@gmail.com>
2024-04-05 19:48:27 -03:00
Rueben Ramirez
b1daf17a61 whitespace consistency across docs (#407)
I saw a rendedered whitespace inconsistency in the Tasks docs here:
ed31860071/docs/core-concepts/Tasks.md (L173)

So I set out to patch that up to make it easier to read.  I then noticed
there were a few whitespace inconsistencies:
- 2 spaces
- 4 whitespaces
- tabs

It appears that the 4 whitespaces is the prevalent whitesapce usage, so
I overwrote other whitespace usages with that in this commit.

Co-authored-by: Rueben Ramirez <rramirez@ruebens-mbp.tail7c016.ts.net>
Co-authored-by: João Moura <joaomdmoura@gmail.com>
2024-04-05 19:47:09 -03:00
GabeKoga
9db99befb6 Feature: Log files (#423)
* log_file

feature: added a new parameter for crew that creates a txt file to log agent execution

* unit tests and documentation

unit test if file is created but not what is inside the file
2024-04-05 19:44:50 -03:00
GabeKoga
aebc443b62 purple (#428)
changed from yellow to purple for visibility
2024-04-05 18:25:59 -03:00
João Moura
2c0e5586e8 TYPO 2024-04-05 09:37:51 -03:00
João Moura
25f7557751 fixing memory docs 2024-04-05 08:59:54 -03:00
João Moura
59ebf7b762 adding specific memmory docs 2024-04-05 08:59:20 -03:00
João Moura
1abe9db8e0 Increasing default max inter 2024-04-05 08:36:09 -03:00
João Moura
e4363f9ed8 updating tests 2024-04-05 08:33:31 -03:00
João Moura
e00b545548 adding max execution time 2024-04-05 08:31:25 -03:00
João Moura
1aa32c2036 preparing new version 2024-04-05 08:24:41 -03:00
João Moura
65824ef814 not overriding llm callbacks 2024-04-05 08:24:20 -03:00
João Moura
d17bc33bfb fix docs 2024-04-04 17:36:50 -03:00
21 changed files with 357 additions and 93 deletions

View File

@@ -1,4 +1,3 @@
```markdown
---
title: crewAI Agents
description: What are crewAI Agents and how to use them.
@@ -25,8 +24,9 @@ description: What are crewAI Agents and how to use them.
| **LLM** *(optional)* | Represents the language model that will run the agent. It dynamically fetches the model name from the `OPENAI_MODEL_NAME` environment variable, defaulting to "gpt-4" if not specified. |
| **Tools** *(optional)* | Set of capabilities or functions that the agent can use to perform tasks. Expected to be instances of custom classes compatible with the agent's execution environment. Tools are initialized with a default value of an empty list. |
| **Function Calling LLM** *(optional)* | Specifies the language model that will handle the tool calling for this agent, overriding the crew function calling LLM if passed. Default is `None`. |
| **Max Iter** *(optional)* | The maximum number of iterations the agent can perform before being forced to give its best answer. Default is `15`. |
| **Max Iter** *(optional)* | The maximum number of iterations the agent can perform before being forced to give its best answer. Default is `25`. |
| **Max RPM** *(optional)* | The maximum number of requests per minute the agent can perform to avoid rate limits. It's optional and can be left unspecified, with a default value of `None`. |
| **max_execution_time** *(optional)* | Maximum execution time for an agent to execute a task It's optional and can be left unspecified, with a default value of `None`, menaning no max execution time |
| **Verbose** *(optional)* | Setting this to `True` configures the internal logger to provide detailed execution logs, aiding in debugging and monitoring. Default is `False`. |
| **Allow Delegation** *(optional)* | Agents can delegate tasks or questions to one another, ensuring that each task is handled by the most suitable agent. Default is `True`. |
| **Step Callback** *(optional)* | A function that is called after each step of the agent. This can be used to log the agent's actions or to perform other operations. It will overwrite the crew `step_callback`. |
@@ -64,5 +64,4 @@ agent = Agent(
```
## Conclusion
Agents are the building blocks of the CrewAI framework. By understanding how to define and interact with agents, you can create sophisticated AI systems that leverage the power of collaborative intelligence.
```
Agents are the building blocks of the CrewAI framework. By understanding how to define and interact with agents, you can create sophisticated AI systems that leverage the power of collaborative intelligence.

View File

@@ -27,6 +27,8 @@ A crew in crewAI represents a collaborative group of agents working together to
| **Step Callback** *(optional)* | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations; it won't override the agent-specific `step_callback`. |
| **Task Callback** *(optional)* | A function that is called after the completion of each task. Useful for monitoring or additional operations post-task execution. |
| **Share Crew** *(optional)* | Whether you want to share the complete crew information and execution with the crewAI team to make the library better, and allow us to train models. |
| **Output Log File** *(optional)* | Whether you want to have a file with the complete crew output and execution. You can set it using True and it will default to the folder you are currently and it will be called logs.txt or passing a string with the full path and name of the file. |
!!! note "Crew Max RPM"
The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.

View File

@@ -1,4 +1,3 @@
```markdown
---
title: crewAI Memory Systems
description: Leveraging memory systems in the crewAI framework to enhance agent capabilities.

View File

@@ -96,26 +96,26 @@ This is useful when you have a task that depends on the output of another task t
# ...
research_ai_task = Task(
description='Find and summarize the latest AI news',
expected_output='A bullet list summary of the top 5 most important AI news',
async_execution=True,
agent=research_agent,
tools=[search_tool]
description='Find and summarize the latest AI news',
expected_output='A bullet list summary of the top 5 most important AI news',
async_execution=True,
agent=research_agent,
tools=[search_tool]
)
research_ops_task = Task(
description='Find and summarize the latest AI Ops news',
expected_output='A bullet list summary of the top 5 most important AI Ops news',
async_execution=True,
agent=research_agent,
tools=[search_tool]
description='Find and summarize the latest AI Ops news',
expected_output='A bullet list summary of the top 5 most important AI Ops news',
async_execution=True,
agent=research_agent,
tools=[search_tool]
)
write_blog_task = Task(
description="Write a full blog post about the importance of AI and its latest news",
expected_output='Full blog post that is 4 paragraphs long',
agent=writer_agent,
context=[research_ai_task, research_ops_task]
description="Write a full blog post about the importance of AI and its latest news",
expected_output='Full blog post that is 4 paragraphs long',
agent=writer_agent,
context=[research_ai_task, research_ops_task]
)
#...
@@ -131,24 +131,24 @@ You can then use the `context` attribute to define in a future task that it shou
#...
list_ideas = Task(
description="List of 5 interesting ideas to explore for an article about AI.",
expected_output="Bullet point list of 5 ideas for an article.",
agent=researcher,
async_execution=True # Will be executed asynchronously
description="List of 5 interesting ideas to explore for an article about AI.",
expected_output="Bullet point list of 5 ideas for an article.",
agent=researcher,
async_execution=True # Will be executed asynchronously
)
list_important_history = Task(
description="Research the history of AI and give me the 5 most important events.",
expected_output="Bullet point list of 5 important events.",
agent=researcher,
async_execution=True # Will be executed asynchronously
description="Research the history of AI and give me the 5 most important events.",
expected_output="Bullet point list of 5 important events.",
agent=researcher,
async_execution=True # Will be executed asynchronously
)
write_article = Task(
description="Write an article about AI, its history, and interesting ideas.",
expected_output="A 4 paragraph article about AI.",
agent=writer,
context=[list_ideas, list_important_history] # Will wait for the output of the two tasks to be completed
description="Write an article about AI, its history, and interesting ideas.",
expected_output="A 4 paragraph article about AI.",
agent=writer,
context=[list_ideas, list_important_history] # Will wait for the output of the two tasks to be completed
)
#...
@@ -162,20 +162,20 @@ The callback function is executed after the task is completed, allowing for acti
# ...
def callback_function(output: TaskOutput):
# Do something after the task is completed
# Example: Send an email to the manager
print(f"""
Task completed!
Task: {output.description}
Output: {output.raw_output}
""")
# Do something after the task is completed
# Example: Send an email to the manager
print(f"""
Task completed!
Task: {output.description}
Output: {output.raw_output}
""")
research_task = Task(
description='Find and summarize the latest AI news',
expected_output='A bullet list summary of the top 5 most important AI news',
agent=research_agent,
tools=[search_tool],
callback=callback_function
description='Find and summarize the latest AI news',
expected_output='A bullet list summary of the top 5 most important AI news',
agent=research_agent,
tools=[search_tool],
callback=callback_function
)
#...
@@ -188,27 +188,27 @@ Once a crew finishes running, you can access the output of a specific task by us
```python
# ...
task1 = Task(
description='Find and summarize the latest AI news',
expected_output='A bullet list summary of the top 5 most important AI news',
agent=research_agent,
tools=[search_tool]
description='Find and summarize the latest AI news',
expected_output='A bullet list summary of the top 5 most important AI news',
agent=research_agent,
tools=[search_tool]
)
#...
crew = Crew(
agents=[research_agent],
tasks=[task1, task2, task3],
verbose=2
agents=[research_agent],
tasks=[task1, task2, task3],
verbose=2
)
result = crew.kickoff()
# Returns a TaskOutput object with the description and results of the task
print(f"""
Task completed!
Task: {task1.output.description}
Output: {task1.output.raw_output}
Task completed!
Task: {task1.output.description}
Output: {task1.output.raw_output}
""")
```

View File

@@ -110,6 +110,16 @@ OPENAI_API_BASE=https://api.mistral.ai/v1
OPENAI_MODEL_NAME="mistral-small"
```
### Solar
```sh
from langchain_community.chat_models.solar import SolarChat
# Initialize language model
os.environ["SOLAR_API_KEY"] = "your-solar-api-key"
llm = SolarChat(max_tokens=1024)
Free developer API key available here: https://console.upstage.ai/services/solar
Langchain Example: https://github.com/langchain-ai/langchain/pull/18556
```
### text-gen-web-ui
```sh
OPENAI_API_BASE=http://localhost:5000/v1
@@ -128,9 +138,9 @@ Free developer API key available here: https://cohere.com/
Langchain Documentation: https://python.langchain.com/docs/integrations/chat/cohere
```
### Azure Open AI
Azure's OpenAI API needs a distinct setup, utilizing the `langchain_openai` component for Azure-specific configurations.
### Azure Open AI Configuration
For Azure OpenAI API integration, set the following environment variables:
```sh
AZURE_OPENAI_VERSION="2022-12-01"
AZURE_OPENAI_DEPLOYMENT=""

View File

@@ -33,6 +33,11 @@ Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By
Crews
</a>
</li>
<li>
<a href="./core-concepts/Memory">
Memory
</a>
</li>
</ul>
</div>
<div style="width:30%">

View File

@@ -22,15 +22,15 @@ from crewai_tools import GithubSearchTool
# Initialize the tool for semantic searches within a specific GitHub repository
tool = GithubSearchTool(
github_repo='https://github.com/example/repo',
content_types=['code', 'issue'] # Options: code, repo, pr, issue
github_repo='https://github.com/example/repo',
content_types=['code', 'issue'] # Options: code, repo, pr, issue
)
# OR
# Initialize the tool for semantic searches within a specific GitHub repository, so the agent can search any repository if it learns about during its execution
tool = GithubSearchTool(
content_types=['code', 'issue'] # Options: code, repo, pr, issue
content_types=['code', 'issue'] # Options: code, repo, pr, issue
)
```

View File

@@ -126,6 +126,7 @@ nav:
- Processes: 'core-concepts/Processes.md'
- Crews: 'core-concepts/Crews.md'
- Collaboration: 'core-concepts/Collaboration.md'
- Memory: 'core-concepts/Memory.md'
- How to Guides:
- Getting Started: 'how-to/Creating-a-Crew-and-kick-it-off.md'
- Create Custom Tools: 'how-to/Create-Custom-Tools.md'

8
poetry.lock generated
View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
[[package]]
name = "aiohttp"
@@ -4962,13 +4962,13 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.
[[package]]
name = "typing-extensions"
version = "4.10.0"
version = "4.11.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"},
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
{file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"},
{file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"},
]
[[package]]

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "crewai"
version = "0.27.0"
version = "0.28.1"
description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks."
authors = ["Joao Moura <joao@crewai.com>"]
readme = "README.md"
@@ -23,7 +23,7 @@ opentelemetry-sdk = "^1.22.0"
opentelemetry-exporter-otlp-proto-http = "^1.22.0"
instructor = "^0.5.2"
regex = "^2023.12.25"
crewai-tools = { version = "^0.1.4", optional = true }
crewai-tools = { version = "^0.1.5", optional = true }
click = "^8.1.7"
python-dotenv = "1.0.0"
embedchain = "^0.1.98"
@@ -44,7 +44,7 @@ mkdocs-material = {extras = ["imaging"], version = "^9.5.7"}
mkdocs-material-extensions = "^1.3.1"
pillow = "^10.2.0"
cairosvg = "^2.7.1"
crewai_tools = "^0.1.4"
crewai-tools = "^0.1.5"
[tool.isort]
profile = "black"

View File

@@ -88,7 +88,11 @@ class Agent(BaseModel):
default_factory=list, description="Tools at agents disposal"
)
max_iter: Optional[int] = Field(
default=15, description="Maximum iterations for an agent to execute a task"
default=25, description="Maximum iterations for an agent to execute a task"
)
max_execution_time: Optional[int] = Field(
default=None,
description="Maximum execution time for an agent to execute a task",
)
agent_executor: InstanceOf[CrewAgentExecutor] = Field(
default=None, description="An instance of the CrewAgentExecutor class."
@@ -156,9 +160,12 @@ class Agent(BaseModel):
def set_agent_executor(self) -> "Agent":
"""set agent executor is set."""
if hasattr(self.llm, "model_name"):
self.llm.callbacks = [
TokenCalcHandler(self.llm.model_name, self._token_process)
]
token_handler = TokenCalcHandler(self.llm.model_name, self._token_process)
if isinstance(self.llm.callbacks, list):
self.llm.callbacks.append(token_handler)
else:
self.llm.callbacks = [token_handler]
if not self.agent_executor:
if not self.cache_handler:
self.cache_handler = CacheHandler()
@@ -273,6 +280,7 @@ class Agent(BaseModel):
"original_tools": tools,
"handle_parsing_errors": True,
"max_iterations": self.max_iter,
"max_execution_time": self.max_execution_time,
"step_callback": self.step_callback,
"tools_handler": self.tools_handler,
"function_calling_llm": self.function_calling_llm,

View File

@@ -23,7 +23,7 @@ poetry install
```
### Customizing
**Add you `OPENAI_API_KEY` on the `.env` file**
**Add your `OPENAI_API_KEY` into the `.env` file**
- Modify `src/{{folder_name}}/config/agents.yaml` to define your agents
- Modify `src/{{folder_name}}/config/tasks.yaml` to define your tasks

View File

@@ -25,7 +25,7 @@ from crewai.process import Process
from crewai.task import Task
from crewai.telemetry import Telemetry
from crewai.tools.agent_tools import AgentTools
from crewai.utilities import I18N, Logger, RPMController
from crewai.utilities import I18N, Logger, RPMController, FileHandler
class Crew(BaseModel):
@@ -55,6 +55,7 @@ class Crew(BaseModel):
_execution_span: Any = PrivateAttr()
_rpm_controller: RPMController = PrivateAttr()
_logger: Logger = PrivateAttr()
_file_handler: FileHandler = PrivateAttr()
_cache_handler: InstanceOf[CacheHandler] = PrivateAttr(default=CacheHandler())
_short_term_memory: Optional[InstanceOf[ShortTermMemory]] = PrivateAttr()
_long_term_memory: Optional[InstanceOf[LongTermMemory]] = PrivateAttr()
@@ -115,6 +116,10 @@ class Crew(BaseModel):
default=None,
description="Path to the language file to be used for the crew.",
)
output_log_file: Optional[Union[bool, str]] = Field(
default=False,
description="output_log_file",
)
@field_validator("id", mode="before")
@classmethod
@@ -145,6 +150,8 @@ class Crew(BaseModel):
"""Set private attributes."""
self._cache_handler = CacheHandler()
self._logger = Logger(self.verbose)
if self.output_log_file:
self._file_handler = FileHandler(self.output_log_file)
self._rpm_controller = RPMController(max_rpm=self.max_rpm, logger=self._logger)
self._telemetry = Telemetry()
self._telemetry.set_tracer()
@@ -273,11 +280,16 @@ class Crew(BaseModel):
task.tools += AgentTools(agents=agents_for_delegation).tools()
role = task.agent.role if task.agent is not None else "None"
self._logger.log("debug", f"== Working Agent: {role}", color="bold_yellow")
self._logger.log("debug", f"== Working Agent: {role}", color="bold_purple")
self._logger.log(
"info", f"== Starting Task: {task.description}", color="bold_yellow"
"info", f"== Starting Task: {task.description}", color="bold_purple"
)
if self.output_log_file:
self._file_handler.log(
agent=role, task=task.description, status="started"
)
output = task.execute(context=task_output)
if not task.async_execution:
task_output = output
@@ -285,6 +297,9 @@ class Crew(BaseModel):
role = task.agent.role if task.agent is not None else "None"
self._logger.log("debug", f"== [{role}] Task output: {task_output}\n\n")
if self.output_log_file:
self._file_handler.log(agent=role, task=task_output, status="completed")
self._finish_execution(task_output)
return self._format_output(task_output)
@@ -306,12 +321,22 @@ class Crew(BaseModel):
self._logger.log("debug", f"Working Agent: {manager.role}")
self._logger.log("info", f"Starting Task: {task.description}")
if self.output_log_file:
self._file_handler.log(
agent=manager.role, task=task.description, status="started"
)
task_output = task.execute(
agent=manager, context=task_output, tools=manager.tools
)
self._logger.log("debug", f"[{manager.role}] Task output: {task_output}")
if self.output_log_file:
self._file_handler.log(
agent=manager.role, task=task_output, status="completed"
)
self._finish_execution(task_output)
return self._format_output(task_output), manager._token_process.get_summary()

View File

@@ -43,7 +43,7 @@ class ContextualMemory:
formatted_results = "\n".join(
[f"{result['metadata']['suggestions']}" for result in ltm_results]
)
formatted_results = list(set(formatted_results))
formatted_results = list(set(formatted_results.split('\n')))
return f"Historical Data:\n{formatted_results}" if ltm_results else ""
def _fetch_entity_context(self, query) -> str:

View File

@@ -13,7 +13,23 @@ from crewai.utilities.pydantic_schema_parser import PydanticSchemaParser
class Task(BaseModel):
"""Class that represent a task to be executed."""
"""Class that represents a task to be executed.
Each task must have a description, an expected output and an agent responsible for execution.
Attributes:
agent: Agent responsible for task execution. Represents entity performing task.
async_execution: Boolean flag indicating asynchronous task execution.
callback: Function/object executed post task completion for additional actions.
config: Dictionary containing task-specific configuration parameters.
context: List of Task instances providing task context or input data.
description: Descriptive text detailing task's purpose and execution.
expected_output: Clear definition of expected task outcome.
output_file: File path for storing task output.
output_json: Pydantic model for structuring JSON output.
output_pydantic: Pydantic model for task output.
tools: List of tools/resources limited for task execution.
"""
class Config:
arbitrary_types_allowed = True

View File

@@ -101,7 +101,7 @@ class ToolUsage:
result = self._i18n.errors("task_repeated_usage").format(
tool_names=self.tools_names
)
self._printer.print(content=f"\n\n{result}\n", color="yellow")
self._printer.print(content=f"\n\n{result}\n", color="purple")
self._telemetry.tool_repeated_usage(
llm=self.function_calling_llm,
tool_name=tool.name,
@@ -178,7 +178,7 @@ class ToolUsage:
calling=calling, output=result, should_cache=should_cache
)
self._printer.print(content=f"\n\n{result}\n", color="yellow")
self._printer.print(content=f"\n\n{result}\n", color="purple")
self._telemetry.tool_usage(
llm=self.function_calling_llm,
tool_name=tool.name,

View File

@@ -5,3 +5,4 @@ from .logger import Logger
from .printer import Printer
from .prompts import Prompts
from .rpm_controller import RPMController
from .fileHandler import FileHandler

View File

@@ -0,0 +1,20 @@
import os
from datetime import datetime
class FileHandler:
"""take care of file operations, currently it only logs messages to a file"""
def __init__(self, file_path):
if isinstance(file_path, bool):
self._path = os.path.join(os.curdir, "logs.txt")
elif isinstance(file_path, str):
self._path = file_path
else:
raise ValueError("file_path must be either a boolean or a string.")
def log(self, **kwargs):
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
message = f"{now}: ".join([f"{key}={value}" for key, value in kwargs.items()])
with open(self._path, "a") as file:
file.write(message + "\n")

View File

@@ -1,24 +1,24 @@
class Printer:
def print(self, content: str, color: str):
if color == "yellow":
self._print_yellow(content)
if color == "purple":
self._print_purple(content)
elif color == "red":
self._print_red(content)
elif color == "bold_green":
self._print_bold_green(content)
elif color == "bold_yellow":
self._print_bold_yellow(content)
elif color == "bold_purple":
self._print_bold_purple(content)
else:
print(content)
def _print_bold_yellow(self, content):
print("\033[1m\033[93m {}\033[00m".format(content))
def _print_bold_purple(self, content):
print("\033[1m\033[95m {}\033[00m".format(content))
def _print_bold_green(self, content):
print("\033[1m\033[92m {}\033[00m".format(content))
def _print_yellow(self, content):
print("\033[93m {}\033[00m".format(content))
def _print_purple(self, content):
print("\033[95m {}\033[00m".format(content))
def _print_red(self, content):
print("\033[91m {}\033[00m".format(content))

View File

@@ -0,0 +1,160 @@
interactions:
- request:
body: '{"messages": [{"role": "user", "content": "You are Researcher. You''re
an expert researcher, specialized in technology, software engineering, AI and
startups. You work as a freelancer and is now working on doing research and
analysis for a new customer.\nYour personal goal is: Make the best research
and analysis on content about AI and AI agentsTo give my best complete final
answer to the task use the exact following format:\n\nThought: I now can give
a great answer\nFinal Answer: my best complete final answer to the task.\nYour
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!\nCurrent
Task: Say Hi\n\nThis is the expect criteria for your final answer: The word:
Hi \n you 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: \n"}], "model":
"gpt-4", "n": 1, "stop": ["\nObservation"], "stream": true, "temperature": 0.7}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate, br
connection:
- keep-alive
content-length:
- '1082'
content-type:
- application/json
cookie:
- _cfuvid=zVKnitRNLhrt8b2P3MHGfXS_82YiqkGpi46seIwshAM-1709396719694-0.0.1.1-604800000
host:
- api.openai.com
user-agent:
- OpenAI/Python 1.16.2
x-stainless-arch:
- other:amd64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- Windows
x-stainless-package-version:
- 1.16.2
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.10.10
method: POST
uri: https://api.openai.com/v1/chat/completions
response:
body:
string: 'data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"I"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
now"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
can"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
give"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
a"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
great"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
answer"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"\n\n"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"Final"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
Answer"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
Hi"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9AjeorqO0QfP8DJ8NwGIUKSlhQqav","object":"chat.completion.chunk","created":1712345814,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]}
data: [DONE]
'
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 86fbfd5e4e45012b-GRU
Cache-Control:
- no-cache, must-revalidate
Connection:
- keep-alive
Content-Type:
- text/event-stream
Date:
- Fri, 05 Apr 2024 19:36:55 GMT
Server:
- cloudflare
Set-Cookie:
- __cf_bm=Dup92ckJhbI_FxZty6XIjohW.sTaChSMX.8lwju_iA8-1712345815-1.0.1.1-DYCBIKozKcyEYWv.mE5gRee5frdxJU8EBOeZrex7BOH_U4HLjPJ4IMUP0m_YMiO3fKf5IClhW3KIzE8cl2C.ww;
path=/; expires=Fri, 05-Apr-24 20:06:55 GMT; domain=.api.openai.com; HttpOnly;
Secure; SameSite=None
- _cfuvid=.Ctsps4oQpopvSdn2mneN2jnLB0vatjzGjPz1HgR734-1712345815450-0.0.1.1-604800000;
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400
openai-model:
- gpt-4-0613
openai-organization:
- crewai-iuxna1
openai-processing-ms:
- '363'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '10000'
x-ratelimit-limit-tokens:
- '300000'
x-ratelimit-remaining-requests:
- '9999'
x-ratelimit-remaining-tokens:
- '299750'
x-ratelimit-reset-requests:
- 6ms
x-ratelimit-reset-tokens:
- 50ms
x-request-id:
- req_83d3bc5e55b3d012f700b51707cc46e0
status:
code: 200
message: OK
version: 1

View File

@@ -648,10 +648,10 @@ def test_agent_usage_metrics_are_captured_for_sequential_process():
result = crew.kickoff()
assert result == "Howdy!"
assert crew.usage_metrics == {
"completion_tokens": 17,
"prompt_tokens": 161,
"successful_requests": 1,
"total_tokens": 178,
"completion_tokens": 51,
"prompt_tokens": 483,
"successful_requests": 3,
"total_tokens": 534,
}
@@ -678,10 +678,10 @@ def test_agent_usage_metrics_are_captured_for_hierarchical_process():
result = crew.kickoff()
assert result == '"Howdy!"'
assert crew.usage_metrics == {
"total_tokens": 1641,
"prompt_tokens": 1358,
"completion_tokens": 283,
"successful_requests": 3,
"total_tokens": 2592,
"prompt_tokens": 2048,
"completion_tokens": 544,
"successful_requests": 6,
}
@@ -894,3 +894,21 @@ def test_disabled_memory_using_contextual_memory():
with patch.object(ContextualMemory, "build_context_for_task") as contextual_mem:
crew.kickoff()
contextual_mem.assert_not_called()
@pytest.mark.vcr(filter_headers=["authorization"])
def test_crew_log_file_output(tmp_path):
test_file = tmp_path / "logs.txt"
tasks = [
Task(
description="Say Hi",
expected_output="The word: Hi",
agent=researcher,
)
]
test_message = {"agent": "Researcher", "task": "Say Hi"}
crew = Crew(agents=[researcher], tasks=tasks, output_log_file=str(test_file))
crew.kickoff()
assert test_file.exists()