mirror of
https://github.com/crewAIInc/crewAI.git
synced 2025-12-30 11:18:31 +00:00
Compare commits
115 Commits
v0.27.0
...
test/githu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
835f0065f1 | ||
|
|
5865a2b899 | ||
|
|
9629337f17 | ||
|
|
2186f5c968 | ||
|
|
d34c2a2672 | ||
|
|
2520f389f2 | ||
|
|
a958b31768 | ||
|
|
5de494c99b | ||
|
|
208c3a780c | ||
|
|
1e112fa50a | ||
|
|
38fc5510ed | ||
|
|
1a1f4717aa | ||
|
|
977c6114ba | ||
|
|
27fddae286 | ||
|
|
615ac7f297 | ||
|
|
87d28e896d | ||
|
|
23f10418d7 | ||
|
|
27e7f48a44 | ||
|
|
7fd8850ddb | ||
|
|
7a4d3dd496 | ||
|
|
c1d7936689 | ||
|
|
1ec4da6947 | ||
|
|
8430c2f9af | ||
|
|
7cc6bccdec | ||
|
|
aeba64feaf | ||
|
|
04b4191de5 | ||
|
|
1da7473f26 | ||
|
|
95d13bd033 | ||
|
|
7eb4fcdaf4 | ||
|
|
809b4b227c | ||
|
|
ff51a2da9b | ||
|
|
be83681665 | ||
|
|
2bd30af72b | ||
|
|
d7b021061b | ||
|
|
73647f1669 | ||
|
|
d341cb3d5c | ||
|
|
30438410d6 | ||
|
|
b264ebabc0 | ||
|
|
2edc88e0a1 | ||
|
|
552dda46f8 | ||
|
|
2340a127d6 | ||
|
|
ecde504a79 | ||
|
|
0b781065d2 | ||
|
|
bcb57ce5f9 | ||
|
|
6392a8cdd0 | ||
|
|
34e3dd24b4 | ||
|
|
c303d3730c | ||
|
|
0a53ce17a2 | ||
|
|
7973651e05 | ||
|
|
672b150972 | ||
|
|
d8bcbd7d0a | ||
|
|
ff2f1477bb | ||
|
|
1139073297 | ||
|
|
39deac2747 | ||
|
|
0a35868367 | ||
|
|
608f869789 | ||
|
|
c30bd1a18e | ||
|
|
20a81af95f | ||
|
|
531c70b476 | ||
|
|
dae0aedc99 | ||
|
|
5fde03f4b0 | ||
|
|
48f53b529b | ||
|
|
4d9b0c6138 | ||
|
|
70cabec876 | ||
|
|
60423376cf | ||
|
|
22c646294a | ||
|
|
10b317cf34 | ||
|
|
03f0c44cac | ||
|
|
caa0e5db8d | ||
|
|
b862e464f8 | ||
|
|
3d5257592b | ||
|
|
ff76715cd2 | ||
|
|
cdb0a9c953 | ||
|
|
b0acae81b0 | ||
|
|
afc616d263 | ||
|
|
e066b4dcb1 | ||
|
|
9ea495902e | ||
|
|
d786c367b4 | ||
|
|
a391004432 | ||
|
|
dd97a2674d | ||
|
|
437c4c91bc | ||
|
|
575f1f98b0 | ||
|
|
2ee6ab6332 | ||
|
|
3d862538d2 | ||
|
|
4bd36e0460 | ||
|
|
7fbf0f1988 | ||
|
|
066127013b | ||
|
|
f675208d72 | ||
|
|
36aa69cf66 | ||
|
|
66b77ffd08 | ||
|
|
d2a3e4869a | ||
|
|
a2dc7c7f31 | ||
|
|
55ac69776a | ||
|
|
7a7c9b0076 | ||
|
|
77d40230a8 | ||
|
|
e4556040a8 | ||
|
|
755b3934a4 | ||
|
|
2d77fb72a5 | ||
|
|
106b0df42e | ||
|
|
c31ac4cf7e | ||
|
|
7b309df0c5 | ||
|
|
326f524e7c | ||
|
|
315ad20111 | ||
|
|
b1daf17a61 | ||
|
|
9db99befb6 | ||
|
|
aebc443b62 | ||
|
|
2c0e5586e8 | ||
|
|
25f7557751 | ||
|
|
59ebf7b762 | ||
|
|
1abe9db8e0 | ||
|
|
e4363f9ed8 | ||
|
|
e00b545548 | ||
|
|
1aa32c2036 | ||
|
|
65824ef814 | ||
|
|
d17bc33bfb |
10
.github/workflows/black.yml
vendored
10
.github/workflows/black.yml
vendored
@@ -1,10 +0,0 @@
|
||||
name: Lint
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: psf/black@stable
|
||||
16
.github/workflows/linter.yml
vendored
Normal file
16
.github/workflows/linter.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: Lint
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Requirements
|
||||
run: |
|
||||
pip install ruff
|
||||
|
||||
- name: Run Ruff Linter
|
||||
run: ruff check --exclude "templates","__init__.py"
|
||||
9
.github/workflows/tests.yml
vendored
9
.github/workflows/tests.yml
vendored
@@ -14,19 +14,18 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install Requirements
|
||||
run: |
|
||||
sudo apt-get update &&
|
||||
pip install poetry &&
|
||||
pip install poetry
|
||||
poetry lock &&
|
||||
poetry install
|
||||
|
||||
- name: Run tests
|
||||
run: poetry run pytest
|
||||
run: poetry run pytest tests
|
||||
|
||||
12
.github/workflows/type-checker.yml
vendored
12
.github/workflows/type-checker.yml
vendored
@@ -1,4 +1,3 @@
|
||||
|
||||
name: Run Type Checks
|
||||
|
||||
on: [pull_request]
|
||||
@@ -12,19 +11,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install Requirements
|
||||
run: |
|
||||
sudo apt-get update &&
|
||||
pip install poetry &&
|
||||
poetry lock &&
|
||||
poetry install
|
||||
pip install mypy
|
||||
|
||||
- name: Run type checks
|
||||
run: poetry run pyright
|
||||
run: mypy src
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -8,4 +8,7 @@ assets/*
|
||||
test/
|
||||
docs_crew/
|
||||
chroma.sqlite3
|
||||
old_en.json
|
||||
old_en.json
|
||||
db/
|
||||
test.py
|
||||
rc-tests/*
|
||||
@@ -1,21 +1,9 @@
|
||||
repos:
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.12.1
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.4.4
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python3.11
|
||||
files: \.(py)$
|
||||
exclude: 'src/crewai/cli/templates/(crew|main)\.py'
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
args: ["--profile", "black", "--filter-files"]
|
||||
|
||||
- repo: https://github.com/PyCQA/autoflake
|
||||
rev: v2.2.1
|
||||
hooks:
|
||||
- id: autoflake
|
||||
args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variables', '--ignore-init-module-imports']
|
||||
- id: ruff
|
||||
args: ["--fix"]
|
||||
exclude: "templates"
|
||||
- id: ruff-format
|
||||
exclude: "templates"
|
||||
|
||||
13
README.md
13
README.md
@@ -30,7 +30,6 @@
|
||||
- [Connecting Your Crew to a Model](#connecting-your-crew-to-a-model)
|
||||
- [How CrewAI Compares](#how-crewai-compares)
|
||||
- [Contribution](#contribution)
|
||||
- [Hire CrewAI](#hire-crewai)
|
||||
- [Telemetry](#telemetry)
|
||||
- [License](#license)
|
||||
|
||||
@@ -49,7 +48,7 @@ To get started with CrewAI, follow these simple steps:
|
||||
pip install crewai
|
||||
```
|
||||
|
||||
If you want to also install crewai-tools, which is a package with tools that can be used by the agents, but more dependencies, you can install it with, example below uses it:
|
||||
If you want to install the 'crewai' package along with its optional features that include additional tools for agents, you can do so by using the following command: pip install 'crewai[tools]'. This command installs the basic package and also adds extra components which require more dependencies to function."
|
||||
|
||||
```shell
|
||||
pip install 'crewai[tools]'
|
||||
@@ -83,7 +82,7 @@ researcher = Agent(
|
||||
verbose=True,
|
||||
allow_delegation=False,
|
||||
tools=[search_tool]
|
||||
# You can pass an optional llm attribute specifying what mode you wanna use.
|
||||
# You can pass an optional llm attribute specifying what model you wanna use.
|
||||
# It can be a local model through Ollama / LM Studio or a remote
|
||||
# model like OpenAI, Mistral, Antrophic or others (https://docs.crewai.com/how-to/LLM-Connections/)
|
||||
#
|
||||
@@ -232,7 +231,7 @@ poetry run pytest
|
||||
### Running static type checks
|
||||
|
||||
```bash
|
||||
poetry run pyright
|
||||
poetry run mypy
|
||||
```
|
||||
|
||||
### Packaging
|
||||
@@ -247,11 +246,6 @@ poetry build
|
||||
pip install dist/*.tar.gz
|
||||
```
|
||||
|
||||
## Hire CrewAI
|
||||
|
||||
We're a company developing crewAI and crewAI Enterprise, we for a limited time are offer consulting with selected customers, to get them early access to our enterprise solution
|
||||
If you are interested on having access to it and hiring weekly hours with our team, feel free to email us at [joao@crewai.com](mailto:joao@crewai.com).
|
||||
|
||||
## Telemetry
|
||||
|
||||
CrewAI uses anonymous telemetry to collect usage data with the main purpose of helping us improve the library by focusing our efforts on the most used features, integrations and tools.
|
||||
@@ -259,6 +253,7 @@ CrewAI uses anonymous telemetry to collect usage data with the main purpose of h
|
||||
There is NO data being collected on the prompts, tasks descriptions agents backstories or goals nor tools usage, no API calls, nor responses nor any data that is being processed by the agents, nor any secrets and env vars.
|
||||
|
||||
Data collected includes:
|
||||
|
||||
- Version of crewAI
|
||||
- So we can understand how many users are using the latest version
|
||||
- Version of Python
|
||||
|
||||
@@ -1463,11 +1463,11 @@
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 3,
|
||||
"text": "Agents have the inert ability of\nreach out to another to delegate\nwork or ask questions.",
|
||||
"text": "Agents have the innate ability of\nreach out to another to delegate\nwork or ask questions.",
|
||||
"textAlign": "right",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Agents have the inert ability of\nreach out to another to delegate\nwork or ask questions.",
|
||||
"originalText": "Agents have the innate ability of\nreach out to another to delegate\nwork or ask questions.",
|
||||
"lineHeight": 1.2,
|
||||
"baseline": 68
|
||||
},
|
||||
@@ -1734,4 +1734,4 @@
|
||||
"viewBackgroundColor": "#ffffff"
|
||||
},
|
||||
"files": {}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 288 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 419 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 263 KiB |
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
```markdown
|
||||
---
|
||||
title: crewAI Memory Systems
|
||||
description: Leveraging memory systems in the crewAI framework to enhance agent capabilities.
|
||||
|
||||
@@ -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}
|
||||
""")
|
||||
```
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ Here is a list of the available tools and their descriptions:
|
||||
| **DirectoryReadTool** | Facilitates reading and processing of directory structures and their contents. |
|
||||
| **FileReadTool** | Enables reading and extracting data from files, supporting various file formats. |
|
||||
| **GithubSearchTool** | A RAG tool for searching within GitHub repositories, useful for code and documentation search.|
|
||||
| **SeperDevTool** | A specialized tool for development purposes, with specific functionalities under development. |
|
||||
| **SerperDevTool** | A specialized tool for development purposes, with specific functionalities under development. |
|
||||
| **TXTSearchTool** | A RAG tool focused on searching within text (.txt) files, suitable for unstructured data. |
|
||||
| **JSONSearchTool** | A RAG tool designed for searching within JSON files, catering to structured data handling. |
|
||||
| **MDXSearchTool** | A RAG tool tailored for searching within Markdown (MDX) files, useful for documentation. |
|
||||
@@ -221,4 +221,4 @@ agent = Agent(
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
Tools are pivotal in extending the capabilities of CrewAI agents, enabling them to undertake a broad spectrum of tasks and collaborate effectively. When building solutions with CrewAI, leverage both custom and existing tools to empower your agents and enhance the AI ecosystem. Consider utilizing error handling, caching mechanisms, and the flexibility of tool arguments to optimize your agents' performance and capabilities.
|
||||
Tools are pivotal in extending the capabilities of CrewAI agents, enabling them to undertake a broad spectrum of tasks and collaborate effectively. When building solutions with CrewAI, leverage both custom and existing tools to empower your agents and enhance the AI ecosystem. Consider utilizing error handling, caching mechanisms, and the flexibility of tool arguments to optimize your agents' performance and capabilities.
|
||||
|
||||
@@ -1,51 +1,52 @@
|
||||
---
|
||||
title: (AgentOps) Observability using AgentOps
|
||||
title: Agent Monitoring with AgentOps
|
||||
description: Understanding and logging your agent performance with AgentOps.
|
||||
---
|
||||
|
||||
# Intro
|
||||
Observability is a key aspect of developing and deploying conversational AI agents. It allows developers to understand how the agent is performing, how users are interacting with the agent, and how the agent is responding to user inputs.
|
||||
Observability is a key aspect of developing and deploying conversational AI agents. It allows developers to understand how their agents are performing, how their agents are interacting with users, and how their agents use external tools and APIs. AgentOps is a product independent of CrewAI that provides a comprehensive observability solution for agents.
|
||||
|
||||
AgentOps is a product, idependent of crewAI that provides a comprehensive observability solution for agents.
|
||||
|
||||
This notebook will provide an overview of AgentOps and how to use it with crewAI.
|
||||
|
||||
## AgentOps
|
||||
|
||||
[AgentOps](https://agentops.ai) provides session replays, metrics, and monitoring for agents.
|
||||
[AgentOps Repo](https://github.com/AgentOps-AI/agentops)
|
||||
[AgentOps](https://agentops.ai/?=crew) provides session replays, metrics, and monitoring for agents.
|
||||
|
||||
At a high level, AgentOps gives you the ability to monitor cost, token usage, latency, agent failures, session-wide statistics, and more. For more info, check out the [AgentOps Repo](https://github.com/AgentOps-AI/agentops).
|
||||
|
||||
### Overview
|
||||
AgentOps provides monotoring for agents in development and production. It provides a dashboard for monitoring agent performance, session replays, and custom reporting.
|
||||
AgentOps provides monitoring for agents in development and production. It provides a dashboard for tracking agent performance, session replays, and custom reporting.
|
||||
|
||||

|
||||
Additionally, AgentOps provides session drilldowns for viewing Crew agent interactions, LLM calls, and tool usage in real-time. This feature is useful for debugging and understanding how agents interact with users as well as other agents.
|
||||
|
||||
Additionally, AgentOps provides session drilldowns that allows users to view the agent's interactions with users in real-time. This feature is useful for debugging and understanding how the agent interacts with users.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
### Features
|
||||
- LLM Cost management and tracking
|
||||
- Replay Analytics
|
||||
- Recursive thought detection
|
||||
- Custom Reporting
|
||||
- Analytics Dashboard
|
||||
- Public Model Testing
|
||||
- Custom Tests
|
||||
- Time Travel Debugging
|
||||
- Compliance and Security
|
||||
- **LLM Cost Management and Tracking**: Track spend with foundation model providers
|
||||
- **Replay Analytics**: Watch step-by-step agent execution graphs
|
||||
- **Recursive Thought Detection**: Identify when agents fall into infinite loops
|
||||
- **Custom Reporting**: Create custom analytics on agent performance
|
||||
- **Analytics Dashboard**: Monitor high level statistics about agents in development and production
|
||||
- **Public Model Testing**: Test your agents against benchmarks and leaderboards
|
||||
- **Custom Tests**: Run your agents against domain specific tests
|
||||
- **Time Travel Debugging**: Restart your sessions from checkpoints
|
||||
- **Compliance and Security**: Create audit logs and detect potential threats such as profanity and PII leaks
|
||||
- **Prompt Injection Detection**: Identify potential code injection and secret leaks
|
||||
|
||||
### Using AgentOps
|
||||
|
||||
Create a user API key here: app.agentops.ai/account
|
||||
1. **Create an API Key:**
|
||||
Create a user API key here: [Create API Key](app.agentops.ai/account)
|
||||
|
||||
2. **Configure Your Environment:**
|
||||
Add your API key to your environment variables
|
||||
|
||||
```
|
||||
AGENTOPS_API_KEY=<YOUR_AGENTOPS_API_KEY>
|
||||
```
|
||||
|
||||
3. **Install AgentOps:**
|
||||
Install AgentOps with:
|
||||
```
|
||||
pip install crewai[agentops]
|
||||
@@ -62,11 +63,26 @@ import agentops
|
||||
agentops.init()
|
||||
```
|
||||
|
||||
This will initiate an AgentOps session as well as automatically track Crew agents. For further info on how to outfit more complex agentic systems, check out the [AgentOps documentation](https://docs.agentops.ai) or join the [Discord](https://discord.gg/j4f3KbeH).
|
||||
|
||||
### Crew + AgentOps Examples
|
||||
- [Job Posting](https://github.com/joaomdmoura/crewAI-examples/tree/main/job-posting)
|
||||
- [Markdown Validator](https://github.com/joaomdmoura/crewAI-examples/tree/main/markdown_validator)
|
||||
- [Instagram Post](https://github.com/joaomdmoura/crewAI-examples/tree/main/instagram_post)
|
||||
|
||||
|
||||
### Futher Information
|
||||
To implement more features and better observability, please see the [AgentOps Repo](https://github.com/AgentOps-AI/agentops)
|
||||
### Further Information
|
||||
|
||||
To get started, create an [AgentOps account](https://agentops.ai/?=crew).
|
||||
|
||||
For feature requests or bug reports, please reach out to the AgentOps team on the [AgentOps Repo](https://github.com/AgentOps-AI/agentops).
|
||||
|
||||
#### Extra links
|
||||
|
||||
<a href="https://twitter.com/agentopsai/">🐦 Twitter</a>
|
||||
<span> • </span>
|
||||
<a href="https://discord.gg/JHPt4C7r">📢 Discord</a>
|
||||
<span> • </span>
|
||||
<a href="https://app.agentops.ai/?=crew">🖇️ AgentOps Dashboard</a>
|
||||
<span> • </span>
|
||||
<a href="https://docs.agentops.ai/introduction">📙 Documentation</a>
|
||||
21
docs/how-to/Installing-CrewAI.md
Normal file
21
docs/how-to/Installing-CrewAI.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Installing crewAI
|
||||
description: A comprehensive guide to installing crewAI and its dependencies, including the latest updates and installation methods.
|
||||
---
|
||||
|
||||
# Installing crewAI
|
||||
|
||||
Welcome to crewAI! This guide will walk you through the installation process for crewAI and its dependencies. crewAI is a flexible and powerful AI framework that enables you to create and manage AI agents, tools, and tasks efficiently. Let's get started!
|
||||
|
||||
## Installation
|
||||
|
||||
To install crewAI, you need to have Python >=3.10 and <=3.13 installed on your system:
|
||||
|
||||
```shell
|
||||
# Install the mains crewAI package
|
||||
pip install crewai
|
||||
|
||||
# Install the main crewAI package and the tools package
|
||||
# that includes a series of helpful tools for your agents
|
||||
pip install 'crewai[tools]'
|
||||
```
|
||||
@@ -16,8 +16,8 @@ The `Agent` class is the cornerstone for implementing AI solutions in CrewAI. He
|
||||
- `role`: Defines the agent's role within the solution.
|
||||
- `goal`: Specifies the agent's objective.
|
||||
- `backstory`: Provides a background story to the agent.
|
||||
- `llm`: The language model that will run the agent. By default, it uses the GPT-4 model defined in the environment variable "OPENAI_MODEL_NAME".
|
||||
- `function_calling_llm`: The language model that will handle the tool calling for this agent, overriding the crew function_calling_llm. Optional.
|
||||
- `llm`: Indicates the Large Language Model the agent uses. By default, it uses the GPT-4 model defined in the environment variable "OPENAI_MODEL_NAME".
|
||||
- `function_calling_llm` *Optional*: Will turn the ReAct crewAI agent into a function calling agent.
|
||||
- `max_iter`: Maximum number of iterations for an agent to execute a task, default is 15.
|
||||
- `memory`: Enables the agent to retain information during and a across executions. Default is `False`.
|
||||
- `max_rpm`: Maximum number of requests per minute the agent's execution should respect. Optional.
|
||||
@@ -42,7 +42,7 @@ example_agent = Agent(
|
||||
```
|
||||
|
||||
## Ollama Integration
|
||||
Ollama is preferred for local LLM integration, offering customization and privacy benefits. To integrate Ollama with CrewAI, set the appropriate environment variables as shown below. Note: Detailed Ollama setup is beyond this document's scope, but general guidance is provided.
|
||||
Ollama is preferred for local LLM integration, offering customization and privacy benefits. To integrate Ollama with CrewAI, set the appropriate environment variables as shown below.
|
||||
|
||||
### Setting Up Ollama
|
||||
- **Environment Variables Configuration**: To integrate Ollama, set the following environment variables:
|
||||
@@ -52,6 +52,71 @@ OPENAI_MODEL_NAME='openhermes' # Adjust based on available model
|
||||
OPENAI_API_KEY=''
|
||||
```
|
||||
|
||||
## Ollama Integration (ex. for using Llama 2 locally)
|
||||
1. [Download Ollama](https://ollama.com/download).
|
||||
2. After setting up the Ollama, Pull the Llama2 by typing following lines into the terminal ```ollama pull llama2```.
|
||||
3. Create a ModelFile similar the one below in your project directory.
|
||||
```
|
||||
FROM llama2
|
||||
|
||||
# Set parameters
|
||||
|
||||
PARAMETER temperature 0.8
|
||||
PARAMETER stop Result
|
||||
|
||||
# Sets a custom system message to specify the behavior of the chat assistant
|
||||
|
||||
# Leaving it blank for now.
|
||||
|
||||
SYSTEM """"""
|
||||
```
|
||||
4. Create a script to get the base model, which in our case is llama2, and create a model on top of that with ModelFile above. PS: this will be ".sh" file.
|
||||
```
|
||||
#!/bin/zsh
|
||||
|
||||
# variables
|
||||
model_name="llama2"
|
||||
custom_model_name="crewai-llama2"
|
||||
|
||||
#get the base model
|
||||
ollama pull $model_name
|
||||
|
||||
#create the model file
|
||||
ollama create $custom_model_name -f ./Llama2ModelFile
|
||||
```
|
||||
5. Go into the directory where the script file and ModelFile is located and run the script.
|
||||
6. Enjoy your free Llama2 model that powered up by excellent agents from crewai.
|
||||
```
|
||||
from crewai import Agent, Task, Crew
|
||||
from langchain_openai import ChatOpenAI
|
||||
import os
|
||||
os.environ["OPENAI_API_KEY"] = "NA"
|
||||
|
||||
llm = ChatOpenAI(
|
||||
model = "crewai-llama2",
|
||||
base_url = "http://localhost:11434/v1")
|
||||
|
||||
general_agent = Agent(role = "Math Professor",
|
||||
goal = """Provide the solution to the students that are asking mathematical questions and give them the answer.""",
|
||||
backstory = """You are an excellent math professor that likes to solve math questions in a way that everyone can understand your solution""",
|
||||
allow_delegation = False,
|
||||
verbose = True,
|
||||
llm = llm)
|
||||
task = Task (description="""what is 3 + 5""",
|
||||
agent = general_agent,
|
||||
expected_output="A numerical answer.")
|
||||
|
||||
crew = Crew(
|
||||
agents=[general_agent],
|
||||
tasks=[task],
|
||||
verbose=2
|
||||
)
|
||||
|
||||
result = crew.kickoff()
|
||||
|
||||
print(result)
|
||||
```
|
||||
|
||||
## HuggingFace Integration
|
||||
There are a couple of different ways you can use HuggingFace to host your LLM.
|
||||
|
||||
@@ -97,10 +162,10 @@ OPENAI_API_KEY=NA
|
||||
```
|
||||
|
||||
#### LM Studio
|
||||
Launch [LM Studio](https://lmstudio.ai) and go to the Server tab. Then select a model from the dropdown menu then wait for it to load. Once it's loaded, click the green Start Server button and use the URL, port, and API key that's shown (you can modify them). Below is an example of the default settings as of LM Studio 0.2.19:
|
||||
```sh
|
||||
OPENAI_API_BASE="http://localhost:8000/v1"
|
||||
OPENAI_MODEL_NAME=NA
|
||||
OPENAI_API_KEY=NA
|
||||
OPENAI_API_BASE="http://localhost:1234/v1"
|
||||
OPENAI_API_KEY="lm-studio"
|
||||
```
|
||||
|
||||
#### Mistral API
|
||||
@@ -110,6 +175,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 +203,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=""
|
||||
|
||||
@@ -33,11 +33,21 @@ 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%">
|
||||
<h2>How-To Guides</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="./how-to/Installing-CrewAI">
|
||||
Installing crewAI
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./how-to/Creating-a-Crew-and-kick-it-off">
|
||||
Getting Started
|
||||
@@ -74,8 +84,8 @@ Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./how-to/AgentOps-Observability.md">
|
||||
Agent Observability using AgentOps
|
||||
<a href="./how-to/AgentOps-Observability">
|
||||
Agent Monitoring with AgentOps
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
29
docs/tools/BrowserbaseLoadTool.md
Normal file
29
docs/tools/BrowserbaseLoadTool.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# BrowserbaseLoadTool
|
||||
|
||||
## Description
|
||||
|
||||
[Browserbase](https://browserbase.com) is a serverless platform for running headless browsers, it offers advanced debugging, session recordings, stealth mode, integrated proxies and captcha solving.
|
||||
|
||||
## Installation
|
||||
|
||||
- Get an API key from [browserbase.com](https://browserbase.com) and set it in environment variables (`BROWSERBASE_API_KEY`).
|
||||
- Install the [Browserbase SDK](http://github.com/browserbase/python-sdk) along with `crewai[tools]` package:
|
||||
|
||||
```
|
||||
pip install browserbase 'crewai[tools]'
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Utilize the BrowserbaseLoadTool as follows to allow your agent to load websites:
|
||||
|
||||
```python
|
||||
from crewai_tools import BrowserbaseLoadTool
|
||||
|
||||
tool = BrowserbaseLoadTool()
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
- `api_key`: Optional. Specifies Browserbase API key. Defaults is the `BROWSERBASE_API_KEY` environment variable.
|
||||
- `text_content`: Optional. Load pages as readable text. Default is `False`.
|
||||
@@ -50,7 +50,7 @@ tool = CSVSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -41,7 +41,7 @@ Note: Substitute 'https://docs.example.com/reference' with your target documenta
|
||||
By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:
|
||||
|
||||
```python
|
||||
tool = YoutubeVideoSearchTool(
|
||||
tool = CodeDocsSearchTool(
|
||||
config=dict(
|
||||
llm=dict(
|
||||
provider="ollama", # or google, openai, anthropic, llama2, ...
|
||||
@@ -53,7 +53,7 @@ tool = YoutubeVideoSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -48,7 +48,7 @@ tool = DOCXSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -43,7 +43,7 @@ tool = DirectorySearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -55,7 +55,7 @@ tool = GithubSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -48,7 +48,7 @@ tool = JSONSearchTool(
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "google",
|
||||
"provider": "google", # or openai, ollama, ...
|
||||
"config": {
|
||||
"model": "models/embedding-001",
|
||||
"task_type": "retrieval_document",
|
||||
|
||||
@@ -49,7 +49,7 @@ tool = MDXSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -48,7 +48,7 @@ tool = PDFSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -19,7 +19,7 @@ pip install 'crewai[tools]'
|
||||
Below is a proposed example showcasing how to use the PGSearchTool for conducting a semantic search on a table within a PostgreSQL database:
|
||||
|
||||
```python
|
||||
rom crewai_tools import PGSearchTool
|
||||
from crewai_tools import PGSearchTool
|
||||
|
||||
# Initialize the tool with the database URI and the target table name
|
||||
tool = PGSearchTool(db_uri='postgresql://user:password@localhost:5432/mydatabase', table_name='employees')
|
||||
@@ -48,7 +48,7 @@ tool = PGSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
@@ -57,4 +57,4 @@ tool = PGSearchTool(
|
||||
),
|
||||
)
|
||||
)
|
||||
```
|
||||
```
|
||||
|
||||
@@ -50,7 +50,7 @@ tool = TXTSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -48,7 +48,7 @@ tool = WebsiteSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -17,7 +17,7 @@ pip install 'crewai[tools]'
|
||||
Here are two examples demonstrating how to use the XMLSearchTool. The first example shows searching within a specific XML file, while the second example illustrates initiating a search without predefining an XML path, providing flexibility in search scope.
|
||||
|
||||
```python
|
||||
from crewai_tools.tools.xml_search_tool import XMLSearchTool
|
||||
from crewai_tools import XMLSearchTool
|
||||
|
||||
# Allow agents to search within any XML file's content as it learns about their paths during execution
|
||||
tool = XMLSearchTool()
|
||||
@@ -48,7 +48,7 @@ tool = XMLSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -48,7 +48,7 @@ tool = YoutubeChannelSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -52,7 +52,7 @@ tool = YoutubeVideoSearchTool(
|
||||
),
|
||||
),
|
||||
embedder=dict(
|
||||
provider="google",
|
||||
provider="google", # or openai, ollama, ...
|
||||
config=dict(
|
||||
model="models/embedding-001",
|
||||
task_type="retrieval_document",
|
||||
|
||||
@@ -126,7 +126,9 @@ nav:
|
||||
- Processes: 'core-concepts/Processes.md'
|
||||
- Crews: 'core-concepts/Crews.md'
|
||||
- Collaboration: 'core-concepts/Collaboration.md'
|
||||
- Memory: 'core-concepts/Memory.md'
|
||||
- How to Guides:
|
||||
- Installing CrewAI: 'how-to/Installing-CrewAI.md'
|
||||
- Getting Started: 'how-to/Creating-a-Crew-and-kick-it-off.md'
|
||||
- Create Custom Tools: 'how-to/Create-Custom-Tools.md'
|
||||
- Using Sequential Process: 'how-to/Sequential.md'
|
||||
@@ -134,9 +136,10 @@ nav:
|
||||
- Connecting to any LLM: 'how-to/LLM-Connections.md'
|
||||
- Customizing Agents: 'how-to/Customizing-Agents.md'
|
||||
- Human Input on Execution: 'how-to/Human-Input-on-Execution.md'
|
||||
- Agent Observability using AgentOps: 'how-to/AgentOps-Observability.md'
|
||||
- Agent Monitoring with AgentOps: 'how-to/AgentOps-Observability.md'
|
||||
- Tools Docs:
|
||||
- Google Serper Search: 'tools/SerperDevTool.md'
|
||||
- Browserbase Web Loader: 'tools/BrowserbaseLoadTool.md'
|
||||
- Scrape Website: 'tools/ScrapeWebsiteTool.md'
|
||||
- Directory Read: 'tools/DirectoryReadTool.md'
|
||||
- File Read: 'tools/FileReadTool.md'
|
||||
|
||||
1693
poetry.lock
generated
1693
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,10 @@
|
||||
[tool.poetry]
|
||||
name = "crewai"
|
||||
version = "0.27.0"
|
||||
version = "0.30.11"
|
||||
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"
|
||||
packages = [
|
||||
{ include = "crewai", from = "src" },
|
||||
]
|
||||
packages = [{ include = "crewai", from = "src" }]
|
||||
|
||||
[tool.poetry.urls]
|
||||
Homepage = "https://crewai.com"
|
||||
@@ -23,9 +21,9 @@ 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.2.6", optional = true }
|
||||
click = "^8.1.7"
|
||||
python-dotenv = "1.0.0"
|
||||
python-dotenv = "^1.0.0"
|
||||
embedchain = "^0.1.98"
|
||||
appdirs = "^1.4.4"
|
||||
|
||||
@@ -34,22 +32,17 @@ tools = ["crewai-tools"]
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
isort = "^5.13.2"
|
||||
pyright = ">=1.1.350,<2.0.0"
|
||||
mypy = "1.10.0"
|
||||
autoflake = "^2.2.1"
|
||||
pre-commit = "^3.6.0"
|
||||
mkdocs = "^1.4.3"
|
||||
mkdocstrings = "^0.22.0"
|
||||
mkdocstrings-python = "^1.1.2"
|
||||
mkdocs-material = {extras = ["imaging"], version = "^9.5.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"
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
known_first_party = ["crewai"]
|
||||
|
||||
crewai-tools = "^0.2.6"
|
||||
|
||||
[tool.poetry.group.test.dependencies]
|
||||
pytest = "^8.0.0"
|
||||
@@ -59,6 +52,11 @@ python-dotenv = "1.0.0"
|
||||
[tool.poetry.scripts]
|
||||
crewai = "crewai.cli.cli:crewai"
|
||||
|
||||
[tool.mypy]
|
||||
ignore_missing_imports = true
|
||||
disable_error_code = 'import-untyped'
|
||||
exclude = ["cli/templates/main.py", "cli/templates/crew.py"]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
@@ -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."
|
||||
@@ -117,6 +121,15 @@ class Agent(BaseModel):
|
||||
callbacks: Optional[List[InstanceOf[BaseCallbackHandler]]] = Field(
|
||||
default=None, description="Callback to be executed"
|
||||
)
|
||||
system_template: Optional[str] = Field(
|
||||
default=None, description="System format for the agent."
|
||||
)
|
||||
prompt_template: Optional[str] = Field(
|
||||
default=None, description="Prompt format for the agent."
|
||||
)
|
||||
response_template: Optional[str] = Field(
|
||||
default=None, description="Response format for the agent."
|
||||
)
|
||||
|
||||
_original_role: str | None = None
|
||||
_original_goal: str | None = None
|
||||
@@ -156,9 +169,18 @@ 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)
|
||||
|
||||
# Ensure self.llm.callbacks is a list
|
||||
if not isinstance(self.llm.callbacks, list):
|
||||
self.llm.callbacks = []
|
||||
|
||||
# Check if an instance of TokenCalcHandler already exists in the list
|
||||
if not any(
|
||||
isinstance(handler, TokenCalcHandler) for handler in self.llm.callbacks
|
||||
):
|
||||
self.llm.callbacks.append(token_handler)
|
||||
|
||||
if not self.agent_executor:
|
||||
if not self.cache_handler:
|
||||
self.cache_handler = CacheHandler()
|
||||
@@ -182,7 +204,7 @@ class Agent(BaseModel):
|
||||
Output of the agent
|
||||
"""
|
||||
if self.tools_handler:
|
||||
self.tools_handler.last_used_tool = {}
|
||||
self.tools_handler.last_used_tool = {} # type: ignore # Incompatible types in assignment (expression has type "dict[Never, Never]", variable has type "ToolCalling")
|
||||
|
||||
task_prompt = task.prompt()
|
||||
|
||||
@@ -202,7 +224,7 @@ class Agent(BaseModel):
|
||||
task_prompt += self.i18n.slice("memory").format(memory=memory)
|
||||
|
||||
tools = tools or self.tools
|
||||
parsed_tools = self._parse_tools(tools)
|
||||
parsed_tools = self._parse_tools(tools) # type: ignore # Argument 1 to "_parse_tools" of "Agent" has incompatible type "list[Any] | None"; expected "list[Any]"
|
||||
|
||||
self.create_agent_executor(tools=tools)
|
||||
self.agent_executor.tools = parsed_tools
|
||||
@@ -273,6 +295,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,
|
||||
@@ -280,11 +303,17 @@ class Agent(BaseModel):
|
||||
}
|
||||
|
||||
if self._rpm_controller:
|
||||
executor_args[
|
||||
"request_within_rpm_limit"
|
||||
] = self._rpm_controller.check_or_wait
|
||||
executor_args["request_within_rpm_limit"] = (
|
||||
self._rpm_controller.check_or_wait
|
||||
)
|
||||
|
||||
prompt = Prompts(i18n=self.i18n, tools=tools).task_execution()
|
||||
prompt = Prompts(
|
||||
i18n=self.i18n,
|
||||
tools=tools,
|
||||
system_template=self.system_template,
|
||||
prompt_template=self.prompt_template,
|
||||
response_template=self.response_template,
|
||||
).task_execution()
|
||||
|
||||
execution_prompt = prompt.partial(
|
||||
goal=self.goal,
|
||||
@@ -292,7 +321,13 @@ class Agent(BaseModel):
|
||||
backstory=self.backstory,
|
||||
)
|
||||
|
||||
bind = self.llm.bind(stop=[self.i18n.slice("observation")])
|
||||
stop_words = [self.i18n.slice("observation")]
|
||||
if self.response_template:
|
||||
stop_words.append(
|
||||
self.response_template.split("{{ .Response }}")[1].strip()
|
||||
)
|
||||
|
||||
bind = self.llm.bind(stop=stop_words)
|
||||
inner_agent = agent_args | execution_prompt | bind | CrewAgentParser(agent=self)
|
||||
self.agent_executor = CrewAgentExecutor(
|
||||
agent=RunnableAgent(runnable=inner_agent), **executor_args
|
||||
@@ -329,7 +364,7 @@ class Agent(BaseModel):
|
||||
thoughts += f"\n{observation_prefix}{observation}\n{llm_prefix}"
|
||||
return thoughts
|
||||
|
||||
def _parse_tools(self, tools: List[Any]) -> List[LangChainTool]:
|
||||
def _parse_tools(self, tools: List[Any]) -> List[LangChainTool]: # type: ignore # Function "langchain_core.tools.tool" is not valid as a type
|
||||
"""Parse tools to be used for the task."""
|
||||
# tentatively try to import from crewai_tools import BaseTool as CrewAITool
|
||||
tools_list = []
|
||||
|
||||
@@ -35,11 +35,14 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
crew: Any = None
|
||||
function_calling_llm: Any = None
|
||||
request_within_rpm_limit: Any = None
|
||||
tools_handler: InstanceOf[ToolsHandler] = None
|
||||
tools_handler: Optional[InstanceOf[ToolsHandler]] = None
|
||||
max_iterations: Optional[int] = 15
|
||||
have_forced_answer: bool = False
|
||||
force_answer_max_iterations: Optional[int] = None
|
||||
step_callback: Optional[Any] = None
|
||||
system_template: Optional[str] = None
|
||||
prompt_template: Optional[str] = None
|
||||
response_template: Optional[str] = None
|
||||
|
||||
@root_validator()
|
||||
def set_force_answer_max_iterations(cls, values: Dict) -> Dict:
|
||||
@@ -81,9 +84,7 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
datetime=str(time.time()),
|
||||
expected_output=self.task.expected_output,
|
||||
metadata={
|
||||
"suggestions": "\n".join(
|
||||
[f"- {s}" for s in evaluation.suggestions]
|
||||
),
|
||||
"suggestions": evaluation.suggestions,
|
||||
"quality": evaluation.quality,
|
||||
},
|
||||
)
|
||||
@@ -115,6 +116,7 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
# Allowing human input given task setting
|
||||
if self.task.human_input:
|
||||
self.should_ask_for_human_input = True
|
||||
|
||||
# Let's start tracking the number of iterations and time elapsed
|
||||
self.iterations = 0
|
||||
time_elapsed = 0.0
|
||||
@@ -130,8 +132,10 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
intermediate_steps,
|
||||
run_manager=run_manager,
|
||||
)
|
||||
|
||||
if self.step_callback:
|
||||
self.step_callback(next_step_output)
|
||||
|
||||
if isinstance(next_step_output, AgentFinish):
|
||||
# Creating long term memory
|
||||
create_long_term_memory = threading.Thread(
|
||||
@@ -185,7 +189,7 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
intermediate_steps = self._prepare_intermediate_steps(intermediate_steps)
|
||||
|
||||
# Call the LLM to see what to do.
|
||||
output = self.agent.plan(
|
||||
output = self.agent.plan( # type: ignore # Incompatible types in assignment (expression has type "AgentAction | AgentFinish | list[AgentAction]", variable has type "AgentAction")
|
||||
intermediate_steps,
|
||||
callbacks=run_manager.get_child() if run_manager else None,
|
||||
**inputs,
|
||||
@@ -271,8 +275,8 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
run_manager.on_agent_action(agent_action, color="green")
|
||||
|
||||
tool_usage = ToolUsage(
|
||||
tools_handler=self.tools_handler,
|
||||
tools=self.tools,
|
||||
tools_handler=self.tools_handler, # type: ignore # Argument "tools_handler" to "ToolUsage" has incompatible type "ToolsHandler | None"; expected "ToolsHandler"
|
||||
tools=self.tools, # type: ignore # Argument "tools" to "ToolUsage" has incompatible type "Sequence[BaseTool]"; expected "list[BaseTool]"
|
||||
original_tools=self.original_tools,
|
||||
tools_description=self.tools_description,
|
||||
tools_names=self.tools_names,
|
||||
@@ -294,7 +298,6 @@ class CrewAgentExecutor(AgentExecutor):
|
||||
tool=tool_calling.tool_name,
|
||||
tools=", ".join([tool.name.casefold() for tool in self.tools]),
|
||||
)
|
||||
|
||||
yield AgentStep(action=agent_action, observation=observation)
|
||||
|
||||
def _ask_human_input(self, final_answer: dict) -> str:
|
||||
|
||||
@@ -52,7 +52,6 @@ class CrewAgentParser(ReActSingleInputOutputParser):
|
||||
action_input = action_match.group(2)
|
||||
tool_input = action_input.strip(" ")
|
||||
tool_input = tool_input.strip('"')
|
||||
|
||||
return AgentAction(action, tool_input, text)
|
||||
|
||||
elif includes_answer:
|
||||
|
||||
@@ -8,13 +8,13 @@ from .cache.cache_handler import CacheHandler
|
||||
class ToolsHandler:
|
||||
"""Callback handler for tool usage."""
|
||||
|
||||
last_used_tool: ToolCalling = {}
|
||||
cache: CacheHandler
|
||||
last_used_tool: ToolCalling = {} # type: ignore # BUG?: Incompatible types in assignment (expression has type "Dict[...]", variable has type "ToolCalling")
|
||||
cache: Optional[CacheHandler]
|
||||
|
||||
def __init__(self, cache: Optional[CacheHandler] = None):
|
||||
"""Initialize the callback handler."""
|
||||
self.cache = cache
|
||||
self.last_used_tool = {}
|
||||
self.last_used_tool = {} # type: ignore # BUG?: same as above
|
||||
|
||||
def on_tool_use(
|
||||
self,
|
||||
@@ -23,7 +23,7 @@ class ToolsHandler:
|
||||
should_cache: bool = True,
|
||||
) -> Any:
|
||||
"""Run when tool ends running."""
|
||||
self.last_used_tool = calling
|
||||
self.last_used_tool = calling # type: ignore # BUG?: Incompatible types in assignment (expression has type "Union[ToolCalling, InstructorToolCalling]", variable has type "ToolCalling")
|
||||
if self.cache and should_cache and calling.tool_name != CacheTools().name:
|
||||
self.cache.add(
|
||||
tool=calling.tool_name,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import click
|
||||
import pkg_resources
|
||||
|
||||
from .create_crew import create_crew
|
||||
from .train_crew import train_crew
|
||||
|
||||
|
||||
@click.group()
|
||||
@@ -15,5 +17,36 @@ def create(project_name):
|
||||
create_crew(project_name)
|
||||
|
||||
|
||||
@crewai.command()
|
||||
@click.option(
|
||||
"--tools", is_flag=True, help="Show the installed version of crewai tools"
|
||||
)
|
||||
def version(tools):
|
||||
"""Show the installed version of crewai."""
|
||||
crewai_version = pkg_resources.get_distribution("crewai").version
|
||||
click.echo(f"crewai version: {crewai_version}")
|
||||
|
||||
if tools:
|
||||
try:
|
||||
tools_version = pkg_resources.get_distribution("crewai-tools").version
|
||||
click.echo(f"crewai tools version: {tools_version}")
|
||||
except pkg_resources.DistributionNotFound:
|
||||
click.echo("crewai tools not installed")
|
||||
|
||||
|
||||
@crewai.command()
|
||||
@click.option(
|
||||
"-n",
|
||||
"--n_iterations",
|
||||
type=int,
|
||||
default=5,
|
||||
help="Number of iterations to train the crew",
|
||||
)
|
||||
def train(n_iterations: int):
|
||||
"""Train the crew."""
|
||||
click.echo(f"Training the crew for {n_iterations} iterations")
|
||||
train_crew(n_iterations)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
crewai()
|
||||
|
||||
@@ -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
|
||||
@@ -40,7 +40,7 @@ poetry run {{folder_name}}
|
||||
|
||||
This command initializes the {{name}} Crew, assembling the agents and assigning them tasks as defined in your configuration.
|
||||
|
||||
This example, unmodified, will run the create a `report.md` file with the output of a research on LLMs in the root folser
|
||||
This example, unmodified, will run the create a `report.md` file with the output of a research on LLMs in the root folder.
|
||||
|
||||
## Understanding Your Crew
|
||||
|
||||
@@ -51,7 +51,7 @@ The {{name}} Crew is composed of multiple AI agents, each with unique roles, goa
|
||||
For support, questions, or feedback regarding the {{crew_name}} Crew or crewAI.
|
||||
- Visit our [documentation](https://docs.crewai.com)
|
||||
- Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai)
|
||||
- [Joing our Discord](https://discord.com/invite/X4JWnZnxPb)
|
||||
- [Chat wtih our docs](https://chatg.pt/DWjSBZn)
|
||||
- [Join our Discord](https://discord.com/invite/X4JWnZnxPb)
|
||||
- [Chat with our docs](https://chatg.pt/DWjSBZn)
|
||||
|
||||
Let's create wonders together with the power and simplicity of crewAI.
|
||||
Let's create wonders together with the power and simplicity of crewAI.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
from {{folder_name}}.crew import {{crew_name}}Crew
|
||||
|
||||
|
||||
@@ -7,4 +8,15 @@ def run():
|
||||
inputs = {
|
||||
'topic': 'AI LLMs'
|
||||
}
|
||||
{{crew_name}}Crew().crew().kickoff(inputs=inputs)
|
||||
{{crew_name}}Crew().crew().kickoff(inputs=inputs)
|
||||
|
||||
|
||||
def train():
|
||||
"""
|
||||
Train the crew for a given number of iterations.
|
||||
"""
|
||||
try:
|
||||
{{crew_name}}Crew().crew().train(n_iterations=int(sys.argv[1]))
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"An error occurred while training the crew: {e}")
|
||||
|
||||
@@ -6,11 +6,12 @@ authors = ["Your Name <you@example.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.10,<=3.13"
|
||||
crewai = {extras = ["tools"], version = "^0.27.0"}
|
||||
crewai = { extras = ["tools"], version = "^0.30.11" }
|
||||
|
||||
[tool.poetry.scripts]
|
||||
{{folder_name}} = "{{folder_name}}.main:run"
|
||||
train = "{{folder_name}}.main:train"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
@@ -3,7 +3,9 @@ from crewai_tools import BaseTool
|
||||
|
||||
class MyCustomTool(BaseTool):
|
||||
name: str = "Name of my tool"
|
||||
description: str = "Clear description for what this tool is useful for, you agent will need this information to use it."
|
||||
description: str = (
|
||||
"Clear description for what this tool is useful for, you agent will need this information to use it."
|
||||
)
|
||||
|
||||
def _run(self, argument: str) -> str:
|
||||
# Implementation goes here
|
||||
|
||||
29
src/crewai/cli/train_crew.py
Normal file
29
src/crewai/cli/train_crew.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import subprocess
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def train_crew(n_iterations: int) -> None:
|
||||
"""
|
||||
Train the crew by running a command in the Poetry environment.
|
||||
|
||||
Args:
|
||||
n_iterations (int): The number of iterations to train the crew.
|
||||
"""
|
||||
command = ["poetry", "run", "train", str(n_iterations)]
|
||||
|
||||
try:
|
||||
if n_iterations <= 0:
|
||||
raise ValueError("The number of iterations must be a positive integer.")
|
||||
|
||||
result = subprocess.run(command, capture_output=False, text=True, check=True)
|
||||
|
||||
if result.stderr:
|
||||
click.echo(result.stderr, err=True)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
click.echo(f"An error occurred while training the crew: {e}", err=True)
|
||||
click.echo(e.output, err=True)
|
||||
|
||||
except Exception as e:
|
||||
click.echo(f"An unexpected error occurred: {e}", err=True)
|
||||
@@ -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, FileHandler, Logger, RPMController
|
||||
|
||||
|
||||
class Crew(BaseModel):
|
||||
@@ -36,6 +36,7 @@ class Crew(BaseModel):
|
||||
tasks: List of tasks assigned to the crew.
|
||||
agents: List of agents part of this crew.
|
||||
manager_llm: The language model that will run manager agent.
|
||||
manager_agent: Custom agent that will be used as manager.
|
||||
memory: Whether the crew should use memory to store memories of it's execution.
|
||||
manager_callbacks: The callback handlers to be executed by the manager agent when hierarchical process is used
|
||||
cache: Whether the crew should use a cache to store the results of the tools execution.
|
||||
@@ -44,6 +45,7 @@ class Crew(BaseModel):
|
||||
verbose: Indicates the verbosity level for logging during execution.
|
||||
config: Configuration settings for the crew.
|
||||
max_rpm: Maximum number of requests per minute for the crew execution to be respected.
|
||||
prompt_file: Path to the prompt json file to be used for the crew.
|
||||
id: A unique identifier for the crew instance.
|
||||
full_output: Whether the crew should return the full output with all tasks outputs or just the final output.
|
||||
task_callback: Callback to be executed after each task for every agents execution.
|
||||
@@ -55,6 +57,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()
|
||||
@@ -85,6 +88,9 @@ class Crew(BaseModel):
|
||||
manager_llm: Optional[Any] = Field(
|
||||
description="Language model that will run the agent.", default=None
|
||||
)
|
||||
manager_agent: Optional[Any] = Field(
|
||||
description="Custom agent that will be used as manager.", default=None
|
||||
)
|
||||
manager_callbacks: Optional[List[InstanceOf[BaseCallbackHandler]]] = Field(
|
||||
default=None,
|
||||
description="A list of callback handlers to be executed by the manager agent when hierarchical process is used",
|
||||
@@ -107,13 +113,13 @@ class Crew(BaseModel):
|
||||
default=None,
|
||||
description="Maximum number of requests per minute for the crew execution to be respected.",
|
||||
)
|
||||
language: str = Field(
|
||||
default="en",
|
||||
description="Language used for the crew, defaults to English.",
|
||||
)
|
||||
language_file: str = Field(
|
||||
prompt_file: str = Field(
|
||||
default=None,
|
||||
description="Path to the language file to be used for the crew.",
|
||||
description="Path to the prompt json 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")
|
||||
@@ -145,6 +151,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()
|
||||
@@ -156,19 +164,32 @@ class Crew(BaseModel):
|
||||
"""Set private attributes."""
|
||||
if self.memory:
|
||||
self._long_term_memory = LongTermMemory()
|
||||
self._short_term_memory = ShortTermMemory(embedder_config=self.embedder)
|
||||
self._entity_memory = EntityMemory(embedder_config=self.embedder)
|
||||
self._short_term_memory = ShortTermMemory(
|
||||
crew=self, embedder_config=self.embedder
|
||||
)
|
||||
self._entity_memory = EntityMemory(crew=self, embedder_config=self.embedder)
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_manager_llm(self):
|
||||
"""Validates that the language model is set when using hierarchical process."""
|
||||
if self.process == Process.hierarchical and not self.manager_llm:
|
||||
raise PydanticCustomError(
|
||||
"missing_manager_llm",
|
||||
"Attribute `manager_llm` is required when using hierarchical process.",
|
||||
{},
|
||||
)
|
||||
if self.process == Process.hierarchical:
|
||||
if not self.manager_llm and not self.manager_agent:
|
||||
raise PydanticCustomError(
|
||||
"missing_manager_llm_or_manager_agent",
|
||||
"Attribute `manager_llm` or `manager_agent` is required when using hierarchical process.",
|
||||
{},
|
||||
)
|
||||
|
||||
if (self.manager_agent is not None) and (
|
||||
self.agents.count(self.manager_agent) > 0
|
||||
):
|
||||
raise PydanticCustomError(
|
||||
"manager_agent_in_agents",
|
||||
"Manager agent should not be included in agents list.",
|
||||
{},
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
@@ -223,10 +244,10 @@ class Crew(BaseModel):
|
||||
def kickoff(self, inputs: Optional[Dict[str, Any]] = {}) -> str:
|
||||
"""Starts the crew to work on its assigned tasks."""
|
||||
self._execution_span = self._telemetry.crew_execution_span(self)
|
||||
self._interpolate_inputs(inputs)
|
||||
self._interpolate_inputs(inputs) # type: ignore # Argument 1 to "_interpolate_inputs" of "Crew" has incompatible type "dict[str, Any] | None"; expected "dict[str, Any]"
|
||||
self._set_tasks_callbacks()
|
||||
|
||||
i18n = I18N(language=self.language, language_file=self.language_file)
|
||||
i18n = I18N(prompt_file=self.prompt_file)
|
||||
|
||||
for agent in self.agents:
|
||||
agent.i18n = i18n
|
||||
@@ -244,8 +265,8 @@ class Crew(BaseModel):
|
||||
if self.process == Process.sequential:
|
||||
result = self._run_sequential_process()
|
||||
elif self.process == Process.hierarchical:
|
||||
result, manager_metrics = self._run_hierarchical_process()
|
||||
metrics.append(manager_metrics)
|
||||
result, manager_metrics = self._run_hierarchical_process() # type: ignore # Unpacking a string is disallowed
|
||||
metrics.append(manager_metrics) # type: ignore # Cannot determine type of "manager_metrics"
|
||||
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
@@ -261,11 +282,15 @@ class Crew(BaseModel):
|
||||
|
||||
return result
|
||||
|
||||
def train(self, n_iterations: int) -> None:
|
||||
# TODO: Implement training
|
||||
pass
|
||||
|
||||
def _run_sequential_process(self) -> str:
|
||||
"""Executes tasks sequentially and returns the final output."""
|
||||
task_output = ""
|
||||
for task in self.tasks:
|
||||
if task.agent.allow_delegation:
|
||||
if task.agent.allow_delegation: # type: ignore # Item "None" of "Agent | None" has no attribute "allow_delegation"
|
||||
agents_for_delegation = [
|
||||
agent for agent in self.agents if agent != task.agent
|
||||
]
|
||||
@@ -273,11 +298,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,50 +315,71 @@ 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)
|
||||
|
||||
def _run_hierarchical_process(self) -> str:
|
||||
"""Creates and assigns a manager agent to make sure the crew completes the tasks."""
|
||||
|
||||
i18n = I18N(language=self.language, language_file=self.language_file)
|
||||
manager = Agent(
|
||||
role=i18n.retrieve("hierarchical_manager_agent", "role"),
|
||||
goal=i18n.retrieve("hierarchical_manager_agent", "goal"),
|
||||
backstory=i18n.retrieve("hierarchical_manager_agent", "backstory"),
|
||||
tools=AgentTools(agents=self.agents).tools(),
|
||||
llm=self.manager_llm,
|
||||
verbose=True,
|
||||
)
|
||||
i18n = I18N(prompt_file=self.prompt_file)
|
||||
if self.manager_agent is not None:
|
||||
self.manager_agent.allow_delegation = True
|
||||
manager = self.manager_agent
|
||||
if len(manager.tools) > 0:
|
||||
raise Exception("Manager agent should not have tools")
|
||||
manager.tools = AgentTools(agents=self.agents).tools()
|
||||
else:
|
||||
manager = Agent(
|
||||
role=i18n.retrieve("hierarchical_manager_agent", "role"),
|
||||
goal=i18n.retrieve("hierarchical_manager_agent", "goal"),
|
||||
backstory=i18n.retrieve("hierarchical_manager_agent", "backstory"),
|
||||
tools=AgentTools(agents=self.agents).tools(),
|
||||
llm=self.manager_llm,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
task_output = ""
|
||||
for task in self.tasks:
|
||||
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}")
|
||||
|
||||
self._finish_execution(task_output)
|
||||
return self._format_output(task_output), manager._token_process.get_summary()
|
||||
if self.output_log_file:
|
||||
self._file_handler.log(
|
||||
agent=manager.role, task=task_output, status="completed"
|
||||
)
|
||||
|
||||
def _set_tasks_callbacks(self) -> str:
|
||||
self._finish_execution(task_output)
|
||||
return self._format_output(task_output), manager._token_process.get_summary() # type: ignore # Incompatible return value type (got "tuple[str, Any]", expected "str")
|
||||
|
||||
def _set_tasks_callbacks(self) -> None:
|
||||
"""Sets callback for every task suing task_callback"""
|
||||
for task in self.tasks:
|
||||
task.callback = self.task_callback
|
||||
if not task.callback:
|
||||
task.callback = self.task_callback
|
||||
|
||||
def _interpolate_inputs(self, inputs: Dict[str, Any]) -> str:
|
||||
def _interpolate_inputs(self, inputs: Dict[str, Any]) -> None:
|
||||
"""Interpolates the inputs in the tasks and agents."""
|
||||
[task.interpolate_inputs(inputs) for task in self.tasks]
|
||||
[agent.interpolate_inputs(inputs) for agent in self.agents]
|
||||
[task.interpolate_inputs(inputs) for task in self.tasks] # type: ignore # "interpolate_inputs" of "Task" does not return a value (it only ever returns None)
|
||||
[agent.interpolate_inputs(inputs) for agent in self.agents] # type: ignore # "interpolate_inputs" of "Agent" does not return a value (it only ever returns None)
|
||||
|
||||
def _format_output(self, output: str) -> str:
|
||||
"""Formats the output of the crew execution."""
|
||||
if self.full_output:
|
||||
return {
|
||||
return { # type: ignore # Incompatible return value type (got "dict[str, Sequence[str | TaskOutput | None]]", expected "str")
|
||||
"final_output": output,
|
||||
"tasks_outputs": [task.output for task in self.tasks if task],
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from crewai.memory import EntityMemory, LongTermMemory, ShortTermMemory
|
||||
|
||||
|
||||
@@ -32,18 +34,23 @@ class ContextualMemory:
|
||||
formatted_results = "\n".join([f"- {result}" for result in stm_results])
|
||||
return f"Recent Insights:\n{formatted_results}" if stm_results else ""
|
||||
|
||||
def _fetch_ltm_context(self, task) -> str:
|
||||
def _fetch_ltm_context(self, task) -> Optional[str]:
|
||||
"""
|
||||
Fetches historical data or insights from LTM that are relevant to the task's description and expected_output,
|
||||
formatted as bullet points.
|
||||
"""
|
||||
ltm_results = self.ltm.search(task)
|
||||
ltm_results = self.ltm.search(task, latest_n=2)
|
||||
if not ltm_results:
|
||||
return None
|
||||
formatted_results = "\n".join(
|
||||
[f"{result['metadata']['suggestions']}" for result in ltm_results]
|
||||
)
|
||||
formatted_results = list(set(formatted_results))
|
||||
|
||||
formatted_results = [
|
||||
suggestion
|
||||
for result in ltm_results
|
||||
for suggestion in result["metadata"]["suggestions"] # type: ignore # Invalid index type "str" for "str"; expected type "SupportsIndex | slice"
|
||||
]
|
||||
formatted_results = list(dict.fromkeys(formatted_results))
|
||||
formatted_results = "\n".join([f"- {result}" for result in formatted_results]) # type: ignore # Incompatible types in assignment (expression has type "str", variable has type "list[str]")
|
||||
|
||||
return f"Historical Data:\n{formatted_results}" if ltm_results else ""
|
||||
|
||||
def _fetch_entity_context(self, query) -> str:
|
||||
@@ -53,6 +60,6 @@ class ContextualMemory:
|
||||
"""
|
||||
em_results = self.em.search(query)
|
||||
formatted_results = "\n".join(
|
||||
[f"- {result['context']}" for result in em_results]
|
||||
[f"- {result['context']}" for result in em_results] # type: ignore # Invalid index type "str" for "str"; expected type "SupportsIndex | slice"
|
||||
)
|
||||
return f"Entities:\n{formatted_results}" if em_results else ""
|
||||
|
||||
@@ -10,13 +10,16 @@ class EntityMemory(Memory):
|
||||
Inherits from the Memory class.
|
||||
"""
|
||||
|
||||
def __init__(self, embedder_config=None):
|
||||
def __init__(self, crew=None, embedder_config=None):
|
||||
storage = RAGStorage(
|
||||
type="entities", allow_reset=False, embedder_config=embedder_config
|
||||
type="entities",
|
||||
allow_reset=False,
|
||||
embedder_config=embedder_config,
|
||||
crew=crew,
|
||||
)
|
||||
super().__init__(storage)
|
||||
|
||||
def save(self, item: EntityMemoryItem) -> None:
|
||||
def save(self, item: EntityMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory"
|
||||
"""Saves an entity item into the SQLite storage."""
|
||||
data = f"{item.name}({item.type}): {item.description}"
|
||||
super().save(data, item.metadata)
|
||||
|
||||
@@ -18,15 +18,15 @@ class LongTermMemory(Memory):
|
||||
storage = LTMSQLiteStorage()
|
||||
super().__init__(storage)
|
||||
|
||||
def save(self, item: LongTermMemoryItem) -> None:
|
||||
def save(self, item: LongTermMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory"
|
||||
metadata = item.metadata
|
||||
metadata.update({"agent": item.agent, "expected_output": item.expected_output})
|
||||
self.storage.save(
|
||||
self.storage.save( # type: ignore # BUG?: Unexpected keyword argument "task_description","score","datetime" for "save" of "Storage"
|
||||
task_description=item.task,
|
||||
score=metadata["quality"],
|
||||
metadata=metadata,
|
||||
datetime=item.datetime,
|
||||
)
|
||||
|
||||
def search(self, task: str) -> Dict[str, Any]:
|
||||
return self.storage.load(task)
|
||||
def search(self, task: str, latest_n: int = 3) -> Dict[str, Any]:
|
||||
return self.storage.load(task, latest_n) # type: ignore # BUG?: "Storage" has no attribute "load"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict, Union
|
||||
from typing import Any, Dict, Optional, Union
|
||||
|
||||
|
||||
class LongTermMemoryItem:
|
||||
@@ -8,8 +8,8 @@ class LongTermMemoryItem:
|
||||
task: str,
|
||||
expected_output: str,
|
||||
datetime: str,
|
||||
quality: Union[int, float] = None,
|
||||
metadata: Dict[str, Any] = None,
|
||||
quality: Optional[Union[int, float]] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
self.task = task
|
||||
self.agent = agent
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from crewai.memory.storage.interface import Storage
|
||||
|
||||
@@ -12,12 +12,16 @@ class Memory:
|
||||
self.storage = storage
|
||||
|
||||
def save(
|
||||
self, value: Any, metadata: Dict[str, Any] = None, agent: str = None
|
||||
self,
|
||||
value: Any,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
agent: Optional[str] = None,
|
||||
) -> None:
|
||||
metadata = metadata or {}
|
||||
if agent:
|
||||
metadata["agent"] = agent
|
||||
self.storage.save(value, metadata)
|
||||
|
||||
self.storage.save(value, metadata) # type: ignore # Maybe BUG? Should be self.storage.save(key, value, metadata)
|
||||
|
||||
def search(self, query: str) -> Dict[str, Any]:
|
||||
return self.storage.search(query)
|
||||
|
||||
@@ -12,12 +12,14 @@ class ShortTermMemory(Memory):
|
||||
MemoryItem instances.
|
||||
"""
|
||||
|
||||
def __init__(self, embedder_config=None):
|
||||
storage = RAGStorage(type="short_term", embedder_config=embedder_config)
|
||||
def __init__(self, crew=None, embedder_config=None):
|
||||
storage = RAGStorage(
|
||||
type="short_term", embedder_config=embedder_config, crew=crew
|
||||
)
|
||||
super().__init__(storage)
|
||||
|
||||
def save(self, item: ShortTermMemoryItem) -> None:
|
||||
def save(self, item: ShortTermMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory"
|
||||
super().save(item.data, item.metadata, item.agent)
|
||||
|
||||
def search(self, query: str, score_threshold: float = 0.35):
|
||||
return self.storage.search(query=query, score_threshold=score_threshold)
|
||||
return self.storage.search(query=query, score_threshold=score_threshold) # type: ignore # BUG? The reference is to the parent class, but the parent class does not have this parameters
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
|
||||
class ShortTermMemoryItem:
|
||||
def __init__(self, data: Any, agent: str, metadata: Dict[str, Any] = None):
|
||||
def __init__(
|
||||
self, data: Any, agent: str, metadata: Optional[Dict[str, Any]] = None
|
||||
):
|
||||
self.data = data
|
||||
self.agent = agent
|
||||
self.metadata = metadata if metadata is not None else {}
|
||||
|
||||
@@ -7,5 +7,5 @@ class Storage:
|
||||
def save(self, key: str, value: Any, metadata: Dict[str, Any]) -> None:
|
||||
pass
|
||||
|
||||
def search(self, key: str) -> Dict[str, Any]:
|
||||
def search(self, key: str) -> Dict[str, Any]: # type: ignore
|
||||
pass
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
import sqlite3
|
||||
from typing import Any, Dict, Union
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from crewai.utilities import Printer
|
||||
from crewai.utilities.paths import db_storage_path
|
||||
@@ -11,7 +11,9 @@ class LTMSQLiteStorage:
|
||||
An updated SQLite storage class for LTM data storage.
|
||||
"""
|
||||
|
||||
def __init__(self, db_path=f"{db_storage_path()}/long_term_memory_storage.db"):
|
||||
def __init__(
|
||||
self, db_path: str = f"{db_storage_path()}/long_term_memory_storage.db"
|
||||
) -> None:
|
||||
self.db_path = db_path
|
||||
self._printer: Printer = Printer()
|
||||
self._initialize_db()
|
||||
@@ -67,19 +69,21 @@ class LTMSQLiteStorage:
|
||||
color="red",
|
||||
)
|
||||
|
||||
def load(self, task_description: str) -> Dict[str, Any]:
|
||||
def load(
|
||||
self, task_description: str, latest_n: int
|
||||
) -> Optional[List[Dict[str, Any]]]:
|
||||
"""Queries the LTM table by task description with error handling."""
|
||||
try:
|
||||
with sqlite3.connect(self.db_path) as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT metadata, datetime, score
|
||||
FROM long_term_memories
|
||||
WHERE task_description = ?
|
||||
ORDER BY datetime DESC, score ASC
|
||||
LIMIT 2
|
||||
""",
|
||||
f"""
|
||||
SELECT metadata, datetime, score
|
||||
FROM long_term_memories
|
||||
WHERE task_description = ?
|
||||
ORDER BY datetime DESC, score ASC
|
||||
LIMIT {latest_n}
|
||||
""",
|
||||
(task_description,),
|
||||
)
|
||||
rows = cursor.fetchall()
|
||||
|
||||
@@ -2,7 +2,7 @@ import contextlib
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from embedchain import App
|
||||
from embedchain.llm.base import BaseLlm
|
||||
@@ -37,13 +37,18 @@ class RAGStorage(Storage):
|
||||
search efficiency.
|
||||
"""
|
||||
|
||||
def __init__(self, type, allow_reset=True, embedder_config=None):
|
||||
def __init__(self, type, allow_reset=True, embedder_config=None, crew=None):
|
||||
super().__init__()
|
||||
if (
|
||||
not os.getenv("OPENAI_API_KEY")
|
||||
and not os.getenv("OPENAI_BASE_URL") == "https://api.openai.com/v1"
|
||||
):
|
||||
os.environ["OPENAI_API_KEY"] = "fake"
|
||||
|
||||
agents = crew.agents if crew else []
|
||||
agents = [agent.role for agent in agents]
|
||||
agents = "_".join(agents)
|
||||
|
||||
config = {
|
||||
"app": {
|
||||
"config": {"name": type, "collect_metrics": False, "log_level": "ERROR"}
|
||||
@@ -58,7 +63,7 @@ class RAGStorage(Storage):
|
||||
"provider": "chroma",
|
||||
"config": {
|
||||
"collection_name": type,
|
||||
"dir": f"{db_storage_path()}/{type}",
|
||||
"dir": f"{db_storage_path()}/{type}/{agents}",
|
||||
"allow_reset": allow_reset,
|
||||
},
|
||||
},
|
||||
@@ -72,16 +77,16 @@ class RAGStorage(Storage):
|
||||
if allow_reset:
|
||||
self.app.reset()
|
||||
|
||||
def save(self, value: Any, metadata: Dict[str, Any]) -> None:
|
||||
def save(self, value: Any, metadata: Dict[str, Any]) -> None: # type: ignore # BUG?: Should be save(key, value, metadata) Signature of "save" incompatible with supertype "Storage"
|
||||
self._generate_embedding(value, metadata)
|
||||
|
||||
def search(
|
||||
def search( # type: ignore # BUG?: Signature of "search" incompatible with supertype "Storage"
|
||||
self,
|
||||
query: str,
|
||||
limit: int = 3,
|
||||
filter: dict = None,
|
||||
filter: Optional[dict] = None,
|
||||
score_threshold: float = 0.35,
|
||||
) -> Dict[str, Any]:
|
||||
) -> List[Any]:
|
||||
with suppress_logging():
|
||||
try:
|
||||
results = (
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
tasks_order = []
|
||||
|
||||
|
||||
def memoize(func):
|
||||
cache = {}
|
||||
|
||||
def memoized_func(*args, **kwargs):
|
||||
key = (args, tuple(kwargs.items()))
|
||||
if key not in cache:
|
||||
cache[key] = func(*args, **kwargs)
|
||||
return cache[key]
|
||||
|
||||
return memoized_func
|
||||
|
||||
|
||||
def task(func):
|
||||
func.is_task = True
|
||||
tasks_order.append(func.__name__)
|
||||
func = memoize(func)
|
||||
return func
|
||||
|
||||
|
||||
def agent(func):
|
||||
func.is_agent = True
|
||||
func = memoize(func)
|
||||
return func
|
||||
|
||||
|
||||
|
||||
@@ -4,13 +4,15 @@ from pathlib import Path
|
||||
|
||||
import yaml
|
||||
from dotenv import load_dotenv
|
||||
from pydantic import ConfigDict
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def CrewBase(cls):
|
||||
class WrappedClass(cls):
|
||||
is_crew_class = True
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
is_crew_class: bool = True # type: ignore
|
||||
|
||||
base_directory = None
|
||||
for frame_info in inspect.stack():
|
||||
@@ -40,6 +42,7 @@ def CrewBase(cls):
|
||||
@staticmethod
|
||||
def load_yaml(config_path: str):
|
||||
with open(config_path, "r") as file:
|
||||
# parsedContent = YamlParser.parse(file) # type: ignore # Argument 1 to "parse" has incompatible type "TextIOWrapper"; expected "YamlParser"
|
||||
return yaml.safe_load(file)
|
||||
|
||||
return WrappedClass
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
@@ -13,7 +15,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
|
||||
@@ -23,7 +41,7 @@ class Task(BaseModel):
|
||||
tools_errors: int = 0
|
||||
delegations: int = 0
|
||||
i18n: I18N = I18N()
|
||||
thread: threading.Thread = None
|
||||
thread: Optional[threading.Thread] = None
|
||||
prompt_context: Optional[str] = None
|
||||
description: str = Field(description="Description of the actual task.")
|
||||
expected_output: str = Field(
|
||||
@@ -91,6 +109,14 @@ class Task(BaseModel):
|
||||
"may_not_set_field", "This field is not to be set by the user.", {}
|
||||
)
|
||||
|
||||
@field_validator("output_file")
|
||||
@classmethod
|
||||
def output_file_validattion(cls, value: str) -> str:
|
||||
"""Validate the output file path by removing the / from the beginning of the path."""
|
||||
if value.startswith("/"):
|
||||
return value[1:]
|
||||
return value
|
||||
|
||||
@model_validator(mode="after")
|
||||
def set_attributes_based_on_config(self) -> "Task":
|
||||
"""Set attributes based on the agent configuration."""
|
||||
@@ -118,7 +144,7 @@ class Task(BaseModel):
|
||||
)
|
||||
return self
|
||||
|
||||
def execute(
|
||||
def execute( # type: ignore # Missing return statement
|
||||
self,
|
||||
agent: Agent | None = None,
|
||||
context: Optional[str] = None,
|
||||
@@ -137,13 +163,13 @@ class Task(BaseModel):
|
||||
)
|
||||
|
||||
if self.context:
|
||||
context = []
|
||||
context = [] # type: ignore # Incompatible types in assignment (expression has type "list[Never]", variable has type "str | None")
|
||||
for task in self.context:
|
||||
if task.async_execution:
|
||||
task.thread.join()
|
||||
task.thread.join() # type: ignore # Item "None" of "Thread | None" has no attribute "join"
|
||||
if task and task.output:
|
||||
context.append(task.output.raw_output)
|
||||
context = "\n".join(context)
|
||||
context.append(task.output.raw_output) # type: ignore # Item "str" of "str | None" has no attribute "append"
|
||||
context = "\n".join(context) # type: ignore # Argument 1 to "join" of "str" has incompatible type "str | None"; expected "Iterable[str]"
|
||||
|
||||
self.prompt_context = context
|
||||
tools = tools or self.tools
|
||||
@@ -224,17 +250,26 @@ class Task(BaseModel):
|
||||
|
||||
# try to convert task_output directly to pydantic/json
|
||||
try:
|
||||
exported_result = model.model_validate_json(result)
|
||||
exported_result = model.model_validate_json(result) # type: ignore # Item "None" of "type[BaseModel] | None" has no attribute "model_validate_json"
|
||||
if self.output_json:
|
||||
return exported_result.model_dump()
|
||||
return exported_result.model_dump() # type: ignore # "str" has no attribute "model_dump"
|
||||
return exported_result
|
||||
except Exception:
|
||||
pass
|
||||
# sometimes the response contains valid JSON in the middle of text
|
||||
match = re.search(r"({.*})", result, re.DOTALL)
|
||||
if match:
|
||||
try:
|
||||
exported_result = model.model_validate_json(match.group(0)) # type: ignore # Item "None" of "type[BaseModel] | None" has no attribute "model_validate_json"
|
||||
if self.output_json:
|
||||
return exported_result.model_dump() # type: ignore # "str" has no attribute "model_dump"
|
||||
return exported_result
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
llm = self.agent.function_calling_llm or self.agent.llm
|
||||
llm = self.agent.function_calling_llm or self.agent.llm # type: ignore # Item "None" of "Agent | None" has no attribute "function_calling_llm"
|
||||
|
||||
if not self._is_gpt(llm):
|
||||
model_schema = PydanticSchemaParser(model=model).get_schema()
|
||||
model_schema = PydanticSchemaParser(model=model).get_schema() # type: ignore # Argument "model" to "PydanticSchemaParser" has incompatible type "type[BaseModel] | None"; expected "type[BaseModel]"
|
||||
instructions = f"{instructions}\n\nThe json should have the following structure, with the following keys:\n{model_schema}"
|
||||
|
||||
converter = Converter(
|
||||
@@ -255,17 +290,22 @@ class Task(BaseModel):
|
||||
|
||||
if self.output_file:
|
||||
content = (
|
||||
exported_result if not self.output_pydantic else exported_result.json()
|
||||
exported_result if not self.output_pydantic else exported_result.json() # type: ignore # "str" has no attribute "json"
|
||||
)
|
||||
self._save_file(content)
|
||||
|
||||
return exported_result
|
||||
|
||||
def _is_gpt(self, llm) -> bool:
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base == None
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base is None
|
||||
|
||||
def _save_file(self, result: Any) -> None:
|
||||
with open(self.output_file, "w") as file:
|
||||
directory = os.path.dirname(self.output_file) # type: ignore # Value of type variable "AnyOrLiteralStr" of "dirname" cannot be "str | None"
|
||||
|
||||
if directory and not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
with open(self.output_file, "w", encoding="utf-8") as file: # type: ignore # Argument 1 to "open" has incompatible type "str | None"; expected "int | str | bytes | PathLike[str] | PathLike[bytes]"
|
||||
file.write(result)
|
||||
return None
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDqDCCAy6gAwIBAgIRAPNkTmtuAFAjfglGvXvh9R0wCgYIKoZIzj0EAwMwgYgx
|
||||
CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz
|
||||
ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD
|
||||
EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEw
|
||||
MjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAkdCMRswGQYDVQQI
|
||||
ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT
|
||||
D1NlY3RpZ28gTGltaXRlZDE3MDUGA1UEAxMuU2VjdGlnbyBFQ0MgRG9tYWluIFZh
|
||||
bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEH
|
||||
A0IABHkYk8qfbZ5sVwAjBTcLXw9YWsTef1Wj6R7W2SUKiKAgSh16TwUwimNJE4xk
|
||||
IQeV/To14UrOkPAY9z2vaKb71EijggFuMIIBajAfBgNVHSMEGDAWgBQ64QmG1M8Z
|
||||
wpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU9oUKOxGG4QR9DqoLLNLuzGR7e64wDgYD
|
||||
VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgEwUAYD
|
||||
VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz
|
||||
dEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/
|
||||
BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVD
|
||||
Q0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1
|
||||
c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMEvnx3FcsVwJbZpCYF9z6fDWJtS1UVRs
|
||||
cS0chWBNKPFNpvDKdrdKRe+oAkr2jU+ubgIxAODheSr2XhcA7oz9HmedGdMhlrd9
|
||||
4ToKFbZl+/OnFFzqnvOhcjHvClECEQcKmc8fmA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID0zCCArugAwIBAgIQVmcdBOpPmUxvEIFHWdJ1lDANBgkqhkiG9w0BAQwFADB7
|
||||
MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
||||
VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
|
||||
AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4
|
||||
MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5
|
||||
MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO
|
||||
ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEGqxUWqn5aCPnetUkb1PGWthL
|
||||
q8bVttHmc3Gu3ZzWDGH926CJA7gFFOxXzu5dP+Ihs8731Ip54KODfi2X0GHE8Znc
|
||||
JZFjq38wo7Rw4sehM5zzvy5cU7Ffs30yf4o043l5o4HyMIHvMB8GA1UdIwQYMBaA
|
||||
FKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1
|
||||
xmNjmjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zARBgNVHSAECjAI
|
||||
MAYGBFUdIAAwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5j
|
||||
b20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQG
|
||||
CCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEM
|
||||
BQADggEBABns652JLCALBIAdGN5CmXKZFjK9Dpx1WywV4ilAbe7/ctvbq5AfjJXy
|
||||
ij0IckKJUAfiORVsAYfZFhr1wHUrxeZWEQff2Ji8fJ8ZOd+LygBkc7xGEJuTI42+
|
||||
FsMuCIKchjN0djsoTI0DQoWz4rIjQtUfenVqGtF8qmchxDM6OW1TyaLtYiKou+JV
|
||||
bJlsQ2uRl9EMC5MCHdK8aXdJ5htN978UeAOwproLtOGFfy/cQjutdAFI3tZs4RmY
|
||||
CV4Ks2dH/hzg1cEo70qLRDEmBDeNiXQ2Lu+lIg+DdEmSx/cQwgwp+7e9un/jX9Wf
|
||||
8qn0dNW44bOwgeThpWOjzOoEeJBuv/c=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
import importlib.resources
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
@@ -41,19 +40,17 @@ class Telemetry:
|
||||
|
||||
def __init__(self):
|
||||
self.ready = False
|
||||
self.trace_set = False
|
||||
try:
|
||||
telemetry_endpoint = "https://telemetry.crewai.com:4319"
|
||||
self.resource = Resource(
|
||||
attributes={SERVICE_NAME: "crewAI-telemetry"},
|
||||
)
|
||||
self.provider = TracerProvider(resource=self.resource)
|
||||
cert_file = importlib.resources.files("crewai.telemetry").joinpath(
|
||||
"STAR_crewai_com_bundle.pem"
|
||||
)
|
||||
|
||||
processor = BatchSpanProcessor(
|
||||
OTLPSpanExporter(
|
||||
endpoint=f"{telemetry_endpoint}/v1/traces",
|
||||
certificate_file=cert_file,
|
||||
timeout=30,
|
||||
)
|
||||
)
|
||||
@@ -69,13 +66,13 @@ class Telemetry:
|
||||
self.ready = False
|
||||
|
||||
def set_tracer(self):
|
||||
if self.ready:
|
||||
provider = trace.get_tracer_provider()
|
||||
if provider is None:
|
||||
try:
|
||||
trace.set_tracer_provider(self.provider)
|
||||
except Exception:
|
||||
self.ready = False
|
||||
if self.ready and not self.trace_set:
|
||||
try:
|
||||
trace.set_tracer_provider(self.provider)
|
||||
self.trace_set = True
|
||||
except Exception:
|
||||
self.ready = False
|
||||
self.trace_set = False
|
||||
|
||||
def crew_creation(self, crew):
|
||||
"""Records the creation of a crew."""
|
||||
@@ -91,7 +88,10 @@ class Telemetry:
|
||||
self._add_attribute(span, "python_version", platform.python_version())
|
||||
self._add_attribute(span, "crew_id", str(crew.id))
|
||||
self._add_attribute(span, "crew_process", crew.process)
|
||||
self._add_attribute(span, "crew_language", crew.language)
|
||||
self._add_attribute(
|
||||
span, "crew_language", crew.prompt_file if crew.i18n else "None"
|
||||
)
|
||||
self._add_attribute(span, "crew_memory", crew.memory)
|
||||
self._add_attribute(span, "crew_number_of_tasks", len(crew.tasks))
|
||||
self._add_attribute(span, "crew_number_of_agents", len(crew.agents))
|
||||
self._add_attribute(
|
||||
@@ -102,11 +102,10 @@ class Telemetry:
|
||||
{
|
||||
"id": str(agent.id),
|
||||
"role": agent.role,
|
||||
"memory_enabled?": agent.memory,
|
||||
"verbose?": agent.verbose,
|
||||
"max_iter": agent.max_iter,
|
||||
"max_rpm": agent.max_rpm,
|
||||
"i18n": agent.i18n.language,
|
||||
"i18n": agent.i18n.prompt_file,
|
||||
"llm": json.dumps(self._safe_llm_attributes(agent.llm)),
|
||||
"delegation_enabled?": agent.allow_delegation,
|
||||
"tools_names": [
|
||||
@@ -150,11 +149,17 @@ class Telemetry:
|
||||
try:
|
||||
tracer = trace.get_tracer("crewai.telemetry")
|
||||
span = tracer.start_span("Tool Repeated Usage")
|
||||
self._add_attribute(
|
||||
span,
|
||||
"crewai_version",
|
||||
pkg_resources.get_distribution("crewai").version,
|
||||
)
|
||||
self._add_attribute(span, "tool_name", tool_name)
|
||||
self._add_attribute(span, "attempts", attempts)
|
||||
self._add_attribute(
|
||||
span, "llm", json.dumps(self._safe_llm_attributes(llm))
|
||||
)
|
||||
if llm:
|
||||
self._add_attribute(
|
||||
span, "llm", json.dumps(self._safe_llm_attributes(llm))
|
||||
)
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
span.end()
|
||||
except Exception:
|
||||
@@ -166,11 +171,17 @@ class Telemetry:
|
||||
try:
|
||||
tracer = trace.get_tracer("crewai.telemetry")
|
||||
span = tracer.start_span("Tool Usage")
|
||||
self._add_attribute(
|
||||
span,
|
||||
"crewai_version",
|
||||
pkg_resources.get_distribution("crewai").version,
|
||||
)
|
||||
self._add_attribute(span, "tool_name", tool_name)
|
||||
self._add_attribute(span, "attempts", attempts)
|
||||
self._add_attribute(
|
||||
span, "llm", json.dumps(self._safe_llm_attributes(llm))
|
||||
)
|
||||
if llm:
|
||||
self._add_attribute(
|
||||
span, "llm", json.dumps(self._safe_llm_attributes(llm))
|
||||
)
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
span.end()
|
||||
except Exception:
|
||||
@@ -183,8 +194,14 @@ class Telemetry:
|
||||
tracer = trace.get_tracer("crewai.telemetry")
|
||||
span = tracer.start_span("Tool Usage Error")
|
||||
self._add_attribute(
|
||||
span, "llm", json.dumps(self._safe_llm_attributes(llm))
|
||||
span,
|
||||
"crewai_version",
|
||||
pkg_resources.get_distribution("crewai").version,
|
||||
)
|
||||
if llm:
|
||||
self._add_attribute(
|
||||
span, "llm", json.dumps(self._safe_llm_attributes(llm))
|
||||
)
|
||||
span.set_status(Status(StatusCode.OK))
|
||||
span.end()
|
||||
except Exception:
|
||||
@@ -198,6 +215,11 @@ class Telemetry:
|
||||
try:
|
||||
tracer = trace.get_tracer("crewai.telemetry")
|
||||
span = tracer.start_span("Crew Execution")
|
||||
self._add_attribute(
|
||||
span,
|
||||
"crewai_version",
|
||||
pkg_resources.get_distribution("crewai").version,
|
||||
)
|
||||
self._add_attribute(span, "crew_id", str(crew.id))
|
||||
self._add_attribute(
|
||||
span,
|
||||
@@ -209,11 +231,10 @@ class Telemetry:
|
||||
"role": agent.role,
|
||||
"goal": agent.goal,
|
||||
"backstory": agent.backstory,
|
||||
"memory_enabled?": agent.memory,
|
||||
"verbose?": agent.verbose,
|
||||
"max_iter": agent.max_iter,
|
||||
"max_rpm": agent.max_rpm,
|
||||
"i18n": agent.i18n.language,
|
||||
"i18n": agent.i18n.prompt_file,
|
||||
"llm": json.dumps(self._safe_llm_attributes(agent.llm)),
|
||||
"delegation_enabled?": agent.allow_delegation,
|
||||
"tools_names": [
|
||||
@@ -235,9 +256,11 @@ class Telemetry:
|
||||
"async_execution?": task.async_execution,
|
||||
"output": task.expected_output,
|
||||
"agent_role": task.agent.role if task.agent else "None",
|
||||
"context": [task.description for task in task.context]
|
||||
if task.context
|
||||
else "None",
|
||||
"context": (
|
||||
[task.description for task in task.context]
|
||||
if task.context
|
||||
else "None"
|
||||
),
|
||||
"tools_names": [
|
||||
tool.name.casefold() for tool in task.tools
|
||||
],
|
||||
@@ -253,6 +276,11 @@ class Telemetry:
|
||||
def end_crew(self, crew, output):
|
||||
if (self.ready) and (crew.share_crew):
|
||||
try:
|
||||
self._add_attribute(
|
||||
crew._execution_span,
|
||||
"crewai_version",
|
||||
pkg_resources.get_distribution("crewai").version,
|
||||
)
|
||||
self._add_attribute(crew._execution_span, "crew_output", output)
|
||||
self._add_attribute(
|
||||
crew._execution_span,
|
||||
@@ -282,6 +310,8 @@ class Telemetry:
|
||||
|
||||
def _safe_llm_attributes(self, llm):
|
||||
attributes = ["name", "model_name", "base_url", "model", "top_k", "temperature"]
|
||||
safe_attributes = {k: v for k, v in vars(llm).items() if k in attributes}
|
||||
safe_attributes["class"] = llm.__class__.__name__
|
||||
return safe_attributes
|
||||
if llm:
|
||||
safe_attributes = {k: v for k, v in vars(llm).items() if k in attributes}
|
||||
safe_attributes["class"] = llm.__class__.__name__
|
||||
return safe_attributes
|
||||
return {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Union
|
||||
|
||||
from langchain.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -33,12 +33,26 @@ class AgentTools(BaseModel):
|
||||
]
|
||||
return tools
|
||||
|
||||
def delegate_work(self, coworker: str, task: str, context: str):
|
||||
"""Useful to delegate a specific task to a coworker passing all necessary context and names."""
|
||||
def delegate_work(
|
||||
self, task: str, context: str, coworker: Union[str, None] = None, **kwargs
|
||||
):
|
||||
"""Useful to delegate a specific task to a co-worker passing all necessary context and names."""
|
||||
coworker = coworker or kwargs.get("co_worker") or kwargs.get("co-worker")
|
||||
if coworker is not None:
|
||||
is_list = coworker.startswith("[") and coworker.endswith("]")
|
||||
if is_list:
|
||||
coworker = coworker[1:-1].split(",")[0]
|
||||
return self._execute(coworker, task, context)
|
||||
|
||||
def ask_question(self, coworker: str, question: str, context: str):
|
||||
"""Useful to ask a question, opinion or take from a coworker passing all necessary context and names."""
|
||||
def ask_question(
|
||||
self, question: str, context: str, coworker: Union[str, None] = None, **kwargs
|
||||
):
|
||||
"""Useful to ask a question, opinion or take from a co-worker passing all necessary context and names."""
|
||||
coworker = coworker or kwargs.get("co_worker") or kwargs.get("co-worker")
|
||||
if coworker is not None:
|
||||
is_list = coworker.startswith("[") and coworker.endswith("]")
|
||||
if is_list:
|
||||
coworker = coworker[1:-1].split(",")[0]
|
||||
return self._execute(coworker, question, context)
|
||||
|
||||
def _execute(self, agent, task, context):
|
||||
@@ -49,7 +63,7 @@ class AgentTools(BaseModel):
|
||||
for available_agent in self.agents
|
||||
if available_agent.role.casefold().strip() == agent.casefold().strip()
|
||||
]
|
||||
except:
|
||||
except Exception as _:
|
||||
return self.i18n.errors("agent_tool_unexsiting_coworker").format(
|
||||
coworkers="\n".join(
|
||||
[f"- {agent.role.casefold()}" for agent in self.agents]
|
||||
@@ -67,6 +81,6 @@ class AgentTools(BaseModel):
|
||||
task = Task(
|
||||
description=task,
|
||||
agent=agent,
|
||||
expected_output="Your best answer to your coworker asking you this, accounting for the context shared.",
|
||||
expected_output="Your best answer to your co-worker asking you this, accounting for the context shared.",
|
||||
)
|
||||
return agent.execute_task(task, context)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ast
|
||||
from difflib import SequenceMatcher
|
||||
from textwrap import dedent
|
||||
from typing import Any, List, Union
|
||||
|
||||
@@ -26,13 +27,13 @@ class ToolUsage:
|
||||
Class that represents the usage of a tool by an agent.
|
||||
|
||||
Attributes:
|
||||
task: Task being executed.
|
||||
tools_handler: Tools handler that will manage the tool usage.
|
||||
tools: List of tools available for the agent.
|
||||
original_tools: Original tools available for the agent before being converted to BaseTool.
|
||||
tools_description: Description of the tools available for the agent.
|
||||
tools_names: Names of the tools available for the agent.
|
||||
function_calling_llm: Language model to be used for the tool usage.
|
||||
task: Task being executed.
|
||||
tools_handler: Tools handler that will manage the tool usage.
|
||||
tools: List of tools available for the agent.
|
||||
original_tools: Original tools available for the agent before being converted to BaseTool.
|
||||
tools_description: Description of the tools available for the agent.
|
||||
tools_names: Names of the tools available for the agent.
|
||||
function_calling_llm: Language model to be used for the tool usage.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -63,7 +64,7 @@ class ToolUsage:
|
||||
|
||||
# Set the maximum parsing attempts for bigger models
|
||||
if (isinstance(self.function_calling_llm, ChatOpenAI)) and (
|
||||
self.function_calling_llm.openai_api_base == None
|
||||
self.function_calling_llm.openai_api_base is None
|
||||
):
|
||||
if self.function_calling_llm.model_name in OPENAI_BIGGER_MODELS:
|
||||
self._max_parsing_attempts = 2
|
||||
@@ -81,6 +82,8 @@ class ToolUsage:
|
||||
self._printer.print(content=f"\n\n{error}\n", color="red")
|
||||
self.task.increment_tools_errors()
|
||||
return error
|
||||
|
||||
# BUG? The code below seems to be unreachable
|
||||
try:
|
||||
tool = self._select_tool(calling.tool_name)
|
||||
except Exception as e:
|
||||
@@ -88,34 +91,35 @@ class ToolUsage:
|
||||
self.task.increment_tools_errors()
|
||||
self._printer.print(content=f"\n\n{error}\n", color="red")
|
||||
return error
|
||||
return f"{self._use(tool_string=tool_string, tool=tool, calling=calling)}"
|
||||
return f"{self._use(tool_string=tool_string, tool=tool, calling=calling)}" # type: ignore # BUG?: "_use" of "ToolUsage" does not return a value (it only ever returns None)
|
||||
|
||||
def _use(
|
||||
self,
|
||||
tool_string: str,
|
||||
tool: BaseTool,
|
||||
calling: Union[ToolCalling, InstructorToolCalling],
|
||||
) -> None:
|
||||
if self._check_tool_repeated_usage(calling=calling):
|
||||
) -> None: # TODO: Fix this return type
|
||||
if self._check_tool_repeated_usage(calling=calling): # type: ignore # _check_tool_repeated_usage of "ToolUsage" does not return a value (it only ever returns None)
|
||||
try:
|
||||
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,
|
||||
attempts=self._run_attempts,
|
||||
)
|
||||
result = self._format_result(result=result)
|
||||
return result
|
||||
result = self._format_result(result=result) # type: ignore # "_format_result" of "ToolUsage" does not return a value (it only ever returns None)
|
||||
return result # type: ignore # Fix the reutrn type of this function
|
||||
|
||||
except Exception:
|
||||
self.task.increment_tools_errors()
|
||||
|
||||
result = None
|
||||
result = None # type: ignore # Incompatible types in assignment (expression has type "None", variable has type "str")
|
||||
|
||||
if self.tools_handler.cache:
|
||||
result = self.tools_handler.cache.read(
|
||||
result = self.tools_handler.cache.read( # type: ignore # Incompatible types in assignment (expression has type "str | None", variable has type "str")
|
||||
tool=calling.tool_name, input=calling.arguments
|
||||
)
|
||||
|
||||
@@ -129,7 +133,7 @@ class ToolUsage:
|
||||
|
||||
if calling.arguments:
|
||||
try:
|
||||
acceptable_args = tool.args_schema.schema()["properties"].keys()
|
||||
acceptable_args = tool.args_schema.schema()["properties"].keys() # type: ignore # Item "None" of "type[BaseModel] | None" has no attribute "schema"
|
||||
arguments = {
|
||||
k: v
|
||||
for k, v in calling.arguments.items()
|
||||
@@ -141,7 +145,7 @@ class ToolUsage:
|
||||
arguments = calling.arguments
|
||||
result = tool._run(**arguments)
|
||||
else:
|
||||
arguments = calling.arguments.values()
|
||||
arguments = calling.arguments.values() # type: ignore # Incompatible types in assignment (expression has type "dict_values[str, Any]", variable has type "dict[str, Any]")
|
||||
result = tool._run(*arguments)
|
||||
else:
|
||||
result = tool._run()
|
||||
@@ -157,9 +161,10 @@ class ToolUsage:
|
||||
).message
|
||||
self.task.increment_tools_errors()
|
||||
self._printer.print(content=f"\n\n{error_message}\n", color="red")
|
||||
return error
|
||||
return error # type: ignore # No return value expected
|
||||
|
||||
self.task.increment_tools_errors()
|
||||
return self.use(calling=calling, tool_string=tool_string)
|
||||
return self.use(calling=calling, tool_string=tool_string) # type: ignore # No return value expected
|
||||
|
||||
if self.tools_handler:
|
||||
should_cache = True
|
||||
@@ -168,9 +173,9 @@ class ToolUsage:
|
||||
)
|
||||
if (
|
||||
hasattr(original_tool, "cache_function")
|
||||
and original_tool.cache_function
|
||||
and original_tool.cache_function # type: ignore # Item "None" of "Any | None" has no attribute "cache_function"
|
||||
):
|
||||
should_cache = original_tool.cache_function(
|
||||
should_cache = original_tool.cache_function( # type: ignore # Item "None" of "Any | None" has no attribute "cache_function"
|
||||
calling.arguments, result
|
||||
)
|
||||
|
||||
@@ -178,19 +183,19 @@ 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,
|
||||
attempts=self._run_attempts,
|
||||
)
|
||||
result = self._format_result(result=result)
|
||||
return result
|
||||
result = self._format_result(result=result) # type: ignore # "_format_result" of "ToolUsage" does not return a value (it only ever returns None)
|
||||
return result # type: ignore # No return value expected
|
||||
|
||||
def _format_result(self, result: Any) -> None:
|
||||
self.task.used_tools += 1
|
||||
if self._should_remember_format():
|
||||
result = self._remember_format(result=result)
|
||||
if self._should_remember_format(): # type: ignore # "_should_remember_format" of "ToolUsage" does not return a value (it only ever returns None)
|
||||
result = self._remember_format(result=result) # type: ignore # "_remember_format" of "ToolUsage" does not return a value (it only ever returns None)
|
||||
return result
|
||||
|
||||
def _should_remember_format(self) -> None:
|
||||
@@ -201,26 +206,39 @@ class ToolUsage:
|
||||
result += "\n\n" + self._i18n.slice("tools").format(
|
||||
tools=self.tools_description, tool_names=self.tools_names
|
||||
)
|
||||
return result
|
||||
return result # type: ignore # No return value expected
|
||||
|
||||
def _check_tool_repeated_usage(
|
||||
self, calling: Union[ToolCalling, InstructorToolCalling]
|
||||
) -> None:
|
||||
if not self.tools_handler:
|
||||
return False
|
||||
return False # type: ignore # No return value expected
|
||||
if last_tool_usage := self.tools_handler.last_used_tool:
|
||||
return (calling.tool_name == last_tool_usage.tool_name) and (
|
||||
return (calling.tool_name == last_tool_usage.tool_name) and ( # type: ignore # No return value expected
|
||||
calling.arguments == last_tool_usage.arguments
|
||||
)
|
||||
|
||||
def _select_tool(self, tool_name: str) -> BaseTool:
|
||||
for tool in self.tools:
|
||||
if tool.name.lower().strip() == tool_name.lower().strip():
|
||||
order_tools = sorted(
|
||||
self.tools,
|
||||
key=lambda tool: SequenceMatcher(
|
||||
None, tool.name.lower().strip(), tool_name.lower().strip()
|
||||
).ratio(),
|
||||
reverse=True,
|
||||
)
|
||||
for tool in order_tools:
|
||||
if (
|
||||
tool.name.lower().strip() == tool_name.lower().strip()
|
||||
or SequenceMatcher(
|
||||
None, tool.name.lower().strip(), tool_name.lower().strip()
|
||||
).ratio()
|
||||
> 0.85
|
||||
):
|
||||
return tool
|
||||
self.task.increment_tools_errors()
|
||||
if tool_name and tool_name != "":
|
||||
raise Exception(
|
||||
f"Action '{tool_name}' don't exist, these are the only available Actions: {self.tools_description}"
|
||||
f"Action '{tool_name}' don't exist, these are the only available Actions:\n {self.tools_description}"
|
||||
)
|
||||
else:
|
||||
raise Exception(
|
||||
@@ -247,7 +265,7 @@ class ToolUsage:
|
||||
return "\n--\n".join(descriptions)
|
||||
|
||||
def _is_gpt(self, llm) -> bool:
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base == None
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base is None
|
||||
|
||||
def _tool_calling(
|
||||
self, tool_string: str
|
||||
@@ -260,17 +278,17 @@ class ToolUsage:
|
||||
else ToolCalling
|
||||
)
|
||||
converter = Converter(
|
||||
text=f"Only tools available:\n###\n{self._render()}\n\nReturn a valid schema for the tool, the tool name must be exactly equal one of the options, use this text to inform the valid ouput schema:\n\n{tool_string}```",
|
||||
text=f"Only tools available:\n###\n{self._render()}\n\nReturn a valid schema for the tool, the tool name must be exactly equal one of the options, use this text to inform the valid output schema:\n\n{tool_string}```",
|
||||
llm=self.function_calling_llm,
|
||||
model=model,
|
||||
instructions=dedent(
|
||||
"""\
|
||||
The schema should have the following structure, only two keys:
|
||||
- tool_name: str
|
||||
- arguments: dict (with all arguments being passed)
|
||||
The schema should have the following structure, only two keys:
|
||||
- tool_name: str
|
||||
- arguments: dict (with all arguments being passed)
|
||||
|
||||
Example:
|
||||
{"tool_name": "tool name", "arguments": {"arg_name1": "value", "arg_name2": 2}}""",
|
||||
Example:
|
||||
{"tool_name": "tool name", "arguments": {"arg_name1": "value", "arg_name2": 2}}""",
|
||||
),
|
||||
max_attemps=1,
|
||||
)
|
||||
@@ -282,16 +300,17 @@ class ToolUsage:
|
||||
tool_name = self.action.tool
|
||||
tool = self._select_tool(tool_name)
|
||||
try:
|
||||
arguments = ast.literal_eval(self.action.tool_input)
|
||||
tool_input = self._validate_tool_input(self.action.tool_input)
|
||||
arguments = ast.literal_eval(tool_input)
|
||||
except Exception:
|
||||
return ToolUsageErrorException(
|
||||
return ToolUsageErrorException( # type: ignore # Incompatible return value type (got "ToolUsageErrorException", expected "ToolCalling | InstructorToolCalling")
|
||||
f'{self._i18n.errors("tool_arguments_error")}'
|
||||
)
|
||||
if not isinstance(arguments, dict):
|
||||
return ToolUsageErrorException(
|
||||
return ToolUsageErrorException( # type: ignore # Incompatible return value type (got "ToolUsageErrorException", expected "ToolCalling | InstructorToolCalling")
|
||||
f'{self._i18n.errors("tool_arguments_error")}'
|
||||
)
|
||||
calling = ToolCalling(
|
||||
calling = ToolCalling( # type: ignore # Unexpected keyword argument "log" for "ToolCalling"
|
||||
tool_name=tool.name,
|
||||
arguments=arguments,
|
||||
log=tool_string,
|
||||
@@ -302,9 +321,60 @@ class ToolUsage:
|
||||
self._telemetry.tool_usage_error(llm=self.function_calling_llm)
|
||||
self.task.increment_tools_errors()
|
||||
self._printer.print(content=f"\n\n{e}\n", color="red")
|
||||
return ToolUsageErrorException(
|
||||
return ToolUsageErrorException( # type: ignore # Incompatible return value type (got "ToolUsageErrorException", expected "ToolCalling | InstructorToolCalling")
|
||||
f'{self._i18n.errors("tool_usage_error").format(error=e)}\nMoving on then. {self._i18n.slice("format").format(tool_names=self.tools_names)}'
|
||||
)
|
||||
return self._tool_calling(tool_string)
|
||||
|
||||
return calling
|
||||
|
||||
def _validate_tool_input(self, tool_input: str) -> str:
|
||||
try:
|
||||
ast.literal_eval(tool_input)
|
||||
return tool_input
|
||||
except Exception:
|
||||
# Clean and ensure the string is properly enclosed in braces
|
||||
tool_input = tool_input.strip()
|
||||
if not tool_input.startswith("{"):
|
||||
tool_input = "{" + tool_input
|
||||
if not tool_input.endswith("}"):
|
||||
tool_input += "}"
|
||||
|
||||
# Manually split the input into key-value pairs
|
||||
entries = tool_input.strip("{} ").split(",")
|
||||
formatted_entries = []
|
||||
|
||||
for entry in entries:
|
||||
if ":" not in entry:
|
||||
continue # Skip malformed entries
|
||||
key, value = entry.split(":", 1)
|
||||
|
||||
# Remove extraneous white spaces and quotes, replace single quotes
|
||||
key = key.strip().strip('"').replace("'", '"')
|
||||
value = value.strip()
|
||||
|
||||
# Handle replacement of single quotes at the start and end of the value string
|
||||
if value.startswith("'") and value.endswith("'"):
|
||||
value = value[1:-1] # Remove single quotes
|
||||
value = (
|
||||
'"' + value.replace('"', '\\"') + '"'
|
||||
) # Re-encapsulate with double quotes
|
||||
elif value.isdigit(): # Check if value is a digit, hence integer
|
||||
formatted_value = value
|
||||
elif value.lower() in [
|
||||
"true",
|
||||
"false",
|
||||
"null",
|
||||
]: # Check for boolean and null values
|
||||
formatted_value = value.lower()
|
||||
else:
|
||||
# Assume the value is a string and needs quotes
|
||||
formatted_value = '"' + value.replace('"', '\\"') + '"'
|
||||
|
||||
# Rebuild the entry with proper quoting
|
||||
formatted_entry = f'"{key}": {formatted_value}'
|
||||
formatted_entries.append(formatted_entry)
|
||||
|
||||
# Reconstruct the JSON string
|
||||
new_json_string = "{" + ", ".join(formatted_entries) + "}"
|
||||
return new_json_string
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
},
|
||||
"slices": {
|
||||
"observation": "\nObservation",
|
||||
"task": "\nCurrent Task: {input}\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: ",
|
||||
"task": "\nCurrent Task: {input}\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:",
|
||||
"memory": "\n\n# Useful context: \n{memory}",
|
||||
"role_playing": "You are {role}. {backstory}\nYour personal goal is: {goal}",
|
||||
"tools": "\nYou ONLY have access to the following tools, and should NEVER make up tools that are not listed here:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, only one name of [{tool_names}], just the name, exactly as it's written.\nAction Input: the input to the action, just a simple a python dictionary using \" to wrap keys and values.\nObservation: the result of the action\n\nOnce all necessary information is gathered:\n\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n",
|
||||
"tools": "\nYou ONLY have access to the following tools, and should NEVER make up tools that are not listed here:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, only one name of [{tool_names}], just the name, exactly as it's written.\nAction Input: the input to the action, just a simple a python dictionary, enclosed in curly braces, using \" to wrap keys and values.\nObservation: the result of the action\n\nOnce all necessary information is gathered:\n\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n",
|
||||
"no_tools": "To 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!",
|
||||
"format": "I MUST either use a tool (use one at time) OR give my best final answer. To Use the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: the input to the action, dictionary\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\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\n ",
|
||||
"format": "I MUST either use a tool (use one at time) OR give my best final answer. To Use the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: the input to the action, dictionary enclosed in curly braces\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\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\n ",
|
||||
"final_answer_format": "If you don't need to use any more tools, you must give your best complete final answer, make sure it satisfy the expect criteria, use the EXACT format below:\n\nThought: I now can give a great answer\nFinal Answer: my best complete final answer to the task.\n\n",
|
||||
"format_without_tools": "\nSorry, I didn't use the right format. I MUST either use a tool (among the available ones), OR give my best final answer.\nI just remembered the expected format I must follow:\n\nQuestion: the input question you must answer\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\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\n",
|
||||
"task_with_context": "{task}\n\nThis is the context you're working with:\n{context}",
|
||||
@@ -20,7 +20,6 @@
|
||||
"getting_input": "This is the agent final answer: {final_answer}\nPlease provide a feedback: "
|
||||
},
|
||||
"errors": {
|
||||
"unexpected_format": "\nSorry, I didn't use the expected format, I MUST either use a tool (use one at time) OR give my best final answer.\n",
|
||||
"force_final_answer": "Tool won't be use because it's time to give your final answer. Don't use tools and just your absolute BEST Final answer.",
|
||||
"agent_tool_unexsiting_coworker": "\nError executing tool. Co-worker mentioned not found, it must to be one of the following options:\n{coworkers}\n",
|
||||
"task_repeated_usage": "I tried reusing the same input, I must stop using this action input. I'll try something else instead.\n\n",
|
||||
@@ -30,7 +29,7 @@
|
||||
"tool_usage_exception": "I encountered an error while trying to use the tool. This was the error: {error}.\n Tool {tool} accepts these inputs: {tool_inputs}"
|
||||
},
|
||||
"tools": {
|
||||
"delegate_work": "Delegate a specific task to one of the following co-workers: {coworkers}\nThe input to this tool should be the coworker, the task you want them to do, and ALL necessary context to exectue the task, they know nothing about the task, so share absolute everything you know, don't reference things but instead explain them.",
|
||||
"ask_question": "Ask a specific question to one of the following co-workers: {coworkers}\nThe input to this tool should be the coworker, the question you have for them, and ALL necessary context to ask the question properly, they know nothing about the question, so share absolute everything you know, don't reference things but instead explain them."
|
||||
"delegate_work": "Delegate a specific task to one of the following co-workers: {coworkers}\nThe input to this tool should be the co-worker, the task you want them to do, and ALL necessary context to execute the task, they know nothing about the task, so share absolute everything you know, don't reference things but instead explain them.",
|
||||
"ask_question": "Ask a specific question to one of the following co-workers: {coworkers}\nThe input to this tool should be the co-worker, the question you have for them, and ALL necessary context to ask the question properly, they know nothing about the question, so share absolute everything you know, don't reference things but instead explain them."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,5 @@ from .logger import Logger
|
||||
from .printer import Printer
|
||||
from .prompts import Prompts
|
||||
from .rpm_controller import RPMController
|
||||
from .fileHandler import FileHandler
|
||||
from .parser import YamlParser
|
||||
|
||||
@@ -83,5 +83,5 @@ class Converter(BaseModel):
|
||||
)
|
||||
return new_prompt | self.llm | parser
|
||||
|
||||
def _is_gpt(self, llm) -> bool:
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base == None
|
||||
def _is_gpt(self, llm) -> bool: # type: ignore # BUG? Name "_is_gpt" defined on line 20 hides name from outer scope
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base is None
|
||||
|
||||
@@ -58,4 +58,4 @@ class TaskEvaluator:
|
||||
return converter.to_pydantic()
|
||||
|
||||
def _is_gpt(self, llm) -> bool:
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base == None
|
||||
return isinstance(llm, ChatOpenAI) and llm.openai_api_base is None
|
||||
|
||||
20
src/crewai/utilities/fileHandler.py
Normal file
20
src/crewai/utilities/fileHandler.py
Normal 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")
|
||||
@@ -2,44 +2,36 @@ import json
|
||||
import os
|
||||
from typing import Dict, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, PrivateAttr, ValidationError, model_validator
|
||||
from pydantic import BaseModel, Field, PrivateAttr, model_validator
|
||||
|
||||
|
||||
class I18N(BaseModel):
|
||||
_translations: Dict[str, Dict[str, str]] = PrivateAttr()
|
||||
language_file: Optional[str] = Field(
|
||||
_prompts: Dict[str, Dict[str, str]] = PrivateAttr()
|
||||
prompt_file: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Path to the translation file to load",
|
||||
)
|
||||
language: Optional[str] = Field(
|
||||
default="en",
|
||||
description="Language used to load translations",
|
||||
description="Path to the prompt_file file to load",
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def load_translation(self) -> "I18N":
|
||||
"""Load translations from a JSON file based on the specified language."""
|
||||
def load_prompts(self) -> "I18N":
|
||||
"""Load prompts from a JSON file."""
|
||||
try:
|
||||
if self.language_file:
|
||||
with open(self.language_file, "r") as f:
|
||||
self._translations = json.load(f)
|
||||
if self.prompt_file:
|
||||
with open(self.prompt_file, "r") as f:
|
||||
self._prompts = json.load(f)
|
||||
else:
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
prompts_path = os.path.join(
|
||||
dir_path, f"../translations/{self.language}.json"
|
||||
)
|
||||
prompts_path = os.path.join(dir_path, "../translations/en.json")
|
||||
|
||||
with open(prompts_path, "r") as f:
|
||||
self._translations = json.load(f)
|
||||
self._prompts = json.load(f)
|
||||
except FileNotFoundError:
|
||||
raise ValidationError(
|
||||
f"Translation file for language '{self.language}' not found."
|
||||
)
|
||||
raise Exception(f"Prompt file '{self.prompt_file}' not found.")
|
||||
except json.JSONDecodeError:
|
||||
raise ValidationError(f"Error decoding JSON from the prompts file.")
|
||||
raise Exception("Error decoding JSON from the prompts file.")
|
||||
|
||||
if not self._translations:
|
||||
self._translations = {}
|
||||
if not self._prompts:
|
||||
self._prompts = {}
|
||||
|
||||
return self
|
||||
|
||||
@@ -54,6 +46,6 @@ class I18N(BaseModel):
|
||||
|
||||
def retrieve(self, kind, key) -> str:
|
||||
try:
|
||||
return self._translations[kind][key]
|
||||
except:
|
||||
raise ValidationError(f"Translation for '{kind}':'{key}' not found.")
|
||||
return self._prompts[kind][key]
|
||||
except Exception as _:
|
||||
raise Exception(f"Prompt for '{kind}':'{key}' not found.")
|
||||
|
||||
17
src/crewai/utilities/parser.py
Normal file
17
src/crewai/utilities/parser.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import re
|
||||
|
||||
|
||||
class YamlParser:
|
||||
def parse(file):
|
||||
content = file.read()
|
||||
# Replace single { and } with doubled ones, while leaving already doubled ones intact and the other special characters {# and {%
|
||||
modified_content = re.sub(r"(?<!\{){(?!\{)(?!\#)(?!\%)", "{{", content)
|
||||
modified_content = re.sub(
|
||||
r"(?<!\})(?<!\%)(?<!\#)\}(?!})", "}}", modified_content
|
||||
)
|
||||
# Check for 'context:' not followed by '[' and raise an error
|
||||
if re.search(r"context:(?!\s*\[)", modified_content):
|
||||
raise ValueError(
|
||||
"Context is currently only supported in code when creating a task. Please use the 'context' key in the task configuration."
|
||||
)
|
||||
return modified_content
|
||||
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import appdirs
|
||||
@@ -13,6 +14,11 @@ def db_storage_path():
|
||||
|
||||
|
||||
def get_project_directory_name():
|
||||
cwd = Path.cwd()
|
||||
project_directory_name = cwd.name
|
||||
return project_directory_name
|
||||
project_directory_name = os.environ.get("CREWAI_STORAGE_DIR")
|
||||
|
||||
if project_directory_name:
|
||||
return project_directory_name
|
||||
else:
|
||||
cwd = Path.cwd()
|
||||
project_directory_name = cwd.name
|
||||
return project_directory_name
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, ClassVar
|
||||
from typing import Any, ClassVar, Optional
|
||||
|
||||
from langchain.prompts import BasePromptTemplate, PromptTemplate
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -7,16 +7,15 @@ from crewai.utilities import I18N
|
||||
|
||||
|
||||
class Prompts(BaseModel):
|
||||
"""Manages and generates prompts for a generic agent with support for different languages."""
|
||||
"""Manages and generates prompts for a generic agent."""
|
||||
|
||||
i18n: I18N = Field(default=I18N())
|
||||
tools: list[Any] = Field(default=[])
|
||||
system_template: Optional[str] = None
|
||||
prompt_template: Optional[str] = None
|
||||
response_template: Optional[str] = None
|
||||
SCRATCHPAD_SLICE: ClassVar[str] = "\n{agent_scratchpad}"
|
||||
|
||||
def task_execution_without_tools(self) -> BasePromptTemplate:
|
||||
"""Generate a prompt for task execution without tools components."""
|
||||
return self._build_prompt(["role_playing", "task"])
|
||||
|
||||
def task_execution(self) -> BasePromptTemplate:
|
||||
"""Generate a standard prompt for task execution."""
|
||||
slices = ["role_playing"]
|
||||
@@ -24,12 +23,42 @@ class Prompts(BaseModel):
|
||||
slices.append("tools")
|
||||
else:
|
||||
slices.append("no_tools")
|
||||
slices.append("task")
|
||||
return self._build_prompt(slices)
|
||||
|
||||
def _build_prompt(self, components: list[str]) -> BasePromptTemplate:
|
||||
slices.append("task")
|
||||
|
||||
if not self.system_template and not self.prompt_template:
|
||||
return self._build_prompt(slices)
|
||||
else:
|
||||
return self._build_prompt(
|
||||
slices,
|
||||
self.system_template,
|
||||
self.prompt_template,
|
||||
self.response_template,
|
||||
)
|
||||
|
||||
def _build_prompt(
|
||||
self,
|
||||
components: list[str],
|
||||
system_template=None,
|
||||
prompt_template=None,
|
||||
response_template=None,
|
||||
) -> BasePromptTemplate:
|
||||
"""Constructs a prompt string from specified components."""
|
||||
prompt_parts = [self.i18n.slice(component) for component in components]
|
||||
prompt_parts.append(self.SCRATCHPAD_SLICE)
|
||||
prompt = PromptTemplate.from_template("".join(prompt_parts))
|
||||
if not system_template and not prompt_template:
|
||||
prompt_parts = [self.i18n.slice(component) for component in components]
|
||||
prompt_parts.append(self.SCRATCHPAD_SLICE)
|
||||
prompt = PromptTemplate.from_template("".join(prompt_parts))
|
||||
else:
|
||||
prompt_parts = [
|
||||
self.i18n.slice(component)
|
||||
for component in components
|
||||
if component != "task"
|
||||
]
|
||||
system = system_template.replace("{{ .System }}", "".join(prompt_parts))
|
||||
prompt = prompt_template.replace(
|
||||
"{{ .Prompt }}",
|
||||
"".join([self.i18n.slice("task"), self.SCRATCHPAD_SLICE]),
|
||||
)
|
||||
response = response_template.split("{{ .Response }}")[0]
|
||||
prompt = PromptTemplate.from_template(f"{system}\n{prompt}\n{response}")
|
||||
return prompt
|
||||
|
||||
@@ -22,7 +22,7 @@ class TokenProcess:
|
||||
def sum_successful_requests(self, requests: int):
|
||||
self.successful_requests = self.successful_requests + requests
|
||||
|
||||
def get_summary(self) -> str:
|
||||
def get_summary(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"total_tokens": self.total_tokens,
|
||||
"prompt_tokens": self.prompt_tokens,
|
||||
@@ -42,12 +42,12 @@ class TokenCalcHandler(BaseCallbackHandler):
|
||||
def on_llm_start(
|
||||
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
|
||||
) -> None:
|
||||
if "gpt" in self.model:
|
||||
try:
|
||||
encoding = tiktoken.encoding_for_model(self.model)
|
||||
else:
|
||||
except KeyError:
|
||||
encoding = tiktoken.get_encoding("cl100k_base")
|
||||
|
||||
if self.token_cost_process == None:
|
||||
if self.token_cost_process is None:
|
||||
return
|
||||
|
||||
for prompt in prompts:
|
||||
|
||||
@@ -31,8 +31,8 @@ def test_agent_default_values():
|
||||
assert isinstance(agent.llm, ChatOpenAI)
|
||||
assert agent.llm.model_name == "gpt-4"
|
||||
assert agent.llm.temperature == 0.7
|
||||
assert agent.llm.verbose == False
|
||||
assert agent.allow_delegation == True
|
||||
assert agent.llm.verbose is False
|
||||
assert agent.allow_delegation is True
|
||||
|
||||
|
||||
def test_custom_llm():
|
||||
@@ -751,9 +751,10 @@ def test_agent_definition_based_on_dict():
|
||||
assert agent.role == "test role"
|
||||
assert agent.goal == "test goal"
|
||||
assert agent.backstory == "test backstory"
|
||||
assert agent.verbose == True
|
||||
assert agent.verbose is True
|
||||
assert agent.tools == []
|
||||
|
||||
|
||||
# test for human input
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_agent_human_input():
|
||||
@@ -780,6 +781,7 @@ def test_agent_human_input():
|
||||
mock_human_input.assert_called_once()
|
||||
assert output == "Hello"
|
||||
|
||||
|
||||
def test_interpolate_inputs():
|
||||
agent = Agent(
|
||||
role="{topic} specialist",
|
||||
@@ -797,3 +799,46 @@ def test_interpolate_inputs():
|
||||
assert agent.goal == "Figure stuff out"
|
||||
assert agent.backstory == "I am the master of nothing"
|
||||
|
||||
|
||||
def test_system_and_prompt_template():
|
||||
agent = Agent(
|
||||
role="{topic} specialist",
|
||||
goal="Figure {goal} out",
|
||||
backstory="I am the master of {role}",
|
||||
system_template="""<|start_header_id|>system<|end_header_id|>
|
||||
|
||||
{{ .System }}<|eot_id|>""",
|
||||
prompt_template="""<|start_header_id|>user<|end_header_id|>
|
||||
|
||||
{{ .Prompt }}<|eot_id|>""",
|
||||
response_template="""<|start_header_id|>assistant<|end_header_id|>
|
||||
|
||||
{{ .Response }}<|eot_id|>""",
|
||||
)
|
||||
|
||||
template = agent.agent_executor.agent.dict()["runnable"]["middle"][0]["template"]
|
||||
assert (
|
||||
template
|
||||
== """<|start_header_id|>system<|end_header_id|>
|
||||
|
||||
You are {role}. {backstory}
|
||||
Your personal goal is: {goal}To give my best complete final answer to the task use the exact following format:
|
||||
|
||||
Thought: I now can give a great answer
|
||||
Final Answer: my best complete final answer to the task.
|
||||
Your final answer must be the great and the most complete as possible, it must be outcome described.
|
||||
|
||||
I MUST use these formats, my job depends on it!<|eot_id|>
|
||||
<|start_header_id|>user<|end_header_id|>
|
||||
|
||||
|
||||
Current Task: {input}
|
||||
|
||||
Begin! This is VERY important to you, use the tools available and give your best Final Answer, your job depends on it!
|
||||
|
||||
Thought:
|
||||
{agent_scratchpad}<|eot_id|>
|
||||
<|start_header_id|>assistant<|end_header_id|>
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -28,6 +28,20 @@ def test_delegate_work():
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_delegate_work_with_wrong_co_worker_variable():
|
||||
result = tools.delegate_work(
|
||||
co_worker="researcher",
|
||||
task="share your take on AI Agents",
|
||||
context="I heard you hate them",
|
||||
)
|
||||
|
||||
assert (
|
||||
result
|
||||
== "AI Agents are essentially computer programs that are designed to perform tasks autonomously, with the ability to adapt and learn from their environment. These tasks range from simple ones such as setting alarms, to more complex ones like diagnosing diseases or driving cars. AI agents have the potential to revolutionize many industries, making processes more efficient and accurate. \n\nHowever, like any technology, AI agents have their downsides. They can be susceptible to biases based on the data they're trained on and they can also raise privacy concerns. Moreover, the widespread adoption of AI agents could result in significant job displacement in certain industries.\n\nDespite these concerns, it's important to note that the development and use of AI agents are heavily dependent on human decisions and policies. Therefore, the key to harnessing the benefits of AI agents while mitigating the risks lies in responsible and thoughtful development and implementation.\n\nWhether one 'loves' or 'hates' AI agents often comes down to individual perspectives and experiences. But as a researcher, it is my job to provide balanced and factual information, so I hope this explanation helps you understand better what AI Agents are and the implications they have."
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_ask_question():
|
||||
result = tools.ask_question(
|
||||
@@ -41,6 +55,46 @@ def test_ask_question():
|
||||
== "As an AI researcher, I don't have personal feelings or emotions like love or hate. However, I recognize the importance of AI Agents in today's technological landscape. They have the potential to greatly enhance our lives and make tasks more efficient. At the same time, it is crucial to consider the ethical implications and societal impacts that come with their use. My role is to provide objective research and analysis on these topics."
|
||||
)
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_ask_question_with_wrong_co_worker_variable():
|
||||
result = tools.ask_question(
|
||||
co_worker="researcher",
|
||||
question="do you hate AI Agents?",
|
||||
context="I heard you LOVE them",
|
||||
)
|
||||
|
||||
assert (
|
||||
result
|
||||
== "No, I don't hate AI agents. In fact, I find them quite fascinating. They are powerful tools that can greatly assist in various tasks, including my research. As a technology researcher, AI and AI agents are subjects of interest to me due to their potential in advancing our understanding and capabilities in various fields. My supposed love for them stems from this professional interest and the potential they hold."
|
||||
)
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_delegate_work_withwith_coworker_as_array():
|
||||
result = tools.delegate_work(
|
||||
co_worker="[researcher]",
|
||||
task="share your take on AI Agents",
|
||||
context="I heard you hate them",
|
||||
)
|
||||
|
||||
assert (
|
||||
result
|
||||
== "AI Agents are software entities which operate in an environment to achieve a particular goal. They can perceive their environment, reason about it, and take actions to fulfill their objectives. This includes everything from chatbots to self-driving cars. They are designed to act autonomously to a certain extent and are capable of learning from their experiences to improve their performance over time.\n\nDespite some people's fears or dislikes, AI Agents are not inherently good or bad. They are tools, and like any tool, their value depends on how they are used. For instance, AI Agents can be used to automate repetitive tasks, provide customer support, or analyze vast amounts of data far more quickly and accurately than a human could. They can also be used in ways that invade privacy or replace jobs, which is often where the apprehension comes from.\n\nThe key is to create regulations and ethical guidelines for the use of AI Agents, and to continue researching and developing them in a way that maximizes their benefits and minimizes their potential harm. From a research perspective, there's a lot of potential in AI Agents, and it's a fascinating field to be a part of."
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_ask_question_with_coworker_as_array():
|
||||
result = tools.ask_question(
|
||||
co_worker="[researcher]",
|
||||
question="do you hate AI Agents?",
|
||||
context="I heard you LOVE them",
|
||||
)
|
||||
|
||||
assert (
|
||||
result
|
||||
== "I don't hate or love AI agents. My passion lies in understanding them, researching about their capabilities, implications, and potential for development. As a researcher, my feelings toward AI are more of fascination and interest rather than personal love or hate."
|
||||
)
|
||||
|
||||
|
||||
def test_delegate_work_to_wrong_agent():
|
||||
result = tools.ask_question(
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"messages": [{"role": "user", "content": "You are researcher. You''re
|
||||
an expert researcher, specialized in technology\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: do you hate AI Agents?\n\nThis is the expect criteria for
|
||||
your final answer: Your best answer to your co-worker asking you this, accounting
|
||||
for the context shared. \n you MUST return the actual complete content as the
|
||||
final answer, not a summary.\n\nThis is the context you''re working with:\nI
|
||||
heard you LOVE them\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:
|
||||
- '1103'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- _cfuvid=r7d0l_hEOM639ffTY.owt.2ZeXQN7IgsM0JmFM6FEiE-1715576040584-0.0.1.1-604800000;
|
||||
__cf_bm=bHXznnX6IEnPWC4UFqVw22jiTLBlLvClKsTW4F99UPc-1715613132-1.0.1.1-5k2TYkm6.lsjrA1MkQ4uD2GxUGKPmwNVeYL_sKTpAPJ_trVvN3.uNZS4HljKfVPlku1XDNCYfU4y43hlt3e.RQ
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.25.1
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.25.1
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.11.7
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: 'data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"As"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
a"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
researcher"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
specialized"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
in"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
technology"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
specifically"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
AI"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
and"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
AI"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
agents"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
my"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
personal"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
feelings"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
towards"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
them"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
are"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
not"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
based"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
on"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
emotion"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
but"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
on"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
professional"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
interest"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
and"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
intellectual"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
curiosity"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
\n\n"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"Final"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
Answer"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
I"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
don"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"''t"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
hate"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
or"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
love"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
AI"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
agents"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
My"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
passion"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
lies"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
in"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
understanding"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
them"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
researching"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
about"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
their"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
capabilities"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
implications"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
and"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
potential"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
for"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
development"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
As"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
a"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
researcher"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
my"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
feelings"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
toward"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
AI"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
are"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
more"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
of"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
fascination"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
and"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
interest"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
rather"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
than"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
personal"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
love"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
or"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
hate"},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-9ORdkG4FJphn6RbqXUgZlUbRtXBIO","object":"chat.completion.chunk","created":1715613148,"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:
|
||||
- 883396429922624c-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- text/event-stream; charset=utf-8
|
||||
Date:
|
||||
- Mon, 13 May 2024 15:12:29 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '514'
|
||||
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:
|
||||
- '299745'
|
||||
x-ratelimit-reset-requests:
|
||||
- 6ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 50ms
|
||||
x-request-id:
|
||||
- req_5a62449ef9052c3a350f1b47f268bbcc
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ interactions:
|
||||
are not listed here:\n\nDelegate work to co-worker: Delegate work to co-worker(coworker:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [Researcher]\nThe input to this tool should be the coworker, the
|
||||
task you want them to do, and ALL necessary context to exectue the task, they
|
||||
task you want them to do, and ALL necessary context to execute the task, they
|
||||
know nothing about the task, so share absolute everything you know, don''t reference
|
||||
things but instead explain them.\nAsk question to co-worker: Ask question to
|
||||
co-worker(coworker: str, question: str, context: str) - Ask a specific question
|
||||
@@ -1030,7 +1030,7 @@ interactions:
|
||||
are not listed here:\n\nDelegate work to co-worker: Delegate work to co-worker(coworker:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [Researcher]\nThe input to this tool should be the coworker, the
|
||||
task you want them to do, and ALL necessary context to exectue the task, they
|
||||
task you want them to do, and ALL necessary context to execute the task, they
|
||||
know nothing about the task, so share absolute everything you know, don''t reference
|
||||
things but instead explain them.\nAsk question to co-worker: Ask question to
|
||||
co-worker(coworker: str, question: str, context: str) - Ask a specific question
|
||||
|
||||
@@ -6,7 +6,7 @@ interactions:
|
||||
co-worker: Delegate work to co-worker(coworker: str, task: str, context: str)
|
||||
- Delegate a specific task to one of the following co-workers: [''test role2'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -326,7 +326,7 @@ interactions:
|
||||
co-worker: Delegate work to co-worker(coworker: str, task: str, context: str)
|
||||
- Delegate a specific task to one of the following co-workers: [''test role2'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -351,7 +351,7 @@ interactions:
|
||||
Delegate work to co-worker(coworker: str, task: str, context: str) - Delegate
|
||||
a specific task to one of the following co-workers: [''test role2'']\nThe input
|
||||
to this tool should be the coworker, the task you want them to do, and ALL necessary
|
||||
context to exectue the task, they know nothing about the task, so share absolute
|
||||
context to execute the task, they know nothing about the task, so share absolute
|
||||
everything you know, don''t reference things but instead explain them.\nAsk
|
||||
question to co-worker: Ask question to co-worker(coworker: str, question: str,
|
||||
context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -1027,7 +1027,7 @@ interactions:
|
||||
co-worker: Delegate work to co-worker(coworker: str, task: str, context: str)
|
||||
- Delegate a specific task to one of the following co-workers: [''test role2'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -1052,7 +1052,7 @@ interactions:
|
||||
Delegate work to co-worker(coworker: str, task: str, context: str) - Delegate
|
||||
a specific task to one of the following co-workers: [''test role2'']\nThe input
|
||||
to this tool should be the coworker, the task you want them to do, and ALL necessary
|
||||
context to exectue the task, they know nothing about the task, so share absolute
|
||||
context to execute the task, they know nothing about the task, so share absolute
|
||||
everything you know, don''t reference things but instead explain them.\nAsk
|
||||
question to co-worker: Ask question to co-worker(coworker: str, question: str,
|
||||
context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -1236,7 +1236,7 @@ interactions:
|
||||
co-worker: Delegate work to co-worker(coworker: str, task: str, context: str)
|
||||
- Delegate a specific task to one of the following co-workers: [''test role2'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -1485,7 +1485,7 @@ interactions:
|
||||
co-worker: Delegate work to co-worker(coworker: str, task: str, context: str)
|
||||
- Delegate a specific task to one of the following co-workers: [''test role'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -2490,7 +2490,7 @@ interactions:
|
||||
co-worker: Delegate work to co-worker(coworker: str, task: str, context: str)
|
||||
- Delegate a specific task to one of the following co-workers: [''test role'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
|
||||
@@ -67,7 +67,7 @@ interactions:
|
||||
work to co-worker: Delegate work to co-worker(coworker: str, task: str, context:
|
||||
str) - Delegate a specific task to one of the following co-workers: [''Researcher'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
@@ -442,7 +442,7 @@ interactions:
|
||||
work to co-worker: Delegate work to co-worker(coworker: str, task: str, context:
|
||||
str) - Delegate a specific task to one of the following co-workers: [''Researcher'']\nThe
|
||||
input to this tool should be the coworker, the task you want them to do, and
|
||||
ALL necessary context to exectue the task, they know nothing about the task,
|
||||
ALL necessary context to execute the task, they know nothing about the task,
|
||||
so share absolute everything you know, don''t reference things but instead explain
|
||||
them.\nAsk question to co-worker: Ask question to co-worker(coworker: str, question:
|
||||
str, context: str) - Ask a specific question to one of the following co-workers:
|
||||
|
||||
@@ -324,7 +324,7 @@ interactions:
|
||||
Name: learn_about_ai\nTool Description: learn_about_AI(topic) -> float - Useful
|
||||
for when you need to learn about AI to write an paragraph about it.\nTool Arguments:
|
||||
{''topic'': {}}\n\nReturn a valid schema for the tool, the tool name must be
|
||||
exactly equal one of the options, use this text to inform the valid ouput schema:\n\nThought:
|
||||
exactly equal one of the options, use this text to inform the valid output schema:\n\nThought:
|
||||
Before I can write an amazing article about AI, I need to understand the basics
|
||||
of AI, its applications, and ethical considerations to ensure that the content
|
||||
is well-rounded and informative.\n\nAction: learn_about_AI\nAction Input: {\"topic\":
|
||||
@@ -854,7 +854,7 @@ interactions:
|
||||
Name: learn_about_ai\nTool Description: learn_about_AI(topic) -> float - Useful
|
||||
for when you need to learn about AI to write an paragraph about it.\nTool Arguments:
|
||||
{''topic'': {}}\n\nReturn a valid schema for the tool, the tool name must be
|
||||
exactly equal one of the options, use this text to inform the valid ouput schema:\n\nThought:
|
||||
exactly equal one of the options, use this text to inform the valid output schema:\n\nThought:
|
||||
Now that I know AI is a broad field, I should learn specifically about its applications
|
||||
to provide concrete examples in my article.\n\nAction: learn_about_AI\nAction
|
||||
Input: {\"topic\": \"applications of AI\"}```"}, {"role": "system", "content":
|
||||
@@ -1325,7 +1325,7 @@ interactions:
|
||||
Name: learn_about_ai\nTool Description: learn_about_AI(topic) -> float - Useful
|
||||
for when you need to learn about AI to write an paragraph about it.\nTool Arguments:
|
||||
{''topic'': {}}\n\nReturn a valid schema for the tool, the tool name must be
|
||||
exactly equal one of the options, use this text to inform the valid ouput schema:\n\nThought:
|
||||
exactly equal one of the options, use this text to inform the valid output schema:\n\nThought:
|
||||
It seems there was an error with the action input. I need to correct the format
|
||||
to ensure the tool works properly for gathering information on the applications
|
||||
of AI.\n\nAction: learn_about_AI\nAction Input: {\"topic\": \"applications of
|
||||
@@ -1807,7 +1807,7 @@ interactions:
|
||||
Name: learn_about_ai\nTool Description: learn_about_AI(topic) -> float - Useful
|
||||
for when you need to learn about AI to write an paragraph about it.\nTool Arguments:
|
||||
{''topic'': {}}\n\nReturn a valid schema for the tool, the tool name must be
|
||||
exactly equal one of the options, use this text to inform the valid ouput schema:\n\nThought:
|
||||
exactly equal one of the options, use this text to inform the valid output schema:\n\nThought:
|
||||
Having understood that AI is a broad field, and after the corrected attempt
|
||||
to learn about its applications, I realize I need more detailed insights into
|
||||
ethical considerations around AI to make sure the article covers a balanced
|
||||
|
||||
160
tests/cassettes/test_crew_log_file_output.yaml
Normal file
160
tests/cassettes/test_crew_log_file_output.yaml
Normal 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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,7 +86,7 @@ interactions:
|
||||
are not listed here:\n\nDelegate work to co-worker: Delegate work to co-worker(coworker:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Senior Writer'']\nThe input to this tool should be the coworker,
|
||||
the task you want them to do, and ALL necessary context to exectue the task,
|
||||
the task you want them to do, and ALL necessary context to execute the task,
|
||||
they know nothing about the task, so share absolute everything you know, don''t
|
||||
reference things but instead explain them.\nAsk question to co-worker: Ask question
|
||||
to co-worker(coworker: str, question: str, context: str) - Ask a specific question
|
||||
@@ -1716,7 +1716,7 @@ interactions:
|
||||
are not listed here:\n\nDelegate work to co-worker: Delegate work to co-worker(coworker:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Senior Writer'']\nThe input to this tool should be the coworker,
|
||||
the task you want them to do, and ALL necessary context to exectue the task,
|
||||
the task you want them to do, and ALL necessary context to execute the task,
|
||||
they know nothing about the task, so share absolute everything you know, don''t
|
||||
reference things but instead explain them.\nAsk question to co-worker: Ask question
|
||||
to co-worker(coworker: str, question: str, context: str) - Ask a specific question
|
||||
|
||||
@@ -67,7 +67,7 @@ interactions:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Researcher'', ''Senior Writer'']\nThe input to this tool should
|
||||
be the coworker, the task you want them to do, and ALL necessary context to
|
||||
exectue the task, they know nothing about the task, so share absolute everything
|
||||
execute the task, they know nothing about the task, so share absolute everything
|
||||
you know, don''t reference things but instead explain them.\nAsk question to
|
||||
co-worker: Ask question to co-worker(coworker: str, question: str, context:
|
||||
str) - Ask a specific question to one of the following co-workers: [''Researcher'',
|
||||
@@ -2448,7 +2448,7 @@ interactions:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Researcher'', ''Senior Writer'']\nThe input to this tool should
|
||||
be the coworker, the task you want them to do, and ALL necessary context to
|
||||
exectue the task, they know nothing about the task, so share absolute everything
|
||||
execute the task, they know nothing about the task, so share absolute everything
|
||||
you know, don''t reference things but instead explain them.\nAsk question to
|
||||
co-worker: Ask question to co-worker(coworker: str, question: str, context:
|
||||
str) - Ask a specific question to one of the following co-workers: [''Researcher'',
|
||||
@@ -5367,7 +5367,7 @@ interactions:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Researcher'', ''Senior Writer'']\nThe input to this tool should
|
||||
be the coworker, the task you want them to do, and ALL necessary context to
|
||||
exectue the task, they know nothing about the task, so share absolute everything
|
||||
execute the task, they know nothing about the task, so share absolute everything
|
||||
you know, don''t reference things but instead explain them.\nAsk question to
|
||||
co-worker: Ask question to co-worker(coworker: str, question: str, context:
|
||||
str) - Ask a specific question to one of the following co-workers: [''Researcher'',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,7 @@ interactions:
|
||||
are not listed here:\n\nDelegate work to co-worker: Delegate work to co-worker(coworker:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Scorer'']\nThe input to this tool should be the coworker, the
|
||||
task you want them to do, and ALL necessary context to exectue the task, they
|
||||
task you want them to do, and ALL necessary context to execute the task, they
|
||||
know nothing about the task, so share absolute everything you know, don''t reference
|
||||
things but instead explain them.\nAsk question to co-worker: Ask question to
|
||||
co-worker(coworker: str, question: str, context: str) - Ask a specific question
|
||||
@@ -3200,7 +3200,7 @@ interactions:
|
||||
are not listed here:\n\nDelegate work to co-worker: Delegate work to co-worker(coworker:
|
||||
str, task: str, context: str) - Delegate a specific task to one of the following
|
||||
co-workers: [''Scorer'']\nThe input to this tool should be the coworker, the
|
||||
task you want them to do, and ALL necessary context to exectue the task, they
|
||||
task you want them to do, and ALL necessary context to execute the task, they
|
||||
know nothing about the task, so share absolute everything you know, don''t reference
|
||||
things but instead explain them.\nAsk question to co-worker: Ask question to
|
||||
co-worker(coworker: str, question: str, context: str) - Ask a specific question
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
59
tests/cli/cli_test.py
Normal file
59
tests/cli/cli_test.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from crewai.cli.cli import train, version
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def runner():
|
||||
return CliRunner()
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.cli.train_crew")
|
||||
def test_train_default_iterations(train_crew, runner):
|
||||
result = runner.invoke(train)
|
||||
|
||||
train_crew.assert_called_once_with(5)
|
||||
assert result.exit_code == 0
|
||||
assert "Training the crew for 5 iterations" in result.output
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.cli.train_crew")
|
||||
def test_train_custom_iterations(train_crew, runner):
|
||||
result = runner.invoke(train, ["--n_iterations", "10"])
|
||||
|
||||
train_crew.assert_called_once_with(10)
|
||||
assert result.exit_code == 0
|
||||
assert "Training the crew for 10 iterations" in result.output
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.cli.train_crew")
|
||||
def test_train_invalid_string_iterations(train_crew, runner):
|
||||
result = runner.invoke(train, ["--n_iterations", "invalid"])
|
||||
|
||||
train_crew.assert_not_called()
|
||||
assert result.exit_code == 2
|
||||
assert (
|
||||
"Usage: train [OPTIONS]\nTry 'train --help' for help.\n\nError: Invalid value for '-n' / '--n_iterations': 'invalid' is not a valid integer.\n"
|
||||
in result.output
|
||||
)
|
||||
|
||||
|
||||
def test_version_command(runner):
|
||||
result = runner.invoke(version)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "crewai version:" in result.output
|
||||
|
||||
|
||||
def test_version_command_with_tools(runner):
|
||||
result = runner.invoke(version, ["--tools"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "crewai version:" in result.output
|
||||
assert (
|
||||
"crewai tools version:" in result.output
|
||||
or "crewai tools not installed" in result.output
|
||||
)
|
||||
87
tests/cli/train_crew_test.py
Normal file
87
tests/cli/train_crew_test.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import subprocess
|
||||
from unittest import mock
|
||||
|
||||
from crewai.cli.train_crew import train_crew
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.train_crew.subprocess.run")
|
||||
def test_train_crew_positive_iterations(mock_subprocess_run):
|
||||
# Arrange
|
||||
n_iterations = 5
|
||||
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
||||
args=["poetry", "run", "train", str(n_iterations)],
|
||||
returncode=0,
|
||||
stdout="Success",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
# Act
|
||||
train_crew(n_iterations)
|
||||
|
||||
# Assert
|
||||
mock_subprocess_run.assert_called_once_with(
|
||||
["poetry", "run", "train", str(n_iterations)],
|
||||
capture_output=False,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.train_crew.click")
|
||||
def test_train_crew_zero_iterations(click):
|
||||
train_crew(0)
|
||||
click.echo.assert_called_once_with(
|
||||
"An unexpected error occurred: The number of iterations must be a positive integer.",
|
||||
err=True,
|
||||
)
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.train_crew.click")
|
||||
def test_train_crew_negative_iterations(click):
|
||||
train_crew(-2)
|
||||
click.echo.assert_called_once_with(
|
||||
"An unexpected error occurred: The number of iterations must be a positive integer.",
|
||||
err=True,
|
||||
)
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.train_crew.click")
|
||||
@mock.patch("crewai.cli.train_crew.subprocess.run")
|
||||
def test_train_crew_called_process_error(mock_subprocess_run, click):
|
||||
n_iterations = 5
|
||||
mock_subprocess_run.side_effect = subprocess.CalledProcessError(
|
||||
returncode=1,
|
||||
cmd=["poetry", "run", "train", str(n_iterations)],
|
||||
output="Error",
|
||||
stderr="Some error occurred",
|
||||
)
|
||||
train_crew(n_iterations)
|
||||
|
||||
mock_subprocess_run.assert_called_once_with(
|
||||
["poetry", "run", "train", "5"], capture_output=False, text=True, check=True
|
||||
)
|
||||
click.echo.assert_has_calls(
|
||||
[
|
||||
mock.call.echo(
|
||||
"An error occurred while training the crew: Command '['poetry', 'run', 'train', '5']' returned non-zero exit status 1.",
|
||||
err=True,
|
||||
),
|
||||
mock.call.echo("Error", err=True),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@mock.patch("crewai.cli.train_crew.click")
|
||||
@mock.patch("crewai.cli.train_crew.subprocess.run")
|
||||
def test_train_crew_unexpected_exception(mock_subprocess_run, click):
|
||||
# Arrange
|
||||
n_iterations = 5
|
||||
mock_subprocess_run.side_effect = Exception("Unexpected error")
|
||||
train_crew(n_iterations)
|
||||
|
||||
mock_subprocess_run.assert_called_once_with(
|
||||
["poetry", "run", "train", "5"], capture_output=False, text=True, check=True
|
||||
)
|
||||
click.echo.assert_called_once_with(
|
||||
"An unexpected error occurred: Unexpected error", err=True
|
||||
)
|
||||
@@ -437,6 +437,7 @@ def test_async_task_execution():
|
||||
process=Process.sequential,
|
||||
tasks=[list_ideas, list_important_history, write_article],
|
||||
)
|
||||
output = TaskOutput(description="A 4 paragraph article about AI.", raw_output="ok")
|
||||
|
||||
with patch.object(Agent, "execute_task") as execute:
|
||||
execute.return_value = "ok"
|
||||
@@ -444,13 +445,11 @@ def test_async_task_execution():
|
||||
thread = threading.Thread(target=lambda: None, args=()).start()
|
||||
start.return_value = thread
|
||||
with patch.object(threading.Thread, "join", wraps=thread.join()) as join:
|
||||
list_ideas.output = TaskOutput(
|
||||
description="A 4 paragraph article about AI.", raw_output="ok"
|
||||
)
|
||||
list_important_history.output = TaskOutput(
|
||||
description="A 4 paragraph article about AI.", raw_output="ok"
|
||||
)
|
||||
list_ideas.output = output
|
||||
list_important_history.output = output
|
||||
|
||||
crew.kickoff()
|
||||
|
||||
start.assert_called()
|
||||
join.assert_called()
|
||||
|
||||
@@ -649,9 +648,9 @@ def test_agent_usage_metrics_are_captured_for_sequential_process():
|
||||
assert result == "Howdy!"
|
||||
assert crew.usage_metrics == {
|
||||
"completion_tokens": 17,
|
||||
"prompt_tokens": 161,
|
||||
"prompt_tokens": 160,
|
||||
"successful_requests": 1,
|
||||
"total_tokens": 178,
|
||||
"total_tokens": 177,
|
||||
}
|
||||
|
||||
|
||||
@@ -678,8 +677,8 @@ 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,
|
||||
"total_tokens": 1666,
|
||||
"prompt_tokens": 1383,
|
||||
"completion_tokens": 283,
|
||||
"successful_requests": 3,
|
||||
}
|
||||
@@ -698,6 +697,8 @@ def test_crew_inputs_interpolate_both_agents_and_tasks():
|
||||
)
|
||||
|
||||
crew = Crew(agents=[agent], tasks=[task], inputs={"topic": "AI", "points": 5})
|
||||
inputs = {"topic": "AI", "points": 5}
|
||||
crew._interpolate_inputs(inputs=inputs) # Manual call for now
|
||||
|
||||
assert crew.tasks[0].description == "Give me an analysis around AI."
|
||||
assert crew.tasks[0].expected_output == "5 bullet points about AI."
|
||||
@@ -706,7 +707,7 @@ def test_crew_inputs_interpolate_both_agents_and_tasks():
|
||||
assert crew.agents[0].backstory == "You have a lot of experience with AI."
|
||||
|
||||
|
||||
def test_crew_inputs_interpolate_both_agents_and_tasks():
|
||||
def test_crew_inputs_interpolate_both_agents_and_tasks_diff():
|
||||
from unittest.mock import patch
|
||||
|
||||
agent = Agent(
|
||||
@@ -828,9 +829,7 @@ def test_tools_with_custom_caching():
|
||||
with patch.object(
|
||||
CacheHandler, "add", wraps=crew._cache_handler.add
|
||||
) as add_to_cache:
|
||||
with patch.object(
|
||||
CacheHandler, "read", wraps=crew._cache_handler.read
|
||||
) as read_from_cache:
|
||||
with patch.object(CacheHandler, "read", wraps=crew._cache_handler.read) as _:
|
||||
result = crew.kickoff()
|
||||
add_to_cache.assert_called_once_with(
|
||||
tool="multiplcation_tool",
|
||||
@@ -894,3 +893,134 @@ 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,
|
||||
)
|
||||
]
|
||||
|
||||
crew = Crew(agents=[researcher], tasks=tasks, output_log_file=str(test_file))
|
||||
crew.kickoff()
|
||||
assert test_file.exists()
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_manager_agent():
|
||||
from unittest.mock import patch
|
||||
|
||||
task = Task(
|
||||
description="Come up with a list of 5 interesting ideas to explore for an article, then write one amazing paragraph highlight for each idea that showcases how good an article about this topic could be. Return the list of ideas with their paragraph and your notes.",
|
||||
expected_output="5 bullet points with a paragraph for each idea.",
|
||||
)
|
||||
|
||||
manager = Agent(
|
||||
role="Manager",
|
||||
goal="Manage the crew and ensure the tasks are completed efficiently.",
|
||||
backstory="You're an experienced manager, skilled in overseeing complex projects and guiding teams to success. Your role is to coordinate the efforts of the crew members, ensuring that each task is completed on time and to the highest standard.",
|
||||
allow_delegation=False,
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
process=Process.hierarchical,
|
||||
manager_agent=manager,
|
||||
tasks=[task],
|
||||
)
|
||||
|
||||
with patch.object(Task, "execute") as execute:
|
||||
crew.kickoff()
|
||||
assert manager.allow_delegation is True
|
||||
execute.assert_called()
|
||||
|
||||
|
||||
def test_manager_agent_in_agents_raises_exception():
|
||||
task = Task(
|
||||
description="Come up with a list of 5 interesting ideas to explore for an article, then write one amazing paragraph highlight for each idea that showcases how good an article about this topic could be. Return the list of ideas with their paragraph and your notes.",
|
||||
expected_output="5 bullet points with a paragraph for each idea.",
|
||||
)
|
||||
|
||||
manager = Agent(
|
||||
role="Manager",
|
||||
goal="Manage the crew and ensure the tasks are completed efficiently.",
|
||||
backstory="You're an experienced manager, skilled in overseeing complex projects and guiding teams to success. Your role is to coordinate the efforts of the crew members, ensuring that each task is completed on time and to the highest standard.",
|
||||
allow_delegation=False,
|
||||
)
|
||||
|
||||
with pytest.raises(pydantic_core._pydantic_core.ValidationError):
|
||||
Crew(
|
||||
agents=[researcher, writer, manager],
|
||||
process=Process.hierarchical,
|
||||
manager_agent=manager,
|
||||
tasks=[task],
|
||||
)
|
||||
|
||||
|
||||
def test_manager_agent_with_tools_raises_exception():
|
||||
from crewai_tools import tool
|
||||
|
||||
@tool
|
||||
def testing_tool(first_number: int, second_number: int) -> int:
|
||||
"""Useful for when you need to multiply two numbers together."""
|
||||
return first_number * second_number
|
||||
|
||||
task = Task(
|
||||
description="Come up with a list of 5 interesting ideas to explore for an article, then write one amazing paragraph highlight for each idea that showcases how good an article about this topic could be. Return the list of ideas with their paragraph and your notes.",
|
||||
expected_output="5 bullet points with a paragraph for each idea.",
|
||||
)
|
||||
|
||||
manager = Agent(
|
||||
role="Manager",
|
||||
goal="Manage the crew and ensure the tasks are completed efficiently.",
|
||||
backstory="You're an experienced manager, skilled in overseeing complex projects and guiding teams to success. Your role is to coordinate the efforts of the crew members, ensuring that each task is completed on time and to the highest standard.",
|
||||
allow_delegation=False,
|
||||
tools=[testing_tool],
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
process=Process.hierarchical,
|
||||
manager_agent=manager,
|
||||
tasks=[task],
|
||||
)
|
||||
|
||||
with pytest.raises(Exception):
|
||||
crew.kickoff()
|
||||
|
||||
|
||||
def test_crew_train_success():
|
||||
task = Task(
|
||||
description="Come up with a list of 5 interesting ideas to explore for an article, then write one amazing paragraph highlight for each idea that showcases how good an article about this topic could be. Return the list of ideas with their paragraph and your notes.",
|
||||
expected_output="5 bullet points with a paragraph for each idea.",
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task],
|
||||
)
|
||||
|
||||
crew.train(n_iterations=2)
|
||||
|
||||
|
||||
def test_crew_train_error():
|
||||
task = Task(
|
||||
description="Come up with a list of 5 interesting ideas to explore for an article",
|
||||
expected_output="5 bullet points with a paragraph for each idea.",
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task],
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError) as e:
|
||||
crew.train()
|
||||
assert "train() missing 1 required positional argument: 'n_iterations'" in str(
|
||||
e
|
||||
)
|
||||
|
||||
405
tests/memory/cassettes/test_save_and_search.yaml
Normal file
405
tests/memory/cassettes/test_save_and_search.yaml
Normal file
@@ -0,0 +1,405 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"input": ["test value test value test value test value test value test
|
||||
value test value test value test value test value test value test value test
|
||||
value test value test value test value test value test value"], "model": "text-embedding-ada-002",
|
||||
"encoding_format": "base64"}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate, br
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '292'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.25.1
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.25.1
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.11.7
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/embeddings
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
GAM=
|
||||
headers:
|
||||
CF-Cache-Status:
|
||||
- DYNAMIC
|
||||
CF-RAY:
|
||||
- 88142860ce7a82e2-GIG
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- br
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 09 May 2024 19:39:49 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie:
|
||||
- __cf_bm=JUH9MsoOBdCquA9K9qOgVbrLUkBpuF4d2k7EvjnBOLg-1715283589-1.0.1.1-96.yHqUmYzRiWC7xZ4.TPKu5RqvB1EFecasHfb_ix62oXcsw_Sp.gz0gDk4Inl119IxRMINM613CI5HheoJM2A;
|
||||
path=/; expires=Thu, 09-May-24 20:09:49 GMT; domain=.api.openai.com; HttpOnly;
|
||||
Secure; SameSite=None
|
||||
- _cfuvid=DPNTnqcoTitPoe12n1vvVltuYsIzavX_dftsSEhQQcc-1715283589489-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:
|
||||
- text-embedding-ada-002
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '15'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=15724800; includeSubDomains
|
||||
x-ratelimit-limit-requests:
|
||||
- '10000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '10000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '9999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '9999946'
|
||||
x-ratelimit-reset-requests:
|
||||
- 6ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_ace5babe6674a08d07fce90792eef7eb
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"input": ["test value"], "model": "text-embedding-ada-002", "encoding_format":
|
||||
"base64"}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate, br
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '89'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- __cf_bm=JUH9MsoOBdCquA9K9qOgVbrLUkBpuF4d2k7EvjnBOLg-1715283589-1.0.1.1-96.yHqUmYzRiWC7xZ4.TPKu5RqvB1EFecasHfb_ix62oXcsw_Sp.gz0gDk4Inl119IxRMINM613CI5HheoJM2A;
|
||||
_cfuvid=DPNTnqcoTitPoe12n1vvVltuYsIzavX_dftsSEhQQcc-1715283589489-0.0.1.1-604800000
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.25.1
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.25.1
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.11.7
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/embeddings
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
headers:
|
||||
CF-Cache-Status:
|
||||
- DYNAMIC
|
||||
CF-RAY:
|
||||
- 88142862e9f182e2-GIG
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- br
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 09 May 2024 19:39:49 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
access-control-allow-origin:
|
||||
- '*'
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
openai-model:
|
||||
- text-embedding-ada-002
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '22'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=15724800; includeSubDomains
|
||||
x-ratelimit-limit-requests:
|
||||
- '10000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '10000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '9999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '9999998'
|
||||
x-ratelimit-reset-requests:
|
||||
- 6ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_834c84237ace9a79492cb9e8d1f68737
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -20,7 +20,7 @@ def test_save_and_search(long_term_memory):
|
||||
metadata={"task": "test_task", "quality": 0.5},
|
||||
)
|
||||
long_term_memory.save(memory)
|
||||
find = long_term_memory.search("test_task")[0]
|
||||
find = long_term_memory.search("test_task", latest_n=5)[0]
|
||||
assert find["score"] == 0.5
|
||||
assert find["datetime"] == "test_datetime"
|
||||
assert find["metadata"]["agent"] == "test_agent"
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
import pytest
|
||||
|
||||
from crewai.agent import Agent
|
||||
from crewai.crew import Crew
|
||||
from crewai.memory.short_term.short_term_memory import ShortTermMemory
|
||||
from crewai.memory.short_term.short_term_memory_item import ShortTermMemoryItem
|
||||
from crewai.task import Task
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def short_term_memory():
|
||||
"""Fixture to create a ShortTermMemory instance"""
|
||||
return ShortTermMemory()
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Search relevant data and provide results",
|
||||
backstory="You are a researcher at a leading tech think tank.",
|
||||
tools=[],
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="Perform a search on specific topics.",
|
||||
expected_output="A list of relevant URLs based on the search query.",
|
||||
agent=agent,
|
||||
)
|
||||
return ShortTermMemory(crew=Crew(
|
||||
agents=[agent],
|
||||
tasks=[task]
|
||||
))
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_save_and_search(short_term_memory):
|
||||
memory = ShortTermMemoryItem(
|
||||
data="""test value test value test value test value test value test value
|
||||
@@ -19,6 +39,7 @@ def test_save_and_search(short_term_memory):
|
||||
metadata={"task": "test_task"},
|
||||
)
|
||||
short_term_memory.save(memory)
|
||||
|
||||
find = short_term_memory.search("test value", score_threshold=0.01)[0]
|
||||
assert find["context"] == memory.data, "Data value mismatch."
|
||||
assert find["metadata"]["agent"] == "test_agent", "Agent value mismatch."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user