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
@@ -0,0 +1,186 @@
1
+ # file: autobyteus/autobyteus/agent/handlers/tool_invocation_request_event_handler.py
2
+ import logging
3
+ import json
4
+ import traceback
5
+ from typing import TYPE_CHECKING, Optional
6
+
7
+ from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
8
+ from autobyteus.agent.events import PendingToolInvocationEvent, ToolResultEvent
9
+ from autobyteus.agent.tool_invocation import ToolInvocation
10
+
11
+ if TYPE_CHECKING:
12
+ from autobyteus.agent.context import AgentContext
13
+ from autobyteus.agent.events.notifiers import AgentExternalEventNotifier
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class ToolInvocationRequestEventHandler(AgentEventHandler):
18
+ """
19
+ Handles PendingToolInvocationEvents.
20
+ If 'auto_execute_tools' (from AgentConfig) is False, it stores the invocation,
21
+ updates history, and emits an AGENT_REQUEST_TOOL_INVOCATION_APPROVAL event via the notifier.
22
+ If 'auto_execute_tools' is True, it executes the tool directly, emits
23
+ AGENT_DATA_TOOL_LOG events for call and result/error,
24
+ and queues a ToolResultEvent.
25
+ """
26
+ def __init__(self): # pragma: no cover
27
+ logger.info("ToolInvocationRequestEventHandler initialized.")
28
+
29
+ async def _execute_tool_directly(self,
30
+ tool_invocation: ToolInvocation,
31
+ context: 'AgentContext',
32
+ notifier: Optional['AgentExternalEventNotifier']) -> None: # pragma: no cover
33
+ agent_id = context.agent_id
34
+ tool_name = tool_invocation.name
35
+ arguments = tool_invocation.arguments
36
+ invocation_id = tool_invocation.id
37
+
38
+ logger.info(f"Agent '{agent_id}' executing tool directly: '{tool_name}' (ID: {invocation_id}) with args: {arguments}")
39
+
40
+ try:
41
+ args_str = json.dumps(arguments)
42
+ except TypeError:
43
+ args_str = str(arguments)
44
+
45
+ log_msg_call = f"[TOOL_CALL_DIRECT] Agent_ID: {agent_id}, Tool: {tool_name}, Invocation_ID: {invocation_id}, Arguments: {args_str}"
46
+ if notifier:
47
+ try:
48
+ notifier.notify_agent_data_tool_log(log_msg_call) # USE RENAMED METHOD
49
+ except Exception as e_notify:
50
+ logger.error(f"Agent '{agent_id}': Error notifying tool call log: {e_notify}", exc_info=True)
51
+
52
+ tool_instance = context.get_tool(tool_name)
53
+ result_event: ToolResultEvent
54
+
55
+ if not tool_instance:
56
+ error_message = f"Tool '{tool_name}' not found or configured for agent '{agent_id}'."
57
+ logger.error(error_message)
58
+ result_event = ToolResultEvent(tool_name=tool_name, result=None, error=error_message, tool_invocation_id=invocation_id)
59
+ context.add_message_to_history({
60
+ "role": "tool",
61
+ "tool_call_id": invocation_id,
62
+ "name": tool_name,
63
+ "content": f"Error: Tool '{tool_name}' execution failed. Reason: {error_message}",
64
+ })
65
+ log_msg_error = f"[TOOL_ERROR_DIRECT] Agent_ID: {agent_id}, Tool: {tool_name}, Invocation_ID: {invocation_id}, Error: {error_message}"
66
+ if notifier:
67
+ try:
68
+ notifier.notify_agent_data_tool_log(log_msg_error) # USE RENAMED METHOD
69
+ notifier.notify_agent_error_output_generation( # USE RENAMED METHOD
70
+ error_source=f"ToolExecutionDirect.ToolNotFound.{tool_name}",
71
+ error_message=error_message
72
+ )
73
+ except Exception as e_notify:
74
+ logger.error(f"Agent '{agent_id}': Error notifying tool error log/output error: {e_notify}", exc_info=True)
75
+ else:
76
+ try:
77
+ logger.debug(f"Executing tool '{tool_name}' for agent '{agent_id}'. Invocation ID: {invocation_id}")
78
+ execution_result = await tool_instance.execute(context=context, **arguments)
79
+
80
+ try:
81
+ result_str_for_log = json.dumps(execution_result)
82
+ except TypeError:
83
+ result_str_for_log = str(execution_result)
84
+
85
+ logger.info(f"Tool '{tool_name}' (ID: {invocation_id}) executed by agent '{agent_id}'. Result: {result_str_for_log[:200]}...")
86
+ result_event = ToolResultEvent(tool_name=tool_name, result=execution_result, error=None, tool_invocation_id=invocation_id)
87
+
88
+ history_content = str(execution_result)
89
+ context.add_message_to_history({
90
+ "role": "tool",
91
+ "tool_call_id": invocation_id,
92
+ "name": tool_name,
93
+ "content": history_content,
94
+ })
95
+ log_msg_result = f"[TOOL_RESULT_DIRECT] Agent_ID: {agent_id}, Tool: {tool_name}, Invocation_ID: {invocation_id}, Outcome (first 200 chars): {result_str_for_log[:200]}"
96
+ if notifier:
97
+ try:
98
+ notifier.notify_agent_data_tool_log(log_msg_result) # USE RENAMED METHOD
99
+ except Exception as e_notify:
100
+ logger.error(f"Agent '{agent_id}': Error notifying tool result log: {e_notify}", exc_info=True)
101
+
102
+ except Exception as e:
103
+ error_message = f"Error executing tool '{tool_name}' (ID: {invocation_id}): {str(e)}"
104
+ logger.error(f"Agent '{agent_id}' {error_message}", exc_info=True)
105
+ result_event = ToolResultEvent(tool_name=tool_name, result=None, error=error_message, tool_invocation_id=invocation_id)
106
+ context.add_message_to_history({
107
+ "role": "tool",
108
+ "tool_call_id": invocation_id,
109
+ "name": tool_name,
110
+ "content": f"Error: Tool '{tool_name}' execution failed. Reason: {error_message}",
111
+ })
112
+ log_msg_exception = f"[TOOL_EXCEPTION_DIRECT] Agent_ID: {agent_id}, Tool: {tool_name}, Invocation_ID: {invocation_id}, Exception: {error_message}"
113
+ if notifier:
114
+ try:
115
+ notifier.notify_agent_data_tool_log(log_msg_exception) # USE RENAMED METHOD
116
+ notifier.notify_agent_error_output_generation( # USE RENAMED METHOD
117
+ error_source=f"ToolExecutionDirect.Exception.{tool_name}",
118
+ error_message=error_message,
119
+ error_details=traceback.format_exc()
120
+ )
121
+ except Exception as e_notify:
122
+ logger.error(f"Agent '{agent_id}': Error notifying tool exception log/output error: {e_notify}", exc_info=True)
123
+
124
+ await context.input_event_queues.enqueue_tool_result(result_event)
125
+ logger.debug(f"Agent '{agent_id}' enqueued ToolResultEvent (direct exec) for '{tool_name}' (ID: {invocation_id}).")
126
+
127
+
128
+ async def handle(self,
129
+ event: PendingToolInvocationEvent,
130
+ context: 'AgentContext') -> None: # pragma: no cover
131
+ if not isinstance(event, PendingToolInvocationEvent):
132
+ logger.warning(f"ToolInvocationRequestEventHandler received non-PendingToolInvocationEvent: {type(event)}. Skipping.")
133
+ return
134
+
135
+ tool_invocation: ToolInvocation = event.tool_invocation
136
+ agent_id = context.agent_id
137
+
138
+ notifier: Optional['AgentExternalEventNotifier'] = None
139
+ if context.phase_manager:
140
+ notifier = context.phase_manager.notifier
141
+
142
+ if not notifier:
143
+ logger.error(f"Agent '{agent_id}': Notifier not available in ToolInvocationRequestEventHandler. Output events for tool approval/logging will be lost.")
144
+ if not context.auto_execute_tools:
145
+ logger.critical(f"Agent '{agent_id}': Notifier is REQUIRED for manual tool approval flow but is unavailable. Tool '{tool_invocation.name}' cannot be processed for approval.")
146
+ return
147
+
148
+ if not context.auto_execute_tools:
149
+ logger.info(f"Agent '{agent_id}': Tool '{tool_invocation.name}' (ID: {tool_invocation.id}) requires approval. Storing pending invocation and emitting request.")
150
+
151
+ context.store_pending_tool_invocation(tool_invocation)
152
+
153
+ try:
154
+ arguments_json_str = json.dumps(tool_invocation.arguments or {})
155
+ except TypeError:
156
+ logger.warning(f"Could not serialize args for history tool_call for '{tool_invocation.name}'. Using empty dict string.")
157
+ arguments_json_str = "{}"
158
+
159
+ context.add_message_to_history({
160
+ "role": "assistant",
161
+ "content": None,
162
+ "tool_calls": [{
163
+ "id": tool_invocation.id,
164
+ "type": "function",
165
+ "function": {
166
+ "name": tool_invocation.name,
167
+ "arguments": arguments_json_str
168
+ }
169
+ }]
170
+ })
171
+
172
+ approval_data = {
173
+ "invocation_id": tool_invocation.id,
174
+ "tool_name": tool_invocation.name,
175
+ "arguments": tool_invocation.arguments,
176
+ }
177
+ if notifier:
178
+ try:
179
+ notifier.notify_agent_request_tool_invocation_approval(approval_data) # USE RENAMED METHOD
180
+ logger.debug(f"Agent '{agent_id}': Emitted AGENT_REQUEST_TOOL_INVOCATION_APPROVAL for '{tool_invocation.name}' (ID: {tool_invocation.id}).")
181
+ except Exception as e_notify:
182
+ logger.error(f"Agent '{agent_id}': Error emitting AGENT_REQUEST_TOOL_INVOCATION_APPROVAL: {e_notify}", exc_info=True)
183
+
184
+ else:
185
+ logger.info(f"Agent '{agent_id}': Tool '{tool_invocation.name}' (ID: {tool_invocation.id}) executing automatically (auto_execute_tools=True).")
186
+ await self._execute_tool_directly(tool_invocation, context, notifier)
@@ -0,0 +1,96 @@
1
+ # file: autobyteus/autobyteus/agent/handlers/tool_result_event_handler.py
2
+ import logging
3
+ import json
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
7
+ from autobyteus.agent.events import ToolResultEvent, LLMUserMessageReadyEvent
8
+ from autobyteus.llm.user_message import LLMUserMessage
9
+
10
+ if TYPE_CHECKING:
11
+ from autobyteus.agent.context import AgentContext
12
+ from autobyteus.agent.events.notifiers import AgentExternalEventNotifier
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ class ToolResultEventHandler(AgentEventHandler):
17
+ """
18
+ Handles ToolResultEvents by formatting the tool's output (or error)
19
+ as a new LLMUserMessage, emitting AGENT_DATA_TOOL_LOG event for this outcome,
20
+ and enqueuing an LLMUserMessageReadyEvent for further LLM processing.
21
+ """
22
+ def __init__(self):
23
+ logger.info("ToolResultEventHandler initialized.")
24
+
25
+ async def handle(self,
26
+ event: ToolResultEvent,
27
+ context: 'AgentContext') -> None:
28
+ if not isinstance(event, ToolResultEvent):
29
+ logger.warning(f"ToolResultEventHandler received non-ToolResultEvent: {type(event)}. Skipping.")
30
+ return
31
+
32
+ agent_id = context.agent_id
33
+ tool_invocation_id = event.tool_invocation_id if event.tool_invocation_id else 'N/A'
34
+
35
+ logger.info(f"Agent '{agent_id}' handling ToolResultEvent from tool: '{event.tool_name}' (Invocation ID: {tool_invocation_id}). Error: {event.error is not None}")
36
+
37
+ notifier: Optional['AgentExternalEventNotifier'] = None
38
+ if context.phase_manager:
39
+ notifier = context.phase_manager.notifier
40
+
41
+ if not notifier: # pragma: no cover
42
+ logger.error(f"Agent '{agent_id}': Notifier not available in ToolResultEventHandler. Tool result processing logs will not be emitted.")
43
+
44
+ if event.error:
45
+ logger.debug(f"Agent '{agent_id}' tool '{event.tool_name}' (ID: {tool_invocation_id}) raw error details: {event.error}")
46
+ else:
47
+ try:
48
+ raw_result_str_for_debug_log = json.dumps(event.result, indent=2)
49
+ except TypeError: # pragma: no cover
50
+ raw_result_str_for_debug_log = str(event.result)
51
+ logger.debug(f"Agent '{agent_id}' tool '{event.tool_name}' (ID: {tool_invocation_id}) raw result:\n---\n{raw_result_str_for_debug_log}\n---")
52
+
53
+
54
+ content_for_llm: str
55
+ if event.error:
56
+ content_for_llm = (
57
+ f"The tool '{event.tool_name}' (invocation ID: {tool_invocation_id}) encountered an error.\n"
58
+ f"Error details: {event.error}\n"
59
+ f"Please analyze this error and decide the next course of action."
60
+ )
61
+ log_msg_error_processed = f"[TOOL_RESULT_ERROR_PROCESSED] Agent_ID: {agent_id}, Tool: {event.tool_name}, Invocation_ID: {tool_invocation_id}, Error: {event.error}"
62
+ if notifier:
63
+ try:
64
+ notifier.notify_agent_data_tool_log(log_msg_error_processed) # USE RENAMED METHOD
65
+ except Exception as e_notify:
66
+ logger.error(f"Agent '{agent_id}': Error notifying tool result error log: {e_notify}", exc_info=True)
67
+ else:
68
+ try:
69
+ result_str_for_llm = json.dumps(event.result, indent=2) if not isinstance(event.result, str) else event.result
70
+ except TypeError: # pragma: no cover
71
+ result_str_for_llm = str(event.result)
72
+
73
+ max_len = 2000
74
+ if len(result_str_for_llm) > max_len: # pragma: no cover
75
+ original_len = len(str(event.result))
76
+ result_str_for_llm = result_str_for_llm[:max_len] + f"... (result truncated, original length {original_len})"
77
+
78
+ content_for_llm = (
79
+ f"The tool '{event.tool_name}' (invocation ID: {tool_invocation_id}) has executed.\n"
80
+ f"Result:\n{result_str_for_llm}\n"
81
+ f"Based on this result, what is the next step or final answer?"
82
+ )
83
+ log_msg_success_processed = f"[TOOL_RESULT_SUCCESS_PROCESSED] Agent_ID: {agent_id}, Tool: {event.tool_name}, Invocation_ID: {tool_invocation_id}, Result (first 200 chars of stringified): {str(event.result)[:200]}"
84
+ if notifier:
85
+ try:
86
+ notifier.notify_agent_data_tool_log(log_msg_success_processed) # USE RENAMED METHOD
87
+ except Exception as e_notify:
88
+ logger.error(f"Agent '{agent_id}': Error notifying tool result success log: {e_notify}", exc_info=True)
89
+
90
+ logger.debug(f"Agent '{agent_id}' preparing message for LLM based on tool '{event.tool_name}' (ID: {tool_invocation_id}) result:\n---\n{content_for_llm}\n---")
91
+ llm_user_message = LLMUserMessage(content=content_for_llm)
92
+
93
+ next_event = LLMUserMessageReadyEvent(llm_user_message=llm_user_message)
94
+ await context.input_event_queues.enqueue_internal_system_event(next_event)
95
+
96
+ logger.info(f"Agent '{agent_id}' enqueued LLMUserMessageReadyEvent for LLM based on tool '{event.tool_name}' (ID: {tool_invocation_id}) result summary.")
@@ -0,0 +1,77 @@
1
+ # file: autobyteus/autobyteus/agent/handlers/user_input_message_event_handler.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from autobyteus.agent.handlers.base_event_handler import AgentEventHandler
6
+ from autobyteus.agent.events import UserMessageReceivedEvent, LLMUserMessageReadyEvent
7
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
8
+ from autobyteus.agent.input_processor import BaseAgentUserInputMessageProcessor
9
+ from autobyteus.llm.user_message import LLMUserMessage
10
+
11
+
12
+ if TYPE_CHECKING:
13
+ from autobyteus.agent.context import AgentContext
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class UserInputMessageEventHandler(AgentEventHandler):
18
+ """
19
+ Handles UserMessageReceivedEvents by first applying any configured
20
+ AgentUserInputMessageProcessors (provided as instances) to the AgentInputUserMessage,
21
+ then converting the processed message into an LLMUserMessage, and finally
22
+ enqueuing an LLMUserMessageReadyEvent for further processing by the LLM.
23
+ """
24
+
25
+ def __init__(self):
26
+ logger.info("UserInputMessageEventHandler initialized.")
27
+
28
+ async def handle(self,
29
+ event: UserMessageReceivedEvent,
30
+ context: 'AgentContext') -> None:
31
+ if not isinstance(event, UserMessageReceivedEvent):
32
+ logger.warning(f"UserInputMessageEventHandler received non-UserMessageReceivedEvent: {type(event)}. Skipping.")
33
+ return
34
+
35
+ original_agent_input_user_msg: AgentInputUserMessage = event.agent_input_user_message
36
+ processed_agent_input_user_msg: AgentInputUserMessage = original_agent_input_user_msg
37
+
38
+ logger.info(f"Agent '{context.agent_id}' handling UserMessageReceivedEvent: '{original_agent_input_user_msg.content[:100]}...'")
39
+
40
+ processor_instances = context.config.input_processors
41
+ if processor_instances:
42
+ processor_names = [p.get_name() for p in processor_instances]
43
+ logger.debug(f"Agent '{context.agent_id}': Applying input processors: {processor_names}")
44
+ for processor_instance in processor_instances:
45
+ processor_name_for_log = "unknown"
46
+ try:
47
+ if not isinstance(processor_instance, BaseAgentUserInputMessageProcessor):
48
+ logger.error(f"Agent '{context.agent_id}': Invalid input processor type in config: {type(processor_instance)}. Skipping.")
49
+ continue
50
+
51
+ processor_name_for_log = processor_instance.get_name()
52
+ logger.debug(f"Agent '{context.agent_id}': Applying input processor '{processor_name_for_log}'.")
53
+ msg_before_this_processor = processed_agent_input_user_msg
54
+ # Pass the original event to the processor
55
+ processed_agent_input_user_msg = await processor_instance.process(
56
+ message=msg_before_this_processor,
57
+ context=context,
58
+ triggering_event=event
59
+ )
60
+ logger.info(f"Agent '{context.agent_id}': Input processor '{processor_name_for_log}' applied successfully.")
61
+
62
+ except Exception as e:
63
+ logger.error(f"Agent '{context.agent_id}': Error applying input processor '{processor_name_for_log}': {e}. "
64
+ f"Skipping this processor and continuing with message from before this processor.", exc_info=True)
65
+ processed_agent_input_user_msg = msg_before_this_processor
66
+ else:
67
+ logger.debug(f"Agent '{context.agent_id}': No input processors configured in agent config.")
68
+
69
+ llm_user_message = LLMUserMessage(
70
+ content=processed_agent_input_user_msg.content,
71
+ image_urls=processed_agent_input_user_msg.image_urls
72
+ )
73
+
74
+ llm_user_message_ready_event = LLMUserMessageReadyEvent(llm_user_message=llm_user_message)
75
+ await context.input_event_queues.enqueue_internal_system_event(llm_user_message_ready_event)
76
+
77
+ logger.info(f"Agent '{context.agent_id}' processed AgentInputUserMessage and enqueued LLMUserMessageReadyEvent.")
@@ -0,0 +1,9 @@
1
+ # file: autobyteus/autobyteus/agent/hooks/__init__.py
2
+ """
3
+ Components for defining and running lifecycle hooks based on agent phase transitions.
4
+ """
5
+ from .base_phase_hook import BasePhaseHook
6
+
7
+ __all__ = [
8
+ "BasePhaseHook",
9
+ ]
@@ -0,0 +1,52 @@
1
+ # file: autobyteus/autobyteus/agent/hooks/base_phase_hook.py
2
+ import logging
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING
5
+
6
+ from autobyteus.agent.context.phases import AgentOperationalPhase
7
+
8
+ if TYPE_CHECKING:
9
+ from autobyteus.agent.context import AgentContext
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class BasePhaseHook(ABC):
14
+ """
15
+ Abstract base class for creating hooks that execute on specific agent
16
+ phase transitions.
17
+
18
+ Subclasses must define the `source_phase` and `target_phase` to specify
19
+ the exact transition they are interested in, and implement the `execute`
20
+ method for their custom logic.
21
+ """
22
+
23
+ @property
24
+ @abstractmethod
25
+ def source_phase(self) -> AgentOperationalPhase:
26
+ """The source phase for the transition this hook targets."""
27
+ raise NotImplementedError
28
+
29
+ @property
30
+ @abstractmethod
31
+ def target_phase(self) -> AgentOperationalPhase:
32
+ """The target phase for the transition this hook targets."""
33
+ raise NotImplementedError
34
+
35
+ @abstractmethod
36
+ async def execute(self, context: 'AgentContext') -> None:
37
+ """
38
+ The method executed when the specified phase transition occurs.
39
+
40
+ Args:
41
+ context: The agent's context at the time of the transition.
42
+ """
43
+ raise NotImplementedError
44
+
45
+ def __repr__(self) -> str:
46
+ # Use try-except in case properties are not yet implemented during introspection
47
+ try:
48
+ return (f"<{self.__class__.__name__} "
49
+ f"source='{self.source_phase.value}' "
50
+ f"target='{self.target_phase.value}'>")
51
+ except (NotImplementedError, AttributeError):
52
+ return f"<{self.__class__.__name__} (unconfigured)>"
@@ -0,0 +1,18 @@
1
+ # file: autobyteus/autobyteus/agent/input_processor/__init__.py
2
+ """
3
+ Components for pre-processing AgentUserMessage objects.
4
+ """
5
+ from .base_user_input_processor import BaseAgentUserInputMessageProcessor
6
+
7
+ # Import concrete processors to make them easily accessible for instantiation
8
+ from .passthrough_input_processor import PassthroughInputProcessor
9
+ from .metadata_appending_input_processor import MetadataAppendingInputProcessor
10
+ from .content_prefixing_input_processor import ContentPrefixingInputProcessor
11
+
12
+
13
+ __all__ = [
14
+ "BaseAgentUserInputMessageProcessor",
15
+ "PassthroughInputProcessor",
16
+ "MetadataAppendingInputProcessor",
17
+ "ContentPrefixingInputProcessor",
18
+ ]
@@ -0,0 +1,51 @@
1
+ # file: autobyteus/autobyteus/agent/input_processor/base_user_input_processor.py
2
+ import logging
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ if TYPE_CHECKING:
7
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
8
+ from autobyteus.agent.context import AgentContext # Composite AgentContext
9
+ from autobyteus.agent.events import UserMessageReceivedEvent
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class BaseAgentUserInputMessageProcessor(ABC):
14
+ """
15
+ Abstract base class for agent user input message processors.
16
+ These processors can modify an AgentInputUserMessage, specifically from a user,
17
+ before it is converted to an LLMUserMessage.
18
+ Subclasses should be instantiated and passed to the AgentSpecification.
19
+ """
20
+
21
+ def get_name(self) -> str:
22
+ """
23
+ Returns the unique registration name for this processor.
24
+ Defaults to the class name. Can be overridden by subclasses.
25
+ """
26
+ return self.__class__.__name__
27
+
28
+ @abstractmethod
29
+ async def process(self,
30
+ message: 'AgentInputUserMessage',
31
+ context: 'AgentContext',
32
+ triggering_event: 'UserMessageReceivedEvent') -> 'AgentInputUserMessage':
33
+ """
34
+ Processes the given AgentInputUserMessage.
35
+
36
+ Args:
37
+ message: The AgentInputUserMessage to process.
38
+ context: The composite AgentContext, providing access to agent's config and state.
39
+ triggering_event: The original UserMessageReceivedEvent that triggered this processing.
40
+ This provides access to the full event payload for more complex processors.
41
+
42
+ Returns:
43
+ The processed (potentially modified) AgentInputUserMessage.
44
+
45
+ Raises:
46
+ NotImplementedError: If the subclass does not implement this method.
47
+ """
48
+ raise NotImplementedError("Subclasses must implement the 'process' method.")
49
+
50
+ def __repr__(self) -> str:
51
+ return f"<{self.__class__.__name__}>"
@@ -0,0 +1,41 @@
1
+ # file: autobyteus/autobyteus/agent/input_processor/content_prefixing_input_processor.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .base_user_input_processor import BaseAgentUserInputMessageProcessor
6
+
7
+ if TYPE_CHECKING:
8
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
+ from autobyteus.agent.context import AgentContext # Composite AgentContext
10
+ from autobyteus.agent.events import UserMessageReceivedEvent
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class ContentPrefixingInputProcessor(BaseAgentUserInputMessageProcessor):
15
+ """
16
+ A processor that adds a predefined prefix to the message content.
17
+ The prefix is defined by the agent's custom_data (in AgentRuntimeState) or a default.
18
+ Example prefix key in custom_data: "content_prefix"
19
+ """
20
+ DEFAULT_PREFIX = "[Processed Message] "
21
+
22
+ async def process(self,
23
+ message: 'AgentInputUserMessage',
24
+ context: 'AgentContext',
25
+ triggering_event: 'UserMessageReceivedEvent') -> 'AgentInputUserMessage':
26
+ """
27
+ Handles the message by prefixing its content.
28
+ The 'triggering_event' parameter is ignored by this processor.
29
+ """
30
+ agent_id = context.agent_id # Convenience property
31
+ logger.debug(f"Agent '{agent_id}': ContentPrefixingInputProcessor processing message.")
32
+
33
+ # Access custom_data via convenience property (or context.state.custom_data)
34
+ prefix = context.custom_data.get("content_prefix", self.DEFAULT_PREFIX)
35
+ if not isinstance(prefix, str):
36
+ logger.warning(f"Agent '{agent_id}': 'content_prefix' in custom_data is not a string. Using default prefix. Found: {type(prefix)}")
37
+ prefix = self.DEFAULT_PREFIX
38
+
39
+ message.content = prefix + message.content
40
+ logger.info(f"Agent '{agent_id}': Prefixed message content with '{prefix}'.")
41
+ return message
@@ -0,0 +1,34 @@
1
+ # file: autobyteus/autobyteus/agent/input_processor/metadata_appending_input_processor.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .base_user_input_processor import BaseAgentUserInputMessageProcessor
6
+
7
+ if TYPE_CHECKING:
8
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
+ from autobyteus.agent.context import AgentContext # Composite AgentContext
10
+ from autobyteus.agent.events import UserMessageReceivedEvent
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class MetadataAppendingInputProcessor(BaseAgentUserInputMessageProcessor):
15
+ """
16
+ A processor that appends fixed metadata to the message.
17
+ Example: Appends agent_id and config_name to metadata.
18
+ """
19
+ async def process(self,
20
+ message: 'AgentInputUserMessage',
21
+ context: 'AgentContext',
22
+ triggering_event: 'UserMessageReceivedEvent') -> 'AgentInputUserMessage':
23
+ """
24
+ Handles the message by appending metadata.
25
+ The 'triggering_event' parameter is ignored by this processor.
26
+ """
27
+ agent_id = context.agent_id
28
+ config_name = context.config.name
29
+
30
+ logger.debug(f"Agent '{agent_id}': MetadataAppendingInputProcessor processing message.")
31
+ message.metadata["processed_by_agent_id"] = agent_id
32
+ message.metadata["processed_with_config_name"] = config_name
33
+ logger.info(f"Agent '{agent_id}': Appended 'processed_by_agent_id' and 'processed_with_config_name' to message metadata.")
34
+ return message
@@ -0,0 +1,32 @@
1
+ # file: autobyteus/autobyteus/agent/input_processor/passthrough_input_processor.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .base_user_input_processor import BaseAgentUserInputMessageProcessor
6
+
7
+ if TYPE_CHECKING:
8
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
+ from autobyteus.agent.context import AgentContext # Composite AgentContext
10
+ from autobyteus.agent.events import UserMessageReceivedEvent
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class PassthroughInputProcessor(BaseAgentUserInputMessageProcessor):
15
+ """
16
+ A processor that returns the message unchanged.
17
+ Can be used as a default or for testing.
18
+ """
19
+ def get_name(self) -> str:
20
+ return "PassthroughInputProcessor"
21
+
22
+ async def process(self,
23
+ message: 'AgentInputUserMessage',
24
+ context: 'AgentContext',
25
+ triggering_event: 'UserMessageReceivedEvent') -> 'AgentInputUserMessage':
26
+ """
27
+ Handles the message by returning it without modification.
28
+ The 'triggering_event' parameter is ignored by this processor.
29
+ """
30
+ agent_id = context.agent_id # Convenience property
31
+ logger.debug(f"Agent '{agent_id}': PassthroughInputProcessor received message, returning as is.")
32
+ return message
@@ -0,0 +1,42 @@
1
+ # file: autobyteus/autobyteus/agent/input_processor/processor_definition.py
2
+ import logging
3
+ from typing import Type, TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from .base_user_input_processor import BaseAgentUserInputMessageProcessor
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class AgentUserInputMessageProcessorDefinition:
11
+ """
12
+ Represents the definition of an agent user input message processor.
13
+ Contains its registered name and the class itself.
14
+ """
15
+ def __init__(self, name: str, processor_class: Type['BaseAgentUserInputMessageProcessor']):
16
+ """
17
+ Initializes the AgentUserInputMessageProcessorDefinition.
18
+
19
+ Args:
20
+ name: The unique registered name of the processor.
21
+ processor_class: The class of the input processor.
22
+
23
+ Raises:
24
+ ValueError: If name is empty or processor_class is not a type.
25
+ """
26
+ if not name or not isinstance(name, str):
27
+ raise ValueError("Processor name must be a non-empty string.")
28
+ if not isinstance(processor_class, type): # Check if it's actually a class
29
+ raise ValueError("processor_class must be a class type.")
30
+
31
+ # Further check if it's a subclass of BaseAgentUserInputMessageProcessor might be too restrictive
32
+ # here if base class is not yet defined due to import cycles, metaclass handles this better.
33
+ # from .base_user_input_processor import BaseAgentUserInputMessageProcessor # Delayed import for check
34
+ # if not issubclass(processor_class, BaseAgentUserInputMessageProcessor):
35
+ # raise ValueError(f"processor_class '{processor_class.__name__}' must be a subclass of BaseAgentUserInputMessageProcessor.")
36
+
37
+ self.name: str = name
38
+ self.processor_class: Type['BaseAgentUserInputMessageProcessor'] = processor_class
39
+ logger.debug(f"AgentUserInputMessageProcessorDefinition created: name='{name}', class='{processor_class.__name__}'.")
40
+
41
+ def __repr__(self) -> str:
42
+ return f"<AgentUserInputMessageProcessorDefinition name='{self.name}', class='{self.processor_class.__name__}'>"