autobyteus 1.0.5__py3-none-any.whl → 1.1.0__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 (256) hide show
  1. autobyteus/agent/agent.py +97 -222
  2. autobyteus/agent/bootstrap_steps/__init__.py +19 -0
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +88 -0
  4. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +57 -0
  5. autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +38 -0
  6. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +93 -0
  7. autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +47 -0
  8. autobyteus/agent/context/__init__.py +18 -0
  9. autobyteus/agent/context/agent_config.py +80 -0
  10. autobyteus/agent/context/agent_context.py +132 -0
  11. autobyteus/agent/context/agent_phase_manager.py +164 -0
  12. autobyteus/agent/context/agent_runtime_state.py +89 -0
  13. autobyteus/agent/context/phases.py +47 -0
  14. autobyteus/agent/events/__init__.py +63 -0
  15. autobyteus/agent/events/agent_events.py +147 -0
  16. autobyteus/agent/events/agent_input_event_queue_manager.py +174 -0
  17. autobyteus/agent/events/notifiers.py +104 -0
  18. autobyteus/agent/events/worker_event_dispatcher.py +118 -0
  19. autobyteus/agent/factory/__init__.py +9 -0
  20. autobyteus/agent/factory/agent_factory.py +126 -79
  21. autobyteus/agent/group/agent_group.py +155 -0
  22. autobyteus/agent/group/agent_group_context.py +81 -0
  23. autobyteus/agent/handlers/__init__.py +36 -0
  24. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +134 -0
  25. autobyteus/agent/handlers/base_event_handler.py +36 -0
  26. autobyteus/agent/handlers/event_handler_registry.py +76 -0
  27. autobyteus/agent/handlers/generic_event_handler.py +46 -0
  28. autobyteus/agent/handlers/inter_agent_message_event_handler.py +76 -0
  29. autobyteus/agent/handlers/lifecycle_event_logger.py +64 -0
  30. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +136 -0
  31. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +140 -0
  32. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +85 -0
  33. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +186 -0
  34. autobyteus/agent/handlers/tool_result_event_handler.py +96 -0
  35. autobyteus/agent/handlers/user_input_message_event_handler.py +77 -0
  36. autobyteus/agent/hooks/__init__.py +9 -0
  37. autobyteus/agent/hooks/base_phase_hook.py +52 -0
  38. autobyteus/agent/input_processor/__init__.py +18 -0
  39. autobyteus/agent/input_processor/base_user_input_processor.py +51 -0
  40. autobyteus/agent/input_processor/content_prefixing_input_processor.py +41 -0
  41. autobyteus/agent/input_processor/metadata_appending_input_processor.py +34 -0
  42. autobyteus/agent/input_processor/passthrough_input_processor.py +32 -0
  43. autobyteus/agent/input_processor/processor_definition.py +42 -0
  44. autobyteus/agent/input_processor/processor_meta.py +46 -0
  45. autobyteus/agent/input_processor/processor_registry.py +98 -0
  46. autobyteus/agent/llm_response_processor/__init__.py +16 -0
  47. autobyteus/agent/llm_response_processor/base_processor.py +50 -0
  48. autobyteus/agent/llm_response_processor/processor_definition.py +36 -0
  49. autobyteus/agent/llm_response_processor/processor_meta.py +37 -0
  50. autobyteus/agent/llm_response_processor/processor_registry.py +94 -0
  51. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +53 -0
  52. autobyteus/agent/message/__init__.py +20 -0
  53. autobyteus/agent/message/agent_input_user_message.py +96 -0
  54. autobyteus/agent/message/context_file.py +82 -0
  55. autobyteus/agent/message/context_file_type.py +64 -0
  56. autobyteus/agent/message/{message.py → inter_agent_message.py} +12 -12
  57. autobyteus/agent/message/{message_types.py → inter_agent_message_type.py} +8 -6
  58. autobyteus/agent/message/send_message_to.py +142 -36
  59. autobyteus/agent/remote_agent.py +240 -5
  60. autobyteus/agent/runtime/__init__.py +15 -0
  61. autobyteus/agent/runtime/agent_runtime.py +139 -0
  62. autobyteus/agent/runtime/agent_thread_pool_manager.py +88 -0
  63. autobyteus/agent/runtime/agent_worker.py +200 -0
  64. autobyteus/agent/streaming/__init__.py +15 -0
  65. autobyteus/agent/streaming/agent_event_stream.py +120 -0
  66. autobyteus/agent/streaming/queue_streamer.py +58 -0
  67. autobyteus/agent/streaming/stream_event_payloads.py +156 -0
  68. autobyteus/agent/streaming/stream_events.py +123 -0
  69. autobyteus/agent/system_prompt_processor/__init__.py +14 -0
  70. autobyteus/agent/system_prompt_processor/base_processor.py +45 -0
  71. autobyteus/agent/system_prompt_processor/processor_definition.py +40 -0
  72. autobyteus/agent/system_prompt_processor/processor_meta.py +47 -0
  73. autobyteus/agent/system_prompt_processor/processor_registry.py +119 -0
  74. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +65 -0
  75. autobyteus/agent/tool_invocation.py +28 -5
  76. autobyteus/agent/utils/__init__.py +9 -0
  77. autobyteus/agent/utils/wait_for_idle.py +59 -0
  78. autobyteus/agent/workflow/__init__.py +11 -0
  79. autobyteus/agent/workflow/agentic_workflow.py +89 -0
  80. autobyteus/agent/workflow/base_agentic_workflow.py +98 -0
  81. autobyteus/agent/workspace/__init__.py +9 -0
  82. autobyteus/agent/workspace/base_workspace.py +55 -0
  83. autobyteus/cli/__init__.py +10 -0
  84. autobyteus/cli/agent_cli.py +299 -0
  85. autobyteus/events/event_emitter.py +33 -56
  86. autobyteus/events/event_manager.py +133 -66
  87. autobyteus/events/event_types.py +41 -14
  88. autobyteus/llm/api/autobyteus_llm.py +13 -15
  89. autobyteus/llm/api/bedrock_llm.py +9 -3
  90. autobyteus/llm/api/claude_llm.py +10 -5
  91. autobyteus/llm/api/deepseek_llm.py +53 -91
  92. autobyteus/llm/api/gemini_llm.py +10 -4
  93. autobyteus/llm/api/grok_llm.py +53 -77
  94. autobyteus/llm/api/groq_llm.py +10 -5
  95. autobyteus/llm/api/mistral_llm.py +10 -5
  96. autobyteus/llm/api/nvidia_llm.py +9 -4
  97. autobyteus/llm/api/ollama_llm.py +56 -48
  98. autobyteus/llm/api/openai_llm.py +20 -14
  99. autobyteus/llm/base_llm.py +95 -34
  100. autobyteus/llm/extensions/base_extension.py +3 -4
  101. autobyteus/llm/extensions/token_usage_tracking_extension.py +2 -3
  102. autobyteus/llm/llm_factory.py +12 -13
  103. autobyteus/llm/models.py +87 -8
  104. autobyteus/llm/user_message.py +73 -0
  105. autobyteus/llm/utils/llm_config.py +124 -27
  106. autobyteus/llm/utils/response_types.py +3 -2
  107. autobyteus/llm/utils/token_usage.py +7 -4
  108. autobyteus/rpc/__init__.py +73 -0
  109. autobyteus/rpc/client/__init__.py +17 -0
  110. autobyteus/rpc/client/abstract_client_connection.py +124 -0
  111. autobyteus/rpc/client/client_connection_manager.py +153 -0
  112. autobyteus/rpc/client/sse_client_connection.py +306 -0
  113. autobyteus/rpc/client/stdio_client_connection.py +280 -0
  114. autobyteus/rpc/config/__init__.py +13 -0
  115. autobyteus/rpc/config/agent_server_config.py +153 -0
  116. autobyteus/rpc/config/agent_server_registry.py +152 -0
  117. autobyteus/rpc/hosting.py +244 -0
  118. autobyteus/rpc/protocol.py +244 -0
  119. autobyteus/rpc/server/__init__.py +20 -0
  120. autobyteus/rpc/server/agent_server_endpoint.py +181 -0
  121. autobyteus/rpc/server/base_method_handler.py +40 -0
  122. autobyteus/rpc/server/method_handlers.py +259 -0
  123. autobyteus/rpc/server/sse_server_handler.py +182 -0
  124. autobyteus/rpc/server/stdio_server_handler.py +151 -0
  125. autobyteus/rpc/server_main.py +198 -0
  126. autobyteus/rpc/transport_type.py +13 -0
  127. autobyteus/tools/__init__.py +75 -0
  128. autobyteus/tools/ask_user_input.py +34 -77
  129. autobyteus/tools/base_tool.py +66 -37
  130. autobyteus/tools/bash/__init__.py +2 -0
  131. autobyteus/tools/bash/bash_executor.py +42 -79
  132. autobyteus/tools/browser/__init__.py +2 -0
  133. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +50 -42
  134. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +7 -4
  135. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +117 -125
  136. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +75 -22
  137. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +94 -28
  138. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +10 -2
  139. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +18 -2
  140. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +10 -2
  141. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +4 -3
  142. autobyteus/tools/browser/standalone/__init__.py +7 -0
  143. autobyteus/tools/browser/standalone/factory/google_search_factory.py +17 -2
  144. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +17 -2
  145. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +10 -2
  146. autobyteus/tools/browser/standalone/google_search_ui.py +104 -67
  147. autobyteus/tools/browser/standalone/navigate_to.py +52 -28
  148. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +94 -0
  149. autobyteus/tools/browser/standalone/webpage_image_downloader.py +146 -61
  150. autobyteus/tools/browser/standalone/webpage_reader.py +80 -61
  151. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +91 -45
  152. autobyteus/tools/factory/__init__.py +9 -0
  153. autobyteus/tools/factory/tool_factory.py +25 -4
  154. autobyteus/tools/file/file_reader.py +22 -51
  155. autobyteus/tools/file/file_writer.py +25 -56
  156. autobyteus/tools/functional_tool.py +234 -0
  157. autobyteus/tools/image_downloader.py +49 -71
  158. autobyteus/tools/mcp/__init__.py +47 -0
  159. autobyteus/tools/mcp/call_handlers/__init__.py +18 -0
  160. autobyteus/tools/mcp/call_handlers/base_handler.py +40 -0
  161. autobyteus/tools/mcp/call_handlers/sse_handler.py +22 -0
  162. autobyteus/tools/mcp/call_handlers/stdio_handler.py +62 -0
  163. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +55 -0
  164. autobyteus/tools/mcp/config_service.py +258 -0
  165. autobyteus/tools/mcp/factory.py +70 -0
  166. autobyteus/tools/mcp/registrar.py +135 -0
  167. autobyteus/tools/mcp/schema_mapper.py +131 -0
  168. autobyteus/tools/mcp/tool.py +101 -0
  169. autobyteus/tools/mcp/types.py +96 -0
  170. autobyteus/tools/parameter_schema.py +268 -0
  171. autobyteus/tools/pdf_downloader.py +78 -79
  172. autobyteus/tools/registry/__init__.py +0 -2
  173. autobyteus/tools/registry/tool_definition.py +106 -34
  174. autobyteus/tools/registry/tool_registry.py +46 -22
  175. autobyteus/tools/timer.py +150 -102
  176. autobyteus/tools/tool_config.py +117 -0
  177. autobyteus/tools/tool_meta.py +48 -26
  178. autobyteus/tools/usage/__init__.py +6 -0
  179. autobyteus/tools/usage/formatters/__init__.py +31 -0
  180. autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py +18 -0
  181. autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py +25 -0
  182. autobyteus/tools/usage/formatters/base_formatter.py +42 -0
  183. autobyteus/tools/usage/formatters/default_json_example_formatter.py +42 -0
  184. autobyteus/tools/usage/formatters/default_json_schema_formatter.py +28 -0
  185. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +55 -0
  186. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +46 -0
  187. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +34 -0
  188. autobyteus/tools/usage/formatters/gemini_json_schema_formatter.py +25 -0
  189. autobyteus/tools/usage/formatters/google_json_example_formatter.py +34 -0
  190. autobyteus/tools/usage/formatters/google_json_schema_formatter.py +25 -0
  191. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +49 -0
  192. autobyteus/tools/usage/formatters/openai_json_schema_formatter.py +28 -0
  193. autobyteus/tools/usage/parsers/__init__.py +22 -0
  194. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +10 -0
  195. autobyteus/tools/usage/parsers/base_parser.py +41 -0
  196. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +106 -0
  197. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +135 -0
  198. autobyteus/tools/usage/parsers/exceptions.py +13 -0
  199. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +68 -0
  200. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +147 -0
  201. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +67 -0
  202. autobyteus/tools/usage/providers/__init__.py +22 -0
  203. autobyteus/tools/usage/providers/json_example_provider.py +32 -0
  204. autobyteus/tools/usage/providers/json_schema_provider.py +35 -0
  205. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +28 -0
  206. autobyteus/tools/usage/providers/tool_manifest_provider.py +68 -0
  207. autobyteus/tools/usage/providers/xml_example_provider.py +28 -0
  208. autobyteus/tools/usage/providers/xml_schema_provider.py +29 -0
  209. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +26 -0
  210. autobyteus/tools/usage/registries/__init__.py +20 -0
  211. autobyteus/tools/usage/registries/json_example_formatter_registry.py +51 -0
  212. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +51 -0
  213. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +42 -0
  214. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +30 -0
  215. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +33 -0
  216. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +30 -0
  217. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/METADATA +21 -3
  218. autobyteus-1.1.0.dist-info/RECORD +279 -0
  219. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/WHEEL +1 -1
  220. autobyteus/agent/async_agent.py +0 -175
  221. autobyteus/agent/async_group_aware_agent.py +0 -136
  222. autobyteus/agent/group/async_group_aware_agent.py +0 -122
  223. autobyteus/agent/group/coordinator_agent.py +0 -36
  224. autobyteus/agent/group/group_aware_agent.py +0 -121
  225. autobyteus/agent/orchestrator/__init__.py +0 -0
  226. autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -82
  227. autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -72
  228. autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -43
  229. autobyteus/agent/registry/__init__.py +0 -11
  230. autobyteus/agent/registry/agent_definition.py +0 -94
  231. autobyteus/agent/registry/agent_registry.py +0 -114
  232. autobyteus/agent/response_parser/__init__.py +0 -0
  233. autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -100
  234. autobyteus/agent/status.py +0 -12
  235. autobyteus/conversation/__init__.py +0 -0
  236. autobyteus/conversation/conversation.py +0 -54
  237. autobyteus/conversation/user_message.py +0 -59
  238. autobyteus/events/decorators.py +0 -29
  239. autobyteus/prompt/prompt_version_manager.py +0 -58
  240. autobyteus/prompt/storage/__init__.py +0 -0
  241. autobyteus/prompt/storage/prompt_version_model.py +0 -29
  242. autobyteus/prompt/storage/prompt_version_repository.py +0 -83
  243. autobyteus/tools/bash/factory/__init__.py +0 -0
  244. autobyteus/tools/bash/factory/bash_executor_factory.py +0 -6
  245. autobyteus/tools/factory/ask_user_input_factory.py +0 -6
  246. autobyteus/tools/factory/image_downloader_factory.py +0 -9
  247. autobyteus/tools/factory/pdf_downloader_factory.py +0 -9
  248. autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -6
  249. autobyteus/tools/file/factory/__init__.py +0 -0
  250. autobyteus/tools/file/factory/file_reader_factory.py +0 -6
  251. autobyteus/tools/file/factory/file_writer_factory.py +0 -6
  252. autobyteus/tools/mcp_remote_tool.py +0 -82
  253. autobyteus/tools/web_page_pdf_generator.py +0 -90
  254. autobyteus-1.0.5.dist-info/RECORD +0 -163
  255. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/licenses/LICENSE +0 -0
  256. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/top_level.txt +0 -0
autobyteus/tools/timer.py CHANGED
@@ -1,121 +1,169 @@
1
1
  import asyncio
2
- from typing import Optional
2
+ from typing import Optional, TYPE_CHECKING, Any
3
3
  from autobyteus.tools.base_tool import BaseTool
4
- from autobyteus.events.event_emitter import EventEmitter
4
+ from autobyteus.tools.tool_config import ToolConfig
5
+ from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
6
+ from autobyteus.events.event_emitter import EventEmitter
5
7
  from autobyteus.events.event_types import EventType
8
+ import logging
6
9
 
7
- class Timer(BaseTool, EventEmitter):
8
- """
9
- A tool that provides timer functionality with configurable duration and event emission.
10
+ if TYPE_CHECKING:
11
+ from autobyteus.agent.context import AgentContext
10
12
 
11
- This class inherits from BaseTool and EventEmitter. It allows setting a timer duration,
12
- starting the timer, and emits events with the remaining time at configurable intervals.
13
- The timer runs independently after being started.
13
+ logger = logging.getLogger(__name__)
14
14
 
15
- Attributes:
16
- duration (int): The duration of the timer in seconds.
17
- interval (int): The interval at which to emit timer events, in seconds.
18
- _is_running (bool): Flag to indicate if the timer is currently running.
19
- _task (Optional[asyncio.Task]): The asyncio task for the running timer.
15
+ class Timer(BaseTool, EventEmitter):
16
+ """
17
+ A tool that provides timer functionality with configurable duration and event emission.
18
+ The timer runs independently after being started and emits TIMER_UPDATE events.
20
19
  """
21
20
 
22
- def __init__(self):
23
- """
24
- Initialize the Timer.
25
- """
26
- BaseTool.__init__(self)
27
- EventEmitter.__init__(self)
28
- self.duration: int = 0
29
- self.interval: int = 60 # Default to 60 seconds if not specified
21
+ def __init__(self, config: Optional[ToolConfig] = None):
22
+ BaseTool.__init__(self, config=config)
23
+ EventEmitter.__init__(self)
24
+
25
+ self.duration: int = 300
26
+ self.interval: int = 60
27
+
28
+ if config:
29
+ try:
30
+ self.duration = int(config.get('duration', 300))
31
+ if not (1 <= self.duration <= 86400):
32
+ logger.warning(f"Timer duration {self.duration} out of bounds (1-86400). Clamping or using default.")
33
+ self.duration = max(1, min(self.duration, 86400))
34
+ except ValueError:
35
+ logger.warning(f"Invalid duration value in config, using default {self.duration}s.")
36
+
37
+ try:
38
+ self.interval = int(config.get('interval', 60))
39
+ if not (1 <= self.interval <= 3600):
40
+ logger.warning(f"Timer interval {self.interval} out of bounds (1-3600). Clamping or using default.")
41
+ self.interval = max(1, min(self.interval, 3600))
42
+ except ValueError:
43
+ logger.warning(f"Invalid interval value in config, using default {self.interval}s.")
44
+
30
45
  self._is_running: bool = False
31
46
  self._task: Optional[asyncio.Task] = None
47
+ logger.debug(f"Timer initialized with duration: {self.duration}s, interval: {self.interval}s")
32
48
 
33
49
  @classmethod
34
- def tool_usage_xml(cls):
35
- """
36
- Return an XML string describing the usage of the Timer tool.
37
-
38
- Returns:
39
- str: An XML description of how to use the Timer tool.
40
- """
41
- return '''Timer: Sets and runs a timer, emitting events with remaining time. Usage:
42
- <command name="Timer">
43
- <arg name="duration">300</arg>
44
- <arg name="interval" optional="true">60</arg>
45
- </command>
46
- where duration and interval are in seconds. interval is optional and defaults to 60 seconds.
47
- '''
48
-
49
- def set_duration(self, duration: int):
50
- """
51
- Set the duration of the timer.
52
-
53
- Args:
54
- duration (int): The duration of the timer in seconds.
55
- """
56
- self.duration = duration
50
+ def get_description(cls) -> str:
51
+ return "Sets and runs a timer. Emits TIMER_UPDATE events with remaining time at specified intervals."
57
52
 
58
- def set_interval(self, interval: int):
59
- """
60
- Set the interval for emitting timer events.
53
+ @classmethod
54
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
55
+ schema = ParameterSchema()
56
+ schema.add_parameter(ParameterDefinition(
57
+ name="duration",
58
+ param_type=ParameterType.INTEGER,
59
+ description="Duration to set for this timer run in seconds.",
60
+ required=True,
61
+ min_value=1,
62
+ max_value=86400
63
+ ))
64
+ schema.add_parameter(ParameterDefinition(
65
+ name="interval",
66
+ param_type=ParameterType.INTEGER,
67
+ description="Interval for emitting timer events in seconds for this run. Overrides instance default.",
68
+ required=False,
69
+ default_value=None,
70
+ min_value=1,
71
+ max_value=3600
72
+ ))
73
+ return schema
61
74
 
62
- Args:
63
- interval (int): The interval at which to emit timer events, in seconds.
64
- """
65
- self.interval = interval
75
+ @classmethod
76
+ def get_config_schema(cls) -> Optional[ParameterSchema]:
77
+ schema = ParameterSchema()
78
+ schema.add_parameter(ParameterDefinition(
79
+ name="duration",
80
+ param_type=ParameterType.INTEGER,
81
+ description="Default duration of the timer in seconds if not overridden by execute.",
82
+ required=False,
83
+ default_value=300,
84
+ min_value=1,
85
+ max_value=86400
86
+ ))
87
+ schema.add_parameter(ParameterDefinition(
88
+ name="interval",
89
+ param_type=ParameterType.INTEGER,
90
+ description="Default interval at which to emit timer events, in seconds, if not overridden by execute.",
91
+ required=False,
92
+ default_value=60,
93
+ min_value=1,
94
+ max_value=3600
95
+ ))
96
+ return schema
97
+
98
+ def set_duration(self, duration: int) -> None:
99
+ if not (1 <= duration <= 86400):
100
+ raise ValueError("Duration must be between 1 and 86400 seconds.")
101
+ self.duration = duration
66
102
 
67
- def start(self):
68
- """
69
- Start the timer if it's not already running.
103
+ def set_interval(self, interval: int) -> None:
104
+ if not (1 <= interval <= 3600):
105
+ raise ValueError("Interval must be between 1 and 3600 seconds.")
106
+ self.interval = interval
70
107
 
71
- Raises:
72
- RuntimeError: If the timer is already running or if no duration has been set.
73
- """
108
+ def start(self, run_duration: Optional[int] = None, run_interval: Optional[int] = None) -> None:
74
109
  if self._is_running:
75
- raise RuntimeError("Timer is already running")
76
- if self.duration <= 0:
77
- raise RuntimeError("Timer duration must be set before starting")
78
- self._is_running = True
79
- self._task = asyncio.create_task(self._run_timer())
80
-
81
- async def _run_timer(self):
82
- """
83
- Run the timer, emitting events at the specified interval.
84
- """
85
- remaining_time = self.duration
86
- while remaining_time > 0:
87
- self.emit(EventType.TIMER_UPDATE, remaining_time=remaining_time)
88
- await asyncio.sleep(min(self.interval, remaining_time))
89
- remaining_time -= self.interval
90
- self.emit(EventType.TIMER_UPDATE, remaining_time=0)
91
- self._is_running = False
92
-
93
- async def _execute(self, **kwargs):
94
- """
95
- Execute the timer.
96
-
97
- This method sets the duration and interval if provided, and starts the timer.
98
- It returns immediately after starting the timer, allowing the timer to run independently.
99
-
100
- Args:
101
- **kwargs: Keyword arguments. Expected arguments:
102
- - duration (int): The duration to set for the timer in seconds.
103
- - interval (int, optional): The interval at which to emit timer events, in seconds.
104
- Defaults to 60 seconds if not provided.
105
-
106
- Returns:
107
- str: A message indicating the timer has started.
108
-
109
- Raises:
110
- ValueError: If the duration is not provided.
111
- """
112
- duration = kwargs.get('duration')
113
- if duration is None:
114
- raise ValueError("Timer duration must be provided")
115
- self.set_duration(duration)
110
+ logger.warning("Timer start called but timer is already running.")
111
+ return
112
+
113
+ current_duration = run_duration if run_duration is not None else self.duration
114
+ current_interval = run_interval if run_interval is not None else self.interval
116
115
 
117
- interval = kwargs.get('interval', 60)
118
- self.set_interval(interval)
116
+ if current_duration <= 0:
117
+ raise RuntimeError("Timer duration must be positive and set before starting.")
118
+ if current_interval <=0:
119
+ raise RuntimeError("Timer interval must be positive and set.")
119
120
 
120
- self.start()
121
- return f"Timer started for {self.duration} seconds, emitting events every {self.interval} seconds"
121
+ self._is_running = True
122
+ self._task = asyncio.create_task(self._run_timer_task(current_duration, current_interval))
123
+ logger.info(f"Timer started for {current_duration}s, events every {current_interval}s.")
124
+
125
+ async def _run_timer_task(self, duration: int, interval: int) -> None:
126
+ remaining_time = duration
127
+ try:
128
+ while remaining_time > 0:
129
+ self.emit(EventType.TIMER_UPDATE, remaining_time=remaining_time)
130
+ await asyncio.sleep(min(interval, remaining_time))
131
+ remaining_time -= interval
132
+ self.emit(EventType.TIMER_UPDATE, remaining_time=0)
133
+ except asyncio.CancelledError:
134
+ logger.info("Timer task was cancelled.")
135
+ self.emit(EventType.TIMER_UPDATE, remaining_time=-1, status="cancelled")
136
+ raise
137
+ finally:
138
+ self._is_running = False
139
+ logger.info("Timer task finished.")
140
+
141
+ async def _execute(self, context: 'AgentContext', duration: int, interval: Optional[int] = None) -> str:
142
+ logger.debug(f"Timer execute called by agent {context.agent_id} with duration: {duration}, interval: {interval}")
143
+
144
+ effective_interval = interval if interval is not None else self.interval
145
+
146
+ if self._task and not self._task.done():
147
+ logger.info("Cancelling previous timer task before starting a new one.")
148
+ self._task.cancel()
149
+ try:
150
+ await self._task
151
+ except asyncio.CancelledError:
152
+ logger.debug("Previous timer task successfully cancelled.")
153
+ self._task = None
154
+
155
+ self.start(run_duration=duration, run_interval=effective_interval)
156
+ return f"Timer started for {duration} seconds, emitting events every {effective_interval} seconds."
157
+
158
+ async def stop(self) -> None:
159
+ if self._task and not self._task.done():
160
+ logger.info("Stopping timer task...")
161
+ self._task.cancel()
162
+ try:
163
+ await self._task
164
+ except asyncio.CancelledError:
165
+ logger.info("Timer task stopped successfully.")
166
+ self._task = None
167
+ self._is_running = False
168
+ else:
169
+ logger.info("Stop called, but no timer task is running or task already done.")
@@ -0,0 +1,117 @@
1
+ # file: autobyteus/autobyteus/tools/tool_config.py
2
+ import logging
3
+ from typing import Dict, Any
4
+ from dataclasses import dataclass, field
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ @dataclass
9
+ class ToolConfig:
10
+ """
11
+ Configuration class for tools - a simple dictionary wrapper.
12
+ Tools define their own default configurations internally and use this
13
+ class to receive configuration overrides.
14
+ """
15
+ params: Dict[str, Any] = field(default_factory=dict)
16
+
17
+ def __post_init__(self):
18
+ """Validate configuration after initialization."""
19
+ if not isinstance(self.params, dict):
20
+ raise TypeError("params must be a dictionary")
21
+
22
+ logger.debug(f"ToolConfig initialized with params keys: {list(self.params.keys())}")
23
+
24
+ def to_dict(self) -> Dict[str, Any]:
25
+ """
26
+ Convert the ToolConfig to a dictionary representation.
27
+
28
+ Returns:
29
+ Dict[str, Any]: Dictionary representation of the configuration.
30
+ """
31
+ return self.params.copy()
32
+
33
+ @classmethod
34
+ def from_dict(cls, config_data: Dict[str, Any]) -> 'ToolConfig':
35
+ """
36
+ Create a ToolConfig instance from a dictionary.
37
+
38
+ Args:
39
+ config_data: Dictionary containing configuration parameters.
40
+
41
+ Returns:
42
+ ToolConfig: New ToolConfig instance.
43
+ """
44
+ if not isinstance(config_data, dict):
45
+ raise TypeError("config_data must be a dictionary")
46
+
47
+ return cls(params=config_data.copy())
48
+
49
+ def merge(self, other: 'ToolConfig') -> 'ToolConfig':
50
+ """
51
+ Merge this ToolConfig with another, with the other taking precedence.
52
+
53
+ Args:
54
+ other: ToolConfig to merge with this one.
55
+
56
+ Returns:
57
+ ToolConfig: New merged ToolConfig instance.
58
+ """
59
+ if not isinstance(other, ToolConfig):
60
+ raise TypeError("Can only merge with another ToolConfig instance")
61
+
62
+ merged_params = self.params.copy()
63
+ merged_params.update(other.params)
64
+
65
+ return ToolConfig(params=merged_params)
66
+
67
+ def get_constructor_kwargs(self) -> Dict[str, Any]:
68
+ """
69
+ Get keyword arguments suitable for tool constructor calls.
70
+
71
+ Returns:
72
+ Dict[str, Any]: Dictionary of constructor arguments.
73
+ """
74
+ return self.params.copy()
75
+
76
+ def get(self, key: str, default: Any = None) -> Any:
77
+ """
78
+ Get a configuration parameter.
79
+
80
+ Args:
81
+ key: The parameter key.
82
+ default: Default value if key doesn't exist.
83
+
84
+ Returns:
85
+ The parameter value or default.
86
+ """
87
+ return self.params.get(key, default)
88
+
89
+ def set(self, key: str, value: Any) -> None:
90
+ """
91
+ Set a configuration parameter.
92
+
93
+ Args:
94
+ key: The parameter key.
95
+ value: The parameter value.
96
+ """
97
+ self.params[key] = value
98
+
99
+ def update(self, params: Dict[str, Any]) -> None:
100
+ """
101
+ Update multiple configuration parameters.
102
+
103
+ Args:
104
+ params: Dictionary of parameters to update.
105
+ """
106
+ if not isinstance(params, dict):
107
+ raise TypeError("params must be a dictionary")
108
+ self.params.update(params)
109
+
110
+ def __repr__(self) -> str:
111
+ return f"ToolConfig(params={self.params})"
112
+
113
+ def __len__(self) -> int:
114
+ return len(self.params)
115
+
116
+ def __bool__(self) -> bool:
117
+ return bool(self.params)
@@ -1,52 +1,74 @@
1
- # file: autobyteus/tools/tool_meta.py
1
+ # file: autobyteus/autobyteus/tools/tool_meta.py
2
2
  import logging
3
3
  from abc import ABCMeta
4
+ from typing import Dict, Any
4
5
 
5
- # Import the global registry and definition class from the registry package
6
6
  from autobyteus.tools.registry import default_tool_registry, ToolDefinition
7
+ from autobyteus.tools.parameter_schema import ParameterSchema
7
8
 
8
- logger = logging.getLogger(__name__) # Using __name__ for specific logger
9
+ logger = logging.getLogger(__name__)
9
10
 
10
11
  class ToolMeta(ABCMeta):
11
12
  """
12
- Metaclass for BaseTool that automatically registers concrete tool subclasses
13
- with the default_tool_registry using their static name and usage description
14
- obtained from class method `tool_usage()`.
13
+ Metaclass for BaseTool that automatically registers concrete tool subclasses.
15
14
  """
16
15
  def __init__(cls, name, bases, dct):
17
- """
18
- Called when a class using this metaclass is defined.
19
- """
20
16
  super().__init__(name, bases, dct)
21
17
 
22
- # Prevent registration of the BaseTool class itself or other explicitly abstract classes
23
- if name == 'BaseTool' or getattr(cls, "__abstractmethods__", None):
24
- logger.debug(f"Skipping registration for abstract class: {name}")
18
+ # Skip registration for special classes that are not meant to be standalone tools.
19
+ # FunctionalTool is an explicit wrapper but shouldn't be registered itself.
20
+ if name in ['BaseTool', 'GenericMcpTool', 'FunctionalTool'] or getattr(cls, "__abstractmethods__", None):
21
+ logger.debug(f"Skipping registration for abstract or special tool class: {name}")
25
22
  return
26
23
 
27
24
  try:
28
- # Get static/class info from the class being defined
25
+ # Use the class itself to get the metadata, not an instance.
29
26
  tool_name = cls.get_name()
30
-
31
- usage_description = cls.tool_usage()
32
-
33
- # Basic validation of fetched static info
34
27
  if not tool_name or not isinstance(tool_name, str):
35
28
  logger.error(f"Tool class {name} must return a valid string from static get_name(). Skipping registration.")
36
29
  return
37
- if not usage_description or not isinstance(usage_description, str):
38
- # Updated error message to reflect source method
39
- logger.error(f"Tool class {name} must return a valid string from class method tool_usage(). Skipping registration.")
30
+
31
+ general_description = cls.get_description()
32
+ if not general_description or not isinstance(general_description, str):
33
+ logger.error(f"Tool class {name} ({tool_name}) must return a valid string from get_description(). Skipping registration.")
40
34
  return
41
35
 
42
- # Create definition using name and the usage description from tool_usage()
43
- definition = ToolDefinition(name=tool_name, description=usage_description)
36
+ argument_schema: ParameterSchema = None
37
+ try:
38
+ argument_schema = cls.get_argument_schema()
39
+ if argument_schema is not None and not isinstance(argument_schema, ParameterSchema):
40
+ logger.error(f"Tool class {name} ({tool_name}) get_argument_schema() must return a ParameterSchema or None. Got {type(argument_schema)}. Skipping registration.")
41
+ return
42
+ except Exception as e:
43
+ logger.error(f"Tool class {name} ({tool_name}) failed to provide argument_schema via get_argument_schema(): {e}. Skipping registration.", exc_info=True)
44
+ return
45
+
46
+ instantiation_config_schema: ParameterSchema = None
47
+ if hasattr(cls, 'get_config_schema'):
48
+ try:
49
+ instantiation_config_schema = cls.get_config_schema()
50
+ if instantiation_config_schema is not None and not isinstance(instantiation_config_schema, ParameterSchema):
51
+ logger.warning(f"Tool class {name} ({tool_name}) get_config_schema() returned non-ParameterSchema type: {type(instantiation_config_schema)}. Treating as no config schema.")
52
+ instantiation_config_schema = None
53
+ except Exception as e:
54
+ logger.warning(f"Tool class {name} ({tool_name}) has get_config_schema() but it failed: {e}. Assuming no instantiation config.")
55
+
56
+ # Create the definition without pre-generating usage strings
57
+ definition = ToolDefinition(
58
+ name=tool_name,
59
+ description=general_description,
60
+ tool_class=cls,
61
+ custom_factory=None,
62
+ argument_schema=argument_schema,
63
+ config_schema=instantiation_config_schema
64
+ )
44
65
  default_tool_registry.register_tool(definition)
45
- logger.info(f"Auto-registered tool: '{tool_name}' from class {name}")
66
+
67
+ arg_schema_info = f"args: {len(argument_schema) if argument_schema else '0'}"
68
+ config_info = f"inst_config: {len(instantiation_config_schema) if instantiation_config_schema else '0'}"
69
+ logger.info(f"Auto-registered tool: '{tool_name}' from class {name} ({arg_schema_info}, {config_info})")
46
70
 
47
71
  except AttributeError as e:
48
- # Catch if required methods are missing (get_name or tool_usage/tool_usage_xml)
49
- logger.error(f"Tool class {name} is missing required static/class method ({e}). Skipping registration.")
72
+ logger.error(f"Tool class {name} is missing a required method ({e}). Skipping registration.")
50
73
  except Exception as e:
51
74
  logger.error(f"Failed to auto-register tool class {name}: {e}", exc_info=True)
52
-
@@ -0,0 +1,6 @@
1
+ # file: autobyteus/autobyteus/tools/usage/__init__.py
2
+ """
3
+ This package contains the framework for generating provider-specific
4
+ tool usage information (schemas and examples) and for parsing
5
+ tool usage from LLM responses.
6
+ """
@@ -0,0 +1,31 @@
1
+ # file: autobyteus/autobyteus/tools/usage/formatters/__init__.py
2
+ """
3
+ This package contains concrete formatter classes that translate a BaseTool's
4
+ metadata into a specific provider's format (e.g., OpenAI JSON, Anthropic JSON, XML).
5
+ """
6
+ from .base_formatter import BaseSchemaFormatter, BaseExampleFormatter
7
+ from .default_xml_schema_formatter import DefaultXmlSchemaFormatter
8
+ from .default_json_schema_formatter import DefaultJsonSchemaFormatter
9
+ from .openai_json_schema_formatter import OpenAiJsonSchemaFormatter
10
+ from .anthropic_json_schema_formatter import AnthropicJsonSchemaFormatter
11
+ from .gemini_json_schema_formatter import GeminiJsonSchemaFormatter
12
+ from .default_xml_example_formatter import DefaultXmlExampleFormatter
13
+ from .default_json_example_formatter import DefaultJsonExampleFormatter
14
+ from .openai_json_example_formatter import OpenAiJsonExampleFormatter
15
+ from .anthropic_json_example_formatter import AnthropicJsonExampleFormatter
16
+ from .gemini_json_example_formatter import GeminiJsonExampleFormatter
17
+
18
+ __all__ = [
19
+ "BaseSchemaFormatter",
20
+ "BaseExampleFormatter",
21
+ "DefaultXmlSchemaFormatter",
22
+ "DefaultJsonSchemaFormatter",
23
+ "OpenAiJsonSchemaFormatter",
24
+ "AnthropicJsonSchemaFormatter",
25
+ "GeminiJsonSchemaFormatter",
26
+ "DefaultXmlExampleFormatter",
27
+ "DefaultJsonExampleFormatter",
28
+ "OpenAiJsonExampleFormatter",
29
+ "AnthropicJsonExampleFormatter",
30
+ "GeminiJsonExampleFormatter",
31
+ ]
@@ -0,0 +1,18 @@
1
+ # file: autobyteus/autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py
2
+ from typing import TYPE_CHECKING
3
+
4
+ from .base_formatter import BaseExampleFormatter
5
+ from .default_xml_example_formatter import DefaultXmlExampleFormatter
6
+
7
+ if TYPE_CHECKING:
8
+ from autobyteus.tools.registry import ToolDefinition
9
+
10
+ class AnthropicJsonExampleFormatter(BaseExampleFormatter):
11
+ """
12
+ Formats a tool usage example for Anthropic models. Since Anthropic uses XML
13
+ for tool calls, this formatter returns a string representing the XML call.
14
+ """
15
+ def provide(self, tool_definition: 'ToolDefinition') -> str:
16
+ # Anthropic expects XML tool call examples.
17
+ # We use the XML formatter's logic directly.
18
+ return DefaultXmlExampleFormatter().provide(tool_definition)
@@ -0,0 +1,25 @@
1
+ # file: autobyteus/autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py
2
+ from typing import Dict, TYPE_CHECKING
3
+
4
+ from .base_formatter import BaseSchemaFormatter
5
+
6
+ if TYPE_CHECKING:
7
+ from autobyteus.tools.registry import ToolDefinition
8
+
9
+ class AnthropicJsonSchemaFormatter(BaseSchemaFormatter):
10
+ """Formats a tool's schema into the Anthropic JSON format."""
11
+
12
+ def provide(self, tool_definition: 'ToolDefinition') -> Dict:
13
+ name = tool_definition.name
14
+ description = tool_definition.description
15
+ arg_schema = tool_definition.argument_schema
16
+
17
+ input_schema = arg_schema.to_json_schema_dict() if arg_schema else {
18
+ "type": "object", "properties": {}, "required": []
19
+ }
20
+
21
+ return {
22
+ "name": name,
23
+ "description": description,
24
+ "input_schema": input_schema,
25
+ }
@@ -0,0 +1,42 @@
1
+ # file: autobyteus/autobyteus/tools/usage/formatters/base_formatter.py
2
+ from abc import ABC, abstractmethod
3
+ from typing import Union, Dict, TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from autobyteus.tools.registry import ToolDefinition
7
+
8
+ class BaseSchemaFormatter(ABC):
9
+ """
10
+ Abstract base class for formatting the schema of a single tool
11
+ into a provider-specific format.
12
+ """
13
+ @abstractmethod
14
+ def provide(self, tool_definition: 'ToolDefinition') -> Union[str, Dict]:
15
+ """
16
+ Formats the schema of the given tool definition.
17
+
18
+ Args:
19
+ tool_definition: The tool definition to format.
20
+
21
+ Returns:
22
+ An XML string or a dictionary representing the tool's schema.
23
+ """
24
+ pass
25
+
26
+ class BaseExampleFormatter(ABC):
27
+ """
28
+ Abstract base class for formatting a usage example of a single tool
29
+ into a provider-specific format.
30
+ """
31
+ @abstractmethod
32
+ def provide(self, tool_definition: 'ToolDefinition') -> Union[str, Dict]:
33
+ """
34
+ Formats a usage example for the given tool definition.
35
+
36
+ Args:
37
+ tool_definition: The tool definition to format an example for.
38
+
39
+ Returns:
40
+ An XML string or a dictionary representing a tool usage example.
41
+ """
42
+ pass
@@ -0,0 +1,42 @@
1
+ # file: autobyteus/autobyteus/tools/usage/formatters/default_json_example_formatter.py
2
+ from typing import Dict, Any, TYPE_CHECKING
3
+
4
+ from autobyteus.tools.parameter_schema import ParameterType, ParameterDefinition
5
+ from .base_formatter import BaseExampleFormatter
6
+
7
+ if TYPE_CHECKING:
8
+ from autobyteus.tools.registry import ToolDefinition
9
+
10
+ class DefaultJsonExampleFormatter(BaseExampleFormatter):
11
+ """
12
+ Formats a tool usage example into a generic JSON format, inspired by
13
+ the default XML format.
14
+ """
15
+
16
+ def provide(self, tool_definition: 'ToolDefinition') -> Dict:
17
+ tool_name = tool_definition.name
18
+ arg_schema = tool_definition.argument_schema
19
+ arguments = {}
20
+
21
+ if arg_schema and arg_schema.parameters:
22
+ for param_def in arg_schema.parameters:
23
+ if param_def.required or param_def.default_value is not None:
24
+ arguments[param_def.name] = self._generate_placeholder_value(param_def)
25
+
26
+ return {
27
+ "tool": {
28
+ "function": tool_name,
29
+ "parameters": arguments,
30
+ },
31
+ }
32
+
33
+ def _generate_placeholder_value(self, param_def: ParameterDefinition) -> Any:
34
+ if param_def.default_value is not None: return param_def.default_value
35
+ if param_def.param_type == ParameterType.STRING: return f"example_{param_def.name}"
36
+ if param_def.param_type == ParameterType.INTEGER: return 123
37
+ if param_def.param_type == ParameterType.FLOAT: return 123.45
38
+ if param_def.param_type == ParameterType.BOOLEAN: return True
39
+ if param_def.param_type == ParameterType.ENUM: return param_def.enum_values[0] if param_def.enum_values else "enum_val"
40
+ if param_def.param_type == ParameterType.OBJECT: return {"key": "value"}
41
+ if param_def.param_type == ParameterType.ARRAY: return ["item1", "item2"]
42
+ return "placeholder"