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
autobyteus/cli/cli_display.py
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
3
|
import sys
|
|
4
|
-
from typing import Optional
|
|
4
|
+
from typing import Optional
|
|
5
5
|
import json
|
|
6
6
|
|
|
7
|
-
from autobyteus.agent.
|
|
7
|
+
from autobyteus.agent.status.status_enum import AgentStatus
|
|
8
8
|
from autobyteus.agent.streaming.stream_events import StreamEvent, StreamEventType
|
|
9
9
|
from autobyteus.agent.streaming.stream_event_payloads import (
|
|
10
10
|
AssistantChunkData,
|
|
11
11
|
AssistantCompleteResponseData,
|
|
12
12
|
ToolInvocationApprovalRequestedData,
|
|
13
13
|
ToolInteractionLogEntryData,
|
|
14
|
-
|
|
14
|
+
AgentStatusUpdateData,
|
|
15
15
|
ErrorEventData,
|
|
16
16
|
ToolInvocationAutoExecutingData,
|
|
17
|
+
SegmentEventData,
|
|
17
18
|
)
|
|
19
|
+
from autobyteus.agent.streaming.parser.events import SegmentEventType, SegmentType
|
|
18
20
|
|
|
19
21
|
logger = logging.getLogger(__name__)
|
|
20
22
|
|
|
@@ -30,14 +32,21 @@ class InteractiveCLIDisplay:
|
|
|
30
32
|
self.current_line_empty = True
|
|
31
33
|
self.agent_has_spoken_this_turn = False
|
|
32
34
|
self.pending_approval_data: Optional[ToolInvocationApprovalRequestedData] = None
|
|
35
|
+
self.approval_prompt_shown: bool = False
|
|
36
|
+
self.current_status: Optional[AgentStatus] = None
|
|
37
|
+
self.awaiting_approval: bool = False
|
|
33
38
|
self.is_thinking = False
|
|
34
39
|
self.is_in_content_block = False
|
|
40
|
+
self._segment_types_by_id = {}
|
|
41
|
+
self._saw_segment_event = False
|
|
35
42
|
|
|
36
43
|
def reset_turn_state(self):
|
|
37
44
|
"""Resets flags that are tracked on a per-turn basis."""
|
|
38
45
|
self._end_thinking_block()
|
|
39
46
|
self.agent_has_spoken_this_turn = False
|
|
40
47
|
self.is_in_content_block = False
|
|
48
|
+
self._segment_types_by_id.clear()
|
|
49
|
+
self._saw_segment_event = False
|
|
41
50
|
|
|
42
51
|
def _ensure_new_line(self):
|
|
43
52
|
"""Ensures the cursor is on a new line if the current one isn't empty."""
|
|
@@ -54,10 +63,148 @@ class InteractiveCLIDisplay:
|
|
|
54
63
|
self.is_thinking = False
|
|
55
64
|
self.current_line_empty = False
|
|
56
65
|
|
|
57
|
-
def
|
|
58
|
-
"""
|
|
59
|
-
if not self.
|
|
66
|
+
def _ensure_agent_prefix(self):
|
|
67
|
+
"""Prints the Agent prefix once per turn."""
|
|
68
|
+
if not self.agent_has_spoken_this_turn:
|
|
69
|
+
self._ensure_new_line()
|
|
70
|
+
sys.stdout.write("Agent:\n")
|
|
71
|
+
sys.stdout.flush()
|
|
72
|
+
self.agent_has_spoken_this_turn = True
|
|
73
|
+
self.current_line_empty = True
|
|
74
|
+
|
|
75
|
+
def _handle_segment_event(self, segment_event: SegmentEventData):
|
|
76
|
+
"""Render segment events emitted by the streaming parser."""
|
|
77
|
+
try:
|
|
78
|
+
event_type = SegmentEventType(segment_event.event_type)
|
|
79
|
+
except ValueError:
|
|
80
|
+
logger.debug(f"CLI Display: Unknown segment event type '{segment_event.event_type}'.")
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
self._saw_segment_event = True
|
|
84
|
+
|
|
85
|
+
segment_type = None
|
|
86
|
+
if segment_event.segment_type:
|
|
87
|
+
try:
|
|
88
|
+
segment_type = SegmentType(segment_event.segment_type)
|
|
89
|
+
except ValueError:
|
|
90
|
+
logger.debug(f"CLI Display: Unknown segment type '{segment_event.segment_type}'.")
|
|
91
|
+
|
|
92
|
+
if segment_type is None and segment_event.segment_id in self._segment_types_by_id:
|
|
93
|
+
segment_type = self._segment_types_by_id.get(segment_event.segment_id)
|
|
94
|
+
|
|
95
|
+
metadata = {}
|
|
96
|
+
if isinstance(segment_event.payload, dict):
|
|
97
|
+
metadata = segment_event.payload.get("metadata", {}) or {}
|
|
98
|
+
|
|
99
|
+
if event_type == SegmentEventType.START:
|
|
100
|
+
if segment_type is not None:
|
|
101
|
+
self._segment_types_by_id[segment_event.segment_id] = segment_type
|
|
102
|
+
|
|
103
|
+
if segment_type != SegmentType.REASONING:
|
|
104
|
+
self._end_thinking_block()
|
|
105
|
+
|
|
106
|
+
self._ensure_agent_prefix()
|
|
107
|
+
|
|
108
|
+
if segment_type == SegmentType.REASONING:
|
|
109
|
+
if not self.is_thinking:
|
|
110
|
+
sys.stdout.write("<Thinking>\n")
|
|
111
|
+
sys.stdout.flush()
|
|
112
|
+
self.is_thinking = True
|
|
113
|
+
self.current_line_empty = True
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
if segment_type == SegmentType.WRITE_FILE:
|
|
117
|
+
path = metadata.get("path", "")
|
|
118
|
+
header = f"<write_file path=\"{path}\">" if path else "<write_file>"
|
|
119
|
+
sys.stdout.write(f"{header}\n")
|
|
120
|
+
sys.stdout.flush()
|
|
121
|
+
self.current_line_empty = True
|
|
122
|
+
self.is_in_content_block = True
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
if segment_type == SegmentType.RUN_BASH:
|
|
126
|
+
sys.stdout.write("<run_bash>\n")
|
|
127
|
+
sys.stdout.flush()
|
|
128
|
+
self.current_line_empty = True
|
|
129
|
+
self.is_in_content_block = True
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
if segment_type == SegmentType.TOOL_CALL:
|
|
133
|
+
tool_name = metadata.get("tool_name", "")
|
|
134
|
+
header = f"<tool name=\"{tool_name}\">" if tool_name else "<tool>"
|
|
135
|
+
sys.stdout.write(f"{header}\n")
|
|
136
|
+
sys.stdout.flush()
|
|
137
|
+
self.current_line_empty = True
|
|
138
|
+
self.is_in_content_block = True
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
# Text segment start does not need a visible marker.
|
|
142
|
+
self.is_in_content_block = True
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
if event_type == SegmentEventType.CONTENT:
|
|
146
|
+
if segment_type == SegmentType.REASONING:
|
|
147
|
+
if not self.is_thinking:
|
|
148
|
+
self._ensure_agent_prefix()
|
|
149
|
+
sys.stdout.write("<Thinking>\n")
|
|
150
|
+
sys.stdout.flush()
|
|
151
|
+
self.is_thinking = True
|
|
152
|
+
delta = segment_event.payload.get("delta", "")
|
|
153
|
+
sys.stdout.write(str(delta))
|
|
154
|
+
sys.stdout.flush()
|
|
155
|
+
self.current_line_empty = str(delta).endswith("\n")
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
delta = segment_event.payload.get("delta", "")
|
|
159
|
+
if delta:
|
|
160
|
+
self._ensure_agent_prefix()
|
|
161
|
+
sys.stdout.write(str(delta))
|
|
162
|
+
sys.stdout.flush()
|
|
163
|
+
self.current_line_empty = str(delta).endswith("\n")
|
|
164
|
+
self.is_in_content_block = True
|
|
60
165
|
return
|
|
166
|
+
|
|
167
|
+
if event_type == SegmentEventType.END:
|
|
168
|
+
if segment_type == SegmentType.REASONING:
|
|
169
|
+
self._end_thinking_block()
|
|
170
|
+
self._segment_types_by_id.pop(segment_event.segment_id, None)
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
if segment_type == SegmentType.WRITE_FILE:
|
|
174
|
+
sys.stdout.write("\n</write_file>\n")
|
|
175
|
+
sys.stdout.flush()
|
|
176
|
+
self.current_line_empty = True
|
|
177
|
+
self.is_in_content_block = False
|
|
178
|
+
self._segment_types_by_id.pop(segment_event.segment_id, None)
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
if segment_type == SegmentType.RUN_BASH:
|
|
182
|
+
sys.stdout.write("\n</run_bash>\n")
|
|
183
|
+
sys.stdout.flush()
|
|
184
|
+
self.current_line_empty = True
|
|
185
|
+
self.is_in_content_block = False
|
|
186
|
+
self._segment_types_by_id.pop(segment_event.segment_id, None)
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
if segment_type == SegmentType.TOOL_CALL:
|
|
190
|
+
sys.stdout.write("\n</tool>\n")
|
|
191
|
+
sys.stdout.flush()
|
|
192
|
+
self.current_line_empty = True
|
|
193
|
+
self.is_in_content_block = False
|
|
194
|
+
self._segment_types_by_id.pop(segment_event.segment_id, None)
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
if segment_type == SegmentType.TEXT:
|
|
198
|
+
self.is_in_content_block = False
|
|
199
|
+
self._segment_types_by_id.pop(segment_event.segment_id, None)
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
self._segment_types_by_id.pop(segment_event.segment_id, None)
|
|
203
|
+
|
|
204
|
+
def get_approval_prompt(self) -> Optional[str]:
|
|
205
|
+
"""Returns the tool approval prompt string using stored pending data."""
|
|
206
|
+
if not self.pending_approval_data:
|
|
207
|
+
return None
|
|
61
208
|
|
|
62
209
|
try:
|
|
63
210
|
args_str = json.dumps(self.pending_approval_data.arguments, indent=2)
|
|
@@ -69,31 +216,17 @@ class InteractiveCLIDisplay:
|
|
|
69
216
|
f"Tool Call: '{self.pending_approval_data.tool_name}' requests permission to run with arguments:\n"
|
|
70
217
|
f"{args_str}\nApprove? (y/n): "
|
|
71
218
|
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
219
|
+
return prompt_message
|
|
220
|
+
|
|
221
|
+
def clear_pending_approval(self):
|
|
222
|
+
self.pending_approval_data = None
|
|
223
|
+
self.approval_prompt_shown = False
|
|
75
224
|
|
|
76
225
|
async def handle_stream_event(self, event: StreamEvent):
|
|
77
226
|
"""Processes a single StreamEvent and updates the CLI display."""
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
isinstance(event.data, AssistantChunkData) and
|
|
82
|
-
bool(event.data.reasoning) and not bool(event.data.content)
|
|
83
|
-
)
|
|
84
|
-
if not is_reasoning_only_chunk:
|
|
85
|
-
self._end_thinking_block()
|
|
86
|
-
|
|
87
|
-
# Most events should start on a new line.
|
|
88
|
-
if event.event_type != StreamEventType.ASSISTANT_CHUNK:
|
|
89
|
-
self._ensure_new_line()
|
|
90
|
-
|
|
91
|
-
if event.event_type in [
|
|
92
|
-
StreamEventType.AGENT_IDLE,
|
|
93
|
-
StreamEventType.ERROR_EVENT,
|
|
94
|
-
StreamEventType.TOOL_INVOCATION_APPROVAL_REQUESTED,
|
|
95
|
-
]:
|
|
96
|
-
self.agent_turn_complete_event.set()
|
|
227
|
+
if event.event_type == StreamEventType.SEGMENT_EVENT and isinstance(event.data, SegmentEventData):
|
|
228
|
+
self._handle_segment_event(event.data)
|
|
229
|
+
return
|
|
97
230
|
|
|
98
231
|
if event.event_type == StreamEventType.ASSISTANT_CHUNK and isinstance(event.data, AssistantChunkData):
|
|
99
232
|
# If this is the first output from the agent this turn, print the "Agent: " prefix.
|
|
@@ -110,7 +243,7 @@ class InteractiveCLIDisplay:
|
|
|
110
243
|
sys.stdout.write("<Thinking>\n")
|
|
111
244
|
sys.stdout.flush()
|
|
112
245
|
self.is_thinking = True
|
|
113
|
-
self.current_line_empty = True
|
|
246
|
+
self.current_line_empty = True
|
|
114
247
|
|
|
115
248
|
sys.stdout.write(event.data.reasoning)
|
|
116
249
|
sys.stdout.flush()
|
|
@@ -119,7 +252,7 @@ class InteractiveCLIDisplay:
|
|
|
119
252
|
# Stream content to stdout.
|
|
120
253
|
if event.data.content:
|
|
121
254
|
if not self.is_in_content_block:
|
|
122
|
-
self._ensure_new_line()
|
|
255
|
+
self._ensure_new_line()
|
|
123
256
|
self.is_in_content_block = True
|
|
124
257
|
sys.stdout.write(event.data.content)
|
|
125
258
|
sys.stdout.flush()
|
|
@@ -132,11 +265,15 @@ class InteractiveCLIDisplay:
|
|
|
132
265
|
f"[Token Usage: Prompt={usage.prompt_tokens}, "
|
|
133
266
|
f"Completion={usage.completion_tokens}, Total={usage.total_tokens}]"
|
|
134
267
|
)
|
|
268
|
+
return
|
|
135
269
|
|
|
136
|
-
|
|
270
|
+
self._end_thinking_block()
|
|
271
|
+
self._ensure_new_line()
|
|
272
|
+
|
|
273
|
+
if event.event_type == StreamEventType.ASSISTANT_COMPLETE_RESPONSE and isinstance(event.data, AssistantCompleteResponseData):
|
|
137
274
|
# The reasoning has already been streamed. Do not log it again.
|
|
138
275
|
|
|
139
|
-
if not self.agent_has_spoken_this_turn:
|
|
276
|
+
if not self._saw_segment_event and not self.agent_has_spoken_this_turn:
|
|
140
277
|
# This case handles responses that might not have streamed any content chunks (e.g., only a tool call).
|
|
141
278
|
# We still need to ensure the agent's turn is visibly terminated with a newline.
|
|
142
279
|
self._ensure_new_line()
|
|
@@ -159,7 +296,8 @@ class InteractiveCLIDisplay:
|
|
|
159
296
|
|
|
160
297
|
elif event.event_type == StreamEventType.TOOL_INVOCATION_APPROVAL_REQUESTED and isinstance(event.data, ToolInvocationApprovalRequestedData):
|
|
161
298
|
self.pending_approval_data = event.data
|
|
162
|
-
self.
|
|
299
|
+
if self.awaiting_approval or self.current_status == AgentStatus.AWAITING_TOOL_APPROVAL:
|
|
300
|
+
self.agent_turn_complete_event.set()
|
|
163
301
|
|
|
164
302
|
elif event.event_type == StreamEventType.TOOL_INVOCATION_AUTO_EXECUTING and isinstance(event.data, ToolInvocationAutoExecutingData):
|
|
165
303
|
tool_name = event.data.tool_name
|
|
@@ -175,30 +313,41 @@ class InteractiveCLIDisplay:
|
|
|
175
313
|
f"[Tool Log ({event.data.tool_name} | {event.data.tool_invocation_id})]: {event.data.log_entry}"
|
|
176
314
|
)
|
|
177
315
|
|
|
178
|
-
elif event.event_type == StreamEventType.
|
|
179
|
-
|
|
316
|
+
elif event.event_type == StreamEventType.AGENT_STATUS_UPDATED and isinstance(event.data, AgentStatusUpdateData):
|
|
317
|
+
self.current_status = event.data.new_status
|
|
318
|
+
if event.data.new_status == AgentStatus.AWAITING_TOOL_APPROVAL:
|
|
319
|
+
self.awaiting_approval = True
|
|
320
|
+
if self.pending_approval_data:
|
|
321
|
+
self.agent_turn_complete_event.set()
|
|
322
|
+
else:
|
|
323
|
+
self.awaiting_approval = False
|
|
324
|
+
|
|
325
|
+
if event.data.new_status in {AgentStatus.IDLE, AgentStatus.ERROR}:
|
|
326
|
+
self.agent_turn_complete_event.set()
|
|
327
|
+
|
|
328
|
+
if event.data.new_status == AgentStatus.EXECUTING_TOOL:
|
|
180
329
|
tool_name = event.data.tool_name or "a tool"
|
|
181
330
|
sys.stdout.write(f"Agent: Waiting for tool '{tool_name}' to complete...\n")
|
|
182
331
|
sys.stdout.flush()
|
|
183
332
|
self.current_line_empty = True
|
|
184
333
|
self.agent_has_spoken_this_turn = True
|
|
185
|
-
elif event.data.
|
|
334
|
+
elif event.data.new_status == AgentStatus.IDLE:
|
|
335
|
+
logger.info("[Agent is now idle.]")
|
|
336
|
+
elif event.data.new_status == AgentStatus.BOOTSTRAPPING:
|
|
186
337
|
logger.info("[Agent is initializing...]")
|
|
187
|
-
elif event.data.
|
|
338
|
+
elif event.data.new_status == AgentStatus.TOOL_DENIED:
|
|
188
339
|
tool_name = event.data.tool_name or "a tool"
|
|
189
340
|
logger.info(f"[Tool '{tool_name}' was denied by user. Agent is reconsidering.]")
|
|
190
341
|
else:
|
|
191
|
-
|
|
342
|
+
status_msg = f"[Agent Status: {event.data.new_status.value}"
|
|
192
343
|
if event.data.tool_name:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
logger.info(
|
|
344
|
+
status_msg += f" ({event.data.tool_name})"
|
|
345
|
+
status_msg += "]"
|
|
346
|
+
logger.info(status_msg)
|
|
196
347
|
|
|
197
348
|
elif event.event_type == StreamEventType.ERROR_EVENT and isinstance(event.data, ErrorEventData):
|
|
198
349
|
logger.error(f"[Error: {event.data.message} (Source: {event.data.source})]")
|
|
199
|
-
|
|
200
|
-
elif event.event_type == StreamEventType.AGENT_IDLE:
|
|
201
|
-
logger.info("[Agent is now idle.]")
|
|
350
|
+
self.agent_turn_complete_event.set()
|
|
202
351
|
|
|
203
352
|
else:
|
|
204
353
|
# Add logging for unhandled events for better debugging
|
|
@@ -16,8 +16,7 @@ from autobyteus.workflow.agentic_workflow import AgenticWorkflow
|
|
|
16
16
|
from autobyteus.workflow.streaming.workflow_event_stream import WorkflowEventStream
|
|
17
17
|
from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
|
|
18
18
|
from autobyteus.agent.streaming.stream_events import StreamEventType as AgentStreamEventType
|
|
19
|
-
from autobyteus.
|
|
20
|
-
from autobyteus.workflow.streaming.workflow_stream_event_payloads import AgentEventRebroadcastPayload, WorkflowPhaseTransitionData
|
|
19
|
+
from autobyteus.workflow.streaming.workflow_stream_event_payloads import AgentEventRebroadcastPayload
|
|
21
20
|
|
|
22
21
|
from .state import TUIStateStore
|
|
23
22
|
from .widgets.agent_list_sidebar import AgentListSidebar
|
|
@@ -139,12 +138,12 @@ class WorkflowApp(App):
|
|
|
139
138
|
|
|
140
139
|
# Fetch fresh data from the store for the update
|
|
141
140
|
tree_data = self.store.get_tree_data()
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
agent_statuses = self.store._agent_statuses
|
|
142
|
+
workflow_statuses = self.store._workflow_statuses
|
|
144
143
|
speaking_agents = self.store._speaking_agents
|
|
145
144
|
|
|
146
145
|
# Update sidebar
|
|
147
|
-
sidebar.update_tree(tree_data,
|
|
146
|
+
sidebar.update_tree(tree_data, agent_statuses, workflow_statuses, speaking_agents)
|
|
148
147
|
|
|
149
148
|
# Intelligently update the focus pane
|
|
150
149
|
focused_data = self.focused_node_data
|
|
@@ -156,12 +155,12 @@ class WorkflowApp(App):
|
|
|
156
155
|
node_data=focused_data,
|
|
157
156
|
history=history,
|
|
158
157
|
pending_approval=None,
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
all_agent_statuses=agent_statuses,
|
|
159
|
+
all_workflow_statuses=workflow_statuses
|
|
161
160
|
)
|
|
162
161
|
elif focused_data and focused_data.get("type") == 'agent':
|
|
163
162
|
# For agents, we only need to update the title status, not the whole log.
|
|
164
|
-
focus_pane.update_current_node_status(
|
|
163
|
+
focus_pane.update_current_node_status(agent_statuses, workflow_statuses)
|
|
165
164
|
|
|
166
165
|
|
|
167
166
|
async def watch_focused_node_data(self, new_node_data: Optional[Dict[str, Any]]):
|
|
@@ -181,8 +180,8 @@ class WorkflowApp(App):
|
|
|
181
180
|
node_data=new_node_data,
|
|
182
181
|
history=history,
|
|
183
182
|
pending_approval=pending_approval,
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
all_agent_statuses=self.store._agent_statuses,
|
|
184
|
+
all_workflow_statuses=self.store._workflow_statuses
|
|
186
185
|
)
|
|
187
186
|
|
|
188
187
|
sidebar.update_selection(node_name)
|
|
@@ -8,15 +8,15 @@ import copy
|
|
|
8
8
|
|
|
9
9
|
from autobyteus.agent.context import AgentConfig
|
|
10
10
|
from autobyteus.workflow.agentic_workflow import AgenticWorkflow
|
|
11
|
-
from autobyteus.agent.
|
|
12
|
-
from autobyteus.workflow.
|
|
11
|
+
from autobyteus.agent.status.status_enum import AgentStatus
|
|
12
|
+
from autobyteus.workflow.status.workflow_status import WorkflowStatus
|
|
13
13
|
from autobyteus.agent.streaming.stream_events import StreamEvent as AgentStreamEvent, StreamEventType as AgentStreamEventType
|
|
14
14
|
from autobyteus.agent.streaming.stream_event_payloads import (
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
AgentStatusUpdateData, ToolInvocationApprovalRequestedData,
|
|
16
|
+
AssistantCompleteResponseData
|
|
17
17
|
)
|
|
18
18
|
from autobyteus.workflow.streaming.workflow_stream_events import WorkflowStreamEvent
|
|
19
|
-
from autobyteus.workflow.streaming.workflow_stream_event_payloads import AgentEventRebroadcastPayload, SubWorkflowEventRebroadcastPayload,
|
|
19
|
+
from autobyteus.workflow.streaming.workflow_stream_event_payloads import AgentEventRebroadcastPayload, SubWorkflowEventRebroadcastPayload, WorkflowStatusUpdateData
|
|
20
20
|
|
|
21
21
|
logger = logging.getLogger(__name__)
|
|
22
22
|
|
|
@@ -38,8 +38,8 @@ class TUIStateStore:
|
|
|
38
38
|
|
|
39
39
|
self._node_roles: Dict[str, str] = self._extract_node_roles(workflow)
|
|
40
40
|
self._nodes: Dict[str, Any] = self._initialize_root_node()
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
41
|
+
self._agent_statuses: Dict[str, AgentStatus] = {}
|
|
42
|
+
self._workflow_statuses: Dict[str, WorkflowStatus] = {self.workflow_name: WorkflowStatus.UNINITIALIZED}
|
|
43
43
|
self._agent_event_history: Dict[str, List[AgentStreamEvent]] = {}
|
|
44
44
|
self._workflow_event_history: Dict[str, List[WorkflowStreamEvent]] = {self.workflow_name: []}
|
|
45
45
|
self._pending_approvals: Dict[str, ToolInvocationApprovalRequestedData] = {}
|
|
@@ -77,8 +77,8 @@ class TUIStateStore:
|
|
|
77
77
|
The main entry point for processing events from the backend.
|
|
78
78
|
This method acts as a reducer, updating the state based on the event.
|
|
79
79
|
"""
|
|
80
|
-
if event.event_source_type == "WORKFLOW" and isinstance(event.data,
|
|
81
|
-
self.
|
|
80
|
+
if event.event_source_type == "WORKFLOW" and isinstance(event.data, WorkflowStatusUpdateData):
|
|
81
|
+
self._workflow_statuses[self.workflow_name] = event.data.new_status
|
|
82
82
|
|
|
83
83
|
self._process_event_recursively(event, self.workflow_name)
|
|
84
84
|
|
|
@@ -113,13 +113,11 @@ class TUIStateStore:
|
|
|
113
113
|
self._agent_event_history[agent_name].append(agent_event)
|
|
114
114
|
|
|
115
115
|
# --- State update logic for specific events (applies to both focused and non-focused) ---
|
|
116
|
-
if agent_event.event_type == AgentStreamEventType.
|
|
117
|
-
|
|
118
|
-
self.
|
|
116
|
+
if agent_event.event_type == AgentStreamEventType.AGENT_STATUS_UPDATED:
|
|
117
|
+
status_data: AgentStatusUpdateData = agent_event.data
|
|
118
|
+
self._agent_statuses[agent_name] = status_data.new_status
|
|
119
119
|
if agent_name in self._pending_approvals:
|
|
120
120
|
del self._pending_approvals[agent_name]
|
|
121
|
-
elif agent_event.event_type == AgentStreamEventType.AGENT_IDLE:
|
|
122
|
-
self._agent_phases[agent_name] = AgentOperationalPhase.IDLE
|
|
123
121
|
elif agent_event.event_type == AgentStreamEventType.TOOL_INVOCATION_APPROVAL_REQUESTED:
|
|
124
122
|
self._pending_approvals[agent_name] = agent_event.data
|
|
125
123
|
|
|
@@ -134,8 +132,8 @@ class TUIStateStore:
|
|
|
134
132
|
role = self._node_roles.get(sub_workflow_name, "Sub-Workflow")
|
|
135
133
|
self._add_node(sub_workflow_name, {"type": "subworkflow", "name": sub_workflow_name, "role": role, "children": {}}, parent_name)
|
|
136
134
|
|
|
137
|
-
if sub_workflow_event.event_source_type == "WORKFLOW" and isinstance(sub_workflow_event.data,
|
|
138
|
-
self.
|
|
135
|
+
if sub_workflow_event.event_source_type == "WORKFLOW" and isinstance(sub_workflow_event.data, WorkflowStatusUpdateData):
|
|
136
|
+
self._workflow_statuses[sub_workflow_name] = sub_workflow_event.data.new_status
|
|
139
137
|
|
|
140
138
|
self._process_event_recursively(sub_workflow_event, parent_name=sub_workflow_name)
|
|
141
139
|
|
|
@@ -10,10 +10,10 @@ from textual.widgets import Static, Tree
|
|
|
10
10
|
from textual.widgets.tree import TreeNode
|
|
11
11
|
from textual.containers import Vertical
|
|
12
12
|
|
|
13
|
-
from autobyteus.agent.
|
|
14
|
-
from autobyteus.workflow.
|
|
13
|
+
from autobyteus.agent.status.status_enum import AgentStatus
|
|
14
|
+
from autobyteus.workflow.status.workflow_status import WorkflowStatus
|
|
15
15
|
from .shared import (
|
|
16
|
-
|
|
16
|
+
AGENT_STATUS_ICONS, WORKFLOW_STATUS_ICONS, SUB_WORKFLOW_ICON,
|
|
17
17
|
WORKFLOW_ICON, SPEAKING_ICON, DEFAULT_ICON
|
|
18
18
|
)
|
|
19
19
|
from .logo import Logo
|
|
@@ -45,19 +45,19 @@ class AgentListSidebar(Static):
|
|
|
45
45
|
self.post_message(self.NodeSelected(event.node.data))
|
|
46
46
|
event.stop()
|
|
47
47
|
|
|
48
|
-
def _build_label(self, name: str, node_data: Dict,
|
|
48
|
+
def _build_label(self, name: str, node_data: Dict, agent_statuses: Dict, workflow_statuses: Dict, speaking_agents: Dict) -> str:
|
|
49
49
|
"""Constructs the display label for a tree node."""
|
|
50
50
|
node_type = node_data["type"]
|
|
51
51
|
icon = DEFAULT_ICON
|
|
52
52
|
|
|
53
53
|
if node_type == "agent":
|
|
54
|
-
|
|
55
|
-
icon = SPEAKING_ICON if speaking_agents.get(name) else
|
|
54
|
+
status = agent_statuses.get(name, AgentStatus.UNINITIALIZED)
|
|
55
|
+
icon = SPEAKING_ICON if speaking_agents.get(name) else AGENT_STATUS_ICONS.get(status, DEFAULT_ICON)
|
|
56
56
|
label = f"{icon} {name}"
|
|
57
57
|
elif node_type in ["workflow", "subworkflow"]:
|
|
58
|
-
|
|
58
|
+
status = workflow_statuses.get(name, WorkflowStatus.UNINITIALIZED)
|
|
59
59
|
default_icon = WORKFLOW_ICON if node_type == "workflow" else SUB_WORKFLOW_ICON
|
|
60
|
-
icon =
|
|
60
|
+
icon = WORKFLOW_STATUS_ICONS.get(status, default_icon)
|
|
61
61
|
role = node_data.get("role")
|
|
62
62
|
label = f"{icon} {role or name}"
|
|
63
63
|
if role and role != name:
|
|
@@ -67,7 +67,7 @@ class AgentListSidebar(Static):
|
|
|
67
67
|
|
|
68
68
|
return label
|
|
69
69
|
|
|
70
|
-
def update_tree(self, tree_data: Dict,
|
|
70
|
+
def update_tree(self, tree_data: Dict, agent_statuses: Dict[str, AgentStatus], workflow_statuses: Dict[str, WorkflowStatus], speaking_agents: Dict[str, bool]):
|
|
71
71
|
"""
|
|
72
72
|
Performs an in-place update of the tree to reflect the new state,
|
|
73
73
|
avoiding a full rebuild for better performance and preserving UI state like expansion.
|
|
@@ -82,17 +82,17 @@ class AgentListSidebar(Static):
|
|
|
82
82
|
root_node_data = tree_data[root_name]
|
|
83
83
|
|
|
84
84
|
# Kick off the recursive update from the root.
|
|
85
|
-
self._update_node_recursively(tree.root, root_node_data,
|
|
85
|
+
self._update_node_recursively(tree.root, root_node_data, agent_statuses, workflow_statuses, speaking_agents)
|
|
86
86
|
|
|
87
87
|
# Ensure the root is expanded on the first run.
|
|
88
88
|
if not tree.root.is_expanded:
|
|
89
89
|
tree.root.expand()
|
|
90
90
|
|
|
91
|
-
def _update_node_recursively(self, ui_node: TreeNode, node_data: Dict,
|
|
91
|
+
def _update_node_recursively(self, ui_node: TreeNode, node_data: Dict, agent_statuses: Dict, workflow_statuses: Dict, speaking_agents: Dict):
|
|
92
92
|
"""Recursively updates a node and reconciles its children."""
|
|
93
93
|
# 1. Update the current node's label and data
|
|
94
94
|
name = node_data['name']
|
|
95
|
-
label = self._build_label(name, node_data,
|
|
95
|
+
label = self._build_label(name, node_data, agent_statuses, workflow_statuses, speaking_agents)
|
|
96
96
|
ui_node.set_label(label)
|
|
97
97
|
ui_node.data = node_data
|
|
98
98
|
self._node_map[name] = ui_node # Ensure map is always up-to-date
|
|
@@ -106,10 +106,10 @@ class AgentListSidebar(Static):
|
|
|
106
106
|
if child_name in existing_ui_children_by_name:
|
|
107
107
|
# Node exists, so we recursively update it
|
|
108
108
|
child_ui_node = existing_ui_children_by_name[child_name]
|
|
109
|
-
self._update_node_recursively(child_ui_node, child_data,
|
|
109
|
+
self._update_node_recursively(child_ui_node, child_data, agent_statuses, workflow_statuses, speaking_agents)
|
|
110
110
|
else:
|
|
111
111
|
# Node is new, so we add it
|
|
112
|
-
new_child_label = self._build_label(child_name, child_data,
|
|
112
|
+
new_child_label = self._build_label(child_name, child_data, agent_statuses, workflow_statuses, speaking_agents)
|
|
113
113
|
is_leaf = child_data.get("children", {}) == {} and child_data['type'] == 'agent'
|
|
114
114
|
|
|
115
115
|
if is_leaf:
|
|
@@ -117,7 +117,7 @@ class AgentListSidebar(Static):
|
|
|
117
117
|
else:
|
|
118
118
|
new_ui_node = ui_node.add(new_child_label, data=child_data)
|
|
119
119
|
# Since this is a new branch, we must build its children too
|
|
120
|
-
self._update_node_recursively(new_ui_node, child_data,
|
|
120
|
+
self._update_node_recursively(new_ui_node, child_data, agent_statuses, workflow_statuses, speaking_agents)
|
|
121
121
|
|
|
122
122
|
self._node_map[child_name] = new_ui_node
|
|
123
123
|
|