├── .cache └── plugin │ └── social │ ├── 0b649b356e60b558dfaafe8bb095862e.png │ ├── 0cce129b2747506603c430fd3fe2b3d6.png │ ├── 0f18d6e26b8551d3f42ef92b0f786024.png │ ├── 14c48b40955d6021b47ae973d9aef723.png │ ├── 17484ad7f45b09a1db146ba3ad3df79a.png │ ├── 1d935acb34360e4768e35ae13479bbf9.png │ ├── 216220c022e734cc7999210b48c9fb59.png │ ├── 246dcba6c47283feac354f5871842fe8.png │ ├── 259ba94ac7e93bd9f968c57ec4a15fe5.png │ ├── 288fd82ce2209be4864d19bd50b21474.png │ ├── 28a844df4871a1cdfcba05fdc87bb3e8.png │ ├── 40770a96ef2fb657a7aa16a9facf702f.png │ ├── 4747e68a5e5c0f0994cdc5b37682a37c.png │ ├── 4809f4ae19b6e78539b900da82d8a1f6.png │ ├── 481b171eb3fe3dec67ca86d2d923f598.png │ ├── 4ae47a8f7da894db700b2f29242cd0c5.png │ ├── 4c1fb3bfd02d6b1317779fe5101058a7.png │ ├── 56e240bc0124af182495bc59877d8d11.png │ ├── 5d2431971fcde0af2c84e4680a4227a7.png │ ├── 69bcd9a2304ea69e1244a7ac510dd98d.png │ ├── 6b49f5ef597c15cabc3df9bac4fbcf44.png │ ├── 7296e2d6c7b2c713ed7b2e4546e3acdb.png │ ├── 805d7c5662a45ca18b52554eecbc34af.png │ ├── 80f1492950494de7a34a1f20f6dd4368.png │ ├── 834ad7f8096fa4c92637b815777bf2bd.png │ ├── 8b089bdf12d22c016f481d654be39eb1.png │ ├── 96f1c198bf51f822eb04a25adf7ca20c.png │ ├── 9f88e9bd3010b149e527e0600c2e438c.png │ ├── Roboto-Black.ttf │ ├── Roboto-BlackItalic.ttf │ ├── Roboto-Bold.ttf │ ├── Roboto-BoldItalic.ttf │ ├── Roboto-Italic.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-LightItalic.ttf │ ├── Roboto-Medium.ttf │ ├── Roboto-MediumItalic.ttf │ ├── Roboto-Regular.ttf │ ├── Roboto-Thin.ttf │ ├── Roboto-ThinItalic.ttf │ ├── a0c21e9a7250afebc533da92c7050bed.png │ ├── a19c79f0bc7a3e5ffc6b511a68273e5d.png │ ├── a1d83c5e1feb928b579ad122a8d3786d.png │ ├── a3d8476a7b5c6630a5f91aed8c210173.png │ ├── ac9c4b6558565d4c349355101e95c74a.png │ ├── b417e4353162a563e70f1350a2777e2c.png │ ├── b84a1e5d0534be3c31f04a7d4a98b515.png │ ├── bca675d7c3c82f52ebd329487fb9ade1.png │ ├── bdf46ef3b5230ebb45ef648933f54fa2.png │ ├── beacb748aad822c66a972b39186dbef1.png │ ├── caa7abb72303dbe5a02ec11e6f1eba6b.png │ ├── cff5eb5aae0959e143c12945428558bc.png │ ├── d01b95e8266a0d2c5f825b88d98a97a1.png │ ├── d7db21df76b132d3ca3ae4313e23f77d.png │ ├── d87db72302152f8c0953d7105c28a206.png │ ├── e580fe32a1d3f15fc89057d053ae3e52.png │ ├── e9111c93e01f7c1dfec7bbab69843076.png │ ├── ebf70df39c2bfd2c4a89d70846a516ff.png │ ├── ed5690e7952bdee0372c8d3f1f5d98d7.png │ ├── f6d08b81ae945faa6c4a436de48d2da6.png │ ├── f875c8d6b0cd71d9ae38300c82361d77.png │ └── fc9a9f44881519178d4000f24000ef9d.png ├── .editorconfig ├── .github └── workflows │ ├── linter.yml │ ├── mkdocs.yml │ ├── tests.yml │ └── type-checker.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── crewAI.excalidraw ├── docs ├── CNAME ├── assets │ ├── agentops-overview.png │ ├── agentops-replay.png │ ├── agentops-session.png │ ├── crewai-langtrace-spans.png │ └── crewai-langtrace-stats.png ├── core-concepts │ ├── Agents.md │ ├── Collaboration.md │ ├── Crews.md │ ├── Memory.md │ ├── Processes.md │ ├── Tasks.md │ ├── Tools.md │ ├── Training-Crew.md │ ├── Using-LangChain-Tools.md │ └── Using-LlamaIndex-Tools.md ├── crewAI-mindmap.png ├── crew_only_logo.png ├── crewai_logo.png ├── how-to │ ├── AgentOps-Observability.md │ ├── Coding-Agents.md │ ├── Create-Custom-Tools.md │ ├── Creating-a-Crew-and-kick-it-off.md │ ├── Customize-Prompts.md │ ├── Customizing-Agents.md │ ├── Force-Tool-Ouput-as-Result.md │ ├── Hierarchical.md │ ├── Human-Input-on-Execution.md │ ├── Installing-CrewAI.md │ ├── Kickoff-async.md │ ├── Kickoff-for-each.md │ ├── LLM-Connections.md │ ├── Langtrace-Observability.md │ ├── Sequential.md │ ├── Start-a-New-CrewAI-Project.md │ └── Your-Own-Manager-Agent.md ├── index.md ├── postcss.config.js ├── stylesheets │ ├── extra.css │ ├── output.css │ └── tailwind.css ├── tailwind.config.js ├── telemetry │ └── Telemetry.md └── tools │ ├── BrowserbaseLoadTool.md │ ├── CSVSearchTool.md │ ├── CodeDocsSearchTool.md │ ├── CodeInterpreterTool.md │ ├── ComposioTool.md │ ├── DOCXSearchTool.md │ ├── DirectoryReadTool.md │ ├── DirectorySearchTool.md │ ├── EXASearchTool.md │ ├── FileReadTool.md │ ├── GitHubSearchTool.md │ ├── JSONSearchTool.md │ ├── MDXSearchTool.md │ ├── PDFSearchTool.md │ ├── PGSearchTool.md │ ├── ScrapeWebsiteTool.md │ ├── SeleniumScrapingTool.md │ ├── SerperDevTool.md │ ├── TXTSearchTool.md │ ├── WebsiteSearchTool.md │ ├── XMLSearchTool.md │ ├── YoutubeChannelSearchTool.md │ └── YoutubeVideoSearchTool.md ├── mkdocs.yml ├── poetry.lock ├── pyproject.toml ├── src └── crewai │ ├── __init__.py │ ├── agent.py │ ├── agents │ ├── __init__.py │ ├── agent_builder │ │ ├── __init__.py │ │ ├── base_agent.py │ │ ├── base_agent_executor_mixin.py │ │ └── utilities │ │ │ ├── __init__.py │ │ │ ├── base_agent_tool.py │ │ │ ├── base_output_converter_base.py │ │ │ └── base_token_process.py │ ├── cache │ │ ├── __init__.py │ │ └── cache_handler.py │ ├── executor.py │ ├── parser.py │ └── tools_handler.py │ ├── cli │ ├── __init__.py │ ├── cli.py │ ├── create_crew.py │ ├── templates │ │ ├── .gitignore │ │ ├── README.md │ │ ├── __init__.py │ │ ├── config │ │ │ ├── agents.yaml │ │ │ └── tasks.yaml │ │ ├── crew.py │ │ ├── main.py │ │ ├── pyproject.toml │ │ └── tools │ │ │ ├── __init__.py │ │ │ └── custom_tool.py │ └── train_crew.py │ ├── crew.py │ ├── memory │ ├── __init__.py │ ├── contextual │ │ ├── __init__.py │ │ └── contextual_memory.py │ ├── entity │ │ ├── __init__.py │ │ ├── entity_memory.py │ │ └── entity_memory_item.py │ ├── long_term │ │ ├── __init__.py │ │ ├── long_term_memory.py │ │ └── long_term_memory_item.py │ ├── memory.py │ ├── short_term │ │ ├── __init__.py │ │ ├── short_term_memory.py │ │ └── short_term_memory_item.py │ └── storage │ │ ├── interface.py │ │ ├── ltm_sqlite_storage.py │ │ └── rag_storage.py │ ├── process.py │ ├── project │ ├── __init__.py │ ├── annotations.py │ └── crew_base.py │ ├── task.py │ ├── tasks │ ├── __init__.py │ └── task_output.py │ ├── telemetry │ ├── __init__.py │ └── telemetry.py │ ├── tools │ ├── __init__.py │ ├── agent_tools.py │ ├── cache_tools.py │ ├── tool_calling.py │ ├── tool_output_parser.py │ └── tool_usage.py │ ├── translations │ └── en.json │ └── utilities │ ├── __init__.py │ ├── constants.py │ ├── converter.py │ ├── crew_pydantic_output_parser.py │ ├── evaluators │ └── task_evaluator.py │ ├── file_handler.py │ ├── i18n.py │ ├── instructor.py │ ├── logger.py │ ├── parser.py │ ├── paths.py │ ├── printer.py │ ├── prompts.py │ ├── pydantic_schema_parser.py │ ├── rpm_controller.py │ ├── token_counter_callback.py │ └── training_handler.py └── tests ├── __init__.py ├── agent_test.py ├── agent_tools ├── __init__.py ├── agent_tools_test.py └── cassettes │ ├── test_ask_question.yaml │ ├── test_ask_question_with_coworker_as_array.yaml │ ├── test_ask_question_with_wrong_co_worker_variable.yaml │ ├── test_delegate_work.yaml │ ├── test_delegate_work_with_wrong_co_worker_variable.yaml │ └── test_delegate_work_withwith_coworker_as_array.yaml ├── cassettes ├── test_agent_custom_max_iterations.yaml ├── test_agent_error_on_parsing_tool.yaml ├── test_agent_execution.yaml ├── test_agent_execution_with_specific_tools.yaml ├── test_agent_execution_with_tools.yaml ├── test_agent_function_calling_llm.yaml ├── test_agent_human_input.yaml ├── test_agent_moved_on_after_max_iterations.yaml ├── test_agent_remembers_output_format_after_using_tools_too_many_times.yaml ├── test_agent_repeated_tool_usage.yaml ├── test_agent_repeated_tool_usage_check_even_with_disabled_cache.yaml ├── test_agent_respect_the_max_rpm_set.yaml ├── test_agent_respect_the_max_rpm_set_over_crew_rpm.yaml ├── test_agent_step_callback.yaml ├── test_agent_usage_metrics_are_captured_for_hierarchical_process.yaml ├── test_agent_usage_metrics_are_captured_for_sequential_process.yaml ├── test_agent_use_specific_tasks_output_as_context.yaml ├── test_agent_without_max_rpm_respet_crew_rpm.yaml ├── test_agent_without_memory.yaml ├── test_agents_do_not_get_delegation_tools_with_there_is_only_one_agent.yaml ├── test_api_calls_throttling.yaml ├── test_cache_hitting.yaml ├── test_cache_hitting_between_agents.yaml ├── test_crew_async_kickoff_for_each_full_ouput.yaml ├── test_crew_creation.yaml ├── test_crew_full_output.yaml ├── test_crew_function_calling_llm.yaml ├── test_crew_kickoff_for_each_full_ouput.yaml ├── test_crew_log_file_output.yaml ├── test_crew_verbose_levels_output.yaml ├── test_crew_verbose_output.yaml ├── test_crew_with_delegating_agents.yaml ├── test_custom_converter_cls.yaml ├── test_disabled_memory_using_contextual_memory.yaml ├── test_disabling_cache_for_agent.yaml ├── test_hierarchical_crew_creation_tasks_with_agents.yaml ├── test_hierarchical_crew_creation_tasks_without_agents.yaml ├── test_hierarchical_process.yaml ├── test_increment_delegations_for_hierarchical_process.yaml ├── test_increment_delegations_for_sequential_process.yaml ├── test_increment_tool_errors.yaml ├── test_logging_tool_usage.yaml ├── test_output_json.yaml ├── test_output_json_to_another_task.yaml ├── test_output_pydantic.yaml ├── test_output_pydantic_to_another_task.yaml ├── test_save_task_json_output.yaml ├── test_save_task_output.yaml ├── test_save_task_pydantic_output.yaml ├── test_sequential_crew_creation_tasks_without_agents.yaml ├── test_task_with_no_arguments.yaml ├── test_tool_result_as_answer_is_the_final_answer_for_the_agent.yaml ├── test_tool_usage_information_is_appended_to_agent.yaml ├── test_tools_with_custom_caching.yaml └── test_using_contextual_memory.yaml ├── cli ├── cli_test.py └── train_crew_test.py ├── conftest.py ├── crew_test.py ├── memory ├── cassettes │ └── test_save_and_search.yaml ├── long_term_memory_test.py └── short_term_memory_test.py ├── project_test.py ├── task_test.py └── utilities ├── evaluators └── test_task_evaluator.py ├── prompts.json ├── test_file_handler.py ├── test_i18n.py └── test_training_handler.py /.cache/plugin/social/0b649b356e60b558dfaafe8bb095862e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/0b649b356e60b558dfaafe8bb095862e.png -------------------------------------------------------------------------------- /.cache/plugin/social/0cce129b2747506603c430fd3fe2b3d6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/0cce129b2747506603c430fd3fe2b3d6.png -------------------------------------------------------------------------------- /.cache/plugin/social/0f18d6e26b8551d3f42ef92b0f786024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/0f18d6e26b8551d3f42ef92b0f786024.png -------------------------------------------------------------------------------- /.cache/plugin/social/14c48b40955d6021b47ae973d9aef723.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/14c48b40955d6021b47ae973d9aef723.png -------------------------------------------------------------------------------- /.cache/plugin/social/17484ad7f45b09a1db146ba3ad3df79a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/17484ad7f45b09a1db146ba3ad3df79a.png -------------------------------------------------------------------------------- /.cache/plugin/social/1d935acb34360e4768e35ae13479bbf9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/1d935acb34360e4768e35ae13479bbf9.png -------------------------------------------------------------------------------- /.cache/plugin/social/216220c022e734cc7999210b48c9fb59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/216220c022e734cc7999210b48c9fb59.png -------------------------------------------------------------------------------- /.cache/plugin/social/246dcba6c47283feac354f5871842fe8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/246dcba6c47283feac354f5871842fe8.png -------------------------------------------------------------------------------- /.cache/plugin/social/259ba94ac7e93bd9f968c57ec4a15fe5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/259ba94ac7e93bd9f968c57ec4a15fe5.png -------------------------------------------------------------------------------- /.cache/plugin/social/288fd82ce2209be4864d19bd50b21474.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/288fd82ce2209be4864d19bd50b21474.png -------------------------------------------------------------------------------- /.cache/plugin/social/28a844df4871a1cdfcba05fdc87bb3e8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/28a844df4871a1cdfcba05fdc87bb3e8.png -------------------------------------------------------------------------------- /.cache/plugin/social/40770a96ef2fb657a7aa16a9facf702f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/40770a96ef2fb657a7aa16a9facf702f.png -------------------------------------------------------------------------------- /.cache/plugin/social/4747e68a5e5c0f0994cdc5b37682a37c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/4747e68a5e5c0f0994cdc5b37682a37c.png -------------------------------------------------------------------------------- /.cache/plugin/social/4809f4ae19b6e78539b900da82d8a1f6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/4809f4ae19b6e78539b900da82d8a1f6.png -------------------------------------------------------------------------------- /.cache/plugin/social/481b171eb3fe3dec67ca86d2d923f598.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/481b171eb3fe3dec67ca86d2d923f598.png -------------------------------------------------------------------------------- /.cache/plugin/social/4ae47a8f7da894db700b2f29242cd0c5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/4ae47a8f7da894db700b2f29242cd0c5.png -------------------------------------------------------------------------------- /.cache/plugin/social/4c1fb3bfd02d6b1317779fe5101058a7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/4c1fb3bfd02d6b1317779fe5101058a7.png -------------------------------------------------------------------------------- /.cache/plugin/social/56e240bc0124af182495bc59877d8d11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/56e240bc0124af182495bc59877d8d11.png -------------------------------------------------------------------------------- /.cache/plugin/social/5d2431971fcde0af2c84e4680a4227a7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/5d2431971fcde0af2c84e4680a4227a7.png -------------------------------------------------------------------------------- /.cache/plugin/social/69bcd9a2304ea69e1244a7ac510dd98d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/69bcd9a2304ea69e1244a7ac510dd98d.png -------------------------------------------------------------------------------- /.cache/plugin/social/6b49f5ef597c15cabc3df9bac4fbcf44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/6b49f5ef597c15cabc3df9bac4fbcf44.png -------------------------------------------------------------------------------- /.cache/plugin/social/7296e2d6c7b2c713ed7b2e4546e3acdb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/7296e2d6c7b2c713ed7b2e4546e3acdb.png -------------------------------------------------------------------------------- /.cache/plugin/social/805d7c5662a45ca18b52554eecbc34af.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/805d7c5662a45ca18b52554eecbc34af.png -------------------------------------------------------------------------------- /.cache/plugin/social/80f1492950494de7a34a1f20f6dd4368.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/80f1492950494de7a34a1f20f6dd4368.png -------------------------------------------------------------------------------- /.cache/plugin/social/834ad7f8096fa4c92637b815777bf2bd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/834ad7f8096fa4c92637b815777bf2bd.png -------------------------------------------------------------------------------- /.cache/plugin/social/8b089bdf12d22c016f481d654be39eb1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/8b089bdf12d22c016f481d654be39eb1.png -------------------------------------------------------------------------------- /.cache/plugin/social/96f1c198bf51f822eb04a25adf7ca20c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/96f1c198bf51f822eb04a25adf7ca20c.png -------------------------------------------------------------------------------- /.cache/plugin/social/9f88e9bd3010b149e527e0600c2e438c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/9f88e9bd3010b149e527e0600c2e438c.png -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Black.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Bold.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Italic.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Light.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Medium.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Regular.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-Thin.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /.cache/plugin/social/a0c21e9a7250afebc533da92c7050bed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/a0c21e9a7250afebc533da92c7050bed.png -------------------------------------------------------------------------------- /.cache/plugin/social/a19c79f0bc7a3e5ffc6b511a68273e5d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/a19c79f0bc7a3e5ffc6b511a68273e5d.png -------------------------------------------------------------------------------- /.cache/plugin/social/a1d83c5e1feb928b579ad122a8d3786d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/a1d83c5e1feb928b579ad122a8d3786d.png -------------------------------------------------------------------------------- /.cache/plugin/social/a3d8476a7b5c6630a5f91aed8c210173.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/a3d8476a7b5c6630a5f91aed8c210173.png -------------------------------------------------------------------------------- /.cache/plugin/social/ac9c4b6558565d4c349355101e95c74a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/ac9c4b6558565d4c349355101e95c74a.png -------------------------------------------------------------------------------- /.cache/plugin/social/b417e4353162a563e70f1350a2777e2c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/b417e4353162a563e70f1350a2777e2c.png -------------------------------------------------------------------------------- /.cache/plugin/social/b84a1e5d0534be3c31f04a7d4a98b515.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/b84a1e5d0534be3c31f04a7d4a98b515.png -------------------------------------------------------------------------------- /.cache/plugin/social/bca675d7c3c82f52ebd329487fb9ade1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/bca675d7c3c82f52ebd329487fb9ade1.png -------------------------------------------------------------------------------- /.cache/plugin/social/bdf46ef3b5230ebb45ef648933f54fa2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/bdf46ef3b5230ebb45ef648933f54fa2.png -------------------------------------------------------------------------------- /.cache/plugin/social/beacb748aad822c66a972b39186dbef1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/beacb748aad822c66a972b39186dbef1.png -------------------------------------------------------------------------------- /.cache/plugin/social/caa7abb72303dbe5a02ec11e6f1eba6b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/caa7abb72303dbe5a02ec11e6f1eba6b.png -------------------------------------------------------------------------------- /.cache/plugin/social/cff5eb5aae0959e143c12945428558bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/cff5eb5aae0959e143c12945428558bc.png -------------------------------------------------------------------------------- /.cache/plugin/social/d01b95e8266a0d2c5f825b88d98a97a1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/d01b95e8266a0d2c5f825b88d98a97a1.png -------------------------------------------------------------------------------- /.cache/plugin/social/d7db21df76b132d3ca3ae4313e23f77d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/d7db21df76b132d3ca3ae4313e23f77d.png -------------------------------------------------------------------------------- /.cache/plugin/social/d87db72302152f8c0953d7105c28a206.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/d87db72302152f8c0953d7105c28a206.png -------------------------------------------------------------------------------- /.cache/plugin/social/e580fe32a1d3f15fc89057d053ae3e52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/e580fe32a1d3f15fc89057d053ae3e52.png -------------------------------------------------------------------------------- /.cache/plugin/social/e9111c93e01f7c1dfec7bbab69843076.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/e9111c93e01f7c1dfec7bbab69843076.png -------------------------------------------------------------------------------- /.cache/plugin/social/ebf70df39c2bfd2c4a89d70846a516ff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/ebf70df39c2bfd2c4a89d70846a516ff.png -------------------------------------------------------------------------------- /.cache/plugin/social/ed5690e7952bdee0372c8d3f1f5d98d7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/ed5690e7952bdee0372c8d3f1f5d98d7.png -------------------------------------------------------------------------------- /.cache/plugin/social/f6d08b81ae945faa6c4a436de48d2da6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/f6d08b81ae945faa6c4a436de48d2da6.png -------------------------------------------------------------------------------- /.cache/plugin/social/f875c8d6b0cd71d9ae38300c82361d77.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/f875c8d6b0cd71d9ae38300c82361d77.png -------------------------------------------------------------------------------- /.cache/plugin/social/fc9a9f44881519178d4000f24000ef9d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/.cache/plugin/social/fc9a9f44881519178d4000f24000ef9d.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # .editorconfig 2 | root = true 3 | 4 | # All files 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | # Python files 12 | [*.py] 13 | indent_style = space 14 | indent_size = 2 -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | 11 | - name: Install Requirements 12 | run: | 13 | pip install ruff 14 | 15 | - name: Run Ruff Linter 16 | run: ruff check --exclude "templates","__init__.py" 17 | -------------------------------------------------------------------------------- /.github/workflows/mkdocs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy MkDocs 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | permissions: 10 | contents: write 11 | 12 | jobs: 13 | deploy: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v2 19 | 20 | - name: Setup Python 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.10' 24 | 25 | - name: Calculate requirements hash 26 | id: req-hash 27 | run: echo "::set-output name=hash::$(sha256sum requirements-doc.txt | awk '{print $1}')" 28 | 29 | - name: Setup cache 30 | uses: actions/cache@v3 31 | with: 32 | key: mkdocs-material-${{ steps.req-hash.outputs.hash }} 33 | path: .cache 34 | restore-keys: | 35 | mkdocs-material- 36 | 37 | - name: Install Requirements 38 | run: | 39 | sudo apt-get update && 40 | sudo apt-get install pngquant && 41 | pip install mkdocs-material mkdocs-material-extensions pillow cairosvg 42 | 43 | env: 44 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 45 | 46 | - name: Build and deploy MkDocs 47 | run: mkdocs gh-deploy --force -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | on: [pull_request] 4 | 5 | permissions: 6 | contents: write 7 | 8 | env: 9 | OPENAI_API_KEY: fake-api-key 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | 19 | - name: Setup Python 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: "3.11.9" 23 | 24 | - name: Install Requirements 25 | run: | 26 | set -e 27 | pip install poetry 28 | poetry install 29 | 30 | - name: Run tests 31 | run: poetry run pytest 32 | -------------------------------------------------------------------------------- /.github/workflows/type-checker.yml: -------------------------------------------------------------------------------- 1 | name: Run Type Checks 2 | 3 | on: [pull_request] 4 | 5 | permissions: 6 | contents: write 7 | 8 | jobs: 9 | type-checker: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Python 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: "3.10" 20 | 21 | - name: Install Requirements 22 | run: | 23 | pip install mypy 24 | 25 | - name: Run type checks 26 | run: mypy src 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .pytest_cache 3 | __pycache__ 4 | dist/ 5 | .env 6 | assets/* 7 | .idea 8 | test/ 9 | docs_crew/ 10 | chroma.sqlite3 11 | old_en.json 12 | db/ 13 | test.py 14 | rc-tests/* 15 | *.pkl 16 | temp/* 17 | .vscode/* -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/astral-sh/ruff-pre-commit 3 | rev: v0.4.4 4 | hooks: 5 | - id: ruff 6 | args: ["--fix"] 7 | exclude: "templates" 8 | - id: ruff-format 9 | exclude: "templates" 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 The Python Packaging Authority 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.crewai.com -------------------------------------------------------------------------------- /docs/assets/agentops-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/assets/agentops-overview.png -------------------------------------------------------------------------------- /docs/assets/agentops-replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/assets/agentops-replay.png -------------------------------------------------------------------------------- /docs/assets/agentops-session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/assets/agentops-session.png -------------------------------------------------------------------------------- /docs/assets/crewai-langtrace-spans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/assets/crewai-langtrace-spans.png -------------------------------------------------------------------------------- /docs/assets/crewai-langtrace-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/assets/crewai-langtrace-stats.png -------------------------------------------------------------------------------- /docs/core-concepts/Training-Crew.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: crewAI Train 3 | description: Learn how to train your crewAI agents by giving them feedback early on and get consistent results. 4 | --- 5 | 6 | ## Introduction 7 | The training feature in CrewAI allows you to train your AI agents using the command-line interface (CLI). By running the command `crewai train -n `, you can specify the number of iterations for the training process. 8 | 9 | During training, CrewAI utilizes techniques to optimize the performance of your agents along with human feedback. This helps the agents improve their understanding, decision-making, and problem-solving abilities. 10 | 11 | ### Training Your Crew Using the CLI 12 | To use the training feature, follow these steps: 13 | 14 | 1. Open your terminal or command prompt. 15 | 2. Navigate to the directory where your CrewAI project is located. 16 | 3. Run the following command: 17 | 18 | ```shell 19 | crewai train -n 20 | ``` 21 | 22 | ### Training Your Crew Programmatically 23 | To train your crew programmatically, use the following steps: 24 | 25 | 1. Define the number of iterations for training. 26 | 2. Specify the input parameters for the training process. 27 | 3. Execute the training command within a try-except block to handle potential errors. 28 | 29 | ```python 30 | n_iterations = 2 31 | inputs = {"topic": "CrewAI Training"} 32 | 33 | try: 34 | YourCrewName_Crew().crew().train(n_iterations= n_iterations, inputs=inputs) 35 | 36 | except Exception as e: 37 | raise Exception(f"An error occurred while training the crew: {e}") 38 | ``` 39 | 40 | !!! note "Replace `` with the desired number of training iterations. This determines how many times the agents will go through the training process." 41 | 42 | 43 | ### Key Points to Note: 44 | - **Positive Integer Requirement:** Ensure that the number of iterations (`n_iterations`) is a positive integer. The code will raise a `ValueError` if this condition is not met. 45 | - **Error Handling:** The code handles subprocess errors and unexpected exceptions, providing error messages to the user. 46 | 47 | It is important to note that the training process may take some time, depending on the complexity of your agents and will also require your feedback on each iteration. 48 | 49 | Once the training is complete, your agents will be equipped with enhanced capabilities and knowledge, ready to tackle complex tasks and provide more consistent and valuable insights. 50 | 51 | Remember to regularly update and retrain your agents to ensure they stay up-to-date with the latest information and advancements in the field. 52 | 53 | Happy training with CrewAI! -------------------------------------------------------------------------------- /docs/core-concepts/Using-LangChain-Tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using LangChain Tools 3 | description: Learn how to integrate LangChain tools with CrewAI agents to enhance search-based queries and more. 4 | --- 5 | 6 | ## Using LangChain Tools 7 | !!! info "LangChain Integration" 8 | CrewAI seamlessly integrates with LangChain’s comprehensive toolkit for search-based queries and more, here are the available built-in tools that are offered by Langchain [LangChain Toolkit](https://python.langchain.com/docs/integrations/tools/) 9 | 10 | ```python 11 | from crewai import Agent 12 | from langchain.agents import Tool 13 | from langchain.utilities import GoogleSerperAPIWrapper 14 | 15 | # Setup API keys 16 | os.environ["SERPER_API_KEY"] = "Your Key" 17 | 18 | search = GoogleSerperAPIWrapper() 19 | 20 | # Create and assign the search tool to an agent 21 | serper_tool = Tool( 22 | name="Intermediate Answer", 23 | func=search.run, 24 | description="Useful for search-based queries", 25 | ) 26 | 27 | agent = Agent( 28 | role='Research Analyst', 29 | goal='Provide up-to-date market analysis', 30 | backstory='An expert analyst with a keen eye for market trends.', 31 | tools=[serper_tool] 32 | ) 33 | 34 | # rest of the code ... 35 | ``` 36 | 37 | ## Conclusion 38 | 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. -------------------------------------------------------------------------------- /docs/core-concepts/Using-LlamaIndex-Tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using LlamaIndex Tools 3 | description: Learn how to integrate LlamaIndex tools with CrewAI agents to enhance search-based queries and more. 4 | --- 5 | 6 | ## Using LlamaIndex Tools 7 | 8 | !!! info "LlamaIndex Integration" 9 | CrewAI seamlessly integrates with LlamaIndex’s comprehensive toolkit for RAG (Retrieval-Augmented Generation) and agentic pipelines, enabling advanced search-based queries and more. Here are the available built-in tools offered by LlamaIndex. 10 | 11 | ```python 12 | from crewai import Agent 13 | from crewai_tools import LlamaIndexTool 14 | 15 | # Example 1: Initialize from FunctionTool 16 | from llama_index.core.tools import FunctionTool 17 | 18 | your_python_function = lambda ...: ... 19 | og_tool = FunctionTool.from_defaults(your_python_function, name="", description='') 20 | tool = LlamaIndexTool.from_tool(og_tool) 21 | 22 | # Example 2: Initialize from LlamaHub Tools 23 | from llama_index.tools.wolfram_alpha import WolframAlphaToolSpec 24 | wolfram_spec = WolframAlphaToolSpec(app_id="") 25 | wolfram_tools = wolfram_spec.to_tool_list() 26 | tools = [LlamaIndexTool.from_tool(t) for t in wolfram_tools] 27 | 28 | # Example 3: Initialize Tool from a LlamaIndex Query Engine 29 | query_engine = index.as_query_engine() 30 | query_tool = LlamaIndexTool.from_query_engine( 31 | query_engine, 32 | name="Uber 2019 10K Query Tool", 33 | description="Use this tool to lookup the 2019 Uber 10K Annual Report" 34 | ) 35 | 36 | # Create and assign the tools to an agent 37 | agent = Agent( 38 | role='Research Analyst', 39 | goal='Provide up-to-date market analysis', 40 | backstory='An expert analyst with a keen eye for market trends.', 41 | tools=[tool, *tools, query_tool] 42 | ) 43 | 44 | # rest of the code ... 45 | ``` 46 | 47 | ## Steps to Get Started 48 | 49 | To effectively use the LlamaIndexTool, follow these steps: 50 | 51 | 1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment. 52 | 53 | ```shell 54 | pip install 'crewai[tools]' 55 | ``` 56 | 57 | 2. **Install and Use LlamaIndex**: Follow LlamaIndex documentation [LlamaIndex Documentation](https://docs.llamaindex.ai/) to set up a RAG/agent pipeline. -------------------------------------------------------------------------------- /docs/crewAI-mindmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/crewAI-mindmap.png -------------------------------------------------------------------------------- /docs/crew_only_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/crew_only_logo.png -------------------------------------------------------------------------------- /docs/crewai_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/docs/crewai_logo.png -------------------------------------------------------------------------------- /docs/how-to/Coding-Agents.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Coding Agents 3 | description: Learn how to enable your crewAI Agents to write and execute code, and explore advanced features for enhanced functionality. 4 | --- 5 | 6 | ## Introduction 7 | 8 | crewAI Agents now have the powerful ability to write and execute code, significantly enhancing their problem-solving capabilities. This feature is particularly useful for tasks that require computational or programmatic solutions. 9 | 10 | ## Enabling Code Execution 11 | 12 | To enable code execution for an agent, set the `allow_code_execution` parameter to `True` when creating the agent. Here's an example: 13 | 14 | ```python 15 | from crewai import Agent 16 | 17 | coding_agent = Agent( 18 | role="Senior Python Developer", 19 | goal="Craft well-designed and thought-out code", 20 | backstory="You are a senior Python developer with extensive experience in software architecture and best practices.", 21 | allow_code_execution=True 22 | ) 23 | ``` 24 | 25 | ## Important Considerations 26 | 27 | 1. **Model Selection**: It is strongly recommended to use more capable models like Claude 3.5 Sonnet and GPT-4 when enabling code execution. These models have a better understanding of programming concepts and are more likely to generate correct and efficient code. 28 | 29 | 2. **Error Handling**: The code execution feature includes error handling. If executed code raises an exception, the agent will receive the error message and can attempt to correct the code or provide alternative solutions. 30 | 31 | 3. **Dependencies**: To use the code execution feature, you need to install the `crewai_tools` package. If not installed, the agent will log an info message: "Coding tools not available. Install crewai_tools." 32 | 33 | ## Code Execution Process 34 | 35 | When an agent with code execution enabled encounters a task requiring programming: 36 | 37 | 1. The agent analyzes the task and determines that code execution is necessary. 38 | 2. It formulates the Python code needed to solve the problem. 39 | 3. The code is sent to the internal code execution tool (`CodeInterpreterTool`). 40 | 4. The tool executes the code in a controlled environment and returns the result. 41 | 5. The agent interprets the result and incorporates it into its response or uses it for further problem-solving. 42 | 43 | ## Example Usage 44 | 45 | Here's a detailed example of creating an agent with code execution capabilities and using it in a task: 46 | 47 | ```python 48 | from crewai import Agent, Task, Crew 49 | 50 | # Create an agent with code execution enabled 51 | coding_agent = Agent( 52 | role="Python Data Analyst", 53 | goal="Analyze data and provide insights using Python", 54 | backstory="You are an experienced data analyst with strong Python skills.", 55 | allow_code_execution=True 56 | ) 57 | 58 | # Create a task that requires code execution 59 | data_analysis_task = Task( 60 | description="Analyze the given dataset and calculate the average age of participants.", 61 | agent=coding_agent 62 | ) 63 | 64 | # Create a crew and add the task 65 | analysis_crew = Crew( 66 | agents=[coding_agent], 67 | tasks=[data_analysis_task] 68 | ) 69 | 70 | # Execute the crew 71 | result = analysis_crew.kickoff() 72 | 73 | print(result) 74 | ``` 75 | 76 | In this example, the `coding_agent` can write and execute Python code to perform data analysis tasks. -------------------------------------------------------------------------------- /docs/how-to/Create-Custom-Tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating and Utilizing Tools in crewAI 3 | description: Comprehensive guide on crafting, using, and managing custom tools within the crewAI framework, including new functionalities and error handling. 4 | --- 5 | 6 | ## Creating and Utilizing Tools in crewAI 7 | This guide provides detailed instructions on creating custom tools for the crewAI framework and how to efficiently manage and utilize these tools, incorporating the latest functionalities such as tool delegation, error handling, and dynamic tool calling. It also highlights the importance of collaboration tools, enabling agents to perform a wide range of actions. 8 | 9 | ### Prerequisites 10 | Before creating your own tools, ensure you have the crewAI extra tools package installed: 11 | 12 | ```bash 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ### Subclassing `BaseTool` 17 | 18 | To create a personalized tool, inherit from `BaseTool` and define the necessary attributes and the `_run` method. 19 | 20 | ```python 21 | from crewai_tools import BaseTool 22 | 23 | class MyCustomTool(BaseTool): 24 | name: str = "Name of my tool" 25 | description: str = "What this tool does. It's vital for effective utilization." 26 | 27 | def _run(self, argument: str) -> str: 28 | # Your tool's logic here 29 | return "Tool's result" 30 | ``` 31 | 32 | ### Using the `tool` Decorator 33 | 34 | Alternatively, use the `tool` decorator for a direct approach to create tools. This requires specifying attributes and the tool's logic within a function. 35 | 36 | ```python 37 | from crewai_tools import tool 38 | 39 | @tool("Tool Name") 40 | def my_simple_tool(question: str) -> str: 41 | """Tool description for clarity.""" 42 | # Tool logic here 43 | return "Tool output" 44 | ``` 45 | 46 | ### Defining a Cache Function for the Tool 47 | 48 | To optimize tool performance with caching, define custom caching strategies using the `cache_function` attribute. 49 | 50 | ```python 51 | @tool("Tool with Caching") 52 | def cached_tool(argument: str) -> str: 53 | """Tool functionality description.""" 54 | return "Cacheable result" 55 | 56 | def my_cache_strategy(arguments: dict, result: str) -> bool: 57 | # Define custom caching logic 58 | return True if some_condition else False 59 | 60 | cached_tool.cache_function = my_cache_strategy 61 | ``` 62 | 63 | By adhering to these guidelines and incorporating new functionalities and collaboration tools into your tool creation and management processes, you can leverage the full capabilities of the crewAI framework, enhancing both the development experience and the efficiency of your AI agents. -------------------------------------------------------------------------------- /docs/how-to/Force-Tool-Ouput-as-Result.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Forcing Tool Output as Result 3 | description: Learn how to force tool output as the result in of an Agent's task in crewAI. 4 | --- 5 | 6 | ## Introduction 7 | In CrewAI, you can force the output of a tool as the result of an agent's task. This feature is useful when you want to ensure that the tool output is captured and returned as the task result, and avoid the agent modifying the output during the task execution. 8 | 9 | ## Forcing Tool Output as Result 10 | To force the tool output as the result of an agent's task, you can set the `force_tool_output` parameter to `True` when creating the task. This parameter ensures that the tool output is captured and returned as the task result, without any modifications by the agent. 11 | 12 | Here's an example of how to force the tool output as the result of an agent's task: 13 | 14 | ```python 15 | # ... 16 | # Define a custom tool that returns the result as the answer 17 | coding_agent =Agent( 18 | role="Data Scientist", 19 | goal="Product amazing resports on AI", 20 | backstory="You work with data and AI", 21 | tools=[MyCustomTool(result_as_answer=True)], 22 | ) 23 | # ... 24 | ``` 25 | 26 | ### Workflow in Action 27 | 28 | 1. **Task Execution**: The agent executes the task using the tool provided. 29 | 2. **Tool Output**: The tool generates the output, which is captured as the task result. 30 | 3. **Agent Interaction**: The agent my reflect and take learnings from the tool but the output is not modified. 31 | 4. **Result Return**: The tool output is returned as the task result without any modifications. 32 | -------------------------------------------------------------------------------- /docs/how-to/Human-Input-on-Execution.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Human Input on Execution 3 | description: Integrating CrewAI with human input during execution in complex decision-making processes and leveraging the full capabilities of the agent's attributes and tools. 4 | --- 5 | 6 | # Human Input in Agent Execution 7 | 8 | Human input is critical in several agent execution scenarios, allowing agents to request additional information or clarification when necessary. This feature is especially useful in complex decision-making processes or when agents require more details to complete a task effectively. 9 | 10 | ## Using Human Input with CrewAI 11 | 12 | To integrate human input into agent execution, set the `human_input` flag in the task definition. When enabled, the agent prompts the user for input before delivering its final answer. This input can provide extra context, clarify ambiguities, or validate the agent's output. 13 | 14 | ### Example: 15 | 16 | ```shell 17 | pip install crewai 18 | ``` 19 | 20 | ```python 21 | import os 22 | from crewai import Agent, Task, Crew 23 | from crewai_tools import SerperDevTool 24 | 25 | os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API key 26 | os.environ["OPENAI_API_KEY"] = "Your Key" 27 | 28 | # Loading Tools 29 | search_tool = SerperDevTool() 30 | 31 | # Define your agents with roles, goals, tools, and additional attributes 32 | researcher = Agent( 33 | role='Senior Research Analyst', 34 | goal='Uncover cutting-edge developments in AI and data science', 35 | backstory=( 36 | "You are a Senior Research Analyst at a leading tech think tank. " 37 | "Your expertise lies in identifying emerging trends and technologies in AI and data science. " 38 | "You have a knack for dissecting complex data and presenting actionable insights." 39 | ), 40 | verbose=True, 41 | allow_delegation=False, 42 | tools=[search_tool] 43 | ) 44 | writer = Agent( 45 | role='Tech Content Strategist', 46 | goal='Craft compelling content on tech advancements', 47 | backstory=( 48 | "You are a renowned Tech Content Strategist, known for your insightful and engaging articles on technology and innovation. " 49 | "With a deep understanding of the tech industry, you transform complex concepts into compelling narratives." 50 | ), 51 | verbose=True, 52 | allow_delegation=True, 53 | tools=[search_tool], 54 | cache=False, # Disable cache for this agent 55 | ) 56 | 57 | # Create tasks for your agents 58 | task1 = Task( 59 | description=( 60 | "Conduct a comprehensive analysis of the latest advancements in AI in 2024. " 61 | "Identify key trends, breakthrough technologies, and potential industry impacts. " 62 | "Compile your findings in a detailed report. " 63 | "Make sure to check with a human if the draft is good before finalizing your answer." 64 | ), 65 | expected_output='A comprehensive full report on the latest AI advancements in 2024, leave nothing out', 66 | agent=researcher, 67 | human_input=True 68 | ) 69 | 70 | task2 = Task( 71 | description=( 72 | "Using the insights from the researcher\'s report, develop an engaging blog post that highlights the most significant AI advancements. " 73 | "Your post should be informative yet accessible, catering to a tech-savvy audience. " 74 | "Aim for a narrative that captures the essence of these breakthroughs and their implications for the future." 75 | ), 76 | expected_output='A compelling 3 paragraphs blog post formatted as markdown about the latest AI advancements in 2024', 77 | agent=writer 78 | ) 79 | 80 | # Instantiate your crew with a sequential process 81 | crew = Crew( 82 | agents=[researcher, writer], 83 | tasks=[task1, task2], 84 | verbose=2, 85 | memory=True, 86 | ) 87 | 88 | # Get your crew to work! 89 | result = crew.kickoff() 90 | 91 | print("######################") 92 | print(result) 93 | ``` -------------------------------------------------------------------------------- /docs/how-to/Installing-CrewAI.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installing crewAI 3 | description: A comprehensive guide to installing crewAI and its dependencies, including the latest updates and installation methods. 4 | --- 5 | 6 | # Installing crewAI 7 | 8 | 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! 9 | 10 | ## Installation 11 | 12 | To install crewAI, you need to have Python >=3.10 and <=3.13 installed on your system: 13 | 14 | ```shell 15 | # Install the main crewAI package 16 | pip install crewai 17 | 18 | # Install the main crewAI package and the tools package 19 | # that includes a series of helpful tools for your agents 20 | pip install 'crewai[tools]' 21 | ``` -------------------------------------------------------------------------------- /docs/how-to/Kickoff-async.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kickoff Async 3 | description: Kickoff a Crew Asynchronously 4 | --- 5 | 6 | ## Introduction 7 | CrewAI provides the ability to kickoff a crew asynchronously, allowing you to start the crew execution in a non-blocking manner. This feature is particularly useful when you want to run multiple crews concurrently or when you need to perform other tasks while the crew is executing. 8 | 9 | ## Asynchronous Crew Execution 10 | To kickoff a crew asynchronously, use the `kickoff_async()` method. This method initiates the crew execution in a separate thread, allowing the main thread to continue executing other tasks. 11 | 12 | Here's an example of how to kickoff a crew asynchronously: 13 | 14 | ```python 15 | from crewai import Crew, Agent, Task 16 | 17 | # Create an agent with code execution enabled 18 | coding_agent = Agent( 19 | role="Python Data Analyst", 20 | goal="Analyze data and provide insights using Python", 21 | backstory="You are an experienced data analyst with strong Python skills.", 22 | allow_code_execution=True 23 | ) 24 | 25 | # Create a task that requires code execution 26 | data_analysis_task = Task( 27 | description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}", 28 | agent=coding_agent 29 | ) 30 | 31 | # Create a crew and add the task 32 | analysis_crew = Crew( 33 | agents=[coding_agent], 34 | tasks=[data_analysis_task] 35 | ) 36 | 37 | # Execute the crew 38 | result = analysis_crew.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]}) 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /docs/how-to/Kickoff-for-each.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kickoff For Each 3 | description: Kickoff a Crew for a List 4 | --- 5 | 6 | ## Introduction 7 | CrewAI provides the ability to kickoff a crew for each item in a list, allowing you to execute the crew for each item in the list. This feature is particularly useful when you need to perform the same set of tasks for multiple items. 8 | 9 | ## Kicking Off a Crew for Each Item 10 | To kickoff a crew for each item in a list, use the `kickoff_for_each()` method. This method executes the crew for each item in the list, allowing you to process multiple items efficiently. 11 | 12 | Here's an example of how to kickoff a crew for each item in a list: 13 | 14 | ```python 15 | from crewai import Crew, Agent, Task 16 | 17 | # Create an agent with code execution enabled 18 | coding_agent = Agent( 19 | role="Python Data Analyst", 20 | goal="Analyze data and provide insights using Python", 21 | backstory="You are an experienced data analyst with strong Python skills.", 22 | allow_code_execution=True 23 | ) 24 | 25 | # Create a task that requires code execution 26 | data_analysis_task = Task( 27 | description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}", 28 | agent=coding_agent 29 | ) 30 | 31 | # Create a crew and add the task 32 | analysis_crew = Crew( 33 | agents=[coding_agent], 34 | tasks=[data_analysis_task] 35 | ) 36 | 37 | datasets = [ 38 | { "ages": [25, 30, 35, 40, 45] }, 39 | { "ages": [20, 25, 30, 35, 40] }, 40 | { "ages": [30, 35, 40, 45, 50] } 41 | ] 42 | 43 | # Execute the crew 44 | result = analysis_crew.kickoff_for_each(inputs=datasets) 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/how-to/Langtrace-Observability.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CrewAI Agent Monitoring with Langtrace 3 | description: How to monitor cost, latency, and performance of CrewAI Agents using Langtrace, an external observability tool. 4 | --- 5 | 6 | # Langtrace Overview 7 | 8 | Langtrace is an open-source, external tool that helps you set up observability and evaluations for Large Language Models (LLMs), LLM frameworks, and Vector Databases. While not built directly into CrewAI, Langtrace can be used alongside CrewAI to gain deep visibility into the cost, latency, and performance of your CrewAI Agents. This integration allows you to log hyperparameters, monitor performance regressions, and establish a process for continuous improvement of your Agents. 9 | 10 | ## Setup Instructions 11 | 12 | 1. Sign up for [Langtrace](https://langtrace.ai/) by visiting [https://langtrace.ai/signup](https://langtrace.ai/signup). 13 | 2. Create a project and generate an API key. 14 | 3. Install Langtrace in your CrewAI project using the following commands: 15 | 16 | ```bash 17 | # Install the SDK 18 | pip install langtrace-python-sdk 19 | ``` 20 | 21 | ## Using Langtrace with CrewAI 22 | 23 | To integrate Langtrace with your CrewAI project, follow these steps: 24 | 25 | 1. Import and initialize Langtrace at the beginning of your script, before any CrewAI imports: 26 | 27 | ```python 28 | from langtrace_python_sdk import langtrace 29 | langtrace.init(api_key='') 30 | 31 | # Now import CrewAI modules 32 | from crewai import Agent, Task, Crew 33 | ``` 34 | 35 | 2. Create your CrewAI agents and tasks as usual. 36 | 37 | 3. Use Langtrace's tracking functions to monitor your CrewAI operations. For example: 38 | 39 | ```python 40 | with langtrace.trace("CrewAI Task Execution"): 41 | result = crew.kickoff() 42 | ``` 43 | 44 | ### Features and Their Application to CrewAI 45 | 46 | 1. **LLM Token and Cost Tracking** 47 | - Monitor the token usage and associated costs for each CrewAI agent interaction. 48 | - Example: 49 | ```python 50 | with langtrace.trace("Agent Interaction"): 51 | agent_response = agent.execute(task) 52 | ``` 53 | 54 | 2. **Trace Graph for Execution Steps** 55 | - Visualize the execution flow of your CrewAI tasks, including latency and logs. 56 | - Useful for identifying bottlenecks in your agent workflows. 57 | 58 | 3. **Dataset Curation with Manual Annotation** 59 | - Create datasets from your CrewAI task outputs for future training or evaluation. 60 | - Example: 61 | ```python 62 | langtrace.log_dataset_item(task_input, agent_output, {"task_type": "research"}) 63 | ``` 64 | 65 | 4. **Prompt Versioning and Management** 66 | - Keep track of different versions of prompts used in your CrewAI agents. 67 | - Useful for A/B testing and optimizing agent performance. 68 | 69 | 5. **Prompt Playground with Model Comparisons** 70 | - Test and compare different prompts and models for your CrewAI agents before deployment. 71 | 72 | 6. **Testing and Evaluations** 73 | - Set up automated tests for your CrewAI agents and tasks. 74 | - Example: 75 | ```python 76 | langtrace.evaluate(agent_output, expected_output, "accuracy") 77 | ``` 78 | 79 | ## Monitoring New CrewAI Features 80 | 81 | CrewAI has introduced several new features that can be monitored using Langtrace: 82 | 83 | 1. **Code Execution**: Monitor the performance and output of code executed by agents. 84 | ```python 85 | with langtrace.trace("Agent Code Execution"): 86 | code_output = agent.execute_code(code_snippet) 87 | ``` 88 | 89 | 2. **Third-party Agent Integration**: Track interactions with LlamaIndex, LangChain, and Autogen agents. -------------------------------------------------------------------------------- /docs/how-to/Your-Own-Manager-Agent.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setting a Specific Agent as Manager in CrewAI 3 | description: Learn how to set a custom agent as the manager in CrewAI, providing more control over task management and coordination. 4 | 5 | --- 6 | 7 | # Setting a Specific Agent as Manager in CrewAI 8 | 9 | CrewAI allows users to set a specific agent as the manager of the crew, providing more control over the management and coordination of tasks. This feature enables the customization of the managerial role to better fit your project's requirements. 10 | 11 | ## Using the `manager_agent` Attribute 12 | 13 | ### Custom Manager Agent 14 | 15 | The `manager_agent` attribute allows you to define a custom agent to manage the crew. This agent will oversee the entire process, ensuring that tasks are completed efficiently and to the highest standard. 16 | 17 | ### Example 18 | 19 | ```python 20 | import os 21 | from crewai import Agent, Task, Crew, Process 22 | 23 | # Define your agents 24 | researcher = Agent( 25 | role="Researcher", 26 | goal="Conduct thorough research and analysis on AI and AI agents", 27 | backstory="You're an expert researcher, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently researching for a new client.", 28 | allow_delegation=False, 29 | ) 30 | 31 | writer = Agent( 32 | role="Senior Writer", 33 | goal="Create compelling content about AI and AI agents", 34 | backstory="You're a senior writer, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently writing content for a new client.", 35 | allow_delegation=False, 36 | ) 37 | 38 | # Define your task 39 | task = Task( 40 | description="Generate a list of 5 interesting ideas for an article, then write one captivating paragraph for each idea that showcases the potential of a full article on this topic. Return the list of ideas with their paragraphs and your notes.", 41 | expected_output="5 bullet points, each with a paragraph and accompanying notes.", 42 | ) 43 | 44 | # Define the manager agent 45 | manager = Agent( 46 | role="Project Manager", 47 | goal="Efficiently manage the crew and ensure high-quality task completion", 48 | backstory="You're an experienced project 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.", 49 | allow_delegation=True, 50 | ) 51 | 52 | # Instantiate your crew with a custom manager 53 | crew = Crew( 54 | agents=[researcher, writer], 55 | tasks=[task], 56 | manager_agent=manager, 57 | process=Process.hierarchical, 58 | ) 59 | 60 | # Start the crew's work 61 | result = crew.kickoff() 62 | ``` 63 | 64 | ## Benefits of a Custom Manager Agent 65 | 66 | - **Enhanced Control**: Tailor the management approach to fit the specific needs of your project. 67 | - **Improved Coordination**: Ensure efficient task coordination and management by an experienced agent. 68 | - **Customizable Management**: Define managerial roles and responsibilities that align with your project's goals. 69 | 70 | ## Setting a Manager LLM 71 | 72 | If you're using the hierarchical process and don't want to set a custom manager agent, you can specify the language model for the manager: 73 | 74 | ```python 75 | from langchain_openai import ChatOpenAI 76 | 77 | manager_llm = ChatOpenAI(model_name="gpt-4") 78 | 79 | crew = Crew( 80 | agents=[researcher, writer], 81 | tasks=[task], 82 | process=Process.hierarchical, 83 | manager_llm=manager_llm 84 | ) 85 | ``` 86 | 87 | Note: Either `manager_agent` or `manager_llm` must be set when using the hierarchical process. -------------------------------------------------------------------------------- /docs/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require('tailwindcss'), require('autoprefixer')] 3 | } -------------------------------------------------------------------------------- /docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | .md-typeset .admonition-title { 2 | margin-bottom: 10px; 3 | } -------------------------------------------------------------------------------- /docs/stylesheets/tailwind.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/base'; 2 | @import 'tailwindcss/components'; 3 | @import 'tailwindcss/utilities'; -------------------------------------------------------------------------------- /docs/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./**/*.md"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | 10 | -------------------------------------------------------------------------------- /docs/telemetry/Telemetry.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Telemetry 3 | description: Understanding the telemetry data collected by CrewAI and how it contributes to the enhancement of the library. 4 | --- 5 | 6 | ## Telemetry 7 | 8 | CrewAI utilizes anonymous telemetry to gather usage statistics with the primary goal of enhancing the library. Our focus is on improving and developing the features, integrations, and tools most utilized by our users. 9 | 10 | It's pivotal to understand that **NO data is collected** concerning prompts, task descriptions, agents' backstories or goals, usage of tools, API calls, responses, any data processed by the agents, or secrets and environment variables, with the exception of the conditions mentioned. When the `share_crew` feature is enabled, detailed data including task descriptions, agents' backstories or goals, and other specific attributes are collected to provide deeper insights while respecting user privacy. 11 | 12 | ### Data Collected Includes: 13 | - **Version of CrewAI**: Assessing the adoption rate of our latest version helps us understand user needs and guide our updates. 14 | - **Python Version**: Identifying the Python versions our users operate with assists in prioritizing our support efforts for these versions. 15 | - **General OS Information**: Details like the number of CPUs and the operating system type (macOS, Windows, Linux) enable us to focus our development on the most used operating systems and explore the potential for OS-specific features. 16 | - **Number of Agents and Tasks in a Crew**: Ensures our internal testing mirrors real-world scenarios, helping us guide users towards best practices. 17 | - **Crew Process Utilization**: Understanding how crews are utilized aids in directing our development focus. 18 | - **Memory and Delegation Use by Agents**: Insights into how these features are used help evaluate their effectiveness and future. 19 | - **Task Execution Mode**: Knowing whether tasks are executed in parallel or sequentially influences our emphasis on enhancing parallel execution capabilities. 20 | - **Language Model Utilization**: Supports our goal to improve support for the most popular languages among our users. 21 | - **Roles of Agents within a Crew**: Understanding the various roles agents play aids in crafting better tools, integrations, and examples. 22 | - **Tool Usage**: Identifying which tools are most frequently used allows us to prioritize improvements in those areas. 23 | 24 | ### Opt-In Further Telemetry Sharing 25 | Users can choose to share their complete telemetry data by enabling the `share_crew` attribute to `True` in their crew configurations. This opt-in approach respects user privacy and aligns with data protection standards by ensuring users have control over their data sharing preferences. Enabling `share_crew` results in the collection of detailed crew and task execution data, including `goal`, `backstory`, `context`, and `output` of tasks. This enables a deeper insight into usage patterns while respecting the user's choice to share. 26 | 27 | ### Updates and Revisions 28 | We are committed to maintaining the accuracy and transparency of our documentation. Regular reviews and updates are performed to ensure our documentation accurately reflects the latest developments of our codebase and telemetry practices. Users are encouraged to review this section for the most current information on our data collection practices and how they contribute to the improvement of CrewAI. -------------------------------------------------------------------------------- /docs/tools/BrowserbaseLoadTool.md: -------------------------------------------------------------------------------- 1 | # BrowserbaseLoadTool 2 | 3 | ## Description 4 | 5 | [Browserbase](https://browserbase.com) is a developer platform to reliably run, manage, and monitor headless browsers. 6 | 7 | Power your AI data retrievals with: 8 | - [Serverless Infrastructure](https://docs.browserbase.com/under-the-hood) providing reliable browsers to extract data from complex UIs 9 | - [Stealth Mode](https://docs.browserbase.com/features/stealth-mode) with included fingerprinting tactics and automatic captcha solving 10 | - [Session Debugger](https://docs.browserbase.com/features/sessions) to inspect your Browser Session with networks timeline and logs 11 | - [Live Debug](https://docs.browserbase.com/guides/session-debug-connection/browser-remote-control) to quickly debug your automation 12 | 13 | ## Installation 14 | 15 | - Get an API key and Project ID from [browserbase.com](https://browserbase.com) and set it in environment variables (`BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`). 16 | - Install the [Browserbase SDK](http://github.com/browserbase/python-sdk) along with `crewai[tools]` package: 17 | 18 | ``` 19 | pip install browserbase 'crewai[tools]' 20 | ``` 21 | 22 | ## Example 23 | 24 | Utilize the BrowserbaseLoadTool as follows to allow your agent to load websites: 25 | 26 | ```python 27 | from crewai_tools import BrowserbaseLoadTool 28 | 29 | tool = BrowserbaseLoadTool() 30 | ``` 31 | 32 | ## Arguments 33 | 34 | - `api_key` Optional. Browserbase API key. Default is `BROWSERBASE_API_KEY` env variable. 35 | - `project_id` Optional. Browserbase Project ID. Default is `BROWSERBASE_PROJECT_ID` env variable. 36 | - `text_content` Retrieve only text content. Default is `False`. 37 | - `session_id` Optional. Provide an existing Session ID. 38 | - `proxy` Optional. Enable/Disable Proxies." 39 | -------------------------------------------------------------------------------- /docs/tools/CSVSearchTool.md: -------------------------------------------------------------------------------- 1 | # CSVSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | 8 | This tool is used to perform a RAG (Retrieval-Augmented Generation) search within a CSV file's content. It allows users to semantically search for queries in the content of a specified CSV file. This feature is particularly useful for extracting information from large CSV datasets where traditional search methods might be inefficient. All tools with "Search" in their name, including CSVSearchTool, are RAG tools designed for searching different sources of data. 9 | 10 | ## Installation 11 | 12 | Install the crewai_tools package 13 | 14 | ```shell 15 | pip install 'crewai[tools]' 16 | ``` 17 | 18 | ## Example 19 | 20 | ```python 21 | from crewai_tools import CSVSearchTool 22 | 23 | # Initialize the tool with a specific CSV file. This setup allows the agent to only search the given CSV file. 24 | tool = CSVSearchTool(csv='path/to/your/csvfile.csv') 25 | 26 | # OR 27 | 28 | # Initialize the tool without a specific CSV file. Agent will need to provide the CSV path at runtime. 29 | tool = CSVSearchTool() 30 | ``` 31 | 32 | ## Arguments 33 | 34 | - `csv` : The path to the CSV file you want to search. This is a mandatory argument if the tool was initialized without a specific CSV file; otherwise, it is optional. 35 | 36 | ## Custom model and embeddings 37 | 38 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 39 | 40 | ```python 41 | tool = CSVSearchTool( 42 | config=dict( 43 | llm=dict( 44 | provider="ollama", # or google, openai, anthropic, llama2, ... 45 | config=dict( 46 | model="llama2", 47 | # temperature=0.5, 48 | # top_p=1, 49 | # stream=true, 50 | ), 51 | ), 52 | embedder=dict( 53 | provider="google", # or openai, ollama, ... 54 | config=dict( 55 | model="models/embedding-001", 56 | task_type="retrieval_document", 57 | # title="Embeddings", 58 | ), 59 | ), 60 | ) 61 | ) 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/tools/CodeDocsSearchTool.md: -------------------------------------------------------------------------------- 1 | # CodeDocsSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | 8 | The CodeDocsSearchTool is a powerful RAG (Retrieval-Augmented Generation) tool designed for semantic searches within code documentation. It enables users to efficiently find specific information or topics within code documentation. By providing a `docs_url` during initialization, the tool narrows down the search to that particular documentation site. Alternatively, without a specific `docs_url`, it searches across a wide array of code documentation known or discovered throughout its execution, making it versatile for various documentation search needs. 9 | 10 | ## Installation 11 | 12 | To start using the CodeDocsSearchTool, first, install the crewai_tools package via pip: 13 | 14 | ``` 15 | pip install 'crewai[tools]' 16 | ``` 17 | 18 | ## Example 19 | 20 | Utilize the CodeDocsSearchTool as follows to conduct searches within code documentation: 21 | 22 | ```python 23 | from crewai_tools import CodeDocsSearchTool 24 | 25 | # To search any code documentation content if the URL is known or discovered during its execution: 26 | tool = CodeDocsSearchTool() 27 | 28 | # OR 29 | 30 | # To specifically focus your search on a given documentation site by providing its URL: 31 | tool = CodeDocsSearchTool(docs_url='https://docs.example.com/reference') 32 | ``` 33 | Note: Substitute 'https://docs.example.com/reference' with your target documentation URL and 'How to use search tool' with the search query relevant to your needs. 34 | 35 | ## Arguments 36 | 37 | - `docs_url`: Optional. Specifies the URL of the code documentation to be searched. Providing this during the tool's initialization focuses the search on the specified documentation content. 38 | 39 | ## Custom model and embeddings 40 | 41 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 42 | 43 | ```python 44 | tool = CodeDocsSearchTool( 45 | config=dict( 46 | llm=dict( 47 | provider="ollama", # or google, openai, anthropic, llama2, ... 48 | config=dict( 49 | model="llama2", 50 | # temperature=0.5, 51 | # top_p=1, 52 | # stream=true, 53 | ), 54 | ), 55 | embedder=dict( 56 | provider="google", # or openai, ollama, ... 57 | config=dict( 58 | model="models/embedding-001", 59 | task_type="retrieval_document", 60 | # title="Embeddings", 61 | ), 62 | ), 63 | ) 64 | ) 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/tools/CodeInterpreterTool.md: -------------------------------------------------------------------------------- 1 | # CodeInterpreterTool 2 | 3 | ## Description 4 | This tool is used to give the Agent the ability to run code (Python3) from the code generated by the Agent itself. The code is executed in a sandboxed environment, so it is safe to run any code. 5 | 6 | It is incredible useful since it allows the Agent to generate code, run it in the same environment, get the result and use it to make decisions. 7 | 8 | ## Requirements 9 | 10 | - Docker 11 | 12 | ## Installation 13 | Install the crewai_tools package 14 | ```shell 15 | pip install 'crewai[tools]' 16 | ``` 17 | 18 | ## Example 19 | 20 | Remember that when using this tool, the code must be generated by the Agent itself. The code must be a Python3 code. And it will take some time for the first time to run because it needs to build the Docker image. 21 | 22 | ```python 23 | from crewai import Agent 24 | from crewai_tools import CodeInterpreterTool 25 | 26 | Agent( 27 | ... 28 | tools=[CodeInterpreterTool()], 29 | ) 30 | ``` 31 | 32 | We also provide a simple way to use it directly from the Agent. 33 | 34 | ```python 35 | from crewai import Agent 36 | 37 | agent = Agent( 38 | ... 39 | allow_code_execution=True, 40 | ) 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/tools/ComposioTool.md: -------------------------------------------------------------------------------- 1 | # ComposioTool Documentation 2 | 3 | ## Description 4 | 5 | This tools is a wrapper around the composio toolset and gives your agent access to a wide variety of tools from the composio SDK. 6 | 7 | ## Installation 8 | 9 | To incorporate this tool into your project, follow the installation instructions below: 10 | 11 | ```shell 12 | pip install composio-core 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | after the installation is complete, either run `composio login` or export your composio API key as `COMPOSIO_API_KEY`. 17 | 18 | ## Example 19 | 20 | The following example demonstrates how to initialize the tool and execute a github action: 21 | 22 | 1. Initialize toolset 23 | 24 | ```python 25 | from composio import App 26 | from crewai_tools import ComposioTool 27 | from crewai import Agent, Task 28 | 29 | 30 | tools = [ComposioTool.from_action(action=Action.GITHUB_ACTIVITY_STAR_REPO_FOR_AUTHENTICATED_USER)] 31 | ``` 32 | 33 | If you don't know what action you want to use, use `from_app` and `tags` filter to get relevant actions 34 | 35 | ```python 36 | tools = ComposioTool.from_app(App.GITHUB, tags=["important"]) 37 | ``` 38 | 39 | or use `use_case` to search relevant actions 40 | 41 | ```python 42 | tools = ComposioTool.from_app(App.GITHUB, use_case="Star a github repository") 43 | ``` 44 | 45 | 2. Define agent 46 | 47 | ```python 48 | crewai_agent = Agent( 49 | role="Github Agent", 50 | goal="You take action on Github using Github APIs", 51 | backstory=( 52 | "You are AI agent that is responsible for taking actions on Github " 53 | "on users behalf. You need to take action on Github using Github APIs" 54 | ), 55 | verbose=True, 56 | tools=tools, 57 | ) 58 | ``` 59 | 60 | 3. Execute task 61 | 62 | ```python 63 | task = Task( 64 | description="Star a repo ComposioHQ/composio on GitHub", 65 | agent=crewai_agent, 66 | expected_output="if the star happened", 67 | ) 68 | 69 | task.execute() 70 | ``` 71 | 72 | * More detailed list of tools can be found [here](https://app.composio.dev) 73 | -------------------------------------------------------------------------------- /docs/tools/DOCXSearchTool.md: -------------------------------------------------------------------------------- 1 | # DOCXSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | The DOCXSearchTool is a RAG tool designed for semantic searching within DOCX documents. It enables users to effectively search and extract relevant information from DOCX files using query-based searches. This tool is invaluable for data analysis, information management, and research tasks, streamlining the process of finding specific information within large document collections. 8 | 9 | ## Installation 10 | Install the crewai_tools package by running the following command in your terminal: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Example 17 | The following example demonstrates initializing the DOCXSearchTool to search within any DOCX file's content or with a specific DOCX file path. 18 | 19 | ```python 20 | from crewai_tools import DOCXSearchTool 21 | 22 | # Initialize the tool to search within any DOCX file's content 23 | tool = DOCXSearchTool() 24 | 25 | # OR 26 | 27 | # Initialize the tool with a specific DOCX file, so the agent can only search the content of the specified DOCX file 28 | tool = DOCXSearchTool(docx='path/to/your/document.docx') 29 | ``` 30 | 31 | ## Arguments 32 | - `docx`: An optional file path to a specific DOCX document you wish to search. If not provided during initialization, the tool allows for later specification of any DOCX file's content path for searching. 33 | 34 | ## Custom model and embeddings 35 | 36 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 37 | 38 | ```python 39 | tool = DOCXSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # or google, openai, anthropic, llama2, ... 43 | config=dict( 44 | model="llama2", 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | ), 49 | ), 50 | embedder=dict( 51 | provider="google", # or openai, ollama, ... 52 | config=dict( 53 | model="models/embedding-001", 54 | task_type="retrieval_document", 55 | # title="Embeddings", 56 | ), 57 | ), 58 | ) 59 | ) 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/tools/DirectoryReadTool.md: -------------------------------------------------------------------------------- 1 | ```markdown 2 | # DirectoryReadTool 3 | 4 | !!! note "Experimental" 5 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 6 | 7 | ## Description 8 | The DirectoryReadTool is a powerful utility designed to provide a comprehensive listing of directory contents. It can recursively navigate through the specified directory, offering users a detailed enumeration of all files, including those within subdirectories. This tool is crucial for tasks that require a thorough inventory of directory structures or for validating the organization of files within directories. 9 | 10 | ## Installation 11 | To utilize the DirectoryReadTool in your project, install the `crewai_tools` package. If this package is not yet part of your environment, you can install it using pip with the command below: 12 | 13 | ```shell 14 | pip install 'crewai[tools]' 15 | ``` 16 | 17 | This command installs the latest version of the `crewai_tools` package, granting access to the DirectoryReadTool among other utilities. 18 | 19 | ## Example 20 | Employing the DirectoryReadTool is straightforward. The following code snippet demonstrates how to set it up and use the tool to list the contents of a specified directory: 21 | 22 | ```python 23 | from crewai_tools import DirectoryReadTool 24 | 25 | # Initialize the tool so the agent can read any directory's content it learns about during execution 26 | tool = DirectoryReadTool() 27 | 28 | # OR 29 | 30 | # Initialize the tool with a specific directory, so the agent can only read the content of the specified directory 31 | tool = DirectoryReadTool(directory='/path/to/your/directory') 32 | ``` 33 | 34 | ## Arguments 35 | The DirectoryReadTool requires minimal configuration for use. The essential argument for this tool is as follows: 36 | 37 | - `directory`: **Optional**. An argument that specifies the path to the directory whose contents you wish to list. It accepts both absolute and relative paths, guiding the tool to the desired directory for content listing. -------------------------------------------------------------------------------- /docs/tools/DirectorySearchTool.md: -------------------------------------------------------------------------------- 1 | # DirectorySearchTool 2 | 3 | !!! note "Experimental" 4 | The DirectorySearchTool is under continuous development. Features and functionalities might evolve, and unexpected behavior may occur as we refine the tool. 5 | 6 | ## Description 7 | The DirectorySearchTool enables semantic search within the content of specified directories, leveraging the Retrieval-Augmented Generation (RAG) methodology for efficient navigation through files. Designed for flexibility, it allows users to dynamically specify search directories at runtime or set a fixed directory during initial setup. 8 | 9 | ## Installation 10 | To use the DirectorySearchTool, begin by installing the crewai_tools package. Execute the following command in your terminal: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Initialization and Usage 17 | Import the DirectorySearchTool from the `crewai_tools` package to start. You can initialize the tool without specifying a directory, enabling the setting of the search directory at runtime. Alternatively, the tool can be initialized with a predefined directory. 18 | 19 | ```python 20 | from crewai_tools import DirectorySearchTool 21 | 22 | # For dynamic directory specification at runtime 23 | tool = DirectorySearchTool() 24 | 25 | # For fixed directory searches 26 | tool = DirectorySearchTool(directory='/path/to/directory') 27 | ``` 28 | 29 | ## Arguments 30 | - `directory`: A string argument that specifies the search directory. This is optional during initialization but required for searches if not set initially. 31 | 32 | ## Custom Model and Embeddings 33 | The DirectorySearchTool uses OpenAI for embeddings and summarization by default. Customization options for these settings include changing the model provider and configuration, enhancing flexibility for advanced users. 34 | 35 | ```python 36 | tool = DirectorySearchTool( 37 | config=dict( 38 | llm=dict( 39 | provider="ollama", # Options include ollama, google, anthropic, llama2, and more 40 | config=dict( 41 | model="llama2", 42 | # Additional configurations here 43 | ), 44 | ), 45 | embedder=dict( 46 | provider="google", # or openai, ollama, ... 47 | config=dict( 48 | model="models/embedding-001", 49 | task_type="retrieval_document", 50 | # title="Embeddings", 51 | ), 52 | ), 53 | ) 54 | ) 55 | ``` -------------------------------------------------------------------------------- /docs/tools/EXASearchTool.md: -------------------------------------------------------------------------------- 1 | # EXASearchTool Documentation 2 | 3 | ## Description 4 | 5 | The EXASearchTool is designed to perform a semantic search for a specified query from a text's content across the internet. It utilizes the [exa.ai](https://exa.ai/) API to fetch and display the most relevant search results based on the query provided by the user. 6 | 7 | ## Installation 8 | 9 | To incorporate this tool into your project, follow the installation instructions below: 10 | 11 | ```shell 12 | pip install 'crewai[tools]' 13 | ``` 14 | 15 | ## Example 16 | 17 | The following example demonstrates how to initialize the tool and execute a search with a given query: 18 | 19 | ```python 20 | from crewai_tools import EXASearchTool 21 | 22 | # Initialize the tool for internet searching capabilities 23 | tool = EXASearchTool() 24 | ``` 25 | 26 | ## Steps to Get Started 27 | 28 | To effectively use the EXASearchTool, follow these steps: 29 | 30 | 1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment. 31 | 2. **API Key Acquisition**: Acquire a [exa.ai](https://exa.ai/) API key by registering for a free account at [exa.ai](https://exa.ai/). 32 | 3. **Environment Configuration**: Store your obtained API key in an environment variable named `EXA_API_KEY` to facilitate its use by the tool. 33 | 34 | ## Conclusion 35 | 36 | By integrating the EXASearchTool into Python projects, users gain the ability to conduct real-time, relevant searches across the internet directly from their applications. By adhering to the setup and usage guidelines provided, incorporating this tool into projects is streamlined and straightforward. 37 | -------------------------------------------------------------------------------- /docs/tools/FileReadTool.md: -------------------------------------------------------------------------------- 1 | # FileReadTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | The FileReadTool conceptually represents a suite of functionalities within the crewai_tools package aimed at facilitating file reading and content retrieval. This suite includes tools for processing batch text files, reading runtime configuration files, and importing data for analytics. It supports a variety of text-based file formats such as `.txt`, `.csv`, `.json`, and more. Depending on the file type, the suite offers specialized functionality, such as converting JSON content into a Python dictionary for ease of use. 8 | 9 | ## Installation 10 | To utilize the functionalities previously attributed to the FileReadTool, install the crewai_tools package: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Usage Example 17 | To get started with the FileReadTool: 18 | 19 | ```python 20 | from crewai_tools import FileReadTool 21 | 22 | # Initialize the tool to read any files the agents knows or lean the path for 23 | file_read_tool = FileReadTool() 24 | 25 | # OR 26 | 27 | # Initialize the tool with a specific file path, so the agent can only read the content of the specified file 28 | file_read_tool = FileReadTool(file_path='path/to/your/file.txt') 29 | ``` 30 | 31 | ## Arguments 32 | - `file_path`: The path to the file you want to read. It accepts both absolute and relative paths. Ensure the file exists and you have the necessary permissions to access it. -------------------------------------------------------------------------------- /docs/tools/GitHubSearchTool.md: -------------------------------------------------------------------------------- 1 | # GithubSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | The GithubSearchTool is a Retrieval-Augmented Generation (RAG) tool specifically designed for conducting semantic searches within GitHub repositories. Utilizing advanced semantic search capabilities, it sifts through code, pull requests, issues, and repositories, making it an essential tool for developers, researchers, or anyone in need of precise information from GitHub. 8 | 9 | ## Installation 10 | To use the GithubSearchTool, first ensure the crewai_tools package is installed in your Python environment: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | This command installs the necessary package to run the GithubSearchTool along with any other tools included in the crewai_tools package. 17 | 18 | ## Example 19 | Here’s how you can use the GithubSearchTool to perform semantic searches within a GitHub repository: 20 | ```python 21 | from crewai_tools import GithubSearchTool 22 | 23 | # Initialize the tool for semantic searches within a specific GitHub repository 24 | tool = GithubSearchTool( 25 | github_repo='https://github.com/example/repo', 26 | content_types=['code', 'issue'] # Options: code, repo, pr, issue 27 | ) 28 | 29 | # OR 30 | 31 | # Initialize the tool for semantic searches within a specific GitHub repository, so the agent can search any repository if it learns about during its execution 32 | tool = GithubSearchTool( 33 | content_types=['code', 'issue'] # Options: code, repo, pr, issue 34 | ) 35 | ``` 36 | 37 | ## Arguments 38 | - `github_repo` : The URL of the GitHub repository where the search will be conducted. This is a mandatory field and specifies the target repository for your search. 39 | - `content_types` : Specifies the types of content to include in your search. You must provide a list of content types from the following options: `code` for searching within the code, `repo` for searching within the repository's general information, `pr` for searching within pull requests, and `issue` for searching within issues. This field is mandatory and allows tailoring the search to specific content types within the GitHub repository. 40 | 41 | ## Custom model and embeddings 42 | 43 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 44 | 45 | ```python 46 | tool = GithubSearchTool( 47 | config=dict( 48 | llm=dict( 49 | provider="ollama", # or google, openai, anthropic, llama2, ... 50 | config=dict( 51 | model="llama2", 52 | # temperature=0.5, 53 | # top_p=1, 54 | # stream=true, 55 | ), 56 | ), 57 | embedder=dict( 58 | provider="google", # or openai, ollama, ... 59 | config=dict( 60 | model="models/embedding-001", 61 | task_type="retrieval_document", 62 | # title="Embeddings", 63 | ), 64 | ), 65 | ) 66 | ) 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/tools/JSONSearchTool.md: -------------------------------------------------------------------------------- 1 | # JSONSearchTool 2 | 3 | !!! note "Experimental Status" 4 | The JSONSearchTool is currently in an experimental phase. This means the tool is under active development, and users might encounter unexpected behavior or changes. We highly encourage feedback on any issues or suggestions for improvements. 5 | 6 | ## Description 7 | The JSONSearchTool is designed to facilitate efficient and precise searches within JSON file contents. It utilizes a RAG (Retrieve and Generate) search mechanism, allowing users to specify a JSON path for targeted searches within a particular JSON file. This capability significantly improves the accuracy and relevance of search results. 8 | 9 | ## Installation 10 | To install the JSONSearchTool, use the following pip command: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Usage Examples 17 | Here are updated examples on how to utilize the JSONSearchTool effectively for searching within JSON files. These examples take into account the current implementation and usage patterns identified in the codebase. 18 | 19 | ```python 20 | from crewai.json_tools import JSONSearchTool # Updated import path 21 | 22 | # General JSON content search 23 | # This approach is suitable when the JSON path is either known beforehand or can be dynamically identified. 24 | tool = JSONSearchTool() 25 | 26 | # Restricting search to a specific JSON file 27 | # Use this initialization method when you want to limit the search scope to a specific JSON file. 28 | tool = JSONSearchTool(json_path='./path/to/your/file.json') 29 | ``` 30 | 31 | ## Arguments 32 | - `json_path` (str, optional): Specifies the path to the JSON file to be searched. This argument is not required if the tool is initialized for a general search. When provided, it confines the search to the specified JSON file. 33 | 34 | ## Configuration Options 35 | The JSONSearchTool supports extensive customization through a configuration dictionary. This allows users to select different models for embeddings and summarization based on their requirements. 36 | 37 | ```python 38 | tool = JSONSearchTool( 39 | config={ 40 | "llm": { 41 | "provider": "ollama", # Other options include google, openai, anthropic, llama2, etc. 42 | "config": { 43 | "model": "llama2", 44 | # Additional optional configurations can be specified here. 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | }, 49 | }, 50 | "embedder": { 51 | "provider": "google", # or openai, ollama, ... 52 | "config": { 53 | "model": "models/embedding-001", 54 | "task_type": "retrieval_document", 55 | # Further customization options can be added here. 56 | }, 57 | }, 58 | } 59 | ) 60 | ``` -------------------------------------------------------------------------------- /docs/tools/MDXSearchTool.md: -------------------------------------------------------------------------------- 1 | # MDXSearchTool 2 | 3 | !!! note "Experimental" 4 | The MDXSearchTool is in continuous development. Features may be added or removed, and functionality could change unpredictably as we refine the tool. 5 | 6 | ## Description 7 | The MDX Search Tool is a component of the `crewai_tools` package aimed at facilitating advanced markdown language extraction. It enables users to effectively search and extract relevant information from MD files using query-based searches. This tool is invaluable for data analysis, information management, and research tasks, streamlining the process of finding specific information within large document collections. 8 | 9 | ## Installation 10 | Before using the MDX Search Tool, ensure the `crewai_tools` package is installed. If it is not, you can install it with the following command: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Usage Example 17 | To use the MDX Search Tool, you must first set up the necessary environment variables. Then, integrate the tool into your crewAI project to begin your market research. Below is a basic example of how to do this: 18 | 19 | ```python 20 | from crewai_tools import MDXSearchTool 21 | 22 | # Initialize the tool to search any MDX content it learns about during execution 23 | tool = MDXSearchTool() 24 | 25 | # OR 26 | 27 | # Initialize the tool with a specific MDX file path for an exclusive search within that document 28 | tool = MDXSearchTool(mdx='path/to/your/document.mdx') 29 | ``` 30 | 31 | ## Parameters 32 | - mdx: **Optional**. Specifies the MDX file path for the search. It can be provided during initialization. 33 | 34 | ## Customization of Model and Embeddings 35 | 36 | The tool defaults to using OpenAI for embeddings and summarization. For customization, utilize a configuration dictionary as shown below: 37 | 38 | ```python 39 | tool = MDXSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # Options include google, openai, anthropic, llama2, etc. 43 | config=dict( 44 | model="llama2", 45 | # Optional parameters can be included here. 46 | # temperature=0.5, 47 | # top_p=1, 48 | # stream=true, 49 | ), 50 | ), 51 | embedder=dict( 52 | provider="google", # or openai, ollama, ... 53 | config=dict( 54 | model="models/embedding-001", 55 | task_type="retrieval_document", 56 | # Optional title for the embeddings can be added here. 57 | # title="Embeddings", 58 | ), 59 | ), 60 | ) 61 | ) 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/tools/PDFSearchTool.md: -------------------------------------------------------------------------------- 1 | # PDFSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | The PDFSearchTool is a RAG tool designed for semantic searches within PDF content. It allows for inputting a search query and a PDF document, leveraging advanced search techniques to find relevant content efficiently. This capability makes it especially useful for extracting specific information from large PDF files quickly. 8 | 9 | ## Installation 10 | To get started with the PDFSearchTool, first, ensure the crewai_tools package is installed with the following command: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Example 17 | Here's how to use the PDFSearchTool to search within a PDF document: 18 | 19 | ```python 20 | from crewai_tools import PDFSearchTool 21 | 22 | # Initialize the tool allowing for any PDF content search if the path is provided during execution 23 | tool = PDFSearchTool() 24 | 25 | # OR 26 | 27 | # Initialize the tool with a specific PDF path for exclusive search within that document 28 | tool = PDFSearchTool(pdf='path/to/your/document.pdf') 29 | ``` 30 | 31 | ## Arguments 32 | - `pdf`: **Optional** The PDF path for the search. Can be provided at initialization or within the `run` method's arguments. If provided at initialization, the tool confines its search to the specified document. 33 | 34 | ## Custom model and embeddings 35 | 36 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 37 | 38 | ```python 39 | tool = PDFSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # or google, openai, anthropic, llama2, ... 43 | config=dict( 44 | model="llama2", 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | ), 49 | ), 50 | embedder=dict( 51 | provider="google", # or openai, ollama, ... 52 | config=dict( 53 | model="models/embedding-001", 54 | task_type="retrieval_document", 55 | # title="Embeddings", 56 | ), 57 | ), 58 | ) 59 | ) 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/tools/PGSearchTool.md: -------------------------------------------------------------------------------- 1 | # PGSearchTool 2 | 3 | !!! note "Under Development" 4 | The PGSearchTool is currently under development. This document outlines the intended functionality and interface. As development progresses, please be aware that some features may not be available or could change. 5 | 6 | ## Description 7 | The PGSearchTool is envisioned as a powerful tool for facilitating semantic searches within PostgreSQL database tables. By leveraging advanced Retrieve and Generate (RAG) technology, it aims to provide an efficient means for querying database table content, specifically tailored for PostgreSQL databases. The tool's goal is to simplify the process of finding relevant data through semantic search queries, offering a valuable resource for users needing to conduct advanced queries on extensive datasets within a PostgreSQL environment. 8 | 9 | ## Installation 10 | The `crewai_tools` package, which will include the PGSearchTool upon its release, can be installed using the following command: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | (Note: The PGSearchTool is not yet available in the current version of the `crewai_tools` package. This installation command will be updated once the tool is released.) 17 | 18 | ## Example Usage 19 | Below is a proposed example showcasing how to use the PGSearchTool for conducting a semantic search on a table within a PostgreSQL database: 20 | 21 | ```python 22 | from crewai_tools import PGSearchTool 23 | 24 | # Initialize the tool with the database URI and the target table name 25 | tool = PGSearchTool(db_uri='postgresql://user:password@localhost:5432/mydatabase', table_name='employees') 26 | ``` 27 | 28 | ## Arguments 29 | The PGSearchTool is designed to require the following arguments for its operation: 30 | 31 | - `db_uri`: A string representing the URI of the PostgreSQL database to be queried. This argument will be mandatory and must include the necessary authentication details and the location of the database. 32 | - `table_name`: A string specifying the name of the table within the database on which the semantic search will be performed. This argument will also be mandatory. 33 | 34 | ## Custom Model and Embeddings 35 | 36 | The tool intends to use OpenAI for both embeddings and summarization by default. Users will have the option to customize the model using a config dictionary as follows: 37 | 38 | ```python 39 | tool = PGSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # or google, openai, anthropic, llama2, ... 43 | config=dict( 44 | model="llama2", 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | ), 49 | ), 50 | embedder=dict( 51 | provider="google", # or openai, ollama, ... 52 | config=dict( 53 | model="models/embedding-001", 54 | task_type="retrieval_document", 55 | # title="Embeddings", 56 | ), 57 | ), 58 | ) 59 | ) 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/tools/ScrapeWebsiteTool.md: -------------------------------------------------------------------------------- 1 | # ScrapeWebsiteTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | A tool designed to extract and read the content of a specified website. It is capable of handling various types of web pages by making HTTP requests and parsing the received HTML content. This tool can be particularly useful for web scraping tasks, data collection, or extracting specific information from websites. 8 | 9 | ## Installation 10 | Install the crewai_tools package 11 | ```shell 12 | pip install 'crewai[tools]' 13 | ``` 14 | 15 | ## Example 16 | ```python 17 | from crewai_tools import ScrapeWebsiteTool 18 | 19 | # To enable scrapping any website it finds during it's execution 20 | tool = ScrapeWebsiteTool() 21 | 22 | # Initialize the tool with the website URL, so the agent can only scrap the content of the specified website 23 | tool = ScrapeWebsiteTool(website_url='https://www.example.com') 24 | 25 | # Extract the text from the site 26 | text = tool.run() 27 | print(text) 28 | ``` 29 | 30 | ## Arguments 31 | - `website_url` : Mandatory website URL to read the file. This is the primary input for the tool, specifying which website's content should be scraped and read. 32 | -------------------------------------------------------------------------------- /docs/tools/SeleniumScrapingTool.md: -------------------------------------------------------------------------------- 1 | # SeleniumScrapingTool 2 | 3 | !!! note "Experimental" 4 | This tool is currently in development. As we refine its capabilities, users may encounter unexpected behavior. Your feedback is invaluable to us for making improvements. 5 | 6 | ## Description 7 | The SeleniumScrapingTool is crafted for high-efficiency web scraping tasks. It allows for precise extraction of content from web pages by using CSS selectors to target specific elements. Its design caters to a wide range of scraping needs, offering flexibility to work with any provided website URL. 8 | 9 | ## Installation 10 | To get started with the SeleniumScrapingTool, install the crewai_tools package using pip: 11 | 12 | ``` 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Usage Examples 17 | Below are some scenarios where the SeleniumScrapingTool can be utilized: 18 | 19 | ```python 20 | from crewai_tools import SeleniumScrapingTool 21 | 22 | # Example 1: Initialize the tool without any parameters to scrape the current page it navigates to 23 | tool = SeleniumScrapingTool() 24 | 25 | # Example 2: Scrape the entire webpage of a given URL 26 | tool = SeleniumScrapingTool(website_url='https://example.com') 27 | 28 | # Example 3: Target and scrape a specific CSS element from a webpage 29 | tool = SeleniumScrapingTool(website_url='https://example.com', css_element='.main-content') 30 | 31 | # Example 4: Perform scraping with additional parameters for a customized experience 32 | tool = SeleniumScrapingTool(website_url='https://example.com', css_element='.main-content', cookie={'name': 'user', 'value': 'John Doe'}, wait_time=10) 33 | ``` 34 | 35 | ## Arguments 36 | The following parameters can be used to customize the SeleniumScrapingTool's scraping process: 37 | 38 | - `website_url`: **Mandatory**. Specifies the URL of the website from which content is to be scraped. 39 | - `css_element`: **Mandatory**. The CSS selector for a specific element to target on the website. This enables focused scraping of a particular part of a webpage. 40 | - `cookie`: **Optional**. A dictionary that contains cookie information. Useful for simulating a logged-in session, thereby providing access to content that might be restricted to non-logged-in users. 41 | - `wait_time`: **Optional**. Specifies the delay (in seconds) before the content is scraped. This delay allows for the website and any dynamic content to fully load, ensuring a successful scrape. 42 | 43 | !!! attention 44 | Since the SeleniumScrapingTool is under active development, the parameters and functionality may evolve over time. Users are encouraged to keep the tool updated and report any issues or suggestions for enhancements. -------------------------------------------------------------------------------- /docs/tools/SerperDevTool.md: -------------------------------------------------------------------------------- 1 | # SerperDevTool Documentation 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | This tool is designed to perform a semantic search for a specified query from a text's content across the internet. It utilizes the [serper.dev](https://serper.dev) API to fetch and display the most relevant search results based on the query provided by the user. 8 | 9 | ## Installation 10 | To incorporate this tool into your project, follow the installation instructions below: 11 | ```shell 12 | pip install 'crewai[tools]' 13 | ``` 14 | 15 | ## Example 16 | The following example demonstrates how to initialize the tool and execute a search with a given query: 17 | 18 | ```python 19 | from crewai_tools import SerperDevTool 20 | 21 | # Initialize the tool for internet searching capabilities 22 | tool = SerperDevTool() 23 | ``` 24 | 25 | ## Steps to Get Started 26 | To effectively use the `SerperDevTool`, follow these steps: 27 | 28 | 1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment. 29 | 2. **API Key Acquisition**: Acquire a `serper.dev` API key by registering for a free account at `serper.dev`. 30 | 3. **Environment Configuration**: Store your obtained API key in an environment variable named `SERPER_API_KEY` to facilitate its use by the tool. 31 | 32 | ## Conclusion 33 | By integrating the `SerperDevTool` into Python projects, users gain the ability to conduct real-time, relevant searches across the internet directly from their applications. By adhering to the setup and usage guidelines provided, incorporating this tool into projects is streamlined and straightforward. 34 | -------------------------------------------------------------------------------- /docs/tools/TXTSearchTool.md: -------------------------------------------------------------------------------- 1 | # TXTSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | This tool is used to perform a RAG (Retrieval-Augmented Generation) search within the content of a text file. It allows for semantic searching of a query within a specified text file's content, making it an invaluable resource for quickly extracting information or finding specific sections of text based on the query provided. 8 | 9 | ## Installation 10 | To use the TXTSearchTool, you first need to install the crewai_tools package. This can be done using pip, a package manager for Python. Open your terminal or command prompt and enter the following command: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | This command will download and install the TXTSearchTool along with any necessary dependencies. 17 | 18 | ## Example 19 | The following example demonstrates how to use the TXTSearchTool to search within a text file. This example shows both the initialization of the tool with a specific text file and the subsequent search within that file's content. 20 | 21 | ```python 22 | from crewai_tools import TXTSearchTool 23 | 24 | # Initialize the tool to search within any text file's content the agent learns about during its execution 25 | tool = TXTSearchTool() 26 | 27 | # OR 28 | 29 | # Initialize the tool with a specific text file, so the agent can search within the given text file's content 30 | tool = TXTSearchTool(txt='path/to/text/file.txt') 31 | ``` 32 | 33 | ## Arguments 34 | - `txt` (str): **Optional**. The path to the text file you want to search. This argument is only required if the tool was not initialized with a specific text file; otherwise, the search will be conducted within the initially provided text file. 35 | 36 | ## Custom model and embeddings 37 | 38 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 39 | 40 | ```python 41 | tool = TXTSearchTool( 42 | config=dict( 43 | llm=dict( 44 | provider="ollama", # or google, openai, anthropic, llama2, ... 45 | config=dict( 46 | model="llama2", 47 | # temperature=0.5, 48 | # top_p=1, 49 | # stream=true, 50 | ), 51 | ), 52 | embedder=dict( 53 | provider="google", # or openai, ollama, ... 54 | config=dict( 55 | model="models/embedding-001", 56 | task_type="retrieval_document", 57 | # title="Embeddings", 58 | ), 59 | ), 60 | ) 61 | ) 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/tools/WebsiteSearchTool.md: -------------------------------------------------------------------------------- 1 | # WebsiteSearchTool 2 | 3 | !!! note "Experimental Status" 4 | The WebsiteSearchTool is currently in an experimental phase. We are actively working on incorporating this tool into our suite of offerings and will update the documentation accordingly. 5 | 6 | ## Description 7 | The WebsiteSearchTool is designed as a concept for conducting semantic searches within the content of websites. It aims to leverage advanced machine learning models like Retrieval-Augmented Generation (RAG) to navigate and extract information from specified URLs efficiently. This tool intends to offer flexibility, allowing users to perform searches across any website or focus on specific websites of interest. Please note, the current implementation details of the WebsiteSearchTool are under development, and its functionalities as described may not yet be accessible. 8 | 9 | ## Installation 10 | To prepare your environment for when the WebsiteSearchTool becomes available, you can install the foundational package with: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | This command installs the necessary dependencies to ensure that once the tool is fully integrated, users can start using it immediately. 17 | 18 | ## Example Usage 19 | Below are examples of how the WebsiteSearchTool could be utilized in different scenarios. Please note, these examples are illustrative and represent planned functionality: 20 | 21 | ```python 22 | from crewai_tools import WebsiteSearchTool 23 | 24 | # Example of initiating tool that agents can use to search across any discovered websites 25 | tool = WebsiteSearchTool() 26 | 27 | # Example of limiting the search to the content of a specific website, so now agents can only search within that website 28 | tool = WebsiteSearchTool(website='https://example.com') 29 | ``` 30 | 31 | ## Arguments 32 | - `website`: An optional argument intended to specify the website URL for focused searches. This argument is designed to enhance the tool's flexibility by allowing targeted searches when necessary. 33 | 34 | ## Customization Options 35 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 36 | 37 | 38 | ```python 39 | tool = WebsiteSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # or google, openai, anthropic, llama2, ... 43 | config=dict( 44 | model="llama2", 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | ), 49 | ), 50 | embedder=dict( 51 | provider="google", # or openai, ollama, ... 52 | config=dict( 53 | model="models/embedding-001", 54 | task_type="retrieval_document", 55 | # title="Embeddings", 56 | ), 57 | ), 58 | ) 59 | ) 60 | ``` -------------------------------------------------------------------------------- /docs/tools/XMLSearchTool.md: -------------------------------------------------------------------------------- 1 | # XMLSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | The XMLSearchTool is a cutting-edge RAG tool engineered for conducting semantic searches within XML files. Ideal for users needing to parse and extract information from XML content efficiently, this tool supports inputting a search query and an optional XML file path. By specifying an XML path, users can target their search more precisely to the content of that file, thereby obtaining more relevant search outcomes. 8 | 9 | ## Installation 10 | To start using the XMLSearchTool, you must first install the crewai_tools package. This can be easily done with the following command: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Example 17 | 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. 18 | 19 | ```python 20 | from crewai_tools import XMLSearchTool 21 | 22 | # Allow agents to search within any XML file's content as it learns about their paths during execution 23 | tool = XMLSearchTool() 24 | 25 | # OR 26 | 27 | # Initialize the tool with a specific XML file path for exclusive search within that document 28 | tool = XMLSearchTool(xml='path/to/your/xmlfile.xml') 29 | ``` 30 | 31 | ## Arguments 32 | - `xml`: This is the path to the XML file you wish to search. It is an optional parameter during the tool's initialization but must be provided either at initialization or as part of the `run` method's arguments to execute a search. 33 | 34 | ## Custom model and embeddings 35 | 36 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 37 | 38 | ```python 39 | tool = XMLSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # or google, openai, anthropic, llama2, ... 43 | config=dict( 44 | model="llama2", 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | ), 49 | ), 50 | embedder=dict( 51 | provider="google", # or openai, ollama, ... 52 | config=dict( 53 | model="models/embedding-001", 54 | task_type="retrieval_document", 55 | # title="Embeddings", 56 | ), 57 | ), 58 | ) 59 | ) 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/tools/YoutubeChannelSearchTool.md: -------------------------------------------------------------------------------- 1 | # YoutubeChannelSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | This tool is designed to perform semantic searches within a specific Youtube channel's content. Leveraging the RAG (Retrieval-Augmented Generation) methodology, it provides relevant search results, making it invaluable for extracting information or finding specific content without the need to manually sift through videos. It streamlines the search process within Youtube channels, catering to researchers, content creators, and viewers seeking specific information or topics. 8 | 9 | ## Installation 10 | To utilize the YoutubeChannelSearchTool, the `crewai_tools` package must be installed. Execute the following command in your shell to install: 11 | 12 | ```shell 13 | pip install 'crewai[tools]' 14 | ``` 15 | 16 | ## Example 17 | To begin using the YoutubeChannelSearchTool, follow the example below. This demonstrates initializing the tool with a specific Youtube channel handle and conducting a search within that channel's content. 18 | 19 | ```python 20 | from crewai_tools import YoutubeChannelSearchTool 21 | 22 | # Initialize the tool to search within any Youtube channel's content the agent learns about during its execution 23 | tool = YoutubeChannelSearchTool() 24 | 25 | # OR 26 | 27 | # Initialize the tool with a specific Youtube channel handle to target your search 28 | tool = YoutubeChannelSearchTool(youtube_channel_handle='@exampleChannel') 29 | ``` 30 | 31 | ## Arguments 32 | - `youtube_channel_handle` : A mandatory string representing the Youtube channel handle. This parameter is crucial for initializing the tool to specify the channel you want to search within. The tool is designed to only search within the content of the provided channel handle. 33 | 34 | ## Custom model and embeddings 35 | 36 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 37 | 38 | ```python 39 | tool = YoutubeChannelSearchTool( 40 | config=dict( 41 | llm=dict( 42 | provider="ollama", # or google, openai, anthropic, llama2, ... 43 | config=dict( 44 | model="llama2", 45 | # temperature=0.5, 46 | # top_p=1, 47 | # stream=true, 48 | ), 49 | ), 50 | embedder=dict( 51 | provider="google", # or openai, ollama, ... 52 | config=dict( 53 | model="models/embedding-001", 54 | task_type="retrieval_document", 55 | # title="Embeddings", 56 | ), 57 | ), 58 | ) 59 | ) 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/tools/YoutubeVideoSearchTool.md: -------------------------------------------------------------------------------- 1 | # YoutubeVideoSearchTool 2 | 3 | !!! note "Experimental" 4 | We are still working on improving tools, so there might be unexpected behavior or changes in the future. 5 | 6 | ## Description 7 | 8 | This tool is part of the `crewai_tools` package and is designed to perform semantic searches within Youtube video content, utilizing Retrieval-Augmented Generation (RAG) techniques. It is one of several "Search" tools in the package that leverage RAG for different sources. The YoutubeVideoSearchTool allows for flexibility in searches; users can search across any Youtube video content without specifying a video URL, or they can target their search to a specific Youtube video by providing its URL. 9 | 10 | ## Installation 11 | 12 | To utilize the YoutubeVideoSearchTool, you must first install the `crewai_tools` package. This package contains the YoutubeVideoSearchTool among other utilities designed to enhance your data analysis and processing tasks. Install the package by executing the following command in your terminal: 13 | 14 | ``` 15 | pip install 'crewai[tools]' 16 | ``` 17 | 18 | ## Example 19 | 20 | To integrate the YoutubeVideoSearchTool into your Python projects, follow the example below. This demonstrates how to use the tool both for general Youtube content searches and for targeted searches within a specific video's content. 21 | 22 | ```python 23 | from crewai_tools import YoutubeVideoSearchTool 24 | 25 | # General search across Youtube content without specifying a video URL, so the agent can search within any Youtube video content it learns about irs url during its operation 26 | tool = YoutubeVideoSearchTool() 27 | 28 | # Targeted search within a specific Youtube video's content 29 | tool = YoutubeVideoSearchTool(youtube_video_url='https://youtube.com/watch?v=example') 30 | ``` 31 | 32 | ## Arguments 33 | 34 | The YoutubeVideoSearchTool accepts the following initialization arguments: 35 | 36 | - `youtube_video_url`: An optional argument at initialization but required if targeting a specific Youtube video. It specifies the Youtube video URL path you want to search within. 37 | 38 | ## Custom model and embeddings 39 | 40 | By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows: 41 | 42 | ```python 43 | tool = YoutubeVideoSearchTool( 44 | config=dict( 45 | llm=dict( 46 | provider="ollama", # or google, openai, anthropic, llama2, ... 47 | config=dict( 48 | model="llama2", 49 | # temperature=0.5, 50 | # top_p=1, 51 | # stream=true, 52 | ), 53 | ), 54 | embedder=dict( 55 | provider="google", # or openai, ollama, ... 56 | config=dict( 57 | model="models/embedding-001", 58 | task_type="retrieval_document", 59 | # title="Embeddings", 60 | ), 61 | ), 62 | ) 63 | ) 64 | ``` 65 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "crewai" 3 | version = "0.36.0" 4 | 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." 5 | authors = ["Joao Moura "] 6 | readme = "README.md" 7 | packages = [{ include = "crewai", from = "src" }] 8 | 9 | [tool.poetry.urls] 10 | Homepage = "https://crewai.com" 11 | Documentation = "https://github.com/joaomdmoura/CrewAI/wiki/Index" 12 | Repository = "https://github.com/joaomdmoura/crewai" 13 | 14 | [tool.poetry.dependencies] 15 | python = ">=3.10,<=3.13" 16 | pydantic = "^2.4.2" 17 | langchain = ">0.2,<=0.3" 18 | openai = "^1.13.3" 19 | opentelemetry-api = "^1.22.0" 20 | opentelemetry-sdk = "^1.22.0" 21 | opentelemetry-exporter-otlp-proto-http = "^1.22.0" 22 | instructor = "1.3.3" 23 | regex = "^2023.12.25" 24 | crewai-tools = { version = "^0.4.8", optional = true } 25 | click = "^8.1.7" 26 | python-dotenv = "^1.0.0" 27 | appdirs = "^1.4.4" 28 | jsonref = "^1.1.0" 29 | agentops = { version = "^0.1.9", optional = true } 30 | embedchain = "^0.1.114" 31 | 32 | [tool.poetry.extras] 33 | tools = ["crewai-tools"] 34 | agentops = ["agentops"] 35 | 36 | [tool.poetry.group.dev.dependencies] 37 | isort = "^5.13.2" 38 | mypy = "1.10.0" 39 | autoflake = "^2.2.1" 40 | pre-commit = "^3.6.0" 41 | mkdocs = "^1.4.3" 42 | mkdocstrings = "^0.22.0" 43 | mkdocstrings-python = "^1.1.2" 44 | mkdocs-material = { extras = ["imaging"], version = "^9.5.7" } 45 | mkdocs-material-extensions = "^1.3.1" 46 | pillow = "^10.2.0" 47 | cairosvg = "^2.7.1" 48 | crewai-tools = "^0.4.8" 49 | 50 | [tool.poetry.group.test.dependencies] 51 | pytest = "^8.0.0" 52 | pytest-vcr = "^1.0.2" 53 | python-dotenv = "1.0.0" 54 | 55 | [tool.poetry.scripts] 56 | crewai = "crewai.cli.cli:crewai" 57 | 58 | [tool.mypy] 59 | ignore_missing_imports = true 60 | disable_error_code = 'import-untyped' 61 | exclude = ["cli/templates/main.py", "cli/templates/crew.py"] 62 | 63 | [build-system] 64 | requires = ["poetry-core"] 65 | build-backend = "poetry.core.masonry.api" 66 | -------------------------------------------------------------------------------- /src/crewai/__init__.py: -------------------------------------------------------------------------------- 1 | from crewai.agent import Agent 2 | from crewai.crew import Crew 3 | from crewai.process import Process 4 | from crewai.task import Task 5 | 6 | __all__ = ["Agent", "Crew", "Process", "Task"] 7 | -------------------------------------------------------------------------------- /src/crewai/agents/__init__.py: -------------------------------------------------------------------------------- 1 | from .cache.cache_handler import CacheHandler 2 | from .executor import CrewAgentExecutor 3 | from .parser import CrewAgentParser 4 | from .tools_handler import ToolsHandler 5 | -------------------------------------------------------------------------------- /src/crewai/agents/agent_builder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/agents/agent_builder/__init__.py -------------------------------------------------------------------------------- /src/crewai/agents/agent_builder/utilities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/agents/agent_builder/utilities/__init__.py -------------------------------------------------------------------------------- /src/crewai/agents/agent_builder/utilities/base_agent_tool.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import List, Optional, Union 3 | 4 | from pydantic import BaseModel, Field 5 | 6 | from crewai.agents.agent_builder.base_agent import BaseAgent 7 | from crewai.task import Task 8 | from crewai.utilities import I18N 9 | 10 | 11 | class BaseAgentTools(BaseModel, ABC): 12 | """Default tools around agent delegation""" 13 | 14 | agents: List[BaseAgent] = Field(description="List of agents in this crew.") 15 | i18n: I18N = Field(default=I18N(), description="Internationalization settings.") 16 | 17 | @abstractmethod 18 | def tools(self): 19 | pass 20 | 21 | def _get_coworker(self, coworker: Optional[str], **kwargs) -> Optional[str]: 22 | coworker = coworker or kwargs.get("co_worker") or kwargs.get("coworker") 23 | if coworker: 24 | is_list = coworker.startswith("[") and coworker.endswith("]") 25 | if is_list: 26 | coworker = coworker[1:-1].split(",")[0] 27 | return coworker 28 | 29 | def delegate_work( 30 | self, task: str, context: str, coworker: Optional[str] = None, **kwargs 31 | ): 32 | """Useful to delegate a specific task to a coworker passing all necessary context and names.""" 33 | coworker = self._get_coworker(coworker, **kwargs) 34 | return self._execute(coworker, task, context) 35 | 36 | def ask_question( 37 | self, question: str, context: str, coworker: Optional[str] = None, **kwargs 38 | ): 39 | """Useful to ask a question, opinion or take from a coworker passing all necessary context and names.""" 40 | coworker = self._get_coworker(coworker, **kwargs) 41 | return self._execute(coworker, question, context) 42 | 43 | def _execute(self, agent: Union[str, None], task: str, context: Union[str, None]): 44 | """Execute the command.""" 45 | try: 46 | if agent is None: 47 | agent = "" 48 | 49 | # It is important to remove the quotes from the agent name. 50 | # The reason we have to do this is because less-powerful LLM's 51 | # have difficulty producing valid JSON. 52 | # As a result, we end up with invalid JSON that is truncated like this: 53 | # {"task": "....", "coworker": ".... 54 | # when it should look like this: 55 | # {"task": "....", "coworker": "...."} 56 | agent_name = agent.casefold().replace('"', "").replace("\n", "") 57 | 58 | agent = [ # type: ignore # Incompatible types in assignment (expression has type "list[BaseAgent]", variable has type "str | None") 59 | available_agent 60 | for available_agent in self.agents 61 | if available_agent.role.casefold().replace("\n", "") == agent_name 62 | ] 63 | except Exception as _: 64 | return self.i18n.errors("agent_tool_unexsiting_coworker").format( 65 | coworkers="\n".join( 66 | [f"- {agent.role.casefold()}" for agent in self.agents] 67 | ) 68 | ) 69 | 70 | if not agent: 71 | return self.i18n.errors("agent_tool_unexsiting_coworker").format( 72 | coworkers="\n".join( 73 | [f"- {agent.role.casefold()}" for agent in self.agents] 74 | ) 75 | ) 76 | 77 | agent = agent[0] 78 | task = Task( # type: ignore # Incompatible types in assignment (expression has type "Task", variable has type "str") 79 | description=task, 80 | agent=agent, 81 | expected_output="Your best answer to your coworker asking you this, accounting for the context shared.", 82 | ) 83 | return agent.execute_task(task, context) # type: ignore # "str" has no attribute "execute_task" 84 | -------------------------------------------------------------------------------- /src/crewai/agents/agent_builder/utilities/base_output_converter_base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Any, Optional 3 | 4 | from pydantic import BaseModel, Field, PrivateAttr 5 | 6 | 7 | class OutputConverter(BaseModel, ABC): 8 | """ 9 | Abstract base class for converting task results into structured formats. 10 | 11 | This class provides a framework for converting unstructured text into 12 | either Pydantic models or JSON, tailored for specific agent requirements. 13 | It uses a language model to interpret and structure the input text based 14 | on given instructions. 15 | 16 | Attributes: 17 | text (str): The input text to be converted. 18 | llm (Any): The language model used for conversion. 19 | model (Any): The target model for structuring the output. 20 | instructions (str): Specific instructions for the conversion process. 21 | max_attempts (int): Maximum number of conversion attempts (default: 3). 22 | """ 23 | 24 | _is_gpt: bool = PrivateAttr(default=True) 25 | text: str = Field(description="Text to be converted.") 26 | llm: Any = Field(description="The language model to be used to convert the text.") 27 | model: Any = Field(description="The model to be used to convert the text.") 28 | instructions: str = Field(description="Conversion instructions to the LLM.") 29 | max_attempts: Optional[int] = Field( 30 | description="Max number of attempts to try to get the output formatted.", 31 | default=3, 32 | ) 33 | 34 | @abstractmethod 35 | def to_pydantic(self, current_attempt=1): 36 | """Convert text to pydantic.""" 37 | pass 38 | 39 | @abstractmethod 40 | def to_json(self, current_attempt=1): 41 | """Convert text to json.""" 42 | pass 43 | 44 | @abstractmethod # type: ignore # Name "_is_gpt" already defined on line 25 45 | def _is_gpt(self, llm): # type: ignore # Name "_is_gpt" already defined on line 25 46 | """Return if llm provided is of gpt from openai.""" 47 | pass 48 | -------------------------------------------------------------------------------- /src/crewai/agents/agent_builder/utilities/base_token_process.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict 2 | 3 | 4 | class TokenProcess: 5 | total_tokens: int = 0 6 | prompt_tokens: int = 0 7 | completion_tokens: int = 0 8 | successful_requests: int = 0 9 | 10 | def sum_prompt_tokens(self, tokens: int): 11 | self.prompt_tokens = self.prompt_tokens + tokens 12 | self.total_tokens = self.total_tokens + tokens 13 | 14 | def sum_completion_tokens(self, tokens: int): 15 | self.completion_tokens = self.completion_tokens + tokens 16 | self.total_tokens = self.total_tokens + tokens 17 | 18 | def sum_successful_requests(self, requests: int): 19 | self.successful_requests = self.successful_requests + requests 20 | 21 | def get_summary(self) -> Dict[str, Any]: 22 | return { 23 | "total_tokens": self.total_tokens, 24 | "prompt_tokens": self.prompt_tokens, 25 | "completion_tokens": self.completion_tokens, 26 | "successful_requests": self.successful_requests, 27 | } 28 | -------------------------------------------------------------------------------- /src/crewai/agents/cache/__init__.py: -------------------------------------------------------------------------------- 1 | from .cache_handler import CacheHandler 2 | -------------------------------------------------------------------------------- /src/crewai/agents/cache/cache_handler.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | 4 | class CacheHandler: 5 | """Callback handler for tool usage.""" 6 | 7 | _cache: dict = {} 8 | 9 | def __init__(self): 10 | self._cache = {} 11 | 12 | def add(self, tool, input, output): 13 | self._cache[f"{tool}-{input}"] = output 14 | 15 | def read(self, tool, input) -> Optional[str]: 16 | return self._cache.get(f"{tool}-{input}") 17 | -------------------------------------------------------------------------------- /src/crewai/agents/parser.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Any, Union 3 | 4 | from langchain.agents.output_parsers import ReActSingleInputOutputParser 5 | from langchain_core.agents import AgentAction, AgentFinish 6 | from langchain_core.exceptions import OutputParserException 7 | 8 | from crewai.utilities import I18N 9 | 10 | FINAL_ANSWER_ACTION = "Final Answer:" 11 | MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE = "I did it wrong. Invalid Format: I missed the 'Action:' after 'Thought:'. I will do right next, and don't use a tool I have already used.\n" 12 | MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE = "I did it wrong. Invalid Format: I missed the 'Action Input:' after 'Action:'. I will do right next, and don't use a tool I have already used.\n" 13 | FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE = "I did it wrong. Tried to both perform Action and give a Final Answer at the same time, I must do one or the other" 14 | 15 | 16 | class CrewAgentParser(ReActSingleInputOutputParser): 17 | """Parses ReAct-style LLM calls that have a single tool input. 18 | 19 | Expects output to be in one of two formats. 20 | 21 | If the output signals that an action should be taken, 22 | should be in the below format. This will result in an AgentAction 23 | being returned. 24 | 25 | Thought: agent thought here 26 | Action: search 27 | Action Input: what is the temperature in SF? 28 | 29 | If the output signals that a final answer should be given, 30 | should be in the below format. This will result in an AgentFinish 31 | being returned. 32 | 33 | Thought: agent thought here 34 | Final Answer: The temperature is 100 degrees 35 | """ 36 | 37 | _i18n: I18N = I18N() 38 | agent: Any = None 39 | 40 | def parse(self, text: str) -> Union[AgentAction, AgentFinish]: 41 | includes_answer = FINAL_ANSWER_ACTION in text 42 | regex = ( 43 | r"Action\s*\d*\s*:[\s]*(.*?)[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)" 44 | ) 45 | action_match = re.search(regex, text, re.DOTALL) 46 | if action_match: 47 | if includes_answer: 48 | raise OutputParserException( 49 | f"{FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE}: {text}" 50 | ) 51 | action = action_match.group(1).strip() 52 | action_input = action_match.group(2) 53 | tool_input = action_input.strip(" ") 54 | tool_input = tool_input.strip('"') 55 | return AgentAction(action, tool_input, text) 56 | 57 | elif includes_answer: 58 | return AgentFinish( 59 | {"output": text.split(FINAL_ANSWER_ACTION)[-1].strip()}, text 60 | ) 61 | 62 | if not re.search(r"Action\s*\d*\s*:[\s]*(.*?)", text, re.DOTALL): 63 | self.agent.increment_formatting_errors() 64 | raise OutputParserException( 65 | f"Could not parse LLM output: `{text}`", 66 | observation=f"{MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE}\n{self._i18n.slice('final_answer_format')}", 67 | llm_output=text, 68 | send_to_llm=True, 69 | ) 70 | elif not re.search( 71 | r"[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)", text, re.DOTALL 72 | ): 73 | self.agent.increment_formatting_errors() 74 | raise OutputParserException( 75 | f"Could not parse LLM output: `{text}`", 76 | observation=MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE, 77 | llm_output=text, 78 | send_to_llm=True, 79 | ) 80 | else: 81 | format = self._i18n.slice("format_without_tools") 82 | error = f"{format}" 83 | self.agent.increment_formatting_errors() 84 | raise OutputParserException( 85 | error, 86 | observation=error, 87 | llm_output=text, 88 | send_to_llm=True, 89 | ) 90 | -------------------------------------------------------------------------------- /src/crewai/agents/tools_handler.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional, Union 2 | 3 | from ..tools.cache_tools import CacheTools 4 | from ..tools.tool_calling import InstructorToolCalling, ToolCalling 5 | from .cache.cache_handler import CacheHandler 6 | 7 | 8 | class ToolsHandler: 9 | """Callback handler for tool usage.""" 10 | 11 | last_used_tool: ToolCalling = {} # type: ignore # BUG?: Incompatible types in assignment (expression has type "Dict[...]", variable has type "ToolCalling") 12 | cache: Optional[CacheHandler] 13 | 14 | def __init__(self, cache: Optional[CacheHandler] = None): 15 | """Initialize the callback handler.""" 16 | self.cache = cache 17 | self.last_used_tool = {} # type: ignore # BUG?: same as above 18 | 19 | def on_tool_use( 20 | self, 21 | calling: Union[ToolCalling, InstructorToolCalling], 22 | output: str, 23 | should_cache: bool = True, 24 | ) -> Any: 25 | """Run when tool ends running.""" 26 | self.last_used_tool = calling # type: ignore # BUG?: Incompatible types in assignment (expression has type "Union[ToolCalling, InstructorToolCalling]", variable has type "ToolCalling") 27 | if self.cache and should_cache and calling.tool_name != CacheTools().name: 28 | self.cache.add( 29 | tool=calling.tool_name, 30 | input=calling.arguments, 31 | output=output, 32 | ) 33 | -------------------------------------------------------------------------------- /src/crewai/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/cli/__init__.py -------------------------------------------------------------------------------- /src/crewai/cli/cli.py: -------------------------------------------------------------------------------- 1 | import click 2 | import pkg_resources 3 | 4 | from .create_crew import create_crew 5 | from .train_crew import train_crew 6 | 7 | 8 | @click.group() 9 | def crewai(): 10 | """Top-level command group for crewai.""" 11 | 12 | 13 | @crewai.command() 14 | @click.argument("project_name") 15 | def create(project_name): 16 | """Create a new crew.""" 17 | create_crew(project_name) 18 | 19 | 20 | @crewai.command() 21 | @click.option( 22 | "--tools", is_flag=True, help="Show the installed version of crewai tools" 23 | ) 24 | def version(tools): 25 | """Show the installed version of crewai.""" 26 | crewai_version = pkg_resources.get_distribution("crewai").version 27 | click.echo(f"crewai version: {crewai_version}") 28 | 29 | if tools: 30 | try: 31 | tools_version = pkg_resources.get_distribution("crewai-tools").version 32 | click.echo(f"crewai tools version: {tools_version}") 33 | except pkg_resources.DistributionNotFound: 34 | click.echo("crewai tools not installed") 35 | 36 | 37 | @crewai.command() 38 | @click.option( 39 | "-n", 40 | "--n_iterations", 41 | type=int, 42 | default=5, 43 | help="Number of iterations to train the crew", 44 | ) 45 | def train(n_iterations: int): 46 | """Train the crew.""" 47 | click.echo(f"Training the crew for {n_iterations} iterations") 48 | train_crew(n_iterations) 49 | 50 | 51 | if __name__ == "__main__": 52 | crewai() 53 | -------------------------------------------------------------------------------- /src/crewai/cli/create_crew.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | import click 5 | 6 | 7 | def create_crew(name): 8 | """Create a new crew.""" 9 | folder_name = name.replace(" ", "_").replace("-", "_").lower() 10 | class_name = name.replace("_", " ").replace("-", " ").title().replace(" ", "") 11 | 12 | click.secho(f"Creating folder {folder_name}...", fg="green", bold=True) 13 | 14 | if not os.path.exists(folder_name): 15 | os.mkdir(folder_name) 16 | os.mkdir(folder_name + "/tests") 17 | os.mkdir(folder_name + "/src") 18 | os.mkdir(folder_name + f"/src/{folder_name}") 19 | os.mkdir(folder_name + f"/src/{folder_name}/tools") 20 | os.mkdir(folder_name + f"/src/{folder_name}/config") 21 | with open(folder_name + "/.env", "w") as file: 22 | file.write("OPENAI_API_KEY=YOUR_API_KEY") 23 | else: 24 | click.secho( 25 | f"\tFolder {folder_name} already exists. Please choose a different name.", 26 | fg="red", 27 | ) 28 | return 29 | 30 | package_dir = Path(__file__).parent 31 | templates_dir = package_dir / "templates" 32 | 33 | # List of template files to copy 34 | root_template_files = [ 35 | ".gitignore", 36 | "pyproject.toml", 37 | "README.md", 38 | ] 39 | tools_template_files = ["tools/custom_tool.py", "tools/__init__.py"] 40 | config_template_files = ["config/agents.yaml", "config/tasks.yaml"] 41 | src_template_files = ["__init__.py", "main.py", "crew.py"] 42 | 43 | for file_name in root_template_files: 44 | src_file = templates_dir / file_name 45 | dst_file = Path(folder_name) / file_name 46 | copy_template(src_file, dst_file, name, class_name, folder_name) 47 | 48 | for file_name in src_template_files: 49 | src_file = templates_dir / file_name 50 | dst_file = Path(folder_name) / "src" / folder_name / file_name 51 | copy_template(src_file, dst_file, name, class_name, folder_name) 52 | 53 | for file_name in tools_template_files: 54 | src_file = templates_dir / file_name 55 | dst_file = Path(folder_name) / "src" / folder_name / file_name 56 | copy_template(src_file, dst_file, name, class_name, folder_name) 57 | 58 | for file_name in config_template_files: 59 | src_file = templates_dir / file_name 60 | dst_file = Path(folder_name) / "src" / folder_name / file_name 61 | copy_template(src_file, dst_file, name, class_name, folder_name) 62 | 63 | click.secho(f"Crew {name} created successfully!", fg="green", bold=True) 64 | 65 | 66 | def copy_template(src, dst, name, class_name, folder_name): 67 | """Copy a file from src to dst.""" 68 | with open(src, "r") as file: 69 | content = file.read() 70 | 71 | # Interpolate the content 72 | content = content.replace("{{name}}", name) 73 | content = content.replace("{{crew_name}}", class_name) 74 | content = content.replace("{{folder_name}}", folder_name) 75 | 76 | # Write the interpolated content to the new file 77 | with open(dst, "w") as file: 78 | file.write(content) 79 | 80 | click.secho(f" - Created {dst}", fg="green") 81 | -------------------------------------------------------------------------------- /src/crewai/cli/templates/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | __pycache__/ 3 | -------------------------------------------------------------------------------- /src/crewai/cli/templates/README.md: -------------------------------------------------------------------------------- 1 | # {{crew_name}} Crew 2 | 3 | Welcome to the {{crew_name}} Crew project, powered by [crewAI](https://crewai.com). This template is designed to help you set up a multi-agent AI system with ease, leveraging the powerful and flexible framework provided by crewAI. Our goal is to enable your agents to collaborate effectively on complex tasks, maximizing their collective intelligence and capabilities. 4 | 5 | ## Installation 6 | 7 | Ensure you have Python >=3.10 <=3.13 installed on your system. This project uses [Poetry](https://python-poetry.org/) for dependency management and package handling, offering a seamless setup and execution experience. 8 | 9 | First, if you haven't already, install Poetry: 10 | 11 | ```bash 12 | pip install poetry 13 | ``` 14 | 15 | Next, navigate to your project directory and install the dependencies: 16 | 17 | 1. First lock the dependencies and then install them: 18 | ```bash 19 | poetry lock 20 | ``` 21 | ```bash 22 | poetry install 23 | ``` 24 | ### Customizing 25 | 26 | **Add your `OPENAI_API_KEY` into the `.env` file** 27 | 28 | - Modify `src/{{folder_name}}/config/agents.yaml` to define your agents 29 | - Modify `src/{{folder_name}}/config/tasks.yaml` to define your tasks 30 | - Modify `src/{{folder_name}}/crew.py` to add your own logic, tools and specific args 31 | - Modify `src/{{folder_name}}/main.py` to add custom inputs for your agents and tasks 32 | 33 | ## Running the Project 34 | 35 | To kickstart your crew of AI agents and begin task execution, run this from the root folder of your project: 36 | 37 | ```bash 38 | poetry run {{folder_name}} 39 | ``` 40 | 41 | This command initializes the {{name}} Crew, assembling the agents and assigning them tasks as defined in your configuration. 42 | 43 | This example, unmodified, will run the create a `report.md` file with the output of a research on LLMs in the root folder. 44 | 45 | ## Understanding Your Crew 46 | 47 | The {{name}} Crew is composed of multiple AI agents, each with unique roles, goals, and tools. These agents collaborate on a series of tasks, defined in `config/tasks.yaml`, leveraging their collective skills to achieve complex objectives. The `config/agents.yaml` file outlines the capabilities and configurations of each agent in your crew. 48 | 49 | ## Support 50 | 51 | For support, questions, or feedback regarding the {{crew_name}} Crew or crewAI. 52 | - Visit our [documentation](https://docs.crewai.com) 53 | - Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai) 54 | - [Join our Discord](https://discord.com/invite/X4JWnZnxPb) 55 | - [Chat with our docs](https://chatg.pt/DWjSBZn) 56 | 57 | Let's create wonders together with the power and simplicity of crewAI. 58 | -------------------------------------------------------------------------------- /src/crewai/cli/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/cli/templates/__init__.py -------------------------------------------------------------------------------- /src/crewai/cli/templates/config/agents.yaml: -------------------------------------------------------------------------------- 1 | researcher: 2 | role: > 3 | {topic} Senior Data Researcher 4 | goal: > 5 | Uncover cutting-edge developments in {topic} 6 | backstory: > 7 | You're a seasoned researcher with a knack for uncovering the latest 8 | developments in {topic}. Known for your ability to find the most relevant 9 | information and present it in a clear and concise manner. 10 | 11 | reporting_analyst: 12 | role: > 13 | {topic} Reporting Analyst 14 | goal: > 15 | Create detailed reports based on {topic} data analysis and research findings 16 | backstory: > 17 | You're a meticulous analyst with a keen eye for detail. You're known for 18 | your ability to turn complex data into clear and concise reports, making 19 | it easy for others to understand and act on the information you provide. -------------------------------------------------------------------------------- /src/crewai/cli/templates/config/tasks.yaml: -------------------------------------------------------------------------------- 1 | research_task: 2 | description: > 3 | Conduct a thorough research about {topic} 4 | Make sure you find any interesting and relevant information given 5 | the current year is 2024. 6 | expected_output: > 7 | A list with 10 bullet points of the most relevant information about {topic} 8 | 9 | reporting_task: 10 | description: > 11 | Review the context you got and expand each topic into a full section for a report. 12 | Make sure the report is detailed and contains any and all relevant information. 13 | expected_output: > 14 | A fully fledge reports with the mains topics, each with a full section of information. 15 | Formatted as markdown without '```' 16 | -------------------------------------------------------------------------------- /src/crewai/cli/templates/crew.py: -------------------------------------------------------------------------------- 1 | from crewai import Agent, Crew, Process, Task 2 | from crewai.project import CrewBase, agent, crew, task 3 | 4 | # Uncomment the following line to use an example of a custom tool 5 | # from {{folder_name}}.tools.custom_tool import MyCustomTool 6 | 7 | # Check our tools documentations for more information on how to use them 8 | # from crewai_tools import SerperDevTool 9 | 10 | @CrewBase 11 | class {{crew_name}}Crew(): 12 | """{{crew_name}} crew""" 13 | agents_config = 'config/agents.yaml' 14 | tasks_config = 'config/tasks.yaml' 15 | 16 | @agent 17 | def researcher(self) -> Agent: 18 | return Agent( 19 | config=self.agents_config['researcher'], 20 | # tools=[MyCustomTool()], # Example of custom tool, loaded on the beginning of file 21 | verbose=True 22 | ) 23 | 24 | @agent 25 | def reporting_analyst(self) -> Agent: 26 | return Agent( 27 | config=self.agents_config['reporting_analyst'], 28 | verbose=True 29 | ) 30 | 31 | @task 32 | def research_task(self) -> Task: 33 | return Task( 34 | config=self.tasks_config['research_task'], 35 | agent=self.researcher() 36 | ) 37 | 38 | @task 39 | def reporting_task(self) -> Task: 40 | return Task( 41 | config=self.tasks_config['reporting_task'], 42 | agent=self.reporting_analyst(), 43 | output_file='report.md' 44 | ) 45 | 46 | @crew 47 | def crew(self) -> Crew: 48 | """Creates the {{crew_name}} crew""" 49 | return Crew( 50 | agents=self.agents, # Automatically created by the @agent decorator 51 | tasks=self.tasks, # Automatically created by the @task decorator 52 | process=Process.sequential, 53 | verbose=2, 54 | # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/ 55 | ) -------------------------------------------------------------------------------- /src/crewai/cli/templates/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from {{folder_name}}.crew import {{crew_name}}Crew 4 | 5 | 6 | def run(): 7 | # Replace with your inputs, it will automatically interpolate any tasks and agents information 8 | inputs = { 9 | 'topic': 'AI LLMs' 10 | } 11 | {{crew_name}}Crew().crew().kickoff(inputs=inputs) 12 | 13 | 14 | def train(): 15 | """ 16 | Train the crew for a given number of iterations. 17 | """ 18 | inputs = {"topic": "AI LLMs"} 19 | try: 20 | {{crew_name}}Crew().crew().train(n_iterations=int(sys.argv[1]), inputs=inputs) 21 | 22 | except Exception as e: 23 | raise Exception(f"An error occurred while training the crew: {e}") 24 | -------------------------------------------------------------------------------- /src/crewai/cli/templates/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "{{folder_name}}" 3 | version = "0.1.0" 4 | description = "{{name}} using crewAI" 5 | authors = ["Your Name "] 6 | 7 | [tool.poetry.dependencies] 8 | python = ">=3.10,<=3.13" 9 | crewai = { extras = ["tools"], version = "^0.35.8" } 10 | 11 | [tool.poetry.scripts] 12 | {{folder_name}} = "{{folder_name}}.main:run" 13 | train = "{{folder_name}}.main:train" 14 | 15 | [build-system] 16 | requires = ["poetry-core"] 17 | build-backend = "poetry.core.masonry.api" 18 | -------------------------------------------------------------------------------- /src/crewai/cli/templates/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/cli/templates/tools/__init__.py -------------------------------------------------------------------------------- /src/crewai/cli/templates/tools/custom_tool.py: -------------------------------------------------------------------------------- 1 | from crewai_tools import BaseTool 2 | 3 | 4 | class MyCustomTool(BaseTool): 5 | name: str = "Name of my tool" 6 | description: str = ( 7 | "Clear description for what this tool is useful for, you agent will need this information to use it." 8 | ) 9 | 10 | def _run(self, argument: str) -> str: 11 | # Implementation goes here 12 | return "this is an example of a tool output, ignore it and move along." 13 | -------------------------------------------------------------------------------- /src/crewai/cli/train_crew.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | import click 4 | 5 | 6 | def train_crew(n_iterations: int) -> None: 7 | """ 8 | Train the crew by running a command in the Poetry environment. 9 | 10 | Args: 11 | n_iterations (int): The number of iterations to train the crew. 12 | """ 13 | command = ["poetry", "run", "train", str(n_iterations)] 14 | 15 | try: 16 | if n_iterations <= 0: 17 | raise ValueError("The number of iterations must be a positive integer.") 18 | 19 | result = subprocess.run(command, capture_output=False, text=True, check=True) 20 | 21 | if result.stderr: 22 | click.echo(result.stderr, err=True) 23 | 24 | except subprocess.CalledProcessError as e: 25 | click.echo(f"An error occurred while training the crew: {e}", err=True) 26 | click.echo(e.output, err=True) 27 | 28 | except Exception as e: 29 | click.echo(f"An unexpected error occurred: {e}", err=True) 30 | -------------------------------------------------------------------------------- /src/crewai/memory/__init__.py: -------------------------------------------------------------------------------- 1 | from .entity.entity_memory import EntityMemory 2 | from .long_term.long_term_memory import LongTermMemory 3 | from .short_term.short_term_memory import ShortTermMemory 4 | -------------------------------------------------------------------------------- /src/crewai/memory/contextual/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/memory/contextual/__init__.py -------------------------------------------------------------------------------- /src/crewai/memory/contextual/contextual_memory.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from crewai.memory import EntityMemory, LongTermMemory, ShortTermMemory 4 | 5 | 6 | class ContextualMemory: 7 | def __init__(self, stm: ShortTermMemory, ltm: LongTermMemory, em: EntityMemory): 8 | self.stm = stm 9 | self.ltm = ltm 10 | self.em = em 11 | 12 | def build_context_for_task(self, task, context) -> str: 13 | """ 14 | Automatically builds a minimal, highly relevant set of contextual information 15 | for a given task. 16 | """ 17 | query = f"{task.description} {context}".strip() 18 | 19 | if query == "": 20 | return "" 21 | 22 | context = [] 23 | context.append(self._fetch_ltm_context(task.description)) 24 | context.append(self._fetch_stm_context(query)) 25 | context.append(self._fetch_entity_context(query)) 26 | return "\n".join(filter(None, context)) 27 | 28 | def _fetch_stm_context(self, query) -> str: 29 | """ 30 | Fetches recent relevant insights from STM related to the task's description and expected_output, 31 | formatted as bullet points. 32 | """ 33 | stm_results = self.stm.search(query) 34 | formatted_results = "\n".join([f"- {result}" for result in stm_results]) 35 | return f"Recent Insights:\n{formatted_results}" if stm_results else "" 36 | 37 | def _fetch_ltm_context(self, task) -> Optional[str]: 38 | """ 39 | Fetches historical data or insights from LTM that are relevant to the task's description and expected_output, 40 | formatted as bullet points. 41 | """ 42 | ltm_results = self.ltm.search(task, latest_n=2) 43 | if not ltm_results: 44 | return None 45 | 46 | formatted_results = [ 47 | suggestion 48 | for result in ltm_results 49 | for suggestion in result["metadata"]["suggestions"] # type: ignore # Invalid index type "str" for "str"; expected type "SupportsIndex | slice" 50 | ] 51 | formatted_results = list(dict.fromkeys(formatted_results)) 52 | 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]") 53 | 54 | return f"Historical Data:\n{formatted_results}" if ltm_results else "" 55 | 56 | def _fetch_entity_context(self, query) -> str: 57 | """ 58 | Fetches relevant entity information from Entity Memory related to the task's description and expected_output, 59 | formatted as bullet points. 60 | """ 61 | em_results = self.em.search(query) 62 | formatted_results = "\n".join( 63 | [f"- {result['context']}" for result in em_results] # type: ignore # Invalid index type "str" for "str"; expected type "SupportsIndex | slice" 64 | ) 65 | return f"Entities:\n{formatted_results}" if em_results else "" 66 | -------------------------------------------------------------------------------- /src/crewai/memory/entity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/memory/entity/__init__.py -------------------------------------------------------------------------------- /src/crewai/memory/entity/entity_memory.py: -------------------------------------------------------------------------------- 1 | from crewai.memory.entity.entity_memory_item import EntityMemoryItem 2 | from crewai.memory.memory import Memory 3 | from crewai.memory.storage.rag_storage import RAGStorage 4 | 5 | 6 | class EntityMemory(Memory): 7 | """ 8 | EntityMemory class for managing structured information about entities 9 | and their relationships using SQLite storage. 10 | Inherits from the Memory class. 11 | """ 12 | 13 | def __init__(self, crew=None, embedder_config=None): 14 | storage = RAGStorage( 15 | type="entities", 16 | allow_reset=False, 17 | embedder_config=embedder_config, 18 | crew=crew, 19 | ) 20 | super().__init__(storage) 21 | 22 | def save(self, item: EntityMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory" 23 | """Saves an entity item into the SQLite storage.""" 24 | data = f"{item.name}({item.type}): {item.description}" 25 | super().save(data, item.metadata) 26 | -------------------------------------------------------------------------------- /src/crewai/memory/entity/entity_memory_item.py: -------------------------------------------------------------------------------- 1 | class EntityMemoryItem: 2 | def __init__( 3 | self, 4 | name: str, 5 | type: str, 6 | description: str, 7 | relationships: str, 8 | ): 9 | self.name = name 10 | self.type = type 11 | self.description = description 12 | self.metadata = {"relationships": relationships} 13 | -------------------------------------------------------------------------------- /src/crewai/memory/long_term/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/memory/long_term/__init__.py -------------------------------------------------------------------------------- /src/crewai/memory/long_term/long_term_memory.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict 2 | 3 | from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem 4 | from crewai.memory.memory import Memory 5 | from crewai.memory.storage.ltm_sqlite_storage import LTMSQLiteStorage 6 | 7 | 8 | class LongTermMemory(Memory): 9 | """ 10 | LongTermMemory class for managing cross runs data related to overall crew's 11 | execution and performance. 12 | Inherits from the Memory class and utilizes an instance of a class that 13 | adheres to the Storage for data storage, specifically working with 14 | LongTermMemoryItem instances. 15 | """ 16 | 17 | def __init__(self): 18 | storage = LTMSQLiteStorage() 19 | super().__init__(storage) 20 | 21 | def save(self, item: LongTermMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory" 22 | metadata = item.metadata 23 | metadata.update({"agent": item.agent, "expected_output": item.expected_output}) 24 | self.storage.save( # type: ignore # BUG?: Unexpected keyword argument "task_description","score","datetime" for "save" of "Storage" 25 | task_description=item.task, 26 | score=metadata["quality"], 27 | metadata=metadata, 28 | datetime=item.datetime, 29 | ) 30 | 31 | def search(self, task: str, latest_n: int = 3) -> Dict[str, Any]: 32 | return self.storage.load(task, latest_n) # type: ignore # BUG?: "Storage" has no attribute "load" 33 | -------------------------------------------------------------------------------- /src/crewai/memory/long_term/long_term_memory_item.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Optional, Union 2 | 3 | 4 | class LongTermMemoryItem: 5 | def __init__( 6 | self, 7 | agent: str, 8 | task: str, 9 | expected_output: str, 10 | datetime: str, 11 | quality: Optional[Union[int, float]] = None, 12 | metadata: Optional[Dict[str, Any]] = None, 13 | ): 14 | self.task = task 15 | self.agent = agent 16 | self.quality = quality 17 | self.datetime = datetime 18 | self.expected_output = expected_output 19 | self.metadata = metadata if metadata is not None else {} 20 | -------------------------------------------------------------------------------- /src/crewai/memory/memory.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Optional 2 | 3 | from crewai.memory.storage.interface import Storage 4 | 5 | 6 | class Memory: 7 | """ 8 | Base class for memory, now supporting agent tags and generic metadata. 9 | """ 10 | 11 | def __init__(self, storage: Storage): 12 | self.storage = storage 13 | 14 | def save( 15 | self, 16 | value: Any, 17 | metadata: Optional[Dict[str, Any]] = None, 18 | agent: Optional[str] = None, 19 | ) -> None: 20 | metadata = metadata or {} 21 | if agent: 22 | metadata["agent"] = agent 23 | 24 | self.storage.save(value, metadata) # type: ignore # Maybe BUG? Should be self.storage.save(key, value, metadata) 25 | 26 | def search(self, query: str) -> Dict[str, Any]: 27 | return self.storage.search(query) 28 | -------------------------------------------------------------------------------- /src/crewai/memory/short_term/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/memory/short_term/__init__.py -------------------------------------------------------------------------------- /src/crewai/memory/short_term/short_term_memory.py: -------------------------------------------------------------------------------- 1 | from crewai.memory.memory import Memory 2 | from crewai.memory.short_term.short_term_memory_item import ShortTermMemoryItem 3 | from crewai.memory.storage.rag_storage import RAGStorage 4 | 5 | 6 | class ShortTermMemory(Memory): 7 | """ 8 | ShortTermMemory class for managing transient data related to immediate tasks 9 | and interactions. 10 | Inherits from the Memory class and utilizes an instance of a class that 11 | adheres to the Storage for data storage, specifically working with 12 | MemoryItem instances. 13 | """ 14 | 15 | def __init__(self, crew=None, embedder_config=None): 16 | storage = RAGStorage( 17 | type="short_term", embedder_config=embedder_config, crew=crew 18 | ) 19 | super().__init__(storage) 20 | 21 | def save(self, item: ShortTermMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory" 22 | super().save(item.data, item.metadata, item.agent) 23 | 24 | def search(self, query: str, score_threshold: float = 0.35): 25 | 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 26 | -------------------------------------------------------------------------------- /src/crewai/memory/short_term/short_term_memory_item.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Optional 2 | 3 | 4 | class ShortTermMemoryItem: 5 | def __init__( 6 | self, data: Any, agent: str, metadata: Optional[Dict[str, Any]] = None 7 | ): 8 | self.data = data 9 | self.agent = agent 10 | self.metadata = metadata if metadata is not None else {} 11 | -------------------------------------------------------------------------------- /src/crewai/memory/storage/interface.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict 2 | 3 | 4 | class Storage: 5 | """Abstract base class defining the storage interface""" 6 | 7 | def save(self, key: str, value: Any, metadata: Dict[str, Any]) -> None: 8 | pass 9 | 10 | def search(self, key: str) -> Dict[str, Any]: # type: ignore 11 | pass 12 | -------------------------------------------------------------------------------- /src/crewai/memory/storage/ltm_sqlite_storage.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sqlite3 3 | from typing import Any, Dict, List, Optional, Union 4 | 5 | from crewai.utilities import Printer 6 | from crewai.utilities.paths import db_storage_path 7 | 8 | 9 | class LTMSQLiteStorage: 10 | """ 11 | An updated SQLite storage class for LTM data storage. 12 | """ 13 | 14 | def __init__( 15 | self, db_path: str = f"{db_storage_path()}/long_term_memory_storage.db" 16 | ) -> None: 17 | self.db_path = db_path 18 | self._printer: Printer = Printer() 19 | self._initialize_db() 20 | 21 | def _initialize_db(self): 22 | """ 23 | Initializes the SQLite database and creates LTM table 24 | """ 25 | try: 26 | with sqlite3.connect(self.db_path) as conn: 27 | cursor = conn.cursor() 28 | cursor.execute( 29 | """ 30 | CREATE TABLE IF NOT EXISTS long_term_memories ( 31 | id INTEGER PRIMARY KEY AUTOINCREMENT, 32 | task_description TEXT, 33 | metadata TEXT, 34 | datetime TEXT, 35 | score REAL 36 | ) 37 | """ 38 | ) 39 | 40 | conn.commit() 41 | except sqlite3.Error as e: 42 | self._printer.print( 43 | content=f"MEMORY ERROR: An error occurred during database initialization: {e}", 44 | color="red", 45 | ) 46 | 47 | def save( 48 | self, 49 | task_description: str, 50 | metadata: Dict[str, Any], 51 | datetime: str, 52 | score: Union[int, float], 53 | ) -> None: 54 | """Saves data to the LTM table with error handling.""" 55 | try: 56 | with sqlite3.connect(self.db_path) as conn: 57 | cursor = conn.cursor() 58 | cursor.execute( 59 | """ 60 | INSERT INTO long_term_memories (task_description, metadata, datetime, score) 61 | VALUES (?, ?, ?, ?) 62 | """, 63 | (task_description, json.dumps(metadata), datetime, score), 64 | ) 65 | conn.commit() 66 | except sqlite3.Error as e: 67 | self._printer.print( 68 | content=f"MEMORY ERROR: An error occurred while saving to LTM: {e}", 69 | color="red", 70 | ) 71 | 72 | def load( 73 | self, task_description: str, latest_n: int 74 | ) -> Optional[List[Dict[str, Any]]]: 75 | """Queries the LTM table by task description with error handling.""" 76 | try: 77 | with sqlite3.connect(self.db_path) as conn: 78 | cursor = conn.cursor() 79 | cursor.execute( 80 | f""" 81 | SELECT metadata, datetime, score 82 | FROM long_term_memories 83 | WHERE task_description = ? 84 | ORDER BY datetime DESC, score ASC 85 | LIMIT {latest_n} 86 | """, 87 | (task_description,), 88 | ) 89 | rows = cursor.fetchall() 90 | if rows: 91 | return [ 92 | { 93 | "metadata": json.loads(row[0]), 94 | "datetime": row[1], 95 | "score": row[2], 96 | } 97 | for row in rows 98 | ] 99 | 100 | except sqlite3.Error as e: 101 | self._printer.print( 102 | content=f"MEMORY ERROR: An error occurred while querying LTM: {e}", 103 | color="red", 104 | ) 105 | return None 106 | -------------------------------------------------------------------------------- /src/crewai/memory/storage/rag_storage.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import io 3 | import logging 4 | import os 5 | from typing import Any, Dict, List, Optional 6 | 7 | from embedchain import App 8 | from embedchain.llm.base import BaseLlm 9 | from embedchain.vectordb.chroma import InvalidDimensionException 10 | 11 | from crewai.memory.storage.interface import Storage 12 | from crewai.utilities.paths import db_storage_path 13 | 14 | 15 | @contextlib.contextmanager 16 | def suppress_logging( 17 | logger_name="chromadb.segment.impl.vector.local_persistent_hnsw", 18 | level=logging.ERROR, 19 | ): 20 | logger = logging.getLogger(logger_name) 21 | original_level = logger.getEffectiveLevel() 22 | logger.setLevel(level) 23 | with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr( 24 | io.StringIO() 25 | ), contextlib.suppress(UserWarning): 26 | yield 27 | logger.setLevel(original_level) 28 | 29 | 30 | class FakeLLM(BaseLlm): 31 | pass 32 | 33 | 34 | class RAGStorage(Storage): 35 | """ 36 | Extends Storage to handle embeddings for memory entries, improving 37 | search efficiency. 38 | """ 39 | 40 | def __init__(self, type, allow_reset=True, embedder_config=None, crew=None): 41 | super().__init__() 42 | if ( 43 | not os.getenv("OPENAI_API_KEY") 44 | and not os.getenv("OPENAI_BASE_URL") == "https://api.openai.com/v1" 45 | ): 46 | os.environ["OPENAI_API_KEY"] = "fake" 47 | 48 | agents = crew.agents if crew else [] 49 | agents = [agent.role for agent in agents] 50 | agents = "_".join(agents) 51 | 52 | config = { 53 | "app": { 54 | "config": {"name": type, "collect_metrics": False, "log_level": "ERROR"} 55 | }, 56 | "chunker": { 57 | "chunk_size": 5000, 58 | "chunk_overlap": 100, 59 | "length_function": "len", 60 | "min_chunk_size": 150, 61 | }, 62 | "vectordb": { 63 | "provider": "chroma", 64 | "config": { 65 | "collection_name": type, 66 | "dir": f"{db_storage_path()}/{type}/{agents}", 67 | "allow_reset": allow_reset, 68 | }, 69 | }, 70 | } 71 | 72 | if embedder_config: 73 | config["embedder"] = embedder_config 74 | 75 | self.app = App.from_config(config=config) 76 | self.app.llm = FakeLLM() 77 | if allow_reset: 78 | self.app.reset() 79 | 80 | 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" 81 | self._generate_embedding(value, metadata) 82 | 83 | def search( # type: ignore # BUG?: Signature of "search" incompatible with supertype "Storage" 84 | self, 85 | query: str, 86 | limit: int = 3, 87 | filter: Optional[dict] = None, 88 | score_threshold: float = 0.35, 89 | ) -> List[Any]: 90 | with suppress_logging(): 91 | try: 92 | results = ( 93 | self.app.search(query, limit, where=filter) 94 | if filter 95 | else self.app.search(query, limit) 96 | ) 97 | except InvalidDimensionException: 98 | self.app.reset() 99 | return [] 100 | return [r for r in results if r["metadata"]["score"] >= score_threshold] 101 | 102 | def _generate_embedding(self, text: str, metadata: Dict[str, Any]) -> Any: 103 | with suppress_logging(): 104 | self.app.add(text, data_type="text", metadata=metadata) 105 | -------------------------------------------------------------------------------- /src/crewai/process.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Process(str, Enum): 5 | """ 6 | Class representing the different processes that can be used to tackle tasks 7 | """ 8 | 9 | sequential = "sequential" 10 | hierarchical = "hierarchical" 11 | # TODO: consensual = 'consensual' 12 | -------------------------------------------------------------------------------- /src/crewai/project/__init__.py: -------------------------------------------------------------------------------- 1 | from .annotations import agent, crew, task 2 | from .crew_base import CrewBase 3 | -------------------------------------------------------------------------------- /src/crewai/project/annotations.py: -------------------------------------------------------------------------------- 1 | def memoize(func): 2 | cache = {} 3 | 4 | def memoized_func(*args, **kwargs): 5 | key = (args, tuple(kwargs.items())) 6 | if key not in cache: 7 | cache[key] = func(*args, **kwargs) 8 | return cache[key] 9 | 10 | memoized_func.__dict__.update(func.__dict__) 11 | return memoized_func 12 | 13 | 14 | def task(func): 15 | if not hasattr(task, "registration_order"): 16 | task.registration_order = [] 17 | 18 | func.is_task = True 19 | wrapped_func = memoize(func) 20 | 21 | # Append the function name to the registration order list 22 | task.registration_order.append(func.__name__) 23 | 24 | return wrapped_func 25 | 26 | 27 | def agent(func): 28 | func.is_agent = True 29 | func = memoize(func) 30 | return func 31 | 32 | 33 | def crew(func): 34 | def wrapper(self, *args, **kwargs): 35 | instantiated_tasks = [] 36 | instantiated_agents = [] 37 | 38 | agent_roles = set() 39 | all_functions = { 40 | name: getattr(self, name) 41 | for name in dir(self) 42 | if callable(getattr(self, name)) 43 | } 44 | tasks = { 45 | name: func 46 | for name, func in all_functions.items() 47 | if hasattr(func, "is_task") 48 | } 49 | agents = { 50 | name: func 51 | for name, func in all_functions.items() 52 | if hasattr(func, "is_agent") 53 | } 54 | 55 | # Sort tasks by their registration order 56 | sorted_task_names = sorted( 57 | tasks, key=lambda name: task.registration_order.index(name) 58 | ) 59 | 60 | # Instantiate tasks in the order they were defined 61 | for task_name in sorted_task_names: 62 | task_instance = tasks[task_name]() 63 | instantiated_tasks.append(task_instance) 64 | if hasattr(task_instance, "agent"): 65 | agent_instance = task_instance.agent 66 | if agent_instance.role not in agent_roles: 67 | instantiated_agents.append(agent_instance) 68 | agent_roles.add(agent_instance.role) 69 | 70 | # Instantiate any additional agents not already included by tasks 71 | for agent_name in agents: 72 | temp_agent_instance = agents[agent_name]() 73 | if temp_agent_instance.role not in agent_roles: 74 | instantiated_agents.append(temp_agent_instance) 75 | agent_roles.add(temp_agent_instance.role) 76 | 77 | self.agents = instantiated_agents 78 | self.tasks = instantiated_tasks 79 | 80 | return func(self, *args, **kwargs) 81 | 82 | return wrapper 83 | -------------------------------------------------------------------------------- /src/crewai/project/crew_base.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import os 3 | from pathlib import Path 4 | 5 | import yaml 6 | from dotenv import load_dotenv 7 | from pydantic import ConfigDict 8 | 9 | load_dotenv() 10 | 11 | 12 | def CrewBase(cls): 13 | class WrappedClass(cls): 14 | model_config = ConfigDict(arbitrary_types_allowed=True) 15 | is_crew_class: bool = True # type: ignore 16 | 17 | base_directory = None 18 | for frame_info in inspect.stack(): 19 | if "site-packages" not in frame_info.filename: 20 | base_directory = Path(frame_info.filename).parent.resolve() 21 | break 22 | 23 | if base_directory is None: 24 | raise Exception( 25 | "Unable to dynamically determine the project's base directory, you must run it from the project's root directory." 26 | ) 27 | 28 | original_agents_config_path = getattr( 29 | cls, "agents_config", "config/agents.yaml" 30 | ) 31 | original_tasks_config_path = getattr(cls, "tasks_config", "config/tasks.yaml") 32 | 33 | def __init__(self, *args, **kwargs): 34 | super().__init__(*args, **kwargs) 35 | self.agents_config = self.load_yaml( 36 | os.path.join(self.base_directory, self.original_agents_config_path) 37 | ) 38 | self.tasks_config = self.load_yaml( 39 | os.path.join(self.base_directory, self.original_tasks_config_path) 40 | ) 41 | 42 | @staticmethod 43 | def load_yaml(config_path: str): 44 | with open(config_path, "r") as file: 45 | # parsedContent = YamlParser.parse(file) # type: ignore # Argument 1 to "parse" has incompatible type "TextIOWrapper"; expected "YamlParser" 46 | return yaml.safe_load(file) 47 | 48 | return WrappedClass 49 | -------------------------------------------------------------------------------- /src/crewai/tasks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/tasks/__init__.py -------------------------------------------------------------------------------- /src/crewai/tasks/task_output.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Union 2 | 3 | from pydantic import BaseModel, Field, model_validator 4 | 5 | 6 | class TaskOutput(BaseModel): 7 | """Class that represents the result of a task.""" 8 | 9 | description: str = Field(description="Description of the task") 10 | summary: Optional[str] = Field(description="Summary of the task", default=None) 11 | exported_output: Union[str, BaseModel] = Field( 12 | description="Output of the task", default=None 13 | ) 14 | agent: str = Field(description="Agent that executed the task") 15 | raw_output: str = Field(description="Result of the task") 16 | 17 | @model_validator(mode="after") 18 | def set_summary(self): 19 | excerpt = " ".join(self.description.split(" ")[:10]) 20 | self.summary = f"{excerpt}..." 21 | return self 22 | 23 | def result(self): 24 | return self.exported_output 25 | -------------------------------------------------------------------------------- /src/crewai/telemetry/__init__.py: -------------------------------------------------------------------------------- 1 | from .telemetry import Telemetry 2 | -------------------------------------------------------------------------------- /src/crewai/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/src/crewai/tools/__init__.py -------------------------------------------------------------------------------- /src/crewai/tools/agent_tools.py: -------------------------------------------------------------------------------- 1 | from langchain.tools import StructuredTool 2 | 3 | from crewai.agents.agent_builder.utilities.base_agent_tool import BaseAgentTools 4 | 5 | 6 | class AgentTools(BaseAgentTools): 7 | """Default tools around agent delegation""" 8 | 9 | def tools(self): 10 | coworkers = f"[{', '.join([f'{agent.role}' for agent in self.agents])}]" 11 | tools = [ 12 | StructuredTool.from_function( 13 | func=self.delegate_work, 14 | name="Delegate work to coworker", 15 | description=self.i18n.tools("delegate_work").format( 16 | coworkers=coworkers 17 | ), 18 | ), 19 | StructuredTool.from_function( 20 | func=self.ask_question, 21 | name="Ask question to coworker", 22 | description=self.i18n.tools("ask_question").format(coworkers=coworkers), 23 | ), 24 | ] 25 | return tools 26 | -------------------------------------------------------------------------------- /src/crewai/tools/cache_tools.py: -------------------------------------------------------------------------------- 1 | from langchain.tools import StructuredTool 2 | from pydantic import BaseModel, ConfigDict, Field 3 | 4 | from crewai.agents.cache import CacheHandler 5 | 6 | 7 | class CacheTools(BaseModel): 8 | """Default tools to hit the cache.""" 9 | 10 | model_config = ConfigDict(arbitrary_types_allowed=True) 11 | name: str = "Hit Cache" 12 | cache_handler: CacheHandler = Field( 13 | description="Cache Handler for the crew", 14 | default=CacheHandler(), 15 | ) 16 | 17 | def tool(self): 18 | return StructuredTool.from_function( 19 | func=self.hit_cache, 20 | name=self.name, 21 | description="Reads directly from the cache", 22 | ) 23 | 24 | def hit_cache(self, key): 25 | split = key.split("tool:") 26 | tool = split[1].split("|input:")[0].strip() 27 | tool_input = split[1].split("|input:")[1].strip() 28 | return self.cache_handler.read(tool, tool_input) 29 | -------------------------------------------------------------------------------- /src/crewai/tools/tool_calling.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Optional 2 | 3 | from pydantic import BaseModel as PydanticBaseModel 4 | from pydantic import Field as PydanticField 5 | from pydantic.v1 import BaseModel, Field 6 | 7 | 8 | class ToolCalling(BaseModel): 9 | tool_name: str = Field(..., description="The name of the tool to be called.") 10 | arguments: Optional[Dict[str, Any]] = Field( 11 | ..., description="A dictionary of arguments to be passed to the tool." 12 | ) 13 | 14 | 15 | class InstructorToolCalling(PydanticBaseModel): 16 | tool_name: str = PydanticField( 17 | ..., description="The name of the tool to be called." 18 | ) 19 | arguments: Optional[Dict[str, Any]] = PydanticField( 20 | ..., description="A dictionary of arguments to be passed to the tool." 21 | ) 22 | -------------------------------------------------------------------------------- /src/crewai/tools/tool_output_parser.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Any, List 3 | 4 | import regex 5 | from langchain.output_parsers import PydanticOutputParser 6 | from langchain_core.exceptions import OutputParserException 7 | from langchain_core.outputs import Generation 8 | from langchain_core.pydantic_v1 import ValidationError 9 | 10 | 11 | class ToolOutputParser(PydanticOutputParser): 12 | """Parses the function calling of a tool usage and it's arguments.""" 13 | 14 | def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any: 15 | result[0].text = self._transform_in_valid_json(result[0].text) 16 | json_object = super().parse_result(result) 17 | try: 18 | return self.pydantic_object.parse_obj(json_object) 19 | except ValidationError as e: 20 | name = self.pydantic_object.__name__ 21 | msg = f"Failed to parse {name} from completion {json_object}. Got: {e}" 22 | raise OutputParserException(msg, llm_output=json_object) 23 | 24 | def _transform_in_valid_json(self, text) -> str: 25 | text = text.replace("```", "").replace("json", "") 26 | json_pattern = r"\{(?:[^{}]|(?R))*\}" 27 | matches = regex.finditer(json_pattern, text) 28 | 29 | for match in matches: 30 | try: 31 | # Attempt to parse the matched string as JSON 32 | json_obj = json.loads(match.group()) 33 | # Return the first successfully parsed JSON object 34 | json_obj = json.dumps(json_obj) 35 | return str(json_obj) 36 | except json.JSONDecodeError: 37 | # If parsing fails, skip to the next match 38 | continue 39 | return text 40 | -------------------------------------------------------------------------------- /src/crewai/utilities/__init__.py: -------------------------------------------------------------------------------- 1 | from .converter import Converter, ConverterError 2 | from .file_handler import FileHandler 3 | from .i18n import I18N 4 | from .instructor import Instructor 5 | from .logger import Logger 6 | from .parser import YamlParser 7 | from .printer import Printer 8 | from .prompts import Prompts 9 | from .rpm_controller import RPMController 10 | 11 | __all__ = [ 12 | "Converter", 13 | "ConverterError", 14 | "FileHandler", 15 | "I18N", 16 | "Instructor", 17 | "Logger", 18 | "Printer", 19 | "Prompts", 20 | "RPMController", 21 | "YamlParser", 22 | ] 23 | -------------------------------------------------------------------------------- /src/crewai/utilities/constants.py: -------------------------------------------------------------------------------- 1 | TRAINING_DATA_FILE = "training_data.pkl" 2 | TRAINED_AGENTS_DATA_FILE = "trained_agents_data.pkl" 3 | -------------------------------------------------------------------------------- /src/crewai/utilities/converter.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from langchain.schema import HumanMessage, SystemMessage 4 | from langchain_openai import ChatOpenAI 5 | from pydantic import model_validator 6 | from crewai.agents.agent_builder.utilities.base_output_converter_base import ( 7 | OutputConverter, 8 | ) 9 | 10 | 11 | class ConverterError(Exception): 12 | """Error raised when Converter fails to parse the input.""" 13 | 14 | def __init__(self, message: str, *args: object) -> None: 15 | super().__init__(message, *args) 16 | self.message = message 17 | 18 | 19 | class Converter(OutputConverter): 20 | """Class that converts text into either pydantic or json.""" 21 | 22 | @model_validator(mode="after") 23 | def check_llm_provider(self): 24 | if not self._is_gpt(self.llm): 25 | self._is_gpt = False 26 | 27 | def to_pydantic(self, current_attempt=1): 28 | """Convert text to pydantic.""" 29 | try: 30 | if self._is_gpt: 31 | return self._create_instructor().to_pydantic() 32 | else: 33 | return self._create_chain().invoke({}) 34 | except Exception as e: 35 | if current_attempt < self.max_attempts: 36 | return self.to_pydantic(current_attempt + 1) 37 | return ConverterError( 38 | f"Failed to convert text into a pydantic model due to the following error: {e}" 39 | ) 40 | 41 | def to_json(self, current_attempt=1): 42 | """Convert text to json.""" 43 | try: 44 | if self._is_gpt: 45 | return self._create_instructor().to_json() 46 | else: 47 | return json.dumps(self._create_chain().invoke({}).model_dump()) 48 | except Exception: 49 | if current_attempt < self.max_attempts: 50 | return self.to_json(current_attempt + 1) 51 | return ConverterError("Failed to convert text into JSON.") 52 | 53 | def _create_instructor(self): 54 | """Create an instructor.""" 55 | from crewai.utilities import Instructor 56 | 57 | inst = Instructor( 58 | llm=self.llm, 59 | max_attempts=self.max_attempts, 60 | model=self.model, 61 | content=self.text, 62 | instructions=self.instructions, 63 | ) 64 | return inst 65 | 66 | def _create_chain(self): 67 | """Create a chain.""" 68 | from crewai.utilities.crew_pydantic_output_parser import ( 69 | CrewPydanticOutputParser, 70 | ) 71 | 72 | parser = CrewPydanticOutputParser(pydantic_object=self.model) 73 | new_prompt = SystemMessage(content=self.instructions) + HumanMessage( 74 | content=self.text 75 | ) 76 | return new_prompt | self.llm | parser 77 | 78 | def _is_gpt(self, llm) -> bool: # type: ignore # BUG? Name "_is_gpt" defined on line 20 hides name from outer scope 79 | return isinstance(llm, ChatOpenAI) and llm.openai_api_base is None 80 | -------------------------------------------------------------------------------- /src/crewai/utilities/crew_pydantic_output_parser.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Any, List, Type, Union 3 | 4 | import regex 5 | from langchain.output_parsers import PydanticOutputParser 6 | from langchain_core.exceptions import OutputParserException 7 | from langchain_core.outputs import Generation 8 | from langchain_core.pydantic_v1 import ValidationError 9 | from pydantic import BaseModel 10 | from pydantic.v1 import BaseModel as V1BaseModel 11 | 12 | 13 | class CrewPydanticOutputParser(PydanticOutputParser): 14 | """Parses the text into pydantic models""" 15 | 16 | pydantic_object: Union[Type[BaseModel], Type[V1BaseModel]] 17 | 18 | def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any: 19 | result[0].text = self._transform_in_valid_json(result[0].text) 20 | json_object = super().parse_result(result) 21 | try: 22 | return self.pydantic_object.parse_obj(json_object) 23 | except ValidationError as e: 24 | name = self.pydantic_object.__name__ 25 | msg = f"Failed to parse {name} from completion {json_object}. Got: {e}" 26 | raise OutputParserException(msg, llm_output=json_object) 27 | 28 | def _transform_in_valid_json(self, text) -> str: 29 | text = text.replace("```", "").replace("json", "") 30 | json_pattern = r"\{(?:[^{}]|(?R))*\}" 31 | matches = regex.finditer(json_pattern, text) 32 | 33 | for match in matches: 34 | try: 35 | # Attempt to parse the matched string as JSON 36 | json_obj = json.loads(match.group()) 37 | # Return the first successfully parsed JSON object 38 | json_obj = json.dumps(json_obj) 39 | return str(json_obj) 40 | except json.JSONDecodeError: 41 | # If parsing fails, skip to the next match 42 | continue 43 | return text 44 | -------------------------------------------------------------------------------- /src/crewai/utilities/file_handler.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pickle 3 | from datetime import datetime 4 | 5 | 6 | class FileHandler: 7 | """take care of file operations, currently it only logs messages to a file""" 8 | 9 | def __init__(self, file_path): 10 | if isinstance(file_path, bool): 11 | self._path = os.path.join(os.curdir, "logs.txt") 12 | elif isinstance(file_path, str): 13 | self._path = file_path 14 | else: 15 | raise ValueError("file_path must be either a boolean or a string.") 16 | 17 | def log(self, **kwargs): 18 | now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 19 | message = f"{now}: ".join([f"{key}={value}" for key, value in kwargs.items()]) 20 | with open(self._path, "a", encoding="utf-8") as file: 21 | file.write(message + "\n") 22 | 23 | 24 | class PickleHandler: 25 | def __init__(self, file_name: str) -> None: 26 | """ 27 | Initialize the PickleHandler with the name of the file where data will be stored. 28 | The file will be saved in the current directory. 29 | 30 | Parameters: 31 | - file_name (str): The name of the file for saving and loading data. 32 | """ 33 | self.file_path = os.path.join(os.getcwd(), file_name) 34 | 35 | def initialize_file(self) -> None: 36 | """ 37 | Initialize the file with an empty dictionary if it does not exist or is empty. 38 | """ 39 | if not os.path.exists(self.file_path) or os.path.getsize(self.file_path) == 0: 40 | self.save({}) # Save an empty dictionary to initialize the file 41 | 42 | def save(self, data) -> None: 43 | """ 44 | Save the data to the specified file using pickle. 45 | 46 | Parameters: 47 | - data (object): The data to be saved. 48 | """ 49 | with open(self.file_path, "wb") as file: 50 | pickle.dump(data, file) 51 | 52 | def load(self) -> dict: 53 | """ 54 | Load the data from the specified file using pickle. 55 | 56 | Returns: 57 | - dict: The data loaded from the file. 58 | """ 59 | if not os.path.exists(self.file_path) or os.path.getsize(self.file_path) == 0: 60 | return {} # Return an empty dictionary if the file does not exist or is empty 61 | 62 | with open(self.file_path, "rb") as file: 63 | try: 64 | return pickle.load(file) 65 | except EOFError: 66 | return {} # Return an empty dictionary if the file is empty or corrupted 67 | except Exception: 68 | raise # Raise any other exceptions that occur during loading 69 | -------------------------------------------------------------------------------- /src/crewai/utilities/i18n.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from typing import Dict, Optional 4 | 5 | from pydantic import BaseModel, Field, PrivateAttr, model_validator 6 | 7 | 8 | class I18N(BaseModel): 9 | _prompts: Dict[str, Dict[str, str]] = PrivateAttr() 10 | prompt_file: Optional[str] = Field( 11 | default=None, 12 | description="Path to the prompt_file file to load", 13 | ) 14 | 15 | @model_validator(mode="after") 16 | def load_prompts(self) -> "I18N": 17 | """Load prompts from a JSON file.""" 18 | try: 19 | if self.prompt_file: 20 | with open(self.prompt_file, "r") as f: 21 | self._prompts = json.load(f) 22 | else: 23 | dir_path = os.path.dirname(os.path.realpath(__file__)) 24 | prompts_path = os.path.join(dir_path, "../translations/en.json") 25 | 26 | with open(prompts_path, "r") as f: 27 | self._prompts = json.load(f) 28 | except FileNotFoundError: 29 | raise Exception(f"Prompt file '{self.prompt_file}' not found.") 30 | except json.JSONDecodeError: 31 | raise Exception("Error decoding JSON from the prompts file.") 32 | 33 | if not self._prompts: 34 | self._prompts = {} 35 | 36 | return self 37 | 38 | def slice(self, slice: str) -> str: 39 | return self.retrieve("slices", slice) 40 | 41 | def errors(self, error: str) -> str: 42 | return self.retrieve("errors", error) 43 | 44 | def tools(self, error: str) -> str: 45 | return self.retrieve("tools", error) 46 | 47 | def retrieve(self, kind, key) -> str: 48 | try: 49 | return self._prompts[kind][key] 50 | except Exception as _: 51 | raise Exception(f"Prompt for '{kind}':'{key}' not found.") 52 | -------------------------------------------------------------------------------- /src/crewai/utilities/instructor.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional, Type 2 | 3 | import instructor 4 | from pydantic import BaseModel, Field, PrivateAttr, model_validator 5 | 6 | 7 | class Instructor(BaseModel): 8 | """Class that wraps an agent llm with instructor.""" 9 | 10 | _client: Any = PrivateAttr() 11 | content: str = Field(description="Content to be sent to the instructor.") 12 | agent: Optional[Any] = Field( 13 | description="The agent that needs to use instructor.", default=None 14 | ) 15 | llm: Optional[Any] = Field( 16 | description="The agent that needs to use instructor.", default=None 17 | ) 18 | instructions: Optional[str] = Field( 19 | description="Instructions to be sent to the instructor.", 20 | default=None, 21 | ) 22 | model: Type[BaseModel] = Field( 23 | description="Pydantic model to be used to create an output." 24 | ) 25 | 26 | @model_validator(mode="after") 27 | def set_instructor(self): 28 | """Set instructor.""" 29 | if self.agent and not self.llm: 30 | self.llm = self.agent.function_calling_llm or self.agent.llm 31 | 32 | self._client = instructor.patch( 33 | self.llm.client._client, 34 | mode=instructor.Mode.TOOLS, 35 | ) 36 | return self 37 | 38 | def to_json(self): 39 | model = self.to_pydantic() 40 | return model.model_dump_json(indent=2) 41 | 42 | def to_pydantic(self): 43 | messages = [{"role": "user", "content": self.content}] 44 | if self.instructions: 45 | messages.append({"role": "system", "content": self.instructions}) 46 | 47 | model = self._client.chat.completions.create( 48 | model=self.llm.model_name, response_model=self.model, messages=messages 49 | ) 50 | return model 51 | -------------------------------------------------------------------------------- /src/crewai/utilities/logger.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from crewai.utilities.printer import Printer 4 | 5 | 6 | class Logger: 7 | _printer = Printer() 8 | 9 | def __init__(self, verbose_level=0): 10 | verbose_level = ( 11 | 2 if isinstance(verbose_level, bool) and verbose_level else verbose_level 12 | ) 13 | self.verbose_level = verbose_level 14 | 15 | def log(self, level, message, color="bold_green"): 16 | level_map = {"debug": 1, "info": 2} 17 | if self.verbose_level and level_map.get(level, 0) <= self.verbose_level: 18 | timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 19 | self._printer.print( 20 | f"[{timestamp}][{level.upper()}]: {message}", color=color 21 | ) 22 | -------------------------------------------------------------------------------- /src/crewai/utilities/parser.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | class YamlParser: 5 | def parse(file): 6 | content = file.read() 7 | # Replace single { and } with doubled ones, while leaving already doubled ones intact and the other special characters {# and {% 8 | modified_content = re.sub(r"(? BasePromptTemplate: 20 | """Generate a standard prompt for task execution.""" 21 | slices = ["role_playing"] 22 | if len(self.tools) > 0: 23 | slices.append("tools") 24 | else: 25 | slices.append("no_tools") 26 | 27 | slices.append("task") 28 | 29 | if not self.system_template and not self.prompt_template: 30 | return self._build_prompt(slices) 31 | else: 32 | return self._build_prompt( 33 | slices, 34 | self.system_template, 35 | self.prompt_template, 36 | self.response_template, 37 | ) 38 | 39 | def _build_prompt( 40 | self, 41 | components: list[str], 42 | system_template=None, 43 | prompt_template=None, 44 | response_template=None, 45 | ) -> BasePromptTemplate: 46 | """Constructs a prompt string from specified components.""" 47 | if not system_template and not prompt_template: 48 | prompt_parts = [self.i18n.slice(component) for component in components] 49 | prompt_parts.append(self.SCRATCHPAD_SLICE) 50 | prompt = PromptTemplate.from_template("".join(prompt_parts)) 51 | else: 52 | prompt_parts = [ 53 | self.i18n.slice(component) 54 | for component in components 55 | if component != "task" 56 | ] 57 | system = system_template.replace("{{ .System }}", "".join(prompt_parts)) 58 | prompt = prompt_template.replace( 59 | "{{ .Prompt }}", 60 | "".join([self.i18n.slice("task"), self.SCRATCHPAD_SLICE]), 61 | ) 62 | response = response_template.split("{{ .Response }}")[0] 63 | prompt = PromptTemplate.from_template(f"{system}\n{prompt}\n{response}") 64 | return prompt 65 | -------------------------------------------------------------------------------- /src/crewai/utilities/pydantic_schema_parser.py: -------------------------------------------------------------------------------- 1 | from typing import Type, get_args, get_origin 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class PydanticSchemaParser(BaseModel): 7 | model: Type[BaseModel] 8 | 9 | def get_schema(self) -> str: 10 | """ 11 | Public method to get the schema of a Pydantic model. 12 | 13 | :param model: The Pydantic model class to generate schema for. 14 | :return: String representation of the model schema. 15 | """ 16 | return self._get_model_schema(self.model) 17 | 18 | def _get_model_schema(self, model, depth=0) -> str: 19 | lines = [] 20 | for field_name, field in model.model_fields.items(): 21 | field_type_str = self._get_field_type(field, depth + 1) 22 | lines.append(f"{' ' * 4 * depth}- {field_name}: {field_type_str}") 23 | 24 | return "\n".join(lines) 25 | 26 | def _get_field_type(self, field, depth) -> str: 27 | field_type = field.annotation 28 | if get_origin(field_type) is list: 29 | list_item_type = get_args(field_type)[0] 30 | if isinstance(list_item_type, type) and issubclass( 31 | list_item_type, BaseModel 32 | ): 33 | nested_schema = self._get_model_schema(list_item_type, depth + 1) 34 | return f"List[\n{nested_schema}\n{' ' * 4 * depth}]" 35 | else: 36 | return f"List[{list_item_type.__name__}]" 37 | elif issubclass(field_type, BaseModel): 38 | return f"\n{self._get_model_schema(field_type, depth)}" 39 | else: 40 | return field_type.__name__ 41 | -------------------------------------------------------------------------------- /src/crewai/utilities/rpm_controller.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | from typing import Union 4 | 5 | from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator 6 | 7 | from crewai.utilities.logger import Logger 8 | 9 | 10 | class RPMController(BaseModel): 11 | model_config = ConfigDict(arbitrary_types_allowed=True) 12 | max_rpm: Union[int, None] = Field(default=None) 13 | logger: Logger = Field(default=None) 14 | _current_rpm: int = PrivateAttr(default=0) 15 | _timer: threading.Timer | None = PrivateAttr(default=None) 16 | _lock: threading.Lock = PrivateAttr(default=None) 17 | _shutdown_flag = False 18 | 19 | @model_validator(mode="after") 20 | def reset_counter(self): 21 | if self.max_rpm: 22 | if not self._shutdown_flag: 23 | self._lock = threading.Lock() 24 | self._reset_request_count() 25 | return self 26 | 27 | def check_or_wait(self): 28 | if not self.max_rpm: 29 | return True 30 | 31 | with self._lock: 32 | if self._current_rpm < self.max_rpm: 33 | self._current_rpm += 1 34 | return True 35 | else: 36 | self.logger.log( 37 | "info", "Max RPM reached, waiting for next minute to start." 38 | ) 39 | self._wait_for_next_minute() 40 | self._current_rpm = 1 41 | return True 42 | 43 | def stop_rpm_counter(self): 44 | if self._timer: 45 | self._timer.cancel() 46 | self._timer = None 47 | 48 | def _wait_for_next_minute(self): 49 | time.sleep(60) 50 | self._current_rpm = 0 51 | 52 | def _reset_request_count(self): 53 | with self._lock: 54 | self._current_rpm = 0 55 | if self._timer: 56 | self._shutdown_flag = True 57 | self._timer.cancel() 58 | self._timer = threading.Timer(60.0, self._reset_request_count) 59 | self._timer.start() 60 | -------------------------------------------------------------------------------- /src/crewai/utilities/token_counter_callback.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List 2 | 3 | import tiktoken 4 | from langchain.callbacks.base import BaseCallbackHandler 5 | from langchain.schema import LLMResult 6 | 7 | from crewai.agents.agent_builder.utilities.base_token_process import TokenProcess 8 | 9 | 10 | class TokenCalcHandler(BaseCallbackHandler): 11 | model_name: str = "" 12 | token_cost_process: TokenProcess 13 | 14 | def __init__(self, model_name, token_cost_process): 15 | self.model_name = model_name 16 | self.token_cost_process = token_cost_process 17 | 18 | def on_llm_start( 19 | self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any 20 | ) -> None: 21 | try: 22 | encoding = tiktoken.encoding_for_model(self.model_name) 23 | except KeyError: 24 | encoding = tiktoken.get_encoding("cl100k_base") 25 | 26 | if self.token_cost_process is None: 27 | return 28 | 29 | for prompt in prompts: 30 | self.token_cost_process.sum_prompt_tokens(len(encoding.encode(prompt))) 31 | 32 | async def on_llm_new_token(self, token: str, **kwargs) -> None: 33 | self.token_cost_process.sum_completion_tokens(1) 34 | 35 | def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None: 36 | self.token_cost_process.sum_successful_requests(1) 37 | -------------------------------------------------------------------------------- /src/crewai/utilities/training_handler.py: -------------------------------------------------------------------------------- 1 | from crewai.utilities.file_handler import PickleHandler 2 | 3 | 4 | class CrewTrainingHandler(PickleHandler): 5 | def save_trained_data(self, agent_id: str, trained_data: dict) -> None: 6 | """ 7 | Save the trained data for a specific agent. 8 | 9 | Parameters: 10 | - agent_id (str): The ID of the agent. 11 | - trained_data (dict): The trained data to be saved. 12 | """ 13 | data = self.load() 14 | data[agent_id] = trained_data 15 | self.save(data) 16 | 17 | def append(self, train_iteration: int, agent_id: str, new_data) -> None: 18 | """ 19 | Append new data to the existing pickle file. 20 | 21 | Parameters: 22 | - new_data (object): The new data to be appended. 23 | """ 24 | data = self.load() 25 | 26 | if agent_id in data: 27 | data[agent_id][train_iteration] = new_data 28 | else: 29 | data[agent_id] = {train_iteration: new_data} 30 | 31 | self.save(data) 32 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/tests/__init__.py -------------------------------------------------------------------------------- /tests/agent_tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhancockio/crewAI/691b094a400c095ccf9d6178b72535ae507060bf/tests/agent_tools/__init__.py -------------------------------------------------------------------------------- /tests/cli/cli_test.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | import pytest 4 | from click.testing import CliRunner 5 | 6 | from crewai.cli.cli import train, version 7 | 8 | 9 | @pytest.fixture 10 | def runner(): 11 | return CliRunner() 12 | 13 | 14 | @mock.patch("crewai.cli.cli.train_crew") 15 | def test_train_default_iterations(train_crew, runner): 16 | result = runner.invoke(train) 17 | 18 | train_crew.assert_called_once_with(5) 19 | assert result.exit_code == 0 20 | assert "Training the crew for 5 iterations" in result.output 21 | 22 | 23 | @mock.patch("crewai.cli.cli.train_crew") 24 | def test_train_custom_iterations(train_crew, runner): 25 | result = runner.invoke(train, ["--n_iterations", "10"]) 26 | 27 | train_crew.assert_called_once_with(10) 28 | assert result.exit_code == 0 29 | assert "Training the crew for 10 iterations" in result.output 30 | 31 | 32 | @mock.patch("crewai.cli.cli.train_crew") 33 | def test_train_invalid_string_iterations(train_crew, runner): 34 | result = runner.invoke(train, ["--n_iterations", "invalid"]) 35 | 36 | train_crew.assert_not_called() 37 | assert result.exit_code == 2 38 | assert ( 39 | "Usage: train [OPTIONS]\nTry 'train --help' for help.\n\nError: Invalid value for '-n' / '--n_iterations': 'invalid' is not a valid integer.\n" 40 | in result.output 41 | ) 42 | 43 | 44 | def test_version_command(runner): 45 | result = runner.invoke(version) 46 | 47 | assert result.exit_code == 0 48 | assert "crewai version:" in result.output 49 | 50 | 51 | def test_version_command_with_tools(runner): 52 | result = runner.invoke(version, ["--tools"]) 53 | 54 | assert result.exit_code == 0 55 | assert "crewai version:" in result.output 56 | assert ( 57 | "crewai tools version:" in result.output 58 | or "crewai tools not installed" in result.output 59 | ) 60 | -------------------------------------------------------------------------------- /tests/cli/train_crew_test.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from unittest import mock 3 | 4 | from crewai.cli.train_crew import train_crew 5 | 6 | 7 | @mock.patch("crewai.cli.train_crew.subprocess.run") 8 | def test_train_crew_positive_iterations(mock_subprocess_run): 9 | # Arrange 10 | n_iterations = 5 11 | mock_subprocess_run.return_value = subprocess.CompletedProcess( 12 | args=["poetry", "run", "train", str(n_iterations)], 13 | returncode=0, 14 | stdout="Success", 15 | stderr="", 16 | ) 17 | 18 | # Act 19 | train_crew(n_iterations) 20 | 21 | # Assert 22 | mock_subprocess_run.assert_called_once_with( 23 | ["poetry", "run", "train", str(n_iterations)], 24 | capture_output=False, 25 | text=True, 26 | check=True, 27 | ) 28 | 29 | 30 | @mock.patch("crewai.cli.train_crew.click") 31 | def test_train_crew_zero_iterations(click): 32 | train_crew(0) 33 | click.echo.assert_called_once_with( 34 | "An unexpected error occurred: The number of iterations must be a positive integer.", 35 | err=True, 36 | ) 37 | 38 | 39 | @mock.patch("crewai.cli.train_crew.click") 40 | def test_train_crew_negative_iterations(click): 41 | train_crew(-2) 42 | click.echo.assert_called_once_with( 43 | "An unexpected error occurred: The number of iterations must be a positive integer.", 44 | err=True, 45 | ) 46 | 47 | 48 | @mock.patch("crewai.cli.train_crew.click") 49 | @mock.patch("crewai.cli.train_crew.subprocess.run") 50 | def test_train_crew_called_process_error(mock_subprocess_run, click): 51 | n_iterations = 5 52 | mock_subprocess_run.side_effect = subprocess.CalledProcessError( 53 | returncode=1, 54 | cmd=["poetry", "run", "train", str(n_iterations)], 55 | output="Error", 56 | stderr="Some error occurred", 57 | ) 58 | train_crew(n_iterations) 59 | 60 | mock_subprocess_run.assert_called_once_with( 61 | ["poetry", "run", "train", "5"], capture_output=False, text=True, check=True 62 | ) 63 | click.echo.assert_has_calls( 64 | [ 65 | mock.call.echo( 66 | "An error occurred while training the crew: Command '['poetry', 'run', 'train', '5']' returned non-zero exit status 1.", 67 | err=True, 68 | ), 69 | mock.call.echo("Error", err=True), 70 | ] 71 | ) 72 | 73 | 74 | @mock.patch("crewai.cli.train_crew.click") 75 | @mock.patch("crewai.cli.train_crew.subprocess.run") 76 | def test_train_crew_unexpected_exception(mock_subprocess_run, click): 77 | # Arrange 78 | n_iterations = 5 79 | mock_subprocess_run.side_effect = Exception("Unexpected error") 80 | train_crew(n_iterations) 81 | 82 | mock_subprocess_run.assert_called_once_with( 83 | ["poetry", "run", "train", "5"], capture_output=False, text=True, check=True 84 | ) 85 | click.echo.assert_called_once_with( 86 | "An unexpected error occurred: Unexpected error", err=True 87 | ) 88 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # conftest.py 2 | from dotenv import load_dotenv 3 | 4 | load_result = load_dotenv(override=True) 5 | -------------------------------------------------------------------------------- /tests/memory/long_term_memory_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from crewai.memory.long_term.long_term_memory import LongTermMemory 4 | from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem 5 | 6 | 7 | @pytest.fixture 8 | def long_term_memory(): 9 | """Fixture to create a LongTermMemory instance""" 10 | return LongTermMemory() 11 | 12 | 13 | def test_save_and_search(long_term_memory): 14 | memory = LongTermMemoryItem( 15 | agent="test_agent", 16 | task="test_task", 17 | expected_output="test_output", 18 | datetime="test_datetime", 19 | quality=0.5, 20 | metadata={"task": "test_task", "quality": 0.5}, 21 | ) 22 | long_term_memory.save(memory) 23 | find = long_term_memory.search("test_task", latest_n=5)[0] 24 | assert find["score"] == 0.5 25 | assert find["datetime"] == "test_datetime" 26 | assert find["metadata"]["agent"] == "test_agent" 27 | assert find["metadata"]["quality"] == 0.5 28 | assert find["metadata"]["task"] == "test_task" 29 | assert find["metadata"]["expected_output"] == "test_output" 30 | -------------------------------------------------------------------------------- /tests/memory/short_term_memory_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from crewai.agent import Agent 4 | from crewai.crew import Crew 5 | from crewai.memory.short_term.short_term_memory import ShortTermMemory 6 | from crewai.memory.short_term.short_term_memory_item import ShortTermMemoryItem 7 | from crewai.task import Task 8 | 9 | 10 | @pytest.fixture 11 | def short_term_memory(): 12 | """Fixture to create a ShortTermMemory instance""" 13 | agent = Agent( 14 | role="Researcher", 15 | goal="Search relevant data and provide results", 16 | backstory="You are a researcher at a leading tech think tank.", 17 | tools=[], 18 | verbose=True, 19 | ) 20 | 21 | task = Task( 22 | description="Perform a search on specific topics.", 23 | expected_output="A list of relevant URLs based on the search query.", 24 | agent=agent, 25 | ) 26 | return ShortTermMemory(crew=Crew( 27 | agents=[agent], 28 | tasks=[task] 29 | )) 30 | 31 | 32 | @pytest.mark.vcr(filter_headers=["authorization"]) 33 | def test_save_and_search(short_term_memory): 34 | memory = ShortTermMemoryItem( 35 | data="""test value test value test value test value test value test value 36 | test value test value test value test value test value test value 37 | test value test value test value test value test value test value""", 38 | agent="test_agent", 39 | metadata={"task": "test_task"}, 40 | ) 41 | short_term_memory.save(memory) 42 | 43 | find = short_term_memory.search("test value", score_threshold=0.01)[0] 44 | assert find["context"] == memory.data, "Data value mismatch." 45 | assert find["metadata"]["agent"] == "test_agent", "Agent value mismatch." 46 | -------------------------------------------------------------------------------- /tests/project_test.py: -------------------------------------------------------------------------------- 1 | from crewai.agent import Agent 2 | from crewai.project import agent, task 3 | from crewai.task import Task 4 | 5 | 6 | class SimpleCrew: 7 | @agent 8 | def simple_agent(self): 9 | return Agent( 10 | role="Simple Agent", goal="Simple Goal", backstory="Simple Backstory" 11 | ) 12 | 13 | @task 14 | def simple_task(self): 15 | return Task(description="Simple Description", expected_output="Simple Output") 16 | 17 | 18 | def test_agent_memoization(): 19 | crew = SimpleCrew() 20 | first_call_result = crew.simple_agent() 21 | second_call_result = crew.simple_agent() 22 | 23 | assert ( 24 | first_call_result is second_call_result 25 | ), "Agent memoization is not working as expected" 26 | 27 | 28 | def test_task_memoization(): 29 | crew = SimpleCrew() 30 | first_call_result = crew.simple_task() 31 | second_call_result = crew.simple_task() 32 | 33 | assert ( 34 | first_call_result is second_call_result 35 | ), "Task memoization is not working as expected" 36 | -------------------------------------------------------------------------------- /tests/utilities/evaluators/test_task_evaluator.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | from unittest.mock import MagicMock, patch 3 | 4 | from crewai.utilities.evaluators.task_evaluator import ( 5 | TaskEvaluator, 6 | TrainingTaskEvaluation, 7 | ) 8 | 9 | 10 | @patch("crewai.utilities.evaluators.task_evaluator.Converter") 11 | def test_evaluate_training_data(converter_mock): 12 | training_data = { 13 | "agent_id": { 14 | "data1": { 15 | "initial_output": "Initial output 1", 16 | "human_feedback": "Human feedback 1", 17 | "improved_output": "Improved output 1", 18 | }, 19 | "data2": { 20 | "initial_output": "Initial output 2", 21 | "human_feedback": "Human feedback 2", 22 | "improved_output": "Improved output 2", 23 | }, 24 | } 25 | } 26 | agent_id = "agent_id" 27 | original_agent = MagicMock() 28 | function_return_value = TrainingTaskEvaluation( 29 | suggestions=[ 30 | "The initial output was already good, having a detailed explanation. However, the improved output " 31 | "gave similar information but in a more professional manner using better vocabulary. For future tasks, " 32 | "try to implement more elaborate language and precise terminology from the beginning." 33 | ], 34 | quality=8.0, 35 | final_summary="The agent responded well initially. However, the improved output showed that there is room " 36 | "for enhancement in terms of language usage, precision, and professionalism. For future tasks, the agent " 37 | "should focus more on these points from the start to increase performance.", 38 | ) 39 | converter_mock.return_value.to_pydantic.return_value = function_return_value 40 | result = TaskEvaluator(original_agent=original_agent).evaluate_training_data( 41 | training_data, agent_id 42 | ) 43 | 44 | assert result == function_return_value 45 | converter_mock.assert_has_calls( 46 | [ 47 | mock.call( 48 | llm=original_agent.llm, 49 | text="Assess the quality of the training data based on the llm output, human feedback , and llm " 50 | "output improved result.\n\nInitial Output:\nInitial output 1\n\nHuman Feedback:\nHuman feedback " 51 | "1\n\nImproved Output:\nImproved output 1\n\nInitial Output:\nInitial output 2\n\nHuman " 52 | "Feedback:\nHuman feedback 2\n\nImproved Output:\nImproved output 2\n\nPlease provide:\n- " 53 | "Based on the Human Feedbacks and the comparison between Initial Outputs and Improved outputs " 54 | "provide action items based on human_feedback for future tasks\n- A score from 0 to 10 evaluating " 55 | "on completion, quality, and overall performance from the improved output to the initial output " 56 | "based on the human feedback\n", 57 | model=TrainingTaskEvaluation, 58 | instructions="I'm gonna convert this raw text into valid JSON.\n\nThe json should have the " 59 | "following structure, with the following keys:\n- suggestions: List[str]\n- " 60 | "quality: float\n- final_summary: str", 61 | ), 62 | mock.call().to_pydantic(), 63 | ] 64 | ) 65 | -------------------------------------------------------------------------------- /tests/utilities/prompts.json: -------------------------------------------------------------------------------- 1 | { 2 | "hierarchical_manager_agent": { 3 | "role": "Lorem ipsum dolor sit amet", 4 | "goal": "Lorem ipsum dolor sit amet", 5 | "backstory": "Lorem ipsum dolor sit amet." 6 | }, 7 | "planning_manager_agent": { 8 | "role": "Lorem ipsum dolor sit amet", 9 | "goal": "Lorem ipsum dolor sit amet", 10 | "backstory": "Lorem ipsum dolor sit amet." 11 | }, 12 | "slices": { 13 | "observation": "Lorem ipsum dolor sit amet", 14 | "task": "Lorem ipsum dolor sit amet", 15 | "memory": "Lorem ipsum dolor sit amet", 16 | "role_playing": "Lorem ipsum dolor sit amet", 17 | "tools": "Lorem ipsum dolor sit amet", 18 | "no_tools": "Lorem ipsum dolor sit amet", 19 | "format": "Lorem ipsum dolor sit amet", 20 | "final_answer_format": "Lorem ipsum dolor sit amet", 21 | "format_without_tools": "Lorem ipsum dolor sit amet", 22 | "task_with_context": "Lorem ipsum dolor sit amet", 23 | "expected_output": "Lorem ipsum dolor sit amet", 24 | "human_feedback": "Lorem ipsum dolor sit amet", 25 | "getting_input": "Lorem ipsum dolor sit amet " 26 | }, 27 | "errors": { 28 | "force_final_answer": "Lorem ipsum dolor sit amet", 29 | "agent_tool_unexsiting_coworker": "Lorem ipsum dolor sit amet", 30 | "task_repeated_usage": "Lorem ipsum dolor sit amet", 31 | "tool_usage_error": "Lorem ipsum dolor sit amet", 32 | "tool_arguments_error": "Lorem ipsum dolor sit amet", 33 | "wrong_tool_name": "Lorem ipsum dolor sit amet", 34 | "tool_usage_exception": "Lorem ipsum dolor sit amet" 35 | }, 36 | "tools": { 37 | "delegate_work": "Lorem ipsum dolor sit amet", 38 | "ask_question": "Lorem ipsum dolor sit amet" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/utilities/test_file_handler.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | import pytest 5 | 6 | from crewai.utilities.file_handler import PickleHandler 7 | 8 | 9 | class TestPickleHandler(unittest.TestCase): 10 | def setUp(self): 11 | self.file_name = "test_data.pkl" 12 | self.file_path = os.path.join(os.getcwd(), self.file_name) 13 | self.handler = PickleHandler(self.file_name) 14 | 15 | def tearDown(self): 16 | if os.path.exists(self.file_path): 17 | os.remove(self.file_path) 18 | 19 | def test_initialize_file(self): 20 | assert os.path.exists(self.file_path) is False 21 | 22 | self.handler.initialize_file() 23 | 24 | assert os.path.exists(self.file_path) is True 25 | assert os.path.getsize(self.file_path) >= 0 26 | 27 | def test_save_and_load(self): 28 | data = {"key": "value"} 29 | self.handler.save(data) 30 | loaded_data = self.handler.load() 31 | assert loaded_data == data 32 | 33 | def test_load_empty_file(self): 34 | loaded_data = self.handler.load() 35 | assert loaded_data == {} 36 | 37 | def test_load_corrupted_file(self): 38 | with open(self.file_path, "wb") as file: 39 | file.write(b"corrupted data") 40 | 41 | with pytest.raises(Exception) as exc: 42 | self.handler.load() 43 | 44 | assert str(exc.value) == "pickle data was truncated" 45 | assert "" == str(exc.type) 46 | -------------------------------------------------------------------------------- /tests/utilities/test_i18n.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from crewai.utilities.i18n import I18N 4 | 5 | 6 | def test_load_prompts(): 7 | i18n = I18N() 8 | i18n.load_prompts() 9 | assert i18n._prompts is not None 10 | 11 | 12 | def test_slice(): 13 | i18n = I18N() 14 | i18n.load_prompts() 15 | assert isinstance(i18n.slice("role_playing"), str) 16 | 17 | 18 | def test_tools(): 19 | i18n = I18N() 20 | i18n.load_prompts() 21 | assert isinstance(i18n.tools("ask_question"), str) 22 | 23 | 24 | def test_retrieve(): 25 | i18n = I18N() 26 | i18n.load_prompts() 27 | assert isinstance(i18n.retrieve("slices", "role_playing"), str) 28 | 29 | 30 | def test_retrieve_not_found(): 31 | i18n = I18N() 32 | i18n.load_prompts() 33 | with pytest.raises(Exception): 34 | i18n.retrieve("nonexistent_kind", "nonexistent_key") 35 | 36 | 37 | def test_prompt_file(): 38 | import os 39 | 40 | path = os.path.join(os.path.dirname(__file__), "prompts.json") 41 | i18n = I18N(prompt_file=path) 42 | i18n.load_prompts() 43 | assert isinstance(i18n.retrieve("slices", "role_playing"), str) 44 | assert i18n.retrieve("slices", "role_playing") == "Lorem ipsum dolor sit amet" 45 | -------------------------------------------------------------------------------- /tests/utilities/test_training_handler.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | from crewai.utilities.training_handler import CrewTrainingHandler 5 | 6 | 7 | class TestCrewTrainingHandler(unittest.TestCase): 8 | def setUp(self): 9 | self.handler = CrewTrainingHandler("trained_data.pkl") 10 | 11 | def tearDown(self): 12 | os.remove("trained_data.pkl") 13 | del self.handler 14 | 15 | def test_save_trained_data(self): 16 | agent_id = "agent1" 17 | trained_data = {"param1": 1, "param2": 2} 18 | self.handler.save_trained_data(agent_id, trained_data) 19 | 20 | # Assert that the trained data is saved correctly 21 | data = self.handler.load() 22 | assert data[agent_id] == trained_data 23 | 24 | def test_append_existing_agent(self): 25 | train_iteration = 1 26 | agent_id = "agent1" 27 | new_data = {"param3": 3, "param4": 4} 28 | self.handler.append(train_iteration, agent_id, new_data) 29 | 30 | # Assert that the new data is appended correctly to the existing agent 31 | data = self.handler.load() 32 | assert data[agent_id][train_iteration] == new_data 33 | 34 | def test_append_new_agent(self): 35 | train_iteration = 1 36 | agent_id = "agent2" 37 | new_data = {"param5": 5, "param6": 6} 38 | self.handler.append(train_iteration, agent_id, new_data) 39 | 40 | # Assert that the new agent and data are appended correctly 41 | data = self.handler.load() 42 | assert data[agent_id][train_iteration] == new_data 43 | --------------------------------------------------------------------------------