crewai-cli 1.14.8a0.dev20260618__tar.gz → 1.14.8a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/PKG-INFO +2 -2
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/pyproject.toml +1 -1
- crewai_cli-1.14.8a2/src/crewai_cli/__init__.py +1 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/create_json_crew.py +4 -1
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/crew_run_tui.py +248 -2
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/run_crew.py +41 -5
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/pyproject.toml +1 -1
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/pyproject.toml +1 -1
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/tool/pyproject.toml +1 -1
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_create_crew.py +11 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_crew_run_tui.py +582 -1
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_run_crew.py +21 -0
- crewai_cli-1.14.8a0.dev20260618/src/crewai_cli/__init__.py +0 -1
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/.gitignore +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/README.md +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/add_crew_to_flow.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/constants.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/auth0.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/base_provider.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/entra_id.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/keycloak.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/okta.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/providers/workos.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/token.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/authentication/utils.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/checkpoint_cli.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/checkpoint_tui.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/cli.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/command.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/config.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/constants.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/create_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/create_flow.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/crew_chat.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/deploy/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/deploy/archive.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/deploy/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/deploy/validate.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/enterprise/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/enterprise/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/evaluate_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/experimental/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/experimental/skills/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/git.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/install_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/kickoff_flow.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/memory_tui.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/organization/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/organization/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/plot_flow.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/plus_api.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/provider.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/py.typed +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/remote_template/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/remote_template/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/replay_from_task.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/reset_memories_command.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/run_flow_definition.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/settings/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/settings/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/shared/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/shared/token_manager.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/task_outputs.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/AGENTS.md +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/.gitignore +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/README.md +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/config/agents.yaml +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/config/tasks.yaml +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/knowledge/user_preference.txt +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/skills/.gitkeep +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/crew/tools/custom_tool.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/.gitignore +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/README.md +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/crews/content_crew/config/agents.yaml +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/crews/content_crew/config/tasks.yaml +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/crews/content_crew/content_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/skills/.gitkeep +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/flow/tools/custom_tool.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/tool/.gitignore +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/tool/README.md +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/tool/src/{{folder_name}}/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/templates/tool/src/{{folder_name}}/tool.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/tools/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/train_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/triggers/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/triggers/main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/tui_picker.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/update_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/user_data.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/utils.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/src/crewai_cli/version.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/providers/test_auth0.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/providers/test_entra_id.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/providers/test_keycloak.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/providers/test_okta.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/providers/test_workos.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/test_auth_main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/authentication/test_utils.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/deploy/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/deploy/test_archive.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/deploy/test_deploy_main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/deploy/test_validate.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/enterprise/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/enterprise/test_main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/experimental/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/experimental/skills/test_main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/organization/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/organization/test_main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/skills/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_cli.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_click_compatibility.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_config.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_constants.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_crew_test.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_git.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_install_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_plus_api.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_run_flow_definition.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_settings_command.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_token_manager.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_train_crew.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_utils.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/test_version.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/tools/test_main.py +0 -0
- {crewai_cli-1.14.8a0.dev20260618 → crewai_cli-1.14.8a2}/tests/triggers/test_main.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crewai-cli
|
|
3
|
-
Version: 1.14.
|
|
3
|
+
Version: 1.14.8a2
|
|
4
4
|
Summary: CLI for CrewAI — scaffold, run, deploy and manage AI agent crews.
|
|
5
5
|
Project-URL: Homepage, https://crewai.com
|
|
6
6
|
Project-URL: Documentation, https://docs.crewai.com
|
|
@@ -10,7 +10,7 @@ Requires-Python: <3.14,>=3.10
|
|
|
10
10
|
Requires-Dist: appdirs~=1.4.4
|
|
11
11
|
Requires-Dist: certifi
|
|
12
12
|
Requires-Dist: click<9,>=8.1.7
|
|
13
|
-
Requires-Dist: crewai-core==1.14.
|
|
13
|
+
Requires-Dist: crewai-core==1.14.8a2
|
|
14
14
|
Requires-Dist: cryptography>=42.0
|
|
15
15
|
Requires-Dist: httpx~=0.28.1
|
|
16
16
|
Requires-Dist: packaging>=23.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.14.8a2"
|
|
@@ -89,13 +89,16 @@ description = "{name} using crewAI"
|
|
|
89
89
|
authors = [{{ name = "Your Name", email = "you@example.com" }}]
|
|
90
90
|
requires-python = ">=3.10,<3.14"
|
|
91
91
|
dependencies = [
|
|
92
|
-
"crewai[tools]
|
|
92
|
+
"crewai[tools]==1.14.8a1"
|
|
93
93
|
]
|
|
94
94
|
|
|
95
95
|
[build-system]
|
|
96
96
|
requires = ["hatchling"]
|
|
97
97
|
build-backend = "hatchling.build"
|
|
98
98
|
|
|
99
|
+
[tool.hatch.build.targets.wheel]
|
|
100
|
+
only-include = ["agents", "crew.jsonc", "tools", "knowledge", "skills"]
|
|
101
|
+
|
|
99
102
|
[tool.crewai]
|
|
100
103
|
type = "crew"
|
|
101
104
|
"""
|
|
@@ -34,6 +34,25 @@ _C_MUTED = "#666666" # dimmer than _C_DIM for past timeline
|
|
|
34
34
|
_STEP_NUMBER_RE = re.compile(r"\bstep\s+(\d+)\b", re.IGNORECASE)
|
|
35
35
|
_REFINEMENT_RE = re.compile(r"^\s*step\s+(\d+)\s*:\s*(.+)\s*$", re.IGNORECASE)
|
|
36
36
|
_INTERNAL_TOOL_NAMES = {"create_reasoning_plan"}
|
|
37
|
+
_LOG_ARGS_TEXT_LIMIT = 3_000
|
|
38
|
+
_LOG_RESULT_TEXT_LIMIT = 5_000
|
|
39
|
+
_LOG_TRUNCATION_SUFFIX = "... [truncated]"
|
|
40
|
+
# Background memory saves can emit their start event just after kickoff returns.
|
|
41
|
+
_MEMORY_SAVE_DRAIN_GRACE_SECONDS = 2.0
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _is_save_to_memory_tool(tool_name: str | None) -> bool:
|
|
45
|
+
return (tool_name or "").replace(" ", "_").lower() == "save_to_memory"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _truncate_log_text(value: Any, limit: int) -> str | None:
|
|
49
|
+
if value is None:
|
|
50
|
+
return None
|
|
51
|
+
text = str(value)
|
|
52
|
+
if len(text) <= limit:
|
|
53
|
+
return text
|
|
54
|
+
suffix = _LOG_TRUNCATION_SUFFIX
|
|
55
|
+
return f"{text[: max(0, limit - len(suffix))]}{suffix}"
|
|
37
56
|
|
|
38
57
|
|
|
39
58
|
def _enable_tracing_in_dotenv() -> None:
|
|
@@ -519,6 +538,8 @@ FooterKey .footer-key--key {
|
|
|
519
538
|
self._log_expanded: set[int] = set()
|
|
520
539
|
self._log_scroll_needed: bool = False
|
|
521
540
|
self._log_line_map: list[tuple[int, int, int]] = []
|
|
541
|
+
self._suppressed_memory_save_event_ids: set[str] = set()
|
|
542
|
+
self._memory_save_drain_timer: Any = None
|
|
522
543
|
|
|
523
544
|
self._event_handlers: list[tuple[type, Any]] = []
|
|
524
545
|
|
|
@@ -633,7 +654,6 @@ FooterKey .footer-key--key {
|
|
|
633
654
|
self.call_from_thread(self._on_crew_failed, str(e))
|
|
634
655
|
|
|
635
656
|
def _on_crew_done(self, output: str | None) -> None:
|
|
636
|
-
self._unsubscribe()
|
|
637
657
|
with self._lock:
|
|
638
658
|
self._status = "completed"
|
|
639
659
|
self._final_output = output
|
|
@@ -649,6 +669,8 @@ FooterKey .footer-key--key {
|
|
|
649
669
|
now = time.time()
|
|
650
670
|
for entry in self._log_entries:
|
|
651
671
|
if entry["status"] == "running":
|
|
672
|
+
if entry["tool_name"] == "memory_save":
|
|
673
|
+
continue
|
|
652
674
|
entry["status"] = "timeout"
|
|
653
675
|
entry["error"] = "No result received before crew completed"
|
|
654
676
|
entry["duration"] = now - entry["start_time"]
|
|
@@ -680,9 +702,9 @@ FooterKey .footer-key--key {
|
|
|
680
702
|
self.call_later(self._focus_activity_log)
|
|
681
703
|
self._tick_timer.stop()
|
|
682
704
|
self._tick_timer = self.set_interval(1 / 2, self._tick)
|
|
705
|
+
self._unsubscribe_if_no_running_memory_save(wait_for_queued=True)
|
|
683
706
|
|
|
684
707
|
def _on_crew_failed(self, error: str) -> None:
|
|
685
|
-
self._unsubscribe()
|
|
686
708
|
with self._lock:
|
|
687
709
|
self._status = "failed"
|
|
688
710
|
self._error = error
|
|
@@ -692,12 +714,16 @@ FooterKey .footer-key--key {
|
|
|
692
714
|
now = time.time()
|
|
693
715
|
for entry in self._log_entries:
|
|
694
716
|
if entry["status"] == "running":
|
|
717
|
+
if entry["tool_name"] == "memory_save":
|
|
718
|
+
continue
|
|
695
719
|
entry["status"] = "error"
|
|
720
|
+
entry["error"] = "No result received before crew failed"
|
|
696
721
|
entry["duration"] = now - entry["start_time"]
|
|
697
722
|
self._tick()
|
|
698
723
|
self.call_later(self._focus_activity_log)
|
|
699
724
|
self._tick_timer.stop()
|
|
700
725
|
self._tick_timer = self.set_interval(1 / 2, self._tick)
|
|
726
|
+
self._unsubscribe_if_no_running_memory_save(wait_for_queued=True)
|
|
701
727
|
|
|
702
728
|
# ── Actions ─────────────────────────────────────────────
|
|
703
729
|
|
|
@@ -1514,6 +1540,53 @@ FooterKey .footer-key--key {
|
|
|
1514
1540
|
pass
|
|
1515
1541
|
self._event_handlers.clear()
|
|
1516
1542
|
|
|
1543
|
+
def _has_running_memory_save_locked(self) -> bool:
|
|
1544
|
+
return any(
|
|
1545
|
+
entry["tool_name"] == "memory_save" and entry["status"] == "running"
|
|
1546
|
+
for entry in self._log_entries
|
|
1547
|
+
)
|
|
1548
|
+
|
|
1549
|
+
def _on_memory_save_drain_elapsed(self) -> None:
|
|
1550
|
+
self._memory_save_drain_timer = None
|
|
1551
|
+
self._unsubscribe_if_no_running_memory_save()
|
|
1552
|
+
|
|
1553
|
+
def _schedule_memory_save_drain_unsubscribe(self) -> bool:
|
|
1554
|
+
loop = getattr(self, "_loop", None)
|
|
1555
|
+
if loop is None:
|
|
1556
|
+
return False
|
|
1557
|
+
if getattr(self, "_thread_id", None) != threading.get_ident():
|
|
1558
|
+
try:
|
|
1559
|
+
loop.call_soon_threadsafe(self._schedule_memory_save_drain_unsubscribe)
|
|
1560
|
+
except RuntimeError:
|
|
1561
|
+
return False
|
|
1562
|
+
return True
|
|
1563
|
+
if self._memory_save_drain_timer is not None:
|
|
1564
|
+
self._memory_save_drain_timer.stop()
|
|
1565
|
+
self._memory_save_drain_timer = self.set_timer(
|
|
1566
|
+
_MEMORY_SAVE_DRAIN_GRACE_SECONDS,
|
|
1567
|
+
self._on_memory_save_drain_elapsed,
|
|
1568
|
+
name="memory-save-drain",
|
|
1569
|
+
)
|
|
1570
|
+
return True
|
|
1571
|
+
|
|
1572
|
+
def _unsubscribe_if_no_running_memory_save(
|
|
1573
|
+
self, *, wait_for_queued: bool = False
|
|
1574
|
+
) -> None:
|
|
1575
|
+
with self._lock:
|
|
1576
|
+
should_unsubscribe = (
|
|
1577
|
+
self._status
|
|
1578
|
+
in {
|
|
1579
|
+
"completed",
|
|
1580
|
+
"failed",
|
|
1581
|
+
}
|
|
1582
|
+
and not self._has_running_memory_save_locked()
|
|
1583
|
+
)
|
|
1584
|
+
|
|
1585
|
+
if should_unsubscribe:
|
|
1586
|
+
if wait_for_queued and self._schedule_memory_save_drain_unsubscribe():
|
|
1587
|
+
return
|
|
1588
|
+
self._unsubscribe()
|
|
1589
|
+
|
|
1517
1590
|
def _subscribe(self) -> None:
|
|
1518
1591
|
from crewai.events.event_bus import crewai_event_bus
|
|
1519
1592
|
from crewai.events.types.crew_events import CrewKickoffStartedEvent
|
|
@@ -1802,6 +1875,8 @@ FooterKey .footer-key--key {
|
|
|
1802
1875
|
entry["status"] == "running"
|
|
1803
1876
|
and entry["tool_name"] != event.tool_name
|
|
1804
1877
|
):
|
|
1878
|
+
if entry["tool_name"] == "memory_save":
|
|
1879
|
+
continue
|
|
1805
1880
|
entry["status"] = "timeout"
|
|
1806
1881
|
entry["error"] = (
|
|
1807
1882
|
"No result received before the next tool started"
|
|
@@ -1830,6 +1905,7 @@ FooterKey .footer-key--key {
|
|
|
1830
1905
|
"duration": None,
|
|
1831
1906
|
"task_idx": self._current_task_idx,
|
|
1832
1907
|
"plan_step_number": plan_step_number,
|
|
1908
|
+
"event_id": event.event_id,
|
|
1833
1909
|
}
|
|
1834
1910
|
)
|
|
1835
1911
|
self._complete_step("teal", f"⚡ {event.tool_name}…")
|
|
@@ -1923,8 +1999,178 @@ FooterKey .footer-key--key {
|
|
|
1923
1999
|
MemoryRetrievalCompletedEvent,
|
|
1924
2000
|
MemoryRetrievalFailedEvent,
|
|
1925
2001
|
MemoryRetrievalStartedEvent,
|
|
2002
|
+
MemorySaveCompletedEvent,
|
|
2003
|
+
MemorySaveFailedEvent,
|
|
2004
|
+
MemorySaveStartedEvent,
|
|
1926
2005
|
)
|
|
1927
2006
|
|
|
2007
|
+
def is_nested_save_to_memory_event(event: Any) -> bool:
|
|
2008
|
+
if event.parent_event_id is None:
|
|
2009
|
+
return False
|
|
2010
|
+
state = crewai_event_bus.runtime_state
|
|
2011
|
+
if state is None:
|
|
2012
|
+
return False
|
|
2013
|
+
parent_node = state.event_record.nodes.get(event.parent_event_id)
|
|
2014
|
+
parent_event = getattr(parent_node, "event", None)
|
|
2015
|
+
return getattr(
|
|
2016
|
+
parent_event, "type", None
|
|
2017
|
+
) == "tool_usage_started" and _is_save_to_memory_tool(
|
|
2018
|
+
getattr(parent_event, "tool_name", None)
|
|
2019
|
+
)
|
|
2020
|
+
|
|
2021
|
+
@crewai_event_bus.on(MemorySaveStartedEvent)
|
|
2022
|
+
def on_memory_save_started(source: Any, event: MemorySaveStartedEvent) -> None:
|
|
2023
|
+
with self._lock:
|
|
2024
|
+
if is_nested_save_to_memory_event(event):
|
|
2025
|
+
self._suppressed_memory_save_event_ids.add(event.event_id)
|
|
2026
|
+
return
|
|
2027
|
+
for entry in reversed(self._log_entries):
|
|
2028
|
+
if (
|
|
2029
|
+
_is_save_to_memory_tool(entry["tool_name"])
|
|
2030
|
+
and entry.get("event_id") == event.parent_event_id
|
|
2031
|
+
):
|
|
2032
|
+
self._suppressed_memory_save_event_ids.add(event.event_id)
|
|
2033
|
+
return
|
|
2034
|
+
for entry in reversed(self._log_entries):
|
|
2035
|
+
if (
|
|
2036
|
+
entry["tool_name"] == "memory_save"
|
|
2037
|
+
and entry.get("started_event_id") == event.event_id
|
|
2038
|
+
):
|
|
2039
|
+
entry["args"] = _truncate_log_text(
|
|
2040
|
+
event.value, _LOG_ARGS_TEXT_LIMIT
|
|
2041
|
+
)
|
|
2042
|
+
return
|
|
2043
|
+
self._log_entries.append(
|
|
2044
|
+
{
|
|
2045
|
+
"tool_name": "memory_save",
|
|
2046
|
+
"status": "running",
|
|
2047
|
+
"args": _truncate_log_text(event.value, _LOG_ARGS_TEXT_LIMIT),
|
|
2048
|
+
"result": None,
|
|
2049
|
+
"error": None,
|
|
2050
|
+
"start_time": time.time(),
|
|
2051
|
+
"duration": None,
|
|
2052
|
+
"task_idx": self._current_task_idx,
|
|
2053
|
+
"event_id": event.event_id,
|
|
2054
|
+
}
|
|
2055
|
+
)
|
|
2056
|
+
|
|
2057
|
+
self._register_handler(MemorySaveStartedEvent, on_memory_save_started)
|
|
2058
|
+
|
|
2059
|
+
@crewai_event_bus.on(MemorySaveCompletedEvent)
|
|
2060
|
+
def on_memory_save_completed(
|
|
2061
|
+
source: Any, event: MemorySaveCompletedEvent
|
|
2062
|
+
) -> None:
|
|
2063
|
+
with self._lock:
|
|
2064
|
+
if (
|
|
2065
|
+
event.started_event_id in self._suppressed_memory_save_event_ids
|
|
2066
|
+
or is_nested_save_to_memory_event(event)
|
|
2067
|
+
):
|
|
2068
|
+
if event.started_event_id is not None:
|
|
2069
|
+
self._suppressed_memory_save_event_ids.discard(
|
|
2070
|
+
event.started_event_id
|
|
2071
|
+
)
|
|
2072
|
+
else:
|
|
2073
|
+
for entry in reversed(self._log_entries):
|
|
2074
|
+
has_started_event_match = (
|
|
2075
|
+
event.started_event_id is not None
|
|
2076
|
+
and (
|
|
2077
|
+
entry.get("event_id") == event.started_event_id
|
|
2078
|
+
or entry.get("started_event_id")
|
|
2079
|
+
== event.started_event_id
|
|
2080
|
+
)
|
|
2081
|
+
)
|
|
2082
|
+
has_running_event_without_id = (
|
|
2083
|
+
event.started_event_id is None
|
|
2084
|
+
and entry["status"] == "running"
|
|
2085
|
+
)
|
|
2086
|
+
if entry["tool_name"] == "memory_save" and (
|
|
2087
|
+
has_running_event_without_id or has_started_event_match
|
|
2088
|
+
):
|
|
2089
|
+
entry["status"] = "success"
|
|
2090
|
+
entry["duration"] = event.save_time_ms / 1000
|
|
2091
|
+
entry["result"] = _truncate_log_text(
|
|
2092
|
+
event.value, _LOG_RESULT_TEXT_LIMIT
|
|
2093
|
+
)
|
|
2094
|
+
entry["error"] = None
|
|
2095
|
+
entry["started_event_id"] = event.started_event_id
|
|
2096
|
+
break
|
|
2097
|
+
else:
|
|
2098
|
+
self._log_entries.append(
|
|
2099
|
+
{
|
|
2100
|
+
"tool_name": "memory_save",
|
|
2101
|
+
"status": "success",
|
|
2102
|
+
"args": None,
|
|
2103
|
+
"result": _truncate_log_text(
|
|
2104
|
+
event.value, _LOG_RESULT_TEXT_LIMIT
|
|
2105
|
+
),
|
|
2106
|
+
"error": None,
|
|
2107
|
+
"start_time": time.time(),
|
|
2108
|
+
"duration": event.save_time_ms / 1000,
|
|
2109
|
+
"task_idx": self._current_task_idx,
|
|
2110
|
+
"started_event_id": event.started_event_id,
|
|
2111
|
+
}
|
|
2112
|
+
)
|
|
2113
|
+
|
|
2114
|
+
self._unsubscribe_if_no_running_memory_save(wait_for_queued=True)
|
|
2115
|
+
|
|
2116
|
+
self._register_handler(MemorySaveCompletedEvent, on_memory_save_completed)
|
|
2117
|
+
|
|
2118
|
+
@crewai_event_bus.on(MemorySaveFailedEvent)
|
|
2119
|
+
def on_memory_save_failed(source: Any, event: MemorySaveFailedEvent) -> None:
|
|
2120
|
+
with self._lock:
|
|
2121
|
+
if (
|
|
2122
|
+
event.started_event_id in self._suppressed_memory_save_event_ids
|
|
2123
|
+
or is_nested_save_to_memory_event(event)
|
|
2124
|
+
):
|
|
2125
|
+
if event.started_event_id is not None:
|
|
2126
|
+
self._suppressed_memory_save_event_ids.discard(
|
|
2127
|
+
event.started_event_id
|
|
2128
|
+
)
|
|
2129
|
+
else:
|
|
2130
|
+
for idx, entry in reversed(list(enumerate(self._log_entries))):
|
|
2131
|
+
has_started_event_match = (
|
|
2132
|
+
event.started_event_id is not None
|
|
2133
|
+
and (
|
|
2134
|
+
entry.get("event_id") == event.started_event_id
|
|
2135
|
+
or entry.get("started_event_id")
|
|
2136
|
+
== event.started_event_id
|
|
2137
|
+
)
|
|
2138
|
+
)
|
|
2139
|
+
has_running_event_without_id = (
|
|
2140
|
+
event.started_event_id is None
|
|
2141
|
+
and entry["status"] == "running"
|
|
2142
|
+
)
|
|
2143
|
+
if entry["tool_name"] == "memory_save" and (
|
|
2144
|
+
has_running_event_without_id or has_started_event_match
|
|
2145
|
+
):
|
|
2146
|
+
entry["status"] = "error"
|
|
2147
|
+
entry["error"] = event.error
|
|
2148
|
+
entry["duration"] = time.time() - entry["start_time"]
|
|
2149
|
+
entry["started_event_id"] = event.started_event_id
|
|
2150
|
+
self._log_expanded.add(idx)
|
|
2151
|
+
break
|
|
2152
|
+
else:
|
|
2153
|
+
self._log_entries.append(
|
|
2154
|
+
{
|
|
2155
|
+
"tool_name": "memory_save",
|
|
2156
|
+
"status": "error",
|
|
2157
|
+
"args": _truncate_log_text(
|
|
2158
|
+
event.value, _LOG_ARGS_TEXT_LIMIT
|
|
2159
|
+
),
|
|
2160
|
+
"result": None,
|
|
2161
|
+
"error": event.error,
|
|
2162
|
+
"start_time": time.time(),
|
|
2163
|
+
"duration": 0,
|
|
2164
|
+
"task_idx": self._current_task_idx,
|
|
2165
|
+
"started_event_id": event.started_event_id,
|
|
2166
|
+
}
|
|
2167
|
+
)
|
|
2168
|
+
self._log_expanded.add(len(self._log_entries) - 1)
|
|
2169
|
+
|
|
2170
|
+
self._unsubscribe_if_no_running_memory_save(wait_for_queued=True)
|
|
2171
|
+
|
|
2172
|
+
self._register_handler(MemorySaveFailedEvent, on_memory_save_failed)
|
|
2173
|
+
|
|
1928
2174
|
@crewai_event_bus.on(MemoryRetrievalStartedEvent)
|
|
1929
2175
|
def on_memory_retrieval_started(
|
|
1930
2176
|
source: Any, event: MemoryRetrievalStartedEvent
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from contextlib import AbstractContextManager, nullcontext
|
|
4
5
|
from enum import Enum
|
|
5
6
|
import os
|
|
@@ -7,10 +8,9 @@ from pathlib import Path
|
|
|
7
8
|
import re
|
|
8
9
|
import subprocess
|
|
9
10
|
import sys
|
|
10
|
-
from typing import TYPE_CHECKING, Any
|
|
11
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
11
12
|
|
|
12
13
|
import click
|
|
13
|
-
from crewai.project.json_loader import find_crew_json_file
|
|
14
14
|
from crewai_core.constants import CREWAI_TRAINED_AGENTS_FILE_ENV
|
|
15
15
|
from packaging import version
|
|
16
16
|
|
|
@@ -38,6 +38,15 @@ class CrewType(Enum):
|
|
|
38
38
|
_INPUT_PLACEHOLDER_RE = re.compile(r"(?<!{){([A-Za-z_][A-Za-z0-9_\-]*)}(?!})")
|
|
39
39
|
_CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV = "CREWAI_CLI_RUNNER_PACKAGE_DIR"
|
|
40
40
|
_CREWAI_RUNNER_SOURCE_DIR_ENV = "CREWAI_RUNNER_SOURCE_DIR"
|
|
41
|
+
_FULL_CREWAI_INSTALL_MESSAGE = """\
|
|
42
|
+
CrewAI CLI is installed without the `crewai` package required to run crews.
|
|
43
|
+
|
|
44
|
+
Install the full CrewAI prerelease package:
|
|
45
|
+
|
|
46
|
+
uv tool install --force --prerelease=allow 'crewai[tools]==1.14.8a1'
|
|
47
|
+
|
|
48
|
+
The quotes are required in zsh so `crewai[tools]` is not treated as a glob.
|
|
49
|
+
"""
|
|
41
50
|
_JSON_CREW_RUNNER_CODE = """
|
|
42
51
|
import importlib.util
|
|
43
52
|
import os
|
|
@@ -72,12 +81,39 @@ module_spec.loader.exec_module(module)
|
|
|
72
81
|
|
|
73
82
|
from crewai_core.constants import CREWAI_TRAINED_AGENTS_FILE_ENV
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
84
|
+
try:
|
|
85
|
+
module._run_json_crew(
|
|
86
|
+
trained_agents_file=os.getenv(CREWAI_TRAINED_AGENTS_FILE_ENV)
|
|
87
|
+
)
|
|
88
|
+
except module.click.ClickException as exc:
|
|
89
|
+
exc.show()
|
|
90
|
+
raise SystemExit(exc.exit_code)
|
|
78
91
|
""".strip()
|
|
79
92
|
|
|
80
93
|
|
|
94
|
+
def _import_find_crew_json_file() -> Callable[[], Path | None]:
|
|
95
|
+
from crewai.project.json_loader import find_crew_json_file as _find_crew_json_file
|
|
96
|
+
|
|
97
|
+
return cast("Callable[[], Path | None]", _find_crew_json_file)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _is_missing_crewai_package(exc: ModuleNotFoundError) -> bool:
|
|
101
|
+
return bool(exc.name and exc.name.startswith("crewai"))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _full_crewai_install_error() -> click.ClickException:
|
|
105
|
+
return click.ClickException(_FULL_CREWAI_INSTALL_MESSAGE)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def find_crew_json_file() -> Path | None:
|
|
109
|
+
try:
|
|
110
|
+
return _import_find_crew_json_file()()
|
|
111
|
+
except ModuleNotFoundError as exc:
|
|
112
|
+
if _is_missing_crewai_package(exc):
|
|
113
|
+
raise _full_crewai_install_error() from exc
|
|
114
|
+
raise
|
|
115
|
+
|
|
116
|
+
|
|
81
117
|
def _has_json_crew() -> bool:
|
|
82
118
|
"""Check if this is a JSON-defined crew project.
|
|
83
119
|
|
|
@@ -5,7 +5,10 @@ from pathlib import Path
|
|
|
5
5
|
from unittest import mock
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
|
+
import tomli
|
|
8
9
|
from click.testing import CliRunner
|
|
10
|
+
from packaging.requirements import Requirement
|
|
11
|
+
from packaging.version import Version
|
|
9
12
|
import crewai_cli.create_json_crew as json_crew
|
|
10
13
|
import crewai_cli.tui_picker as tui_picker
|
|
11
14
|
from crewai_cli.create_crew import create_crew, create_folder_structure
|
|
@@ -712,6 +715,14 @@ def test_json_create_provider_preselects_default_model(tmp_path, monkeypatch):
|
|
|
712
715
|
assert not (tmp_path / "json_crew" / "tests").exists()
|
|
713
716
|
assert not (tmp_path / "json_crew" / "config.jsonc").exists()
|
|
714
717
|
|
|
718
|
+
pyproject = tomli.loads((tmp_path / "json_crew" / "pyproject.toml").read_text())
|
|
719
|
+
dependency = pyproject["project"]["dependencies"][0]
|
|
720
|
+
assert dependency == "crewai[tools]==1.14.8a1"
|
|
721
|
+
assert Version("1.14.8a1") in Requirement(dependency).specifier
|
|
722
|
+
assert pyproject["tool"]["hatch"]["build"]["targets"]["wheel"][
|
|
723
|
+
"only-include"
|
|
724
|
+
] == ["agents", "crew.jsonc", "tools", "knowledge", "skills"]
|
|
725
|
+
|
|
715
726
|
crew_template = (tmp_path / "json_crew" / "crew.jsonc").read_text()
|
|
716
727
|
assert (
|
|
717
728
|
'"guardrail": "Every factual claim needs context support."'
|