autobyteus 1.1.3__py3-none-any.whl → 1.1.5__py3-none-any.whl

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 (284) hide show
  1. autobyteus/agent/agent.py +1 -1
  2. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +4 -2
  3. autobyteus/agent/context/__init__.py +4 -2
  4. autobyteus/agent/context/agent_config.py +35 -8
  5. autobyteus/agent/context/agent_context_registry.py +73 -0
  6. autobyteus/agent/events/notifiers.py +4 -0
  7. autobyteus/agent/events/worker_event_dispatcher.py +1 -2
  8. autobyteus/agent/handlers/inter_agent_message_event_handler.py +8 -3
  9. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +19 -19
  10. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +2 -2
  11. autobyteus/agent/handlers/tool_result_event_handler.py +48 -20
  12. autobyteus/agent/handlers/user_input_message_event_handler.py +16 -1
  13. autobyteus/agent/input_processor/__init__.py +1 -7
  14. autobyteus/agent/message/context_file_type.py +6 -0
  15. autobyteus/agent/message/send_message_to.py +74 -99
  16. autobyteus/agent/phases/discover.py +2 -1
  17. autobyteus/agent/runtime/agent_runtime.py +10 -2
  18. autobyteus/agent/runtime/agent_worker.py +1 -0
  19. autobyteus/agent/sender_type.py +15 -0
  20. autobyteus/agent/streaming/agent_event_stream.py +6 -0
  21. autobyteus/agent/streaming/stream_event_payloads.py +12 -0
  22. autobyteus/agent/streaming/stream_events.py +3 -0
  23. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +7 -4
  24. autobyteus/agent/tool_execution_result_processor/__init__.py +9 -0
  25. autobyteus/agent/tool_execution_result_processor/base_processor.py +46 -0
  26. autobyteus/agent/tool_execution_result_processor/processor_definition.py +36 -0
  27. autobyteus/agent/tool_execution_result_processor/processor_meta.py +36 -0
  28. autobyteus/agent/tool_execution_result_processor/processor_registry.py +70 -0
  29. autobyteus/agent/workspace/base_workspace.py +17 -2
  30. autobyteus/agent_team/__init__.py +1 -0
  31. autobyteus/agent_team/agent_team.py +93 -0
  32. autobyteus/agent_team/agent_team_builder.py +184 -0
  33. autobyteus/agent_team/base_agent_team.py +86 -0
  34. autobyteus/agent_team/bootstrap_steps/__init__.py +24 -0
  35. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +73 -0
  36. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +54 -0
  37. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +25 -0
  38. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +23 -0
  39. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +41 -0
  40. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +85 -0
  41. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +51 -0
  42. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +45 -0
  43. autobyteus/agent_team/context/__init__.py +17 -0
  44. autobyteus/agent_team/context/agent_team_config.py +33 -0
  45. autobyteus/agent_team/context/agent_team_context.py +61 -0
  46. autobyteus/agent_team/context/agent_team_runtime_state.py +56 -0
  47. autobyteus/agent_team/context/team_manager.py +147 -0
  48. autobyteus/agent_team/context/team_node_config.py +76 -0
  49. autobyteus/agent_team/events/__init__.py +29 -0
  50. autobyteus/agent_team/events/agent_team_event_dispatcher.py +39 -0
  51. autobyteus/agent_team/events/agent_team_events.py +53 -0
  52. autobyteus/agent_team/events/agent_team_input_event_queue_manager.py +21 -0
  53. autobyteus/agent_team/exceptions.py +8 -0
  54. autobyteus/agent_team/factory/__init__.py +9 -0
  55. autobyteus/agent_team/factory/agent_team_factory.py +99 -0
  56. autobyteus/agent_team/handlers/__init__.py +19 -0
  57. autobyteus/agent_team/handlers/agent_team_event_handler_registry.py +23 -0
  58. autobyteus/agent_team/handlers/base_agent_team_event_handler.py +16 -0
  59. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +61 -0
  60. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +27 -0
  61. autobyteus/agent_team/handlers/process_user_message_event_handler.py +46 -0
  62. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +48 -0
  63. autobyteus/agent_team/phases/__init__.py +11 -0
  64. autobyteus/agent_team/phases/agent_team_operational_phase.py +19 -0
  65. autobyteus/agent_team/phases/agent_team_phase_manager.py +48 -0
  66. autobyteus/agent_team/runtime/__init__.py +13 -0
  67. autobyteus/agent_team/runtime/agent_team_runtime.py +82 -0
  68. autobyteus/agent_team/runtime/agent_team_worker.py +117 -0
  69. autobyteus/agent_team/shutdown_steps/__init__.py +17 -0
  70. autobyteus/agent_team/shutdown_steps/agent_team_shutdown_orchestrator.py +35 -0
  71. autobyteus/agent_team/shutdown_steps/agent_team_shutdown_step.py +42 -0
  72. autobyteus/agent_team/shutdown_steps/base_agent_team_shutdown_step.py +16 -0
  73. autobyteus/agent_team/shutdown_steps/bridge_cleanup_step.py +28 -0
  74. autobyteus/agent_team/shutdown_steps/sub_team_shutdown_step.py +41 -0
  75. autobyteus/agent_team/streaming/__init__.py +26 -0
  76. autobyteus/agent_team/streaming/agent_event_bridge.py +48 -0
  77. autobyteus/agent_team/streaming/agent_event_multiplexer.py +70 -0
  78. autobyteus/agent_team/streaming/agent_team_event_notifier.py +64 -0
  79. autobyteus/agent_team/streaming/agent_team_event_stream.py +33 -0
  80. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +32 -0
  81. autobyteus/agent_team/streaming/agent_team_stream_events.py +56 -0
  82. autobyteus/agent_team/streaming/team_event_bridge.py +50 -0
  83. autobyteus/agent_team/task_notification/__init__.py +11 -0
  84. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +164 -0
  85. autobyteus/agent_team/task_notification/task_notification_mode.py +24 -0
  86. autobyteus/agent_team/utils/__init__.py +9 -0
  87. autobyteus/agent_team/utils/wait_for_idle.py +46 -0
  88. autobyteus/cli/__init__.py +1 -1
  89. autobyteus/cli/agent_team_tui/__init__.py +4 -0
  90. autobyteus/cli/agent_team_tui/app.py +210 -0
  91. autobyteus/cli/agent_team_tui/state.py +180 -0
  92. autobyteus/cli/agent_team_tui/widgets/__init__.py +6 -0
  93. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +149 -0
  94. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +320 -0
  95. autobyteus/cli/agent_team_tui/widgets/logo.py +20 -0
  96. autobyteus/cli/agent_team_tui/widgets/renderables.py +77 -0
  97. autobyteus/cli/agent_team_tui/widgets/shared.py +60 -0
  98. autobyteus/cli/agent_team_tui/widgets/status_bar.py +14 -0
  99. autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +82 -0
  100. autobyteus/cli/cli_display.py +1 -1
  101. autobyteus/cli/workflow_tui/__init__.py +4 -0
  102. autobyteus/cli/workflow_tui/app.py +210 -0
  103. autobyteus/cli/workflow_tui/state.py +189 -0
  104. autobyteus/cli/workflow_tui/widgets/__init__.py +6 -0
  105. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +149 -0
  106. autobyteus/cli/workflow_tui/widgets/focus_pane.py +335 -0
  107. autobyteus/cli/workflow_tui/widgets/logo.py +27 -0
  108. autobyteus/cli/workflow_tui/widgets/renderables.py +70 -0
  109. autobyteus/cli/workflow_tui/widgets/shared.py +51 -0
  110. autobyteus/cli/workflow_tui/widgets/status_bar.py +14 -0
  111. autobyteus/events/event_types.py +8 -0
  112. autobyteus/llm/api/autobyteus_llm.py +11 -12
  113. autobyteus/llm/api/lmstudio_llm.py +34 -0
  114. autobyteus/llm/api/ollama_llm.py +8 -13
  115. autobyteus/llm/api/openai_compatible_llm.py +20 -3
  116. autobyteus/llm/autobyteus_provider.py +73 -46
  117. autobyteus/llm/llm_factory.py +103 -139
  118. autobyteus/llm/lmstudio_provider.py +104 -0
  119. autobyteus/llm/models.py +83 -53
  120. autobyteus/llm/ollama_provider.py +69 -61
  121. autobyteus/llm/ollama_provider_resolver.py +1 -0
  122. autobyteus/llm/providers.py +13 -12
  123. autobyteus/llm/runtimes.py +11 -0
  124. autobyteus/llm/token_counter/token_counter_factory.py +2 -0
  125. autobyteus/task_management/__init__.py +43 -0
  126. autobyteus/task_management/base_task_board.py +68 -0
  127. autobyteus/task_management/converters/__init__.py +11 -0
  128. autobyteus/task_management/converters/task_board_converter.py +64 -0
  129. autobyteus/task_management/converters/task_plan_converter.py +48 -0
  130. autobyteus/task_management/deliverable.py +16 -0
  131. autobyteus/task_management/deliverables/__init__.py +8 -0
  132. autobyteus/task_management/deliverables/file_deliverable.py +15 -0
  133. autobyteus/task_management/events.py +27 -0
  134. autobyteus/task_management/in_memory_task_board.py +126 -0
  135. autobyteus/task_management/schemas/__init__.py +15 -0
  136. autobyteus/task_management/schemas/deliverable_schema.py +13 -0
  137. autobyteus/task_management/schemas/plan_definition.py +35 -0
  138. autobyteus/task_management/schemas/task_status_report.py +27 -0
  139. autobyteus/task_management/task_plan.py +110 -0
  140. autobyteus/task_management/tools/__init__.py +14 -0
  141. autobyteus/task_management/tools/get_task_board_status.py +68 -0
  142. autobyteus/task_management/tools/publish_task_plan.py +113 -0
  143. autobyteus/task_management/tools/update_task_status.py +135 -0
  144. autobyteus/tools/__init__.py +2 -0
  145. autobyteus/tools/ask_user_input.py +2 -1
  146. autobyteus/tools/bash/bash_executor.py +61 -15
  147. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +2 -0
  148. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +3 -0
  149. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +3 -0
  150. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +3 -0
  151. autobyteus/tools/browser/standalone/google_search_ui.py +2 -0
  152. autobyteus/tools/browser/standalone/navigate_to.py +2 -0
  153. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +3 -0
  154. autobyteus/tools/browser/standalone/webpage_image_downloader.py +3 -0
  155. autobyteus/tools/browser/standalone/webpage_reader.py +2 -0
  156. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +3 -0
  157. autobyteus/tools/file/file_reader.py +36 -9
  158. autobyteus/tools/file/file_writer.py +37 -9
  159. autobyteus/tools/functional_tool.py +5 -4
  160. autobyteus/tools/image_downloader.py +2 -0
  161. autobyteus/tools/mcp/config_service.py +63 -58
  162. autobyteus/tools/mcp/server/http_managed_mcp_server.py +14 -2
  163. autobyteus/tools/mcp/server/stdio_managed_mcp_server.py +14 -2
  164. autobyteus/tools/mcp/server_instance_manager.py +30 -4
  165. autobyteus/tools/mcp/tool_registrar.py +106 -51
  166. autobyteus/tools/parameter_schema.py +17 -11
  167. autobyteus/tools/pdf_downloader.py +2 -1
  168. autobyteus/tools/registry/tool_definition.py +36 -37
  169. autobyteus/tools/registry/tool_registry.py +50 -2
  170. autobyteus/tools/timer.py +2 -0
  171. autobyteus/tools/tool_category.py +15 -4
  172. autobyteus/tools/tool_meta.py +6 -1
  173. autobyteus/tools/tool_origin.py +10 -0
  174. autobyteus/tools/usage/formatters/default_json_example_formatter.py +78 -3
  175. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +23 -3
  176. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +6 -0
  177. autobyteus/tools/usage/formatters/google_json_example_formatter.py +7 -0
  178. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +6 -4
  179. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +23 -7
  180. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +14 -25
  181. autobyteus/tools/usage/providers/__init__.py +2 -12
  182. autobyteus/tools/usage/providers/tool_manifest_provider.py +36 -29
  183. autobyteus/tools/usage/registries/__init__.py +7 -12
  184. autobyteus/tools/usage/registries/tool_formatter_pair.py +15 -0
  185. autobyteus/tools/usage/registries/tool_formatting_registry.py +58 -0
  186. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +55 -0
  187. autobyteus/workflow/agentic_workflow.py +93 -0
  188. autobyteus/{agent/workflow → workflow}/base_agentic_workflow.py +19 -27
  189. autobyteus/workflow/bootstrap_steps/__init__.py +20 -0
  190. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +34 -0
  191. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +23 -0
  192. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +41 -0
  193. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +108 -0
  194. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +50 -0
  195. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +25 -0
  196. autobyteus/workflow/context/__init__.py +17 -0
  197. autobyteus/workflow/context/team_manager.py +147 -0
  198. autobyteus/workflow/context/workflow_config.py +30 -0
  199. autobyteus/workflow/context/workflow_context.py +61 -0
  200. autobyteus/workflow/context/workflow_node_config.py +76 -0
  201. autobyteus/workflow/context/workflow_runtime_state.py +53 -0
  202. autobyteus/workflow/events/__init__.py +29 -0
  203. autobyteus/workflow/events/workflow_event_dispatcher.py +39 -0
  204. autobyteus/workflow/events/workflow_events.py +53 -0
  205. autobyteus/workflow/events/workflow_input_event_queue_manager.py +21 -0
  206. autobyteus/workflow/exceptions.py +8 -0
  207. autobyteus/workflow/factory/__init__.py +9 -0
  208. autobyteus/workflow/factory/workflow_factory.py +99 -0
  209. autobyteus/workflow/handlers/__init__.py +19 -0
  210. autobyteus/workflow/handlers/base_workflow_event_handler.py +16 -0
  211. autobyteus/workflow/handlers/inter_agent_message_request_event_handler.py +61 -0
  212. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +27 -0
  213. autobyteus/workflow/handlers/process_user_message_event_handler.py +46 -0
  214. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +39 -0
  215. autobyteus/workflow/handlers/workflow_event_handler_registry.py +23 -0
  216. autobyteus/workflow/phases/__init__.py +11 -0
  217. autobyteus/workflow/phases/workflow_operational_phase.py +19 -0
  218. autobyteus/workflow/phases/workflow_phase_manager.py +48 -0
  219. autobyteus/workflow/runtime/__init__.py +13 -0
  220. autobyteus/workflow/runtime/workflow_runtime.py +82 -0
  221. autobyteus/workflow/runtime/workflow_worker.py +117 -0
  222. autobyteus/workflow/shutdown_steps/__init__.py +17 -0
  223. autobyteus/workflow/shutdown_steps/agent_team_shutdown_step.py +42 -0
  224. autobyteus/workflow/shutdown_steps/base_workflow_shutdown_step.py +16 -0
  225. autobyteus/workflow/shutdown_steps/bridge_cleanup_step.py +28 -0
  226. autobyteus/workflow/shutdown_steps/sub_workflow_shutdown_step.py +41 -0
  227. autobyteus/workflow/shutdown_steps/workflow_shutdown_orchestrator.py +35 -0
  228. autobyteus/workflow/streaming/__init__.py +26 -0
  229. autobyteus/workflow/streaming/agent_event_bridge.py +48 -0
  230. autobyteus/workflow/streaming/agent_event_multiplexer.py +70 -0
  231. autobyteus/workflow/streaming/workflow_event_bridge.py +50 -0
  232. autobyteus/workflow/streaming/workflow_event_notifier.py +83 -0
  233. autobyteus/workflow/streaming/workflow_event_stream.py +33 -0
  234. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +28 -0
  235. autobyteus/workflow/streaming/workflow_stream_events.py +45 -0
  236. autobyteus/workflow/utils/__init__.py +9 -0
  237. autobyteus/workflow/utils/wait_for_idle.py +46 -0
  238. autobyteus/workflow/workflow_builder.py +151 -0
  239. {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/METADATA +16 -14
  240. autobyteus-1.1.5.dist-info/RECORD +455 -0
  241. {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/top_level.txt +1 -0
  242. examples/__init__.py +1 -0
  243. examples/agent_team/__init__.py +1 -0
  244. examples/discover_phase_transitions.py +104 -0
  245. examples/run_browser_agent.py +262 -0
  246. examples/run_google_slides_agent.py +287 -0
  247. examples/run_mcp_browser_client.py +174 -0
  248. examples/run_mcp_google_slides_client.py +270 -0
  249. examples/run_mcp_list_tools.py +189 -0
  250. examples/run_poem_writer.py +284 -0
  251. examples/run_sqlite_agent.py +295 -0
  252. autobyteus/agent/context/agent_phase_manager.py +0 -264
  253. autobyteus/agent/context/phases.py +0 -49
  254. autobyteus/agent/group/__init__.py +0 -0
  255. autobyteus/agent/group/agent_group.py +0 -164
  256. autobyteus/agent/group/agent_group_context.py +0 -81
  257. autobyteus/agent/input_processor/content_prefixing_input_processor.py +0 -41
  258. autobyteus/agent/input_processor/metadata_appending_input_processor.py +0 -34
  259. autobyteus/agent/input_processor/passthrough_input_processor.py +0 -33
  260. autobyteus/agent/workflow/__init__.py +0 -11
  261. autobyteus/agent/workflow/agentic_workflow.py +0 -89
  262. autobyteus/tools/mcp/call_handlers/__init__.py +0 -16
  263. autobyteus/tools/mcp/call_handlers/base_handler.py +0 -40
  264. autobyteus/tools/mcp/call_handlers/stdio_handler.py +0 -76
  265. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +0 -55
  266. autobyteus/tools/mcp/registrar.py +0 -202
  267. autobyteus/tools/usage/providers/json_example_provider.py +0 -32
  268. autobyteus/tools/usage/providers/json_schema_provider.py +0 -35
  269. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +0 -28
  270. autobyteus/tools/usage/providers/xml_example_provider.py +0 -28
  271. autobyteus/tools/usage/providers/xml_schema_provider.py +0 -29
  272. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +0 -26
  273. autobyteus/tools/usage/registries/json_example_formatter_registry.py +0 -51
  274. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +0 -51
  275. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +0 -42
  276. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +0 -30
  277. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +0 -33
  278. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +0 -30
  279. autobyteus/workflow/simple_task.py +0 -98
  280. autobyteus/workflow/task.py +0 -147
  281. autobyteus/workflow/workflow.py +0 -49
  282. autobyteus-1.1.3.dist-info/RECORD +0 -312
  283. {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/WHEEL +0 -0
  284. {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,113 @@
1
+ # file: autobyteus/autobyteus/task_management/tools/publish_task_plan.py
2
+ import json
3
+ import logging
4
+ from typing import TYPE_CHECKING, Optional, Dict, Any
5
+
6
+ from pydantic import ValidationError
7
+ # No longer need GenerateJsonSchema from pydantic.json_schema
8
+ # from pydantic.json_schema import GenerateJsonSchema
9
+
10
+ from autobyteus.tools.base_tool import BaseTool
11
+ from autobyteus.tools.tool_category import ToolCategory
12
+ from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
13
+ from autobyteus.task_management.schemas import TaskPlanDefinitionSchema
14
+ from autobyteus.task_management.converters import TaskPlanConverter, TaskBoardConverter
15
+
16
+ if TYPE_CHECKING:
17
+ from autobyteus.agent.context import AgentContext
18
+ from autobyteus.agent_team.context import AgentTeamContext
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ class PublishTaskPlan(BaseTool):
23
+ """A tool for the coordinator to parse and load a generated plan into the TaskBoard."""
24
+
25
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
26
+
27
+ # The failing custom InlineSchemaGenerator has been removed.
28
+
29
+ @classmethod
30
+ def get_name(cls) -> str:
31
+ return "PublishTaskPlan"
32
+
33
+ @classmethod
34
+ def get_description(cls) -> str:
35
+ return (
36
+ "Parses a structured object representing a complete task plan, converts it into a "
37
+ "system-ready format, and loads it onto the team's shared task board. "
38
+ "This action resets the task board with the new plan. Upon success, it returns "
39
+ "the initial status of the newly loaded task board. "
40
+ "This tool should typically only be used by the team coordinator."
41
+ )
42
+
43
+ @classmethod
44
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
45
+ schema = ParameterSchema()
46
+
47
+ # CORRECTED IMPLEMENTATION:
48
+ # A direct, standard call to model_json_schema(). This generates a valid
49
+ # JSON schema with $refs, which the framework handles correctly.
50
+ # This completely avoids the TypeError caused by the unsupported 'ref_strategy' argument.
51
+ object_json_schema = TaskPlanDefinitionSchema.model_json_schema()
52
+
53
+ schema.add_parameter(ParameterDefinition(
54
+ name="plan",
55
+ param_type=ParameterType.OBJECT,
56
+ description=(
57
+ "A structured object representing a complete task plan. This object defines the overall goal "
58
+ "and a list of tasks with their assignees, descriptions, and dependencies. "
59
+ "Each task must have a unique name within the plan."
60
+ ),
61
+ required=True,
62
+ object_schema=object_json_schema
63
+ ))
64
+ return schema
65
+
66
+ async def _execute(self, context: 'AgentContext', plan: Dict[str, Any]) -> str:
67
+ """
68
+ Executes the tool by validating the plan object, using a converter to create a TaskPlan,
69
+ and loading it onto the task board.
70
+ """
71
+ logger.info(f"Agent '{context.agent_id}' is executing PublishTaskPlan.")
72
+
73
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
74
+ if not team_context:
75
+ error_msg = "Error: Team context is not available. Cannot access the task board."
76
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
77
+ return error_msg
78
+
79
+ task_board = getattr(team_context.state, 'task_board', None)
80
+ if not task_board:
81
+ error_msg = "Error: Task board has not been initialized for this team."
82
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
83
+ return error_msg
84
+
85
+ try:
86
+ # Step 1: The input is now a dictionary, so we can directly validate it.
87
+ plan_definition_schema = TaskPlanDefinitionSchema(**plan)
88
+
89
+ # Step 2: Use the dedicated converter to create the internal TaskPlan object.
90
+ final_plan = TaskPlanConverter.from_schema(plan_definition_schema)
91
+
92
+ except (ValidationError, ValueError) as e:
93
+ error_msg = f"Invalid or inconsistent task plan provided: {e}"
94
+ logger.warning(f"Agent '{context.agent_id}' provided an invalid plan for PublishTaskPlan: {error_msg}")
95
+ return f"Error: {error_msg}"
96
+ except Exception as e:
97
+ error_msg = f"An unexpected error occurred during plan parsing or conversion: {e}"
98
+ logger.error(f"Agent '{context.agent_id}': {error_msg}", exc_info=True)
99
+ return f"Error: {error_msg}"
100
+
101
+ if task_board.load_task_plan(final_plan):
102
+ logger.info(f"Agent '{context.agent_id}': Task plan published successfully. Returning new board status.")
103
+ # Convert the new state of the board back to an LLM-friendly schema and return it.
104
+ status_report_schema = TaskBoardConverter.to_schema(task_board)
105
+ if status_report_schema:
106
+ return status_report_schema.model_dump_json(indent=2)
107
+ else:
108
+ # This is a fallback case, shouldn't happen right after a successful load.
109
+ return "Task plan published successfully, but could not generate status report."
110
+ else:
111
+ error_msg = "Failed to load task plan onto the board. This can happen if the board implementation rejects the plan."
112
+ logger.error(f"Agent '{context.agent_id}': {error_msg}")
113
+ return f"Error: {error_msg}"
@@ -0,0 +1,135 @@
1
+ import logging
2
+ from typing import TYPE_CHECKING, Optional, List, Dict, Any
3
+
4
+ from pydantic import ValidationError
5
+
6
+ from autobyteus.tools.base_tool import BaseTool
7
+ from autobyteus.tools.tool_category import ToolCategory
8
+ from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.task_management.base_task_board import TaskStatus
10
+ from autobyteus.task_management.deliverable import FileDeliverable
11
+ from autobyteus.task_management.schemas import FileDeliverableSchema
12
+
13
+ if TYPE_CHECKING:
14
+ from autobyteus.agent.context import AgentContext
15
+ from autobyteus.agent_team.context import AgentTeamContext
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ class UpdateTaskStatus(BaseTool):
20
+ """A tool for member agents to update their progress and submit file deliverables on the TaskBoard."""
21
+
22
+ CATEGORY = ToolCategory.TASK_MANAGEMENT
23
+
24
+ @classmethod
25
+ def get_name(cls) -> str:
26
+ return "UpdateTaskStatus"
27
+
28
+ @classmethod
29
+ def get_description(cls) -> str:
30
+ return (
31
+ "Updates the status of a specific task on the team's shared task board. "
32
+ "When completing a task, this tool can also be used to formally submit a list of file deliverables."
33
+ )
34
+
35
+ @classmethod
36
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
37
+ schema = ParameterSchema()
38
+ schema.add_parameter(ParameterDefinition(
39
+ name="task_name",
40
+ param_type=ParameterType.STRING,
41
+ description="The unique name of the task to update (e.g., 'implement_scraper').",
42
+ required=True
43
+ ))
44
+ schema.add_parameter(ParameterDefinition(
45
+ name="status",
46
+ param_type=ParameterType.ENUM,
47
+ description=f"The new status for the task. Must be one of: {', '.join([s.value for s in TaskStatus])}.",
48
+ required=True,
49
+ enum_values=[s.value for s in TaskStatus]
50
+ ))
51
+ schema.add_parameter(ParameterDefinition(
52
+ name="deliverables",
53
+ param_type=ParameterType.ARRAY,
54
+ description="Optional. A list of file deliverables to submit for this task, typically when status is 'completed'. Each deliverable must include a file_path and a summary.",
55
+ required=False,
56
+ array_item_schema=FileDeliverableSchema.model_json_schema()
57
+ ))
58
+ return schema
59
+
60
+ async def _execute(self, context: 'AgentContext', task_name: str, status: str, deliverables: Optional[List[Dict[str, Any]]] = None) -> str:
61
+ """
62
+ Executes the tool to update a task's status and optionally submit deliverables.
63
+ """
64
+ agent_name = context.config.name
65
+ log_msg = f"Agent '{agent_name}' is executing UpdateTaskStatus for task '{task_name}' to status '{status}'"
66
+ if deliverables:
67
+ log_msg += f" with {len(deliverables)} deliverable(s)."
68
+ logger.info(log_msg)
69
+
70
+ team_context: Optional['AgentTeamContext'] = context.custom_data.get("team_context")
71
+ if not team_context:
72
+ error_msg = "Error: Team context is not available. Cannot access the task board."
73
+ logger.error(f"Agent '{agent_name}': {error_msg}")
74
+ return error_msg
75
+
76
+ task_board = getattr(team_context.state, 'task_board', None)
77
+ if not task_board:
78
+ error_msg = "Error: Task board has not been initialized for this team."
79
+ logger.error(f"Agent '{agent_name}': {error_msg}")
80
+ return error_msg
81
+
82
+ if not task_board.current_plan:
83
+ error_msg = "Error: No task plan is currently loaded on the task board."
84
+ logger.warning(f"Agent '{agent_name}' tried to update task status, but no plan is loaded.")
85
+ return error_msg
86
+
87
+ # Find the task by name
88
+ target_task = None
89
+ for task in task_board.current_plan.tasks:
90
+ if task.task_name == task_name:
91
+ target_task = task
92
+ break
93
+
94
+ if not target_task:
95
+ error_msg = f"Failed to update status for task '{task_name}'. The task name does not exist on the current plan."
96
+ logger.warning(f"Agent '{agent_name}' failed to update status for non-existent task '{task_name}'.")
97
+ return f"Error: {error_msg}"
98
+
99
+ try:
100
+ status_enum = TaskStatus(status)
101
+ except ValueError:
102
+ error_msg = f"Invalid status '{status}'. Must be one of: {', '.join([s.value for s in TaskStatus])}."
103
+ logger.warning(f"Agent '{agent_name}' provided invalid status for UpdateTaskStatus: {status}")
104
+ return f"Error: {error_msg}"
105
+
106
+ # --- Process Deliverables FIRST --- (CORRECTED ORDER)
107
+ if deliverables:
108
+ try:
109
+ for d_data in deliverables:
110
+ # Validate and create the internal deliverable object
111
+ deliverable_schema = FileDeliverableSchema(**d_data)
112
+ full_deliverable = FileDeliverable(
113
+ **deliverable_schema.model_dump(),
114
+ author_agent_name=agent_name
115
+ )
116
+ # Append to the task object
117
+ target_task.file_deliverables.append(full_deliverable)
118
+ logger.info(f"Agent '{agent_name}' successfully processed and added {len(deliverables)} deliverables to task '{task_name}'.")
119
+ except (ValidationError, TypeError) as e:
120
+ error_msg = f"Failed to process deliverables due to invalid data: {e}. Task status was NOT updated."
121
+ logger.warning(f"Agent '{agent_name}': {error_msg}")
122
+ return f"Error: {error_msg}"
123
+
124
+ # --- Update Status SECOND --- (CORRECTED ORDER)
125
+ # This will now emit an event with the deliverables already attached to the task.
126
+ if not task_board.update_task_status(target_task.task_id, status_enum, agent_name):
127
+ error_msg = f"Failed to update status for task '{task_name}'. An unexpected error occurred on the task board."
128
+ logger.error(f"Agent '{agent_name}': {error_msg}")
129
+ return f"Error: {error_msg}"
130
+
131
+ success_msg = f"Successfully updated status of task '{task_name}' to '{status}'."
132
+ if deliverables:
133
+ success_msg += f" and submitted {len(deliverables)} deliverable(s)."
134
+ logger.info(f"Agent '{agent_name}': {success_msg}")
135
+ return success_msg
@@ -10,6 +10,7 @@ from .base_tool import BaseTool
10
10
  from .functional_tool import tool # The @tool decorator
11
11
  from .parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
12
12
  from .tool_config import ToolConfig # Configuration data object, primarily for class-based tools
13
+ from .tool_origin import ToolOrigin
13
14
  from .tool_category import ToolCategory
14
15
 
15
16
  # --- Re-export specific tools for easier access ---
@@ -48,6 +49,7 @@ __all__ = [
48
49
  "ParameterDefinition",
49
50
  "ParameterType",
50
51
  "ToolConfig",
52
+ "ToolOrigin",
51
53
  "ToolCategory",
52
54
 
53
55
  # Re-exported functional tool instances
@@ -3,13 +3,14 @@ import logging
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from autobyteus.tools import tool # Main @tool decorator
6
+ from autobyteus.tools.tool_category import ToolCategory
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from autobyteus.agent.context import AgentContext
9
10
 
10
11
  logger = logging.getLogger(__name__)
11
12
 
12
- @tool(name="AskUserInput") # Explicit name matching the old class name
13
+ @tool(name="AskUserInput", category=ToolCategory.USER_INTERACTION)
13
14
  async def ask_user_input(context: 'AgentContext', request: str) -> str: # Function name can be ask_user_input
14
15
  """
15
16
  Requests input from the user based on a given prompt and returns the user's textual response.
@@ -1,37 +1,73 @@
1
1
  import asyncio
2
2
  import subprocess
3
3
  import logging
4
+ import shutil
5
+ import tempfile
4
6
  from typing import TYPE_CHECKING, Optional
5
7
 
6
8
  from autobyteus.tools import tool
9
+ from autobyteus.tools.tool_category import ToolCategory
7
10
 
8
11
  if TYPE_CHECKING:
9
12
  from autobyteus.agent.context import AgentContext
10
13
 
11
14
  logger = logging.getLogger(__name__)
12
15
 
13
- @tool(name="BashExecutor")
14
- async def bash_executor(context: Optional['AgentContext'], command: str, cwd: Optional[str] = None) -> str:
16
+ @tool(name="BashExecutor", category=ToolCategory.SYSTEM)
17
+ async def bash_executor(context: Optional['AgentContext'], command: str) -> str:
15
18
  """
16
- Executes bash commands and retrieves their standard output.
19
+ Executes bash commands using the '/bin/bash' interpreter.
20
+ On success, it returns a formatted string containing the command's standard output (stdout) and/or diagnostic logs.
21
+ On failure, it raises an exception.
22
+ - If a command has only stdout, its content is returned directly.
23
+ - If a command has diagnostic output (from stderr), it will be included and labeled as 'LOGS' in the output.
17
24
  'command' is the bash command string to be executed.
18
- 'cwd' is the optional directory to run the command in.
19
- Errors during command execution are raised as exceptions.
25
+ The command is executed in the agent's workspace directory if available.
20
26
  """
27
+ if not shutil.which("bash"):
28
+ error_msg = "'bash' executable not found in system PATH. The BashExecutor tool cannot be used."
29
+ logger.error(error_msg)
30
+ raise FileNotFoundError(error_msg)
31
+
21
32
  agent_id_str = context.agent_id if context else "Non-Agent"
22
- logger.debug(f"Functional BashExecutor tool executing for '{agent_id_str}': {command} in cwd: {cwd or 'default'}")
33
+
34
+ effective_cwd = None
35
+ log_cwd_source = ""
36
+
37
+ if context and hasattr(context, 'workspace') and context.workspace:
38
+ try:
39
+ base_path = context.workspace.get_base_path()
40
+ if base_path and isinstance(base_path, str):
41
+ effective_cwd = base_path
42
+ log_cwd_source = f"agent workspace: {effective_cwd}"
43
+ else:
44
+ logger.warning(f"Agent '{agent_id_str}' has a workspace, but it provided an invalid base path ('{base_path}'). "
45
+ f"Falling back to system temporary directory.")
46
+ except Exception as e:
47
+ logger.warning(f"Could not retrieve workspace for agent '{agent_id_str}': {e}. "
48
+ f"Falling back to system temporary directory.")
49
+
50
+ if not effective_cwd:
51
+ effective_cwd = tempfile.gettempdir()
52
+ log_cwd_source = f"system temporary directory: {effective_cwd}"
53
+
54
+ logger.debug(f"Functional BashExecutor tool executing for '{agent_id_str}': {command} in cwd from {log_cwd_source}")
23
55
 
24
56
  try:
25
- process = await asyncio.create_subprocess_shell(
26
- command,
57
+ # Explicitly use 'bash -c' for reliable execution
58
+ process = await asyncio.create_subprocess_exec(
59
+ 'bash', '-c', command,
27
60
  stdout=asyncio.subprocess.PIPE,
28
61
  stderr=asyncio.subprocess.PIPE,
29
- cwd=cwd
62
+ cwd=effective_cwd
30
63
  )
31
64
  stdout, stderr = await process.communicate()
65
+
66
+ stdout_output = stdout.decode().strip() if stdout else ""
67
+ stderr_output = stderr.decode().strip() if stderr else ""
32
68
 
33
69
  if process.returncode != 0:
34
- error_message = stderr.decode().strip() if stderr else "Unknown error"
70
+ error_message = stderr_output if stderr_output else "Unknown error"
35
71
  if not error_message and process.returncode != 0:
36
72
  error_message = f"Command failed with exit code {process.returncode} and no stderr output."
37
73
 
@@ -39,16 +75,26 @@ async def bash_executor(context: Optional['AgentContext'], command: str, cwd: Op
39
75
  raise subprocess.CalledProcessError(
40
76
  returncode=process.returncode,
41
77
  cmd=command,
42
- output=stdout.decode().strip() if stdout else "",
78
+ output=stdout_output,
43
79
  stderr=error_message
44
80
  )
45
-
46
- output = stdout.decode().strip() if stdout else ""
47
- logger.debug(f"Command '{command}' output: {output}")
48
- return output
81
+
82
+ # Adaptive return for successful commands to provide maximum context to the agent.
83
+ if stdout_output and stderr_output:
84
+ return f"STDOUT:\n{stdout_output}\n\nLOGS:\n{stderr_output}"
85
+ elif stdout_output:
86
+ return stdout_output # Keep it simple for commands with only stdout
87
+ elif stderr_output:
88
+ return f"LOGS:\n{stderr_output}"
89
+ else:
90
+ return "Command executed successfully with no output."
49
91
 
50
92
  except subprocess.CalledProcessError:
51
93
  raise
94
+ except FileNotFoundError:
95
+ # This can be raised by create_subprocess_exec if 'bash' is not found, despite the initial check.
96
+ logger.error("'bash' executable not found when attempting to execute command. Please ensure it is installed and in the PATH.")
97
+ raise
52
98
  except Exception as e:
53
99
  logger.exception(f"An error occurred while preparing or executing command '{command}': {str(e)}")
54
100
  raise RuntimeError(f"Failed to execute command '{command}': {str(e)}")
@@ -1,6 +1,7 @@
1
1
  from autobyteus.tools.browser.session_aware.browser_session_aware_tool import BrowserSessionAwareTool
2
2
  from autobyteus.tools.browser.session_aware.shared_browser_session import SharedBrowserSession
3
3
  from autobyteus.tools.tool_config import ToolConfig
4
+ from autobyteus.tools.tool_category import ToolCategory
4
5
  from urllib.parse import urlparse
5
6
  from typing import Optional, TYPE_CHECKING, Any
6
7
  import logging
@@ -16,6 +17,7 @@ class BrowserSessionAwareNavigateTo(BrowserSessionAwareTool):
16
17
  """
17
18
  A session-aware tool for navigating to a specified website using a shared browser session.
18
19
  """
20
+ CATEGORY = ToolCategory.WEB
19
21
 
20
22
  def __init__(self, config: Optional[ToolConfig] = None):
21
23
  super().__init__(config=config)
@@ -9,6 +9,7 @@ from autobyteus.tools.browser.session_aware.shared_browser_session import Shared
9
9
  from autobyteus.tools.browser.session_aware.web_element_action import WebElementAction
10
10
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
11
  from autobyteus.tools.tool_config import ToolConfig
12
+ from autobyteus.tools.tool_category import ToolCategory
12
13
 
13
14
  if TYPE_CHECKING:
14
15
  pass
@@ -19,6 +20,8 @@ class BrowserSessionAwareWebElementTrigger(BrowserSessionAwareTool):
19
20
  """
20
21
  A session-aware tool to trigger actions on web elements identified by a CSS selector.
21
22
  """
23
+ CATEGORY = ToolCategory.WEB
24
+
22
25
  def __init__(self, config: Optional[ToolConfig] = None):
23
26
  super().__init__(config=config)
24
27
  logger.debug("BrowserSessionAwareWebElementTrigger tool initialized.")
@@ -6,6 +6,7 @@ from autobyteus.tools.browser.session_aware.browser_session_aware_tool import Br
6
6
  from autobyteus.tools.browser.session_aware.shared_browser_session import SharedBrowserSession
7
7
  from autobyteus.tools.tool_config import ToolConfig
8
8
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
9
+ from autobyteus.tools.tool_category import ToolCategory
9
10
  from autobyteus.utils.html_cleaner import clean, CleaningMode
10
11
 
11
12
  if TYPE_CHECKING:
@@ -18,6 +19,8 @@ class BrowserSessionAwareWebPageReader(BrowserSessionAwareTool):
18
19
  A session-aware tool to read and clean HTML content from the current page
19
20
  in a shared browser session.
20
21
  """
22
+ CATEGORY = ToolCategory.WEB
23
+
21
24
  def __init__(self, config: Optional[ToolConfig] = None):
22
25
  super().__init__(config=config)
23
26
 
@@ -7,6 +7,7 @@ from autobyteus.tools.browser.session_aware.browser_session_aware_tool import Br
7
7
  from autobyteus.tools.browser.session_aware.shared_browser_session import SharedBrowserSession
8
8
  from autobyteus.tools.tool_config import ToolConfig
9
9
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
10
+ from autobyteus.tools.tool_category import ToolCategory
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from autobyteus.agent.context import AgentContext
@@ -17,6 +18,8 @@ class BrowserSessionAwareWebPageScreenshotTaker(BrowserSessionAwareTool):
17
18
  """
18
19
  A session-aware tool to take a screenshot of the current page in a shared browser session.
19
20
  """
21
+ CATEGORY = ToolCategory.WEB
22
+
20
23
  def __init__(self, config: Optional[ToolConfig] = None):
21
24
  super().__init__(config=config)
22
25
 
@@ -9,6 +9,7 @@ from typing import Optional, TYPE_CHECKING, Any
9
9
  from autobyteus.tools.base_tool import BaseTool
10
10
  from autobyteus.tools.tool_config import ToolConfig
11
11
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
12
+ from autobyteus.tools.tool_category import ToolCategory
12
13
  from brui_core.ui_integrator import UIIntegrator
13
14
  from autobyteus.utils.html_cleaner import clean, CleaningMode
14
15
 
@@ -22,6 +23,7 @@ class GoogleSearch(BaseTool, UIIntegrator): # Multiple inheritance
22
23
  A tool that allows for performing a Google search using Playwright and retrieving the search results.
23
24
  Inherits from BaseTool for tool framework compatibility and UIIntegrator for Playwright integration.
24
25
  """
26
+ CATEGORY = ToolCategory.WEB
25
27
 
26
28
  def __init__(self, config: Optional[ToolConfig] = None):
27
29
  BaseTool.__init__(self, config=config)
@@ -1,5 +1,6 @@
1
1
  from autobyteus.tools.base_tool import BaseTool
2
2
  from autobyteus.tools.tool_config import ToolConfig
3
+ from autobyteus.tools.tool_category import ToolCategory
3
4
  from brui_core.ui_integrator import UIIntegrator
4
5
  from urllib.parse import urlparse
5
6
  from typing import Optional, TYPE_CHECKING, Any
@@ -17,6 +18,7 @@ class NavigateTo(BaseTool, UIIntegrator):
17
18
  A standalone tool for navigating to a specified website using Playwright.
18
19
  It initializes and closes its own browser instance for each navigation.
19
20
  """
21
+ CATEGORY = ToolCategory.WEB
20
22
 
21
23
  def __init__(self, config: Optional[ToolConfig] = None):
22
24
  BaseTool.__init__(self, config=config)
@@ -1,5 +1,6 @@
1
1
  from autobyteus.tools.base_tool import BaseTool
2
2
  from autobyteus.tools.tool_config import ToolConfig
3
+ from autobyteus.tools.tool_category import ToolCategory
3
4
  from brui_core.ui_integrator import UIIntegrator
4
5
  import os
5
6
  import logging
@@ -18,6 +19,8 @@ class WebPagePDFGenerator(BaseTool, UIIntegrator):
18
19
  A class that generates a PDF of a given webpage URL using Playwright.
19
20
  Saves the PDF to a specified directory. This is a standalone browser tool.
20
21
  """
22
+ CATEGORY = ToolCategory.WEB
23
+
21
24
  def __init__(self, config: Optional[ToolConfig] = None):
22
25
  BaseTool.__init__(self, config=config)
23
26
  UIIntegrator.__init__(self)
@@ -1,5 +1,6 @@
1
1
  from autobyteus.tools.base_tool import BaseTool
2
2
  from autobyteus.tools.tool_config import ToolConfig
3
+ from autobyteus.tools.tool_category import ToolCategory
3
4
  from brui_core.ui_integrator import UIIntegrator
4
5
  import os
5
6
  import logging
@@ -18,6 +19,8 @@ class WebPageImageDownloader(BaseTool, UIIntegrator):
18
19
  A class that downloads images (excluding SVGs and data URIs) from a given webpage URL using Playwright.
19
20
  Saves images to a specified directory.
20
21
  """
22
+ CATEGORY = ToolCategory.WEB
23
+
21
24
  def __init__(self, config: Optional[ToolConfig] = None):
22
25
  BaseTool.__init__(self, config=config)
23
26
  UIIntegrator.__init__(self)
@@ -8,6 +8,7 @@ from typing import Optional, TYPE_CHECKING, Any
8
8
  from autobyteus.tools.base_tool import BaseTool
9
9
  from autobyteus.tools.tool_config import ToolConfig
10
10
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
11
+ from autobyteus.tools.tool_category import ToolCategory
11
12
  from brui_core.ui_integrator import UIIntegrator
12
13
  from autobyteus.utils.html_cleaner import clean, CleaningMode
13
14
 
@@ -20,6 +21,7 @@ class WebPageReader(BaseTool, UIIntegrator):
20
21
  """
21
22
  A class that reads and cleans the HTML content from a given webpage using Playwright.
22
23
  """
24
+ CATEGORY = ToolCategory.WEB
23
25
 
24
26
  def __init__(self, config: Optional[ToolConfig] = None):
25
27
  BaseTool.__init__(self, config=config)
@@ -2,6 +2,7 @@ from typing import Optional, TYPE_CHECKING, Any
2
2
  from autobyteus.tools.base_tool import BaseTool
3
3
  from autobyteus.tools.tool_config import ToolConfig
4
4
  from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
5
+ from autobyteus.tools.tool_category import ToolCategory
5
6
  from brui_core.ui_integrator import UIIntegrator
6
7
  import logging
7
8
  import os
@@ -15,6 +16,8 @@ class WebPageScreenshotTaker(BaseTool, UIIntegrator):
15
16
  """
16
17
  A class that takes a screenshot of a given webpage using Playwright and saves it.
17
18
  """
19
+ CATEGORY = ToolCategory.WEB
20
+
18
21
  def __init__(self, config: Optional[ToolConfig] = None):
19
22
  BaseTool.__init__(self, config=config)
20
23
  UIIntegrator.__init__(self)
@@ -3,27 +3,54 @@ import logging
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from autobyteus.tools import tool
6
+ from autobyteus.tools.tool_category import ToolCategory
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from autobyteus.agent.context import AgentContext
9
10
 
10
11
  logger = logging.getLogger(__name__)
11
12
 
12
- @tool(name="FileReader") # Keep registered name "FileReader"
13
- async def file_reader(context: 'AgentContext', path: str) -> str: # function name can be same
13
+ @tool(name="FileReader", category=ToolCategory.FILE_SYSTEM)
14
+ async def file_reader(context: 'AgentContext', path: str) -> str:
14
15
  """
15
16
  Reads content from a specified file.
16
- 'path' is the absolute or relative path to the file.
17
+ 'path' is the path to the file. If relative, it must be resolved against a configured agent workspace.
18
+ Raises ValueError if a relative path is given without a valid workspace.
17
19
  Raises FileNotFoundError if the file does not exist.
18
20
  Raises IOError if file reading fails for other reasons.
19
21
  """
20
- logger.debug(f"Functional FileReader tool for agent {context.agent_id}, path: {path}")
21
- if not os.path.exists(path):
22
- raise FileNotFoundError(f"The file at {path} does not exist.")
22
+ logger.debug(f"Functional FileReader tool for agent {context.agent_id}, initial path: {path}")
23
+
24
+ final_path: str
25
+ if os.path.isabs(path):
26
+ final_path = path
27
+ logger.debug(f"Path '{path}' is absolute. Using it directly.")
28
+ else:
29
+ if not context.workspace:
30
+ error_msg = f"Relative path '{path}' provided, but no workspace is configured for agent '{context.agent_id}'. A workspace is required to resolve relative paths."
31
+ logger.error(error_msg)
32
+ raise ValueError(error_msg)
33
+
34
+ base_path = context.workspace.get_base_path()
35
+ if not base_path or not isinstance(base_path, str):
36
+ error_msg = f"Agent '{context.agent_id}' has a configured workspace, but it provided an invalid base path ('{base_path}'). Cannot resolve relative path '{path}'."
37
+ logger.error(error_msg)
38
+ raise ValueError(error_msg)
39
+
40
+ final_path = os.path.join(base_path, path)
41
+ logger.debug(f"Path '{path}' is relative. Resolved to '{final_path}' using workspace base path '{base_path}'.")
42
+
43
+ # It's good practice to normalize the path to handle things like '..'
44
+ final_path = os.path.normpath(final_path)
45
+
46
+ if not os.path.exists(final_path):
47
+ raise FileNotFoundError(f"The file at resolved path {final_path} does not exist.")
48
+
23
49
  try:
24
- with open(path, 'r', encoding='utf-8') as file:
50
+ with open(final_path, 'r', encoding='utf-8') as file:
25
51
  content = file.read()
52
+ logger.info(f"File successfully read from '{final_path}' for agent '{context.agent_id}'.")
26
53
  return content
27
54
  except Exception as e:
28
- logger.error(f"Error reading file {path} for agent {context.agent_id}: {e}", exc_info=True)
29
- raise IOError(f"Could not read file at {path}: {str(e)}")
55
+ logger.error(f"Error reading file from final path '{final_path}' for agent {context.agent_id}: {e}", exc_info=True)
56
+ raise IOError(f"Could not read file at {final_path}: {str(e)}")