crewai-cli 1.14.8a2.dev20260623__tar.gz → 1.14.8a3.dev20260624__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.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/PKG-INFO +2 -2
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/pyproject.toml +1 -1
- crewai_cli-1.14.8a3.dev20260624/src/crewai_cli/__init__.py +1 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/crew_run_tui.py +238 -2
- crewai_cli-1.14.8a3.dev20260624/src/crewai_cli/kickoff_flow.py +105 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/run_crew.py +10 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/run_declarative_flow.py +92 -63
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/pyproject.toml +1 -1
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/declarative_flow/pyproject.toml +1 -1
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/pyproject.toml +1 -1
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/tool/pyproject.toml +1 -1
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_crew_run_tui.py +46 -0
- crewai_cli-1.14.8a3.dev20260624/tests/test_flow_commands.py +248 -0
- crewai_cli-1.14.8a3.dev20260624/tests/test_kickoff_flow.py +63 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_run_crew.py +46 -2
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_run_declarative_flow.py +37 -0
- crewai_cli-1.14.8a2.dev20260623/src/crewai_cli/__init__.py +0 -1
- crewai_cli-1.14.8a2.dev20260623/tests/test_flow_commands.py +0 -117
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/.gitignore +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/README.md +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/add_crew_to_flow.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/constants.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/auth0.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/base_provider.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/entra_id.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/keycloak.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/okta.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/providers/workos.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/token.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/authentication/utils.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/checkpoint_cli.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/checkpoint_tui.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/cli.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/command.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/config.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/constants.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/create_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/create_flow.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/create_json_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/crew_chat.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/deploy/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/deploy/archive.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/deploy/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/deploy/validate.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/enterprise/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/enterprise/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/evaluate_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/experimental/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/experimental/skills/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/git.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/install_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/memory_tui.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/organization/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/organization/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/plot_flow.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/plus_api.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/provider.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/py.typed +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/remote_template/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/remote_template/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/replay_from_task.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/reset_memories_command.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/settings/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/settings/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/shared/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/shared/token_manager.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/task_outputs.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/AGENTS.md +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/.gitignore +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/README.md +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/config/agents.yaml +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/config/tasks.yaml +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/knowledge/user_preference.txt +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/skills/.gitkeep +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/crew/tools/custom_tool.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/declarative_flow/.gitignore +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/declarative_flow/README.md +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/declarative_flow/flow.yaml +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/.gitignore +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/README.md +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/crews/content_crew/config/agents.yaml +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/crews/content_crew/config/tasks.yaml +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/crews/content_crew/content_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/skills/.gitkeep +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/flow/tools/custom_tool.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/tool/.gitignore +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/tool/README.md +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/tool/src/{{folder_name}}/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/templates/tool/src/{{folder_name}}/tool.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/tools/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/train_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/triggers/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/triggers/main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/tui_picker.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/update_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/user_data.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/utils.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/version.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/providers/test_auth0.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/providers/test_entra_id.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/providers/test_keycloak.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/providers/test_okta.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/providers/test_workos.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/test_auth_main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/authentication/test_utils.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/deploy/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/deploy/test_archive.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/deploy/test_deploy_main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/deploy/test_validate.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/enterprise/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/enterprise/test_main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/experimental/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/experimental/skills/test_main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/organization/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/organization/test_main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/skills/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_cli.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_click_compatibility.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_config.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_constants.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_create_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_create_flow.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_crew_test.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_git.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_install_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_plus_api.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_settings_command.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_token_manager.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_train_crew.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_utils.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/test_version.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/tools/__init__.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/tests/tools/test_main.py +0 -0
- {crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/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.8a3.dev20260624
|
|
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.8a3.dev20260624
|
|
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.8a3.dev20260624"
|
{crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/crew_run_tui.py
RENAMED
|
@@ -17,7 +17,7 @@ from textual.binding import Binding, BindingType
|
|
|
17
17
|
from textual.containers import Horizontal, Vertical, VerticalScroll
|
|
18
18
|
from textual.css.query import NoMatches
|
|
19
19
|
from textual.screen import ModalScreen
|
|
20
|
-
from textual.widgets import Button, Footer, Header, Static
|
|
20
|
+
from textual.widgets import Button, Footer, Header, Input, Static
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
_SPINNER = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
@@ -382,6 +382,18 @@ Screen {
|
|
|
382
382
|
height: auto;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
+
#conversation-input {
|
|
386
|
+
display: none;
|
|
387
|
+
height: 3;
|
|
388
|
+
border-top: hkey #333333;
|
|
389
|
+
background: #1c1c1c;
|
|
390
|
+
color: #e0e0e0;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
#conversation-input:focus {
|
|
394
|
+
border-top: hkey #1F7982;
|
|
395
|
+
}
|
|
396
|
+
|
|
385
397
|
Header {
|
|
386
398
|
background: #1c1c1c;
|
|
387
399
|
color: #FF5A50;
|
|
@@ -483,6 +495,7 @@ FooterKey .footer-key--key {
|
|
|
483
495
|
total_tasks: int = 0,
|
|
484
496
|
agent_names: list[str] | None = None,
|
|
485
497
|
task_names: list[str] | None = None,
|
|
498
|
+
conversational: bool = False,
|
|
486
499
|
):
|
|
487
500
|
super().__init__()
|
|
488
501
|
self.title = f"CrewAI — {crew_name}"
|
|
@@ -544,6 +557,13 @@ FooterKey .footer-key--key {
|
|
|
544
557
|
self._event_handlers: list[tuple[type, Any]] = []
|
|
545
558
|
|
|
546
559
|
self._crew: Any = None
|
|
560
|
+
self._flow: Any = None
|
|
561
|
+
self._is_conversational = conversational
|
|
562
|
+
self._conversation_messages: list[tuple[str, str]] = []
|
|
563
|
+
self._conversation_turns = 0
|
|
564
|
+
self._conversation_turn_in_progress = False
|
|
565
|
+
self._conversation_previous_defer_trace_finalization: bool | None = None
|
|
566
|
+
self._conversation_exit_commands = {"exit", "quit"}
|
|
547
567
|
self._default_inputs: dict[str, Any] | None = None
|
|
548
568
|
self._crew_result: Any = None
|
|
549
569
|
self._crew_json_path: Any = None
|
|
@@ -566,6 +586,10 @@ FooterKey .footer-key--key {
|
|
|
566
586
|
yield Static(id="task-header")
|
|
567
587
|
with VerticalScroll(id="scroll-area"):
|
|
568
588
|
yield Static(id="main-content")
|
|
589
|
+
yield Input(
|
|
590
|
+
placeholder="Message the flow...",
|
|
591
|
+
id="conversation-input",
|
|
592
|
+
)
|
|
569
593
|
with VerticalScroll(id="log-panel"):
|
|
570
594
|
yield Static(id="log-content")
|
|
571
595
|
yield Footer()
|
|
@@ -574,7 +598,9 @@ FooterKey .footer-key--key {
|
|
|
574
598
|
self._start_time = time.time()
|
|
575
599
|
self._subscribe()
|
|
576
600
|
self._tick_timer = self.set_interval(1 / 8, self._tick)
|
|
577
|
-
if self.
|
|
601
|
+
if self._is_conversational and self._flow:
|
|
602
|
+
self._start_conversational_session()
|
|
603
|
+
elif self._crew:
|
|
578
604
|
self._run_crew_worker()
|
|
579
605
|
elif self._crew_json_path:
|
|
580
606
|
self._load_and_run_worker()
|
|
@@ -725,6 +751,140 @@ FooterKey .footer-key--key {
|
|
|
725
751
|
self._tick_timer = self.set_interval(1 / 2, self._tick)
|
|
726
752
|
self._unsubscribe_if_no_running_memory_save(wait_for_queued=True)
|
|
727
753
|
|
|
754
|
+
# ── Conversational flow execution ───────────────────────
|
|
755
|
+
|
|
756
|
+
def _start_conversational_session(self) -> None:
|
|
757
|
+
from crewai.events.listeners.tracing.utils import (
|
|
758
|
+
set_suppress_tracing_messages,
|
|
759
|
+
set_tui_mode,
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
set_tui_mode(True)
|
|
763
|
+
set_suppress_tracing_messages(True)
|
|
764
|
+
with self._lock:
|
|
765
|
+
self._status = "chatting"
|
|
766
|
+
self._current_step = None
|
|
767
|
+
self._elapsed_frozen = None
|
|
768
|
+
self._conversation_previous_defer_trace_finalization = getattr(
|
|
769
|
+
self._flow, "defer_trace_finalization", False
|
|
770
|
+
)
|
|
771
|
+
self._flow.defer_trace_finalization = True
|
|
772
|
+
|
|
773
|
+
try:
|
|
774
|
+
input_widget = self.query_one("#conversation-input", Input)
|
|
775
|
+
input_widget.display = True
|
|
776
|
+
input_widget.focus()
|
|
777
|
+
except Exception: # noqa: S110
|
|
778
|
+
pass
|
|
779
|
+
|
|
780
|
+
def _finalize_conversational_session(self) -> None:
|
|
781
|
+
if not (self._is_conversational and self._flow):
|
|
782
|
+
return
|
|
783
|
+
try:
|
|
784
|
+
self._flow.finalize_session_traces()
|
|
785
|
+
except Exception: # noqa: S110
|
|
786
|
+
pass
|
|
787
|
+
previous = self._conversation_previous_defer_trace_finalization
|
|
788
|
+
if previous is not None:
|
|
789
|
+
try:
|
|
790
|
+
self._flow.defer_trace_finalization = previous
|
|
791
|
+
except Exception: # noqa: S110
|
|
792
|
+
pass
|
|
793
|
+
|
|
794
|
+
def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
795
|
+
if event.input.id != "conversation-input":
|
|
796
|
+
return
|
|
797
|
+
if not self._is_conversational:
|
|
798
|
+
return
|
|
799
|
+
|
|
800
|
+
message = event.value.strip()
|
|
801
|
+
event.input.value = ""
|
|
802
|
+
if not message:
|
|
803
|
+
return
|
|
804
|
+
if message.lower() in self._conversation_exit_commands:
|
|
805
|
+
self._finalize_conversational_session()
|
|
806
|
+
self._unsubscribe()
|
|
807
|
+
self.exit(self._crew_result)
|
|
808
|
+
return
|
|
809
|
+
if self._conversation_turn_in_progress:
|
|
810
|
+
return
|
|
811
|
+
|
|
812
|
+
with self._lock:
|
|
813
|
+
self._conversation_messages.append(("user", message))
|
|
814
|
+
self._conversation_turn_in_progress = True
|
|
815
|
+
self._conversation_turns += 1
|
|
816
|
+
self._status = "working"
|
|
817
|
+
self._current_step = ("yellow", "Thinking…", "")
|
|
818
|
+
self._is_streaming = False
|
|
819
|
+
self._streaming_text = ""
|
|
820
|
+
self._task_full_output = ""
|
|
821
|
+
self._current_llm_text = ""
|
|
822
|
+
|
|
823
|
+
event.input.disabled = True
|
|
824
|
+
self._run_conversation_turn_worker(message)
|
|
825
|
+
|
|
826
|
+
@work(thread=True, exclusive=True, group="conversation")
|
|
827
|
+
def _run_conversation_turn_worker(self, message: str) -> None:
|
|
828
|
+
from crewai.events.listeners.tracing.utils import (
|
|
829
|
+
set_suppress_tracing_messages,
|
|
830
|
+
set_tui_mode,
|
|
831
|
+
)
|
|
832
|
+
|
|
833
|
+
set_tui_mode(True)
|
|
834
|
+
set_suppress_tracing_messages(True)
|
|
835
|
+
try:
|
|
836
|
+
result = self._flow.handle_turn(message)
|
|
837
|
+
if hasattr(result, "get_full_text") and hasattr(result, "result"):
|
|
838
|
+
for _chunk in result:
|
|
839
|
+
pass
|
|
840
|
+
result = result.result
|
|
841
|
+
self.call_from_thread(self._on_conversation_turn_done, result)
|
|
842
|
+
except Exception as e:
|
|
843
|
+
self.call_from_thread(self._on_conversation_turn_failed, str(e))
|
|
844
|
+
|
|
845
|
+
def _on_conversation_turn_done(self, result: Any) -> None:
|
|
846
|
+
with self._lock:
|
|
847
|
+
output = self._stringify_output(result)
|
|
848
|
+
self._conversation_messages.append(("assistant", output))
|
|
849
|
+
self._crew_result = result
|
|
850
|
+
self._conversation_turn_in_progress = False
|
|
851
|
+
self._status = "chatting"
|
|
852
|
+
self._is_streaming = False
|
|
853
|
+
self._streaming_text = ""
|
|
854
|
+
self._current_step = None
|
|
855
|
+
self._enable_conversation_input()
|
|
856
|
+
self._tick()
|
|
857
|
+
self._scroll_to_result()
|
|
858
|
+
|
|
859
|
+
def _on_conversation_turn_failed(self, error: str) -> None:
|
|
860
|
+
with self._lock:
|
|
861
|
+
self._status = "failed"
|
|
862
|
+
self._error = error
|
|
863
|
+
self._conversation_turn_in_progress = False
|
|
864
|
+
self._is_streaming = False
|
|
865
|
+
self._current_step = None
|
|
866
|
+
self._enable_conversation_input()
|
|
867
|
+
self._tick()
|
|
868
|
+
|
|
869
|
+
def _enable_conversation_input(self) -> None:
|
|
870
|
+
try:
|
|
871
|
+
input_widget = self.query_one("#conversation-input", Input)
|
|
872
|
+
input_widget.disabled = False
|
|
873
|
+
input_widget.focus()
|
|
874
|
+
except Exception: # noqa: S110
|
|
875
|
+
pass
|
|
876
|
+
|
|
877
|
+
def _stringify_output(self, result: Any) -> str:
|
|
878
|
+
raw_result = getattr(result, "raw", result)
|
|
879
|
+
if raw_result is None:
|
|
880
|
+
return ""
|
|
881
|
+
if isinstance(raw_result, str):
|
|
882
|
+
return raw_result
|
|
883
|
+
try:
|
|
884
|
+
return _json.dumps(raw_result, default=str, ensure_ascii=False)
|
|
885
|
+
except TypeError:
|
|
886
|
+
return str(raw_result)
|
|
887
|
+
|
|
728
888
|
# ── Actions ─────────────────────────────────────────────
|
|
729
889
|
|
|
730
890
|
def action_toggle_sidebar(self) -> None:
|
|
@@ -783,6 +943,7 @@ FooterKey .footer-key--key {
|
|
|
783
943
|
self._refresh_log_panel()
|
|
784
944
|
|
|
785
945
|
async def action_quit(self) -> None:
|
|
946
|
+
self._finalize_conversational_session()
|
|
786
947
|
self._unsubscribe()
|
|
787
948
|
self.exit(self._crew_result)
|
|
788
949
|
|
|
@@ -958,6 +1119,30 @@ FooterKey .footer-key--key {
|
|
|
958
1119
|
t = Text()
|
|
959
1120
|
sidebar_width = 30
|
|
960
1121
|
|
|
1122
|
+
if self._is_conversational:
|
|
1123
|
+
t.append(" CONVERSATION\n", style=f"bold {_C_PRIMARY}")
|
|
1124
|
+
t.append("\n")
|
|
1125
|
+
if self._conversation_turn_in_progress:
|
|
1126
|
+
t.append(f" {self._spinner()} ", style=_C_PRIMARY)
|
|
1127
|
+
t.append("Working\n", style=f"bold {_C_TEXT}")
|
|
1128
|
+
elif self._status == "failed":
|
|
1129
|
+
t.append(" ✘ Failed\n", style=_C_RED)
|
|
1130
|
+
else:
|
|
1131
|
+
t.append(" ● Ready\n", style=_C_GREEN)
|
|
1132
|
+
t.append(f" Turns {self._conversation_turns}\n", style=_C_DIM)
|
|
1133
|
+
t.append("\n")
|
|
1134
|
+
t.append(" TOKENS\n", style=f"bold {_C_PRIMARY}")
|
|
1135
|
+
t.append("\n")
|
|
1136
|
+
out = self._output_tokens + self._live_out_tokens
|
|
1137
|
+
t.append(f" ↑ {self._input_tokens:,}\n", style=_C_DIM)
|
|
1138
|
+
t.append(f" ↓ {out:,}\n", style=_C_DIM)
|
|
1139
|
+
t.append("\n")
|
|
1140
|
+
t.append(" COMMANDS\n", style=f"bold {_C_PRIMARY}")
|
|
1141
|
+
t.append("\n")
|
|
1142
|
+
t.append(" quit / exit\n", style=_C_DIM)
|
|
1143
|
+
widget.update(t)
|
|
1144
|
+
return
|
|
1145
|
+
|
|
961
1146
|
t.append(" TASKS\n", style=f"bold {_C_PRIMARY}")
|
|
962
1147
|
t.append("\n")
|
|
963
1148
|
|
|
@@ -1011,6 +1196,22 @@ FooterKey .footer-key--key {
|
|
|
1011
1196
|
widget = self.query_one("#task-header", Static)
|
|
1012
1197
|
t = Text()
|
|
1013
1198
|
|
|
1199
|
+
if self._is_conversational:
|
|
1200
|
+
if self._status == "failed":
|
|
1201
|
+
t.append("✘ ", style=f"bold {_C_RED}")
|
|
1202
|
+
t.append("Failed", style=f"bold {_C_RED}")
|
|
1203
|
+
if self._error:
|
|
1204
|
+
t.append(f"\n{self._error[:120]}", style=_C_RED)
|
|
1205
|
+
elif self._conversation_turn_in_progress:
|
|
1206
|
+
t.append(f"{self._spinner()} ", style=_C_PRIMARY)
|
|
1207
|
+
t.append("Flow is responding", style=f"bold {_C_PRIMARY}")
|
|
1208
|
+
else:
|
|
1209
|
+
t.append("● ", style=f"bold {_C_GREEN}")
|
|
1210
|
+
t.append("Conversational flow ready", style=f"bold {_C_GREEN}")
|
|
1211
|
+
t.append(" Type a message below", style=_C_DIM)
|
|
1212
|
+
widget.update(t)
|
|
1213
|
+
return
|
|
1214
|
+
|
|
1014
1215
|
if self._status == "completed":
|
|
1015
1216
|
elapsed = self._elapsed_frozen or (time.time() - self._start_time)
|
|
1016
1217
|
t.append("✔ ", style=f"bold {_C_GREEN}")
|
|
@@ -1062,6 +1263,41 @@ FooterKey .footer-key--key {
|
|
|
1062
1263
|
t = Text()
|
|
1063
1264
|
should_scroll = False
|
|
1064
1265
|
|
|
1266
|
+
if self._is_conversational:
|
|
1267
|
+
if not self._conversation_messages and not self._is_streaming:
|
|
1268
|
+
t.append(" Start the conversation below.\n", style=_C_MUTED)
|
|
1269
|
+
for role, content in self._conversation_messages:
|
|
1270
|
+
if role == "user":
|
|
1271
|
+
t.append("\n You\n", style=f"bold {_C_TEAL}")
|
|
1272
|
+
else:
|
|
1273
|
+
t.append("\n Assistant\n", style=f"bold {_C_PRIMARY}")
|
|
1274
|
+
rendered = _format_json_in_text(_unescape_text(content))
|
|
1275
|
+
for line in rendered.split("\n"):
|
|
1276
|
+
style = _C_TEXT if role == "assistant" else _C_DIM
|
|
1277
|
+
t.append(f" {line}\n", style=style)
|
|
1278
|
+
|
|
1279
|
+
if self._is_streaming and self._streaming_text:
|
|
1280
|
+
text = _unescape_text(self._filtered_streaming_text())
|
|
1281
|
+
if text.strip():
|
|
1282
|
+
t.append("\n Assistant\n", style=f"bold {_C_PRIMARY}")
|
|
1283
|
+
for line in text.rstrip().split("\n")[-40:]:
|
|
1284
|
+
t.append(f" {line}\n", style=_C_TEXT)
|
|
1285
|
+
should_scroll = True
|
|
1286
|
+
|
|
1287
|
+
if self._status == "failed" and self._error:
|
|
1288
|
+
t.append("\n Error\n", style=f"bold {_C_RED}")
|
|
1289
|
+
t.append(f" {self._error}\n", style=_C_RED)
|
|
1290
|
+
|
|
1291
|
+
widget.update(t)
|
|
1292
|
+
if should_scroll:
|
|
1293
|
+
try:
|
|
1294
|
+
self.query_one("#scroll-area", VerticalScroll).scroll_end(
|
|
1295
|
+
animate=False
|
|
1296
|
+
)
|
|
1297
|
+
except Exception: # noqa: S110
|
|
1298
|
+
pass
|
|
1299
|
+
return
|
|
1300
|
+
|
|
1065
1301
|
# Plan section
|
|
1066
1302
|
if self._plan and self._plan.get("steps"):
|
|
1067
1303
|
plan_title = self._plan.get("plan", "Plan")
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import inspect
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _project_script_target(script_name: str) -> str | None:
|
|
14
|
+
try:
|
|
15
|
+
from crewai_cli.utils import read_toml
|
|
16
|
+
|
|
17
|
+
pyproject = read_toml()
|
|
18
|
+
except Exception:
|
|
19
|
+
return None
|
|
20
|
+
|
|
21
|
+
target = pyproject.get("project", {}).get("scripts", {}).get(script_name)
|
|
22
|
+
return target if isinstance(target, str) else None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _prepare_project_import_path() -> None:
|
|
26
|
+
cwd = Path.cwd()
|
|
27
|
+
for path in (cwd / "src", cwd):
|
|
28
|
+
path_str = str(path)
|
|
29
|
+
if path.exists() and path_str not in sys.path:
|
|
30
|
+
sys.path.insert(0, path_str)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _load_conversational_flow_from_kickoff_script() -> Any | None:
|
|
34
|
+
target = _project_script_target("kickoff")
|
|
35
|
+
if not target or ":" not in target:
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
module_name, _callable_name = target.split(":", 1)
|
|
39
|
+
_prepare_project_import_path()
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
module = importlib.import_module(module_name)
|
|
43
|
+
from crewai.flow.flow import Flow
|
|
44
|
+
except Exception:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
for value in vars(module).values():
|
|
48
|
+
if (
|
|
49
|
+
inspect.isclass(value)
|
|
50
|
+
and value is not Flow
|
|
51
|
+
and issubclass(value, Flow)
|
|
52
|
+
and getattr(value, "conversational", False)
|
|
53
|
+
):
|
|
54
|
+
return value()
|
|
55
|
+
|
|
56
|
+
for value in vars(module).values():
|
|
57
|
+
if (
|
|
58
|
+
isinstance(value, Flow)
|
|
59
|
+
and getattr(value, "conversational", False)
|
|
60
|
+
and callable(getattr(value, "handle_turn", None))
|
|
61
|
+
):
|
|
62
|
+
return value
|
|
63
|
+
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _run_conversational_flow_tui(flow: Any) -> Any:
|
|
68
|
+
from crewai_cli.crew_run_tui import CrewRunApp
|
|
69
|
+
|
|
70
|
+
app = CrewRunApp(
|
|
71
|
+
crew_name=getattr(flow, "name", None) or type(flow).__name__,
|
|
72
|
+
conversational=True,
|
|
73
|
+
)
|
|
74
|
+
app._flow = flow
|
|
75
|
+
app.run()
|
|
76
|
+
|
|
77
|
+
if app._status == "failed":
|
|
78
|
+
raise SystemExit(1)
|
|
79
|
+
|
|
80
|
+
return app._crew_result
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def kickoff_flow() -> None:
|
|
84
|
+
"""
|
|
85
|
+
Kickoff the flow by running a command in the UV environment.
|
|
86
|
+
"""
|
|
87
|
+
flow = _load_conversational_flow_from_kickoff_script()
|
|
88
|
+
if flow is not None:
|
|
89
|
+
_run_conversational_flow_tui(flow)
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
command = ["uv", "run", "kickoff"]
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
result = subprocess.run(command, capture_output=False, text=True, check=True) # noqa: S603
|
|
96
|
+
|
|
97
|
+
if result.stderr:
|
|
98
|
+
click.echo(result.stderr, err=True)
|
|
99
|
+
|
|
100
|
+
except subprocess.CalledProcessError as e:
|
|
101
|
+
click.echo(f"An error occurred while running the flow: {e}", err=True)
|
|
102
|
+
click.echo(e.output, err=True)
|
|
103
|
+
|
|
104
|
+
except Exception as e:
|
|
105
|
+
click.echo(f"An unexpected error occurred: {e}", err=True)
|
{crewai_cli-1.14.8a2.dev20260623 → crewai_cli-1.14.8a3.dev20260624}/src/crewai_cli/run_crew.py
RENAMED
|
@@ -604,6 +604,16 @@ def _run_flow_project(
|
|
|
604
604
|
run_declarative_flow_in_project_env(definition=definition)
|
|
605
605
|
return
|
|
606
606
|
|
|
607
|
+
from crewai_cli.kickoff_flow import (
|
|
608
|
+
_load_conversational_flow_from_kickoff_script,
|
|
609
|
+
_run_conversational_flow_tui,
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
flow = _load_conversational_flow_from_kickoff_script()
|
|
613
|
+
if flow is not None:
|
|
614
|
+
_run_conversational_flow_tui(flow)
|
|
615
|
+
return
|
|
616
|
+
|
|
607
617
|
_execute_uv_script("kickoff", entity_type="flow")
|
|
608
618
|
|
|
609
619
|
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from pathlib import Path
|
|
4
|
+
from pathlib import Path, PureWindowsPath
|
|
5
5
|
import subprocess
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
|
+
from pydantic import ValidationError
|
|
9
10
|
|
|
10
11
|
from crewai_cli.utils import build_env_with_all_tool_credentials
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def run_declarative_flow_in_project_env(
|
|
14
|
-
definition: str, inputs: str | None = None
|
|
15
|
+
definition: str | Path, inputs: str | None = None
|
|
15
16
|
) -> None:
|
|
16
17
|
"""Run a declarative flow inside the project's Python environment."""
|
|
17
18
|
if is_declarative_flow_project_env() or not _has_project_file():
|
|
@@ -24,7 +25,7 @@ def run_declarative_flow_in_project_env(
|
|
|
24
25
|
_execute_declarative_flow_command(["uv", "run", "crewai", "run"])
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
def plot_declarative_flow_in_project_env(definition: str) -> None:
|
|
28
|
+
def plot_declarative_flow_in_project_env(definition: str | Path) -> None:
|
|
28
29
|
"""Plot a declarative flow inside the project's Python environment."""
|
|
29
30
|
if is_declarative_flow_project_env() or not _has_project_file():
|
|
30
31
|
plot_declarative_flow(definition=definition)
|
|
@@ -33,7 +34,7 @@ def plot_declarative_flow_in_project_env(definition: str) -> None:
|
|
|
33
34
|
_execute_declarative_flow_command(["uv", "run", "crewai", "flow", "plot"])
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def run_declarative_flow(definition: str, inputs: str | None = None) -> None:
|
|
37
|
+
def run_declarative_flow(definition: str | Path, inputs: str | None = None) -> None:
|
|
37
38
|
"""Run a declarative flow from a definition path."""
|
|
38
39
|
parsed_inputs = _parse_inputs(inputs)
|
|
39
40
|
|
|
@@ -49,7 +50,7 @@ def run_declarative_flow(definition: str, inputs: str | None = None) -> None:
|
|
|
49
50
|
click.echo(_format_result(result))
|
|
50
51
|
|
|
51
52
|
|
|
52
|
-
def plot_declarative_flow(definition: str) -> None:
|
|
53
|
+
def plot_declarative_flow(definition: str | Path) -> None:
|
|
53
54
|
"""Plot a declarative flow from a definition path."""
|
|
54
55
|
try:
|
|
55
56
|
flow = load_declarative_flow(definition)
|
|
@@ -61,11 +62,10 @@ def plot_declarative_flow(definition: str) -> None:
|
|
|
61
62
|
raise SystemExit(1) from exc
|
|
62
63
|
|
|
63
64
|
|
|
64
|
-
def load_declarative_flow(definition: str) -> Any:
|
|
65
|
+
def load_declarative_flow(definition: str | Path) -> Any:
|
|
65
66
|
"""Load a declarative Flow instance from a definition path."""
|
|
66
67
|
try:
|
|
67
68
|
from crewai.flow.flow import Flow
|
|
68
|
-
from crewai.flow.flow_definition import FlowDefinition
|
|
69
69
|
except ImportError as exc:
|
|
70
70
|
click.echo(
|
|
71
71
|
"Running declarative flows requires the full crewai package.",
|
|
@@ -74,19 +74,36 @@ def load_declarative_flow(definition: str) -> Any:
|
|
|
74
74
|
raise SystemExit(1) from exc
|
|
75
75
|
|
|
76
76
|
definition_path = Path(definition).expanduser()
|
|
77
|
-
|
|
77
|
+
try:
|
|
78
|
+
if not definition_path.is_file():
|
|
79
|
+
if definition_path.exists():
|
|
80
|
+
click.echo(
|
|
81
|
+
f"Invalid --definition path: {definition} is not a file.",
|
|
82
|
+
err=True,
|
|
83
|
+
)
|
|
84
|
+
raise SystemExit(1)
|
|
85
|
+
click.echo(
|
|
86
|
+
f"Invalid --definition path: {definition} does not exist.", err=True
|
|
87
|
+
)
|
|
88
|
+
raise SystemExit(1)
|
|
89
|
+
except OSError as exc:
|
|
90
|
+
click.echo(f"Invalid --definition path: {definition} ({exc})", err=True)
|
|
91
|
+
raise SystemExit(1) from exc
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
try:
|
|
94
|
+
return Flow.from_declaration(path=definition_path)
|
|
95
|
+
except (OSError, UnicodeError, ValueError, ValidationError) as exc:
|
|
96
|
+
click.echo(
|
|
97
|
+
f"Unable to read --definition path {definition_path}: {exc}",
|
|
98
|
+
err=True,
|
|
99
|
+
)
|
|
100
|
+
raise SystemExit(1) from exc
|
|
85
101
|
|
|
86
102
|
|
|
87
103
|
def configured_project_declarative_flow(
|
|
88
104
|
pyproject_data: dict[str, Any] | None = None,
|
|
89
|
-
|
|
105
|
+
project_root: Path | None = None,
|
|
106
|
+
) -> Path | None:
|
|
90
107
|
"""Return the configured declarative flow source for flow projects."""
|
|
91
108
|
if pyproject_data is None:
|
|
92
109
|
try:
|
|
@@ -102,7 +119,66 @@ def configured_project_declarative_flow(
|
|
|
102
119
|
definition = crewai_config.get("definition")
|
|
103
120
|
if not isinstance(definition, str):
|
|
104
121
|
return None
|
|
105
|
-
|
|
122
|
+
definition = definition.strip()
|
|
123
|
+
if not definition:
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
return _resolve_project_definition_path(
|
|
127
|
+
definition=definition,
|
|
128
|
+
project_root=project_root or Path.cwd(),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _resolve_project_definition_path(definition: str, project_root: Path) -> Path:
|
|
133
|
+
definition_path = Path(definition)
|
|
134
|
+
windows_definition_path = PureWindowsPath(definition)
|
|
135
|
+
|
|
136
|
+
if definition.startswith("~"):
|
|
137
|
+
raise click.UsageError(
|
|
138
|
+
"[tool.crewai] definition must be a project-local path; "
|
|
139
|
+
f"got {definition!r}."
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
if definition_path.is_absolute() or windows_definition_path.is_absolute():
|
|
143
|
+
raise click.UsageError(
|
|
144
|
+
"[tool.crewai] definition must be relative to the project root; "
|
|
145
|
+
f"got {definition!r}."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
root = project_root.resolve(strict=True)
|
|
150
|
+
except OSError as exc:
|
|
151
|
+
raise click.UsageError(
|
|
152
|
+
f"Invalid project root for [tool.crewai] definition: {exc}"
|
|
153
|
+
) from exc
|
|
154
|
+
|
|
155
|
+
candidate = root / definition_path
|
|
156
|
+
try:
|
|
157
|
+
resolved_candidate = candidate.resolve(strict=False)
|
|
158
|
+
except OSError as exc:
|
|
159
|
+
raise click.UsageError(
|
|
160
|
+
f"Invalid [tool.crewai] definition path {definition!r}: {exc}"
|
|
161
|
+
) from exc
|
|
162
|
+
|
|
163
|
+
if not resolved_candidate.is_relative_to(root):
|
|
164
|
+
raise click.UsageError(
|
|
165
|
+
"[tool.crewai] definition must resolve inside the project root; "
|
|
166
|
+
f"got {definition!r}."
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if not resolved_candidate.exists():
|
|
170
|
+
raise click.UsageError(
|
|
171
|
+
"[tool.crewai] definition must point to an existing file; "
|
|
172
|
+
f"got {definition!r}."
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if not resolved_candidate.is_file():
|
|
176
|
+
raise click.UsageError(
|
|
177
|
+
"[tool.crewai] definition must point to a regular file; "
|
|
178
|
+
f"got {definition!r}."
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
return resolved_candidate
|
|
106
182
|
|
|
107
183
|
|
|
108
184
|
def _execute_declarative_flow_command(command: list[str]) -> None:
|
|
@@ -154,53 +230,6 @@ def _parse_inputs(inputs: str | None) -> dict[str, Any] | None:
|
|
|
154
230
|
return parsed
|
|
155
231
|
|
|
156
232
|
|
|
157
|
-
def _read_declarative_flow_source(path: Path, definition: str) -> str:
|
|
158
|
-
try:
|
|
159
|
-
if path.is_file():
|
|
160
|
-
source = _read_declarative_flow_file(path)
|
|
161
|
-
elif path.exists():
|
|
162
|
-
click.echo(
|
|
163
|
-
f"Invalid --definition path: {definition} is not a file.", err=True
|
|
164
|
-
)
|
|
165
|
-
raise SystemExit(1)
|
|
166
|
-
else:
|
|
167
|
-
click.echo(
|
|
168
|
-
f"Invalid --definition path: {definition} does not exist.", err=True
|
|
169
|
-
)
|
|
170
|
-
raise SystemExit(1)
|
|
171
|
-
except OSError as exc:
|
|
172
|
-
click.echo(f"Invalid --definition path: {definition} ({exc})", err=True)
|
|
173
|
-
raise SystemExit(1) from exc
|
|
174
|
-
|
|
175
|
-
return source
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def _read_declarative_flow_file(path: Path) -> str:
|
|
179
|
-
try:
|
|
180
|
-
source = path.read_text(encoding="utf-8")
|
|
181
|
-
except (OSError, UnicodeError) as exc:
|
|
182
|
-
click.echo(
|
|
183
|
-
f"Unable to read --definition path {path}: {exc}",
|
|
184
|
-
err=True,
|
|
185
|
-
)
|
|
186
|
-
raise SystemExit(1) from exc
|
|
187
|
-
return source
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def _parse_declarative_flow(
|
|
191
|
-
flow_definition_cls: type[Any], source: str, *, source_path: Path
|
|
192
|
-
) -> Any:
|
|
193
|
-
if _looks_like_json(source):
|
|
194
|
-
return flow_definition_cls.from_json(source, source_path=source_path)
|
|
195
|
-
|
|
196
|
-
return flow_definition_cls.from_yaml(source, source_path=source_path)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _looks_like_json(source: str) -> bool:
|
|
200
|
-
stripped = source.lstrip()
|
|
201
|
-
return stripped.startswith("{")
|
|
202
|
-
|
|
203
|
-
|
|
204
233
|
def _format_result(result: Any) -> str:
|
|
205
234
|
raw_result = getattr(result, "raw", result)
|
|
206
235
|
if isinstance(raw_result, str):
|