crewai-cli 1.15.2.dev20260710__tar.gz → 1.15.2.dev20260714__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.dev20260710 → crewai_cli-1.15.2.dev20260714}/PKG-INFO +2 -2
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/pyproject.toml +1 -1
- crewai_cli-1.15.2.dev20260714/src/crewai_cli/__init__.py +1 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/crew_run_tui.py +234 -3
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/run_declarative_flow.py +176 -3
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/declarative_flow/AGENTS.md +4 -10
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_create_flow.py +3 -1
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_crew_run_tui.py +240 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_run_declarative_flow.py +211 -0
- crewai_cli-1.15.2.dev20260710/src/crewai_cli/__init__.py +0 -1
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/README.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/add_crew_to_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/constants.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/auth0.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/base_provider.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/entra_id.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/keycloak.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/okta.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/providers/workos.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/token.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/authentication/utils.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/checkpoint_cli.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/checkpoint_tui.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/cli.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/command.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/config.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/constants.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/create_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/create_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/create_json_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/crew_chat.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/deploy/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/deploy/archive.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/deploy/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/deploy/validate.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/enterprise/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/enterprise/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/evaluate_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/experimental/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/experimental/skills/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/git.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/input_prompt.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/install_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/kickoff_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/memory_tui.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/model_catalog.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/organization/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/organization/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/plot_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/plus_api.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/provider.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/py.typed +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/remote_template/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/remote_template/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/replay_from_task.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/reset_memories_command.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/run_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/settings/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/settings/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/shared/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/shared/token_manager.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/task_outputs.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/AGENTS.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/README.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/config/agents.yaml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/config/tasks.yaml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/knowledge/user_preference.txt +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/skills/.gitkeep +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/crew/tools/custom_tool.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/declarative_flow/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/declarative_flow/README.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/declarative_flow/flow.yaml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/declarative_flow/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/README.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/crews/content_crew/config/agents.yaml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/crews/content_crew/config/tasks.yaml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/crews/content_crew/content_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/skills/.gitkeep +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/flow/tools/custom_tool.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/README.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/agent.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/agent_settings.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/crew.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/knowledge/user_preference.txt +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/json_crew/task.jsonc +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/tool/.gitignore +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/tool/README.md +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/tool/pyproject.toml +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/tool/src/{{folder_name}}/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/templates/tool/src/{{folder_name}}/tool.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/tools/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/train_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/triggers/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/triggers/main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/tui_picker.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/update_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/user_data.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/utils.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/src/crewai_cli/version.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/providers/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/providers/test_auth0.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/providers/test_entra_id.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/providers/test_keycloak.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/providers/test_okta.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/providers/test_workos.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/test_auth_main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/authentication/test_utils.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/deploy/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/deploy/test_archive.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/deploy/test_deploy_main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/deploy/test_validate.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/enterprise/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/enterprise/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/experimental/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/experimental/skills/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/experimental/skills/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/organization/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/organization/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/skills/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/skills/test_safe_extract.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_cli.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_click_compatibility.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_config.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_constants.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_create_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_crew_test.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_flow_commands.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_git.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_input_prompt.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_install_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_kickoff_flow.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_model_catalog.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_plus_api.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_run_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_settings_command.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_token_manager.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_train_crew.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_utils.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/test_version.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/tools/__init__.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/tests/tools/test_main.py +0 -0
- {crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/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.dev20260714
|
|
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.dev20260714
|
|
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.dev20260714"
|
{crewai_cli-1.15.2.dev20260710 → crewai_cli-1.15.2.dev20260714}/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
|
|
|
@@ -59,9 +59,9 @@ Use these expression forms correctly:
|
|
|
59
59
|
- Raw CEL: use in `expr`. Do not wrap raw CEL in `${...}`.
|
|
60
60
|
- Use `${...}` inside action mapping strings to read Flow data with CEL. Example value: `Ticket: ${state.ticket_id}`.
|
|
61
61
|
- Use `state` for input data. Use `outputs.step_name` for a completed method result.
|
|
62
|
+
- In action mapping strings, keep literal text outside `${...}` and interpolate each Flow value directly. Write `Ticket: ${state.ticket_id}`; do not assemble the string with CEL `+`.
|
|
62
63
|
- If a value is only one `${...}` expression, the result keeps its type. Use this for numbers, booleans, objects, and lists.
|
|
63
64
|
- If the string has other text, the final value is text. Non-text values become JSON. `null` becomes empty text.
|
|
64
|
-
- Use `text(root, "path", "default")` for values that may be missing or null. The default is optional and is `""`.
|
|
65
65
|
|
|
66
66
|
Expression examples:
|
|
67
67
|
|
|
@@ -78,12 +78,6 @@ domains: "${state.domains}"
|
|
|
78
78
|
limit: "${state.limit}"
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
Use a default for missing text:
|
|
82
|
-
|
|
83
|
-
```yaml
|
|
84
|
-
input: "Ticket ${text(state, \"ticket.id\", \"unknown\")}"
|
|
85
|
-
```
|
|
86
|
-
|
|
87
81
|
- Crew text: use `{name}` placeholders from crew inputs. Example: `Research {topic}`.
|
|
88
82
|
- Crew inputs become prompt text only when agent or task text references matching `{name}` placeholders.
|
|
89
83
|
- Passing an input that is not referenced by any `{name}` placeholder does not ground the crew. If the crew needs a field, put that placeholder in an agent `goal`, task `description`, or task `expected_output`.
|
|
@@ -111,6 +105,7 @@ Dynamic value rules:
|
|
|
111
105
|
- Do not use fields outside the declaration schema.
|
|
112
106
|
- Do not put more than one action under a method's `do`.
|
|
113
107
|
- Do not make `do` a list.
|
|
108
|
+
- Do not use CEL `+` to build text in action mappings. Keep the text literal and insert each dynamic value with `${...}`.
|
|
114
109
|
- Do not reference `outputs.some_method` before `some_method` can run.
|
|
115
110
|
- Do not set a method's `listen` to its own method name.
|
|
116
111
|
- Do not use the same string for an emitted event and a method name unless the user asks for it.
|
|
@@ -246,7 +241,7 @@ Shape:
|
|
|
246
241
|
Fields:
|
|
247
242
|
- `call` (required): must be `crew`. Action discriminator. Use crew to run an inline Crew definition. Example: `crew`
|
|
248
243
|
- `with` (required): inline crew definition. Inline Crew definition to load and execute for this action. Example: `{"agents": {"researcher": {"backstory": "Knows the domain.", "goal": "Research {topic}", "role": "Researcher"}}, "name": "inline_research", "tasks": [{"agent": "researcher", "description": "Research {topic}", "expected_output": "Findings about {topic}", "name": "research_task"}]}`
|
|
249
|
-
- `inputs` (optional): map of string to expression data | null; default `null`.
|
|
244
|
+
- `inputs` (optional): map of string to expression data | null; default `null`. Runtime inputs passed to the Crew. Insert Flow values with `${...}` and reference each input as `{name}` in agent or task text. Example: `{"topic": "${state.topic}"}`
|
|
250
245
|
|
|
251
246
|
#### Crew Definition (`methods.<name>.do[call=crew].with`)
|
|
252
247
|
|
|
@@ -311,7 +306,7 @@ Fields:
|
|
|
311
306
|
- `tools` (optional): list[string | map of string to any] | null; default `null`. Tool refs or serialized tool definitions available to this agent. String refs can use CrewAI tool names, `custom:<name>`, or fully qualified `module:Class` references. Example: `["crewai_tools:SerperDevTool", "custom:file_read"]`
|
|
312
307
|
- `apps` (optional): list[string] | null; default `null`. Platform apps available to this agent. Can contain app names such as `gmail` or app/action refs such as `gmail/send_email`. Example: `["gmail", "slack/send_message"]`
|
|
313
308
|
- `mcps` (optional): list[string | map of string to any] | null; default `null`. MCP server refs or serialized MCP server configs available to this agent. String refs can use HTTPS URLs, connected MCP integration slugs, or refs with a `#tool_name` suffix for specific tools. Example: `["https://api.weather.com/mcp#get_current_weather", "snowflake", "stripe#list_invoices", {"cache_tools_list": true, "headers": {"Authorization": "Bearer your_token"}, "streamable": true, "url": "https://api.example.com/mcp"}]`
|
|
314
|
-
- `input` (required): string.
|
|
309
|
+
- `input` (required): string. Agent prompt template. Insert Flow values with `${...}`, for example `Ticket: ${state.ticket_id}`. Example: `${state.ticket.body}`
|
|
315
310
|
|
|
316
311
|
#### LLM Definition
|
|
317
312
|
|
|
@@ -349,4 +344,3 @@ Fields:
|
|
|
349
344
|
- Crew action-level `inputs` are the Crew kickoff inputs; use CEL-wrapped strings there for runtime values.
|
|
350
345
|
- Crew agent/task interpolation uses `{name}` placeholders from evaluated crew inputs.
|
|
351
346
|
- Agent `with.input` must be text. Use `${outputs.method_name.raw}` or a text field like `${outputs.method_name.json_dict.summary}`.
|
|
352
|
-
|
|
@@ -29,7 +29,9 @@ def test_create_flow_declarative_project_can_run(
|
|
|
29
29
|
agents_md = (project_root / "AGENTS.md").read_text(encoding="utf-8")
|
|
30
30
|
assert "CrewAI Flow declaration" in agents_md
|
|
31
31
|
assert "schema: crewai.flow/v1" in agents_md
|
|
32
|
-
assert
|
|
32
|
+
assert "do not assemble the string with CEL `+`" in agents_md
|
|
33
|
+
assert "Agent prompt template. Insert Flow values with `${...}`" in agents_md
|
|
34
|
+
assert "Runtime inputs passed to the Crew" in agents_md
|
|
33
35
|
assert "call: expression" in agents_md
|
|
34
36
|
assert "call: tool" not in agents_md
|
|
35
37
|
assert "call: script" not in agents_md
|