autobyteus 1.2.1__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autobyteus/agent/agent.py +15 -5
- autobyteus/agent/bootstrap_steps/__init__.py +3 -3
- autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +5 -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/working_context_snapshot_restore_step.py +38 -0
- autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
- autobyteus/agent/context/agent_config.py +47 -20
- autobyteus/agent/context/agent_context.py +23 -18
- autobyteus/agent/context/agent_runtime_state.py +21 -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 +83 -6
- 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 +44 -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 +82 -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 +35 -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 +205 -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/path_resolver.py +27 -0
- autobyteus/memory/policies/__init__.py +5 -0
- autobyteus/memory/policies/compaction_policy.py +16 -0
- autobyteus/memory/restore/__init__.py +1 -0
- autobyteus/memory/restore/working_context_snapshot_bootstrapper.py +61 -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 +9 -0
- autobyteus/memory/store/base_store.py +14 -0
- autobyteus/memory/store/file_store.py +98 -0
- autobyteus/memory/store/working_context_snapshot_store.py +28 -0
- autobyteus/memory/tool_interaction_builder.py +46 -0
- autobyteus/memory/turn_tracker.py +9 -0
- autobyteus/memory/working_context_snapshot.py +69 -0
- autobyteus/memory/working_context_snapshot_serializer.py +135 -0
- autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
- autobyteus/multimedia/audio/api/gemini_audio_client.py +109 -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 +39 -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 +64 -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.3.0.dist-info/METADATA +293 -0
- autobyteus-1.3.0.dist-info/RECORD +606 -0
- {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/WHEEL +1 -1
- {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.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.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/client/stdio_client_connection.py
|
|
2
|
-
import asyncio
|
|
3
|
-
import logging
|
|
4
|
-
import json
|
|
5
|
-
from typing import List, Optional, Dict, Any, AsyncIterator # Added Any, AsyncIterator
|
|
6
|
-
|
|
7
|
-
from autobyteus.rpc.protocol import ProtocolMessage, MessageType, ErrorCode
|
|
8
|
-
from .abstract_client_connection import AbstractClientConnection
|
|
9
|
-
from autobyteus.rpc.config import AgentServerConfig, TransportType # Added TransportType
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
DEFAULT_STDIO_TIMEOUT = 10.0 # seconds for a response
|
|
14
|
-
|
|
15
|
-
class StdioClientConnection(AbstractClientConnection):
|
|
16
|
-
"""
|
|
17
|
-
Client connection implementation for stdio-based Agent Servers.
|
|
18
|
-
Manages a subprocess and communicates via its stdin/stdout using
|
|
19
|
-
newline-delimited JSON ProtocolMessages.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def __init__(self, server_config: AgentServerConfig):
|
|
23
|
-
"""
|
|
24
|
-
Initializes the StdioClientConnection.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
server_config: The configuration for the stdio server.
|
|
28
|
-
|
|
29
|
-
Raises:
|
|
30
|
-
ValueError: If server_config is not for stdio or stdio_command is missing.
|
|
31
|
-
"""
|
|
32
|
-
if server_config.transport_type != TransportType.STDIO: # Using Enum member
|
|
33
|
-
raise ValueError("StdioClientConnection requires an AgentServerConfig with transport_type 'stdio'.")
|
|
34
|
-
if not server_config.stdio_command:
|
|
35
|
-
raise ValueError("AgentServerConfig for stdio transport must have a stdio_command.")
|
|
36
|
-
|
|
37
|
-
super().__init__(server_id=server_config.server_id)
|
|
38
|
-
self.server_config: AgentServerConfig = server_config
|
|
39
|
-
self._process: Optional[asyncio.subprocess.Process] = None
|
|
40
|
-
self._response_futures: Dict[str, asyncio.Future] = {}
|
|
41
|
-
self._reader_task: Optional[asyncio.Task] = None
|
|
42
|
-
self._lock = asyncio.Lock() # For managing access to _response_futures
|
|
43
|
-
|
|
44
|
-
async def connect(self) -> None:
|
|
45
|
-
"""
|
|
46
|
-
Starts the stdio server subprocess and establishes communication.
|
|
47
|
-
"""
|
|
48
|
-
async with self._connection_lock:
|
|
49
|
-
if self._is_connected:
|
|
50
|
-
logger.debug(f"StdioClientConnection to '{self.server_id}' already connected.")
|
|
51
|
-
return
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
logger.info(f"Connecting StdioClientConnection to '{self.server_id}' using command: {' '.join(self.server_config.stdio_command)}")
|
|
55
|
-
self._process = await asyncio.create_subprocess_exec(
|
|
56
|
-
*self.server_config.stdio_command,
|
|
57
|
-
stdin=asyncio.subprocess.PIPE,
|
|
58
|
-
stdout=asyncio.subprocess.PIPE,
|
|
59
|
-
stderr=asyncio.subprocess.PIPE
|
|
60
|
-
)
|
|
61
|
-
self._is_connected = True
|
|
62
|
-
self._reader_task = asyncio.create_task(self._read_loop(), name=f"stdio_reader_{self.server_id}")
|
|
63
|
-
asyncio.create_task(self._log_stderr(), name=f"stdio_stderr_logger_{self.server_id}")
|
|
64
|
-
logger.info(f"StdioClientConnection to '{self.server_id}' connected successfully (PID: {self._process.pid}).")
|
|
65
|
-
except Exception as e:
|
|
66
|
-
logger.error(f"Failed to connect StdioClientConnection to '{self.server_id}': {e}", exc_info=True)
|
|
67
|
-
self._is_connected = False
|
|
68
|
-
if self._process and self._process.returncode is None:
|
|
69
|
-
self._process.terminate()
|
|
70
|
-
await self._process.wait()
|
|
71
|
-
self._process = None
|
|
72
|
-
raise ConnectionError(f"Failed to start or connect to stdio server '{self.server_id}': {e}") from e
|
|
73
|
-
|
|
74
|
-
async def _log_stderr(self) -> None:
|
|
75
|
-
"""Logs stderr from the subprocess."""
|
|
76
|
-
if not self._process or not self._process.stderr:
|
|
77
|
-
return
|
|
78
|
-
|
|
79
|
-
try:
|
|
80
|
-
while self._process.returncode is None:
|
|
81
|
-
line_bytes = await self._process.stderr.readline()
|
|
82
|
-
if not line_bytes:
|
|
83
|
-
if self._process.returncode is not None:
|
|
84
|
-
break
|
|
85
|
-
await asyncio.sleep(0.01)
|
|
86
|
-
continue
|
|
87
|
-
|
|
88
|
-
line_str = line_bytes.decode(errors='replace').strip()
|
|
89
|
-
if line_str:
|
|
90
|
-
logger.warning(f"StdioServer '{self.server_id}' stderr: {line_str}")
|
|
91
|
-
|
|
92
|
-
if self._process.returncode is not None and self._process.stderr.at_eof():
|
|
93
|
-
break
|
|
94
|
-
|
|
95
|
-
except asyncio.CancelledError:
|
|
96
|
-
logger.info(f"Stderr logging for '{self.server_id}' cancelled.")
|
|
97
|
-
except Exception as e:
|
|
98
|
-
logger.error(f"Error in stderr logging for '{self.server_id}': {e}", exc_info=True)
|
|
99
|
-
finally:
|
|
100
|
-
logger.debug(f"Stderr logging task for '{self.server_id}' finished.")
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
async def _read_loop(self) -> None:
|
|
104
|
-
"""Reads messages from stdout and dispatches them."""
|
|
105
|
-
if not self._process or not self._process.stdout:
|
|
106
|
-
logger.error(f"StdioClientConnection '{self.server_id}' read_loop: Process or stdout not available.")
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
try:
|
|
110
|
-
while self._is_connected and self._process.returncode is None:
|
|
111
|
-
line_bytes = await self._process.stdout.readline()
|
|
112
|
-
if not line_bytes:
|
|
113
|
-
logger.info(f"StdioServer '{self.server_id}' stdout EOF reached. Process likely terminated.")
|
|
114
|
-
if self._is_connected:
|
|
115
|
-
await self._handle_unexpected_disconnect()
|
|
116
|
-
break
|
|
117
|
-
|
|
118
|
-
line_str = line_bytes.decode().strip()
|
|
119
|
-
if not line_str:
|
|
120
|
-
continue
|
|
121
|
-
|
|
122
|
-
try:
|
|
123
|
-
message = ProtocolMessage.from_json_str(line_str)
|
|
124
|
-
if message.id and message.id in self._response_futures:
|
|
125
|
-
future = self._response_futures.pop(message.id, None)
|
|
126
|
-
if future and not future.done():
|
|
127
|
-
future.set_result(message)
|
|
128
|
-
elif future and future.done():
|
|
129
|
-
logger.warning(f"Future for response ID '{message.id}' was already done. Duplicate response or late arrival?")
|
|
130
|
-
elif message.type == MessageType.EVENT:
|
|
131
|
-
logger.info(f"Received EVENT message via stdio (unexpected for this model): {message}")
|
|
132
|
-
else:
|
|
133
|
-
logger.warning(f"Received stdio message with no matching future or unhandled type: {message}")
|
|
134
|
-
except (json.JSONDecodeError, ValueError) as e:
|
|
135
|
-
logger.error(f"Failed to parse ProtocolMessage from stdio server '{self.server_id}': {e}. Line: '{line_str[:200]}'")
|
|
136
|
-
except Exception as e:
|
|
137
|
-
logger.error(f"Unexpected error processing message from stdio server '{self.server_id}': {e}. Line: '{line_str[:200]}'", exc_info=True)
|
|
138
|
-
|
|
139
|
-
except asyncio.CancelledError:
|
|
140
|
-
logger.info(f"Stdio read_loop for '{self.server_id}' cancelled.")
|
|
141
|
-
except Exception as e:
|
|
142
|
-
logger.error(f"Fatal error in stdio read_loop for '{self.server_id}': {e}", exc_info=True)
|
|
143
|
-
if self._is_connected:
|
|
144
|
-
self._handle_unexpected_disconnect()
|
|
145
|
-
finally:
|
|
146
|
-
logger.info(f"Stdio read_loop for '{self.server_id}' exiting.")
|
|
147
|
-
if self._is_connected:
|
|
148
|
-
await self._handle_unexpected_disconnect(log_warning=False)
|
|
149
|
-
|
|
150
|
-
async def _handle_unexpected_disconnect(self, log_warning=True):
|
|
151
|
-
"""Handles unexpected disconnection by failing pending futures."""
|
|
152
|
-
if log_warning:
|
|
153
|
-
logger.warning(f"StdioClientConnection to '{self.server_id}' unexpectedly disconnected or process terminated.")
|
|
154
|
-
self._is_connected = False
|
|
155
|
-
|
|
156
|
-
# Error response is not used here, futures are set with specific errors
|
|
157
|
-
# error_response = ProtocolMessage.create_error_response(...)
|
|
158
|
-
async with self._lock:
|
|
159
|
-
for msg_id, future in list(self._response_futures.items()):
|
|
160
|
-
if not future.done():
|
|
161
|
-
custom_error = ProtocolMessage.create_error_response(
|
|
162
|
-
id=msg_id, code=ErrorCode.INTERNAL_ERROR,
|
|
163
|
-
message=f"Connection lost before response for request ID {msg_id} was received."
|
|
164
|
-
)
|
|
165
|
-
future.set_result(custom_error)
|
|
166
|
-
self._response_futures.pop(msg_id, None)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
async def close(self) -> None:
|
|
170
|
-
"""Closes the connection and terminates the subprocess."""
|
|
171
|
-
async with self._connection_lock:
|
|
172
|
-
if not self._is_connected and not self._process:
|
|
173
|
-
logger.debug(f"StdioClientConnection to '{self.server_id}' already closed or never connected.")
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
self._is_connected = False
|
|
177
|
-
|
|
178
|
-
if self._reader_task and not self._reader_task.done():
|
|
179
|
-
self._reader_task.cancel()
|
|
180
|
-
try:
|
|
181
|
-
await self._reader_task
|
|
182
|
-
except asyncio.CancelledError:
|
|
183
|
-
pass
|
|
184
|
-
self._reader_task = None
|
|
185
|
-
|
|
186
|
-
error_on_close = ProtocolMessage.create_error_response(
|
|
187
|
-
id=None, code=ErrorCode.INTERNAL_ERROR, message="Connection closed by client while request was pending."
|
|
188
|
-
)
|
|
189
|
-
for msg_id, future in list(self._response_futures.items()):
|
|
190
|
-
if not future.done():
|
|
191
|
-
custom_error = ProtocolMessage.create_error_response(
|
|
192
|
-
id=msg_id, code=ErrorCode.INTERNAL_ERROR,
|
|
193
|
-
message=f"Connection closed for request ID {msg_id} before response."
|
|
194
|
-
)
|
|
195
|
-
future.set_result(custom_error)
|
|
196
|
-
self._response_futures.pop(msg_id, None)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if self._process:
|
|
200
|
-
if self._process.returncode is None:
|
|
201
|
-
logger.info(f"Terminating stdio server process for '{self.server_id}' (PID: {self._process.pid}).")
|
|
202
|
-
try:
|
|
203
|
-
self._process.terminate()
|
|
204
|
-
await asyncio.wait_for(self._process.wait(), timeout=DEFAULT_STDIO_TIMEOUT / 2)
|
|
205
|
-
except asyncio.TimeoutError:
|
|
206
|
-
logger.warning(f"Timeout terminating stdio server '{self.server_id}'. Killing process.")
|
|
207
|
-
if self._process.returncode is None: self._process.kill() # Check again before kill
|
|
208
|
-
await self._process.wait()
|
|
209
|
-
except Exception as e:
|
|
210
|
-
logger.error(f"Error during stdio server termination for '{self.server_id}': {e}")
|
|
211
|
-
else:
|
|
212
|
-
logger.info(f"Stdio server process for '{self.server_id}' (PID: {self._process.pid}) already exited with code {self._process.returncode}.")
|
|
213
|
-
self._process = None
|
|
214
|
-
|
|
215
|
-
logger.info(f"StdioClientConnection to '{self.server_id}' closed.")
|
|
216
|
-
|
|
217
|
-
async def send_request(self, request_message: ProtocolMessage) -> ProtocolMessage:
|
|
218
|
-
"""Sends a request and waits for a response."""
|
|
219
|
-
if not self._is_connected or not self._process or not self._process.stdin:
|
|
220
|
-
# Attempt to reconnect if not connected
|
|
221
|
-
logger.info(f"StdioClientConnection '{self.server_id}' not connected. Attempting to connect before send_request.")
|
|
222
|
-
await self.connect()
|
|
223
|
-
if not self._is_connected or not self._process or not self._process.stdin:
|
|
224
|
-
raise ConnectionError(f"Failed to connect to stdio server '{self.server_id}' for send_request.")
|
|
225
|
-
|
|
226
|
-
if request_message.type != MessageType.REQUEST:
|
|
227
|
-
raise ValueError("ProtocolMessage must be of type REQUEST to be sent via send_request.")
|
|
228
|
-
if not request_message.id:
|
|
229
|
-
raise ValueError("Request ProtocolMessage must have an ID.")
|
|
230
|
-
|
|
231
|
-
future: asyncio.Future[ProtocolMessage] = asyncio.Future()
|
|
232
|
-
async with self._lock:
|
|
233
|
-
self._response_futures[request_message.id] = future
|
|
234
|
-
|
|
235
|
-
try:
|
|
236
|
-
json_str = request_message.to_json_str()
|
|
237
|
-
logger.debug(f"StdioClient '{self.server_id}' sending: {json_str}")
|
|
238
|
-
self._process.stdin.write(json_str.encode() + b'\n')
|
|
239
|
-
await self._process.stdin.drain()
|
|
240
|
-
except Exception as e:
|
|
241
|
-
async with self._lock:
|
|
242
|
-
self._response_futures.pop(request_message.id, None)
|
|
243
|
-
# Don't cancel future, let it timeout or be resolved by _handle_unexpected_disconnect
|
|
244
|
-
logger.error(f"Error sending request to stdio server '{self.server_id}': {e}", exc_info=True)
|
|
245
|
-
# If send fails, connection is likely broken. Mark as such and try to close.
|
|
246
|
-
await self.close()
|
|
247
|
-
raise ConnectionError(f"Failed to send request to stdio server '{self.server_id}': {e}") from e
|
|
248
|
-
|
|
249
|
-
try:
|
|
250
|
-
response = await asyncio.wait_for(future, timeout=DEFAULT_STDIO_TIMEOUT)
|
|
251
|
-
return response
|
|
252
|
-
except asyncio.TimeoutError:
|
|
253
|
-
logger.warning(f"Timeout waiting for response to request ID '{request_message.id}' from stdio server '{self.server_id}'.")
|
|
254
|
-
async with self._lock:
|
|
255
|
-
if request_message.id in self._response_futures:
|
|
256
|
-
self._response_futures.pop(request_message.id, None)
|
|
257
|
-
return ProtocolMessage.create_error_response(
|
|
258
|
-
id=request_message.id,
|
|
259
|
-
code=ErrorCode.SERVER_ERROR_TIMEOUT,
|
|
260
|
-
message=f"Timeout waiting for response to request ID '{request_message.id}'."
|
|
261
|
-
)
|
|
262
|
-
except asyncio.CancelledError:
|
|
263
|
-
logger.info(f"Request ID '{request_message.id}' was cancelled while awaiting response.")
|
|
264
|
-
return ProtocolMessage.create_error_response(
|
|
265
|
-
id=request_message.id,
|
|
266
|
-
code=ErrorCode.INTERNAL_ERROR,
|
|
267
|
-
message=f"Request ID '{request_message.id}' cancelled."
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
async def request_and_download_stream(
|
|
271
|
-
self,
|
|
272
|
-
stream_request_params: Dict[str, Any],
|
|
273
|
-
target_agent_id: str
|
|
274
|
-
) -> AsyncIterator[bytes]:
|
|
275
|
-
logger.warning(f"StdioClientConnection does not support HTTP stream downloads for target_agent_id '{target_agent_id}'.")
|
|
276
|
-
raise NotImplementedError("StdioClientConnection does not support HTTP stream downloads.")
|
|
277
|
-
# This construct makes it an async generator that immediately raises
|
|
278
|
-
if False: # pragma: no cover
|
|
279
|
-
yield b''
|
|
280
|
-
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/config/__init__.py
|
|
2
|
-
"""
|
|
3
|
-
Configuration components for the AutoByteUs RPC framework.
|
|
4
|
-
"""
|
|
5
|
-
from .agent_server_config import AgentServerConfig
|
|
6
|
-
from .agent_server_registry import AgentServerRegistry, default_agent_server_registry
|
|
7
|
-
|
|
8
|
-
__all__ = [
|
|
9
|
-
"AgentServerConfig",
|
|
10
|
-
"AgentServerRegistry",
|
|
11
|
-
"default_agent_server_registry",
|
|
12
|
-
]
|
|
13
|
-
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/config/agent_server_config.py
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Optional, Dict, Any, List # List was missing
|
|
4
|
-
from pydantic import BaseModel, Field, validator, HttpUrl
|
|
5
|
-
|
|
6
|
-
from autobyteus.rpc.transport_type import TransportType
|
|
7
|
-
|
|
8
|
-
logger = logging.getLogger(__name__)
|
|
9
|
-
|
|
10
|
-
class AgentServerConfig(BaseModel):
|
|
11
|
-
"""
|
|
12
|
-
Configuration for an Agent Server, specifying how it can be connected to.
|
|
13
|
-
"""
|
|
14
|
-
server_id: str = Field(..., description="Unique identifier for this server configuration.")
|
|
15
|
-
transport_type: TransportType = Field(..., description="The transport mechanism (e.g., stdio, sse).")
|
|
16
|
-
|
|
17
|
-
# For stdio transport
|
|
18
|
-
stdio_command: Optional[List[str]] = Field(default=None, description="Command and arguments to launch the agent server process for stdio.")
|
|
19
|
-
|
|
20
|
-
# For sse transport
|
|
21
|
-
sse_base_url: Optional[HttpUrl] = Field(default=None, description="Base URL for the agent server's HTTP/SSE endpoints.")
|
|
22
|
-
sse_request_endpoint: str = Field(default="/invoke", description="Relative path for synchronous requests (e.g., invoke_method).")
|
|
23
|
-
sse_events_endpoint: str = Field(default="/events", description="Relative path for the Server-Sent Events stream.")
|
|
24
|
-
# New field for HTTP stream downloads
|
|
25
|
-
sse_stream_download_path_prefix: str = Field(default="/streams", description="Base relative path for HTTP stream downloads. Full path will be {base_url}{prefix}/{agent_id_on_server}/{stream_id}.")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Optional metadata
|
|
29
|
-
metadata: Dict[str, Any] = Field(default_factory=dict, description="Optional metadata for the server configuration.")
|
|
30
|
-
|
|
31
|
-
class Config:
|
|
32
|
-
use_enum_values = True # Serialize enums to their values
|
|
33
|
-
validate_assignment = True
|
|
34
|
-
|
|
35
|
-
@validator('stdio_command')
|
|
36
|
-
def _check_stdio_command(cls, v, values):
|
|
37
|
-
if values.get('transport_type') == TransportType.STDIO and not v:
|
|
38
|
-
raise ValueError("stdio_command is required for stdio transport type.")
|
|
39
|
-
if values.get('transport_type') != TransportType.STDIO and v:
|
|
40
|
-
logger.warning("stdio_command is provided but transport_type is not stdio. It will be ignored.")
|
|
41
|
-
return v
|
|
42
|
-
|
|
43
|
-
@validator('sse_base_url')
|
|
44
|
-
def _check_sse_base_url(cls, v, values):
|
|
45
|
-
if values.get('transport_type') == TransportType.SSE and not v:
|
|
46
|
-
raise ValueError("sse_base_url is required for sse transport type.")
|
|
47
|
-
if values.get('transport_type') != TransportType.SSE and v:
|
|
48
|
-
logger.warning("sse_base_url is provided but transport_type is not sse. It will be ignored.")
|
|
49
|
-
return v
|
|
50
|
-
|
|
51
|
-
@validator('sse_stream_download_path_prefix')
|
|
52
|
-
def _check_sse_stream_download_path_prefix(cls, v, values):
|
|
53
|
-
if not v.startswith('/'):
|
|
54
|
-
raise ValueError("sse_stream_download_path_prefix must start with a '/'.")
|
|
55
|
-
if values.get('transport_type') != TransportType.SSE and v != "/streams": # if not default and not SSE
|
|
56
|
-
logger.warning("sse_stream_download_path_prefix is customized but transport_type is not sse. It might be ignored.")
|
|
57
|
-
return v
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def get_sse_full_request_url(self) -> Optional[str]:
|
|
61
|
-
"""Returns the full URL for SSE synchronous requests if applicable."""
|
|
62
|
-
if self.transport_type == TransportType.SSE and self.sse_base_url:
|
|
63
|
-
# Pydantic's HttpUrl converts to string automatically when concatenated this way
|
|
64
|
-
return str(self.sse_base_url).rstrip('/') + self.sse_request_endpoint
|
|
65
|
-
return None
|
|
66
|
-
|
|
67
|
-
def get_sse_full_events_url(self) -> Optional[str]:
|
|
68
|
-
"""Returns the full URL for the SSE event stream if applicable."""
|
|
69
|
-
if self.transport_type == TransportType.SSE and self.sse_base_url:
|
|
70
|
-
return str(self.sse_base_url).rstrip('/') + self.sse_events_endpoint
|
|
71
|
-
return None
|
|
72
|
-
|
|
73
|
-
def get_sse_full_stream_download_url_prefix_for_agent(self, agent_id_on_server: str) -> Optional[str]:
|
|
74
|
-
"""
|
|
75
|
-
Returns the full URL prefix for HTTP stream downloads for a specific agent,
|
|
76
|
-
up to the point where stream_id should be appended.
|
|
77
|
-
e.g., http://host:port/streams/{agent_id_on_server}
|
|
78
|
-
"""
|
|
79
|
-
if self.transport_type == TransportType.SSE and self.sse_base_url:
|
|
80
|
-
base = str(self.sse_base_url).rstrip('/')
|
|
81
|
-
prefix = self.sse_stream_download_path_prefix.rstrip('/')
|
|
82
|
-
return f"{base}{prefix}/{agent_id_on_server}"
|
|
83
|
-
return None
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def __repr__(self) -> str:
|
|
87
|
-
return f"<AgentServerConfig server_id='{self.server_id}', transport='{self.transport_type.value}'>"
|
|
88
|
-
|
|
89
|
-
if __name__ == "__main__": # pragma: no cover
|
|
90
|
-
logging.basicConfig(level=logging.DEBUG)
|
|
91
|
-
|
|
92
|
-
# Stdio Example
|
|
93
|
-
try:
|
|
94
|
-
stdio_config_data = {
|
|
95
|
-
"server_id": "local_agent_stdio",
|
|
96
|
-
"transport_type": "stdio",
|
|
97
|
-
"stdio_command": ["python", "-m", "autobyteus.agent.server_main", "--config-id", "local_agent_stdio"]
|
|
98
|
-
}
|
|
99
|
-
stdio_config = AgentServerConfig(**stdio_config_data)
|
|
100
|
-
logger.info(f"Stdio Config: {stdio_config!r}")
|
|
101
|
-
logger.info(f"Stdio Config (dict): {stdio_config.model_dump_json(indent=2)}")
|
|
102
|
-
except ValueError as e:
|
|
103
|
-
logger.error(f"Error creating stdio_config: {e}")
|
|
104
|
-
|
|
105
|
-
# SSE Example
|
|
106
|
-
try:
|
|
107
|
-
sse_config_data = {
|
|
108
|
-
"server_id": "remote_agent_sse",
|
|
109
|
-
"transport_type": "sse",
|
|
110
|
-
"sse_base_url": "http://localhost:8000/agent1",
|
|
111
|
-
"sse_request_endpoint": "/api/request",
|
|
112
|
-
"sse_events_endpoint": "/api/events",
|
|
113
|
-
"sse_stream_download_path_prefix": "/downloadable_content" # Custom prefix
|
|
114
|
-
}
|
|
115
|
-
sse_config = AgentServerConfig(**sse_config_data)
|
|
116
|
-
logger.info(f"SSE Config: {sse_config!r}")
|
|
117
|
-
logger.info(f"SSE Config (dict): {sse_config.model_dump_json(indent=2)}")
|
|
118
|
-
logger.info(f"SSE Request URL: {sse_config.get_sse_full_request_url()}")
|
|
119
|
-
logger.info(f"SSE Events URL: {sse_config.get_sse_full_events_url()}")
|
|
120
|
-
logger.info(f"SSE Stream Download URL prefix for agent 'test_agent': {sse_config.get_sse_full_stream_download_url_prefix_for_agent('test_agent')}")
|
|
121
|
-
|
|
122
|
-
# Test HttpUrl string conversion
|
|
123
|
-
assert isinstance(sse_config.sse_base_url, HttpUrl)
|
|
124
|
-
logger.info(f"SSE base URL type: {type(sse_config.sse_base_url)}, value: {sse_config.sse_base_url}")
|
|
125
|
-
|
|
126
|
-
except ValueError as e:
|
|
127
|
-
logger.error(f"Error creating sse_config: {e}")
|
|
128
|
-
|
|
129
|
-
# Validation error examples
|
|
130
|
-
try:
|
|
131
|
-
invalid_stdio_data = {"server_id": "invalid_stdio", "transport_type": "stdio"} # Missing stdio_command
|
|
132
|
-
AgentServerConfig(**invalid_stdio_data)
|
|
133
|
-
except ValueError as e:
|
|
134
|
-
logger.error(f"Expected validation error (stdio): {e}")
|
|
135
|
-
|
|
136
|
-
try:
|
|
137
|
-
invalid_sse_data = {"server_id": "invalid_sse", "transport_type": "sse"} # Missing sse_base_url
|
|
138
|
-
AgentServerConfig(**invalid_sse_data)
|
|
139
|
-
except ValueError as e:
|
|
140
|
-
logger.error(f"Expected validation error (sse): {e}")
|
|
141
|
-
|
|
142
|
-
try:
|
|
143
|
-
invalid_url_sse_data = {"server_id": "invalid_url_sse", "transport_type": "sse", "sse_base_url": "not_a_url"}
|
|
144
|
-
AgentServerConfig(**invalid_url_sse_data)
|
|
145
|
-
except ValueError as e:
|
|
146
|
-
logger.error(f"Expected validation error (invalid sse_base_url): {e}")
|
|
147
|
-
|
|
148
|
-
try:
|
|
149
|
-
invalid_stream_prefix = {"server_id": "invalid_stream_prefix", "transport_type": "sse", "sse_base_url":"http://foo.com", "sse_stream_download_path_prefix": "no_slash_prefix"}
|
|
150
|
-
AgentServerConfig(**invalid_stream_prefix)
|
|
151
|
-
except ValueError as e:
|
|
152
|
-
logger.error(f"Expected validation error (invalid sse_stream_download_path_prefix): {e}")
|
|
153
|
-
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/rpc/config/agent_server_registry.py
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Dict, Optional, List
|
|
4
|
-
|
|
5
|
-
from autobyteus.utils.singleton import SingletonMeta
|
|
6
|
-
from .agent_server_config import AgentServerConfig
|
|
7
|
-
|
|
8
|
-
logger = logging.getLogger(__name__)
|
|
9
|
-
|
|
10
|
-
class AgentServerRegistry(metaclass=SingletonMeta):
|
|
11
|
-
"""
|
|
12
|
-
A singleton registry for storing and managing AgentServerConfig objects.
|
|
13
|
-
This allows different parts of the system to retrieve server connection
|
|
14
|
-
details by a server_id.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
def __init__(self):
|
|
18
|
-
"""Initializes the AgentServerRegistry with an empty store."""
|
|
19
|
-
self._configs: Dict[str, AgentServerConfig] = {}
|
|
20
|
-
logger.info("AgentServerRegistry initialized.")
|
|
21
|
-
|
|
22
|
-
def register_config(self, config: AgentServerConfig) -> None:
|
|
23
|
-
"""
|
|
24
|
-
Registers an agent server configuration.
|
|
25
|
-
If a configuration with the same server_id already exists, it will be
|
|
26
|
-
overwritten, and a warning will be logged.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
config: The AgentServerConfig object to register.
|
|
30
|
-
|
|
31
|
-
Raises:
|
|
32
|
-
TypeError: If the provided config is not an AgentServerConfig instance.
|
|
33
|
-
"""
|
|
34
|
-
if not isinstance(config, AgentServerConfig):
|
|
35
|
-
raise TypeError(f"Expected AgentServerConfig instance, got {type(config).__name__}.")
|
|
36
|
-
|
|
37
|
-
if config.server_id in self._configs:
|
|
38
|
-
logger.warning(f"Overwriting existing agent server configuration for server_id: '{config.server_id}'.")
|
|
39
|
-
|
|
40
|
-
self._configs[config.server_id] = config
|
|
41
|
-
logger.info(f"AgentServerConfig for server_id '{config.server_id}' (transport: {config.transport_type.value}) registered.")
|
|
42
|
-
|
|
43
|
-
def get_config(self, server_id: str) -> Optional[AgentServerConfig]:
|
|
44
|
-
"""
|
|
45
|
-
Retrieves an agent server configuration by its server_id.
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
server_id: The unique identifier of the server configuration.
|
|
49
|
-
|
|
50
|
-
Returns:
|
|
51
|
-
The AgentServerConfig object if found, otherwise None.
|
|
52
|
-
"""
|
|
53
|
-
if not isinstance(server_id, str):
|
|
54
|
-
logger.warning(f"Attempted to retrieve agent server config with non-string server_id: {type(server_id).__name__}.")
|
|
55
|
-
return None
|
|
56
|
-
|
|
57
|
-
config = self._configs.get(server_id)
|
|
58
|
-
if not config:
|
|
59
|
-
logger.debug(f"AgentServerConfig with server_id '{server_id}' not found in registry.")
|
|
60
|
-
return config
|
|
61
|
-
|
|
62
|
-
def unregister_config(self, server_id: str) -> bool:
|
|
63
|
-
"""
|
|
64
|
-
Removes an agent server configuration from the registry.
|
|
65
|
-
|
|
66
|
-
Args:
|
|
67
|
-
server_id: The server_id of the configuration to remove.
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
True if the configuration was found and removed, False otherwise.
|
|
71
|
-
"""
|
|
72
|
-
if not isinstance(server_id, str):
|
|
73
|
-
logger.warning(f"Attempted to unregister agent server config with non-string server_id: {type(server_id).__name__}.")
|
|
74
|
-
return False
|
|
75
|
-
|
|
76
|
-
if server_id in self._configs:
|
|
77
|
-
removed_config = self._configs.pop(server_id)
|
|
78
|
-
logger.info(f"AgentServerConfig for server_id '{removed_config.server_id}' unregistered successfully.")
|
|
79
|
-
return True
|
|
80
|
-
else:
|
|
81
|
-
logger.warning(f"AgentServerConfig with server_id '{server_id}' not found for unregistration.")
|
|
82
|
-
return False
|
|
83
|
-
|
|
84
|
-
def list_server_ids(self) -> List[str]:
|
|
85
|
-
"""Returns a list of all registered server_ids."""
|
|
86
|
-
return list(self._configs.keys())
|
|
87
|
-
|
|
88
|
-
def get_all_configs(self) -> Dict[str, AgentServerConfig]:
|
|
89
|
-
"""Returns a shallow copy of all registered configurations."""
|
|
90
|
-
return dict(self._configs)
|
|
91
|
-
|
|
92
|
-
def clear(self) -> None:
|
|
93
|
-
"""Removes all configurations from the registry."""
|
|
94
|
-
count = len(self._configs)
|
|
95
|
-
self._configs.clear()
|
|
96
|
-
logger.info(f"Cleared {count} configurations from the AgentServerRegistry.")
|
|
97
|
-
|
|
98
|
-
def __len__(self) -> int:
|
|
99
|
-
return len(self._configs)
|
|
100
|
-
|
|
101
|
-
def __contains__(self, server_id: str) -> bool:
|
|
102
|
-
if isinstance(server_id, str):
|
|
103
|
-
return server_id in self._configs
|
|
104
|
-
return False
|
|
105
|
-
|
|
106
|
-
# Default global instance of the registry
|
|
107
|
-
default_agent_server_registry = AgentServerRegistry()
|
|
108
|
-
|
|
109
|
-
if __name__ == "__main__": # pragma: no cover
|
|
110
|
-
logging.basicConfig(level=logging.DEBUG)
|
|
111
|
-
|
|
112
|
-
registry = default_agent_server_registry # Use the default instance
|
|
113
|
-
|
|
114
|
-
# Stdio Config
|
|
115
|
-
stdio_config_data = {
|
|
116
|
-
"server_id": "local_agent_stdio_main",
|
|
117
|
-
"transport_type": "stdio",
|
|
118
|
-
"stdio_command": ["python", "-m", "some_module"]
|
|
119
|
-
}
|
|
120
|
-
stdio_conf = AgentServerConfig(**stdio_config_data)
|
|
121
|
-
registry.register_config(stdio_conf)
|
|
122
|
-
|
|
123
|
-
# SSE Config
|
|
124
|
-
sse_config_data = {
|
|
125
|
-
"server_id": "remote_agent_sse_main",
|
|
126
|
-
"transport_type": "sse",
|
|
127
|
-
"sse_base_url": "http://localhost:8080"
|
|
128
|
-
}
|
|
129
|
-
sse_conf = AgentServerConfig(**sse_config_data)
|
|
130
|
-
registry.register_config(sse_conf)
|
|
131
|
-
|
|
132
|
-
logger.info(f"Registered server IDs: {registry.list_server_ids()}")
|
|
133
|
-
|
|
134
|
-
retrieved_stdio = registry.get_config("local_agent_stdio_main")
|
|
135
|
-
if retrieved_stdio:
|
|
136
|
-
logger.info(f"Retrieved Stdio Config: {retrieved_stdio.stdio_command}")
|
|
137
|
-
|
|
138
|
-
retrieved_sse = registry.get_config("remote_agent_sse_main")
|
|
139
|
-
if retrieved_sse:
|
|
140
|
-
logger.info(f"Retrieved SSE Config URL: {retrieved_sse.get_sse_full_request_url()}")
|
|
141
|
-
|
|
142
|
-
assert "local_agent_stdio_main" in registry
|
|
143
|
-
assert len(registry) == 2
|
|
144
|
-
|
|
145
|
-
registry.unregister_config("local_agent_stdio_main")
|
|
146
|
-
assert "local_agent_stdio_main" not in registry
|
|
147
|
-
logger.info(f"After unregistering, server IDs: {registry.list_server_ids()}")
|
|
148
|
-
|
|
149
|
-
registry.clear()
|
|
150
|
-
assert len(registry) == 0
|
|
151
|
-
logger.info(f"After clearing, server IDs: {registry.list_server_ids()}")
|
|
152
|
-
|