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
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from autobyteus.skills.model import Skill
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
class SkillLoader:
|
|
10
|
+
"""
|
|
11
|
+
Responsible for loading and parsing SKILL.md files.
|
|
12
|
+
Designed to be forgiving of minor formatting variations in LLM-generated content.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def load_skill(path: str) -> Skill:
|
|
17
|
+
"""
|
|
18
|
+
Loads a skill from a given directory path.
|
|
19
|
+
"""
|
|
20
|
+
if not os.path.isdir(path):
|
|
21
|
+
raise FileNotFoundError(f"Skill directory not found: {path}")
|
|
22
|
+
|
|
23
|
+
skill_file = os.path.join(path, "SKILL.md")
|
|
24
|
+
if not os.path.exists(skill_file):
|
|
25
|
+
raise FileNotFoundError(f"SKILL.md not found in {path}")
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
with open(skill_file, 'r', encoding='utf-8') as f:
|
|
29
|
+
raw_content = f.read()
|
|
30
|
+
except Exception as e:
|
|
31
|
+
raise IOError(f"Failed to read SKILL.md at {skill_file}: {e}")
|
|
32
|
+
|
|
33
|
+
return SkillLoader._parse_skill(raw_content, path)
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _parse_skill(raw_content: str, root_path: str) -> Skill:
|
|
37
|
+
"""
|
|
38
|
+
Parses the content of a SKILL.md file.
|
|
39
|
+
Extracts metadata from the frontmatter block (delimited by ---).
|
|
40
|
+
"""
|
|
41
|
+
# Extract the frontmatter block
|
|
42
|
+
# Using a regex that is forgiving of whitespace around delimiters
|
|
43
|
+
match = re.search(r'^\s*---\s*\n(.*?)\n\s*---\s*\n(.*)', raw_content, re.DOTALL | re.MULTILINE)
|
|
44
|
+
|
|
45
|
+
if not match:
|
|
46
|
+
raise ValueError("Invalid SKILL.md format: Could not find frontmatter block delimited by '---'")
|
|
47
|
+
|
|
48
|
+
frontmatter_text = match.group(1)
|
|
49
|
+
body_content = match.group(2).strip()
|
|
50
|
+
|
|
51
|
+
# Parse frontmatter lines (Key: Value)
|
|
52
|
+
metadata = {}
|
|
53
|
+
for line in frontmatter_text.splitlines():
|
|
54
|
+
if ":" in line:
|
|
55
|
+
key, value = line.split(":", 1)
|
|
56
|
+
metadata[key.strip().lower()] = value.strip()
|
|
57
|
+
|
|
58
|
+
name = metadata.get("name")
|
|
59
|
+
description = metadata.get("description")
|
|
60
|
+
|
|
61
|
+
if not name:
|
|
62
|
+
raise ValueError("Missing 'name' in SKILL.md metadata")
|
|
63
|
+
if not description:
|
|
64
|
+
raise ValueError("Missing 'description' in SKILL.md metadata")
|
|
65
|
+
|
|
66
|
+
return Skill(
|
|
67
|
+
name=name,
|
|
68
|
+
description=description,
|
|
69
|
+
content=body_content,
|
|
70
|
+
root_path=root_path
|
|
71
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
from autobyteus.utils.singleton import SingletonMeta
|
|
5
|
+
from autobyteus.skills.model import Skill
|
|
6
|
+
from autobyteus.skills.loader import SkillLoader
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
class SkillRegistry(metaclass=SingletonMeta):
|
|
11
|
+
"""
|
|
12
|
+
A singleton registry for managing and discovering agent skills.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self._skills: Dict[str, Skill] = {}
|
|
17
|
+
logger.info("SkillRegistry initialized.")
|
|
18
|
+
|
|
19
|
+
def register_skill_from_path(self, path: str) -> Skill:
|
|
20
|
+
"""
|
|
21
|
+
Loads a skill from the given path and registers it.
|
|
22
|
+
If a skill with the same name already exists, it will be overwritten.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
skill = SkillLoader.load_skill(path)
|
|
26
|
+
self._skills[skill.name] = skill
|
|
27
|
+
logger.info(f"Skill '{skill.name}' registered from path: {path}")
|
|
28
|
+
return skill
|
|
29
|
+
except Exception as e:
|
|
30
|
+
logger.error(f"Failed to register skill from path '{path}': {e}")
|
|
31
|
+
raise
|
|
32
|
+
|
|
33
|
+
def discover_skills(self, directory_path: str):
|
|
34
|
+
"""
|
|
35
|
+
Scans a directory for skill subdirectories (those containing SKILL.md)
|
|
36
|
+
and registers them.
|
|
37
|
+
"""
|
|
38
|
+
if not os.path.isdir(directory_path):
|
|
39
|
+
logger.warning(f"Discovery directory not found: {directory_path}")
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
logger.debug(f"Discovering skills in: {directory_path}")
|
|
43
|
+
for entry in os.scandir(directory_path):
|
|
44
|
+
if entry.is_dir():
|
|
45
|
+
skill_md_path = os.path.join(entry.path, "SKILL.md")
|
|
46
|
+
if os.path.exists(skill_md_path):
|
|
47
|
+
try:
|
|
48
|
+
self.register_skill_from_path(entry.path)
|
|
49
|
+
except Exception:
|
|
50
|
+
# Continue discovering other skills even if one fails
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
def get_skill(self, name: str) -> Optional[Skill]:
|
|
54
|
+
"""
|
|
55
|
+
Retrieves a skill by its name.
|
|
56
|
+
"""
|
|
57
|
+
return self._skills.get(name)
|
|
58
|
+
|
|
59
|
+
def list_skills(self) -> List[Skill]:
|
|
60
|
+
"""
|
|
61
|
+
Returns a list of all registered skills.
|
|
62
|
+
"""
|
|
63
|
+
return list(self._skills.values())
|
|
64
|
+
|
|
65
|
+
def clear(self):
|
|
66
|
+
"""
|
|
67
|
+
Clears all registered skills. Primarily for testing.
|
|
68
|
+
"""
|
|
69
|
+
self._skills.clear()
|
|
70
|
+
logger.debug("SkillRegistry cleared.")
|
|
@@ -16,11 +16,11 @@ if TYPE_CHECKING:
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
18
|
def _notify_todo_update(context: 'AgentContext'):
|
|
19
|
-
if context.
|
|
19
|
+
if context.status_manager and context.status_manager.notifier:
|
|
20
20
|
todo_list = context.state.todo_list
|
|
21
21
|
if todo_list:
|
|
22
22
|
todos_for_llm = [todo.model_dump(mode='json') for todo in todo_list.get_all_todos()]
|
|
23
|
-
context.
|
|
23
|
+
context.status_manager.notifier.notify_agent_data_todo_list_updated(todos_for_llm)
|
|
24
24
|
logger.debug(f"Agent '{context.agent_id}': Notified ToDo list update with {len(todos_for_llm)} items.")
|
|
25
25
|
|
|
26
26
|
class AddToDo(BaseTool):
|
|
@@ -17,11 +17,11 @@ if TYPE_CHECKING:
|
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
18
18
|
|
|
19
19
|
def _notify_todo_update(context: 'AgentContext'):
|
|
20
|
-
if context.
|
|
20
|
+
if context.status_manager and context.status_manager.notifier:
|
|
21
21
|
todo_list = context.state.todo_list
|
|
22
22
|
if todo_list:
|
|
23
23
|
todos_for_llm = [todo.model_dump(mode='json') for todo in todo_list.get_all_todos()]
|
|
24
|
-
context.
|
|
24
|
+
context.status_manager.notifier.notify_agent_data_todo_list_updated(todos_for_llm)
|
|
25
25
|
logger.debug(f"Agent '{context.agent_id}': Notified ToDo list update with {len(todos_for_llm)} items.")
|
|
26
26
|
|
|
27
27
|
class CreateToDoList(BaseTool):
|
|
@@ -13,11 +13,11 @@ if TYPE_CHECKING:
|
|
|
13
13
|
logger = logging.getLogger(__name__)
|
|
14
14
|
|
|
15
15
|
def _notify_todo_update(context: 'AgentContext'):
|
|
16
|
-
if context.
|
|
16
|
+
if context.status_manager and context.status_manager.notifier:
|
|
17
17
|
todo_list = context.state.todo_list
|
|
18
18
|
if todo_list:
|
|
19
19
|
todos_for_llm = [todo.model_dump(mode='json') for todo in todo_list.get_all_todos()]
|
|
20
|
-
context.
|
|
20
|
+
context.status_manager.notifier.notify_agent_data_todo_list_updated(todos_for_llm)
|
|
21
21
|
logger.debug(f"Agent '{context.agent_id}': Notified ToDo list update with {len(todos_for_llm)} items.")
|
|
22
22
|
|
|
23
23
|
class UpdateToDoStatus(BaseTool):
|
autobyteus/tools/__init__.py
CHANGED
|
@@ -15,17 +15,28 @@ from .tool_config import ToolConfig # Configuration data object, primarily for c
|
|
|
15
15
|
from .tool_origin import ToolOrigin
|
|
16
16
|
from .tool_category import ToolCategory
|
|
17
17
|
|
|
18
|
+
# Tool Formatting Registration Support
|
|
19
|
+
# Tool Formatting Registration Support
|
|
20
|
+
from autobyteus.tools.usage.registries.tool_formatting_registry import ToolFormattingRegistry, register_tool_formatter
|
|
21
|
+
from autobyteus.tools.usage.registries.tool_formatter_pair import ToolFormatterPair
|
|
22
|
+
from autobyteus.tools.usage.formatters.base_formatter import BaseSchemaFormatter, BaseExampleFormatter
|
|
23
|
+
|
|
24
|
+
|
|
18
25
|
logger = logging.getLogger(__name__)
|
|
19
26
|
|
|
20
27
|
# --- Re-export specific tools for easier access ---
|
|
21
28
|
|
|
22
29
|
# Functional tools (decorated functions are now instances)
|
|
23
|
-
from .bash.bash_executor import bash_executor
|
|
24
30
|
from .file.read_file import read_file
|
|
25
31
|
from .file.write_file import write_file
|
|
26
|
-
from .file.
|
|
27
|
-
from .
|
|
28
|
-
|
|
32
|
+
from .file.patch_file import patch_file
|
|
33
|
+
from .skill.load_skill import load_skill
|
|
34
|
+
|
|
35
|
+
# Terminal tools (PTY-based stateful terminal)
|
|
36
|
+
from .terminal.tools.run_bash import run_bash
|
|
37
|
+
from .terminal.tools.start_background_process import start_background_process
|
|
38
|
+
from .terminal.tools.get_process_output import get_process_output
|
|
39
|
+
from .terminal.tools.stop_background_process import stop_background_process
|
|
29
40
|
|
|
30
41
|
# General Class-based tools
|
|
31
42
|
try:
|
|
@@ -33,7 +44,6 @@ try:
|
|
|
33
44
|
except ModuleNotFoundError as import_err:
|
|
34
45
|
logger.warning("Search tool not available: %s", import_err)
|
|
35
46
|
Search = None
|
|
36
|
-
from .timer import Timer
|
|
37
47
|
try:
|
|
38
48
|
from .multimedia.image_tools import GenerateImageTool, EditImageTool
|
|
39
49
|
except ModuleNotFoundError as import_err:
|
|
@@ -51,33 +61,14 @@ except ModuleNotFoundError as import_err:
|
|
|
51
61
|
logger.warning("Download media tool not available: %s", import_err)
|
|
52
62
|
DownloadMediaTool = None
|
|
53
63
|
|
|
54
|
-
#
|
|
55
|
-
try:
|
|
56
|
-
from .browser.standalone.navigate_to import NavigateTo as StandaloneNavigateTo # Alias to avoid name clash
|
|
57
|
-
from .browser.standalone.webpage_reader import WebPageReader as StandaloneWebPageReader # Alias
|
|
58
|
-
from .browser.standalone.webpage_screenshot_taker import WebPageScreenshotTaker as StandaloneWebPageScreenshotTaker # Alias
|
|
59
|
-
from .browser.standalone.webpage_image_downloader import WebPageImageDownloader
|
|
60
|
-
from .browser.standalone.web_page_pdf_generator import WebPagePDFGenerator
|
|
61
|
-
except ModuleNotFoundError as import_err:
|
|
62
|
-
logger.warning('Standalone browser tools not available: %s', import_err)
|
|
63
|
-
StandaloneNavigateTo = None
|
|
64
|
-
StandaloneWebPageReader = None
|
|
65
|
-
StandaloneWebPageScreenshotTaker = None
|
|
66
|
-
WebPageImageDownloader = None
|
|
67
|
-
WebPagePDFGenerator = None
|
|
68
|
-
|
|
69
|
-
# Session-Aware Browser tools
|
|
64
|
+
# Web tools
|
|
70
65
|
try:
|
|
71
|
-
from .
|
|
72
|
-
from .browser.session_aware.browser_session_aware_web_element_trigger import BrowserSessionAwareWebElementTrigger
|
|
73
|
-
from .browser.session_aware.browser_session_aware_webpage_reader import BrowserSessionAwareWebPageReader
|
|
74
|
-
from .browser.session_aware.browser_session_aware_webpage_screenshot_taker import BrowserSessionAwareWebPageScreenshotTaker
|
|
66
|
+
from .web.read_url_tool import ReadUrl
|
|
75
67
|
except ModuleNotFoundError as import_err:
|
|
76
|
-
logger.warning(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
BrowserSessionAwareWebPageScreenshotTaker = None
|
|
68
|
+
logger.warning("ReadUrl tool not available: %s", import_err)
|
|
69
|
+
ReadUrl = None
|
|
70
|
+
|
|
71
|
+
|
|
81
72
|
|
|
82
73
|
|
|
83
74
|
__all__ = [
|
|
@@ -92,31 +83,27 @@ __all__ = [
|
|
|
92
83
|
"ToolCategory",
|
|
93
84
|
|
|
94
85
|
# Re-exported functional tool instances
|
|
95
|
-
"
|
|
86
|
+
"run_bash",
|
|
87
|
+
"start_background_process",
|
|
88
|
+
"get_process_output",
|
|
89
|
+
"stop_background_process",
|
|
96
90
|
"read_file",
|
|
97
91
|
"write_file",
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"list_directory",
|
|
92
|
+
"patch_file",
|
|
93
|
+
"load_skill",
|
|
101
94
|
|
|
102
95
|
# Re-exported general class-based tools
|
|
103
96
|
"Search",
|
|
104
|
-
"Timer",
|
|
105
97
|
"GenerateImageTool",
|
|
106
98
|
"EditImageTool",
|
|
107
99
|
"ReadMediaFile",
|
|
108
100
|
"DownloadMediaTool",
|
|
109
101
|
|
|
110
|
-
# Re-exported
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
# Re-exported Session-Aware Browser tools
|
|
118
|
-
"BrowserSessionAwareNavigateTo",
|
|
119
|
-
"BrowserSessionAwareWebElementTrigger",
|
|
120
|
-
"BrowserSessionAwareWebPageReader",
|
|
121
|
-
"BrowserSessionAwareWebPageScreenshotTaker",
|
|
102
|
+
# Re-exported Web tools
|
|
103
|
+
"ReadUrl",
|
|
104
|
+
|
|
105
|
+
# Tool Formatting
|
|
106
|
+
"register_tool_formatter",
|
|
107
|
+
"BaseSchemaFormatter",
|
|
108
|
+
"BaseExampleFormatter",
|
|
122
109
|
]
|
autobyteus/tools/base_tool.py
CHANGED
|
@@ -174,6 +174,13 @@ class BaseTool(ABC, EventEmitter, metaclass=ToolMeta):
|
|
|
174
174
|
async def _execute(self, context: 'AgentContext', **kwargs) -> Any:
|
|
175
175
|
raise NotImplementedError("Subclasses must implement the '_execute' method.")
|
|
176
176
|
|
|
177
|
+
async def cleanup(self) -> None:
|
|
178
|
+
"""
|
|
179
|
+
Lifecycle hook invoked during agent shutdown to release resources held by the tool.
|
|
180
|
+
Default implementation is a no-op.
|
|
181
|
+
"""
|
|
182
|
+
return None
|
|
183
|
+
|
|
177
184
|
@classmethod
|
|
178
185
|
def tool_usage(cls) -> str:
|
|
179
186
|
logger.warning("BaseTool.tool_usage() is deprecated. Tool usage is now generated by formatters.")
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from .patch_file import patch_file
|
|
2
2
|
from .read_file import read_file
|
|
3
3
|
from .write_file import write_file
|
|
4
|
-
from .search_files import search_files
|
|
5
|
-
from .list_directory import list_directory
|
|
6
4
|
|
|
7
5
|
__all__ = [
|
|
8
|
-
"
|
|
6
|
+
"patch_file",
|
|
9
7
|
"read_file",
|
|
10
8
|
"write_file",
|
|
11
|
-
"search_files",
|
|
12
|
-
"list_directory",
|
|
13
9
|
]
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, List
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from autobyteus.tools.functional_tool import tool
|
|
8
|
+
from autobyteus.tools.tool_category import ToolCategory
|
|
9
|
+
from autobyteus.utils.diff_utils import apply_unified_diff, PatchApplicationError
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from autobyteus.agent.context import AgentContext
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _resolve_file_path(context: 'AgentContext', path: str) -> str:
|
|
18
|
+
"""Resolves an absolute path for the given input, using the agent workspace when needed."""
|
|
19
|
+
if os.path.isabs(path):
|
|
20
|
+
final_path = path
|
|
21
|
+
logger.debug("patch_file: provided path '%s' is absolute.", path)
|
|
22
|
+
else:
|
|
23
|
+
if not context.workspace:
|
|
24
|
+
error_msg = ("Relative path '%s' provided, but no workspace is configured for agent '%s'. "
|
|
25
|
+
"A workspace is required to resolve relative paths.")
|
|
26
|
+
logger.error(error_msg, path, context.agent_id)
|
|
27
|
+
raise ValueError(error_msg % (path, context.agent_id))
|
|
28
|
+
base_path = context.workspace.get_base_path()
|
|
29
|
+
if not base_path or not isinstance(base_path, str):
|
|
30
|
+
error_msg = ("Agent '%s' has a configured workspace, but it provided an invalid base path ('%s'). "
|
|
31
|
+
"Cannot resolve relative path '%s'.")
|
|
32
|
+
logger.error(error_msg, context.agent_id, base_path, path)
|
|
33
|
+
raise ValueError(error_msg % (context.agent_id, base_path, path))
|
|
34
|
+
final_path = os.path.join(base_path, path)
|
|
35
|
+
logger.debug("patch_file: resolved relative path '%s' against workspace base '%s' to '%s'.", path, base_path, final_path)
|
|
36
|
+
|
|
37
|
+
normalized_path = os.path.normpath(final_path)
|
|
38
|
+
logger.debug("patch_file: normalized path to '%s'.", normalized_path)
|
|
39
|
+
return normalized_path
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@tool(name="patch_file", category=ToolCategory.FILE_SYSTEM)
|
|
43
|
+
async def patch_file(
|
|
44
|
+
context: 'AgentContext',
|
|
45
|
+
path: str = Field(..., description="Path to the target file."),
|
|
46
|
+
patch: str = Field(
|
|
47
|
+
...,
|
|
48
|
+
description=(
|
|
49
|
+
"Unified diff hunks describing edits to apply. "
|
|
50
|
+
"Example:\n"
|
|
51
|
+
"--- a/sample.txt\n"
|
|
52
|
+
"+++ b/sample.txt\n"
|
|
53
|
+
"@@ -1,2 +1,2 @@\n"
|
|
54
|
+
"-old line\n"
|
|
55
|
+
"+new line\n"
|
|
56
|
+
" unchanged line"
|
|
57
|
+
),
|
|
58
|
+
),
|
|
59
|
+
) -> str:
|
|
60
|
+
"""Applies a unified diff patch to update a text file without overwriting unrelated content.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
path: Path to the target file. Relative paths are resolved against the agent workspace when available.
|
|
64
|
+
patch: Unified diff patch describing the edits to apply.
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
FileNotFoundError: If the file does not exist.
|
|
68
|
+
PatchApplicationError: If the patch content cannot be applied cleanly.
|
|
69
|
+
IOError: If file reading or writing fails.
|
|
70
|
+
"""
|
|
71
|
+
logger.debug("patch_file: requested patch for agent '%s' on path '%s'.", context.agent_id, path)
|
|
72
|
+
return_path = os.path.normpath(path)
|
|
73
|
+
|
|
74
|
+
# Detailed logging for debugging patch content
|
|
75
|
+
logger.info("patch_file: ===== PATCH ARGUMENT DEBUG START =====")
|
|
76
|
+
logger.info("patch_file: raw patch repr: %r", patch)
|
|
77
|
+
logger.info("patch_file: patch length: %d chars", len(patch) if patch else 0)
|
|
78
|
+
patch_lines = patch.splitlines(keepends=True) if patch else []
|
|
79
|
+
for i, line in enumerate(patch_lines, 1):
|
|
80
|
+
prefix = line[0] if line else '<empty>'
|
|
81
|
+
logger.info("patch_file: line %d: prefix=%r content=%r", i, prefix, line)
|
|
82
|
+
logger.info("patch_file: ===== PATCH ARGUMENT DEBUG END =====")
|
|
83
|
+
|
|
84
|
+
final_path = _resolve_file_path(context, path)
|
|
85
|
+
|
|
86
|
+
file_exists = os.path.exists(final_path)
|
|
87
|
+
if not file_exists:
|
|
88
|
+
raise FileNotFoundError(f"The file at resolved path {final_path} does not exist.")
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
original_lines: List[str]
|
|
92
|
+
if file_exists:
|
|
93
|
+
with open(final_path, 'r', encoding='utf-8') as source:
|
|
94
|
+
original_lines = source.read().splitlines(keepends=True)
|
|
95
|
+
else:
|
|
96
|
+
original_lines = []
|
|
97
|
+
|
|
98
|
+
# Log original file content for comparison
|
|
99
|
+
logger.info("patch_file: ===== ORIGINAL FILE DEBUG START =====")
|
|
100
|
+
for i, line in enumerate(original_lines, 1):
|
|
101
|
+
logger.info("patch_file: original line %d: %r", i, line)
|
|
102
|
+
logger.info("patch_file: ===== ORIGINAL FILE DEBUG END =====")
|
|
103
|
+
|
|
104
|
+
patched_lines = None
|
|
105
|
+
patch_error = None
|
|
106
|
+
retry_strategies = [
|
|
107
|
+
(0, False),
|
|
108
|
+
(1, False),
|
|
109
|
+
(1, True),
|
|
110
|
+
(2, True),
|
|
111
|
+
]
|
|
112
|
+
for fuzz_factor, ignore_whitespace in retry_strategies:
|
|
113
|
+
try:
|
|
114
|
+
patched_lines = apply_unified_diff(
|
|
115
|
+
original_lines,
|
|
116
|
+
patch,
|
|
117
|
+
fuzz_factor=fuzz_factor,
|
|
118
|
+
ignore_whitespace=ignore_whitespace,
|
|
119
|
+
)
|
|
120
|
+
if (fuzz_factor, ignore_whitespace) != (0, False):
|
|
121
|
+
logger.info(
|
|
122
|
+
"patch_file: applied with fuzz=%d ignore_whitespace=%s.",
|
|
123
|
+
fuzz_factor,
|
|
124
|
+
ignore_whitespace,
|
|
125
|
+
)
|
|
126
|
+
break
|
|
127
|
+
except PatchApplicationError as patch_err:
|
|
128
|
+
patch_error = patch_err
|
|
129
|
+
logger.warning(
|
|
130
|
+
"patch_file: patch failed with fuzz=%d ignore_whitespace=%s: %s",
|
|
131
|
+
fuzz_factor,
|
|
132
|
+
ignore_whitespace,
|
|
133
|
+
patch_err,
|
|
134
|
+
)
|
|
135
|
+
continue
|
|
136
|
+
if patched_lines is None:
|
|
137
|
+
raise patch_error or PatchApplicationError("Patch could not be applied.")
|
|
138
|
+
|
|
139
|
+
with open(final_path, 'w', encoding='utf-8') as destination:
|
|
140
|
+
destination.writelines(patched_lines)
|
|
141
|
+
|
|
142
|
+
logger.info("patch_file: successfully applied patch to '%s'.", final_path)
|
|
143
|
+
return f"File patched successfully at {return_path}"
|
|
144
|
+
except PatchApplicationError as patch_err:
|
|
145
|
+
logger.error("patch_file: failed to apply patch to '%s': %s", final_path, patch_err, exc_info=True)
|
|
146
|
+
raise patch_err
|
|
147
|
+
except Exception as exc: # pragma: no cover - general safeguard
|
|
148
|
+
logger.error("patch_file: unexpected error while patching '%s': %s", final_path, exc, exc_info=True)
|
|
149
|
+
raise IOError(f"Could not patch file at '{final_path}': {exc}")
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import logging
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
4
6
|
|
|
5
7
|
from autobyteus.tools import tool
|
|
6
8
|
from autobyteus.tools.tool_category import ToolCategory
|
|
@@ -11,15 +13,32 @@ if TYPE_CHECKING:
|
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
12
14
|
|
|
13
15
|
@tool(name="read_file", category=ToolCategory.FILE_SYSTEM)
|
|
14
|
-
async def read_file(
|
|
16
|
+
async def read_file(
|
|
17
|
+
context: 'AgentContext',
|
|
18
|
+
path: str,
|
|
19
|
+
start_line: Optional[int] = None,
|
|
20
|
+
end_line: Optional[int] = None,
|
|
21
|
+
include_line_numbers: bool = Field(
|
|
22
|
+
True,
|
|
23
|
+
description="If true, prefix each returned line with its line number (default).",
|
|
24
|
+
),
|
|
25
|
+
) -> str:
|
|
15
26
|
"""
|
|
16
|
-
Reads content from a specified file.
|
|
27
|
+
Reads content from a specified file. Supports optional 1-based inclusive line ranges via start_line/end_line.
|
|
28
|
+
Each returned line is prefixed with its line number when include_line_numbers is true.
|
|
17
29
|
'path' is the path to the file. If relative, it must be resolved against a configured agent workspace.
|
|
18
|
-
Raises ValueError if a relative path is given without a valid workspace.
|
|
30
|
+
Raises ValueError if a relative path is given without a valid workspace or if line range arguments are invalid.
|
|
19
31
|
Raises FileNotFoundError if the file does not exist.
|
|
20
32
|
Raises IOError if file reading fails for other reasons.
|
|
21
33
|
"""
|
|
22
34
|
logger.debug(f"Functional read_file tool for agent {context.agent_id}, initial path: {path}")
|
|
35
|
+
|
|
36
|
+
if start_line is not None and start_line < 1:
|
|
37
|
+
raise ValueError(f"start_line must be >= 1 when provided; got {start_line}.")
|
|
38
|
+
if end_line is not None and end_line < 1:
|
|
39
|
+
raise ValueError(f"end_line must be >= 1 when provided; got {end_line}.")
|
|
40
|
+
if start_line is not None and end_line is not None and end_line < start_line:
|
|
41
|
+
raise ValueError(f"end_line ({end_line}) must be >= start_line ({start_line}).")
|
|
23
42
|
|
|
24
43
|
final_path: str
|
|
25
44
|
if os.path.isabs(path):
|
|
@@ -48,7 +67,19 @@ async def read_file(context: 'AgentContext', path: str) -> str:
|
|
|
48
67
|
|
|
49
68
|
try:
|
|
50
69
|
with open(final_path, 'r', encoding='utf-8') as file:
|
|
51
|
-
|
|
70
|
+
selected_lines = []
|
|
71
|
+
for line_no, line in enumerate(file, start=1):
|
|
72
|
+
if start_line is not None and line_no < start_line:
|
|
73
|
+
continue
|
|
74
|
+
if end_line is not None and line_no > end_line:
|
|
75
|
+
break
|
|
76
|
+
if include_line_numbers:
|
|
77
|
+
line_text = line.rstrip('\n')
|
|
78
|
+
line_suffix = '\n' if line.endswith('\n') else ''
|
|
79
|
+
selected_lines.append(f"{line_no}: {line_text}{line_suffix}")
|
|
80
|
+
else:
|
|
81
|
+
selected_lines.append(line)
|
|
82
|
+
content = ''.join(selected_lines)
|
|
52
83
|
logger.info(f"File successfully read from '{final_path}' for agent '{context.agent_id}'.")
|
|
53
84
|
return content
|
|
54
85
|
except Exception as e:
|
|
@@ -23,8 +23,10 @@ async def write_file(context: 'AgentContext', path: str, content: str) -> str:
|
|
|
23
23
|
logger.debug(f"Functional write_file tool for agent {context.agent_id}, initial path: {path}")
|
|
24
24
|
|
|
25
25
|
final_path: str
|
|
26
|
+
return_path: str
|
|
26
27
|
if os.path.isabs(path):
|
|
27
28
|
final_path = path
|
|
29
|
+
return_path = final_path
|
|
28
30
|
logger.debug(f"Path '{path}' is absolute. Using it directly.")
|
|
29
31
|
else:
|
|
30
32
|
if not context.workspace:
|
|
@@ -39,6 +41,7 @@ async def write_file(context: 'AgentContext', path: str, content: str) -> str:
|
|
|
39
41
|
raise ValueError(error_msg)
|
|
40
42
|
|
|
41
43
|
final_path = os.path.join(base_path, path)
|
|
44
|
+
return_path = os.path.normpath(path)
|
|
42
45
|
logger.debug(f"Path '{path}' is relative. Resolved to '{final_path}' using workspace base path '{base_path}'.")
|
|
43
46
|
|
|
44
47
|
try:
|
|
@@ -53,7 +56,7 @@ async def write_file(context: 'AgentContext', path: str, content: str) -> str:
|
|
|
53
56
|
file.write(content)
|
|
54
57
|
|
|
55
58
|
logger.info(f"File successfully written to '{final_path}' for agent '{context.agent_id}'.")
|
|
56
|
-
return f"File created/updated at {
|
|
59
|
+
return f"File created/updated at {return_path}"
|
|
57
60
|
except Exception as e:
|
|
58
61
|
logger.error(f"Error writing file to final path '{final_path}' for agent {context.agent_id}: {e}", exc_info=True)
|
|
59
62
|
raise IOError(f"Could not write file at '{final_path}': {str(e)}")
|