autobyteus 1.0.6__py3-none-any.whl → 1.1.1__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 (270) 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 +13 -0
  9. autobyteus/agent/context/agent_config.py +84 -0
  10. autobyteus/agent/context/agent_context.py +129 -0
  11. autobyteus/agent/context/agent_phase_manager.py +264 -0
  12. autobyteus/agent/context/agent_runtime_state.py +89 -0
  13. autobyteus/agent/context/phases.py +49 -0
  14. autobyteus/agent/events/__init__.py +52 -0
  15. autobyteus/agent/events/agent_events.py +110 -0
  16. autobyteus/agent/events/agent_input_event_queue_manager.py +174 -0
  17. autobyteus/agent/events/notifiers.py +122 -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 +145 -0
  21. autobyteus/agent/group/agent_group.py +164 -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 +148 -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 +138 -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 +211 -0
  34. autobyteus/agent/handlers/tool_result_event_handler.py +101 -0
  35. autobyteus/agent/handlers/user_input_message_event_handler.py +77 -0
  36. autobyteus/agent/hooks/__init__.py +16 -0
  37. autobyteus/agent/hooks/base_phase_hook.py +61 -0
  38. autobyteus/agent/hooks/hook_definition.py +36 -0
  39. autobyteus/agent/hooks/hook_meta.py +37 -0
  40. autobyteus/agent/hooks/hook_registry.py +118 -0
  41. autobyteus/agent/input_processor/__init__.py +18 -0
  42. autobyteus/agent/input_processor/base_user_input_processor.py +54 -0
  43. autobyteus/agent/input_processor/content_prefixing_input_processor.py +41 -0
  44. autobyteus/agent/input_processor/metadata_appending_input_processor.py +34 -0
  45. autobyteus/agent/input_processor/passthrough_input_processor.py +33 -0
  46. autobyteus/agent/input_processor/processor_definition.py +42 -0
  47. autobyteus/agent/input_processor/processor_meta.py +46 -0
  48. autobyteus/agent/input_processor/processor_registry.py +117 -0
  49. autobyteus/agent/llm_response_processor/__init__.py +16 -0
  50. autobyteus/agent/llm_response_processor/base_processor.py +53 -0
  51. autobyteus/agent/llm_response_processor/processor_definition.py +36 -0
  52. autobyteus/agent/llm_response_processor/processor_meta.py +37 -0
  53. autobyteus/agent/llm_response_processor/processor_registry.py +113 -0
  54. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +54 -0
  55. autobyteus/agent/message/__init__.py +20 -0
  56. autobyteus/agent/message/agent_input_user_message.py +96 -0
  57. autobyteus/agent/message/context_file.py +82 -0
  58. autobyteus/agent/message/context_file_type.py +63 -0
  59. autobyteus/agent/message/{message.py → inter_agent_message.py} +12 -12
  60. autobyteus/agent/message/{message_types.py → inter_agent_message_type.py} +8 -6
  61. autobyteus/agent/message/send_message_to.py +142 -36
  62. autobyteus/agent/phases/__init__.py +18 -0
  63. autobyteus/agent/phases/discover.py +52 -0
  64. autobyteus/agent/phases/manager.py +265 -0
  65. autobyteus/agent/phases/phase_enum.py +49 -0
  66. autobyteus/agent/phases/transition_decorator.py +40 -0
  67. autobyteus/agent/phases/transition_info.py +33 -0
  68. autobyteus/agent/remote_agent.py +244 -0
  69. autobyteus/agent/runtime/__init__.py +15 -0
  70. autobyteus/agent/runtime/agent_runtime.py +137 -0
  71. autobyteus/agent/runtime/agent_thread_pool_manager.py +88 -0
  72. autobyteus/agent/runtime/agent_worker.py +200 -0
  73. autobyteus/agent/streaming/__init__.py +15 -0
  74. autobyteus/agent/streaming/agent_event_stream.py +173 -0
  75. autobyteus/agent/streaming/queue_streamer.py +58 -0
  76. autobyteus/agent/streaming/stream_event_payloads.py +167 -0
  77. autobyteus/agent/streaming/stream_events.py +126 -0
  78. autobyteus/agent/system_prompt_processor/__init__.py +14 -0
  79. autobyteus/agent/system_prompt_processor/base_processor.py +48 -0
  80. autobyteus/agent/system_prompt_processor/processor_definition.py +40 -0
  81. autobyteus/agent/system_prompt_processor/processor_meta.py +47 -0
  82. autobyteus/agent/system_prompt_processor/processor_registry.py +119 -0
  83. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +79 -0
  84. autobyteus/agent/tool_invocation.py +54 -5
  85. autobyteus/agent/utils/__init__.py +9 -0
  86. autobyteus/agent/utils/wait_for_idle.py +59 -0
  87. autobyteus/agent/workflow/__init__.py +11 -0
  88. autobyteus/agent/workflow/agentic_workflow.py +89 -0
  89. autobyteus/agent/workflow/base_agentic_workflow.py +98 -0
  90. autobyteus/agent/workspace/__init__.py +11 -0
  91. autobyteus/agent/workspace/base_workspace.py +77 -0
  92. autobyteus/agent/workspace/workspace_config.py +160 -0
  93. autobyteus/agent/workspace/workspace_definition.py +36 -0
  94. autobyteus/agent/workspace/workspace_meta.py +37 -0
  95. autobyteus/agent/workspace/workspace_registry.py +72 -0
  96. autobyteus/cli/__init__.py +11 -0
  97. autobyteus/cli/agent_cli.py +117 -0
  98. autobyteus/cli/cli_display.py +205 -0
  99. autobyteus/events/event_emitter.py +33 -56
  100. autobyteus/events/event_manager.py +134 -66
  101. autobyteus/events/event_types.py +43 -14
  102. autobyteus/llm/api/autobyteus_llm.py +13 -25
  103. autobyteus/llm/api/bedrock_llm.py +9 -3
  104. autobyteus/llm/api/claude_llm.py +10 -5
  105. autobyteus/llm/api/deepseek_llm.py +55 -93
  106. autobyteus/llm/api/gemini_llm.py +10 -4
  107. autobyteus/llm/api/grok_llm.py +55 -79
  108. autobyteus/llm/api/groq_llm.py +10 -5
  109. autobyteus/llm/api/mistral_llm.py +13 -8
  110. autobyteus/llm/api/nvidia_llm.py +9 -4
  111. autobyteus/llm/api/ollama_llm.py +58 -50
  112. autobyteus/llm/api/openai_llm.py +20 -14
  113. autobyteus/llm/base_llm.py +95 -34
  114. autobyteus/llm/extensions/base_extension.py +3 -4
  115. autobyteus/llm/extensions/token_usage_tracking_extension.py +13 -4
  116. autobyteus/llm/llm_factory.py +116 -53
  117. autobyteus/llm/models.py +92 -17
  118. autobyteus/llm/ollama_provider.py +6 -2
  119. autobyteus/llm/ollama_provider_resolver.py +44 -0
  120. autobyteus/llm/user_message.py +73 -0
  121. autobyteus/llm/utils/llm_config.py +124 -27
  122. autobyteus/llm/utils/response_types.py +3 -2
  123. autobyteus/llm/utils/token_usage.py +7 -4
  124. autobyteus/rpc/__init__.py +73 -0
  125. autobyteus/rpc/client/__init__.py +17 -0
  126. autobyteus/rpc/client/abstract_client_connection.py +124 -0
  127. autobyteus/rpc/client/client_connection_manager.py +153 -0
  128. autobyteus/rpc/client/sse_client_connection.py +306 -0
  129. autobyteus/rpc/client/stdio_client_connection.py +280 -0
  130. autobyteus/rpc/config/__init__.py +13 -0
  131. autobyteus/rpc/config/agent_server_config.py +153 -0
  132. autobyteus/rpc/config/agent_server_registry.py +152 -0
  133. autobyteus/rpc/hosting.py +244 -0
  134. autobyteus/rpc/protocol.py +244 -0
  135. autobyteus/rpc/server/__init__.py +20 -0
  136. autobyteus/rpc/server/agent_server_endpoint.py +181 -0
  137. autobyteus/rpc/server/base_method_handler.py +40 -0
  138. autobyteus/rpc/server/method_handlers.py +259 -0
  139. autobyteus/rpc/server/sse_server_handler.py +182 -0
  140. autobyteus/rpc/server/stdio_server_handler.py +151 -0
  141. autobyteus/rpc/server_main.py +198 -0
  142. autobyteus/rpc/transport_type.py +13 -0
  143. autobyteus/tools/__init__.py +77 -0
  144. autobyteus/tools/ask_user_input.py +34 -77
  145. autobyteus/tools/base_tool.py +73 -38
  146. autobyteus/tools/bash/__init__.py +2 -0
  147. autobyteus/tools/bash/bash_executor.py +42 -79
  148. autobyteus/tools/browser/__init__.py +2 -0
  149. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +50 -42
  150. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +7 -4
  151. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +117 -125
  152. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +75 -22
  153. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +94 -28
  154. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +10 -2
  155. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +18 -2
  156. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +10 -2
  157. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +4 -3
  158. autobyteus/tools/browser/standalone/__init__.py +7 -0
  159. autobyteus/tools/browser/standalone/factory/google_search_factory.py +17 -2
  160. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +17 -2
  161. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +10 -2
  162. autobyteus/tools/browser/standalone/google_search_ui.py +104 -67
  163. autobyteus/tools/browser/standalone/navigate_to.py +52 -28
  164. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +94 -0
  165. autobyteus/tools/browser/standalone/webpage_image_downloader.py +146 -61
  166. autobyteus/tools/browser/standalone/webpage_reader.py +80 -61
  167. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +91 -45
  168. autobyteus/tools/factory/__init__.py +9 -0
  169. autobyteus/tools/factory/tool_factory.py +25 -4
  170. autobyteus/tools/file/file_reader.py +22 -51
  171. autobyteus/tools/file/file_writer.py +25 -56
  172. autobyteus/tools/functional_tool.py +249 -0
  173. autobyteus/tools/image_downloader.py +49 -71
  174. autobyteus/tools/mcp/__init__.py +47 -0
  175. autobyteus/tools/mcp/call_handlers/__init__.py +18 -0
  176. autobyteus/tools/mcp/call_handlers/base_handler.py +40 -0
  177. autobyteus/tools/mcp/call_handlers/sse_handler.py +22 -0
  178. autobyteus/tools/mcp/call_handlers/stdio_handler.py +76 -0
  179. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +55 -0
  180. autobyteus/tools/mcp/config_service.py +237 -0
  181. autobyteus/tools/mcp/factory.py +70 -0
  182. autobyteus/tools/mcp/registrar.py +323 -0
  183. autobyteus/tools/mcp/schema_mapper.py +131 -0
  184. autobyteus/tools/mcp/tool.py +101 -0
  185. autobyteus/tools/mcp/types.py +98 -0
  186. autobyteus/tools/parameter_schema.py +268 -0
  187. autobyteus/tools/pdf_downloader.py +78 -79
  188. autobyteus/tools/registry/__init__.py +0 -2
  189. autobyteus/tools/registry/tool_definition.py +113 -34
  190. autobyteus/tools/registry/tool_registry.py +64 -22
  191. autobyteus/tools/timer.py +150 -102
  192. autobyteus/tools/tool_category.py +11 -0
  193. autobyteus/tools/tool_config.py +117 -0
  194. autobyteus/tools/tool_meta.py +50 -26
  195. autobyteus/tools/tool_state.py +20 -0
  196. autobyteus/tools/usage/__init__.py +6 -0
  197. autobyteus/tools/usage/formatters/__init__.py +31 -0
  198. autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py +18 -0
  199. autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py +25 -0
  200. autobyteus/tools/usage/formatters/base_formatter.py +42 -0
  201. autobyteus/tools/usage/formatters/default_json_example_formatter.py +42 -0
  202. autobyteus/tools/usage/formatters/default_json_schema_formatter.py +28 -0
  203. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +55 -0
  204. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +46 -0
  205. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +34 -0
  206. autobyteus/tools/usage/formatters/gemini_json_schema_formatter.py +25 -0
  207. autobyteus/tools/usage/formatters/google_json_example_formatter.py +34 -0
  208. autobyteus/tools/usage/formatters/google_json_schema_formatter.py +25 -0
  209. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +49 -0
  210. autobyteus/tools/usage/formatters/openai_json_schema_formatter.py +28 -0
  211. autobyteus/tools/usage/parsers/__init__.py +22 -0
  212. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +10 -0
  213. autobyteus/tools/usage/parsers/base_parser.py +41 -0
  214. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +106 -0
  215. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +136 -0
  216. autobyteus/tools/usage/parsers/exceptions.py +13 -0
  217. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +66 -0
  218. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +196 -0
  219. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +67 -0
  220. autobyteus/tools/usage/providers/__init__.py +22 -0
  221. autobyteus/tools/usage/providers/json_example_provider.py +32 -0
  222. autobyteus/tools/usage/providers/json_schema_provider.py +35 -0
  223. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +28 -0
  224. autobyteus/tools/usage/providers/tool_manifest_provider.py +68 -0
  225. autobyteus/tools/usage/providers/xml_example_provider.py +28 -0
  226. autobyteus/tools/usage/providers/xml_schema_provider.py +29 -0
  227. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +26 -0
  228. autobyteus/tools/usage/registries/__init__.py +20 -0
  229. autobyteus/tools/usage/registries/json_example_formatter_registry.py +51 -0
  230. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +51 -0
  231. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +42 -0
  232. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +30 -0
  233. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +33 -0
  234. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +30 -0
  235. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/METADATA +23 -5
  236. autobyteus-1.1.1.dist-info/RECORD +296 -0
  237. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/WHEEL +1 -1
  238. autobyteus/agent/async_agent.py +0 -175
  239. autobyteus/agent/async_group_aware_agent.py +0 -136
  240. autobyteus/agent/group/async_group_aware_agent.py +0 -122
  241. autobyteus/agent/group/coordinator_agent.py +0 -36
  242. autobyteus/agent/group/group_aware_agent.py +0 -121
  243. autobyteus/agent/orchestrator/__init__.py +0 -0
  244. autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -82
  245. autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -72
  246. autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -43
  247. autobyteus/agent/response_parser/__init__.py +0 -0
  248. autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -100
  249. autobyteus/agent/status.py +0 -12
  250. autobyteus/conversation/__init__.py +0 -0
  251. autobyteus/conversation/conversation.py +0 -54
  252. autobyteus/conversation/user_message.py +0 -59
  253. autobyteus/events/decorators.py +0 -29
  254. autobyteus/prompt/prompt_version_manager.py +0 -58
  255. autobyteus/prompt/storage/__init__.py +0 -0
  256. autobyteus/prompt/storage/prompt_version_model.py +0 -29
  257. autobyteus/prompt/storage/prompt_version_repository.py +0 -83
  258. autobyteus/tools/bash/factory/__init__.py +0 -0
  259. autobyteus/tools/bash/factory/bash_executor_factory.py +0 -6
  260. autobyteus/tools/factory/ask_user_input_factory.py +0 -6
  261. autobyteus/tools/factory/image_downloader_factory.py +0 -9
  262. autobyteus/tools/factory/pdf_downloader_factory.py +0 -9
  263. autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -6
  264. autobyteus/tools/file/factory/__init__.py +0 -0
  265. autobyteus/tools/file/factory/file_reader_factory.py +0 -6
  266. autobyteus/tools/file/factory/file_writer_factory.py +0 -6
  267. autobyteus/tools/web_page_pdf_generator.py +0 -90
  268. autobyteus-1.0.6.dist-info/RECORD +0 -157
  269. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/licenses/LICENSE +0 -0
  270. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/top_level.txt +0 -0
autobyteus/agent/agent.py CHANGED
@@ -1,231 +1,106 @@
1
+ # file: autobyteus/autobyteus/agent/agent.py
1
2
  import asyncio
2
3
  import logging
3
- from typing import List, Optional
4
- from autobyteus.agent.response_parser.tool_usage_command_parser import ToolUsageCommandParser
5
- from autobyteus.events.event_emitter import EventEmitter
6
- from autobyteus.llm.base_llm import BaseLLM
7
- from autobyteus.tools.base_tool import BaseTool
8
- from autobyteus.prompt.prompt_builder import PromptBuilder
9
- from autobyteus.events.event_types import EventType
10
- from autobyteus.agent.status import AgentStatus
11
- from autobyteus.conversation.user_message import UserMessage
12
- from autobyteus.conversation.conversation import Conversation
4
+ from typing import AsyncIterator, Optional, List, Any, Dict, TYPE_CHECKING
5
+
6
+ from autobyteus.agent.runtime.agent_runtime import AgentRuntime
7
+ from autobyteus.agent.context.phases import AgentOperationalPhase
8
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
+ from autobyteus.agent.message.inter_agent_message import InterAgentMessage
10
+ from autobyteus.agent.events import UserMessageReceivedEvent, InterAgentMessageReceivedEvent, ToolExecutionApprovalEvent, BaseEvent
11
+
12
+ if TYPE_CHECKING:
13
+ from autobyteus.agent.context import AgentContext
13
14
 
14
15
  logger = logging.getLogger(__name__)
15
16
 
16
- class Agent(EventEmitter):
17
- def __init__(self, role: str, llm: BaseLLM, tools: Optional[List[BaseTool]] = None,
18
- agent_id=None,
19
- prompt_builder: Optional[PromptBuilder] = None,
20
- initial_user_message: Optional[UserMessage] = None):
21
- super().__init__()
22
- self.role = role
23
- self.llm = llm
24
- self.tools = tools or []
25
- self.tool_usage_response_parser = ToolUsageCommandParser() if self.tools else None
26
- self.conversation = None
27
- self.agent_id = agent_id or f"{self.role}-001"
28
- self.status = AgentStatus.NOT_STARTED
29
- self._run_task = None
30
- self._queues_initialized = False
31
- self.task_completed = None
32
- self.prompt_builder = prompt_builder
33
- self.initial_user_message = initial_user_message
34
-
35
- if not self.prompt_builder and not self.initial_user_message:
36
- raise ValueError("Either prompt_builder or initial_user_message must be provided")
37
-
38
- if self.tools:
39
- self.set_agent_id_on_tools()
40
-
41
- logger.info(f"StandaloneAgent initialized with role: {self.role}, agent_id: {self.agent_id}")
42
-
43
- def _initialize_queues(self):
44
- if not self._queues_initialized:
45
- self.tool_result_messages = asyncio.Queue()
46
- self.user_messages = asyncio.Queue()
47
- self._queues_initialized = True
48
- logger.info(f"Queues initialized for agent {self.role}")
49
-
50
- def _initialize_task_completed(self):
51
- if self.task_completed is None:
52
- self.task_completed = asyncio.Event()
53
- logger.info(f"task_completed Event initialized for agent {self.role}")
54
-
55
- def get_task_completed(self):
56
- if self.task_completed is None:
57
- raise RuntimeError("task_completed Event accessed before initialization")
58
- return self.task_completed
59
-
60
- async def run(self):
61
- try:
62
- logger.info(f"Starting execution for agent: {self.role}")
63
- self._initialize_queues()
64
- self._initialize_task_completed()
65
- await self.initialize_conversation()
66
-
67
- user_message_handler = asyncio.create_task(self.handle_user_messages())
68
- tool_result_handler = asyncio.create_task(self.handle_tool_result_messages())
69
-
70
- # Once everything is ready, set the status to RUNNING
71
- self.status = AgentStatus.RUNNING
72
-
73
- await asyncio.gather(user_message_handler, tool_result_handler)
74
-
75
- except Exception as e:
76
- logger.error(f"Error in agent {self.role} execution: {str(e)}")
77
- self.status = AgentStatus.ERROR
78
- finally:
79
- self.status = AgentStatus.ENDED
80
- await self.cleanup()
81
-
82
- async def handle_user_messages(self):
83
- logger.info(f"Agent {self.role} started handling user messages")
84
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
85
- try:
86
- user_message: UserMessage = await asyncio.wait_for(self.user_messages.get(), timeout=1.0)
87
- logger.info(f"Agent {self.role} handling user message")
88
- response = await self.conversation.send_user_message(user_message.content, user_message.file_paths)
89
- await self.process_llm_response(response)
90
- except asyncio.TimeoutError:
91
- continue
92
- except asyncio.CancelledError:
93
- logger.info(f"User message handler for agent {self.role} cancelled")
94
- break
95
- except Exception as e:
96
- logger.error(f"Error handling user message for agent {self.role}: {str(e)}")
97
-
98
- async def receive_user_message(self, message: UserMessage):
99
- """
100
- This method gracefully waits for the agent to become RUNNING
101
- if it's in the process of starting up, ensuring the queues are
102
- initialized before we put a message into them.
103
- """
104
- logger.info(f"Agent {self.agent_id} received user message")
105
-
106
- # If the agent is not started (or ended), begin the start process
107
- if self.status in [AgentStatus.NOT_STARTED, AgentStatus.ENDED]:
108
- self.start()
109
-
110
- # If the agent is still starting, wait until it transitions to RUNNING
111
- while self.status == AgentStatus.STARTING:
112
- await asyncio.sleep(0.1)
113
-
114
- if self.status != AgentStatus.RUNNING:
115
- logger.error(f"Agent is not in a running state: {self.status}")
116
- return
17
+ class Agent:
18
+ """
19
+ User-facing API for interacting with an agent's runtime.
20
+ It manages an underlying AgentRuntime instance and translates user actions
21
+ into events for the agent's event processing loop by submitting them
22
+ to AgentRuntime. Output is consumed via AgentEventStream which listens
23
+ to AgentExternalEventNotifier.
24
+ """
25
+
26
+ def __init__(self, runtime: AgentRuntime):
27
+ if not isinstance(runtime, AgentRuntime): # pragma: no cover
28
+ raise TypeError(f"Agent requires an AgentRuntime instance, got {type(runtime).__name__}")
29
+
30
+ self._runtime: AgentRuntime = runtime
31
+ self.agent_id: str = self._runtime.context.agent_id
32
+
33
+ logger.info(f"Agent facade initialized for agent_id '{self.agent_id}'.")
34
+
35
+ @property
36
+ def context(self) -> 'AgentContext':
37
+ return self._runtime.context
38
+
39
+ async def _submit_event_to_runtime(self, event: BaseEvent) -> None:
40
+ """Internal helper to submit an event to the runtime and handle startup."""
41
+ if not self._runtime.is_running: # pragma: no cover
42
+ logger.info(f"Agent '{self.agent_id}' runtime is not running. Calling start() before submitting event.")
43
+ self.start()
44
+ await asyncio.sleep(0.05)
45
+
46
+ logger.debug(f"Agent '{self.agent_id}': Submitting {type(event).__name__} to runtime.")
47
+ await self._runtime.submit_event(event)
48
+
49
+ async def post_user_message(self, agent_input_user_message: AgentInputUserMessage) -> None:
50
+ if not isinstance(agent_input_user_message, AgentInputUserMessage): # pragma: no cover
51
+ raise TypeError(f"Agent for '{self.agent_id}' received invalid type for user_message. Expected AgentInputUserMessage, got {type(agent_input_user_message)}.")
52
+
53
+ event = UserMessageReceivedEvent(agent_input_user_message=agent_input_user_message)
54
+ await self._submit_event_to_runtime(event)
117
55
 
118
- # Now that we are running, safely place the message in the queue
119
- await self.user_messages.put(message)
120
-
121
- async def handle_tool_result_messages(self):
122
- logger.info(f"Agent {self.role} started handling tool result messages")
123
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
124
- try:
125
- message = await asyncio.wait_for(self.tool_result_messages.get(), timeout=1.0)
126
- logger.info(f"Agent {self.role} handling tool result message: {message}")
127
- response = await self.conversation.send_user_message(f"Tool execution result: {message}")
128
- await self.process_llm_response(response)
129
- except asyncio.TimeoutError:
130
- continue
131
- except asyncio.CancelledError:
132
- logger.info(f"Tool result handler for agent {self.role} cancelled")
133
- break
134
- except Exception as e:
135
- logger.error(f"Error handling tool result for agent {self.role}: {str(e)}")
136
-
137
- async def initialize_conversation(self):
138
- logger.info(f"Initializing conversation for agent: {self.role}")
139
- self.conversation = Conversation(self.llm)
140
-
141
- if self.initial_user_message:
142
- initial_message = self.initial_user_message
143
- else:
144
- prompt_content = self.prompt_builder.set_variable_value(
145
- "external_tools",
146
- self._get_external_tools_section()
147
- ).build()
148
- initial_message = UserMessage(content=prompt_content)
149
-
150
- logger.debug(f"Initial user message for agent {self.role}: {initial_message}")
151
- initial_llm_response = await self.conversation.send_user_message(
152
- initial_message.content,
153
- initial_message.file_paths
154
- )
155
- await self.process_llm_response(initial_llm_response)
156
56
 
157
- async def process_llm_response(self, response: str) -> None:
158
- self.emit(EventType.ASSISTANT_RESPONSE, response=response)
57
+ async def post_inter_agent_message(self, inter_agent_message: InterAgentMessage) -> None:
58
+ if not isinstance(inter_agent_message, InterAgentMessage): # pragma: no cover
59
+ raise TypeError(
60
+ f"Agent for '{self.agent_id}' received invalid type for inter_agent_message. "
61
+ f"Expected InterAgentMessage, got {type(inter_agent_message).__name__}."
62
+ )
159
63
 
160
- if self.tools and self.tool_usage_response_parser:
161
- tool_invocation = self.tool_usage_response_parser.parse_response(response)
162
- if tool_invocation.is_valid():
163
- await self.execute_tool(tool_invocation)
164
- return
165
-
166
- logger.info(f"Assistant response for agent {self.role}: {response}")
167
-
168
- async def execute_tool(self, tool_invocation):
169
- name = tool_invocation.name
170
- arguments = tool_invocation.arguments
171
- logger.info(f"Agent {self.role} attempting to execute tool: {name}")
172
-
173
- tool = next((t for t in self.tools if t.get_name() == name), None)
174
- if tool:
175
- try:
176
- result = await tool.execute(**arguments)
177
- logger.info(f"Tool '{name}' executed successfully by agent {self.role}. Result: {result}")
178
- await self.tool_result_messages.put(result)
179
- except Exception as e:
180
- error_message = str(e)
181
- logger.error(f"Error executing tool '{name}' by agent {self.role}: {error_message}")
182
- await self.tool_result_messages.put(f"Error: {error_message}")
183
- else:
184
- logger.warning(f"Tool '{name}' not found for agent {self.role}.")
185
-
186
- def start(self):
187
- """
188
- Starts the agent by creating a task that runs the main loop (run).
189
- Sets the AgentStatus to STARTING to prevent message enqueuing before
190
- the system is fully initialized.
191
- """
192
- if self.status in [AgentStatus.NOT_STARTED, AgentStatus.ENDED]:
193
- logger.info(f"Starting agent {self.role}")
194
- self.status = AgentStatus.STARTING
195
- self._run_task = asyncio.create_task(self.run())
196
- elif self.status == AgentStatus.STARTING:
197
- logger.info(f"Agent {self.role} is already in STARTING state.")
198
- elif self.status == AgentStatus.RUNNING:
199
- logger.info(f"Agent {self.role} is already running.")
200
- else:
201
- logger.warning(f"Agent {self.role} is in an unexpected state: {self.status}")
202
-
203
- def stop(self):
204
- if self._run_task and not self._run_task.done():
205
- self._run_task.cancel()
206
-
207
- async def cleanup(self):
208
- while not self.tool_result_messages.empty():
209
- self.tool_result_messages.get_nowait()
210
- while not self.user_messages.empty():
211
- self.user_messages.get_nowait()
212
- await self.llm.cleanup()
213
- logger.info(f"Cleanup completed for agent: {self.role}")
214
-
215
- def set_agent_id_on_tools(self):
216
- if self.tools:
217
- for tool in self.tools:
218
- tool.set_agent_id(self.agent_id)
219
-
220
- def _get_external_tools_section(self) -> str:
221
- if not self.tools:
222
- return ""
64
+ event = InterAgentMessageReceivedEvent(inter_agent_message=inter_agent_message)
65
+ await self._submit_event_to_runtime(event)
66
+
67
+
68
+ async def post_tool_execution_approval(self,
69
+ tool_invocation_id: str,
70
+ is_approved: bool,
71
+ reason: Optional[str] = None) -> None:
72
+ if not isinstance(tool_invocation_id, str) or not tool_invocation_id: # pragma: no cover
73
+ raise ValueError("tool_invocation_id must be a non-empty string.")
74
+ if not isinstance(is_approved, bool): # pragma: no cover
75
+ raise TypeError("is_approved must be a boolean.")
76
+
77
+ approval_event = ToolExecutionApprovalEvent(
78
+ tool_invocation_id=tool_invocation_id,
79
+ is_approved=is_approved,
80
+ reason=reason
81
+ )
82
+ await self._submit_event_to_runtime(approval_event)
83
+
84
+ def get_current_phase(self) -> AgentOperationalPhase:
85
+ return self._runtime.current_phase_property
86
+
87
+ @property
88
+ def is_running(self) -> bool:
89
+ return self._runtime.is_running
90
+
91
+ def start(self) -> None:
92
+ if self._runtime.is_running: # pragma: no cover
93
+ logger.info(f"Agent '{self.agent_id}' runtime is already running. Ignoring start command.")
94
+ return
223
95
 
224
- external_tools_section = ""
225
- for i, tool in enumerate(self.tools):
226
- external_tools_section += f" {i + 1} {tool.tool_usage()}\n\n"
227
- return external_tools_section.strip()
228
-
229
- def on_task_completed(self, *args, **kwargs):
230
- logger.info(f"Task completed event received for agent: {self.role}")
231
- self.task_completed.set()
96
+ logger.info(f"Agent '{self.agent_id}' requesting runtime to start.")
97
+ self._runtime.start()
98
+
99
+ async def stop(self, timeout: float = 10.0) -> None: # pragma: no cover
100
+ logger.info(f"Agent '{self.agent_id}' requesting runtime to stop (timeout: {timeout}s).")
101
+ await self._runtime.stop(timeout=timeout)
102
+
103
+
104
+ def __repr__(self) -> str:
105
+ phase_val = self._runtime.current_phase_property.value
106
+ return f"<Agent agent_id='{self.agent_id}', current_phase='{phase_val}'>"
@@ -0,0 +1,19 @@
1
+ # file: autobyteus/autobyteus/agent/bootstrap_steps/__init__.py
2
+ """
3
+ Defines individual, self-contained steps for the agent bootstrapping process.
4
+ These steps are orchestrated by the BootstrapAgentEventHandler.
5
+ """
6
+
7
+ from .base_bootstrap_step import BaseBootstrapStep
8
+ from .agent_runtime_queue_initialization_step import AgentRuntimeQueueInitializationStep # UPDATED
9
+ from .workspace_context_initialization_step import WorkspaceContextInitializationStep
10
+ # ToolInitializationStep is no longer a bootstrap step.
11
+ from .system_prompt_processing_step import SystemPromptProcessingStep
12
+ # LLMConfigFinalizationStep and LLMInstanceCreationStep removed.
13
+
14
+ __all__ = [
15
+ "BaseBootstrapStep",
16
+ "AgentRuntimeQueueInitializationStep", # UPDATED
17
+ "WorkspaceContextInitializationStep",
18
+ "SystemPromptProcessingStep",
19
+ ]
@@ -0,0 +1,88 @@
1
+ # file: autobyteus/autobyteus/agent/bootstrap_steps/agent_bootstrapper.py
2
+ import logging
3
+ from typing import TYPE_CHECKING, List, Optional
4
+
5
+ from .base_bootstrap_step import BaseBootstrapStep
6
+ from .agent_runtime_queue_initialization_step import AgentRuntimeQueueInitializationStep
7
+ from .workspace_context_initialization_step import WorkspaceContextInitializationStep
8
+ from .system_prompt_processing_step import SystemPromptProcessingStep
9
+ from autobyteus.agent.events import AgentReadyEvent
10
+
11
+ if TYPE_CHECKING:
12
+ from autobyteus.agent.context import AgentContext
13
+ from autobyteus.agent.phases import AgentPhaseManager
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class AgentBootstrapper:
18
+ """
19
+ Orchestrates the agent's bootstrapping process by executing a sequence of
20
+ self-contained bootstrap steps.
21
+ """
22
+ def __init__(self, steps: Optional[List[BaseBootstrapStep]] = None):
23
+ """
24
+ Initializes the AgentBootstrapper.
25
+
26
+ Args:
27
+ steps: An optional list of bootstrap steps to execute. If not provided,
28
+ a default sequence will be used.
29
+ """
30
+ if steps is None:
31
+ self.bootstrap_steps: List[BaseBootstrapStep] = [
32
+ AgentRuntimeQueueInitializationStep(),
33
+ WorkspaceContextInitializationStep(),
34
+ SystemPromptProcessingStep(),
35
+ ]
36
+ logger.debug("AgentBootstrapper initialized with default steps.")
37
+ else:
38
+ self.bootstrap_steps = steps
39
+ logger.debug(f"AgentBootstrapper initialized with {len(steps)} custom steps.")
40
+
41
+ async def run(self, context: 'AgentContext', phase_manager: 'AgentPhaseManager') -> bool:
42
+ """
43
+ Executes the configured sequence of bootstrap steps.
44
+
45
+ Args:
46
+ context: The agent's context.
47
+ phase_manager: The agent's phase manager.
48
+
49
+ Returns:
50
+ True if all steps completed successfully, False otherwise.
51
+ """
52
+ agent_id = context.agent_id
53
+
54
+ # Set the agent phase to BOOTSTRAPPING and wait for any associated hooks.
55
+ await phase_manager.notify_bootstrapping_started()
56
+ logger.info(f"Agent '{agent_id}': AgentBootstrapper starting execution. Phase set to BOOTSTRAPPING.")
57
+
58
+ for step_index, step_instance in enumerate(self.bootstrap_steps):
59
+ step_name = step_instance.__class__.__name__
60
+ logger.debug(f"Agent '{agent_id}': Executing bootstrap step {step_index + 1}/{len(self.bootstrap_steps)}: {step_name}")
61
+
62
+ success = await step_instance.execute(context, phase_manager)
63
+
64
+ if not success:
65
+ error_message = f"Bootstrap step {step_name} failed."
66
+ logger.error(f"Agent '{agent_id}': {error_message} Halting bootstrap process.")
67
+ # The step itself is responsible for detailed error logging.
68
+ # We are responsible for notifying the phase manager to set the agent to an error state.
69
+ await phase_manager.notify_error_occurred(
70
+ error_message=f"Critical bootstrap failure at {step_name}",
71
+ error_details=f"Agent '{agent_id}' failed during bootstrap step '{step_name}'. Check logs for details."
72
+ )
73
+ return False
74
+
75
+ logger.info(f"Agent '{agent_id}': All bootstrap steps completed successfully. Enqueuing AgentReadyEvent.")
76
+ # After successful bootstrapping, enqueue the ready event.
77
+ if context.state.input_event_queues:
78
+ await context.state.input_event_queues.enqueue_internal_system_event(AgentReadyEvent())
79
+ else: # pragma: no cover
80
+ # Should not happen if AgentRuntimeQueueInitializationStep is present and successful
81
+ logger.critical(f"Agent '{agent_id}': Bootstrap succeeded but input queues are not available to enqueue AgentReadyEvent.")
82
+ await phase_manager.notify_error_occurred(
83
+ error_message="Input queues unavailable after bootstrap",
84
+ error_details=f"Agent '{agent_id}' bootstrap process seemed to succeed, but input event queues are missing."
85
+ )
86
+ return False
87
+
88
+ return True
@@ -0,0 +1,57 @@
1
+ # file: autobyteus/autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .base_bootstrap_step import BaseBootstrapStep
6
+ from autobyteus.agent.events import AgentErrorEvent, AgentInputEventQueueManager
7
+ # AgentOutputDataManager is no longer initialized here.
8
+
9
+ if TYPE_CHECKING:
10
+ from autobyteus.agent.context import AgentContext
11
+ from autobyteus.agent.phases import AgentPhaseManager
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class AgentRuntimeQueueInitializationStep(BaseBootstrapStep):
16
+ """
17
+ Bootstrap step for initializing the agent's runtime INPUT event queues.
18
+ These queues are created within the AgentWorker's event loop.
19
+ Output data is now handled by emitting events via AgentExternalEventNotifier.
20
+ """
21
+ def __init__(self, input_queue_size: int = 0): # Removed output_queue_size
22
+ self.input_queue_size = input_queue_size
23
+ logger.debug(f"AgentRuntimeQueueInitializationStep initialized with input_q_size={input_queue_size}.")
24
+
25
+ async def execute(self,
26
+ context: 'AgentContext',
27
+ phase_manager: 'AgentPhaseManager') -> bool:
28
+ agent_id = context.agent_id
29
+ logger.info(f"Agent '{agent_id}': Executing AgentRuntimeQueueInitializationStep (for input queues).")
30
+
31
+ try:
32
+ if context.state.input_event_queues is not None: # Check only input queues
33
+ logger.warning(f"Agent '{agent_id}': Input runtime queues seem to be already initialized. Overwriting. This might indicate a logic error.")
34
+
35
+ input_queues = AgentInputEventQueueManager(queue_size=self.input_queue_size)
36
+ context.state.input_event_queues = input_queues
37
+ # context.state.output_data_queues is no longer set here.
38
+
39
+ logger.info(f"Agent '{agent_id}': AgentInputEventQueueManager initialized and set in agent state.")
40
+ if context.state.input_event_queues is None: # pragma: no cover
41
+ raise RuntimeError("Input event queue manager was not successfully set in agent state during AgentRuntimeQueueInitializationStep.")
42
+
43
+ return True
44
+ except Exception as e:
45
+ error_message = f"Agent '{agent_id}': Critical failure during AgentRuntimeQueueInitializationStep (input queues): {e}"
46
+ logger.error(error_message, exc_info=True)
47
+
48
+ # Attempt to enqueue an error event if input_event_queues was partially created
49
+ # This check itself might be problematic if input_queues is the thing that failed.
50
+ # However, if it failed *after* assigning self.input_event_queues, this might work.
51
+ if context.state.input_event_queues and context.state.input_event_queues.internal_system_event_queue: # pragma: no cover
52
+ await context.state.input_event_queues.enqueue_internal_system_event(
53
+ AgentErrorEvent(error_message=error_message, exception_details=str(e))
54
+ )
55
+ else: # pragma: no cover
56
+ logger.error(f"Agent '{agent_id}': Cannot enqueue AgentErrorEvent as input_event_queues are not available after AgentRuntimeQueueInitializationStep failure.")
57
+ return False
@@ -0,0 +1,38 @@
1
+ # file: autobyteus/autobyteus/agent/bootstrap_steps/base_bootstrap_step.py
2
+ import logging
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from autobyteus.agent.context import AgentContext
8
+ from autobyteus.agent.phases import AgentPhaseManager
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ class BaseBootstrapStep(ABC):
13
+ """
14
+ Abstract base class for individual steps in the agent bootstrapping process.
15
+ Each step is responsible for a specific part of the initialization and
16
+ for reporting its success or failure.
17
+ """
18
+
19
+ @abstractmethod
20
+ async def execute(self,
21
+ context: 'AgentContext',
22
+ phase_manager: 'AgentPhaseManager') -> bool:
23
+ """
24
+ Executes the bootstrap step.
25
+
26
+ Args:
27
+ context: The agent's context, providing access to configuration and state.
28
+ phase_manager: The agent's phase manager for notifying phase transitions.
29
+
30
+ Returns:
31
+ True if the step completed successfully, False otherwise.
32
+ If False, the step is expected to have handled logging and enqueuing
33
+ an AgentErrorEvent.
34
+ """
35
+ raise NotImplementedError("Subclasses must implement the 'execute' method.")
36
+
37
+ def __repr__(self) -> str:
38
+ return f"<{self.__class__.__name__}>"
@@ -0,0 +1,93 @@
1
+ # file: autobyteus/autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .base_bootstrap_step import BaseBootstrapStep
6
+ from autobyteus.agent.events import AgentErrorEvent
7
+ from autobyteus.agent.system_prompt_processor.base_processor import BaseSystemPromptProcessor
8
+
9
+ if TYPE_CHECKING:
10
+ from autobyteus.agent.context import AgentContext
11
+ from autobyteus.agent.phases import AgentPhaseManager
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class SystemPromptProcessingStep(BaseBootstrapStep):
16
+ """
17
+ Bootstrap step for processing the agent's system prompt and setting it
18
+ on the pre-initialized LLM instance.
19
+ If any configured processor fails, this entire step is considered failed.
20
+ """
21
+ def __init__(self):
22
+ logger.debug("SystemPromptProcessingStep initialized.")
23
+
24
+ async def execute(self,
25
+ context: 'AgentContext',
26
+ phase_manager: 'AgentPhaseManager') -> bool:
27
+ agent_id = context.agent_id
28
+ # The phase is now managed by the AgentBootstrapper.
29
+ logger.info(f"Agent '{agent_id}': Executing SystemPromptProcessingStep.")
30
+
31
+ try:
32
+ # The LLM instance is now expected to be present from the start.
33
+ llm_instance = context.llm_instance
34
+ if not llm_instance:
35
+ raise ValueError("LLM instance not found in agent state. It must be provided in AgentConfig.")
36
+
37
+ current_system_prompt = context.config.system_prompt
38
+ logger.debug(f"Agent '{agent_id}': Retrieved base system prompt from agent config.")
39
+
40
+ processor_instances = context.config.system_prompt_processors
41
+ tool_instances_for_processor = context.tool_instances
42
+
43
+ if not processor_instances:
44
+ logger.debug(f"Agent '{agent_id}': No system prompt processors configured. Using system prompt as is.")
45
+ else:
46
+ logger.debug(f"Agent '{agent_id}': Found {len(processor_instances)} configured system prompt processors. Applying sequentially.")
47
+ for processor_instance in processor_instances:
48
+ if not isinstance(processor_instance, BaseSystemPromptProcessor):
49
+ error_message = f"Agent '{agent_id}': Invalid system prompt processor configuration type: {type(processor_instance)}. Expected BaseSystemPromptProcessor."
50
+ logger.error(error_message)
51
+ raise TypeError(error_message)
52
+
53
+ processor_name = processor_instance.get_name()
54
+ try:
55
+ logger.debug(f"Agent '{agent_id}': Applying system prompt processor '{processor_name}'.")
56
+ current_system_prompt = processor_instance.process(
57
+ system_prompt=current_system_prompt,
58
+ tool_instances=tool_instances_for_processor,
59
+ agent_id=agent_id,
60
+ context=context
61
+ )
62
+ logger.info(f"Agent '{agent_id}': System prompt processor '{processor_name}' applied successfully.")
63
+ except Exception as e_proc:
64
+ error_message = f"Agent '{agent_id}': Error applying system prompt processor '{processor_name}': {e_proc}"
65
+ logger.error(error_message, exc_info=True)
66
+ if context.state.input_event_queues:
67
+ await context.state.input_event_queues.enqueue_internal_system_event(
68
+ AgentErrorEvent(error_message=error_message, exception_details=str(e_proc))
69
+ )
70
+ return False # Signal failure of the entire step
71
+
72
+ context.state.processed_system_prompt = current_system_prompt
73
+
74
+ # --- New Logic: Set the prompt on the existing LLM instance ---
75
+ if hasattr(llm_instance, 'configure_system_prompt') and callable(getattr(llm_instance, 'configure_system_prompt')):
76
+ llm_instance.configure_system_prompt(current_system_prompt)
77
+ logger.info(f"Agent '{agent_id}': Final processed system prompt configured on LLM instance. Final length: {len(current_system_prompt)}.")
78
+ else:
79
+ # This path should ideally not be taken if all LLMs inherit from the updated BaseLLM.
80
+ # It's kept as a fallback with a strong warning.
81
+ logger.warning(f"Agent '{agent_id}': LLM instance ({llm_instance.__class__.__name__}) does not have a 'configure_system_prompt' method. "
82
+ f"The system prompt cannot be dynamically updated on the LLM instance after initialization. This may lead to incorrect agent behavior.")
83
+
84
+ logger.info(f"Agent '{agent_id}': Final processed system prompt:\n---\n{current_system_prompt}\n---")
85
+ return True
86
+ except Exception as e: # Catches other errors in the step setup itself
87
+ error_message = f"Agent '{agent_id}': Critical failure during system prompt processing step: {e}"
88
+ logger.error(error_message, exc_info=True)
89
+ if context.state.input_event_queues:
90
+ await context.input_event_queues.enqueue_internal_system_event(
91
+ AgentErrorEvent(error_message=error_message, exception_details=str(e))
92
+ )
93
+ return False