autobyteus 1.2.1__py3-none-any.whl → 1.2.3__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.
- autobyteus/agent/agent.py +15 -5
- autobyteus/agent/bootstrap_steps/__init__.py +1 -3
- autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +3 -59
- autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +1 -4
- autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +1 -3
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +16 -13
- autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
- autobyteus/agent/context/agent_config.py +43 -20
- autobyteus/agent/context/agent_context.py +23 -18
- autobyteus/agent/context/agent_runtime_state.py +19 -19
- autobyteus/agent/events/__init__.py +16 -1
- autobyteus/agent/events/agent_events.py +43 -3
- autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
- autobyteus/agent/events/event_store.py +57 -0
- autobyteus/agent/events/notifiers.py +69 -59
- autobyteus/agent/events/worker_event_dispatcher.py +21 -64
- autobyteus/agent/factory/agent_factory.py +52 -0
- autobyteus/agent/handlers/__init__.py +2 -0
- autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
- autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
- autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
- autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
- autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
- autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
- autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
- autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
- autobyteus/agent/input_processor/memory_ingest_input_processor.py +40 -0
- autobyteus/agent/lifecycle/__init__.py +12 -0
- autobyteus/agent/lifecycle/base_processor.py +109 -0
- autobyteus/agent/lifecycle/events.py +35 -0
- autobyteus/agent/lifecycle/processor_definition.py +36 -0
- autobyteus/agent/lifecycle/processor_registry.py +106 -0
- autobyteus/agent/llm_request_assembler.py +98 -0
- autobyteus/agent/llm_response_processor/__init__.py +1 -8
- autobyteus/agent/message/context_file_type.py +1 -1
- autobyteus/agent/runtime/agent_runtime.py +29 -21
- autobyteus/agent/runtime/agent_worker.py +98 -19
- autobyteus/agent/shutdown_steps/__init__.py +2 -0
- autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +2 -0
- autobyteus/agent/shutdown_steps/tool_cleanup_step.py +58 -0
- autobyteus/agent/status/__init__.py +14 -0
- autobyteus/agent/status/manager.py +93 -0
- autobyteus/agent/status/status_deriver.py +96 -0
- autobyteus/agent/{phases/phase_enum.py → status/status_enum.py} +16 -16
- autobyteus/agent/status/status_update_utils.py +73 -0
- autobyteus/agent/streaming/__init__.py +52 -5
- autobyteus/agent/streaming/adapters/__init__.py +18 -0
- autobyteus/agent/streaming/adapters/invocation_adapter.py +184 -0
- autobyteus/agent/streaming/adapters/tool_call_parsing.py +163 -0
- autobyteus/agent/streaming/adapters/tool_syntax_registry.py +67 -0
- autobyteus/agent/streaming/agent_event_stream.py +3 -183
- autobyteus/agent/streaming/api_tool_call/__init__.py +16 -0
- autobyteus/agent/streaming/api_tool_call/file_content_streamer.py +56 -0
- autobyteus/agent/streaming/api_tool_call/json_string_field_extractor.py +175 -0
- autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/events/__init__.py +6 -0
- autobyteus/agent/streaming/events/stream_event_payloads.py +284 -0
- autobyteus/agent/streaming/events/stream_events.py +141 -0
- autobyteus/agent/streaming/handlers/__init__.py +15 -0
- autobyteus/agent/streaming/handlers/api_tool_call_streaming_response_handler.py +303 -0
- autobyteus/agent/streaming/handlers/parsing_streaming_response_handler.py +107 -0
- autobyteus/agent/streaming/handlers/pass_through_streaming_response_handler.py +107 -0
- autobyteus/agent/streaming/handlers/streaming_handler_factory.py +177 -0
- autobyteus/agent/streaming/handlers/streaming_response_handler.py +58 -0
- autobyteus/agent/streaming/parser/__init__.py +61 -0
- autobyteus/agent/streaming/parser/event_emitter.py +181 -0
- autobyteus/agent/streaming/parser/events.py +4 -0
- autobyteus/agent/streaming/parser/invocation_adapter.py +4 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/__init__.py +19 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/base.py +32 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/default.py +34 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/gemini.py +31 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/openai.py +64 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/registry.py +75 -0
- autobyteus/agent/streaming/parser/parser_context.py +227 -0
- autobyteus/agent/streaming/parser/parser_factory.py +132 -0
- autobyteus/agent/streaming/parser/sentinel_format.py +7 -0
- autobyteus/agent/streaming/parser/state_factory.py +62 -0
- autobyteus/agent/streaming/parser/states/__init__.py +1 -0
- autobyteus/agent/streaming/parser/states/base_state.py +60 -0
- autobyteus/agent/streaming/parser/states/custom_xml_tag_run_bash_parsing_state.py +38 -0
- autobyteus/agent/streaming/parser/states/custom_xml_tag_write_file_parsing_state.py +55 -0
- autobyteus/agent/streaming/parser/states/delimited_content_state.py +146 -0
- autobyteus/agent/streaming/parser/states/json_initialization_state.py +144 -0
- autobyteus/agent/streaming/parser/states/json_tool_parsing_state.py +137 -0
- autobyteus/agent/streaming/parser/states/sentinel_content_state.py +30 -0
- autobyteus/agent/streaming/parser/states/sentinel_initialization_state.py +117 -0
- autobyteus/agent/streaming/parser/states/text_state.py +78 -0
- autobyteus/agent/streaming/parser/states/xml_patch_file_tool_parsing_state.py +328 -0
- autobyteus/agent/streaming/parser/states/xml_run_bash_tool_parsing_state.py +129 -0
- autobyteus/agent/streaming/parser/states/xml_tag_initialization_state.py +151 -0
- autobyteus/agent/streaming/parser/states/xml_tool_parsing_state.py +63 -0
- autobyteus/agent/streaming/parser/states/xml_write_file_tool_parsing_state.py +343 -0
- autobyteus/agent/streaming/parser/strategies/__init__.py +17 -0
- autobyteus/agent/streaming/parser/strategies/base.py +24 -0
- autobyteus/agent/streaming/parser/strategies/json_tool_strategy.py +26 -0
- autobyteus/agent/streaming/parser/strategies/registry.py +28 -0
- autobyteus/agent/streaming/parser/strategies/sentinel_strategy.py +23 -0
- autobyteus/agent/streaming/parser/strategies/xml_tag_strategy.py +21 -0
- autobyteus/agent/streaming/parser/stream_scanner.py +167 -0
- autobyteus/agent/streaming/parser/streaming_parser.py +212 -0
- autobyteus/agent/streaming/parser/tool_call_parsing.py +4 -0
- autobyteus/agent/streaming/parser/tool_constants.py +7 -0
- autobyteus/agent/streaming/parser/tool_syntax_registry.py +4 -0
- autobyteus/agent/streaming/parser/xml_tool_parsing_state_registry.py +55 -0
- autobyteus/agent/streaming/parsing_streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/pass_through_streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/queue_streamer.py +3 -57
- autobyteus/agent/streaming/segments/__init__.py +5 -0
- autobyteus/agent/streaming/segments/segment_events.py +81 -0
- autobyteus/agent/streaming/stream_event_payloads.py +2 -223
- autobyteus/agent/streaming/stream_events.py +3 -140
- autobyteus/agent/streaming/streaming_handler_factory.py +4 -0
- autobyteus/agent/streaming/streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/streams/__init__.py +5 -0
- autobyteus/agent/streaming/streams/agent_event_stream.py +197 -0
- autobyteus/agent/streaming/utils/__init__.py +5 -0
- autobyteus/agent/streaming/utils/queue_streamer.py +59 -0
- autobyteus/agent/system_prompt_processor/__init__.py +2 -0
- autobyteus/agent/system_prompt_processor/available_skills_processor.py +96 -0
- autobyteus/agent/system_prompt_processor/base_processor.py +1 -1
- autobyteus/agent/system_prompt_processor/processor_meta.py +15 -2
- autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +39 -58
- autobyteus/agent/token_budget.py +56 -0
- autobyteus/agent/tool_execution_result_processor/memory_ingest_tool_result_processor.py +29 -0
- autobyteus/agent/tool_invocation.py +16 -40
- autobyteus/agent/tool_invocation_preprocessor/__init__.py +9 -0
- autobyteus/agent/tool_invocation_preprocessor/base_preprocessor.py +45 -0
- autobyteus/agent/tool_invocation_preprocessor/processor_definition.py +15 -0
- autobyteus/agent/tool_invocation_preprocessor/processor_meta.py +33 -0
- autobyteus/agent/tool_invocation_preprocessor/processor_registry.py +60 -0
- autobyteus/agent/utils/wait_for_idle.py +12 -14
- autobyteus/agent/workspace/base_workspace.py +6 -27
- autobyteus/agent_team/agent_team.py +3 -3
- autobyteus/agent_team/agent_team_builder.py +1 -41
- autobyteus/agent_team/bootstrap_steps/__init__.py +0 -4
- autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +8 -18
- autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +4 -16
- autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +1 -2
- autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +1 -2
- autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +1 -2
- autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +4 -4
- autobyteus/agent_team/context/agent_team_config.py +6 -3
- autobyteus/agent_team/context/agent_team_context.py +25 -3
- autobyteus/agent_team/context/agent_team_runtime_state.py +9 -6
- autobyteus/agent_team/events/__init__.py +11 -0
- autobyteus/agent_team/events/agent_team_event_dispatcher.py +22 -9
- autobyteus/agent_team/events/agent_team_events.py +16 -0
- autobyteus/agent_team/events/event_store.py +57 -0
- autobyteus/agent_team/factory/agent_team_factory.py +8 -0
- autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +18 -2
- autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +21 -5
- autobyteus/agent_team/handlers/process_user_message_event_handler.py +17 -8
- autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +19 -4
- autobyteus/agent_team/runtime/agent_team_runtime.py +41 -10
- autobyteus/agent_team/runtime/agent_team_worker.py +69 -5
- autobyteus/agent_team/status/__init__.py +14 -0
- autobyteus/agent_team/status/agent_team_status.py +18 -0
- autobyteus/agent_team/status/agent_team_status_manager.py +33 -0
- autobyteus/agent_team/status/status_deriver.py +62 -0
- autobyteus/agent_team/status/status_update_utils.py +42 -0
- autobyteus/agent_team/streaming/__init__.py +2 -2
- autobyteus/agent_team/streaming/agent_team_event_notifier.py +6 -6
- autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +4 -4
- autobyteus/agent_team/streaming/agent_team_stream_events.py +3 -3
- autobyteus/agent_team/system_prompt_processor/__init__.py +6 -0
- autobyteus/agent_team/system_prompt_processor/team_manifest_injector_processor.py +76 -0
- autobyteus/agent_team/task_notification/task_notification_mode.py +19 -0
- autobyteus/agent_team/utils/wait_for_idle.py +4 -4
- autobyteus/cli/agent_cli.py +18 -10
- autobyteus/cli/agent_team_tui/app.py +14 -11
- autobyteus/cli/agent_team_tui/state.py +13 -15
- autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
- autobyteus/cli/agent_team_tui/widgets/focus_pane.py +143 -36
- autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
- autobyteus/cli/agent_team_tui/widgets/shared.py +25 -25
- autobyteus/cli/cli_display.py +193 -44
- autobyteus/cli/workflow_tui/app.py +9 -10
- autobyteus/cli/workflow_tui/state.py +14 -16
- autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
- autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
- autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
- autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
- autobyteus/clients/autobyteus_client.py +94 -1
- autobyteus/events/event_types.py +11 -18
- autobyteus/llm/api/autobyteus_llm.py +33 -29
- autobyteus/llm/api/claude_llm.py +142 -36
- autobyteus/llm/api/gemini_llm.py +163 -59
- autobyteus/llm/api/grok_llm.py +1 -1
- autobyteus/llm/api/minimax_llm.py +26 -0
- autobyteus/llm/api/mistral_llm.py +113 -87
- autobyteus/llm/api/ollama_llm.py +9 -42
- autobyteus/llm/api/openai_compatible_llm.py +127 -91
- autobyteus/llm/api/openai_llm.py +3 -3
- autobyteus/llm/api/openai_responses_llm.py +324 -0
- autobyteus/llm/api/zhipu_llm.py +21 -2
- autobyteus/llm/autobyteus_provider.py +70 -60
- autobyteus/llm/base_llm.py +85 -81
- autobyteus/llm/converters/__init__.py +14 -0
- autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
- autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
- autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
- autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
- autobyteus/llm/extensions/base_extension.py +6 -12
- autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
- autobyteus/llm/llm_factory.py +282 -204
- autobyteus/llm/lmstudio_provider.py +60 -49
- autobyteus/llm/models.py +35 -2
- autobyteus/llm/ollama_provider.py +60 -49
- autobyteus/llm/ollama_provider_resolver.py +0 -1
- autobyteus/llm/prompt_renderers/__init__.py +19 -0
- autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
- autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
- autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
- autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
- autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
- autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
- autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
- autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
- autobyteus/llm/providers.py +1 -3
- autobyteus/llm/token_counter/claude_token_counter.py +56 -25
- autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
- autobyteus/llm/token_counter/openai_token_counter.py +24 -5
- autobyteus/llm/token_counter/token_counter_factory.py +12 -5
- autobyteus/llm/utils/llm_config.py +6 -12
- autobyteus/llm/utils/media_payload_formatter.py +27 -20
- autobyteus/llm/utils/messages.py +55 -3
- autobyteus/llm/utils/response_types.py +3 -0
- autobyteus/llm/utils/tool_call_delta.py +31 -0
- autobyteus/memory/__init__.py +32 -0
- autobyteus/memory/active_transcript.py +69 -0
- autobyteus/memory/compaction/__init__.py +9 -0
- autobyteus/memory/compaction/compaction_result.py +8 -0
- autobyteus/memory/compaction/compactor.py +89 -0
- autobyteus/memory/compaction/summarizer.py +11 -0
- autobyteus/memory/compaction_snapshot_builder.py +84 -0
- autobyteus/memory/memory_manager.py +183 -0
- autobyteus/memory/models/__init__.py +14 -0
- autobyteus/memory/models/episodic_item.py +41 -0
- autobyteus/memory/models/memory_types.py +7 -0
- autobyteus/memory/models/raw_trace_item.py +79 -0
- autobyteus/memory/models/semantic_item.py +41 -0
- autobyteus/memory/models/tool_interaction.py +20 -0
- autobyteus/memory/policies/__init__.py +5 -0
- autobyteus/memory/policies/compaction_policy.py +16 -0
- autobyteus/memory/retrieval/__init__.py +7 -0
- autobyteus/memory/retrieval/memory_bundle.py +11 -0
- autobyteus/memory/retrieval/retriever.py +13 -0
- autobyteus/memory/store/__init__.py +7 -0
- autobyteus/memory/store/base_store.py +14 -0
- autobyteus/memory/store/file_store.py +98 -0
- autobyteus/memory/tool_interaction_builder.py +46 -0
- autobyteus/memory/turn_tracker.py +9 -0
- autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
- autobyteus/multimedia/audio/api/gemini_audio_client.py +108 -16
- autobyteus/multimedia/audio/audio_client_factory.py +47 -9
- autobyteus/multimedia/audio/audio_model.py +2 -1
- autobyteus/multimedia/image/api/autobyteus_image_client.py +19 -5
- autobyteus/multimedia/image/api/gemini_image_client.py +38 -17
- autobyteus/multimedia/image/api/openai_image_client.py +125 -43
- autobyteus/multimedia/image/autobyteus_image_provider.py +2 -1
- autobyteus/multimedia/image/image_client_factory.py +47 -15
- autobyteus/multimedia/image/image_model.py +5 -2
- autobyteus/multimedia/providers.py +3 -2
- autobyteus/skills/loader.py +71 -0
- autobyteus/skills/model.py +11 -0
- autobyteus/skills/registry.py +70 -0
- autobyteus/task_management/tools/todo_tools/add_todo.py +2 -2
- autobyteus/task_management/tools/todo_tools/create_todo_list.py +2 -2
- autobyteus/task_management/tools/todo_tools/update_todo_status.py +2 -2
- autobyteus/tools/__init__.py +34 -47
- autobyteus/tools/base_tool.py +7 -0
- autobyteus/tools/file/__init__.py +2 -6
- autobyteus/tools/file/patch_file.py +149 -0
- autobyteus/tools/file/read_file.py +36 -5
- autobyteus/tools/file/write_file.py +4 -1
- autobyteus/tools/functional_tool.py +43 -6
- autobyteus/tools/mcp/__init__.py +2 -0
- autobyteus/tools/mcp/config_service.py +5 -1
- autobyteus/tools/mcp/server/__init__.py +2 -0
- autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
- autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
- autobyteus/tools/mcp/server_instance_manager.py +8 -1
- autobyteus/tools/mcp/types.py +61 -0
- autobyteus/tools/multimedia/audio_tools.py +70 -17
- autobyteus/tools/multimedia/download_media_tool.py +18 -4
- autobyteus/tools/multimedia/image_tools.py +246 -62
- autobyteus/tools/operation_executor/journal_manager.py +107 -0
- autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
- autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
- autobyteus/tools/operation_executor/operation_executor.py +58 -0
- autobyteus/tools/registry/tool_definition.py +43 -2
- autobyteus/tools/skill/load_skill.py +50 -0
- autobyteus/tools/terminal/__init__.py +45 -0
- autobyteus/tools/terminal/ansi_utils.py +32 -0
- autobyteus/tools/terminal/background_process_manager.py +233 -0
- autobyteus/tools/terminal/output_buffer.py +105 -0
- autobyteus/tools/terminal/prompt_detector.py +63 -0
- autobyteus/tools/terminal/pty_session.py +241 -0
- autobyteus/tools/terminal/session_factory.py +20 -0
- autobyteus/tools/terminal/terminal_session_manager.py +226 -0
- autobyteus/tools/terminal/tools/__init__.py +13 -0
- autobyteus/tools/terminal/tools/get_process_output.py +81 -0
- autobyteus/tools/terminal/tools/run_bash.py +109 -0
- autobyteus/tools/terminal/tools/start_background_process.py +104 -0
- autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
- autobyteus/tools/terminal/types.py +54 -0
- autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
- autobyteus/tools/terminal/wsl_utils.py +156 -0
- autobyteus/tools/transaction_management/backup_handler.py +48 -0
- autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
- autobyteus/tools/usage/__init__.py +1 -2
- autobyteus/tools/usage/formatters/__init__.py +17 -1
- autobyteus/tools/usage/formatters/base_formatter.py +8 -0
- autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
- autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
- autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
- autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
- autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
- autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
- autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
- autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
- autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
- autobyteus/tools/usage/registries/__init__.py +1 -3
- autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
- autobyteus/tools/usage/tool_schema_provider.py +51 -0
- autobyteus/tools/web/__init__.py +4 -0
- autobyteus/tools/web/read_url_tool.py +80 -0
- autobyteus/utils/diff_utils.py +271 -0
- autobyteus/utils/download_utils.py +109 -0
- autobyteus/utils/file_utils.py +57 -2
- autobyteus/utils/gemini_helper.py +56 -0
- autobyteus/utils/gemini_model_mapping.py +71 -0
- autobyteus/utils/llm_output_formatter.py +75 -0
- autobyteus/utils/tool_call_format.py +36 -0
- autobyteus/workflow/agentic_workflow.py +3 -3
- autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
- autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
- autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
- autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +3 -9
- autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
- autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
- autobyteus/workflow/context/workflow_context.py +3 -3
- autobyteus/workflow/context/workflow_runtime_state.py +5 -5
- autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
- autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
- autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
- autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
- autobyteus/workflow/runtime/workflow_runtime.py +8 -8
- autobyteus/workflow/runtime/workflow_worker.py +3 -3
- autobyteus/workflow/status/__init__.py +11 -0
- autobyteus/workflow/status/workflow_status.py +19 -0
- autobyteus/workflow/status/workflow_status_manager.py +48 -0
- autobyteus/workflow/streaming/__init__.py +2 -2
- autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
- autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
- autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
- autobyteus/workflow/utils/wait_for_idle.py +4 -4
- autobyteus-1.2.3.dist-info/METADATA +293 -0
- autobyteus-1.2.3.dist-info/RECORD +600 -0
- {autobyteus-1.2.1.dist-info → autobyteus-1.2.3.dist-info}/WHEEL +1 -1
- {autobyteus-1.2.1.dist-info → autobyteus-1.2.3.dist-info}/top_level.txt +0 -1
- autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
- autobyteus/agent/hooks/__init__.py +0 -16
- autobyteus/agent/hooks/base_phase_hook.py +0 -78
- autobyteus/agent/hooks/hook_definition.py +0 -36
- autobyteus/agent/hooks/hook_meta.py +0 -37
- autobyteus/agent/hooks/hook_registry.py +0 -106
- autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
- autobyteus/agent/phases/__init__.py +0 -18
- autobyteus/agent/phases/discover.py +0 -53
- autobyteus/agent/phases/manager.py +0 -265
- autobyteus/agent/phases/transition_decorator.py +0 -40
- autobyteus/agent/phases/transition_info.py +0 -33
- autobyteus/agent/remote_agent.py +0 -244
- autobyteus/agent/workspace/workspace_definition.py +0 -36
- autobyteus/agent/workspace/workspace_meta.py +0 -37
- autobyteus/agent/workspace/workspace_registry.py +0 -72
- autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
- autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
- autobyteus/agent_team/phases/__init__.py +0 -11
- autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
- autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
- autobyteus/llm/api/bedrock_llm.py +0 -92
- autobyteus/llm/api/groq_llm.py +0 -94
- autobyteus/llm/api/nvidia_llm.py +0 -108
- autobyteus/llm/utils/token_pricing_config.py +0 -87
- autobyteus/rpc/__init__.py +0 -73
- autobyteus/rpc/client/__init__.py +0 -17
- autobyteus/rpc/client/abstract_client_connection.py +0 -124
- autobyteus/rpc/client/client_connection_manager.py +0 -153
- autobyteus/rpc/client/sse_client_connection.py +0 -306
- autobyteus/rpc/client/stdio_client_connection.py +0 -280
- autobyteus/rpc/config/__init__.py +0 -13
- autobyteus/rpc/config/agent_server_config.py +0 -153
- autobyteus/rpc/config/agent_server_registry.py +0 -152
- autobyteus/rpc/hosting.py +0 -244
- autobyteus/rpc/protocol.py +0 -244
- autobyteus/rpc/server/__init__.py +0 -20
- autobyteus/rpc/server/agent_server_endpoint.py +0 -181
- autobyteus/rpc/server/base_method_handler.py +0 -40
- autobyteus/rpc/server/method_handlers.py +0 -259
- autobyteus/rpc/server/sse_server_handler.py +0 -182
- autobyteus/rpc/server/stdio_server_handler.py +0 -151
- autobyteus/rpc/server_main.py +0 -198
- autobyteus/rpc/transport_type.py +0 -13
- autobyteus/tools/bash/__init__.py +0 -2
- autobyteus/tools/bash/bash_executor.py +0 -100
- autobyteus/tools/browser/__init__.py +0 -2
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
- autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
- autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
- autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
- autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
- autobyteus/tools/browser/standalone/__init__.py +0 -6
- autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
- autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
- autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
- autobyteus/tools/browser/standalone/navigate_to.py +0 -84
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -101
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -169
- autobyteus/tools/browser/standalone/webpage_reader.py +0 -105
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -105
- autobyteus/tools/file/edit_file.py +0 -200
- autobyteus/tools/file/list_directory.py +0 -168
- autobyteus/tools/file/search_files.py +0 -188
- autobyteus/tools/timer.py +0 -175
- autobyteus/tools/usage/parsers/__init__.py +0 -22
- autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
- autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
- autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
- autobyteus/tools/usage/parsers/base_parser.py +0 -41
- autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
- autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
- autobyteus/tools/usage/parsers/exceptions.py +0 -13
- autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
- autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
- autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
- autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
- autobyteus/workflow/phases/__init__.py +0 -11
- autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
- autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
- autobyteus-1.2.1.dist-info/METADATA +0 -205
- autobyteus-1.2.1.dist-info/RECORD +0 -511
- examples/__init__.py +0 -1
- examples/agent_team/__init__.py +0 -1
- examples/discover_phase_transitions.py +0 -104
- examples/run_agentic_software_engineer.py +0 -239
- examples/run_browser_agent.py +0 -262
- examples/run_google_slides_agent.py +0 -287
- examples/run_mcp_browser_client.py +0 -174
- examples/run_mcp_google_slides_client.py +0 -270
- examples/run_mcp_list_tools.py +0 -189
- examples/run_poem_writer.py +0 -284
- examples/run_sqlite_agent.py +0 -295
- /autobyteus/{tools/browser/session_aware → skills}/__init__.py +0 -0
- /autobyteus/tools/{browser/session_aware/factory → skill}/__init__.py +0 -0
- {autobyteus-1.2.1.dist-info → autobyteus-1.2.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/server/sse_server_handler.py
|
|
2
|
-
import asyncio
|
|
3
|
-
import logging
|
|
4
|
-
import json
|
|
5
|
-
from typing import Dict, Optional, Union, Set, cast, AsyncIterator
|
|
6
|
-
from weakref import WeakSet
|
|
7
|
-
|
|
8
|
-
from aiohttp import web
|
|
9
|
-
from aiohttp_sse import sse_response
|
|
10
|
-
|
|
11
|
-
from autobyteus.agent.agent import Agent
|
|
12
|
-
# MODIFIED: Import AgentEventStream (remains the same, but it's now the sole class)
|
|
13
|
-
from autobyteus.agent.streaming import AgentEventStream
|
|
14
|
-
from autobyteus.agent.streaming.stream_events import StreamEvent, StreamEventType
|
|
15
|
-
from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode, RequestType, ResponseType, EventType as RPCEventType
|
|
16
|
-
from autobyteus.rpc.server.base_method_handler import BaseMethodHandler
|
|
17
|
-
from autobyteus.rpc.config import AgentServerConfig
|
|
18
|
-
|
|
19
|
-
logger = logging.getLogger(__name__)
|
|
20
|
-
|
|
21
|
-
DEFAULT_STREAM_CHUNK_SIZE = 8192
|
|
22
|
-
|
|
23
|
-
class SseServerHandler:
|
|
24
|
-
def __init__(self, agents: Dict[str, Agent], method_handlers: Dict[Union[RequestType, str], BaseMethodHandler]):
|
|
25
|
-
self._agents: Dict[str, Agent] = agents
|
|
26
|
-
self._method_handlers = method_handlers
|
|
27
|
-
self._app = web.Application()
|
|
28
|
-
self._runner: Optional[web.AppRunner] = None
|
|
29
|
-
self._site: Optional[web.TCPSite] = None
|
|
30
|
-
self._active_sse_forwarding_tasks: Dict[web.StreamResponse, asyncio.Task] = {}
|
|
31
|
-
logger.info(f"SseServerHandler initialized to serve agents: {list(self._agents.keys())}.")
|
|
32
|
-
|
|
33
|
-
def _setup_routes(self, config: AgentServerConfig):
|
|
34
|
-
# ... (method body remains the same) ...
|
|
35
|
-
rpc_request_path = config.sse_request_endpoint
|
|
36
|
-
base_events_path = config.sse_events_endpoint.rstrip('/')
|
|
37
|
-
full_events_path = f"{base_events_path}/{{agent_id_on_server}}"
|
|
38
|
-
stream_download_prefix = config.sse_stream_download_path_prefix.rstrip('/')
|
|
39
|
-
full_stream_download_path = f"{stream_download_prefix}/{{agent_id_on_server}}/{{stream_id}}"
|
|
40
|
-
self._app.router.add_post(rpc_request_path, self.handle_rpc_request)
|
|
41
|
-
self._app.router.add_get(full_events_path, self.handle_sse_events_subscription)
|
|
42
|
-
self._app.router.add_get(full_stream_download_path, self.handle_http_stream_download)
|
|
43
|
-
logger.info(f"SseServerHandler routes: POST {rpc_request_path} (RPC), GET {full_events_path} (SSE per agent), GET {full_stream_download_path} (HTTP Stream Download).")
|
|
44
|
-
|
|
45
|
-
async def handle_rpc_request(self, http_request: web.Request) -> web.Response:
|
|
46
|
-
# ... (method body remains the same) ...
|
|
47
|
-
request_id: Optional[str] = None; raw_body_str: str = ""; target_agent_id: Optional[str] = None
|
|
48
|
-
try:
|
|
49
|
-
raw_body = await http_request.read(); raw_body_str = raw_body.decode()
|
|
50
|
-
try: parsed_json_early = json.loads(raw_body_str); request_id = parsed_json_early.get("id")
|
|
51
|
-
except json.JSONDecodeError: pass
|
|
52
|
-
request_message = ProtocolMessage.from_json_str(raw_body_str); request_id = request_message.id
|
|
53
|
-
if request_message.type != MessageType.REQUEST or not request_message.method:
|
|
54
|
-
return self._create_json_error_response(request_id, ErrorCode.INVALID_REQUEST, "Must be REQUEST with method.", 400)
|
|
55
|
-
if request_message.params and "target_agent_id" in request_message.params:
|
|
56
|
-
target_agent_id = str(request_message.params["target_agent_id"])
|
|
57
|
-
if not target_agent_id: return self._create_json_error_response(request_id, ErrorCode.INVALID_PARAMS, "'target_agent_id' missing in request params.", 400)
|
|
58
|
-
target_agent = self._agents.get(target_agent_id)
|
|
59
|
-
if not target_agent: return self._create_json_error_response(request_id, ErrorCode.METHOD_NOT_FOUND, f"Agent with id '{target_agent_id}' not found.", 404)
|
|
60
|
-
actual_handler_params = request_message.params
|
|
61
|
-
handler = self._method_handlers.get(request_message.method)
|
|
62
|
-
if not handler: return self._create_json_error_response(request_id, ErrorCode.METHOD_NOT_FOUND, f"RPC Method '{request_message.method}' not found.", 404)
|
|
63
|
-
logger.debug(f"SseServerHandler dispatching RPC '{request_message.method}' (ReqID: {request_id}) to '{handler.__class__.__name__}' for agent '{target_agent_id}'.")
|
|
64
|
-
response_proto = await handler.handle(request_id, actual_handler_params, target_agent)
|
|
65
|
-
if response_proto.response_type == ResponseType.STREAM_DOWNLOAD_READY and response_proto.result and "stream_id" in response_proto.result and target_agent_id:
|
|
66
|
-
server_config: AgentServerConfig = http_request.app['agent_server_config']
|
|
67
|
-
full_url_prefix = server_config.get_sse_full_stream_download_url_prefix_for_agent(target_agent_id)
|
|
68
|
-
if full_url_prefix:
|
|
69
|
-
stream_id = response_proto.result["stream_id"]; download_url = f"{full_url_prefix.rstrip('/')}/{stream_id}"
|
|
70
|
-
response_proto.result["download_url"] = download_url; logger.info(f"Constructed download URL for stream_id '{stream_id}': {download_url}")
|
|
71
|
-
else: logger.error(f"Could not construct download_url for stream_id '{response_proto.result['stream_id']}'.")
|
|
72
|
-
http_status = 200
|
|
73
|
-
if response_proto.type == MessageType.ERROR and response_proto.error:
|
|
74
|
-
if response_proto.error.code == ErrorCode.METHOD_NOT_FOUND.value: http_status = 404
|
|
75
|
-
elif response_proto.error.code in [ErrorCode.INVALID_REQUEST.value, ErrorCode.INVALID_PARAMS.value, ErrorCode.PARSE_ERROR.value]: http_status = 400
|
|
76
|
-
else: http_status = 500
|
|
77
|
-
return web.json_response(response_proto.model_dump(exclude_none=True), status=http_status)
|
|
78
|
-
except json.JSONDecodeError as e: logger.error(f"Sse JSONDecodeError: {e}. Body: '{raw_body_str[:200]}'"); return self._create_json_error_response(request_id, ErrorCode.PARSE_ERROR, f"JSON parse error: {e}", 400)
|
|
79
|
-
except ValueError as e: logger.error(f"Sse Protocol validation error: {e}. Body: '{raw_body_str[:200]}'"); return self._create_json_error_response(request_id, ErrorCode.INVALID_REQUEST, f"Invalid request: {e}", 400)
|
|
80
|
-
except Exception as e: logger.error(f"Sse unexpected error: {e}", exc_info=True); return self._create_json_error_response(request_id, ErrorCode.INTERNAL_ERROR, f"Server error: {e}", 500)
|
|
81
|
-
|
|
82
|
-
def _create_json_error_response(self, req_id: Optional[str], code: ErrorCode, msg: str, http_status: int) -> web.Response:
|
|
83
|
-
# ... (method body remains the same) ...
|
|
84
|
-
err_proto = ProtocolMessage.create_error_response(req_id, code, msg)
|
|
85
|
-
return web.json_response(err_proto.model_dump(exclude_none=True), status=http_status)
|
|
86
|
-
|
|
87
|
-
async def handle_sse_events_subscription(self, http_request: web.Request) -> web.StreamResponse:
|
|
88
|
-
# ... (method body remains the same, it instantiates AgentEventStream and calls all_events()) ...
|
|
89
|
-
agent_id_on_server = http_request.match_info.get("agent_id_on_server")
|
|
90
|
-
if not agent_id_on_server: raise web.HTTPBadRequest(text="'agent_id_on_server' path param required.")
|
|
91
|
-
target_agent = self._agents.get(agent_id_on_server)
|
|
92
|
-
if not target_agent: raise web.HTTPNotFound(text=f"Agent '{agent_id_on_server}' not found.")
|
|
93
|
-
client_addr = http_request.remote
|
|
94
|
-
logger.info(f"SSE client {client_addr} subscribing to events for agent '{target_agent.agent_id}' (server key: '{agent_id_on_server}').")
|
|
95
|
-
sse_resp = web.StreamResponse(status=200, reason='OK', headers={'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive'})
|
|
96
|
-
await sse_resp.prepare(http_request)
|
|
97
|
-
forwarding_task = asyncio.create_task(self._stream_agent_events_to_client(sse_resp, target_agent, agent_id_on_server), name=f"sse_fwd_{target_agent.agent_id}_{client_addr}")
|
|
98
|
-
self._active_sse_forwarding_tasks[sse_resp] = forwarding_task
|
|
99
|
-
try: await forwarding_task
|
|
100
|
-
except asyncio.CancelledError: logger.info(f"SSE task for agent '{target_agent.agent_id}' to {client_addr} cancelled.")
|
|
101
|
-
except Exception as e: logger.error(f"Error in SSE streaming for agent '{target_agent.agent_id}' to {client_addr}: {e}", exc_info=True)
|
|
102
|
-
finally: logger.info(f"SSE client {client_addr} for agent '{target_agent.agent_id}' disconnected."); self._active_sse_forwarding_tasks.pop(sse_resp, None)
|
|
103
|
-
return sse_resp
|
|
104
|
-
|
|
105
|
-
async def _stream_agent_events_to_client(self, sse_client_resp: web.StreamResponse, agent: Agent, agent_id_on_server: str):
|
|
106
|
-
# Instantiates AgentEventStream
|
|
107
|
-
event_stream_provider = AgentEventStream(agent)
|
|
108
|
-
logger.debug(f"SseServerHandler: Streaming events from agent '{agent.agent_id}' (key: {agent_id_on_server}) via AgentEventStream.all_events().")
|
|
109
|
-
try:
|
|
110
|
-
# Calls .all_events() method
|
|
111
|
-
async for agent_event_obj in event_stream_provider.all_events():
|
|
112
|
-
if sse_client_resp.closed: break
|
|
113
|
-
rpc_event_type: RPCEventType
|
|
114
|
-
if agent_event_obj.event_type == StreamEventType.ASSISTANT_CHUNK: rpc_event_type = RPCEventType.AGENT_OUTPUT_CHUNK
|
|
115
|
-
elif agent_event_obj.event_type == StreamEventType.ASSISTANT_FINAL_MESSAGE: rpc_event_type = RPCEventType.AGENT_FINAL_MESSAGE
|
|
116
|
-
elif agent_event_obj.event_type == StreamEventType.TOOL_INTERACTION_LOG_ENTRY: rpc_event_type = RPCEventType.TOOL_LOG_ENTRY
|
|
117
|
-
elif agent_event_obj.event_type == StreamEventType.AGENT_STATUS_CHANGE: rpc_event_type = RPCEventType.AGENT_STATUS_UPDATE
|
|
118
|
-
elif agent_event_obj.event_type == StreamEventType.ERROR_EVENT: rpc_event_type = RPCEventType.AGENT_STATUS_UPDATE; logger.error(f"Unified stream error for agent '{agent.agent_id}': {agent_event_obj.data}")
|
|
119
|
-
else: rpc_event_type = RPCEventType.AGENT_STATUS_UPDATE; logger.warning(f"Unhandled StreamEventType '{agent_event_obj.event_type}' from agent '{agent.agent_id}'.")
|
|
120
|
-
payload_data = {"agent_id_on_server": agent_id_on_server, **agent_event_obj.data}
|
|
121
|
-
protocol_event_msg = ProtocolMessage.create_event(event_type=rpc_event_type, payload=payload_data)
|
|
122
|
-
try:
|
|
123
|
-
sse_event_str = f"event: {str(protocol_event_msg.event_type.value)}\ndata: {protocol_event_msg.to_json_str()}\n\n"
|
|
124
|
-
await sse_client_resp.write(sse_event_str.encode('utf-8'))
|
|
125
|
-
except ConnectionResetError: logger.info(f"SSE client reset for agent '{agent.agent_id}'."); break
|
|
126
|
-
except Exception as send_e: logger.error(f"Error sending SSE event for agent '{agent.agent_id}': {send_e}"); break
|
|
127
|
-
if not sse_client_resp.closed: await sse_client_resp.write_eof()
|
|
128
|
-
except asyncio.CancelledError: logger.info(f"Event streaming for agent '{agent.agent_id}' (key: {agent_id_on_server}) cancelled.")
|
|
129
|
-
except Exception as e: logger.error(f"Error in event streaming for agent '{agent.agent_id}' (key: {agent_id_on_server}): {e}", exc_info=True)
|
|
130
|
-
finally: logger.debug(f"Finished event streaming from agent '{agent.agent_id}' (key: {agent_id_on_server}).")
|
|
131
|
-
|
|
132
|
-
async def handle_http_stream_download(self, http_request: web.Request) -> web.StreamResponse:
|
|
133
|
-
# ... (method body remains the same) ...
|
|
134
|
-
agent_id_on_server = http_request.match_info.get("agent_id_on_server"); stream_id = http_request.match_info.get("stream_id")
|
|
135
|
-
if not agent_id_on_server or not stream_id: raise web.HTTPBadRequest(text="'agent_id_on_server' and 'stream_id' path params required.")
|
|
136
|
-
target_agent = self._agents.get(agent_id_on_server)
|
|
137
|
-
if not target_agent: raise web.HTTPNotFound(text=f"Agent '{agent_id_on_server}' not found.")
|
|
138
|
-
logger.info(f"HTTP stream download for agent '{target_agent.agent_id}' (key: '{agent_id_on_server}'), stream_id '{stream_id}'.")
|
|
139
|
-
if not hasattr(target_agent, "get_stream_data") or not hasattr(target_agent, "cleanup_stream_resource"):
|
|
140
|
-
raise web.HTTPNotImplemented(text=f"Agent '{target_agent.agent_id}' does not support stream retrieval.")
|
|
141
|
-
try:
|
|
142
|
-
get_stream_data_method = getattr(target_agent, "get_stream_data")
|
|
143
|
-
data_iterator: AsyncIterator[bytes] = await get_stream_data_method(stream_id)
|
|
144
|
-
response = web.StreamResponse(status=200, reason="OK", headers={"Content-Type": "application/octet-stream"})
|
|
145
|
-
await response.prepare(http_request)
|
|
146
|
-
async for chunk in data_iterator:
|
|
147
|
-
if not isinstance(chunk, bytes): logger.error(f"Agent '{target_agent.agent_id}' stream '{stream_id}' yielded non-bytes: {type(chunk)}."); break
|
|
148
|
-
await response.write(chunk); await asyncio.sleep(0)
|
|
149
|
-
await response.write_eof(); logger.info(f"Streamed data for agent '{target_agent.agent_id}', stream_id '{stream_id}'."); return response
|
|
150
|
-
except FileNotFoundError: logger.warning(f"Stream '{stream_id}' not found for agent '{target_agent.agent_id}'."); raise web.HTTPNotFound(text=f"Stream resource '{stream_id}' not found.")
|
|
151
|
-
except asyncio.CancelledError: logger.info(f"HTTP stream download for '{stream_id}' (agent '{target_agent.agent_id}') cancelled."); raise
|
|
152
|
-
except Exception as e: logger.error(f"Error during HTTP stream download for '{stream_id}' (agent '{target_agent.agent_id}'): {e}", exc_info=True); raise web.HTTPInternalServerError(text="Error serving stream data.")
|
|
153
|
-
finally:
|
|
154
|
-
try: cleanup_method = getattr(target_agent, "cleanup_stream_resource"); await cleanup_method(stream_id); logger.debug(f"Agent '{target_agent.agent_id}' cleaned up stream '{stream_id}'.")
|
|
155
|
-
except Exception as cleanup_e: logger.error(f"Error cleaning up stream '{stream_id}': {cleanup_e}", exc_info=True)
|
|
156
|
-
|
|
157
|
-
async def start_server(self, config: AgentServerConfig):
|
|
158
|
-
# ... (method body remains the same) ...
|
|
159
|
-
if not config.sse_base_url: raise ValueError("SSE base URL required.")
|
|
160
|
-
self._app['agent_server_config'] = config; self._setup_routes(config)
|
|
161
|
-
host = config.sse_base_url.host or "0.0.0.0"; port = config.sse_base_url.port or 80
|
|
162
|
-
self._runner = web.AppRunner(self._app); await self._runner.setup()
|
|
163
|
-
self._site = web.TCPSite(self._runner, host, port)
|
|
164
|
-
try: await self._site.start(); logger.info(f"SseServerHandler started for agents {list(self._agents.keys())} on http://{host}:{port}")
|
|
165
|
-
except OSError as e: logger.error(f"Failed to start SseServer on http://{host}:{port}: {e}", exc_info=True); await self.stop_server(); raise
|
|
166
|
-
except Exception as e: logger.error(f"Unexpected error starting SseServer: {e}", exc_info=True); await self.stop_server(); raise
|
|
167
|
-
|
|
168
|
-
async def stop_server(self):
|
|
169
|
-
# ... (method body remains the same) ...
|
|
170
|
-
logger.info(f"SseServerHandler for agents {list(self._agents.keys())} stopping...")
|
|
171
|
-
for task in list(self._active_sse_forwarding_tasks.values()):
|
|
172
|
-
if task and not task.done(): task.cancel()
|
|
173
|
-
if self._active_sse_forwarding_tasks: await asyncio.gather(*self._active_sse_forwarding_tasks.values(), return_exceptions=True)
|
|
174
|
-
self._active_sse_forwarding_tasks.clear()
|
|
175
|
-
if self._site: try: await self._site.stop()
|
|
176
|
-
except Exception as e: logger.error(f"Error stopping TCPSite: {e}", exc_info=True)
|
|
177
|
-
self._site = None
|
|
178
|
-
if self._runner: try: await self._runner.cleanup()
|
|
179
|
-
except Exception as e: logger.error(f"Error cleaning AppRunner: {e}", exc_info=True)
|
|
180
|
-
self._runner = None
|
|
181
|
-
logger.info(f"SseServerHandler for agents {list(self._agents.keys())} stopped.")
|
|
182
|
-
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/server/stdio_server_handler.py
|
|
2
|
-
import asyncio
|
|
3
|
-
import sys
|
|
4
|
-
import json
|
|
5
|
-
import logging
|
|
6
|
-
from typing import Dict, Optional, Union
|
|
7
|
-
|
|
8
|
-
from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode, RequestType
|
|
9
|
-
from autobyteus.rpc.server.base_method_handler import BaseMethodHandler
|
|
10
|
-
from autobyteus.agent.agent import Agent # Changed from AgentRuntime
|
|
11
|
-
|
|
12
|
-
logger = logging.getLogger(__name__)
|
|
13
|
-
|
|
14
|
-
class StdioServerHandler:
|
|
15
|
-
"""
|
|
16
|
-
Handles RPC communication over stdio for an Agent Server.
|
|
17
|
-
Reads newline-delimited JSON ProtocolMessages from stdin, dispatches them
|
|
18
|
-
to appropriate method handlers (which operate on an Agent instance),
|
|
19
|
-
and writes responses to stdout.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def __init__(self, agent: Agent, method_handlers: Dict[Union[RequestType, str], BaseMethodHandler]): # Changed runtime to agent
|
|
23
|
-
"""
|
|
24
|
-
Initializes the StdioServerHandler.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
agent: The Agent instance this server handler is serving.
|
|
28
|
-
method_handlers: A dictionary mapping method names (RequestType or str)
|
|
29
|
-
to their handler instances.
|
|
30
|
-
"""
|
|
31
|
-
self._agent = agent # Changed from _runtime to _agent
|
|
32
|
-
self._method_handlers = method_handlers
|
|
33
|
-
self._running = False
|
|
34
|
-
logger.info(f"StdioServerHandler initialized for agent '{self._agent.agent_id}'.") # Use agent.agent_id
|
|
35
|
-
|
|
36
|
-
async def listen_and_dispatch(self) -> None:
|
|
37
|
-
"""
|
|
38
|
-
Starts listening on stdin for requests and dispatches them.
|
|
39
|
-
This method runs indefinitely until stdin is closed or an error occurs.
|
|
40
|
-
"""
|
|
41
|
-
self._running = True
|
|
42
|
-
logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' now listening on stdin.")
|
|
43
|
-
|
|
44
|
-
loop = asyncio.get_event_loop()
|
|
45
|
-
reader = asyncio.StreamReader(loop=loop)
|
|
46
|
-
protocol = asyncio.StreamReaderProtocol(reader, loop=loop)
|
|
47
|
-
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
|
|
48
|
-
|
|
49
|
-
try:
|
|
50
|
-
while self._running:
|
|
51
|
-
line_bytes = await reader.readline()
|
|
52
|
-
if not line_bytes:
|
|
53
|
-
logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}': stdin EOF reached. Shutting down.")
|
|
54
|
-
self._running = False
|
|
55
|
-
break
|
|
56
|
-
|
|
57
|
-
line_str = line_bytes.decode().strip()
|
|
58
|
-
if not line_str:
|
|
59
|
-
continue
|
|
60
|
-
|
|
61
|
-
request_id: Optional[str] = None
|
|
62
|
-
try:
|
|
63
|
-
try:
|
|
64
|
-
parsed_json = json.loads(line_str)
|
|
65
|
-
request_id = parsed_json.get("id")
|
|
66
|
-
except json.JSONDecodeError:
|
|
67
|
-
pass
|
|
68
|
-
|
|
69
|
-
message = ProtocolMessage.from_json_str(line_str)
|
|
70
|
-
request_id = message.id
|
|
71
|
-
|
|
72
|
-
if message.type == MessageType.REQUEST:
|
|
73
|
-
response_message = await self._process_request(message)
|
|
74
|
-
else:
|
|
75
|
-
logger.warning(f"StdioServerHandler received non-REQUEST message type: {message.type}. Ignoring.")
|
|
76
|
-
response_message = ProtocolMessage.create_error_response(
|
|
77
|
-
id=request_id,
|
|
78
|
-
code=ErrorCode.INVALID_REQUEST,
|
|
79
|
-
message="Server only accepts REQUEST messages via stdio."
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
await self._send_response(response_message)
|
|
83
|
-
|
|
84
|
-
except json.JSONDecodeError as e:
|
|
85
|
-
logger.error(f"StdioServerHandler: JSONDecodeError: {e}. Raw line: '{line_str[:200]}'")
|
|
86
|
-
err_response = ProtocolMessage.create_error_response(
|
|
87
|
-
id=request_id,
|
|
88
|
-
code=ErrorCode.PARSE_ERROR,
|
|
89
|
-
message=f"Failed to parse JSON request: {e}"
|
|
90
|
-
)
|
|
91
|
-
await self._send_response(err_response)
|
|
92
|
-
except ValueError as e:
|
|
93
|
-
logger.error(f"StdioServerHandler: ProtocolMessage validation error: {e}. Raw line: '{line_str[:200]}'")
|
|
94
|
-
err_response = ProtocolMessage.create_error_response(
|
|
95
|
-
id=request_id,
|
|
96
|
-
code=ErrorCode.INVALID_REQUEST,
|
|
97
|
-
message=f"Invalid request structure: {e}"
|
|
98
|
-
)
|
|
99
|
-
await self._send_response(err_response)
|
|
100
|
-
except Exception as e:
|
|
101
|
-
logger.error(f"StdioServerHandler: Unexpected error processing line: {e}. Raw line: '{line_str[:200]}'", exc_info=True)
|
|
102
|
-
err_response = ProtocolMessage.create_error_response(
|
|
103
|
-
id=request_id,
|
|
104
|
-
code=ErrorCode.INTERNAL_ERROR,
|
|
105
|
-
message=f"Internal server error: {e}"
|
|
106
|
-
)
|
|
107
|
-
await self._send_response(err_response)
|
|
108
|
-
|
|
109
|
-
except asyncio.CancelledError:
|
|
110
|
-
logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' listen_and_dispatch task cancelled.")
|
|
111
|
-
except Exception as e:
|
|
112
|
-
logger.error(f"StdioServerHandler for agent '{self._agent.agent_id}' fatal error in listen_and_dispatch: {e}", exc_info=True)
|
|
113
|
-
finally:
|
|
114
|
-
self._running = False
|
|
115
|
-
logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' stopped listening.")
|
|
116
|
-
|
|
117
|
-
async def _process_request(self, request_message: ProtocolMessage) -> ProtocolMessage:
|
|
118
|
-
if not request_message.method:
|
|
119
|
-
logger.warning(f"StdioServerHandler: Request message missing 'method'. ID: {request_message.id}")
|
|
120
|
-
return ProtocolMessage.create_error_response(
|
|
121
|
-
id=request_message.id,
|
|
122
|
-
code=ErrorCode.INVALID_REQUEST,
|
|
123
|
-
message="Request message must include a 'method'."
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
handler = self._method_handlers.get(request_message.method)
|
|
127
|
-
if not handler:
|
|
128
|
-
logger.warning(f"StdioServerHandler: No handler found for method '{request_message.method}'. ID: {request_message.id}")
|
|
129
|
-
return ProtocolMessage.create_error_response(
|
|
130
|
-
id=request_message.id,
|
|
131
|
-
code=ErrorCode.METHOD_NOT_FOUND,
|
|
132
|
-
message=f"Method '{request_message.method}' not found."
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
logger.debug(f"StdioServerHandler dispatching method '{request_message.method}' (ID: {request_message.id}) to {handler.__class__.__name__}.")
|
|
136
|
-
return await handler.handle(request_message.id, request_message.params, self._agent) # Pass self._agent
|
|
137
|
-
|
|
138
|
-
async def _send_response(self, response_message: ProtocolMessage) -> None:
|
|
139
|
-
try:
|
|
140
|
-
json_response = response_message.to_json_str()
|
|
141
|
-
loop = asyncio.get_event_loop()
|
|
142
|
-
await loop.run_in_executor(None, lambda: sys.stdout.write(json_response + '\n'))
|
|
143
|
-
await loop.run_in_executor(None, sys.stdout.flush)
|
|
144
|
-
logger.debug(f"StdioServerHandler sent response (ID: {response_message.id}, Type: {response_message.type}).")
|
|
145
|
-
except Exception as e:
|
|
146
|
-
logger.error(f"StdioServerHandler failed to send response: {e}", exc_info=True)
|
|
147
|
-
|
|
148
|
-
def stop(self):
|
|
149
|
-
logger.info(f"StdioServerHandler for agent '{self._agent.agent_id}' stop requested.")
|
|
150
|
-
self._running = False
|
|
151
|
-
|
autobyteus/rpc/server_main.py
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/server_main.py
|
|
2
|
-
import asyncio
|
|
3
|
-
import logging
|
|
4
|
-
import argparse
|
|
5
|
-
import signal
|
|
6
|
-
import sys
|
|
7
|
-
from typing import Optional
|
|
8
|
-
|
|
9
|
-
from autobyteus.agent.registry.agent_definition import AgentDefinition
|
|
10
|
-
from autobyteus.agent.registry.agent_registry import default_definition_registry, default_agent_registry
|
|
11
|
-
from autobyteus.agent.agent import Agent
|
|
12
|
-
from autobyteus.llm.models import LLMModel
|
|
13
|
-
|
|
14
|
-
from autobyteus.rpc.config import AgentServerConfig, default_agent_server_registry
|
|
15
|
-
from autobyteus.rpc.server import AgentServerEndpoint
|
|
16
|
-
from autobyteus.rpc.transport_type import TransportType
|
|
17
|
-
|
|
18
|
-
try:
|
|
19
|
-
from autobyteus.agent.input_processor import PassthroughInputProcessor
|
|
20
|
-
except ImportError:
|
|
21
|
-
print("WARNING: PassthroughInputProcessor not found, EchoAgentDefinition in server_main might fail if used.", file=sys.stderr)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
logging.basicConfig(
|
|
25
|
-
level=logging.INFO,
|
|
26
|
-
format='%(asctime)s - %(levelname)s - %(name)s - [%(process)d] - %(message)s',
|
|
27
|
-
stream=sys.stderr
|
|
28
|
-
)
|
|
29
|
-
logger = logging.getLogger(__name__)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
ECHO_AGENT_DEF: Optional[AgentDefinition] = None
|
|
33
|
-
try:
|
|
34
|
-
if not default_definition_registry.get("EchoAgent", "echo_responder"):
|
|
35
|
-
ECHO_AGENT_DEF = AgentDefinition(
|
|
36
|
-
name="EchoAgent",
|
|
37
|
-
role="echo_responder",
|
|
38
|
-
description="A simple agent that echoes back user messages.",
|
|
39
|
-
system_prompt="You are an echo agent. Repeat the user's message precisely.",
|
|
40
|
-
tool_names=[],
|
|
41
|
-
input_processor_names=["PassthroughInputProcessor"], # Assumes PassthroughInputProcessor is registered
|
|
42
|
-
llm_response_processor_names=[]
|
|
43
|
-
)
|
|
44
|
-
logger.info(f"Example AgentDefinition '{ECHO_AGENT_DEF.name}' created and auto-registered for server_main.")
|
|
45
|
-
else:
|
|
46
|
-
ECHO_AGENT_DEF = default_definition_registry.get("EchoAgent", "echo_responder")
|
|
47
|
-
logger.info(f"Example AgentDefinition 'EchoAgent' already registered. Using existing one for server_main.")
|
|
48
|
-
except Exception as e:
|
|
49
|
-
logger.error(f"Could not create/retrieve example EchoAgentDefinition: {e}. server_main might fail if it's requested.")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
shutdown_event = asyncio.Event()
|
|
53
|
-
agent_global: Optional[Agent] = None
|
|
54
|
-
server_endpoint_global: Optional[AgentServerEndpoint] = None
|
|
55
|
-
|
|
56
|
-
async def main():
|
|
57
|
-
global agent_global, server_endpoint_global
|
|
58
|
-
|
|
59
|
-
parser = argparse.ArgumentParser(description="AutoByteUs Agent RPC Server")
|
|
60
|
-
parser.add_argument("--agent-def-name", type=str, required=True, help="Name of the AgentDefinition.")
|
|
61
|
-
parser.add_argument("--agent-def-role", type=str, required=True, help="Role of the AgentDefinition.")
|
|
62
|
-
parser.add_argument("--llm-model-name", type=str, required=True, help="Name of the LLMModel (e.g., 'GPT_4o_API'). This is the string name for the model, not the enum member itself.")
|
|
63
|
-
parser.add_argument("--server-config-id", type=str, required=True, help="ID of the AgentServerConfig.")
|
|
64
|
-
|
|
65
|
-
args = parser.parse_args()
|
|
66
|
-
logger.info(f"server_main starting with args: {args}")
|
|
67
|
-
|
|
68
|
-
agent_definition = default_definition_registry.get(args.agent_def_name, args.agent_def_role)
|
|
69
|
-
if not agent_definition:
|
|
70
|
-
logger.error(f"AgentDefinition not found for name='{args.agent_def_name}', role='{args.agent_def_role}'.")
|
|
71
|
-
sys.exit(1)
|
|
72
|
-
|
|
73
|
-
# The llm_model_name from args is already a string, which is what create_agent now expects.
|
|
74
|
-
# We still need to validate if it's a known model name for robustness,
|
|
75
|
-
# though create_agent (via AgentFactory -> AgentConfig) will also do this.
|
|
76
|
-
try:
|
|
77
|
-
LLMModel[args.llm_model_name.upper()] # Validate if the name maps to a known LLMModel enum member
|
|
78
|
-
except KeyError:
|
|
79
|
-
logger.error(f"LLMModel name '{args.llm_model_name}' provided via --llm-model-name is not a recognized LLMModel. Available: {[m.name for m in LLMModel]}")
|
|
80
|
-
sys.exit(1)
|
|
81
|
-
|
|
82
|
-
server_config = default_agent_server_registry.get_config(args.server_config_id)
|
|
83
|
-
if not server_config:
|
|
84
|
-
logger.error(f"AgentServerConfig not found for server_config_id='{args.server_config_id}'.")
|
|
85
|
-
sys.exit(1)
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
# UPDATED: Pass llm_model_name directly as a string.
|
|
89
|
-
# AgentRegistry.create_agent -> AgentFactory.create_agent_runtime -> AgentFactory.create_agent_context
|
|
90
|
-
# -> AgentConfig now takes llm_model_name: str.
|
|
91
|
-
agent = default_agent_registry.create_agent(
|
|
92
|
-
definition=agent_definition,
|
|
93
|
-
llm_model_name=args.llm_model_name # Pass the string name
|
|
94
|
-
# custom_llm_config, custom_tool_config, etc., can be added here if needed
|
|
95
|
-
)
|
|
96
|
-
agent_global = agent
|
|
97
|
-
except Exception as e:
|
|
98
|
-
logger.error(f"Failed to create Agent instance: {e}", exc_info=True)
|
|
99
|
-
sys.exit(1)
|
|
100
|
-
|
|
101
|
-
logger.info(f"Agent instance created with agent_id '{agent.agent_id}'.")
|
|
102
|
-
|
|
103
|
-
server_endpoint = AgentServerEndpoint(agent)
|
|
104
|
-
server_endpoint_global = server_endpoint
|
|
105
|
-
logger.info(f"AgentServerEndpoint instantiated for agent '{agent.agent_id}'.")
|
|
106
|
-
|
|
107
|
-
try:
|
|
108
|
-
logger.info(f"Starting Agent '{agent.agent_id}' (runtime execution loop)...")
|
|
109
|
-
agent.start()
|
|
110
|
-
|
|
111
|
-
logger.info(f"Starting AgentServerEndpoint for agent '{agent.agent_id}' with config '{server_config.server_id}' (Transport: {server_config.transport_type.value})...")
|
|
112
|
-
await server_endpoint.start(server_config)
|
|
113
|
-
|
|
114
|
-
logger.info(f"Agent '{agent.agent_id}' is now hosted and listening via RPC ({server_config.transport_type.value}).")
|
|
115
|
-
await shutdown_event.wait()
|
|
116
|
-
|
|
117
|
-
except Exception as e:
|
|
118
|
-
logger.error(f"Error during server startup or main execution: {e}", exc_info=True)
|
|
119
|
-
finally:
|
|
120
|
-
logger.info("server_main performing final shutdown...")
|
|
121
|
-
if server_endpoint_global and server_endpoint_global.is_running:
|
|
122
|
-
logger.info("Stopping AgentServerEndpoint...")
|
|
123
|
-
await server_endpoint_global.stop()
|
|
124
|
-
|
|
125
|
-
if agent_global and agent_global.is_running:
|
|
126
|
-
logger.info(f"Stopping Agent '{agent_global.agent_id}'...")
|
|
127
|
-
await agent_global.stop()
|
|
128
|
-
|
|
129
|
-
logger.info("server_main has shut down.")
|
|
130
|
-
|
|
131
|
-
async def initiate_shutdown_from_signal():
|
|
132
|
-
logger.debug("Initiating shutdown via signal...")
|
|
133
|
-
shutdown_event.set()
|
|
134
|
-
|
|
135
|
-
if __name__ == "__main__":
|
|
136
|
-
# Ensure input processors are available if EchoAgentDefinition needs them
|
|
137
|
-
# This try-except is more for robustness during development/examples.
|
|
138
|
-
try:
|
|
139
|
-
# This import ensures that processors like PassthroughInputProcessor are registered
|
|
140
|
-
# if EchoAgentDefinition (or others used by server_main) depends on them.
|
|
141
|
-
from autobyteus.agent import input_processor # type: ignore
|
|
142
|
-
except ImportError as e_proc:
|
|
143
|
-
logger.warning(f"Could not import autobyteus.agent.input_processor: {e_proc}. "
|
|
144
|
-
"Make sure custom input processors are correctly installed and registered if used by agent definitions.")
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# Example STDIO server config (remains for testing server_main directly)
|
|
148
|
-
stdio_cfg_id = "default_stdio_server_cfg"
|
|
149
|
-
if not default_agent_server_registry.get_config(stdio_cfg_id):
|
|
150
|
-
example_stdio_cfg = AgentServerConfig(
|
|
151
|
-
server_id=stdio_cfg_id,
|
|
152
|
-
transport_type=TransportType.STDIO,
|
|
153
|
-
# stdio_command is usually for launching this script itself as a subprocess.
|
|
154
|
-
# For direct execution of server_main.py, this specific command isn't directly used
|
|
155
|
-
# but a valid config is needed if --server-config-id=default_stdio_server_cfg is passed.
|
|
156
|
-
stdio_command=["python", "-m", "autobyteus.rpc.server_main",
|
|
157
|
-
"--agent-def-name", "EchoAgent",
|
|
158
|
-
"--agent-def-role", "echo_responder",
|
|
159
|
-
"--llm-model-name", "GPT_4O_API", # Example model name
|
|
160
|
-
"--server-config-id", stdio_cfg_id
|
|
161
|
-
]
|
|
162
|
-
)
|
|
163
|
-
default_agent_server_registry.register_config(example_stdio_cfg)
|
|
164
|
-
logger.info(f"Registered example STDIOServerConfig '{stdio_cfg_id}'.")
|
|
165
|
-
|
|
166
|
-
# Example SSE server config
|
|
167
|
-
sse_cfg_id = "default_sse_server_cfg"
|
|
168
|
-
if not default_agent_server_registry.get_config(sse_cfg_id):
|
|
169
|
-
example_sse_cfg = AgentServerConfig(
|
|
170
|
-
server_id=sse_cfg_id, # This ID is for the server config itself
|
|
171
|
-
transport_type=TransportType.SSE,
|
|
172
|
-
sse_base_url="http://localhost:8765",
|
|
173
|
-
sse_request_endpoint="/invoke_rpc", # Changed from /rpc to avoid clash with potential future global /rpc
|
|
174
|
-
sse_events_endpoint="/agent_events" # Changed from /events
|
|
175
|
-
)
|
|
176
|
-
default_agent_server_registry.register_config(example_sse_cfg)
|
|
177
|
-
logger.info(f"Registered example SseServerConfig '{sse_cfg_id}'.")
|
|
178
|
-
|
|
179
|
-
loop = asyncio.get_event_loop()
|
|
180
|
-
for sig_name_str in ('SIGINT', 'SIGTERM'):
|
|
181
|
-
sig_enum_member = getattr(signal, sig_name_str, None)
|
|
182
|
-
if sig_enum_member:
|
|
183
|
-
try:
|
|
184
|
-
loop.add_signal_handler(sig_enum_member, lambda s=sig_name_str: asyncio.create_task(initiate_shutdown_from_signal()))
|
|
185
|
-
except (ValueError, RuntimeError, NotImplementedError) as e: # Might fail on Windows for SIGTERM
|
|
186
|
-
logger.warning(f"Could not set signal handler for {sig_name_str} on this platform: {e}.")
|
|
187
|
-
try:
|
|
188
|
-
loop.run_until_complete(main())
|
|
189
|
-
except KeyboardInterrupt:
|
|
190
|
-
logger.info("KeyboardInterrupt received in main. Shutting down.")
|
|
191
|
-
if not shutdown_event.is_set():
|
|
192
|
-
if loop.is_running():
|
|
193
|
-
asyncio.ensure_future(initiate_shutdown_from_signal(), loop=loop)
|
|
194
|
-
else: # Should not happen if loop was running
|
|
195
|
-
loop.run_until_complete(initiate_shutdown_from_signal())
|
|
196
|
-
finally:
|
|
197
|
-
logger.info("Asyncio loop in server_main is finalizing.")
|
|
198
|
-
|
autobyteus/rpc/transport_type.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/transport_type.py
|
|
2
|
-
from enum import Enum
|
|
3
|
-
|
|
4
|
-
class TransportType(str, Enum):
|
|
5
|
-
"""
|
|
6
|
-
Defines the transport mechanisms supported for RPC communication.
|
|
7
|
-
"""
|
|
8
|
-
STDIO = "stdio"
|
|
9
|
-
SSE = "sse" # Server-Sent Events over HTTP
|
|
10
|
-
|
|
11
|
-
def __str__(self) -> str:
|
|
12
|
-
return self.value
|
|
13
|
-
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import subprocess
|
|
3
|
-
import logging
|
|
4
|
-
import shutil
|
|
5
|
-
import tempfile
|
|
6
|
-
from typing import TYPE_CHECKING, Optional
|
|
7
|
-
|
|
8
|
-
from autobyteus.tools import tool
|
|
9
|
-
from autobyteus.tools.tool_category import ToolCategory
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from autobyteus.agent.context import AgentContext
|
|
13
|
-
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
15
|
-
|
|
16
|
-
@tool(name="execute_bash", category=ToolCategory.SYSTEM)
|
|
17
|
-
async def bash_executor(context: Optional['AgentContext'], command: str) -> str:
|
|
18
|
-
"""
|
|
19
|
-
Executes bash commands using the '/bin/bash' interpreter.
|
|
20
|
-
On success, it returns a formatted string containing the command's standard output (stdout) and/or diagnostic logs.
|
|
21
|
-
On failure, it raises an exception.
|
|
22
|
-
- If a command has only stdout, its content is returned directly.
|
|
23
|
-
- If a command has diagnostic output (from stderr), it will be included and labeled as 'LOGS' in the output.
|
|
24
|
-
'command' is the bash command string to be executed.
|
|
25
|
-
The command is executed in the agent's workspace directory if available.
|
|
26
|
-
"""
|
|
27
|
-
if not shutil.which("bash"):
|
|
28
|
-
error_msg = "'bash' executable not found in system PATH. The execute_bash tool cannot be used."
|
|
29
|
-
logger.error(error_msg)
|
|
30
|
-
raise FileNotFoundError(error_msg)
|
|
31
|
-
|
|
32
|
-
agent_id_str = context.agent_id if context else "Non-Agent"
|
|
33
|
-
|
|
34
|
-
effective_cwd = None
|
|
35
|
-
log_cwd_source = ""
|
|
36
|
-
|
|
37
|
-
if context and hasattr(context, 'workspace') and context.workspace:
|
|
38
|
-
try:
|
|
39
|
-
base_path = context.workspace.get_base_path()
|
|
40
|
-
if base_path and isinstance(base_path, str):
|
|
41
|
-
effective_cwd = base_path
|
|
42
|
-
log_cwd_source = f"agent workspace: {effective_cwd}"
|
|
43
|
-
else:
|
|
44
|
-
logger.warning(f"Agent '{agent_id_str}' has a workspace, but it provided an invalid base path ('{base_path}'). "
|
|
45
|
-
f"Falling back to system temporary directory.")
|
|
46
|
-
except Exception as e:
|
|
47
|
-
logger.warning(f"Could not retrieve workspace for agent '{agent_id_str}': {e}. "
|
|
48
|
-
f"Falling back to system temporary directory.")
|
|
49
|
-
|
|
50
|
-
if not effective_cwd:
|
|
51
|
-
effective_cwd = tempfile.gettempdir()
|
|
52
|
-
log_cwd_source = f"system temporary directory: {effective_cwd}"
|
|
53
|
-
|
|
54
|
-
logger.debug(f"Functional execute_bash tool executing for '{agent_id_str}': {command} in cwd from {log_cwd_source}")
|
|
55
|
-
|
|
56
|
-
try:
|
|
57
|
-
# Explicitly use 'bash -c' for reliable execution
|
|
58
|
-
process = await asyncio.create_subprocess_exec(
|
|
59
|
-
'bash', '-c', command,
|
|
60
|
-
stdout=asyncio.subprocess.PIPE,
|
|
61
|
-
stderr=asyncio.subprocess.PIPE,
|
|
62
|
-
cwd=effective_cwd
|
|
63
|
-
)
|
|
64
|
-
stdout, stderr = await process.communicate()
|
|
65
|
-
|
|
66
|
-
stdout_output = stdout.decode().strip() if stdout else ""
|
|
67
|
-
stderr_output = stderr.decode().strip() if stderr else ""
|
|
68
|
-
|
|
69
|
-
if process.returncode != 0:
|
|
70
|
-
error_message = stderr_output if stderr_output else "Unknown error"
|
|
71
|
-
if not error_message and process.returncode != 0:
|
|
72
|
-
error_message = f"Command failed with exit code {process.returncode} and no stderr output."
|
|
73
|
-
|
|
74
|
-
logger.error(f"Command '{command}' failed with return code {process.returncode}: {error_message}")
|
|
75
|
-
raise subprocess.CalledProcessError(
|
|
76
|
-
returncode=process.returncode,
|
|
77
|
-
cmd=command,
|
|
78
|
-
output=stdout_output,
|
|
79
|
-
stderr=error_message
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
# Adaptive return for successful commands to provide maximum context to the agent.
|
|
83
|
-
if stdout_output and stderr_output:
|
|
84
|
-
return f"STDOUT:\n{stdout_output}\n\nLOGS:\n{stderr_output}"
|
|
85
|
-
elif stdout_output:
|
|
86
|
-
return stdout_output # Keep it simple for commands with only stdout
|
|
87
|
-
elif stderr_output:
|
|
88
|
-
return f"LOGS:\n{stderr_output}"
|
|
89
|
-
else:
|
|
90
|
-
return "Command executed successfully with no output."
|
|
91
|
-
|
|
92
|
-
except subprocess.CalledProcessError:
|
|
93
|
-
raise
|
|
94
|
-
except FileNotFoundError:
|
|
95
|
-
# This can be raised by create_subprocess_exec if 'bash' is not found, despite the initial check.
|
|
96
|
-
logger.error("'bash' executable not found when attempting to execute command. Please ensure it is installed and in the PATH.")
|
|
97
|
-
raise
|
|
98
|
-
except Exception as e:
|
|
99
|
-
logger.exception(f"An error occurred while preparing or executing command '{command}': {str(e)}")
|
|
100
|
-
raise RuntimeError(f"Failed to execute command '{command}': {str(e)}")
|