agentcrew-ai 0.8.5__tar.gz → 0.8.6__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 (202) hide show
  1. agentcrew_ai-0.8.6/AgentCrew/__init__.py +1 -0
  2. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/task_manager.py +153 -29
  3. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/local_agent.py +8 -8
  4. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/command_execution/constants.py +2 -2
  5. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/command_execution/service.py +37 -83
  6. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/command_execution/tool.py +5 -7
  7. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/command_execution/types.py +3 -4
  8. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/diff_display.py +13 -13
  9. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/input_handler.py +2 -3
  10. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/llm/constants.py +24 -3
  11. {agentcrew_ai-0.8.5/agentcrew_ai.egg-info → agentcrew_ai-0.8.6}/PKG-INFO +1 -1
  12. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6/agentcrew_ai.egg-info}/PKG-INFO +1 -1
  13. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/agentcrew_ai.egg-info/SOURCES.txt +0 -1
  14. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/pyproject.toml +1 -1
  15. agentcrew_ai-0.8.5/AgentCrew/__init__.py +0 -1
  16. agentcrew_ai-0.8.5/AgentCrew/modules/command_execution/metric.py +0 -55
  17. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/app.py +0 -0
  18. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/assets/agentcrew_logo.png +0 -0
  19. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/main.py +0 -0
  20. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/main_docker.py +0 -0
  21. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/__init__.py +0 -0
  22. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/__init__.py +0 -0
  23. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/adapters.py +0 -0
  24. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/agent_cards.py +0 -0
  25. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/__init__.py +0 -0
  26. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/client/__init__.py +0 -0
  27. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/client/card_resolver.py +0 -0
  28. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/client/client.py +0 -0
  29. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/server/__init__.py +0 -0
  30. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/server/auth_middleware.py +0 -0
  31. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/server/task_manager.py +0 -0
  32. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/common/server/utils.py +0 -0
  33. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/errors.py +0 -0
  34. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/registry.py +0 -0
  35. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/a2a/server.py +0 -0
  36. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/__init__.py +0 -0
  37. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/base.py +0 -0
  38. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/example.py +0 -0
  39. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/manager.py +0 -0
  40. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/remote_agent.py +0 -0
  41. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/tools/__init__.py +0 -0
  42. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/tools/ask.py +0 -0
  43. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/tools/delegate.py +0 -0
  44. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/agents/tools/transfer.py +0 -0
  45. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/anthropic/__init__.py +0 -0
  46. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/anthropic/service.py +0 -0
  47. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/__init__.py +0 -0
  48. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/chrome_manager.py +0 -0
  49. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/element_extractor.py +0 -0
  50. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/click_element.js +0 -0
  51. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/draw_element_boxes.js +0 -0
  52. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/extract_clickable_elements.js +0 -0
  53. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/extract_elements_by_text.js +0 -0
  54. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/extract_input_elements.js +0 -0
  55. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/extract_scrollable_elements.js +0 -0
  56. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/filter_hidden_elements.js +0 -0
  57. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/focus_and_clear_element.js +0 -0
  58. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/remove_element_boxes.js +0 -0
  59. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/scroll_page.js +0 -0
  60. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js/trigger_input_events.js +0 -0
  61. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/js_loader.py +0 -0
  62. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/service.py +0 -0
  63. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/browser_automation/tool.py +0 -0
  64. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/__init__.py +0 -0
  65. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/consolidation.py +0 -0
  66. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/file_handler.py +0 -0
  67. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/history.py +0 -0
  68. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message/__init__.py +0 -0
  69. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message/base.py +0 -0
  70. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message/command_processor.py +0 -0
  71. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message/conversation.py +0 -0
  72. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message/handler.py +0 -0
  73. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message/tool_manager.py +0 -0
  74. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/chat/message_handler.py +0 -0
  75. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/clipboard/__init__.py +0 -0
  76. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/clipboard/service.py +0 -0
  77. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/clipboard/tool.py +0 -0
  78. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/code_analysis/__init__.py +0 -0
  79. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/code_analysis/service.py +0 -0
  80. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/code_analysis/tool.py +0 -0
  81. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/command_execution/__init__.py +0 -0
  82. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/config/__init__.py +0 -0
  83. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/config/config_management.py +0 -0
  84. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/__init__.py +0 -0
  85. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/command_handlers.py +0 -0
  86. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/completers.py +0 -0
  87. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/confirmation_handler.py +0 -0
  88. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/console_ui.py +0 -0
  89. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/constants.py +0 -0
  90. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/conversation_handler.py +0 -0
  91. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/display_handlers.py +0 -0
  92. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/tool_display.py +0 -0
  93. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/ui_effects.py +0 -0
  94. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/console/utils.py +0 -0
  95. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/custom_llm/__init__.py +0 -0
  96. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/custom_llm/copilot_response_service.py +0 -0
  97. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/custom_llm/deepinfra_service.py +0 -0
  98. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/custom_llm/github_copilot_service.py +0 -0
  99. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/custom_llm/service.py +0 -0
  100. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/file_editing/__init__.py +0 -0
  101. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/file_editing/safety_validator.py +0 -0
  102. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/file_editing/search_replace_engine.py +0 -0
  103. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/file_editing/service.py +0 -0
  104. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/file_editing/tool.py +0 -0
  105. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/file_editing/tree_sitter_checker.py +0 -0
  106. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/google/__init__.py +0 -0
  107. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/google/native_service.py +0 -0
  108. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/google/service.py +0 -0
  109. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/groq/__init__.py +0 -0
  110. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/groq/service.py +0 -0
  111. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/__init__.py +0 -0
  112. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/__init__.py +0 -0
  113. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/chat_components.py +0 -0
  114. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/command_handler.py +0 -0
  115. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/completers.py +0 -0
  116. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/conversation_components.py +0 -0
  117. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/input_components.py +0 -0
  118. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/keyboard_handler.py +0 -0
  119. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/menu_components.py +0 -0
  120. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/message_handlers.py +0 -0
  121. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/tool_handlers.py +0 -0
  122. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/components/ui_state_manager.py +0 -0
  123. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/qt_ui.py +0 -0
  124. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/README.md +0 -0
  125. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/__init__.py +0 -0
  126. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/atom_light.py +0 -0
  127. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/catppuccin.py +0 -0
  128. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/dracula.py +0 -0
  129. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/nord.py +0 -0
  130. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/saigontech.py +0 -0
  131. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/style_provider.py +0 -0
  132. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/themes/unicorn.py +0 -0
  133. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/utils/__init__.py +0 -0
  134. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/utils/macos_clipboard.py +0 -0
  135. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/utils/strings.py +0 -0
  136. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/utils/wins_clipboard.py +0 -0
  137. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/__init__.py +0 -0
  138. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/config_window.py +0 -0
  139. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/configs/__init__.py +0 -0
  140. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/configs/agent_config.py +0 -0
  141. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/configs/custom_llm_provider.py +0 -0
  142. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/configs/global_settings.py +0 -0
  143. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/configs/mcp_config.py +0 -0
  144. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/configs/save_worker.py +0 -0
  145. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/history_sidebar.py +0 -0
  146. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/json_editor.py +0 -0
  147. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/loading_overlay.py +0 -0
  148. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/markdown_editor.py +0 -0
  149. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/message_bubble.py +0 -0
  150. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/paste_aware_textedit.py +0 -0
  151. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/system_message.py +0 -0
  152. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/token_usage.py +0 -0
  153. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/widgets/tool_widget.py +0 -0
  154. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/gui/worker.py +0 -0
  155. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/image_generation/__init__.py +0 -0
  156. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/image_generation/service.py +0 -0
  157. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/image_generation/tool.py +0 -0
  158. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/llm/__init__.py +0 -0
  159. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/llm/base.py +0 -0
  160. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/llm/model_registry.py +0 -0
  161. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/llm/service_manager.py +0 -0
  162. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/llm/types.py +0 -0
  163. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/mcpclient/__init__.py +0 -0
  164. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/mcpclient/auth.py +0 -0
  165. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/mcpclient/config.py +0 -0
  166. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/mcpclient/manager.py +0 -0
  167. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/mcpclient/service.py +0 -0
  168. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/mcpclient/tool.py +0 -0
  169. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/__init__.py +0 -0
  170. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/base_service.py +0 -0
  171. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/chroma_service.py +0 -0
  172. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/context_persistent.py +0 -0
  173. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/github_copilot_ef.py +0 -0
  174. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/google_genai_ef.py +0 -0
  175. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/tool.py +0 -0
  176. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/memory/voyageai_ef.py +0 -0
  177. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/openai/__init__.py +0 -0
  178. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/openai/response_service.py +0 -0
  179. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/openai/service.py +0 -0
  180. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/prompts/__init__.py +0 -0
  181. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/prompts/constants.py +0 -0
  182. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/tools/README.md +0 -0
  183. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/tools/registration.py +0 -0
  184. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/tools/registry.py +0 -0
  185. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/voice/__init__.py +0 -0
  186. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/voice/audio_handler.py +0 -0
  187. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/voice/base.py +0 -0
  188. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/voice/deepinfra_service.py +0 -0
  189. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/voice/elevenlabs_service.py +0 -0
  190. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/voice/text_cleaner.py +0 -0
  191. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/web_search/__init__.py +0 -0
  192. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/web_search/service.py +0 -0
  193. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/AgentCrew/modules/web_search/tool.py +0 -0
  194. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/CONTRIBUTING.md +0 -0
  195. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/LICENSE +0 -0
  196. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/MANIFEST.in +0 -0
  197. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/README.md +0 -0
  198. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/agentcrew_ai.egg-info/dependency_links.txt +0 -0
  199. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/agentcrew_ai.egg-info/entry_points.txt +0 -0
  200. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/agentcrew_ai.egg-info/requires.txt +0 -0
  201. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/agentcrew_ai.egg-info/top_level.txt +0 -0
  202. {agentcrew_ai-0.8.5 → agentcrew_ai-0.8.6}/setup.cfg +0 -0
@@ -0,0 +1 @@
1
+ __version__ = "0.8.6"
@@ -27,6 +27,11 @@ from a2a.types import (
27
27
  TaskState,
28
28
  TaskStatusUpdateEvent,
29
29
  TaskArtifactUpdateEvent,
30
+ Part,
31
+ TextPart,
32
+ DataPart,
33
+ Role,
34
+ Message,
30
35
  )
31
36
 
32
37
  from AgentCrew.modules.agents import LocalAgent
@@ -58,6 +63,7 @@ class AgentTaskManager(TaskManager):
58
63
  """Manages tasks for a specific agent"""
59
64
 
60
65
  TERMINAL_STATES = {TaskState.completed, TaskState.canceled, TaskState.failed}
66
+ INPUT_REQUIRED_STATES = {TaskState.input_required}
61
67
 
62
68
  def __init__(self, agent_name: str, agent_manager: AgentManager):
63
69
  self.agent_name = agent_name
@@ -72,6 +78,9 @@ class AgentTaskManager(TaskManager):
72
78
  ] = defaultdict(list)
73
79
  self.streaming_enabled_tasks: set[str] = set()
74
80
 
81
+ self.pending_ask_responses: Dict[str, asyncio.Event] = {}
82
+ self.ask_responses: Dict[str, str] = {}
83
+
75
84
  self.agent = self.agent_manager.get_agent(self.agent_name)
76
85
  if self.agent is None or not isinstance(self.agent, LocalAgent):
77
86
  raise ValueError(f"Agent {agent_name} not found or is not a LocalAgent")
@@ -82,6 +91,19 @@ class AgentTaskManager(TaskManager):
82
91
  """Check if a state is terminal."""
83
92
  return state in self.TERMINAL_STATES
84
93
 
94
+ def _extract_text_from_message(self, message: Dict[str, Any]) -> str:
95
+ """Extract text content from a message."""
96
+ content = message.get("content", [])
97
+ if isinstance(content, str):
98
+ return content
99
+ text_parts = []
100
+ for part in content:
101
+ if isinstance(part, str):
102
+ text_parts.append(part)
103
+ elif isinstance(part, dict) and part.get("type") == "text":
104
+ text_parts.append(part.get("text", ""))
105
+ return " ".join(text_parts)
106
+
85
107
  def _validate_task_not_terminal(
86
108
  self, task: Task, operation: str
87
109
  ) -> Optional[TaskNotCancelableError]:
@@ -121,7 +143,6 @@ class AgentTaskManager(TaskManager):
121
143
  )
122
144
  )
123
145
 
124
- # Generate task ID from message
125
146
  task_id = (
126
147
  request.params.message.task_id
127
148
  or f"task_{request.params.message.message_id}"
@@ -135,8 +156,19 @@ class AgentTaskManager(TaskManager):
135
156
  root=JSONRPCErrorResponse(id=request.id, error=error)
136
157
  )
137
158
 
159
+ if existing_task.status.state == TaskState.input_required:
160
+ message = convert_a2a_message_to_agent(request.params.message)
161
+ user_response = self._extract_text_from_message(message)
162
+
163
+ if task_id in self.pending_ask_responses:
164
+ self.ask_responses[task_id] = user_response
165
+ self.pending_ask_responses[task_id].set()
166
+
167
+ return SendMessageResponse(
168
+ root=SendMessageSuccessResponse(id=request.id, result=existing_task)
169
+ )
170
+
138
171
  if task_id not in self.tasks:
139
- # Create task with initial state
140
172
  task = Task(
141
173
  id=task_id,
142
174
  context_id=request.params.message.context_id or f"ctx_{task_id}",
@@ -147,8 +179,8 @@ class AgentTaskManager(TaskManager):
147
179
  self.tasks[task.id] = task
148
180
 
149
181
  task = self.tasks[task_id]
150
- if task_id not in self.task_history:
151
- self.task_history[task_id] = []
182
+ if task.context_id not in self.task_history:
183
+ self.task_history[task.context_id] = []
152
184
 
153
185
  # Convert A2A message to SwissKnife format
154
186
  message = convert_a2a_message_to_agent(request.params.message)
@@ -185,9 +217,8 @@ class AgentTaskManager(TaskManager):
185
217
 
186
218
  message["content"] = new_parts
187
219
 
188
- self.task_history[task_id].append(message)
220
+ self.task_history[task.context_id].append(message)
189
221
 
190
- # Process with agent (non-blocking)
191
222
  asyncio.create_task(self._process_agent_task(self.agent, task))
192
223
 
193
224
  # Return initial task state
@@ -243,6 +274,35 @@ class AgentTaskManager(TaskManager):
243
274
  # Clean up
244
275
  self.streaming_tasks.pop(task_id, None)
245
276
 
277
+ def _create_ask_tool_message(
278
+ self, question: str, guided_answers: list[str]
279
+ ) -> Message:
280
+ """
281
+ Create an A2A message for the ask tool's input-required state.
282
+
283
+ Args:
284
+ question: The question to ask the user
285
+ guided_answers: List of suggested answers
286
+
287
+ Returns:
288
+ A2A Message with the question and guided answers
289
+ """
290
+ ask_data = {
291
+ "type": "ask",
292
+ "question": question,
293
+ "guided_answers": guided_answers,
294
+ "instruction": "Please respond with one of the guided answers or provide a custom response.",
295
+ }
296
+
297
+ return Message(
298
+ message_id=f"ask_{hash(question)}",
299
+ role=Role.agent,
300
+ parts=[
301
+ Part(root=TextPart(text=f"❓ {question}")),
302
+ Part(root=DataPart(data=ask_data)),
303
+ ],
304
+ )
305
+
246
306
  def _record_and_emit_event(
247
307
  self, task_id: str, event: Union[TaskStatusUpdateEvent, TaskArtifactUpdateEvent]
248
308
  ):
@@ -281,7 +341,7 @@ class AgentTaskManager(TaskManager):
281
341
 
282
342
  try:
283
343
  artifacts = []
284
- if task.id not in self.task_history:
344
+ if task.context_id not in self.task_history:
285
345
  raise ValueError("Task history is not existed")
286
346
 
287
347
  input_tokens = 0
@@ -308,7 +368,7 @@ class AgentTaskManager(TaskManager):
308
368
  chunk_text,
309
369
  thinking_chunk,
310
370
  ) in agent.process_messages(
311
- self.task_history[task.id], callback=process_result
371
+ self.task_history[task.context_id], callback=process_result
312
372
  ):
313
373
  # Update current response
314
374
  if response_message:
@@ -388,9 +448,8 @@ class AgentTaskManager(TaskManager):
388
448
  MessageType.Thinking, {"thinking": thinking_data}
389
449
  )
390
450
  if thinking_message:
391
- self.task_history[task.id].append(thinking_message)
451
+ self.task_history[task.context_id].append(thinking_message)
392
452
 
393
- # Format assistant message with the response and tool uses
394
453
  assistant_message = agent.format_message(
395
454
  MessageType.Assistant,
396
455
  {
@@ -401,34 +460,99 @@ class AgentTaskManager(TaskManager):
401
460
  },
402
461
  )
403
462
  if assistant_message:
404
- self.task_history[task.id].append(assistant_message)
463
+ self.task_history[task.context_id].append(assistant_message)
405
464
 
406
- # Process each tool use
407
465
  for tool_use in tool_uses:
408
- try:
409
- tool_result = await agent.execute_tool_call(
410
- tool_use["name"],
411
- tool_use["input"],
466
+ tool_name = tool_use["name"]
467
+
468
+ if tool_name == "ask":
469
+ question = tool_use["input"].get("question", "")
470
+ guided_answers = tool_use["input"].get("guided_answers", [])
471
+
472
+ task.status.state = TaskState.input_required
473
+ task.status.timestamp = datetime.now().isoformat()
474
+ task.status.message = self._create_ask_tool_message(
475
+ question, guided_answers
476
+ )
477
+
478
+ self._record_and_emit_event(
479
+ task.id,
480
+ TaskStatusUpdateEvent(
481
+ task_id=task.id,
482
+ context_id=task.context_id,
483
+ status=task.status,
484
+ final=False,
485
+ ),
412
486
  )
413
487
 
488
+ wait_event = asyncio.Event()
489
+ self.pending_ask_responses[task.id] = wait_event
490
+
491
+ try:
492
+ await asyncio.wait_for(wait_event.wait(), timeout=300)
493
+ user_answer = self.ask_responses.get(
494
+ task.id, "No response received"
495
+ )
496
+ except asyncio.TimeoutError:
497
+ user_answer = "User did not respond in time."
498
+ finally:
499
+ self.pending_ask_responses.pop(task.id, None)
500
+ self.ask_responses.pop(task.id, None)
501
+
502
+ tool_result = f"User's answer: {user_answer}"
503
+
504
+ task.status.state = TaskState.working
505
+ task.status.timestamp = datetime.now().isoformat()
506
+ task.status.message = None
507
+
414
508
  tool_result_message = agent.format_message(
415
509
  MessageType.ToolResult,
416
510
  {"tool_use": tool_use, "tool_result": tool_result},
417
511
  )
418
512
  if tool_result_message:
419
- self.task_history[task.id].append(tool_result_message)
513
+ self.task_history[task.context_id].append(
514
+ tool_result_message
515
+ )
420
516
 
421
- except Exception as e:
422
- error_message = agent.format_message(
423
- MessageType.ToolResult,
424
- {
425
- "tool_use": tool_use,
426
- "tool_result": str(e),
427
- "is_error": True,
428
- },
517
+ self._record_and_emit_event(
518
+ task.id,
519
+ TaskStatusUpdateEvent(
520
+ task_id=task.id,
521
+ context_id=task.context_id,
522
+ status=task.status,
523
+ final=False,
524
+ ),
429
525
  )
430
- if error_message:
431
- self.task_history[task.id].append(error_message)
526
+
527
+ else:
528
+ try:
529
+ tool_result = await agent.execute_tool_call(
530
+ tool_name,
531
+ tool_use["input"],
532
+ )
533
+
534
+ tool_result_message = agent.format_message(
535
+ MessageType.ToolResult,
536
+ {"tool_use": tool_use, "tool_result": tool_result},
537
+ )
538
+ if tool_result_message:
539
+ self.task_history[task.context_id].append(
540
+ tool_result_message
541
+ )
542
+
543
+ except Exception as e:
544
+ error_message = agent.format_message(
545
+ MessageType.ToolResult,
546
+ {
547
+ "tool_use": tool_use,
548
+ "tool_result": str(e),
549
+ "is_error": True,
550
+ },
551
+ )
552
+ if error_message:
553
+ self.task_history[task.context_id].append(
554
+ error_message
555
+ )
432
556
 
433
557
  return await _process_task()
434
558
  return current_response
@@ -442,9 +566,9 @@ class AgentTaskManager(TaskManager):
442
566
  },
443
567
  )
444
568
  if assistant_message:
445
- self.task_history[task.id].append(assistant_message)
569
+ self.task_history[task.context_id].append(assistant_message)
446
570
  user_message = (
447
- self.task_history[task.id][0]
571
+ self.task_history[task.context_id][0]
448
572
  .get("content", [{}])[0]
449
573
  .get("text", "")
450
574
  )
@@ -111,25 +111,25 @@ class LocalAgent(BaseAgent):
111
111
  # self.tool_prompts.append(
112
112
  # delegate_tool_prompt(self.services["agent_manager"])
113
113
  # )
114
+ from AgentCrew.modules.agents.tools.ask import (
115
+ register as register_ask,
116
+ ask_tool_prompt,
117
+ )
118
+
119
+ register_ask(self)
120
+ self.tool_prompts.append(ask_tool_prompt())
121
+
114
122
  if not self.is_remoting_mode:
115
123
  from AgentCrew.modules.agents.tools.transfer import (
116
124
  register as register_transfer,
117
125
  transfer_tool_prompt,
118
126
  )
119
- from AgentCrew.modules.agents.tools.ask import (
120
- register as register_ask,
121
- ask_tool_prompt,
122
- )
123
127
 
124
128
  register_transfer(self.services["agent_manager"], self)
125
129
  self.tool_prompts.append(
126
130
  transfer_tool_prompt(self.services["agent_manager"])
127
131
  )
128
132
 
129
- # Register the ask tool (always available)
130
- register_ask(self)
131
- self.tool_prompts.append(ask_tool_prompt())
132
-
133
133
  for tool_name in self.tools:
134
134
  if self.services and tool_name in self.services:
135
135
  service = self.services[tool_name]
@@ -15,8 +15,8 @@ MAX_CONCURRENT_COMMANDS = 3
15
15
  # Maximum lifetime for a single command execution (seconds)
16
16
  MAX_COMMAND_LIFETIME = 600
17
17
 
18
- # Maximum output size per command (bytes)
19
- MAX_OUTPUT_SIZE = 1 * 1024 * 1024 # 1MB
18
+ # Maximum output lines to keep in rolling buffer per stream (stdout/stderr)
19
+ MAX_OUTPUT_LINES = 300
20
20
 
21
21
  # Maximum number of commands allowed per minute (application-wide rate limit)
22
22
  MAX_COMMANDS_PER_MINUTE = 10
@@ -2,7 +2,6 @@ import os
2
2
  import sys
3
3
  import time
4
4
  import uuid
5
- import queue
6
5
  import threading
7
6
  import subprocess
8
7
  import re
@@ -10,12 +9,11 @@ import atexit
10
9
  import hashlib
11
10
  from typing import Dict, Any, Optional, Tuple, List
12
11
  from datetime import datetime
13
- from .metric import CommandMetrics
14
12
  from .types import CommandState, CommandProcess
15
13
  from .constants import (
16
14
  MAX_CONCURRENT_COMMANDS,
17
15
  MAX_COMMAND_LIFETIME,
18
- MAX_OUTPUT_SIZE,
16
+ MAX_OUTPUT_LINES,
19
17
  MAX_COMMANDS_PER_MINUTE,
20
18
  MAX_INPUT_SIZE,
21
19
  BLOCKED_PATTERNS,
@@ -68,9 +66,6 @@ class CommandExecutionService:
68
66
  # Rate limiting (application-wide)
69
67
  self._rate_limiter: List[float] = []
70
68
 
71
- # Metrics
72
- self.metrics = CommandMetrics()
73
-
74
69
  # Register cleanup on shutdown
75
70
  atexit.register(self.shutdown)
76
71
 
@@ -242,40 +237,40 @@ class CommandExecutionService:
242
237
  def _reader_thread(
243
238
  self,
244
239
  stream,
245
- output_queue: queue.Queue,
240
+ output_list: list,
241
+ output_lock: threading.Lock,
246
242
  stop_event: threading.Event,
247
- max_size: int,
243
+ max_lines: int,
248
244
  ):
249
245
  """
250
- Read stream line by line into queue with size enforcement.
246
+ Read stream line by line into persistent list with rolling buffer.
251
247
 
252
- Uses sentinel values:
253
- - ('data', line): Normal output line
254
- - ('eof', None): End of stream
255
- - ('error', msg): Error occurred
256
- - ('size_limit', None): Output size limit reached
257
- """
258
- total_bytes = 0
248
+ When output exceeds max_lines, old lines are removed to keep recent output.
259
249
 
250
+ Args:
251
+ stream: Process stdout or stderr stream
252
+ output_list: Persistent list to append output lines
253
+ output_lock: Threading lock for thread-safe list access
254
+ stop_event: Event to signal thread stop
255
+ max_lines: Maximum number of lines to keep (rolling buffer)
256
+ """
260
257
  try:
261
258
  for line in iter(stream.readline, b""):
262
259
  if stop_event.is_set():
263
260
  break
264
261
 
265
- total_bytes += len(line)
266
- if total_bytes > max_size:
267
- output_queue.put(("size_limit", None))
268
- logger.warning(f"Output size limit ({max_size} bytes) exceeded")
269
- break
270
-
271
262
  decoded = line.decode("utf-8", errors="replace")
272
- output_queue.put(("data", decoded))
263
+
264
+ with output_lock:
265
+ output_list.append(decoded)
266
+
267
+ # Keep only recent lines using slice
268
+ if len(output_list) > max_lines:
269
+ output_list[:] = output_list[-max_lines:]
273
270
 
274
271
  except Exception as e:
275
272
  logger.error(f"Reader thread error: {e}")
276
- output_queue.put(("error", str(e)))
277
273
  finally:
278
- output_queue.put(("eof", None))
279
274
  stream.close()
280
275
 
281
276
  def execute_command(
@@ -371,9 +366,10 @@ class CommandExecutionService:
371
366
  target=self._reader_thread,
372
367
  args=(
373
368
  process.stdout,
374
- cmd_process.output_queue,
369
+ cmd_process.stdout_lines,
370
+ cmd_process.output_lock,
375
371
  cmd_process.stop_event,
376
- MAX_OUTPUT_SIZE,
372
+ MAX_OUTPUT_LINES,
377
373
  ),
378
374
  daemon=True,
379
375
  name=f"stdout-reader-{command_id}",
@@ -383,9 +379,10 @@ class CommandExecutionService:
383
379
  target=self._reader_thread,
384
380
  args=(
385
381
  process.stderr,
386
- cmd_process.error_queue,
382
+ cmd_process.stderr_lines,
383
+ cmd_process.output_lock,
387
384
  cmd_process.stop_event,
388
- MAX_OUTPUT_SIZE,
385
+ MAX_OUTPUT_LINES,
389
386
  ),
390
387
  daemon=True,
391
388
  name=f"stderr-reader-{command_id}",
@@ -405,21 +402,10 @@ class CommandExecutionService:
405
402
  cmd_process.exit_code = process.returncode
406
403
  cmd_process.transition_to(CommandState.COMPLETING)
407
404
 
408
- output_lines = []
409
- error_lines = []
410
-
411
- while not cmd_process.output_queue.empty():
412
- msg_type, data = cmd_process.output_queue.get()
413
- if msg_type == "data":
414
- output_lines.append(data)
415
-
416
- while not cmd_process.error_queue.empty():
417
- msg_type, data = cmd_process.error_queue.get()
418
- if msg_type == "data":
419
- error_lines.append(data)
420
-
421
- output = "".join(output_lines)
422
- error_output = "".join(error_lines)
405
+ # Get output from persistent storage (thread-safe)
406
+ with cmd_process.output_lock:
407
+ output = "".join(cmd_process.stdout_lines)
408
+ error_output = "".join(cmd_process.stderr_lines)
423
409
 
424
410
  duration = time.time() - start_time
425
411
 
@@ -433,7 +419,6 @@ class CommandExecutionService:
433
419
  len(output) + len(error_output),
434
420
  )
435
421
 
436
- self.metrics.record_execution(command, duration, "completed")
437
422
  self._cleanup_command_internal(command_id)
438
423
 
439
424
  result = {
@@ -466,22 +451,20 @@ class CommandExecutionService:
466
451
  logger.error(f"Command execution error: {e}")
467
452
 
468
453
  self._audit_log(command, "error", command_id)
469
- self.metrics.record_execution(command, time.time() - start_time, "error")
470
454
 
471
455
  if command_id in self._instances:
472
456
  self._cleanup_command_internal(command_id)
473
457
 
474
458
  return {"status": "error", "error": f"Execution failed: {str(e)}"}
475
459
 
476
- def get_command_status(
477
- self, command_id: str, consume_output: bool = True
478
- ) -> Dict[str, Any]:
460
+ def get_command_status(self, command_id: str) -> Dict[str, Any]:
479
461
  """
480
462
  Check status of running command.
481
463
 
464
+ Output is persistent and will be returned in full on every call.
465
+
482
466
  Args:
483
467
  command_id: Command identifier
484
- consume_output: If True, drain and return queued output
485
468
 
486
469
  Returns:
487
470
  Dict with status, output, exit_code, elapsed_time
@@ -494,30 +477,11 @@ class CommandExecutionService:
494
477
 
495
478
  exit_code = cmd_process.process.poll()
496
479
 
497
- output_lines = []
498
- error_lines = []
499
-
500
- if consume_output:
501
- while not cmd_process.output_queue.empty():
502
- try:
503
- msg_type, data = cmd_process.output_queue.get_nowait()
504
- if msg_type == "data":
505
- output_lines.append(data)
506
- elif msg_type == "size_limit":
507
- output_lines.append("\n[OUTPUT SIZE LIMIT REACHED]\n")
508
- except queue.Empty:
509
- break
510
-
511
- while not cmd_process.error_queue.empty():
512
- try:
513
- msg_type, data = cmd_process.error_queue.get_nowait()
514
- if msg_type == "data":
515
- error_lines.append(data)
516
- except queue.Empty:
517
- break
480
+ # Get output from persistent storage (thread-safe)
481
+ with cmd_process.output_lock:
482
+ output = "".join(cmd_process.stdout_lines)
483
+ error_output = "".join(cmd_process.stderr_lines)
518
484
 
519
- output = "".join(output_lines)
520
- error_output = "".join(error_lines)
521
485
  elapsed = time.time() - cmd_process.start_time
522
486
 
523
487
  if elapsed > MAX_COMMAND_LIFETIME:
@@ -546,7 +510,6 @@ class CommandExecutionService:
546
510
  duration,
547
511
  len(output) + len(error_output),
548
512
  )
549
- self.metrics.record_execution(cmd_process.command, duration, "completed")
550
513
  self._cleanup_command_internal(command_id)
551
514
 
552
515
  return {
@@ -690,11 +653,6 @@ class CommandExecutionService:
690
653
  pass
691
654
 
692
655
  cmd_process.transition_to(CommandState.KILLED)
693
- self.metrics.record_execution(
694
- cmd_process.command,
695
- time.time() - cmd_process.start_time,
696
- "killed",
697
- )
698
656
 
699
657
  except Exception as e:
700
658
  logger.error(f"Process termination error: {e}")
@@ -767,10 +725,6 @@ class CommandExecutionService:
767
725
  """
768
726
  return self.cleanup_command(command_id)
769
727
 
770
- def get_metrics(self) -> Dict[str, Any]:
771
- """Get command execution metrics"""
772
- return self.metrics.get_report()
773
-
774
728
  def shutdown(self):
775
729
  """Shutdown service and cleanup all running commands"""
776
730
  logger.info("Shutting down CommandExecutionService")
@@ -6,6 +6,7 @@ Tool definitions and handlers for secure shell command execution.
6
6
 
7
7
  from typing import Dict, Any, Callable
8
8
  from .service import CommandExecutionService
9
+ import os
9
10
 
10
11
 
11
12
  def get_run_command_tool_definition(provider="claude") -> Dict[str, Any]:
@@ -34,8 +35,7 @@ def get_run_command_tool_definition(provider="claude") -> Dict[str, Any]:
34
35
  },
35
36
  "working_dir": {
36
37
  "type": "string",
37
- "default": "./",
38
- "description": "Working directory.",
38
+ "description": f"Working directory. Current working directory is {os.getcwd()}. Use ./ for current dir.",
39
39
  },
40
40
  "env_vars": {
41
41
  "type": "object",
@@ -50,7 +50,7 @@ def get_run_command_tool_definition(provider="claude") -> Dict[str, Any]:
50
50
  "input_schema": {
51
51
  "type": "object",
52
52
  "properties": args,
53
- "required": ["command"],
53
+ "required": ["command", "working_dir"],
54
54
  },
55
55
  }
56
56
  else:
@@ -62,7 +62,7 @@ def get_run_command_tool_definition(provider="claude") -> Dict[str, Any]:
62
62
  "parameters": {
63
63
  "type": "object",
64
64
  "properties": args,
65
- "required": ["command"],
65
+ "required": ["command", "working_dir"],
66
66
  },
67
67
  },
68
68
  }
@@ -258,9 +258,7 @@ def get_check_command_status_tool_handler(
258
258
  if not command_id:
259
259
  raise ValueError("Missing required parameter: command_id")
260
260
 
261
- result = command_service.get_command_status(
262
- command_id=command_id, consume_output=True
263
- )
261
+ result = command_service.get_command_status(command_id=command_id)
264
262
 
265
263
  if result["status"] == "completed":
266
264
  response = f"Command completed.\nExit Code: {result['exit_code']}\nDuration: {result['duration_seconds']}s\n\n"
@@ -1,4 +1,3 @@
1
- import queue
2
1
  import threading
3
2
  import subprocess
4
3
  from enum import Enum
@@ -31,13 +30,13 @@ class CommandProcess:
31
30
  process: subprocess.Popen
32
31
  platform: str
33
32
  start_time: float
34
- output_queue: queue.Queue = field(default_factory=queue.Queue)
35
- error_queue: queue.Queue = field(default_factory=queue.Queue)
33
+ stdout_lines: List[str] = field(default_factory=list)
34
+ stderr_lines: List[str] = field(default_factory=list)
35
+ output_lock: threading.Lock = field(default_factory=threading.Lock)
36
36
  state: CommandState = CommandState.QUEUED
37
37
  exit_code: Optional[int] = None
38
38
  reader_threads: List[threading.Thread] = field(default_factory=list)
39
39
  stop_event: threading.Event = field(default_factory=threading.Event)
40
- total_output_size: int = 0
41
40
  working_dir: Optional[str] = None
42
41
 
43
42
  def transition_to(self, new_state: CommandState):