agentcrew-ai 0.9.0__tar.gz → 0.9.1__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 (228) hide show
  1. agentcrew_ai-0.9.1/AgentCrew/__init__.py +1 -0
  2. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/app.py +12 -1
  3. agentcrew_ai-0.9.1/AgentCrew/modules/a2a/common/client/card_resolver.py +39 -0
  4. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/server.py +5 -0
  5. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/task_manager.py +1 -0
  6. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message/conversation.py +18 -1
  7. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/service.py +50 -7
  8. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/tool.py +9 -8
  9. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/completers.py +4 -0
  10. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/console_ui.py +17 -0
  11. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/display_handlers.py +4 -0
  12. agentcrew_ai-0.9.1/AgentCrew/modules/console/visual_mode/__init__.py +5 -0
  13. agentcrew_ai-0.9.1/AgentCrew/modules/console/visual_mode/viewer.py +41 -0
  14. agentcrew_ai-0.9.1/AgentCrew/modules/console/visual_mode/viewer_input_handler.py +315 -0
  15. agentcrew_ai-0.9.1/AgentCrew/modules/console/visual_mode/viewer_ui.py +608 -0
  16. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/menu_components.py +8 -7
  17. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/style_provider.py +3 -1
  18. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/configs/global_settings.py +1 -0
  19. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/history_sidebar.py +6 -1
  20. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/llm/constants.py +15 -5
  21. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/mcpclient/service.py +0 -1
  22. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/base_service.py +13 -0
  23. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/chroma_service.py +50 -0
  24. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/PKG-INFO +1 -1
  25. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/agentcrew_ai.egg-info/PKG-INFO +1 -1
  26. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/agentcrew_ai.egg-info/SOURCES.txt +4 -0
  27. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/pyproject.toml +1 -1
  28. agentcrew_ai-0.9.0/AgentCrew/__init__.py +0 -1
  29. agentcrew_ai-0.9.0/AgentCrew/modules/a2a/common/client/card_resolver.py +0 -20
  30. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/assets/agentcrew_logo.png +0 -0
  31. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/main.py +0 -0
  32. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/main_docker.py +0 -0
  33. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/__init__.py +0 -0
  34. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/__init__.py +0 -0
  35. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/adapters.py +0 -0
  36. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/agent_cards.py +0 -0
  37. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/__init__.py +0 -0
  38. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/client/__init__.py +0 -0
  39. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/client/client.py +0 -0
  40. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/server/__init__.py +0 -0
  41. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/server/auth_middleware.py +0 -0
  42. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/server/task_manager.py +0 -0
  43. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/common/server/utils.py +0 -0
  44. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/errors.py +0 -0
  45. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/a2a/registry.py +0 -0
  46. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/__init__.py +0 -0
  47. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/base.py +0 -0
  48. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/example.py +0 -0
  49. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/local_agent.py +0 -0
  50. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/manager.py +0 -0
  51. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/remote_agent.py +0 -0
  52. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/tools/__init__.py +0 -0
  53. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/tools/ask.py +0 -0
  54. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/tools/delegate.py +0 -0
  55. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/agents/tools/transfer.py +0 -0
  56. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/anthropic/__init__.py +0 -0
  57. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/anthropic/service.py +0 -0
  58. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/__init__.py +0 -0
  59. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/chrome_manager.py +0 -0
  60. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/element_extractor.py +0 -0
  61. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/click_element.js +0 -0
  62. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/draw_element_boxes.js +0 -0
  63. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/extract_clickable_elements.js +0 -0
  64. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/extract_elements_by_text.js +0 -0
  65. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/extract_input_elements.js +0 -0
  66. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/extract_scrollable_elements.js +0 -0
  67. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/filter_hidden_elements.js +0 -0
  68. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/focus_and_clear_element.js +0 -0
  69. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/remove_element_boxes.js +0 -0
  70. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/scroll_to_element.js +0 -0
  71. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js/trigger_input_events.js +0 -0
  72. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/js_loader.py +0 -0
  73. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/service.py +0 -0
  74. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/browser_automation/tool.py +0 -0
  75. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/__init__.py +0 -0
  76. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/consolidation.py +0 -0
  77. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/file_handler.py +0 -0
  78. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/history.py +0 -0
  79. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message/__init__.py +0 -0
  80. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message/base.py +0 -0
  81. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message/command_processor.py +0 -0
  82. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message/handler.py +0 -0
  83. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message/tool_manager.py +0 -0
  84. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/chat/message_handler.py +0 -0
  85. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/clipboard/__init__.py +0 -0
  86. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/clipboard/service.py +0 -0
  87. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/clipboard/tool.py +0 -0
  88. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/__init__.py +0 -0
  89. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/file_search_service.py +0 -0
  90. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/grep_service.py +0 -0
  91. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/__init__.py +0 -0
  92. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/base.py +0 -0
  93. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/cpp_parser.py +0 -0
  94. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/csharp_parser.py +0 -0
  95. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/generic_parser.py +0 -0
  96. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/go_parser.py +0 -0
  97. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/java_parser.py +0 -0
  98. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/javascript_parser.py +0 -0
  99. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/kotlin_parser.py +0 -0
  100. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/php_parser.py +0 -0
  101. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/python_parser.py +0 -0
  102. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/ruby_parser.py +0 -0
  103. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/code_analysis/parsers/rust_parser.py +0 -0
  104. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/command_execution/__init__.py +0 -0
  105. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/command_execution/constants.py +0 -0
  106. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/command_execution/service.py +0 -0
  107. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/command_execution/tool.py +0 -0
  108. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/command_execution/types.py +0 -0
  109. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/config/__init__.py +0 -0
  110. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/config/config_management.py +0 -0
  111. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/__init__.py +0 -0
  112. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/command_handlers.py +0 -0
  113. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/confirmation_handler.py +0 -0
  114. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/constants.py +0 -0
  115. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/conversation_browser/__init__.py +0 -0
  116. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/conversation_browser/browser.py +0 -0
  117. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/conversation_browser/browser_input_handler.py +0 -0
  118. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/conversation_browser/browser_ui.py +0 -0
  119. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/conversation_handler.py +0 -0
  120. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/diff_display.py +0 -0
  121. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/input_handler.py +0 -0
  122. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/tool_display.py +0 -0
  123. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/ui_effects.py +0 -0
  124. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/console/utils.py +0 -0
  125. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/custom_llm/__init__.py +0 -0
  126. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/custom_llm/copilot_response_service.py +0 -0
  127. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/custom_llm/deepinfra_service.py +0 -0
  128. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/custom_llm/github_copilot_service.py +0 -0
  129. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/custom_llm/service.py +0 -0
  130. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/file_editing/__init__.py +0 -0
  131. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/file_editing/safety_validator.py +0 -0
  132. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/file_editing/search_replace_engine.py +0 -0
  133. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/file_editing/service.py +0 -0
  134. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/file_editing/tool.py +0 -0
  135. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/file_editing/tree_sitter_checker.py +0 -0
  136. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/google/__init__.py +0 -0
  137. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/google/native_service.py +0 -0
  138. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/google/service.py +0 -0
  139. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/groq/__init__.py +0 -0
  140. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/groq/service.py +0 -0
  141. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/__init__.py +0 -0
  142. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/__init__.py +0 -0
  143. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/chat_components.py +0 -0
  144. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/command_handler.py +0 -0
  145. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/completers.py +0 -0
  146. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/conversation_components.py +0 -0
  147. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/input_components.py +0 -0
  148. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/keyboard_handler.py +0 -0
  149. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/message_handlers.py +0 -0
  150. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/tool_handlers.py +0 -0
  151. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/components/ui_state_manager.py +0 -0
  152. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/qt_ui.py +0 -0
  153. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/README.md +0 -0
  154. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/__init__.py +0 -0
  155. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/atom_light.yaml +0 -0
  156. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/catppuccin.yaml +0 -0
  157. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/dracula.yaml +0 -0
  158. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/nord.yaml +0 -0
  159. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/saigontech.yaml +0 -0
  160. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/theme_loader.py +0 -0
  161. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/themes/unicorn.yaml +0 -0
  162. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/utils/__init__.py +0 -0
  163. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/utils/macos_clipboard.py +0 -0
  164. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/utils/strings.py +0 -0
  165. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/utils/wins_clipboard.py +0 -0
  166. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/__init__.py +0 -0
  167. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/config_window.py +0 -0
  168. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/configs/__init__.py +0 -0
  169. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/configs/agent_config.py +0 -0
  170. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/configs/custom_llm_provider.py +0 -0
  171. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/configs/mcp_config.py +0 -0
  172. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/configs/save_worker.py +0 -0
  173. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/diff_widget.py +0 -0
  174. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/json_editor.py +0 -0
  175. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/loading_overlay.py +0 -0
  176. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/markdown_editor.py +0 -0
  177. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/message_bubble.py +0 -0
  178. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/paste_aware_textedit.py +0 -0
  179. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/system_message.py +0 -0
  180. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/token_usage.py +0 -0
  181. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/widgets/tool_widget.py +0 -0
  182. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/gui/worker.py +0 -0
  183. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/image_generation/__init__.py +0 -0
  184. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/image_generation/service.py +0 -0
  185. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/image_generation/tool.py +0 -0
  186. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/llm/__init__.py +0 -0
  187. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/llm/base.py +0 -0
  188. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/llm/model_registry.py +0 -0
  189. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/llm/service_manager.py +0 -0
  190. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/llm/types.py +0 -0
  191. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/mcpclient/__init__.py +0 -0
  192. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/mcpclient/auth.py +0 -0
  193. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/mcpclient/config.py +0 -0
  194. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/mcpclient/manager.py +0 -0
  195. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/mcpclient/tool.py +0 -0
  196. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/__init__.py +0 -0
  197. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/context_persistent.py +0 -0
  198. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/github_copilot_ef.py +0 -0
  199. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/google_genai_ef.py +0 -0
  200. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/tool.py +0 -0
  201. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/memory/voyageai_ef.py +0 -0
  202. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/openai/__init__.py +0 -0
  203. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/openai/response_service.py +0 -0
  204. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/openai/service.py +0 -0
  205. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/prompts/__init__.py +0 -0
  206. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/prompts/constants.py +0 -0
  207. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/tools/README.md +0 -0
  208. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/tools/registration.py +0 -0
  209. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/tools/registry.py +0 -0
  210. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/voice/__init__.py +0 -0
  211. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/voice/audio_handler.py +0 -0
  212. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/voice/base.py +0 -0
  213. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/voice/deepinfra_service.py +0 -0
  214. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/voice/elevenlabs_service.py +0 -0
  215. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/voice/text_cleaner.py +0 -0
  216. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/web_search/__init__.py +0 -0
  217. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/web_search/service.py +0 -0
  218. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/modules/web_search/tool.py +0 -0
  219. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/AgentCrew/setup.py +0 -0
  220. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/CONTRIBUTING.md +0 -0
  221. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/LICENSE +0 -0
  222. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/MANIFEST.in +0 -0
  223. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/README.md +0 -0
  224. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/agentcrew_ai.egg-info/dependency_links.txt +0 -0
  225. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/agentcrew_ai.egg-info/entry_points.txt +0 -0
  226. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/agentcrew_ai.egg-info/requires.txt +0 -0
  227. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/agentcrew_ai.egg-info/top_level.txt +0 -0
  228. {agentcrew_ai-0.9.0 → agentcrew_ai-0.9.1}/setup.cfg +0 -0
@@ -0,0 +1 @@
1
+ __version__ = "0.9.1"
@@ -246,13 +246,24 @@ class AgentCrewApplication:
246
246
  except Exception as e:
247
247
  raise ValueError(f"Failed to load output schema: {e}")
248
248
 
249
+ def _clean_json_response(self, response: str) -> str:
250
+ import re
251
+
252
+ cleaned = response.strip()
253
+ pattern = r"^```(?:json)?\s*\n?(.*?)\n?```$"
254
+ match = re.match(pattern, cleaned, re.DOTALL)
255
+ if match:
256
+ cleaned = match.group(1).strip()
257
+ return cleaned
258
+
249
259
  def _validate_response_against_schema(
250
260
  self, response: str, schema_dict: Dict[str, Any]
251
261
  ) -> tuple[bool, Optional[str]]:
252
262
  from jsonschema import validate, ValidationError
253
263
 
254
264
  try:
255
- response_json = json.loads(response)
265
+ cleaned_response = self._clean_json_response(response)
266
+ response_json = json.loads(cleaned_response)
256
267
  except json.JSONDecodeError as e:
257
268
  return (
258
269
  False,
@@ -0,0 +1,39 @@
1
+ import json
2
+
3
+ import httpx
4
+
5
+ from a2a.types import AgentCard
6
+
7
+ DEFAULT_AGENT_CARD_PATHS = [
8
+ "/.well-known/agent-card.json",
9
+ "/.well-known/agent.json",
10
+ ]
11
+
12
+
13
+ class A2ACardResolver:
14
+ def __init__(self, base_url, agent_card_path: str | None = None):
15
+ self.base_url = base_url.rstrip("/")
16
+ self.agent_card_path = agent_card_path.lstrip("/") if agent_card_path else None
17
+
18
+ def get_agent_card(self) -> AgentCard:
19
+ with httpx.Client() as client:
20
+ if self.agent_card_path:
21
+ return self._fetch_agent_card(client, self.agent_card_path)
22
+
23
+ for path in DEFAULT_AGENT_CARD_PATHS:
24
+ try:
25
+ return self._fetch_agent_card(client, path.lstrip("/"))
26
+ except httpx.HTTPStatusError:
27
+ continue
28
+
29
+ raise httpx.RequestError(
30
+ f"Agent card not found at any of the default paths: {DEFAULT_AGENT_CARD_PATHS}"
31
+ )
32
+
33
+ def _fetch_agent_card(self, client: httpx.Client, path: str) -> AgentCard:
34
+ response = client.get(self.base_url + "/" + path)
35
+ response.raise_for_status()
36
+ try:
37
+ return AgentCard(**response.json())
38
+ except json.JSONDecodeError as e:
39
+ raise httpx.RequestError(str(e)) from e
@@ -82,6 +82,11 @@ class A2AServer:
82
82
  agent_routes = Mount(
83
83
  f"/{agent_name}",
84
84
  routes=[
85
+ Route(
86
+ "/.well-known/agent-card.json",
87
+ self._get_agent_card_factory(agent_name),
88
+ methods=["GET"],
89
+ ),
85
90
  Route(
86
91
  "/.well-known/agent.json",
87
92
  self._get_agent_card_factory(agent_name),
@@ -608,6 +608,7 @@ class AgentTaskManager(TaskManager):
608
608
 
609
609
  except Exception as e:
610
610
  logger.error(str(e))
611
+ logger.debug(self.task_history[task.context_id])
611
612
  # Handle errors
612
613
  task.status.state = TaskState.failed
613
614
  task.status.timestamp = datetime.now().isoformat()
@@ -198,6 +198,7 @@ class ConversationManager:
198
198
  def delete_conversation_by_id(self, conversation_id: str) -> bool:
199
199
  """
200
200
  Deletes a conversation by its ID, handling file deletion and UI updates.
201
+ Also deletes associated memory data.
201
202
 
202
203
  Args:
203
204
  conversation_id: The ID of the conversation to delete.
@@ -215,6 +216,22 @@ class ConversationManager:
215
216
  logger.info(
216
217
  f"INFO: Successfully deleted conversation file for ID: {conversation_id}"
217
218
  )
219
+
220
+ if self.message_handler.memory_service:
221
+ memory_result = (
222
+ self.message_handler.memory_service.delete_by_conversation_id(
223
+ conversation_id
224
+ )
225
+ )
226
+ if memory_result.get("success"):
227
+ logger.info(
228
+ f"INFO: Deleted {memory_result.get('count', 0)} memories for conversation {conversation_id}"
229
+ )
230
+ else:
231
+ logger.warning(
232
+ f"WARNING: Failed to delete memories for conversation {conversation_id}: {memory_result.get('message')}"
233
+ )
234
+
218
235
  self.message_handler._notify("conversations_changed", None)
219
236
  self.message_handler._notify(
220
237
  "system_message", f"Conversation {conversation_id[:8]}... deleted."
@@ -224,7 +241,7 @@ class ConversationManager:
224
241
  logger.info(
225
242
  f"INFO: Deleted conversation {conversation_id} was the current one. Starting new conversation."
226
243
  )
227
- self.start_new_conversation() # This will notify "clear_requested"
244
+ self.start_new_conversation()
228
245
  return True
229
246
  else:
230
247
  error_msg = f"Failed to delete conversation {conversation_id[:8]}..."
@@ -3,13 +3,22 @@ import fnmatch
3
3
  import subprocess
4
4
  import json
5
5
  import asyncio
6
- from typing import Any, Dict, List, Optional, TYPE_CHECKING
6
+ import base64
7
+ from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING
7
8
  from loguru import logger
8
9
 
9
10
  from tree_sitter_language_pack import get_parser
10
11
  from tree_sitter import Parser
11
12
 
12
13
  from .parsers import get_parser_for_language, BaseLanguageParser
14
+ import mimetypes
15
+
16
+ IMAGE_MIME_TYPES = [
17
+ "image/jpeg",
18
+ "image/png",
19
+ "image/gif",
20
+ "image/webp",
21
+ ]
13
22
 
14
23
  if TYPE_CHECKING:
15
24
  from AgentCrew.modules.llm.base import BaseLLMService
@@ -59,6 +68,7 @@ class CodeAnalysisService:
59
68
  analyzing large repositories (>500 files).
60
69
  """
61
70
  self.llm_service = llm_service
71
+ self.file_handler = None
62
72
  if self.llm_service:
63
73
  if self.llm_service.provider_name == "google":
64
74
  self.llm_service.model = "gemini-2.5-flash-lite"
@@ -666,18 +676,49 @@ Example response format:
666
676
  file_path,
667
677
  start_line=None,
668
678
  end_line=None,
669
- ) -> Dict[str, str]:
679
+ ) -> Union[Tuple[str, str], Tuple[str, Dict[str, Any]]]:
670
680
  """
671
681
  Return the content of a file, optionally reading only a specific line range.
682
+ For document files (PDF, DOCX, XLSX, PPTX), uses Docling to convert
683
+ to text/markdown and ignores start_line/end_line parameters.
684
+ For image files, returns base64 encoded data in image_url format.
672
685
 
673
686
  Args:
674
687
  file_path: Path to the file to read
675
- start_line: Optional starting line number (1-indexed)
676
- end_line: Optional ending line number (1-indexed, inclusive)
688
+ start_line: Optional starting line number (1-indexed) - ignored for document files
689
+ end_line: Optional ending line number (1-indexed, inclusive) - ignored for document files
677
690
 
678
691
  Returns:
679
- Dictionary with file content (key: "file", value: file content string)
692
+ Tuple of (file_path, content) where content is either:
693
+ - str: text content for text/document files
694
+ - dict: {"type": "image_url", "image_url": {"url": "data:mime;base64,..."}} for images
680
695
  """
696
+
697
+ from AgentCrew.modules.chat.file_handler import (
698
+ FileHandler,
699
+ ALLOWED_MIME_TYPES,
700
+ )
701
+
702
+ mime_type, _ = mimetypes.guess_type(file_path)
703
+
704
+ if mime_type and mime_type in IMAGE_MIME_TYPES:
705
+ with open(file_path, "rb") as file:
706
+ binary_data = file.read()
707
+ base64_data = base64.b64encode(binary_data).decode("utf-8")
708
+ return file_path, {
709
+ "type": "image_url",
710
+ "image_url": {"url": f"data:{mime_type};base64,{base64_data}"},
711
+ }
712
+
713
+ if mime_type and mime_type in ALLOWED_MIME_TYPES:
714
+ if self.file_handler is None:
715
+ self.file_handler = FileHandler()
716
+ result = self.file_handler.process_file(file_path)
717
+ if result and "text" in result:
718
+ return file_path, result["text"]
719
+ elif result is None:
720
+ raise ValueError(f"Failed to process document file: {file_path}")
721
+
681
722
  with open(file_path, "rb") as file:
682
723
  content = file.read()
683
724
 
@@ -700,9 +741,11 @@ Example response format:
700
741
  end_line = total_lines
701
742
 
702
743
  selected_lines = lines[start_line - 1 : end_line]
703
- return {"file": "\n".join(selected_lines)}
744
+ return file_path, "\n".join(selected_lines)
745
+
746
+ return file_path, decoded_content
704
747
 
705
- return {"file": decoded_content}
748
+ return file_path, decoded_content
706
749
 
707
750
  def _build_file_tree(self, file_paths: List[str]) -> Dict[str, Any]:
708
751
  """Build a hierarchical tree structure from flat file paths.
@@ -109,7 +109,7 @@ def get_file_content_tool_definition(provider="claude"):
109
109
  Returns:
110
110
  Dict containing the tool definition
111
111
  """
112
- tool_description = "Gets the content of a file, or a specific lines within that file (function or class body). Use this to examine the logic of specific functions, the structure of classes, or the overall content of a file."
112
+ tool_description = "Gets the content of a file, or a specific lines within that file (function or class body). Use this to examine the logic of specific functions, the structure of classes, or the overall content of a file. Also supports reading document files (PDF, DOCX, XLSX, PPTX, images) which will be converted to text/markdown - for document files, start_line and end_line parameters are ignored."
113
113
 
114
114
  tool_arguments = {
115
115
  "file_path": {
@@ -157,7 +157,7 @@ def get_file_content_tool_handler(
157
157
  ):
158
158
  """Returns a function that handles the get_file_content tool."""
159
159
 
160
- def handler(**params) -> str:
160
+ def handler(**params):
161
161
  file_path = params.get("file_path", "./")
162
162
  start_line = params.get("start_line")
163
163
  end_line = params.get("end_line")
@@ -168,16 +168,17 @@ def get_file_content_tool_handler(
168
168
  if not os.path.isabs(file_path):
169
169
  file_path = os.path.abspath(file_path)
170
170
 
171
- results = code_analysis_service.get_file_content(
171
+ path, file_content = code_analysis_service.get_file_content(
172
172
  file_path, start_line=start_line, end_line=end_line
173
173
  )
174
174
 
175
- content = ""
176
-
177
- for path, code in results.items():
178
- content += f"{path}: {code}\n"
175
+ if isinstance(file_content, dict) and file_content.get("type") == "image_url":
176
+ return [
177
+ {"type": "text", "text": f"Image file: {path}"},
178
+ file_content,
179
+ ]
179
180
 
180
- return content
181
+ return f"`{path}`: {file_content}"
181
182
 
182
183
  return handler
183
184
 
@@ -233,6 +233,10 @@ class ChatCompleter(Completer):
233
233
  "/delete_behavior",
234
234
  "Delete an adaptive behavior (usage: /delete_behavior <id>)",
235
235
  ),
236
+ (
237
+ "/visual",
238
+ "Open visual mode to view raw message content with vim-like navigation",
239
+ ),
236
240
  ("/exit", "Exit the application"),
237
241
  ("/quit", "Exit the application"),
238
242
  ]
@@ -494,6 +494,23 @@ class ConsoleUI(Observer):
494
494
  self.print_welcome_message()
495
495
  continue
496
496
 
497
+ elif user_input.strip() == "/visual":
498
+ self.input_handler._stop_input_thread()
499
+ try:
500
+ from .visual_mode import VisualModeViewer
501
+
502
+ viewer = VisualModeViewer(
503
+ console=self.console,
504
+ on_copy=self.copy_to_clipboard,
505
+ )
506
+ viewer.set_messages(
507
+ self.message_handler.streamline_messages
508
+ )
509
+ viewer.show()
510
+ finally:
511
+ self.input_handler._start_input_thread()
512
+ continue
513
+
497
514
  # Handle toggle_session_yolo command directly (console only, session-based)
498
515
  elif user_input.strip() == "/toggle_session_yolo":
499
516
  self.command_handlers.handle_toggle_session_yolo_command()
@@ -494,6 +494,10 @@ class DisplayHandlers:
494
494
  "Use '/unconsolidate' undo last consolidated.",
495
495
  style=RICH_STYLE_YELLOW,
496
496
  ),
497
+ Text(
498
+ "Use '/visual' to view raw message content with vim-like navigation and copy.",
499
+ style=RICH_STYLE_YELLOW,
500
+ ),
497
501
  Text(
498
502
  "Tool calls require confirmation before execution.",
499
503
  style=RICH_STYLE_BLUE,
@@ -0,0 +1,5 @@
1
+ """Visual mode module for viewing raw message content."""
2
+
3
+ from .viewer import VisualModeViewer
4
+
5
+ __all__ = ["VisualModeViewer"]
@@ -0,0 +1,41 @@
1
+ """Visual mode viewer for raw message content."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, List, Dict, Any, Optional, Callable
6
+
7
+ from rich.console import Console
8
+ from rich.text import Text
9
+
10
+ from .viewer_ui import VisualModeUI
11
+ from .viewer_input_handler import VisualModeInputHandler
12
+ from ..constants import RICH_STYLE_YELLOW
13
+
14
+ if TYPE_CHECKING:
15
+ pass
16
+
17
+
18
+ class VisualModeViewer:
19
+ """Main class for visual mode viewing of raw message content."""
20
+
21
+ def __init__(
22
+ self,
23
+ console: Console,
24
+ on_copy: Optional[Callable[[str], None]] = None,
25
+ ):
26
+ self._console = console
27
+ self._on_copy = on_copy
28
+ self._ui = VisualModeUI(console)
29
+ self._input_handler = VisualModeInputHandler(self._ui, on_copy=on_copy)
30
+
31
+ def set_messages(self, messages: List[Dict[str, Any]]):
32
+ self._ui.set_messages(messages)
33
+
34
+ def show(self):
35
+ if not self._ui._messages:
36
+ self._console.print(
37
+ Text("No messages to display in visual mode.", style=RICH_STYLE_YELLOW)
38
+ )
39
+ return
40
+
41
+ self._input_handler.run()
@@ -0,0 +1,315 @@
1
+ """Input handler for visual mode viewer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Optional, Callable
6
+
7
+ from prompt_toolkit import PromptSession
8
+ from prompt_toolkit.key_binding import KeyBindings
9
+ from prompt_toolkit.keys import Keys
10
+
11
+ from loguru import logger
12
+
13
+ if TYPE_CHECKING:
14
+ from .viewer_ui import VisualModeUI
15
+
16
+
17
+ class VisualModeInputHandler:
18
+ """Handles keyboard input for the visual mode viewer."""
19
+
20
+ def __init__(
21
+ self,
22
+ ui: VisualModeUI,
23
+ on_copy: Optional[Callable[[str], None]] = None,
24
+ ):
25
+ self._ui = ui
26
+ self._running = False
27
+ self._g_pressed = False
28
+ self._on_copy = on_copy
29
+
30
+ def _create_key_bindings(self) -> KeyBindings:
31
+ kb = KeyBindings()
32
+
33
+ @kb.add(Keys.Up)
34
+ @kb.add("k")
35
+ def _(event):
36
+ if self._ui._search_mode:
37
+ return
38
+ self._g_pressed = False
39
+ if self._ui.move_cursor("up"):
40
+ self._ui.render()
41
+
42
+ @kb.add(Keys.Down)
43
+ @kb.add("j")
44
+ def _(event):
45
+ if self._ui._search_mode:
46
+ return
47
+ self._g_pressed = False
48
+ if self._ui.move_cursor("down"):
49
+ self._ui.render()
50
+
51
+ @kb.add(Keys.Left)
52
+ @kb.add("h")
53
+ def _(event):
54
+ if self._ui._search_mode:
55
+ return
56
+ self._g_pressed = False
57
+ if self._ui.move_cursor("left"):
58
+ self._ui.render()
59
+
60
+ @kb.add(Keys.Right)
61
+ @kb.add("l")
62
+ def _(event):
63
+ if self._ui._search_mode:
64
+ return
65
+ self._g_pressed = False
66
+ if self._ui.move_cursor("right"):
67
+ self._ui.render()
68
+
69
+ @kb.add("w")
70
+ def _(event):
71
+ if self._ui._search_mode:
72
+ self._ui.append_search_char("w")
73
+ self._ui.render()
74
+ return
75
+ self._g_pressed = False
76
+ if self._ui.move_cursor("word_forward"):
77
+ self._ui.render()
78
+
79
+ @kb.add("b")
80
+ def _(event):
81
+ if self._ui._search_mode:
82
+ self._ui.append_search_char("b")
83
+ self._ui.render()
84
+ return
85
+ self._g_pressed = False
86
+ if self._ui.move_cursor("word_backward"):
87
+ self._ui.render()
88
+
89
+ @kb.add("0")
90
+ def _(event):
91
+ if self._ui._search_mode:
92
+ self._ui.append_search_char("0")
93
+ self._ui.render()
94
+ return
95
+ self._g_pressed = False
96
+ if self._ui.move_cursor("line_start"):
97
+ self._ui.render()
98
+
99
+ @kb.add("$")
100
+ def _(event):
101
+ if self._ui._search_mode:
102
+ self._ui.append_search_char("$")
103
+ self._ui.render()
104
+ return
105
+ self._g_pressed = False
106
+ if self._ui.move_cursor("line_end"):
107
+ self._ui.render()
108
+
109
+ @kb.add("g")
110
+ def _(event):
111
+ if self._ui._search_mode:
112
+ self._ui.append_search_char("g")
113
+ self._ui.render()
114
+ return
115
+ if self._g_pressed:
116
+ self._g_pressed = False
117
+ if self._ui.move_cursor("top"):
118
+ self._ui.render()
119
+ else:
120
+ self._g_pressed = True
121
+
122
+ @kb.add("G")
123
+ def _(event):
124
+ if self._ui._search_mode:
125
+ self._ui.append_search_char("G")
126
+ self._ui.render()
127
+ return
128
+ self._g_pressed = False
129
+ if self._ui.move_cursor("bottom"):
130
+ self._ui.render()
131
+
132
+ @kb.add(Keys.ControlU)
133
+ def _(event):
134
+ if self._ui._search_mode:
135
+ return
136
+ self._g_pressed = False
137
+ if self._ui.move_cursor("half_up"):
138
+ self._ui.render()
139
+
140
+ @kb.add(Keys.ControlD)
141
+ def _(event):
142
+ if self._ui._search_mode:
143
+ return
144
+ self._g_pressed = False
145
+ if self._ui.move_cursor("half_down"):
146
+ self._ui.render()
147
+
148
+ @kb.add(Keys.PageUp)
149
+ def _(event):
150
+ if self._ui._search_mode:
151
+ return
152
+ self._g_pressed = False
153
+ if self._ui.move_cursor("page_up"):
154
+ self._ui.render()
155
+
156
+ @kb.add(Keys.PageDown)
157
+ def _(event):
158
+ if self._ui._search_mode:
159
+ return
160
+ self._g_pressed = False
161
+ if self._ui.move_cursor("page_down"):
162
+ self._ui.render()
163
+
164
+ @kb.add("v")
165
+ def _(event):
166
+ if self._ui._search_mode:
167
+ self._ui.append_search_char("v")
168
+ self._ui.render()
169
+ return
170
+ self._g_pressed = False
171
+ self._ui.toggle_visual_mode()
172
+ self._ui.render()
173
+
174
+ @kb.add("y")
175
+ def _(event):
176
+ if self._ui._search_mode:
177
+ self._ui.append_search_char("y")
178
+ self._ui.render()
179
+ return
180
+ self._g_pressed = False
181
+ text = self._ui.get_selected_text()
182
+ if text and self._on_copy:
183
+ self._on_copy(text)
184
+ if self._ui._visual_mode:
185
+ self._ui.toggle_visual_mode()
186
+ self._ui.render()
187
+
188
+ @kb.add("Y")
189
+ def _(event):
190
+ if self._ui._search_mode:
191
+ self._ui.append_search_char("Y")
192
+ self._ui.render()
193
+ return
194
+ self._g_pressed = False
195
+ if 0 <= self._ui._cursor_line < len(self._ui._lines):
196
+ line_text = self._ui._lines[self._ui._cursor_line][0]
197
+ if self._on_copy:
198
+ self._on_copy(line_text)
199
+
200
+ @kb.add("/")
201
+ def _(event):
202
+ if self._ui._search_mode:
203
+ self._ui.append_search_char("/")
204
+ self._ui.render()
205
+ return
206
+ self._g_pressed = False
207
+ self._ui.start_search_mode()
208
+ self._ui.render()
209
+
210
+ @kb.add("n")
211
+ def _(event):
212
+ if self._ui._search_mode:
213
+ self._ui.append_search_char("n")
214
+ self._ui.render()
215
+ return
216
+ self._g_pressed = False
217
+ self._ui.next_search_match()
218
+ self._ui.render()
219
+
220
+ @kb.add("N")
221
+ def _(event):
222
+ if self._ui._search_mode:
223
+ self._ui.append_search_char("N")
224
+ self._ui.render()
225
+ return
226
+ self._g_pressed = False
227
+ self._ui.prev_search_match()
228
+ self._ui.render()
229
+
230
+ @kb.add(Keys.Enter)
231
+ def _(event):
232
+ if self._ui._search_mode:
233
+ self._ui.exit_search_mode(clear_results=False)
234
+ self._ui.render()
235
+
236
+ @kb.add(Keys.Backspace)
237
+ def _(event):
238
+ if self._ui._search_mode:
239
+ self._ui.backspace_search()
240
+ self._ui.render()
241
+
242
+ @kb.add(Keys.Escape)
243
+ def _(event):
244
+ self._g_pressed = False
245
+ if self._ui._visual_mode:
246
+ self._ui.toggle_visual_mode()
247
+ self._ui.render()
248
+ elif self._ui._search_mode:
249
+ self._ui.exit_search_mode(clear_results=True)
250
+ self._ui.render()
251
+ else:
252
+ event.app.exit()
253
+
254
+ @kb.add("q")
255
+ def _(event):
256
+ if self._ui._search_mode:
257
+ self._ui.append_search_char("q")
258
+ self._ui.render()
259
+ return
260
+ self._g_pressed = False
261
+ event.app.exit()
262
+
263
+ @kb.add(Keys.ControlC)
264
+ def _(event):
265
+ self._g_pressed = False
266
+ if self._ui._visual_mode:
267
+ text = self._ui.get_selected_text()
268
+ if text and self._on_copy:
269
+ self._on_copy(text)
270
+ self._ui.toggle_visual_mode()
271
+ self._ui.render()
272
+ elif self._ui._search_mode:
273
+ self._ui.exit_search_mode(clear_results=True)
274
+ self._ui.render()
275
+ else:
276
+ event.app.exit()
277
+
278
+ @kb.add(Keys.Any)
279
+ def _(event):
280
+ if self._ui._search_mode:
281
+ char = event.data
282
+ if char and char.isprintable():
283
+ self._ui.append_search_char(char)
284
+ self._ui.render()
285
+ return
286
+ self._g_pressed = False
287
+
288
+ return kb
289
+
290
+ def run(self):
291
+ self._running = True
292
+ self._g_pressed = False
293
+
294
+ self._ui.start_live()
295
+
296
+ kb = self._create_key_bindings()
297
+
298
+ try:
299
+ session = PromptSession(key_bindings=kb)
300
+ session.prompt("")
301
+ except (KeyboardInterrupt, EOFError):
302
+ pass
303
+ except Exception as e:
304
+ logger.error(f"Error in visual mode input handler: {e}")
305
+ finally:
306
+ self._ui.stop_live()
307
+
308
+ self._running = False
309
+
310
+ @property
311
+ def is_running(self) -> bool:
312
+ return self._running
313
+
314
+ def stop(self):
315
+ self._running = False