crewai-cli 1.15.2.dev20260708__tar.gz → 1.15.2.dev20260711__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.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/PKG-INFO +2 -2
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/pyproject.toml +1 -1
- crewai_cli-1.15.2.dev20260711/src/crewai_cli/__init__.py +1 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/crew_run_tui.py +234 -3
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/run_declarative_flow.py +176 -3
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_crew_run_tui.py +240 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_run_declarative_flow.py +211 -0
- crewai_cli-1.15.2.dev20260708/src/crewai_cli/__init__.py +0 -1
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/README.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/add_crew_to_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/constants.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/auth0.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/base_provider.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/entra_id.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/keycloak.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/okta.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/workos.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/token.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/utils.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/checkpoint_cli.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/checkpoint_tui.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/cli.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/command.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/config.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/constants.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/create_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/create_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/create_json_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/crew_chat.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/archive.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/validate.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/enterprise/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/enterprise/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/evaluate_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/experimental/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/experimental/skills/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/git.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/input_prompt.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/install_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/kickoff_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/memory_tui.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/model_catalog.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/organization/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/organization/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/plot_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/plus_api.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/provider.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/py.typed +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/remote_template/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/remote_template/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/replay_from_task.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/reset_memories_command.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/run_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/settings/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/settings/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/shared/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/shared/token_manager.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/task_outputs.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/AGENTS.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/README.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/config/agents.yaml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/config/tasks.yaml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/knowledge/user_preference.txt +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/skills/.gitkeep +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/tools/custom_tool.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/AGENTS.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/README.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/flow.yaml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/README.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/crews/content_crew/config/agents.yaml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/crews/content_crew/config/tasks.yaml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/crews/content_crew/content_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/skills/.gitkeep +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/tools/custom_tool.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/README.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/agent.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/agent_settings.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/crew.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/knowledge/user_preference.txt +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/task.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/README.md +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/src/{{folder_name}}/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/src/{{folder_name}}/tool.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/tools/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/train_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/triggers/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/triggers/main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/tui_picker.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/update_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/user_data.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/utils.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/version.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_auth0.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_entra_id.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_keycloak.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_okta.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_workos.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/test_auth_main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/test_utils.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/test_archive.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/test_deploy_main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/test_validate.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/enterprise/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/enterprise/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/experimental/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/experimental/skills/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/organization/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/organization/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/skills/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/skills/test_safe_extract.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_cli.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_click_compatibility.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_config.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_constants.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_create_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_create_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_crew_test.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_flow_commands.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_git.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_input_prompt.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_install_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_kickoff_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_model_catalog.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_plus_api.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_run_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_settings_command.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_token_manager.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_train_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_utils.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_version.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/tools/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/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.15.2.
|
|
3
|
+
Version: 1.15.2.dev20260711
|
|
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.15.2.
|
|
13
|
+
Requires-Dist: crewai-core==1.15.2.dev20260711
|
|
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.15.2.dev20260711"
|
{crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/crew_run_tui.py
RENAMED
|
@@ -568,12 +568,32 @@ FooterKey .footer-key--key {
|
|
|
568
568
|
self._default_inputs: dict[str, Any] | None = None
|
|
569
569
|
self._crew_result: Any = None
|
|
570
570
|
self._crew_json_path: Any = None
|
|
571
|
+
# Declarative-flow execution state. A flow renders per-method "STEPS"
|
|
572
|
+
# (built from flow method events) instead of the crew task list.
|
|
573
|
+
self._flow_inputs: dict[str, Any] | None = None
|
|
574
|
+
self._flow_method_types: dict[str, str] = {}
|
|
575
|
+
self._flow_steps: list[dict[str, Any]] = []
|
|
576
|
+
self._current_method: str | None = None
|
|
571
577
|
self._elapsed_frozen: float | None = None
|
|
572
578
|
self._want_deploy: bool = False
|
|
573
579
|
self._trace_url: str | None = None
|
|
574
580
|
self._consent_screen: TraceConsentScreen | None = None
|
|
575
581
|
self._telemetry: Telemetry | None = None
|
|
576
582
|
|
|
583
|
+
@property
|
|
584
|
+
def _is_flow_run(self) -> bool:
|
|
585
|
+
"""True for a non-conversational declarative flow (the STEPS view).
|
|
586
|
+
|
|
587
|
+
Gates every flow-specific rendering branch so crew and conversational
|
|
588
|
+
paths stay byte-identical.
|
|
589
|
+
"""
|
|
590
|
+
return self._flow is not None and not self._is_conversational
|
|
591
|
+
|
|
592
|
+
@property
|
|
593
|
+
def _run_noun(self) -> str:
|
|
594
|
+
"""User-facing noun for the run — 'flow' for a declarative flow, else 'crew'."""
|
|
595
|
+
return "flow" if self._is_flow_run else "crew"
|
|
596
|
+
|
|
577
597
|
# ── Layout ──────────────────────────────────────────────
|
|
578
598
|
|
|
579
599
|
def compose(self) -> ComposeResult:
|
|
@@ -602,6 +622,8 @@ FooterKey .footer-key--key {
|
|
|
602
622
|
self._tick_timer = self.set_interval(1 / 8, self._tick)
|
|
603
623
|
if self._is_conversational and self._flow:
|
|
604
624
|
self._start_conversational_session()
|
|
625
|
+
elif self._flow:
|
|
626
|
+
self._run_flow_worker()
|
|
605
627
|
elif self._crew:
|
|
606
628
|
self._run_crew_worker()
|
|
607
629
|
elif self._crew_json_path:
|
|
@@ -681,6 +703,49 @@ FooterKey .footer-key--key {
|
|
|
681
703
|
except Exception as e:
|
|
682
704
|
self.call_from_thread(self._on_crew_failed, str(e))
|
|
683
705
|
|
|
706
|
+
@work(thread=True, exclusive=True, group="flow")
|
|
707
|
+
def _run_flow_worker(self) -> None:
|
|
708
|
+
from crewai.events.listeners.tracing.utils import (
|
|
709
|
+
set_suppress_tracing_messages,
|
|
710
|
+
set_tui_mode,
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
set_tui_mode(True)
|
|
714
|
+
set_suppress_tracing_messages(True)
|
|
715
|
+
try:
|
|
716
|
+
# A declarative flow returns either a CrewOutput (has ``.raw``) or a
|
|
717
|
+
# bare value (str/dict/pydantic); _stringify_output handles both.
|
|
718
|
+
result = self._flow.kickoff(inputs=self._flow_inputs)
|
|
719
|
+
output = self._stringify_output(result)
|
|
720
|
+
with self._lock:
|
|
721
|
+
self._crew_result = result
|
|
722
|
+
self.call_from_thread(self._on_crew_done, output)
|
|
723
|
+
except Exception as e:
|
|
724
|
+
self.call_from_thread(self._on_crew_failed, str(e))
|
|
725
|
+
|
|
726
|
+
def _set_flow_step_status(self, name: str, status: str) -> None:
|
|
727
|
+
"""Update a flow method step's status. Caller must hold ``self._lock``."""
|
|
728
|
+
for step in self._flow_steps:
|
|
729
|
+
if step["name"] == name:
|
|
730
|
+
step["status"] = status
|
|
731
|
+
return
|
|
732
|
+
|
|
733
|
+
def _clear_current_method(self, finished_name: str) -> None:
|
|
734
|
+
"""Drop the header's active method once it ends. Caller holds the lock.
|
|
735
|
+
|
|
736
|
+
Falls back to another still-active step (methods can overlap) so the
|
|
737
|
+
header never keeps spinning a method the STEPS list already shows as
|
|
738
|
+
done or failed.
|
|
739
|
+
"""
|
|
740
|
+
if self._current_method != finished_name:
|
|
741
|
+
return
|
|
742
|
+
self._current_method = next(
|
|
743
|
+
(s["name"] for s in self._flow_steps if s["status"] == "active"), None
|
|
744
|
+
)
|
|
745
|
+
# The active method changed; drop its agent so the header doesn't show a
|
|
746
|
+
# stale agent until the next method's agent event arrives.
|
|
747
|
+
self._current_agent = ""
|
|
748
|
+
|
|
684
749
|
def _on_crew_done(self, output: str | None) -> None:
|
|
685
750
|
with self._lock:
|
|
686
751
|
self._status = "completed"
|
|
@@ -694,13 +759,18 @@ FooterKey .footer-key--key {
|
|
|
694
759
|
for k in self._task_statuses:
|
|
695
760
|
if self._task_statuses[k] == "active":
|
|
696
761
|
self._task_statuses[k] = "done"
|
|
762
|
+
for step in self._flow_steps:
|
|
763
|
+
if step["status"] == "active":
|
|
764
|
+
step["status"] = "done"
|
|
697
765
|
now = time.time()
|
|
698
766
|
for entry in self._log_entries:
|
|
699
767
|
if entry["status"] == "running":
|
|
700
768
|
if entry["tool_name"] == "memory_save":
|
|
701
769
|
continue
|
|
702
770
|
entry["status"] = "timeout"
|
|
703
|
-
entry["error"] =
|
|
771
|
+
entry["error"] = (
|
|
772
|
+
f"No result received before {self._run_noun} completed"
|
|
773
|
+
)
|
|
704
774
|
entry["duration"] = now - entry["start_time"]
|
|
705
775
|
try:
|
|
706
776
|
from crewai.events.listeners.tracing.trace_listener import (
|
|
@@ -739,13 +809,18 @@ FooterKey .footer-key--key {
|
|
|
739
809
|
self._is_streaming = False
|
|
740
810
|
self._current_step = None
|
|
741
811
|
self._elapsed_frozen = time.time() - self._start_time
|
|
812
|
+
for step in self._flow_steps:
|
|
813
|
+
if step["status"] == "active":
|
|
814
|
+
step["status"] = "failed"
|
|
742
815
|
now = time.time()
|
|
743
816
|
for entry in self._log_entries:
|
|
744
817
|
if entry["status"] == "running":
|
|
745
818
|
if entry["tool_name"] == "memory_save":
|
|
746
819
|
continue
|
|
747
820
|
entry["status"] = "error"
|
|
748
|
-
entry["error"] =
|
|
821
|
+
entry["error"] = (
|
|
822
|
+
f"No result received before {self._run_noun} failed"
|
|
823
|
+
)
|
|
749
824
|
entry["duration"] = now - entry["start_time"]
|
|
750
825
|
self._tick()
|
|
751
826
|
self.call_later(self._focus_activity_log)
|
|
@@ -1156,6 +1231,45 @@ FooterKey .footer-key--key {
|
|
|
1156
1231
|
widget.update(t)
|
|
1157
1232
|
return
|
|
1158
1233
|
|
|
1234
|
+
if self._is_flow_run:
|
|
1235
|
+
t.append(" STEPS\n", style=f"bold {_C_PRIMARY}")
|
|
1236
|
+
t.append("\n")
|
|
1237
|
+
if not self._flow_steps:
|
|
1238
|
+
t.append(" ○ waiting…\n", style=_C_DIM)
|
|
1239
|
+
for step in self._flow_steps:
|
|
1240
|
+
name = step["name"]
|
|
1241
|
+
max_name = sidebar_width - 6
|
|
1242
|
+
if len(name) > max_name:
|
|
1243
|
+
name = name[: max_name - 1] + "…"
|
|
1244
|
+
status = step.get("status", "pending")
|
|
1245
|
+
if status == "done":
|
|
1246
|
+
t.append(" ✔ ", style=_C_GREEN)
|
|
1247
|
+
t.append(name, style=_C_DIM)
|
|
1248
|
+
elif status == "active":
|
|
1249
|
+
t.append(f" {self._spinner()} ", style=_C_PRIMARY)
|
|
1250
|
+
t.append(name, style=f"bold {_C_TEXT}")
|
|
1251
|
+
elif status == "failed":
|
|
1252
|
+
t.append(" ✘ ", style=_C_RED)
|
|
1253
|
+
t.append(name, style=_C_RED)
|
|
1254
|
+
elif status == "paused":
|
|
1255
|
+
t.append(" ⏸ ", style=_C_TEAL)
|
|
1256
|
+
t.append(name, style=_C_TEAL)
|
|
1257
|
+
else:
|
|
1258
|
+
t.append(" ○ ", style=_C_DIM)
|
|
1259
|
+
t.append(name, style=_C_DIM)
|
|
1260
|
+
if step.get("call_type"):
|
|
1261
|
+
t.append(f" ({step['call_type']})", style=_C_DIM)
|
|
1262
|
+
t.append("\n")
|
|
1263
|
+
|
|
1264
|
+
t.append("\n")
|
|
1265
|
+
t.append(" TOKENS\n", style=f"bold {_C_PRIMARY}")
|
|
1266
|
+
t.append("\n")
|
|
1267
|
+
out = self._output_tokens + self._live_out_tokens
|
|
1268
|
+
t.append(f" ↑ {self._input_tokens:,}\n", style=_C_DIM)
|
|
1269
|
+
t.append(f" ↓ {out:,}\n", style=_C_DIM)
|
|
1270
|
+
widget.update(t)
|
|
1271
|
+
return
|
|
1272
|
+
|
|
1159
1273
|
t.append(" TASKS\n", style=f"bold {_C_PRIMARY}")
|
|
1160
1274
|
t.append("\n")
|
|
1161
1275
|
|
|
@@ -1225,6 +1339,55 @@ FooterKey .footer-key--key {
|
|
|
1225
1339
|
widget.update(t)
|
|
1226
1340
|
return
|
|
1227
1341
|
|
|
1342
|
+
if self._is_flow_run:
|
|
1343
|
+
if self._status == "completed":
|
|
1344
|
+
elapsed = self._elapsed_frozen or (time.time() - self._start_time)
|
|
1345
|
+
t.append("✔ ", style=f"bold {_C_GREEN}")
|
|
1346
|
+
t.append("Flow complete", style=f"bold {_C_GREEN}")
|
|
1347
|
+
t.append(f" {elapsed:.1f}s", style=_C_DIM)
|
|
1348
|
+
out = self._output_tokens + self._live_out_tokens
|
|
1349
|
+
parts = []
|
|
1350
|
+
if self._input_tokens:
|
|
1351
|
+
parts.append(f"↑{self._input_tokens:,}")
|
|
1352
|
+
if out:
|
|
1353
|
+
parts.append(f"↓{out:,}")
|
|
1354
|
+
if parts:
|
|
1355
|
+
t.append(f" {' '.join(parts)} tokens", style=_C_DIM)
|
|
1356
|
+
elif self._status == "failed":
|
|
1357
|
+
t.append("✘ ", style=f"bold {_C_RED}")
|
|
1358
|
+
t.append("Failed", style=f"bold {_C_RED}")
|
|
1359
|
+
if self._error:
|
|
1360
|
+
t.append(f"\n{self._error[:120]}", style=_C_RED)
|
|
1361
|
+
elif self._current_method:
|
|
1362
|
+
paused = any(
|
|
1363
|
+
s["name"] == self._current_method and s["status"] == "paused"
|
|
1364
|
+
for s in self._flow_steps
|
|
1365
|
+
)
|
|
1366
|
+
if paused:
|
|
1367
|
+
t.append("⏸ ", style=_C_TEAL)
|
|
1368
|
+
t.append(self._current_method, style=f"bold {_C_TEAL}")
|
|
1369
|
+
else:
|
|
1370
|
+
t.append(f"{self._spinner()} ", style=_C_PRIMARY)
|
|
1371
|
+
t.append(self._current_method, style=f"bold {_C_PRIMARY}")
|
|
1372
|
+
call_type = self._flow_method_types.get(self._current_method)
|
|
1373
|
+
if call_type:
|
|
1374
|
+
t.append(f" ({call_type})", style=_C_DIM)
|
|
1375
|
+
if paused:
|
|
1376
|
+
t.append(" waiting for feedback", style=_C_DIM)
|
|
1377
|
+
elif self._current_agent:
|
|
1378
|
+
t.append("\nAgent: ", style=_C_DIM)
|
|
1379
|
+
t.append(self._current_agent, style=f"bold {_C_TEXT}")
|
|
1380
|
+
else:
|
|
1381
|
+
t.append(f"{self._spinner()} ", style=_C_PRIMARY)
|
|
1382
|
+
# "Working…" once a step has run (between/after methods);
|
|
1383
|
+
# "Starting flow…" only before the first method.
|
|
1384
|
+
t.append(
|
|
1385
|
+
"Working…" if self._flow_steps else "Starting flow…",
|
|
1386
|
+
style=_C_DIM,
|
|
1387
|
+
)
|
|
1388
|
+
widget.update(t)
|
|
1389
|
+
return
|
|
1390
|
+
|
|
1228
1391
|
if self._status == "completed":
|
|
1229
1392
|
elapsed = self._elapsed_frozen or (time.time() - self._start_time)
|
|
1230
1393
|
t.append("✔ ", style=f"bold {_C_GREEN}")
|
|
@@ -1839,6 +2002,13 @@ FooterKey .footer-key--key {
|
|
|
1839
2002
|
def _subscribe(self) -> None:
|
|
1840
2003
|
from crewai.events.event_bus import crewai_event_bus
|
|
1841
2004
|
from crewai.events.types.crew_events import CrewKickoffStartedEvent
|
|
2005
|
+
from crewai.events.types.flow_events import (
|
|
2006
|
+
FlowStartedEvent,
|
|
2007
|
+
MethodExecutionFailedEvent,
|
|
2008
|
+
MethodExecutionFinishedEvent,
|
|
2009
|
+
MethodExecutionPausedEvent,
|
|
2010
|
+
MethodExecutionStartedEvent,
|
|
2011
|
+
)
|
|
1842
2012
|
from crewai.events.types.llm_events import (
|
|
1843
2013
|
LLMCallCompletedEvent,
|
|
1844
2014
|
LLMCallStartedEvent,
|
|
@@ -1872,13 +2042,74 @@ FooterKey .footer-key--key {
|
|
|
1872
2042
|
@crewai_event_bus.on(CrewKickoffStartedEvent)
|
|
1873
2043
|
def on_crew_started(source: Any, event: CrewKickoffStartedEvent) -> None:
|
|
1874
2044
|
with self._lock:
|
|
1875
|
-
|
|
2045
|
+
# In flow mode the app is named for the flow; a nested crew's
|
|
2046
|
+
# kickoff (a `call: crew` step) must not rename it.
|
|
2047
|
+
if event.crew_name and not self._is_flow_run:
|
|
1876
2048
|
self._crew_name = event.crew_name
|
|
1877
2049
|
self.title = f"CrewAI — {event.crew_name}"
|
|
1878
2050
|
self._status = "working"
|
|
1879
2051
|
|
|
1880
2052
|
self._register_handler(CrewKickoffStartedEvent, on_crew_started)
|
|
1881
2053
|
|
|
2054
|
+
# ── Declarative-flow method events → STEPS panel ────────
|
|
2055
|
+
@crewai_event_bus.on(FlowStartedEvent)
|
|
2056
|
+
def on_flow_started(source: Any, event: FlowStartedEvent) -> None:
|
|
2057
|
+
with self._lock:
|
|
2058
|
+
self._status = "working"
|
|
2059
|
+
|
|
2060
|
+
self._register_handler(FlowStartedEvent, on_flow_started)
|
|
2061
|
+
|
|
2062
|
+
@crewai_event_bus.on(MethodExecutionStartedEvent)
|
|
2063
|
+
def on_method_started(source: Any, event: MethodExecutionStartedEvent) -> None:
|
|
2064
|
+
with self._lock:
|
|
2065
|
+
name = event.method_name
|
|
2066
|
+
self._current_method = name
|
|
2067
|
+
# Agent is per-method; clear it so the header doesn't show the
|
|
2068
|
+
# previous method's agent until a new agent event arrives.
|
|
2069
|
+
self._current_agent = ""
|
|
2070
|
+
for step in self._flow_steps:
|
|
2071
|
+
if step["name"] == name:
|
|
2072
|
+
step["status"] = "active"
|
|
2073
|
+
break
|
|
2074
|
+
else:
|
|
2075
|
+
self._flow_steps.append(
|
|
2076
|
+
{
|
|
2077
|
+
"name": name,
|
|
2078
|
+
"call_type": self._flow_method_types.get(name),
|
|
2079
|
+
"status": "active",
|
|
2080
|
+
}
|
|
2081
|
+
)
|
|
2082
|
+
|
|
2083
|
+
self._register_handler(MethodExecutionStartedEvent, on_method_started)
|
|
2084
|
+
|
|
2085
|
+
@crewai_event_bus.on(MethodExecutionFinishedEvent)
|
|
2086
|
+
def on_method_finished(
|
|
2087
|
+
source: Any, event: MethodExecutionFinishedEvent
|
|
2088
|
+
) -> None:
|
|
2089
|
+
with self._lock:
|
|
2090
|
+
self._set_flow_step_status(event.method_name, "done")
|
|
2091
|
+
self._clear_current_method(event.method_name)
|
|
2092
|
+
|
|
2093
|
+
self._register_handler(MethodExecutionFinishedEvent, on_method_finished)
|
|
2094
|
+
|
|
2095
|
+
@crewai_event_bus.on(MethodExecutionFailedEvent)
|
|
2096
|
+
def on_method_failed(source: Any, event: MethodExecutionFailedEvent) -> None:
|
|
2097
|
+
with self._lock:
|
|
2098
|
+
self._set_flow_step_status(event.method_name, "failed")
|
|
2099
|
+
self._clear_current_method(event.method_name)
|
|
2100
|
+
|
|
2101
|
+
self._register_handler(MethodExecutionFailedEvent, on_method_failed)
|
|
2102
|
+
|
|
2103
|
+
@crewai_event_bus.on(MethodExecutionPausedEvent)
|
|
2104
|
+
def on_method_paused(source: Any, event: MethodExecutionPausedEvent) -> None:
|
|
2105
|
+
# A @human_feedback method paused; flow status panels are suppressed
|
|
2106
|
+
# in TUI mode, so surface the wait in STEPS/header instead of leaving
|
|
2107
|
+
# a spinner. _current_method stays pointed at it.
|
|
2108
|
+
with self._lock:
|
|
2109
|
+
self._set_flow_step_status(event.method_name, "paused")
|
|
2110
|
+
|
|
2111
|
+
self._register_handler(MethodExecutionPausedEvent, on_method_paused)
|
|
2112
|
+
|
|
1882
2113
|
@crewai_event_bus.on(TaskStartedEvent)
|
|
1883
2114
|
def on_task_started(source: Any, event: TaskStartedEvent) -> None:
|
|
1884
2115
|
with self._lock:
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import logging
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
import subprocess
|
|
6
|
-
from typing import Any
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
7
8
|
|
|
8
9
|
import click
|
|
9
10
|
from crewai_core.project import ProjectDefinitionError, configured_project_definition
|
|
@@ -18,6 +19,13 @@ from crewai_cli.input_prompt import (
|
|
|
18
19
|
from crewai_cli.utils import build_env_with_all_tool_credentials
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from crewai.flow.flow import Flow
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
21
29
|
def run_declarative_flow_in_project_env(
|
|
22
30
|
definition: str | Path, inputs: str | None = None
|
|
23
31
|
) -> None:
|
|
@@ -66,17 +74,182 @@ def run_declarative_flow(definition: str | Path, inputs: str | None = None) -> N
|
|
|
66
74
|
flow = load_declarative_flow(definition)
|
|
67
75
|
resolved_inputs = _resolve_flow_inputs(flow, provided)
|
|
68
76
|
|
|
77
|
+
# The TUI is the interactive default. Headless contexts run directly on the
|
|
78
|
+
# terminal: deploy/CREWAI_DMN, piped output, CI — anything without an
|
|
79
|
+
# interactive TTY. is_interactive() already folds in the CREWAI_DMN check.
|
|
80
|
+
# Human-feedback flows also run on the terminal: their methods collect input
|
|
81
|
+
# via the flow runtime's blocking input()/Rich prompts (and async feedback
|
|
82
|
+
# returns a pending marker rather than completing), neither of which the
|
|
83
|
+
# Textual TUI can handle correctly.
|
|
84
|
+
if is_interactive() and not _flow_uses_human_feedback(flow):
|
|
85
|
+
_run_declarative_flow_tui(flow, resolved_inputs or None)
|
|
86
|
+
return
|
|
87
|
+
|
|
69
88
|
try:
|
|
70
89
|
result = flow.kickoff(inputs=resolved_inputs or None)
|
|
71
90
|
except Exception as exc:
|
|
72
91
|
click.echo(
|
|
73
|
-
f"An error occurred while running the declarative flow: {exc}",
|
|
92
|
+
f"An error occurred while running the declarative flow: {exc}",
|
|
93
|
+
err=True,
|
|
74
94
|
)
|
|
75
95
|
raise SystemExit(1) from exc
|
|
76
|
-
|
|
77
96
|
click.echo(_format_result(result))
|
|
78
97
|
|
|
79
98
|
|
|
99
|
+
def _run_declarative_flow_tui(
|
|
100
|
+
flow: Flow[Any], resolved_inputs: dict[str, Any] | None
|
|
101
|
+
) -> Any:
|
|
102
|
+
"""Run a declarative flow on the CrewAI TUI (the interactive default).
|
|
103
|
+
|
|
104
|
+
Mirrors the declarative-crew TUI contract (``run_crew._run_json_crew``):
|
|
105
|
+
a failed flow exits non-zero, a user quit ends the process so in-flight LLM
|
|
106
|
+
work stops, and choosing Deploy chains into the deploy command.
|
|
107
|
+
"""
|
|
108
|
+
import os
|
|
109
|
+
import sys
|
|
110
|
+
|
|
111
|
+
from crewai.events.event_listener import EventListener
|
|
112
|
+
|
|
113
|
+
from crewai_cli.crew_run_tui import CrewRunApp
|
|
114
|
+
|
|
115
|
+
# The flow runtime (unlike a Crew constructor) doesn't create the event
|
|
116
|
+
# listener, and the TUI's trace/telemetry features depend on it.
|
|
117
|
+
EventListener()
|
|
118
|
+
|
|
119
|
+
# The STEPS panel and header are driven by flow method events. A flow may
|
|
120
|
+
# declare ``config.suppress_flow_events`` (a headless/production
|
|
121
|
+
# optimization) which would leave STEPS stuck on "waiting…" here — so force
|
|
122
|
+
# emission on for the interactive TUI run. The headless path never reaches
|
|
123
|
+
# this and keeps the flow's declared setting.
|
|
124
|
+
try:
|
|
125
|
+
flow.suppress_flow_events = False
|
|
126
|
+
except Exception:
|
|
127
|
+
logger.debug(
|
|
128
|
+
"Could not disable suppress_flow_events for the flow TUI", exc_info=True
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
app = CrewRunApp(crew_name=flow.name or type(flow).__name__)
|
|
132
|
+
app._flow = flow
|
|
133
|
+
app._flow_inputs = resolved_inputs
|
|
134
|
+
app._flow_method_types = _flow_method_types(flow)
|
|
135
|
+
|
|
136
|
+
app.run()
|
|
137
|
+
|
|
138
|
+
_print_flow_post_tui_summary(app)
|
|
139
|
+
|
|
140
|
+
if app._status == "failed":
|
|
141
|
+
raise SystemExit(1)
|
|
142
|
+
|
|
143
|
+
if app._status not in ("completed", "failed"):
|
|
144
|
+
# User quit mid-run. kickoff runs in a thread worker that cannot be
|
|
145
|
+
# force-cancelled, so end the process to stop in-flight LLM and tool
|
|
146
|
+
# work instead of letting it burn tokens in the background.
|
|
147
|
+
click.secho("\n Run cancelled.", fg="yellow")
|
|
148
|
+
sys.stdout.flush()
|
|
149
|
+
os._exit(130)
|
|
150
|
+
|
|
151
|
+
if getattr(app, "_want_deploy", False):
|
|
152
|
+
from crewai_cli.run_crew import _chain_deploy
|
|
153
|
+
|
|
154
|
+
_chain_deploy()
|
|
155
|
+
|
|
156
|
+
return app._crew_result
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _flow_uses_human_feedback(flow: Flow[Any]) -> bool:
|
|
160
|
+
"""True if any declarative method declares ``@human_feedback``.
|
|
161
|
+
|
|
162
|
+
Such flows need the flow runtime's interactive stdin / Rich prompts, which
|
|
163
|
+
don't compose with Textual — so they run on the terminal, not the TUI.
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
return any(
|
|
167
|
+
method.human_feedback is not None
|
|
168
|
+
for method in flow._definition.methods.values()
|
|
169
|
+
)
|
|
170
|
+
except Exception:
|
|
171
|
+
logger.debug("Could not inspect flow for human feedback", exc_info=True)
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _flow_method_types(flow: Flow[Any]) -> dict[str, str]:
|
|
176
|
+
"""Map each declarative method name to its ``call`` type (crew/agent/…).
|
|
177
|
+
|
|
178
|
+
Best-effort: the STEPS panel shows this as a dim label. Method events don't
|
|
179
|
+
carry the call type, so it's read from the flow definition up front.
|
|
180
|
+
"""
|
|
181
|
+
method_types: dict[str, str] = {}
|
|
182
|
+
try:
|
|
183
|
+
for name, method_definition in flow._definition.methods.items():
|
|
184
|
+
method_types[name] = method_definition.do.call
|
|
185
|
+
except Exception:
|
|
186
|
+
logger.debug("Could not derive flow method types", exc_info=True)
|
|
187
|
+
return method_types
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _print_flow_post_tui_summary(app: Any) -> None:
|
|
191
|
+
"""Print a compact result panel after the flow TUI exits."""
|
|
192
|
+
import time
|
|
193
|
+
|
|
194
|
+
from rich.console import Console
|
|
195
|
+
from rich.markdown import Markdown
|
|
196
|
+
from rich.padding import Padding
|
|
197
|
+
from rich.panel import Panel
|
|
198
|
+
from rich.text import Text
|
|
199
|
+
|
|
200
|
+
console = Console()
|
|
201
|
+
elapsed = (app._elapsed_frozen or (time.time() - app._start_time)) or 0.0
|
|
202
|
+
|
|
203
|
+
out_tokens = app._output_tokens + app._live_out_tokens
|
|
204
|
+
token_parts = []
|
|
205
|
+
if app._input_tokens:
|
|
206
|
+
token_parts.append(f"↑{app._input_tokens:,}")
|
|
207
|
+
if out_tokens:
|
|
208
|
+
token_parts.append(f"↓{out_tokens:,}")
|
|
209
|
+
token_str = " ".join(token_parts)
|
|
210
|
+
if token_str:
|
|
211
|
+
token_str += " tokens"
|
|
212
|
+
|
|
213
|
+
crewai_red = "#FF5A50"
|
|
214
|
+
crewai_teal = "#1F7982"
|
|
215
|
+
|
|
216
|
+
if app._status == "completed":
|
|
217
|
+
summary = Text()
|
|
218
|
+
summary.append(" ✔ Flow complete", style=f"bold {crewai_teal}")
|
|
219
|
+
summary.append(f" in {elapsed:.1f}s", style="dim")
|
|
220
|
+
if token_str:
|
|
221
|
+
summary.append(f" {token_str}", style="dim")
|
|
222
|
+
console.print(
|
|
223
|
+
Panel(
|
|
224
|
+
summary,
|
|
225
|
+
title=f" {app._crew_name} ",
|
|
226
|
+
title_align="left",
|
|
227
|
+
border_style=crewai_teal,
|
|
228
|
+
padding=(0, 1),
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
if app._final_output:
|
|
232
|
+
console.print()
|
|
233
|
+
console.print(Text(" Final Result", style=f"bold {crewai_teal}"))
|
|
234
|
+
console.print()
|
|
235
|
+
console.print(Padding(Markdown(app._final_output), (0, 2)))
|
|
236
|
+
elif app._status == "failed":
|
|
237
|
+
content = Text()
|
|
238
|
+
content.append(" ✘ Failed", style=f"bold {crewai_red}")
|
|
239
|
+
content.append(f" after {elapsed:.1f}s\n", style="dim")
|
|
240
|
+
if app._error:
|
|
241
|
+
content.append(f"\n {app._error}\n", style=crewai_red)
|
|
242
|
+
console.print(
|
|
243
|
+
Panel(
|
|
244
|
+
content,
|
|
245
|
+
title=f" {app._crew_name} ",
|
|
246
|
+
title_align="left",
|
|
247
|
+
border_style=crewai_red,
|
|
248
|
+
padding=(0, 1),
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
80
253
|
def _resolve_flow_inputs(flow: Any, provided: dict[str, Any]) -> dict[str, Any]:
|
|
81
254
|
"""Resolve kickoff inputs from the flow's state schema.
|
|
82
255
|
|