crewai-cli 1.14.8a0.dev20260618__tar.gz → 1.14.8a2__tar.gz

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